aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes4
-rw-r--r--.github/workflows/ci.yaml83
-rw-r--r--.github/workflows/metrics.yaml32
-rw-r--r--Cargo.lock538
-rw-r--r--Cargo.toml7
-rw-r--r--README.md14
-rw-r--r--crates/expect/Cargo.toml14
-rw-r--r--crates/expect/src/lib.rs356
-rw-r--r--crates/flycheck/Cargo.toml3
-rw-r--r--crates/flycheck/src/lib.rs23
-rw-r--r--crates/paths/Cargo.toml1
-rw-r--r--crates/ra_arena/Cargo.toml1
-rw-r--r--crates/ra_assists/Cargo.toml1
-rw-r--r--crates/ra_assists/src/assist_config.rs5
-rw-r--r--crates/ra_assists/src/assist_context.rs56
-rw-r--r--crates/ra_assists/src/ast_transform.rs20
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs8
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs22
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs98
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs52
-rw-r--r--crates/ra_assists/src/handlers/add_turbo_fish.rs42
-rw-r--r--crates/ra_assists/src/handlers/apply_demorgan.rs17
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs160
-rw-r--r--crates/ra_assists/src/handlers/change_return_type_to_result.rs12
-rw-r--r--crates/ra_assists/src/handlers/change_visibility.rs35
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs160
-rw-r--r--crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs17
-rw-r--r--crates/ra_assists/src/handlers/extract_variable.rs202
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs251
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs120
-rw-r--r--crates/ra_assists/src/handlers/flip_binexpr.rs21
-rw-r--r--crates/ra_assists/src/handlers/flip_comma.rs15
-rw-r--r--crates/ra_assists/src/handlers/flip_trait_bound.rs15
-rw-r--r--crates/ra_assists/src/handlers/generate_derive.rs (renamed from crates/ra_assists/src/handlers/add_derive.rs)67
-rw-r--r--crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs (renamed from crates/ra_assists/src/handlers/add_from_impl_for_enum.rs)28
-rw-r--r--crates/ra_assists/src/handlers/generate_function.rs (renamed from crates/ra_assists/src/handlers/add_function.rs)97
-rw-r--r--crates/ra_assists/src/handlers/generate_impl.rs109
-rw-r--r--crates/ra_assists/src/handlers/generate_new.rs (renamed from crates/ra_assists/src/handlers/add_new.rs)70
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs24
-rw-r--r--crates/ra_assists/src/handlers/introduce_named_lifetime.rs28
-rw-r--r--crates/ra_assists/src/handlers/invert_if.rs4
-rw-r--r--crates/ra_assists/src/handlers/merge_imports.rs15
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs45
-rw-r--r--crates/ra_assists/src/handlers/move_bounds.rs69
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs29
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs176
-rw-r--r--crates/ra_assists/src/handlers/remove_dbg.rs98
-rw-r--r--crates/ra_assists/src/handlers/remove_mut.rs13
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs27
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs50
-rw-r--r--crates/ra_assists/src/handlers/replace_let_with_if_let.rs41
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs10
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs60
-rw-r--r--crates/ra_assists/src/handlers/split_import.rs4
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs4
-rw-r--r--crates/ra_assists/src/lib.rs52
-rw-r--r--crates/ra_assists/src/tests.rs45
-rw-r--r--crates/ra_assists/src/tests/generated.rs218
-rw-r--r--crates/ra_assists/src/utils.rs13
-rw-r--r--crates/ra_assists/src/utils/insert_use.rs10
-rw-r--r--crates/ra_cfg/Cargo.toml1
-rw-r--r--crates/ra_cfg/src/cfg_expr.rs21
-rw-r--r--crates/ra_cfg/src/lib.rs20
-rw-r--r--crates/ra_db/Cargo.toml4
-rw-r--r--crates/ra_db/src/fixture.rs10
-rw-r--r--crates/ra_db/src/input.rs58
-rw-r--r--crates/ra_db/src/lib.rs18
-rw-r--r--crates/ra_fmt/Cargo.toml1
-rw-r--r--crates/ra_hir/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model.rs179
-rw-r--r--crates/ra_hir/src/db.rs10
-rw-r--r--crates/ra_hir/src/diagnostics.rs8
-rw-r--r--crates/ra_hir/src/has_source.rs42
-rw-r--r--crates/ra_hir/src/lib.rs32
-rw-r--r--crates/ra_hir/src/semantics.rs381
-rw-r--r--crates/ra_hir/src/semantics/source_to_def.rs81
-rw-r--r--crates/ra_hir/src/source_analyzer.rs41
-rw-r--r--crates/ra_hir_def/Cargo.toml3
-rw-r--r--crates/ra_hir_def/src/adt.rs18
-rw-r--r--crates/ra_hir_def/src/attr.rs28
-rw-r--r--crates/ra_hir_def/src/body.rs69
-rw-r--r--crates/ra_hir_def/src/body/lower.rs48
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs2
-rw-r--r--crates/ra_hir_def/src/data.rs4
-rw-r--r--crates/ra_hir_def/src/generics.rs12
-rw-r--r--crates/ra_hir_def/src/import_map.rs370
-rw-r--r--crates/ra_hir_def/src/item_scope.rs132
-rw-r--r--crates/ra_hir_def/src/item_tree.rs53
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs187
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs218
-rw-r--r--crates/ra_hir_def/src/keys.rs26
-rw-r--r--crates/ra_hir_def/src/lib.rs55
-rw-r--r--crates/ra_hir_def/src/nameres.rs22
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs116
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs10
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs972
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs578
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs1061
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs1289
-rw-r--r--crates/ra_hir_def/src/nameres/tests/primitives.rs33
-rw-r--r--crates/ra_hir_def/src/path.rs2
-rw-r--r--crates/ra_hir_def/src/path/lower.rs6
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs8
-rw-r--r--crates/ra_hir_def/src/test_db.rs28
-rw-r--r--crates/ra_hir_def/src/type_ref.rs34
-rw-r--r--crates/ra_hir_def/src/visibility.rs41
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs2
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs2
-rw-r--r--crates/ra_hir_expand/src/db.rs21
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs62
-rw-r--r--crates/ra_hir_expand/src/lib.rs31
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_expand/src/test_db.rs24
-rw-r--r--crates/ra_hir_ty/Cargo.toml12
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs15
-rw-r--r--crates/ra_hir_ty/src/db.rs44
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs308
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs (renamed from crates/ra_hir_ty/src/expr.rs)291
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs (renamed from crates/ra_hir_ty/src/_match.rs)1678
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs (renamed from crates/ra_hir_ty/src/unsafe_validation.rs)77
-rw-r--r--crates/ra_hir_ty/src/display.rs47
-rw-r--r--crates/ra_hir_ty/src/infer.rs37
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs25
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs55
-rw-r--r--crates/ra_hir_ty/src/lib.rs107
-rw-r--r--crates/ra_hir_ty/src/lower.rs61
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs302
-rw-r--r--crates/ra_hir_ty/src/test_db.rs125
-rw-r--r--crates/ra_hir_ty/src/tests.rs419
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs1386
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs620
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs1150
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs315
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs1102
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs1137
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs3398
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs3460
-rw-r--r--crates/ra_hir_ty/src/traits.rs80
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs371
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs205
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/interner.rs29
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs233
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs28
-rw-r--r--crates/ra_hir_ty/src/utils.rs32
-rw-r--r--crates/ra_ide/Cargo.toml4
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs97
-rw-r--r--crates/ra_ide/src/call_info.rs789
-rw-r--r--crates/ra_ide/src/completion.rs18
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs1263
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs994
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs161
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs562
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs137
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs126
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs635
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs1506
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs546
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs106
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs498
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs1615
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs59
-rw-r--r--crates/ra_ide/src/completion/completion_item.rs26
-rw-r--r--crates/ra_ide/src/completion/patterns.rs16
-rw-r--r--crates/ra_ide/src/completion/presentation.rs1675
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs72
-rw-r--r--crates/ra_ide/src/diagnostics.rs913
-rw-r--r--crates/ra_ide/src/display.rs96
-rw-r--r--crates/ra_ide/src/display/function_signature.rs334
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs207
-rw-r--r--crates/ra_ide/src/display/short_label.rs36
-rw-r--r--crates/ra_ide/src/display/structure.rs438
-rw-r--r--crates/ra_ide/src/expand_macro.rs241
-rw-r--r--crates/ra_ide/src/extend_selection.rs8
-rw-r--r--crates/ra_ide/src/file_structure.rs431
-rw-r--r--crates/ra_ide/src/folding_ranges.rs194
-rw-r--r--crates/ra_ide/src/goto_definition.rs1168
-rw-r--r--crates/ra_ide/src/goto_implementation.rs211
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs132
-rw-r--r--crates/ra_ide/src/hover.rs3454
-rw-r--r--crates/ra_ide/src/inlay_hints.rs1062
-rw-r--r--crates/ra_ide/src/lib.rs142
-rw-r--r--crates/ra_ide/src/markup.rs38
-rw-r--r--crates/ra_ide/src/mock_analysis.rs40
-rw-r--r--crates/ra_ide/src/references.rs47
-rw-r--r--crates/ra_ide/src/references/rename.rs1101
-rw-r--r--crates/ra_ide/src/runnables.rs1137
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html101
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html95
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html117
-rw-r--r--crates/ra_ide/src/ssr.rs53
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs114
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs32
-rw-r--r--crates/ra_ide/src/syntax_tree.rs14
-rw-r--r--crates/ra_ide/src/typing.rs1
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs67
-rw-r--r--crates/ra_ide/test_data/highlight_doctest.html102
-rw-r--r--crates/ra_ide/test_data/highlight_injection.html (renamed from crates/ra_ide/src/snapshots/highlight_injection.html)25
-rw-r--r--crates/ra_ide/test_data/highlight_strings.html96
-rw-r--r--crates/ra_ide/test_data/highlight_unsafe.html (renamed from crates/ra_ide/src/snapshots/highlight_unsafe.html)33
-rw-r--r--crates/ra_ide/test_data/highlighting.html128
-rw-r--r--crates/ra_ide/test_data/rainbow_highlighting.html (renamed from crates/ra_ide/src/snapshots/rainbow_highlighting.html)25
-rw-r--r--crates/ra_ide_db/Cargo.toml4
-rw-r--r--crates/ra_ide_db/src/change.rs87
-rw-r--r--crates/ra_ide_db/src/defs.rs91
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs88
-rw-r--r--crates/ra_ide_db/src/lib.rs43
-rw-r--r--crates/ra_ide_db/src/line_index.rs8
-rw-r--r--crates/ra_ide_db/src/search.rs18
-rw-r--r--crates/ra_ide_db/src/source_change.rs2
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs24
-rw-r--r--crates/ra_mbe/Cargo.toml1
-rw-r--r--crates/ra_mbe/src/lib.rs6
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs2
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs2
-rw-r--r--crates/ra_mbe/src/tests.rs18
-rw-r--r--crates/ra_parser/Cargo.toml1
-rw-r--r--crates/ra_parser/src/grammar.rs20
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs6
-rw-r--r--crates/ra_parser/src/grammar/items.rs18
-rw-r--r--crates/ra_parser/src/grammar/items/adt.rs18
-rw-r--r--crates/ra_parser/src/grammar/items/consts.rs4
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs4
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs50
-rw-r--r--crates/ra_proc_macro/Cargo.toml1
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml3
-rw-r--r--crates/ra_proc_macro_srv/src/dylib.rs2
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs14
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs3
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs8
-rw-r--r--crates/ra_proc_macro_srv/src/rustc_server.rs13
-rw-r--r--crates/ra_proc_macro_srv/src/tests/mod.rs6
-rw-r--r--crates/ra_proc_macro_srv/src/tests/utils.rs4
-rw-r--r--crates/ra_prof/Cargo.toml13
-rw-r--r--crates/ra_prof/src/lib.rs17
-rw-r--r--crates/ra_prof/src/memory_usage.rs52
-rw-r--r--crates/ra_prof/src/stop_watch.rs86
-rw-r--r--crates/ra_project_model/Cargo.toml3
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs98
-rw-r--r--crates/ra_project_model/src/cfg_flag.rs51
-rw-r--r--crates/ra_project_model/src/lib.rs182
-rw-r--r--crates/ra_project_model/src/project_json.rs118
-rw-r--r--crates/ra_project_model/src/sysroot.rs102
-rw-r--r--crates/ra_ssr/Cargo.toml4
-rw-r--r--crates/ra_ssr/src/errors.rs29
-rw-r--r--crates/ra_ssr/src/lib.rs308
-rw-r--r--crates/ra_ssr/src/matching.rs381
-rw-r--r--crates/ra_ssr/src/nester.rs98
-rw-r--r--crates/ra_ssr/src/parsing.rs259
-rw-r--r--crates/ra_ssr/src/replacing.rs204
-rw-r--r--crates/ra_ssr/src/resolving.rs228
-rw-r--r--crates/ra_ssr/src/search.rs273
-rw-r--r--crates/ra_ssr/src/tests.rs963
-rw-r--r--crates/ra_syntax/Cargo.toml4
-rw-r--r--crates/ra_syntax/src/ast.rs22
-rw-r--r--crates/ra_syntax/src/ast/edit.rs46
-rw-r--r--crates/ra_syntax/src/ast/expr_ext.rs (renamed from crates/ra_syntax/src/ast/expr_extensions.rs)13
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs3812
-rw-r--r--crates/ra_syntax/src/ast/make.rs14
-rw-r--r--crates/ra_syntax/src/ast/node_ext.rs (renamed from crates/ra_syntax/src/ast/extensions.rs)91
-rw-r--r--crates/ra_syntax/src/ast/token_ext.rs (renamed from crates/ra_syntax/src/ast/tokens.rs)20
-rw-r--r--crates/ra_syntax/src/ast/traits.rs12
-rw-r--r--crates/ra_syntax/src/lib.rs12
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs9
-rw-r--r--crates/ra_syntax/src/ptr.rs2
-rw-r--r--crates/ra_syntax/src/syntax_node.rs4
-rw-r--r--crates/ra_syntax/src/tests.rs118
-rw-r--r--crates/ra_syntax/src/validation.rs8
-rw-r--r--crates/ra_syntax/src/validation/block.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/err/0019_let_recover.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0025_nope.rast46
-rw-r--r--crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0029_field_completion.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0036_partial_use.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0043_default_const.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast28
-rw-r--r--crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/fuzz-failures/0000.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast28
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast26
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0161_labeled_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0162_unsafe_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast13
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0009_use_item.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0012_visibility.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast26
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast68
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0019_enums.rast52
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast40
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0023_static_items.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0024_const_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_traits.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0031_extern.rast24
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0032_where_for.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0033_label_break.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast50
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0049_async_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast42
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0060_as_range.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0066_default_const.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast38
-rw-r--r--crates/ra_text_edit/Cargo.toml1
-rw-r--r--crates/ra_toolchain/Cargo.toml4
-rw-r--r--crates/ra_tt/Cargo.toml2
-rw-r--r--crates/ra_tt/src/lib.rs19
-rw-r--r--crates/rust-analyzer/Cargo.toml16
-rw-r--r--crates/rust-analyzer/src/bin/args.rs93
-rw-r--r--crates/rust-analyzer/src/bin/main.rs45
-rw-r--r--crates/rust-analyzer/src/caps.rs22
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs81
-rw-r--r--crates/rust-analyzer/src/cli.rs21
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs161
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs470
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs49
-rw-r--r--crates/rust-analyzer/src/config.rs339
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs298
-rw-r--r--crates/rust-analyzer/src/document.rs16
-rw-r--r--crates/rust-analyzer/src/from_proto.rs16
-rw-r--r--crates/rust-analyzer/src/global_state.rs51
-rw-r--r--crates/rust-analyzer/src/handlers.rs197
-rw-r--r--crates/rust-analyzer/src/lib.rs22
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs54
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs40
-rw-r--r--crates/rust-analyzer/src/main_loop.rs218
-rw-r--r--crates/rust-analyzer/src/reload.rs225
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs206
-rw-r--r--crates/rust-analyzer/test_data/clippy_pass_by_ref.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_clippy_pass_by_ref.snap)18
-rw-r--r--crates/rust-analyzer/test_data/handles_macro_location.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_handles_macro_location.snap)18
-rw-r--r--crates/rust-analyzer/test_data/macro_compiler_error.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_macro_compiler_error.snap)18
-rw-r--r--crates/rust-analyzer/test_data/rustc_incompatible_type_for_trait.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_incompatible_type_for_trait.snap)18
-rw-r--r--crates/rust-analyzer/test_data/rustc_mismatched_type.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_mismatched_type.snap)18
-rw-r--r--crates/rust-analyzer/test_data/rustc_unused_variable.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap)26
-rw-r--r--crates/rust-analyzer/test_data/rustc_unused_variable_as_hint.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap)26
-rw-r--r--crates/rust-analyzer/test_data/rustc_unused_variable_as_info.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap)26
-rw-r--r--crates/rust-analyzer/test_data/rustc_wrong_number_of_parameters.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_wrong_number_of_parameters.snap)18
-rw-r--r--crates/rust-analyzer/test_data/snap_multi_line_fix.txt (renamed from crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap)26
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs22
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs42
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/testdir.rs62
-rw-r--r--crates/stdx/Cargo.toml1
-rw-r--r--crates/stdx/src/lib.rs68
-rw-r--r--crates/stdx/src/macros.rs40
-rw-r--r--crates/test_utils/Cargo.toml1
-rw-r--r--crates/test_utils/src/fixture.rs10
-rw-r--r--crates/test_utils/src/lib.rs221
-rw-r--r--crates/test_utils/src/mark.rs4
-rw-r--r--crates/vfs-notify/Cargo.toml5
-rw-r--r--crates/vfs-notify/src/include.rs43
-rw-r--r--crates/vfs-notify/src/lib.rs147
-rw-r--r--crates/vfs/Cargo.toml5
-rw-r--r--crates/vfs/src/file_set.rs135
-rw-r--r--crates/vfs/src/lib.rs6
-rw-r--r--crates/vfs/src/loader.rs78
-rw-r--r--crates/vfs/src/vfs_path.rs31
-rw-r--r--docs/dev/README.md27
-rw-r--r--docs/dev/architecture.md3
-rw-r--r--docs/dev/lsp-extensions.md35
-rw-r--r--docs/dev/syntax.md4
-rw-r--r--docs/user/manual.adoc120
-rw-r--r--editors/code/package-lock.json972
-rw-r--r--editors/code/package.json111
-rw-r--r--editors/code/rollup.config.js3
-rw-r--r--editors/code/rust.tmGrammar.json4
-rw-r--r--editors/code/src/client.ts8
-rw-r--r--editors/code/src/commands.ts51
-rw-r--r--editors/code/src/config.ts14
-rw-r--r--editors/code/src/ctx.ts43
-rw-r--r--editors/code/src/debug.ts16
-rw-r--r--editors/code/src/lsp_ext.ts10
-rw-r--r--editors/code/src/main.ts54
-rw-r--r--editors/code/src/net.ts21
-rw-r--r--editors/code/src/persistent_state.ts2
-rw-r--r--editors/code/src/run.ts31
-rw-r--r--editors/code/src/snippets.ts4
-rw-r--r--editors/code/src/util.ts45
-rw-r--r--editors/code/tests/unit/index.ts4
-rw-r--r--editors/code/tests/unit/runnable_env.test.ts118
-rw-r--r--editors/code/tsconfig.json2
-rw-r--r--xtask/Cargo.toml9
-rw-r--r--xtask/src/ast_src.rs2080
-rw-r--r--xtask/src/codegen/gen_syntax.rs290
-rw-r--r--xtask/src/codegen/rust.ungram544
-rw-r--r--xtask/src/dist.rs56
-rw-r--r--xtask/src/install.rs14
-rw-r--r--xtask/src/lib.rs3
-rw-r--r--xtask/src/main.rs29
-rw-r--r--xtask/src/metrics.rs279
-rw-r--r--xtask/src/not_bash.rs20
-rw-r--r--xtask/src/release.rs36
-rw-r--r--xtask/tests/tidy.rs59
655 files changed, 33791 insertions, 35962 deletions
diff --git a/.gitattributes b/.gitattributes
index e749e1dc9..4cd50e481 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,6 @@
1* text=auto eol=lf 1* text=auto eol=lf
2crates/ra_syntax/test_data/** -text eof=LF 2crates/ra_syntax/test_data/** -text eof=LF
3# Older git versions try to fix line endings on images, this prevents it.
4*.png binary
5*.jpg binary
6*.ico binary
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ed9191c49..2acd44012 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -16,25 +16,25 @@ env:
16 RUSTUP_MAX_RETRIES: 10 16 RUSTUP_MAX_RETRIES: 10
17 17
18jobs: 18jobs:
19 rust-audit: 19 # rust-audit:
20 name: Audit Rust vulnerabilities 20 # name: Audit Rust vulnerabilities
21 runs-on: ubuntu-latest 21 # runs-on: ubuntu-latest
22 steps: 22 # steps:
23 - name: Checkout repository 23 # - name: Checkout repository
24 uses: actions/checkout@v2 24 # uses: actions/checkout@v2
25 25
26 - uses: actions-rs/[email protected] 26 # - uses: actions-rs/[email protected]
27 with: 27 # with:
28 crate: cargo-audit 28 # crate: cargo-audit
29 use-tool-cache: true 29 # use-tool-cache: true
30 30
31 - run: cargo audit 31 # - run: cargo audit
32 32
33 rust: 33 rust:
34 name: Rust 34 name: Rust
35 runs-on: ${{ matrix.os }} 35 runs-on: ${{ matrix.os }}
36 env: 36 env:
37 CC: deny_c 37 CC: deny_c
38 38
39 strategy: 39 strategy:
40 fail-fast: false 40 fail-fast: false
@@ -61,29 +61,22 @@ jobs:
61 override: true 61 override: true
62 components: rustfmt, rust-src 62 components: rustfmt, rust-src
63 63
64 - if: matrix.os == 'ubuntu-latest' 64 - name: Cache cargo directories
65 run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ 65 uses: actions/cache@v2
66
67 - name: Cache cargo registry
68 uses: actions/cache@v1
69 with: 66 with:
70 path: ~/.cargo/registry 67 path: |
71 key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 68 ~/.cargo/registry
72 69 ~/.cargo/git
73 - name: Cache cargo index 70 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
74 uses: actions/cache@v1
75 with:
76 path: ~/.cargo/git
77 key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
78 71
79 - name: Cache cargo target dir 72 - name: Cache cargo target dir
80 uses: actions/cache@v1 73 uses: actions/cache@v2
81 with: 74 with:
82 path: target 75 path: target
83 key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} 76 key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
84 77
85 - name: Compile 78 - name: Compile
86 run: cargo test --no-run 79 run: cargo test --no-run --locked
87 80
88 - name: Test 81 - name: Test
89 run: cargo test 82 run: cargo test
@@ -95,6 +88,34 @@ jobs:
95 if: matrix.os == 'windows-latest' 88 if: matrix.os == 'windows-latest'
96 run: Remove-Item ./target/debug/xtask.exe, ./target/debug/deps/xtask.exe 89 run: Remove-Item ./target/debug/xtask.exe, ./target/debug/deps/xtask.exe
97 90
91 # Weird target to catch non-portable code
92 rust-power:
93 name: Rust Power
94 runs-on: ubuntu-latest
95
96 steps:
97 - name: Checkout repository
98 uses: actions/checkout@v2
99
100 - name: Install Rust toolchain
101 uses: actions-rs/toolchain@v1
102 with:
103 toolchain: stable
104 profile: minimal
105 override: true
106 target: 'powerpc-unknown-linux-gnu'
107
108 - name: Cache cargo directories
109 uses: actions/cache@v2
110 with:
111 path: |
112 ~/.cargo/registry
113 ~/.cargo/git
114 key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
115
116 - name: Check
117 run: cargo check --target=powerpc-unknown-linux-gnu --all-targets
118
98 typescript: 119 typescript:
99 name: TypeScript 120 name: TypeScript
100 strategy: 121 strategy:
@@ -103,7 +124,7 @@ jobs:
103 os: [ubuntu-latest, windows-latest, macos-latest] 124 os: [ubuntu-latest, windows-latest, macos-latest]
104 125
105 runs-on: ${{ matrix.os }} 126 runs-on: ${{ matrix.os }}
106 127
107 steps: 128 steps:
108 - name: Checkout repository 129 - name: Checkout repository
109 uses: actions/checkout@v2 130 uses: actions/checkout@v2
@@ -116,9 +137,9 @@ jobs:
116 - run: npm ci 137 - run: npm ci
117 working-directory: ./editors/code 138 working-directory: ./editors/code
118 139
119 - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } 140# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
120 if: runner.os == 'Linux' 141# if: runner.os == 'Linux'
121 working-directory: ./editors/code 142# working-directory: ./editors/code
122 143
123 - run: npm run lint 144 - run: npm run lint
124 working-directory: ./editors/code 145 working-directory: ./editors/code
diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml
new file mode 100644
index 000000000..ea780e875
--- /dev/null
+++ b/.github/workflows/metrics.yaml
@@ -0,0 +1,32 @@
1name: metrics
2on:
3 push:
4 branches:
5 - master
6
7env:
8 CARGO_INCREMENTAL: 0
9 CARGO_NET_RETRY: 10
10 RUSTFLAGS: -D warnings
11 RUSTUP_MAX_RETRIES: 10
12
13jobs:
14 metrics:
15 runs-on: ubuntu-latest
16
17 steps:
18 - name: Checkout repository
19 uses: actions/checkout@v2
20
21 - name: Install Rust toolchain
22 uses: actions-rs/toolchain@v1
23 with:
24 toolchain: stable
25 profile: minimal
26 override: true
27 components: rust-src
28
29 - name: Collect metrics
30 run: cargo xtask metrics
31 env:
32 METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }}
diff --git a/Cargo.lock b/Cargo.lock
index 459f82f3a..572fb868e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,18 +2,18 @@
2# It is not intended for manual editing. 2# It is not intended for manual editing.
3[[package]] 3[[package]]
4name = "addr2line" 4name = "addr2line"
5version = "0.12.2" 5version = "0.13.0"
6source = "registry+https://github.com/rust-lang/crates.io-index" 6source = "registry+https://github.com/rust-lang/crates.io-index"
7checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" 7checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
8dependencies = [ 8dependencies = [
9 "gimli", 9 "gimli",
10] 10]
11 11
12[[package]] 12[[package]]
13name = "adler32" 13name = "adler"
14version = "1.1.0" 14version = "0.2.3"
15source = "registry+https://github.com/rust-lang/crates.io-index" 15source = "registry+https://github.com/rust-lang/crates.io-index"
16checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" 16checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
17 17
18[[package]] 18[[package]]
19name = "aho-corasick" 19name = "aho-corasick"
@@ -26,18 +26,18 @@ dependencies = [
26 26
27[[package]] 27[[package]]
28name = "ansi_term" 28name = "ansi_term"
29version = "0.11.0" 29version = "0.12.1"
30source = "registry+https://github.com/rust-lang/crates.io-index" 30source = "registry+https://github.com/rust-lang/crates.io-index"
31checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 31checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
32dependencies = [ 32dependencies = [
33 "winapi 0.3.9", 33 "winapi 0.3.9",
34] 34]
35 35
36[[package]] 36[[package]]
37name = "anyhow" 37name = "anyhow"
38version = "1.0.31" 38version = "1.0.32"
39source = "registry+https://github.com/rust-lang/crates.io-index" 39source = "registry+https://github.com/rust-lang/crates.io-index"
40checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" 40checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
41 41
42[[package]] 42[[package]]
43name = "anymap" 43name = "anymap"
@@ -52,6 +52,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
52checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 52checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
53 53
54[[package]] 54[[package]]
55name = "atty"
56version = "0.2.14"
57source = "registry+https://github.com/rust-lang/crates.io-index"
58checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
59dependencies = [
60 "hermit-abi",
61 "libc",
62 "winapi 0.3.9",
63]
64
65[[package]]
55name = "autocfg" 66name = "autocfg"
56version = "1.0.0" 67version = "1.0.0"
57source = "registry+https://github.com/rust-lang/crates.io-index" 68source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -59,9 +70,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
59 70
60[[package]] 71[[package]]
61name = "backtrace" 72name = "backtrace"
62version = "0.3.49" 73version = "0.3.50"
63source = "registry+https://github.com/rust-lang/crates.io-index" 74source = "registry+https://github.com/rust-lang/crates.io-index"
64checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" 75checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
65dependencies = [ 76dependencies = [
66 "addr2line", 77 "addr2line",
67 "cfg-if", 78 "cfg-if",
@@ -84,15 +95,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
84checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 95checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
85 96
86[[package]] 97[[package]]
87name = "bstr"
88version = "0.2.13"
89source = "registry+https://github.com/rust-lang/crates.io-index"
90checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
91dependencies = [
92 "memchr",
93]
94
95[[package]]
96name = "byteorder" 98name = "byteorder"
97version = "1.3.4" 99version = "1.3.4"
98source = "registry+https://github.com/rust-lang/crates.io-index" 100source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -100,21 +102,20 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
100 102
101[[package]] 103[[package]]
102name = "cargo_metadata" 104name = "cargo_metadata"
103version = "0.10.0" 105version = "0.11.1"
104source = "registry+https://github.com/rust-lang/crates.io-index" 106source = "registry+https://github.com/rust-lang/crates.io-index"
105checksum = "b8de60b887edf6d74370fc8eb177040da4847d971d6234c7b13a6da324ef0caf" 107checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35"
106dependencies = [ 108dependencies = [
107 "semver", 109 "semver",
108 "serde", 110 "serde",
109 "serde_derive",
110 "serde_json", 111 "serde_json",
111] 112]
112 113
113[[package]] 114[[package]]
114name = "cc" 115name = "cc"
115version = "1.0.56" 116version = "1.0.58"
116source = "registry+https://github.com/rust-lang/crates.io-index" 117source = "registry+https://github.com/rust-lang/crates.io-index"
117checksum = "77c1f1d60091c1b73e2b1f4560ab419204b178e625fa945ded7b660becd2bd46" 118checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
118 119
119[[package]] 120[[package]]
120name = "cfg-if" 121name = "cfg-if"
@@ -124,9 +125,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
124 125
125[[package]] 126[[package]]
126name = "chalk-derive" 127name = "chalk-derive"
127version = "0.15.0" 128version = "0.19.0"
128source = "registry+https://github.com/rust-lang/crates.io-index" 129source = "registry+https://github.com/rust-lang/crates.io-index"
129checksum = "c7379caa72d04103fcfd9bde5642b816f58e3ffd6a0d39347e9e35a066648226" 130checksum = "654c611946ba2629c5028cb7708687af975faf2c29d731824cb294c873df4697"
130dependencies = [ 131dependencies = [
131 "proc-macro2", 132 "proc-macro2",
132 "quote", 133 "quote",
@@ -135,35 +136,35 @@ dependencies = [
135] 136]
136 137
137[[package]] 138[[package]]
138name = "chalk-engine" 139name = "chalk-ir"
139version = "0.15.0" 140version = "0.19.0"
140source = "registry+https://github.com/rust-lang/crates.io-index" 141source = "registry+https://github.com/rust-lang/crates.io-index"
141checksum = "8e8afe48b5663504b485791ab4fae69cf4864869a71ceec9c758fd4d03423722" 142checksum = "0a5341fbc654ca886b73b804a36aebf0e621057ccc1a68e9815b5b39b3ac9ae8"
142dependencies = [ 143dependencies = [
143 "chalk-derive", 144 "chalk-derive",
144 "chalk-ir", 145 "lazy_static",
145 "rustc-hash",
146 "tracing",
147] 146]
148 147
149[[package]] 148[[package]]
150name = "chalk-ir" 149name = "chalk-recursive"
151version = "0.15.0" 150version = "0.19.0"
152source = "registry+https://github.com/rust-lang/crates.io-index" 151source = "registry+https://github.com/rust-lang/crates.io-index"
153checksum = "231e391a03c1fc45874171d92be9542efedc939bac59d9501ee28b9521feb406" 152checksum = "4484807b155b5a411e6135d330295f9ba5042e2920b8712c6574ca6ea91e9ee5"
154dependencies = [ 153dependencies = [
155 "chalk-derive", 154 "chalk-derive",
156 "lazy_static", 155 "chalk-ir",
156 "chalk-solve",
157 "rustc-hash",
158 "tracing",
157] 159]
158 160
159[[package]] 161[[package]]
160name = "chalk-solve" 162name = "chalk-solve"
161version = "0.15.0" 163version = "0.19.0"
162source = "registry+https://github.com/rust-lang/crates.io-index" 164source = "registry+https://github.com/rust-lang/crates.io-index"
163checksum = "72c969c0fd06ad50538253327ca3445ff02cc9d0209f94c3cbf198ad9d365b48" 165checksum = "281f82facd2538997fbe52132b1941ed213d266748215c31d15f62a8664429ad"
164dependencies = [ 166dependencies = [
165 "chalk-derive", 167 "chalk-derive",
166 "chalk-engine",
167 "chalk-ir", 168 "chalk-ir",
168 "ena", 169 "ena",
169 "itertools", 170 "itertools",
@@ -171,13 +172,14 @@ dependencies = [
171 "rustc-hash", 172 "rustc-hash",
172 "tracing", 173 "tracing",
173 "tracing-subscriber", 174 "tracing-subscriber",
175 "tracing-tree",
174] 176]
175 177
176[[package]] 178[[package]]
177name = "chrono" 179name = "chrono"
178version = "0.4.11" 180version = "0.4.13"
179source = "registry+https://github.com/rust-lang/crates.io-index" 181source = "registry+https://github.com/rust-lang/crates.io-index"
180checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 182checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
181dependencies = [ 183dependencies = [
182 "num-integer", 184 "num-integer",
183 "num-traits", 185 "num-traits",
@@ -194,41 +196,31 @@ dependencies = [
194] 196]
195 197
196[[package]] 198[[package]]
197name = "console" 199name = "cmake"
198version = "0.11.3" 200version = "0.1.44"
199source = "registry+https://github.com/rust-lang/crates.io-index" 201source = "registry+https://github.com/rust-lang/crates.io-index"
200checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a" 202checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb"
201dependencies = [ 203dependencies = [
202 "encode_unicode", 204 "cc",
203 "lazy_static",
204 "libc",
205 "terminal_size",
206 "termios",
207 "winapi 0.3.9",
208] 205]
209 206
210[[package]] 207[[package]]
211name = "crossbeam" 208name = "crc32fast"
212version = "0.7.3" 209version = "1.2.0"
213source = "registry+https://github.com/rust-lang/crates.io-index" 210source = "registry+https://github.com/rust-lang/crates.io-index"
214checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" 211checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
215dependencies = [ 212dependencies = [
216 "cfg-if", 213 "cfg-if",
217 "crossbeam-channel",
218 "crossbeam-deque",
219 "crossbeam-epoch",
220 "crossbeam-queue",
221 "crossbeam-utils",
222] 214]
223 215
224[[package]] 216[[package]]
225name = "crossbeam-channel" 217name = "crossbeam-channel"
226version = "0.4.2" 218version = "0.4.3"
227source = "registry+https://github.com/rust-lang/crates.io-index" 219source = "registry+https://github.com/rust-lang/crates.io-index"
228checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" 220checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
229dependencies = [ 221dependencies = [
222 "cfg-if",
230 "crossbeam-utils", 223 "crossbeam-utils",
231 "maybe-uninit",
232] 224]
233 225
234[[package]] 226[[package]]
@@ -292,12 +284,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
292checksum = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" 284checksum = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f"
293 285
294[[package]] 286[[package]]
295name = "dtoa"
296version = "0.4.6"
297source = "registry+https://github.com/rust-lang/crates.io-index"
298checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
299
300[[package]]
301name = "either" 287name = "either"
302version = "1.5.3" 288version = "1.5.3"
303source = "registry+https://github.com/rust-lang/crates.io-index" 289source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -313,12 +299,6 @@ dependencies = [
313] 299]
314 300
315[[package]] 301[[package]]
316name = "encode_unicode"
317version = "0.3.6"
318source = "registry+https://github.com/rust-lang/crates.io-index"
319checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
320
321[[package]]
322name = "env_logger" 302name = "env_logger"
323version = "0.7.1" 303version = "0.7.1"
324source = "registry+https://github.com/rust-lang/crates.io-index" 304source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -328,10 +308,19 @@ dependencies = [
328] 308]
329 309
330[[package]] 310[[package]]
311name = "expect"
312version = "0.1.0"
313dependencies = [
314 "difference",
315 "once_cell",
316 "stdx",
317]
318
319[[package]]
331name = "filetime" 320name = "filetime"
332version = "0.2.10" 321version = "0.2.11"
333source = "registry+https://github.com/rust-lang/crates.io-index" 322source = "registry+https://github.com/rust-lang/crates.io-index"
334checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695" 323checksum = "e500da2fab70bdc43f8f0e0b350a227f31c72311c56aba48f01d5cd62bb0345b"
335dependencies = [ 324dependencies = [
336 "cfg-if", 325 "cfg-if",
337 "libc", 326 "libc",
@@ -346,6 +335,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
346checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" 335checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
347 336
348[[package]] 337[[package]]
338name = "flate2"
339version = "1.0.16"
340source = "registry+https://github.com/rust-lang/crates.io-index"
341checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
342dependencies = [
343 "cfg-if",
344 "crc32fast",
345 "libc",
346 "miniz_oxide",
347]
348
349[[package]]
349name = "flycheck" 350name = "flycheck"
350version = "0.1.0" 351version = "0.1.0"
351dependencies = [ 352dependencies = [
@@ -358,18 +359,6 @@ dependencies = [
358] 359]
359 360
360[[package]] 361[[package]]
361name = "fnv"
362version = "1.0.7"
363source = "registry+https://github.com/rust-lang/crates.io-index"
364checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
365
366[[package]]
367name = "fs_extra"
368version = "1.1.0"
369source = "registry+https://github.com/rust-lang/crates.io-index"
370checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
371
372[[package]]
373name = "fsevent" 362name = "fsevent"
374version = "2.0.2" 363version = "2.0.2"
375source = "registry+https://github.com/rust-lang/crates.io-index" 364source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -432,22 +421,9 @@ dependencies = [
432 421
433[[package]] 422[[package]]
434name = "gimli" 423name = "gimli"
435version = "0.21.0" 424version = "0.22.0"
436source = "registry+https://github.com/rust-lang/crates.io-index" 425source = "registry+https://github.com/rust-lang/crates.io-index"
437checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" 426checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
438
439[[package]]
440name = "globset"
441version = "0.4.5"
442source = "registry+https://github.com/rust-lang/crates.io-index"
443checksum = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
444dependencies = [
445 "aho-corasick",
446 "bstr",
447 "fnv",
448 "log",
449 "regex",
450]
451 427
452[[package]] 428[[package]]
453name = "goblin" 429name = "goblin"
@@ -461,6 +437,15 @@ dependencies = [
461] 437]
462 438
463[[package]] 439[[package]]
440name = "hashbrown"
441version = "0.8.1"
442source = "registry+https://github.com/rust-lang/crates.io-index"
443checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb"
444dependencies = [
445 "autocfg",
446]
447
448[[package]]
464name = "heck" 449name = "heck"
465version = "0.3.1" 450version = "0.3.1"
466source = "registry+https://github.com/rust-lang/crates.io-index" 451source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -471,9 +456,9 @@ dependencies = [
471 456
472[[package]] 457[[package]]
473name = "hermit-abi" 458name = "hermit-abi"
474version = "0.1.14" 459version = "0.1.15"
475source = "registry+https://github.com/rust-lang/crates.io-index" 460source = "registry+https://github.com/rust-lang/crates.io-index"
476checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" 461checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
477dependencies = [ 462dependencies = [
478 "libc", 463 "libc",
479] 464]
@@ -500,11 +485,12 @@ dependencies = [
500 485
501[[package]] 486[[package]]
502name = "indexmap" 487name = "indexmap"
503version = "1.4.0" 488version = "1.5.0"
504source = "registry+https://github.com/rust-lang/crates.io-index" 489source = "registry+https://github.com/rust-lang/crates.io-index"
505checksum = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe" 490checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7"
506dependencies = [ 491dependencies = [
507 "autocfg", 492 "autocfg",
493 "hashbrown",
508] 494]
509 495
510[[package]] 496[[package]]
@@ -528,24 +514,10 @@ dependencies = [
528] 514]
529 515
530[[package]] 516[[package]]
531name = "insta"
532version = "0.16.1"
533source = "registry+https://github.com/rust-lang/crates.io-index"
534checksum = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee"
535dependencies = [
536 "console",
537 "difference",
538 "lazy_static",
539 "serde",
540 "serde_json",
541 "serde_yaml",
542]
543
544[[package]]
545name = "instant" 517name = "instant"
546version = "0.1.5" 518version = "0.1.6"
547source = "registry+https://github.com/rust-lang/crates.io-index" 519source = "registry+https://github.com/rust-lang/crates.io-index"
548checksum = "69da7ce1490173c2bf4d26bc8be429aaeeaf4cce6c4b970b7949651fa17655fe" 520checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
549 521
550[[package]] 522[[package]]
551name = "iovec" 523name = "iovec"
@@ -572,38 +544,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
572checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 544checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
573 545
574[[package]] 546[[package]]
575name = "jemalloc-ctl"
576version = "0.3.3"
577source = "registry+https://github.com/rust-lang/crates.io-index"
578checksum = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7"
579dependencies = [
580 "jemalloc-sys",
581 "libc",
582 "paste",
583]
584
585[[package]]
586name = "jemalloc-sys"
587version = "0.3.2"
588source = "registry+https://github.com/rust-lang/crates.io-index"
589checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
590dependencies = [
591 "cc",
592 "fs_extra",
593 "libc",
594]
595
596[[package]]
597name = "jemallocator"
598version = "0.3.2"
599source = "registry+https://github.com/rust-lang/crates.io-index"
600checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
601dependencies = [
602 "jemalloc-sys",
603 "libc",
604]
605
606[[package]]
607name = "jod-thread" 547name = "jod-thread"
608version = "0.1.2" 548version = "0.1.2"
609source = "registry+https://github.com/rust-lang/crates.io-index" 549source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -633,9 +573,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
633 573
634[[package]] 574[[package]]
635name = "libc" 575name = "libc"
636version = "0.2.71" 576version = "0.2.74"
637source = "registry+https://github.com/rust-lang/crates.io-index" 577source = "registry+https://github.com/rust-lang/crates.io-index"
638checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" 578checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
639 579
640[[package]] 580[[package]]
641name = "libloading" 581name = "libloading"
@@ -647,25 +587,28 @@ dependencies = [
647] 587]
648 588
649[[package]] 589[[package]]
650name = "linked-hash-map" 590name = "libmimalloc-sys"
651version = "0.5.3" 591version = "0.1.15"
652source = "registry+https://github.com/rust-lang/crates.io-index" 592source = "registry+https://github.com/rust-lang/crates.io-index"
653checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" 593checksum = "a27252ec1d0c4e0dd6142cbc572da50b363ab56fc334f7aa8fadf295b2e24e74"
594dependencies = [
595 "cmake",
596]
654 597
655[[package]] 598[[package]]
656name = "lock_api" 599name = "lock_api"
657version = "0.4.0" 600version = "0.4.1"
658source = "registry+https://github.com/rust-lang/crates.io-index" 601source = "registry+https://github.com/rust-lang/crates.io-index"
659checksum = "de302ce1fe7482db13738fbaf2e21cfb06a986b89c0bf38d88abf16681aada4e" 602checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
660dependencies = [ 603dependencies = [
661 "scopeguard", 604 "scopeguard",
662] 605]
663 606
664[[package]] 607[[package]]
665name = "log" 608name = "log"
666version = "0.4.8" 609version = "0.4.11"
667source = "registry+https://github.com/rust-lang/crates.io-index" 610source = "registry+https://github.com/rust-lang/crates.io-index"
668checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 611checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
669dependencies = [ 612dependencies = [
670 "cfg-if", 613 "cfg-if",
671] 614]
@@ -684,9 +627,9 @@ dependencies = [
684 627
685[[package]] 628[[package]]
686name = "lsp-types" 629name = "lsp-types"
687version = "0.74.2" 630version = "0.79.0"
688source = "registry+https://github.com/rust-lang/crates.io-index" 631source = "registry+https://github.com/rust-lang/crates.io-index"
689checksum = "b360754e89e0e13c114245131382ba921d4ff1efabb918e549422938aaa8d392" 632checksum = "7f1f86677fdbe8df5f88b99131b1424e50aad27bbe3e5900d221bc414bd72e9b"
690dependencies = [ 633dependencies = [
691 "base64", 634 "base64",
692 "bitflags", 635 "bitflags",
@@ -741,20 +684,29 @@ dependencies = [
741 684
742[[package]] 685[[package]]
743name = "memoffset" 686name = "memoffset"
744version = "0.5.4" 687version = "0.5.5"
745source = "registry+https://github.com/rust-lang/crates.io-index" 688source = "registry+https://github.com/rust-lang/crates.io-index"
746checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" 689checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f"
747dependencies = [ 690dependencies = [
748 "autocfg", 691 "autocfg",
749] 692]
750 693
751[[package]] 694[[package]]
695name = "mimalloc"
696version = "0.1.19"
697source = "registry+https://github.com/rust-lang/crates.io-index"
698checksum = "6c52de2069999f01bd26436564dbe7de3a87898feeb7a0d0ff9eb20a05bb7ca0"
699dependencies = [
700 "libmimalloc-sys",
701]
702
703[[package]]
752name = "miniz_oxide" 704name = "miniz_oxide"
753version = "0.3.7" 705version = "0.4.0"
754source = "registry+https://github.com/rust-lang/crates.io-index" 706source = "registry+https://github.com/rust-lang/crates.io-index"
755checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" 707checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
756dependencies = [ 708dependencies = [
757 "adler32", 709 "adler",
758] 710]
759 711
760[[package]] 712[[package]]
@@ -873,6 +825,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
873checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" 825checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
874 826
875[[package]] 827[[package]]
828name = "oorandom"
829version = "11.1.2"
830source = "registry+https://github.com/rust-lang/crates.io-index"
831checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c"
832
833[[package]]
876name = "parking_lot" 834name = "parking_lot"
877version = "0.11.0" 835version = "0.11.0"
878source = "registry+https://github.com/rust-lang/crates.io-index" 836source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -899,33 +857,33 @@ dependencies = [
899] 857]
900 858
901[[package]] 859[[package]]
902name = "paste" 860name = "paths"
903version = "0.1.18" 861version = "0.1.0"
862
863[[package]]
864name = "percent-encoding"
865version = "2.1.0"
904source = "registry+https://github.com/rust-lang/crates.io-index" 866source = "registry+https://github.com/rust-lang/crates.io-index"
905checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" 867checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
906dependencies = [
907 "paste-impl",
908 "proc-macro-hack",
909]
910 868
911[[package]] 869[[package]]
912name = "paste-impl" 870name = "perf-event"
913version = "0.1.18" 871version = "0.4.4"
914source = "registry+https://github.com/rust-lang/crates.io-index" 872source = "registry+https://github.com/rust-lang/crates.io-index"
915checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" 873checksum = "76c42ba5d85a2f4472b99f475fb60cf336d9b4c85b1ea8bb300fef2e3c7c8f89"
916dependencies = [ 874dependencies = [
917 "proc-macro-hack", 875 "libc",
876 "perf-event-open-sys",
918] 877]
919 878
920[[package]] 879[[package]]
921name = "paths" 880name = "perf-event-open-sys"
922version = "0.1.0" 881version = "0.3.1"
923
924[[package]]
925name = "percent-encoding"
926version = "2.1.0"
927source = "registry+https://github.com/rust-lang/crates.io-index" 882source = "registry+https://github.com/rust-lang/crates.io-index"
928checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 883checksum = "95db63e37862bc1b842135d2234ef9418f222cc660c6752f45e7cf9ddfb97f96"
884dependencies = [
885 "libc",
886]
929 887
930[[package]] 888[[package]]
931name = "petgraph" 889name = "petgraph"
@@ -956,25 +914,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
956checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" 914checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
957 915
958[[package]] 916[[package]]
959name = "proc-macro-hack"
960version = "0.5.16"
961source = "registry+https://github.com/rust-lang/crates.io-index"
962checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
963
964[[package]]
965name = "proc-macro2" 917name = "proc-macro2"
966version = "1.0.18" 918version = "1.0.19"
967source = "registry+https://github.com/rust-lang/crates.io-index" 919source = "registry+https://github.com/rust-lang/crates.io-index"
968checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" 920checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
969dependencies = [ 921dependencies = [
970 "unicode-xid", 922 "unicode-xid",
971] 923]
972 924
973[[package]] 925[[package]]
974name = "pulldown-cmark" 926name = "pulldown-cmark"
975version = "0.7.1" 927version = "0.7.2"
976source = "registry+https://github.com/rust-lang/crates.io-index" 928source = "registry+https://github.com/rust-lang/crates.io-index"
977checksum = "3e142c3b8f49d2200605ee6ba0b1d757310e9e7a72afe78c36ee2ef67300ee00" 929checksum = "ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"
978dependencies = [ 930dependencies = [
979 "bitflags", 931 "bitflags",
980 "getopts", 932 "getopts",
@@ -1040,7 +992,6 @@ dependencies = [
1040 "ra_prof", 992 "ra_prof",
1041 "ra_syntax", 993 "ra_syntax",
1042 "ra_tt", 994 "ra_tt",
1043 "relative-path",
1044 "rustc-hash", 995 "rustc-hash",
1045 "salsa", 996 "salsa",
1046 "stdx", 997 "stdx",
@@ -1071,6 +1022,7 @@ dependencies = [
1071 "ra_prof", 1022 "ra_prof",
1072 "ra_syntax", 1023 "ra_syntax",
1073 "rustc-hash", 1024 "rustc-hash",
1025 "stdx",
1074] 1026]
1075 1027
1076[[package]] 1028[[package]]
@@ -1080,9 +1032,9 @@ dependencies = [
1080 "anymap", 1032 "anymap",
1081 "drop_bomb", 1033 "drop_bomb",
1082 "either", 1034 "either",
1035 "expect",
1083 "fst", 1036 "fst",
1084 "indexmap", 1037 "indexmap",
1085 "insta",
1086 "itertools", 1038 "itertools",
1087 "log", 1039 "log",
1088 "once_cell", 1040 "once_cell",
@@ -1123,9 +1075,10 @@ version = "0.1.0"
1123dependencies = [ 1075dependencies = [
1124 "arrayvec", 1076 "arrayvec",
1125 "chalk-ir", 1077 "chalk-ir",
1078 "chalk-recursive",
1126 "chalk-solve", 1079 "chalk-solve",
1127 "ena", 1080 "ena",
1128 "insta", 1081 "expect",
1129 "itertools", 1082 "itertools",
1130 "log", 1083 "log",
1131 "ra_arena", 1084 "ra_arena",
@@ -1139,6 +1092,9 @@ dependencies = [
1139 "smallvec", 1092 "smallvec",
1140 "stdx", 1093 "stdx",
1141 "test_utils", 1094 "test_utils",
1095 "tracing",
1096 "tracing-subscriber",
1097 "tracing-tree",
1142] 1098]
1143 1099
1144[[package]] 1100[[package]]
@@ -1146,12 +1102,13 @@ name = "ra_ide"
1146version = "0.1.0" 1102version = "0.1.0"
1147dependencies = [ 1103dependencies = [
1148 "either", 1104 "either",
1105 "expect",
1149 "indexmap", 1106 "indexmap",
1150 "insta",
1151 "itertools", 1107 "itertools",
1152 "lazy_static", 1108 "lazy_static",
1153 "log", 1109 "log",
1154 "maplit", 1110 "maplit",
1111 "oorandom",
1155 "pulldown-cmark", 1112 "pulldown-cmark",
1156 "pulldown-cmark-to-cmark", 1113 "pulldown-cmark-to-cmark",
1157 "ra_assists", 1114 "ra_assists",
@@ -1190,7 +1147,7 @@ dependencies = [
1190 "ra_text_edit", 1147 "ra_text_edit",
1191 "rayon", 1148 "rayon",
1192 "rustc-hash", 1149 "rustc-hash",
1193 "superslice", 1150 "stdx",
1194 "test_utils", 1151 "test_utils",
1195] 1152]
1196 1153
@@ -1248,9 +1205,10 @@ name = "ra_prof"
1248version = "0.1.0" 1205version = "0.1.0"
1249dependencies = [ 1206dependencies = [
1250 "backtrace", 1207 "backtrace",
1251 "jemalloc-ctl", 1208 "cfg-if",
1252 "jemallocator", 1209 "libc",
1253 "once_cell", 1210 "once_cell",
1211 "perf-event",
1254 "ra_arena", 1212 "ra_arena",
1255] 1213]
1256 1214
@@ -1277,12 +1235,14 @@ dependencies = [
1277name = "ra_ssr" 1235name = "ra_ssr"
1278version = "0.1.0" 1236version = "0.1.0"
1279dependencies = [ 1237dependencies = [
1238 "expect",
1280 "ra_db", 1239 "ra_db",
1281 "ra_hir", 1240 "ra_hir",
1282 "ra_ide_db", 1241 "ra_ide_db",
1283 "ra_syntax", 1242 "ra_syntax",
1284 "ra_text_edit", 1243 "ra_text_edit",
1285 "rustc-hash", 1244 "rustc-hash",
1245 "test_utils",
1286] 1246]
1287 1247
1288[[package]] 1248[[package]]
@@ -1290,10 +1250,12 @@ name = "ra_syntax"
1290version = "0.1.0" 1250version = "0.1.0"
1291dependencies = [ 1251dependencies = [
1292 "arrayvec", 1252 "arrayvec",
1253 "expect",
1293 "itertools", 1254 "itertools",
1294 "once_cell", 1255 "once_cell",
1295 "ra_parser", 1256 "ra_parser",
1296 "ra_text_edit", 1257 "ra_text_edit",
1258 "rayon",
1297 "rowan", 1259 "rowan",
1298 "rustc-ap-rustc_lexer", 1260 "rustc-ap-rustc_lexer",
1299 "rustc-hash", 1261 "rustc-hash",
@@ -1323,6 +1285,7 @@ name = "ra_tt"
1323version = "0.1.0" 1285version = "0.1.0"
1324dependencies = [ 1286dependencies = [
1325 "smol_str", 1287 "smol_str",
1288 "stdx",
1326] 1289]
1327 1290
1328[[package]] 1291[[package]]
@@ -1403,9 +1366,9 @@ dependencies = [
1403 1366
1404[[package]] 1367[[package]]
1405name = "redox_syscall" 1368name = "redox_syscall"
1406version = "0.1.56" 1369version = "0.1.57"
1407source = "registry+https://github.com/rust-lang/crates.io-index" 1370source = "registry+https://github.com/rust-lang/crates.io-index"
1408checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1371checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
1409 1372
1410[[package]] 1373[[package]]
1411name = "regex" 1374name = "regex"
@@ -1436,21 +1399,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1436checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" 1399checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
1437 1400
1438[[package]] 1401[[package]]
1439name = "relative-path"
1440version = "1.2.1"
1441source = "registry+https://github.com/rust-lang/crates.io-index"
1442checksum = "c602122c47b382cd045b10866a084b184035d45d8c2609cdd3762852ddfae2a1"
1443
1444[[package]]
1445name = "remove_dir_all"
1446version = "0.5.3"
1447source = "registry+https://github.com/rust-lang/crates.io-index"
1448checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
1449dependencies = [
1450 "winapi 0.3.9",
1451]
1452
1453[[package]]
1454name = "rowan" 1402name = "rowan"
1455version = "0.10.0" 1403version = "0.10.0"
1456source = "registry+https://github.com/rust-lang/crates.io-index" 1404source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1469,14 +1417,15 @@ dependencies = [
1469 "anyhow", 1417 "anyhow",
1470 "crossbeam-channel", 1418 "crossbeam-channel",
1471 "env_logger", 1419 "env_logger",
1420 "expect",
1472 "flycheck", 1421 "flycheck",
1473 "globset",
1474 "insta",
1475 "itertools", 1422 "itertools",
1476 "jod-thread", 1423 "jod-thread",
1477 "log", 1424 "log",
1478 "lsp-server", 1425 "lsp-server",
1479 "lsp-types", 1426 "lsp-types",
1427 "mimalloc",
1428 "oorandom",
1480 "parking_lot", 1429 "parking_lot",
1481 "pico-args", 1430 "pico-args",
1482 "ra_cfg", 1431 "ra_cfg",
@@ -1495,12 +1444,11 @@ dependencies = [
1495 "ra_text_edit", 1444 "ra_text_edit",
1496 "ra_toolchain", 1445 "ra_toolchain",
1497 "ra_tt", 1446 "ra_tt",
1498 "rand", 1447 "rayon",
1499 "rustc-hash", 1448 "rustc-hash",
1500 "serde", 1449 "serde",
1501 "serde_json", 1450 "serde_json",
1502 "stdx", 1451 "stdx",
1503 "tempfile",
1504 "test_utils", 1452 "test_utils",
1505 "threadpool", 1453 "threadpool",
1506 "vfs", 1454 "vfs",
@@ -1510,9 +1458,9 @@ dependencies = [
1510 1458
1511[[package]] 1459[[package]]
1512name = "rustc-ap-rustc_lexer" 1460name = "rustc-ap-rustc_lexer"
1513version = "666.0.0" 1461version = "671.0.0"
1514source = "registry+https://github.com/rust-lang/crates.io-index" 1462source = "registry+https://github.com/rust-lang/crates.io-index"
1515checksum = "4e00c526f9f8430ea4cd2178d25b02bfc7debe6677350c57292f92f50e65d2fe" 1463checksum = "22e1221f3bfa2943c942cf8da319ab2346887f8757778c29c7f1822cd27b521f"
1516dependencies = [ 1464dependencies = [
1517 "unicode-xid", 1465 "unicode-xid",
1518] 1466]
@@ -1537,15 +1485,16 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
1537 1485
1538[[package]] 1486[[package]]
1539name = "salsa" 1487name = "salsa"
1540version = "0.14.2" 1488version = "0.15.1"
1541source = "registry+https://github.com/rust-lang/crates.io-index" 1489source = "registry+https://github.com/rust-lang/crates.io-index"
1542checksum = "6a976dce155e392af3f1aa540ca23a6fc7303a7fef425cb431c464deb263eb54" 1490checksum = "d4cdc109fcc9e9450c7ef47fb7474e99bffd51799da03ed0a6c7f0e2cb3848a6"
1543dependencies = [ 1491dependencies = [
1544 "crossbeam", 1492 "crossbeam-utils",
1545 "indexmap", 1493 "indexmap",
1494 "lock_api",
1546 "log", 1495 "log",
1496 "oorandom",
1547 "parking_lot", 1497 "parking_lot",
1548 "rand",
1549 "rustc-hash", 1498 "rustc-hash",
1550 "salsa-macros", 1499 "salsa-macros",
1551 "smallvec", 1500 "smallvec",
@@ -1553,9 +1502,9 @@ dependencies = [
1553 1502
1554[[package]] 1503[[package]]
1555name = "salsa-macros" 1504name = "salsa-macros"
1556version = "0.14.1" 1505version = "0.15.0"
1557source = "registry+https://github.com/rust-lang/crates.io-index" 1506source = "registry+https://github.com/rust-lang/crates.io-index"
1558checksum = "038a09b6271446f1123f142fe7e5bef6d4687c4cf82e6986be574c2af3745530" 1507checksum = "2c280ac85b15ac214b86ac4b407626a48e6a1c4f90769a582fec74aa57942b9f"
1559dependencies = [ 1508dependencies = [
1560 "heck", 1509 "heck",
1561 "proc-macro2", 1510 "proc-macro2",
@@ -1606,9 +1555,9 @@ dependencies = [
1606 1555
1607[[package]] 1556[[package]]
1608name = "semver" 1557name = "semver"
1609version = "0.9.0" 1558version = "0.10.0"
1610source = "registry+https://github.com/rust-lang/crates.io-index" 1559source = "registry+https://github.com/rust-lang/crates.io-index"
1611checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1560checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190"
1612dependencies = [ 1561dependencies = [
1613 "semver-parser", 1562 "semver-parser",
1614 "serde", 1563 "serde",
@@ -1642,9 +1591,9 @@ dependencies = [
1642 1591
1643[[package]] 1592[[package]]
1644name = "serde_json" 1593name = "serde_json"
1645version = "1.0.56" 1594version = "1.0.57"
1646source = "registry+https://github.com/rust-lang/crates.io-index" 1595source = "registry+https://github.com/rust-lang/crates.io-index"
1647checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" 1596checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
1648dependencies = [ 1597dependencies = [
1649 "itoa", 1598 "itoa",
1650 "ryu", 1599 "ryu",
@@ -1663,18 +1612,6 @@ dependencies = [
1663] 1612]
1664 1613
1665[[package]] 1614[[package]]
1666name = "serde_yaml"
1667version = "0.8.13"
1668source = "registry+https://github.com/rust-lang/crates.io-index"
1669checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
1670dependencies = [
1671 "dtoa",
1672 "linked-hash-map",
1673 "serde",
1674 "yaml-rust",
1675]
1676
1677[[package]]
1678name = "sharded-slab" 1615name = "sharded-slab"
1679version = "0.0.9" 1616version = "0.0.9"
1680source = "registry+https://github.com/rust-lang/crates.io-index" 1617source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1691,15 +1628,15 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1691 1628
1692[[package]] 1629[[package]]
1693name = "smallvec" 1630name = "smallvec"
1694version = "1.4.0" 1631version = "1.4.1"
1695source = "registry+https://github.com/rust-lang/crates.io-index" 1632source = "registry+https://github.com/rust-lang/crates.io-index"
1696checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" 1633checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f"
1697 1634
1698[[package]] 1635[[package]]
1699name = "smol_str" 1636name = "smol_str"
1700version = "0.1.15" 1637version = "0.1.16"
1701source = "registry+https://github.com/rust-lang/crates.io-index" 1638source = "registry+https://github.com/rust-lang/crates.io-index"
1702checksum = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" 1639checksum = "2f7909a1d8bc166a862124d84fdc11bda0ea4ed3157ccca662296919c2972db1"
1703dependencies = [ 1640dependencies = [
1704 "serde", 1641 "serde",
1705] 1642]
@@ -1709,16 +1646,10 @@ name = "stdx"
1709version = "0.1.0" 1646version = "0.1.0"
1710 1647
1711[[package]] 1648[[package]]
1712name = "superslice"
1713version = "1.0.0"
1714source = "registry+https://github.com/rust-lang/crates.io-index"
1715checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1716
1717[[package]]
1718name = "syn" 1649name = "syn"
1719version = "1.0.33" 1650version = "1.0.36"
1720source = "registry+https://github.com/rust-lang/crates.io-index" 1651source = "registry+https://github.com/rust-lang/crates.io-index"
1721checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" 1652checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
1722dependencies = [ 1653dependencies = [
1723 "proc-macro2", 1654 "proc-macro2",
1724 "quote", 1655 "quote",
@@ -1738,36 +1669,12 @@ dependencies = [
1738] 1669]
1739 1670
1740[[package]] 1671[[package]]
1741name = "tempfile" 1672name = "termcolor"
1742version = "3.1.0" 1673version = "1.1.0"
1743source = "registry+https://github.com/rust-lang/crates.io-index"
1744checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
1745dependencies = [
1746 "cfg-if",
1747 "libc",
1748 "rand",
1749 "redox_syscall",
1750 "remove_dir_all",
1751 "winapi 0.3.9",
1752]
1753
1754[[package]]
1755name = "terminal_size"
1756version = "0.1.12"
1757source = "registry+https://github.com/rust-lang/crates.io-index"
1758checksum = "8038f95fc7a6f351163f4b964af631bd26c9e828f7db085f2a84aca56f70d13b"
1759dependencies = [
1760 "libc",
1761 "winapi 0.3.9",
1762]
1763
1764[[package]]
1765name = "termios"
1766version = "0.3.2"
1767source = "registry+https://github.com/rust-lang/crates.io-index" 1674source = "registry+https://github.com/rust-lang/crates.io-index"
1768checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2" 1675checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
1769dependencies = [ 1676dependencies = [
1770 "libc", 1677 "winapi-util",
1771] 1678]
1772 1679
1773[[package]] 1680[[package]]
@@ -1829,9 +1736,9 @@ checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
1829 1736
1830[[package]] 1737[[package]]
1831name = "tracing" 1738name = "tracing"
1832version = "0.1.15" 1739version = "0.1.17"
1833source = "registry+https://github.com/rust-lang/crates.io-index" 1740source = "registry+https://github.com/rust-lang/crates.io-index"
1834checksum = "a41f40ed0e162c911ac6fcb53ecdc8134c46905fdbbae8c50add462a538b495f" 1741checksum = "dbdf4ccd1652592b01286a5dbe1e2a77d78afaa34beadd9872a5f7396f92aaa9"
1835dependencies = [ 1742dependencies = [
1836 "cfg-if", 1743 "cfg-if",
1837 "tracing-attributes", 1744 "tracing-attributes",
@@ -1840,9 +1747,9 @@ dependencies = [
1840 1747
1841[[package]] 1748[[package]]
1842name = "tracing-attributes" 1749name = "tracing-attributes"
1843version = "0.1.8" 1750version = "0.1.9"
1844source = "registry+https://github.com/rust-lang/crates.io-index" 1751source = "registry+https://github.com/rust-lang/crates.io-index"
1845checksum = "99bbad0de3fd923c9c3232ead88510b783e5a4d16a6154adffa3d53308de984c" 1752checksum = "f0693bf8d6f2bf22c690fc61a9d21ac69efdbb894a17ed596b9af0f01e64b84b"
1846dependencies = [ 1753dependencies = [
1847 "proc-macro2", 1754 "proc-macro2",
1848 "quote", 1755 "quote",
@@ -1851,9 +1758,9 @@ dependencies = [
1851 1758
1852[[package]] 1759[[package]]
1853name = "tracing-core" 1760name = "tracing-core"
1854version = "0.1.10" 1761version = "0.1.11"
1855source = "registry+https://github.com/rust-lang/crates.io-index" 1762source = "registry+https://github.com/rust-lang/crates.io-index"
1856checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" 1763checksum = "94ae75f0d28ae10786f3b1895c55fe72e79928fd5ccdebb5438c75e93fec178f"
1857dependencies = [ 1764dependencies = [
1858 "lazy_static", 1765 "lazy_static",
1859] 1766]
@@ -1881,9 +1788,9 @@ dependencies = [
1881 1788
1882[[package]] 1789[[package]]
1883name = "tracing-subscriber" 1790name = "tracing-subscriber"
1884version = "0.2.6" 1791version = "0.2.9"
1885source = "registry+https://github.com/rust-lang/crates.io-index" 1792source = "registry+https://github.com/rust-lang/crates.io-index"
1886checksum = "04a11b459109e38ff6e1b580bafef4142a11d44889f5d07424cbce2fd2a2a119" 1793checksum = "e4f5dd7095c2481b7b3cbed71c8de53085fb3542bc3c2b4c73cba43e8f11c7ba"
1887dependencies = [ 1794dependencies = [
1888 "ansi_term", 1795 "ansi_term",
1889 "chrono", 1796 "chrono",
@@ -1900,6 +1807,26 @@ dependencies = [
1900] 1807]
1901 1808
1902[[package]] 1809[[package]]
1810name = "tracing-tree"
1811version = "0.1.4"
1812source = "registry+https://github.com/rust-lang/crates.io-index"
1813checksum = "37ee7f0f53ed2093971a698db799ef56a2dfd89b32e3aeb5165f0e637a02be04"
1814dependencies = [
1815 "ansi_term",
1816 "atty",
1817 "chrono",
1818 "termcolor",
1819 "tracing",
1820 "tracing-subscriber",
1821]
1822
1823[[package]]
1824name = "ungrammar"
1825version = "0.1.0"
1826source = "registry+https://github.com/rust-lang/crates.io-index"
1827checksum = "0ee12e4891ab3acc2d95d5023022ace22020247bb8a8d1ece875a443f7dab37d"
1828
1829[[package]]
1903name = "unicase" 1830name = "unicase"
1904version = "2.6.0" 1831version = "2.6.0"
1905source = "registry+https://github.com/rust-lang/crates.io-index" 1832source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1966,6 +1893,7 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1966name = "vfs" 1893name = "vfs"
1967version = "0.1.0" 1894version = "0.1.0"
1968dependencies = [ 1895dependencies = [
1896 "fst",
1969 "paths", 1897 "paths",
1970 "rustc-hash", 1898 "rustc-hash",
1971] 1899]
@@ -1975,7 +1903,6 @@ name = "vfs-notify"
1975version = "0.1.0" 1903version = "0.1.0"
1976dependencies = [ 1904dependencies = [
1977 "crossbeam-channel", 1905 "crossbeam-channel",
1978 "globset",
1979 "jod-thread", 1906 "jod-thread",
1980 "log", 1907 "log",
1981 "notify", 1908 "notify",
@@ -2060,17 +1987,10 @@ name = "xtask"
2060version = "0.1.0" 1987version = "0.1.0"
2061dependencies = [ 1988dependencies = [
2062 "anyhow", 1989 "anyhow",
1990 "flate2",
2063 "pico-args", 1991 "pico-args",
2064 "proc-macro2", 1992 "proc-macro2",
2065 "quote", 1993 "quote",
1994 "ungrammar",
2066 "walkdir", 1995 "walkdir",
2067] 1996]
2068
2069[[package]]
2070name = "yaml-rust"
2071version = "0.4.4"
2072source = "registry+https://github.com/rust-lang/crates.io-index"
2073checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
2074dependencies = [
2075 "linked-hash-map",
2076]
diff --git a/Cargo.toml b/Cargo.toml
index 5278b5a16..612e6809f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,9 +24,16 @@ opt-level = 0
24opt-level = 0 24opt-level = 0
25[profile.release.package.salsa-macros] 25[profile.release.package.salsa-macros]
26opt-level = 0 26opt-level = 0
27[profile.release.package.tracing-attributes]
28opt-level = 0
27[profile.release.package.xtask] 29[profile.release.package.xtask]
28opt-level = 0 30opt-level = 0
29 31
32# Gzipping the artifacts is up to 10 times faster with optimizations (`cargo xtask dist`).
33# `miniz_oxide` is the direct dependency of `flate2` which does all the heavy lifting
34[profile.dev.package.miniz_oxide]
35opt-level = 3
36
30[patch.'crates-io'] 37[patch.'crates-io']
31# rowan = { path = "../rowan" } 38# rowan = { path = "../rowan" }
32 39
diff --git a/README.md b/README.md
index 7ba705e73..16c980400 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,8 @@
2 <img src="https://user-images.githubusercontent.com/1711539/72443316-5a79f280-37ae-11ea-858f-035209ece2dd.png" alt="rust-analyzer logo"> 2 <img src="https://user-images.githubusercontent.com/1711539/72443316-5a79f280-37ae-11ea-858f-035209ece2dd.png" alt="rust-analyzer logo">
3</p> 3</p>
4 4
5rust-analyzer is an **experimental** modular compiler frontend for the Rust 5rust-analyzer is an **experimental** modular compiler frontend for the Rust language.
6language. It is a part of a larger rls-2.0 effort to create excellent IDE 6It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust.
7support for Rust. If you want to get involved, check the rls-2.0 working group:
8
9https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
10 7
11Work on rust-analyzer is sponsored by 8Work on rust-analyzer is sponsored by
12 9
@@ -25,8 +22,8 @@ If you want to **contribute** to rust-analyzer or are just curious about how
25things work under the hood, check the [./docs/dev](./docs/dev) folder. 22things work under the hood, check the [./docs/dev](./docs/dev) folder.
26 23
27If you want to **use** rust-analyzer's language server with your editor of 24If you want to **use** rust-analyzer's language server with your editor of
28choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. It also contains some tips & tricks to help 25choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder.
29you be more productive when using rust-analyzer. 26It also contains some tips & tricks to help you be more productive when using rust-analyzer.
30 27
31## Communication 28## Communication
32 29
@@ -40,8 +37,9 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
40 37
41## Quick Links 38## Quick Links
42 39
43* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide/
44* Website: https://rust-analyzer.github.io/ 40* Website: https://rust-analyzer.github.io/
41* Metrics: https://rust-analyzer.github.io/metrics/
42* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide/
45 43
46## License 44## License
47 45
diff --git a/crates/expect/Cargo.toml b/crates/expect/Cargo.toml
new file mode 100644
index 000000000..77775630d
--- /dev/null
+++ b/crates/expect/Cargo.toml
@@ -0,0 +1,14 @@
1[package]
2name = "expect"
3version = "0.1.0"
4authors = ["rust-analyzer developers"]
5edition = "2018"
6license = "MIT OR Apache-2.0"
7
8[lib]
9doctest = false
10
11[dependencies]
12once_cell = "1"
13difference = "2"
14stdx = { path = "../stdx" }
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
new file mode 100644
index 000000000..21a458d47
--- /dev/null
+++ b/crates/expect/src/lib.rs
@@ -0,0 +1,356 @@
1//! Snapshot testing library, see
2//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
3use std::{
4 collections::HashMap,
5 env, fmt, fs, mem,
6 ops::Range,
7 panic,
8 path::{Path, PathBuf},
9 sync::Mutex,
10};
11
12use difference::Changeset;
13use once_cell::sync::Lazy;
14use stdx::{lines_with_ends, trim_indent};
15
16const HELP: &str = "
17You can update all `expect![[]]` tests by running:
18
19 env UPDATE_EXPECT=1 cargo test
20
21To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
22";
23
24fn update_expect() -> bool {
25 env::var("UPDATE_EXPECT").is_ok()
26}
27
28/// expect![[r#"inline snapshot"#]]
29#[macro_export]
30macro_rules! expect {
31 [[$data:literal]] => {$crate::Expect {
32 position: $crate::Position {
33 file: file!(),
34 line: line!(),
35 column: column!(),
36 },
37 data: $data,
38 }};
39 [[]] => { $crate::expect![[""]] };
40}
41
42/// expect_file!["/crates/foo/test_data/bar.html"]
43#[macro_export]
44macro_rules! expect_file {
45 [$path:expr] => {$crate::ExpectFile {
46 path: std::path::PathBuf::from($path)
47 }};
48}
49
50#[derive(Debug)]
51pub struct Expect {
52 pub position: Position,
53 pub data: &'static str,
54}
55
56#[derive(Debug)]
57pub struct ExpectFile {
58 pub path: PathBuf,
59}
60
61#[derive(Debug)]
62pub struct Position {
63 pub file: &'static str,
64 pub line: u32,
65 pub column: u32,
66}
67
68impl fmt::Display for Position {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{}:{}:{}", self.file, self.line, self.column)
71 }
72}
73
74impl Expect {
75 pub fn assert_eq(&self, actual: &str) {
76 let trimmed = self.trimmed();
77 if &trimmed == actual {
78 return;
79 }
80 Runtime::fail_expect(self, &trimmed, actual);
81 }
82 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
83 let actual = format!("{:#?}\n", actual);
84 self.assert_eq(&actual)
85 }
86
87 fn trimmed(&self) -> String {
88 if !self.data.contains('\n') {
89 return self.data.to_string();
90 }
91 trim_indent(self.data)
92 }
93
94 fn locate(&self, file: &str) -> Location {
95 let mut target_line = None;
96 let mut line_start = 0;
97 for (i, line) in lines_with_ends(file).enumerate() {
98 if i == self.position.line as usize - 1 {
99 let pat = "expect![[";
100 let offset = line.find(pat).unwrap();
101 let literal_start = line_start + offset + pat.len();
102 let indent = line.chars().take_while(|&it| it == ' ').count();
103 target_line = Some((literal_start, indent));
104 break;
105 }
106 line_start += line.len();
107 }
108 let (literal_start, line_indent) = target_line.unwrap();
109 let literal_length =
110 file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
111 let literal_range = literal_start..literal_start + literal_length;
112 Location { line_indent, literal_range }
113 }
114}
115
116impl ExpectFile {
117 pub fn assert_eq(&self, actual: &str) {
118 let expected = self.read();
119 if actual == expected {
120 return;
121 }
122 Runtime::fail_file(self, &expected, actual);
123 }
124 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
125 let actual = format!("{:#?}\n", actual);
126 self.assert_eq(&actual)
127 }
128 fn read(&self) -> String {
129 fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
130 }
131 fn write(&self, contents: &str) {
132 fs::write(self.abs_path(), contents).unwrap()
133 }
134 fn abs_path(&self) -> PathBuf {
135 WORKSPACE_ROOT.join(&self.path)
136 }
137}
138
139#[derive(Default)]
140struct Runtime {
141 help_printed: bool,
142 per_file: HashMap<&'static str, FileRuntime>,
143}
144static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);
145
146impl Runtime {
147 fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
148 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
149 if update_expect() {
150 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
151 rt.per_file
152 .entry(expect.position.file)
153 .or_insert_with(|| FileRuntime::new(expect))
154 .update(expect, actual);
155 return;
156 }
157 rt.panic(expect.position.to_string(), expected, actual);
158 }
159
160 fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
161 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
162 if update_expect() {
163 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path.display());
164 expect.write(actual);
165 return;
166 }
167 rt.panic(expect.path.display().to_string(), expected, actual);
168 }
169
170 fn panic(&mut self, position: String, expected: &str, actual: &str) {
171 let print_help = !mem::replace(&mut self.help_printed, true);
172 let help = if print_help { HELP } else { "" };
173
174 let diff = Changeset::new(actual, expected, "\n");
175
176 println!(
177 "\n
178\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m
179 \x1b[1m\x1b[34m-->\x1b[0m {}
180{}
181\x1b[1mExpect\x1b[0m:
182----
183{}
184----
185
186\x1b[1mActual\x1b[0m:
187----
188{}
189----
190
191\x1b[1mDiff\x1b[0m:
192----
193{}
194----
195",
196 position, help, expected, actual, diff
197 );
198 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
199 panic::resume_unwind(Box::new(()));
200 }
201}
202
203struct FileRuntime {
204 path: PathBuf,
205 original_text: String,
206 patchwork: Patchwork,
207}
208
209impl FileRuntime {
210 fn new(expect: &Expect) -> FileRuntime {
211 let path = WORKSPACE_ROOT.join(expect.position.file);
212 let original_text = fs::read_to_string(&path).unwrap();
213 let patchwork = Patchwork::new(original_text.clone());
214 FileRuntime { path, original_text, patchwork }
215 }
216 fn update(&mut self, expect: &Expect, actual: &str) {
217 let loc = expect.locate(&self.original_text);
218 let patch = format_patch(loc.line_indent.clone(), actual);
219 self.patchwork.patch(loc.literal_range, &patch);
220 fs::write(&self.path, &self.patchwork.text).unwrap()
221 }
222}
223
224#[derive(Debug)]
225struct Location {
226 line_indent: usize,
227 literal_range: Range<usize>,
228}
229
230#[derive(Debug)]
231struct Patchwork {
232 text: String,
233 indels: Vec<(Range<usize>, usize)>,
234}
235
236impl Patchwork {
237 fn new(text: String) -> Patchwork {
238 Patchwork { text, indels: Vec::new() }
239 }
240 fn patch(&mut self, mut range: Range<usize>, patch: &str) {
241 self.indels.push((range.clone(), patch.len()));
242 self.indels.sort_by_key(|(delete, _insert)| delete.start);
243
244 let (delete, insert) = self
245 .indels
246 .iter()
247 .take_while(|(delete, _)| delete.start < range.start)
248 .map(|(delete, insert)| (delete.end - delete.start, insert))
249 .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));
250
251 for pos in &mut [&mut range.start, &mut range.end] {
252 **pos -= delete;
253 **pos += insert;
254 }
255
256 self.text.replace_range(range, &patch);
257 }
258}
259
260fn format_patch(line_indent: usize, patch: &str) -> String {
261 let mut max_hashes = 0;
262 let mut cur_hashes = 0;
263 for byte in patch.bytes() {
264 if byte != b'#' {
265 cur_hashes = 0;
266 continue;
267 }
268 cur_hashes += 1;
269 max_hashes = max_hashes.max(cur_hashes);
270 }
271 let hashes = &"#".repeat(max_hashes + 1);
272 let indent = &" ".repeat(line_indent);
273 let is_multiline = patch.contains('\n');
274
275 let mut buf = String::new();
276 buf.push('r');
277 buf.push_str(hashes);
278 buf.push('"');
279 if is_multiline {
280 buf.push('\n');
281 }
282 let mut final_newline = false;
283 for line in lines_with_ends(patch) {
284 if is_multiline && !line.trim().is_empty() {
285 buf.push_str(indent);
286 buf.push_str(" ");
287 }
288 buf.push_str(line);
289 final_newline = line.ends_with('\n');
290 }
291 if final_newline {
292 buf.push_str(indent);
293 }
294 buf.push('"');
295 buf.push_str(hashes);
296 buf
297}
298
299static WORKSPACE_ROOT: Lazy<PathBuf> = Lazy::new(|| {
300 let my_manifest =
301 env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned());
302 // Heuristic, see https://github.com/rust-lang/cargo/issues/3946
303 Path::new(&my_manifest)
304 .ancestors()
305 .filter(|it| it.join("Cargo.toml").exists())
306 .last()
307 .unwrap()
308 .to_path_buf()
309});
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn test_format_patch() {
317 let patch = format_patch(0, "hello\nworld\n");
318 expect![[r##"
319 r#"
320 hello
321 world
322 "#"##]]
323 .assert_eq(&patch);
324
325 let patch = format_patch(4, "single line");
326 expect![[r##"r#"single line"#"##]].assert_eq(&patch);
327 }
328
329 #[test]
330 fn test_patchwork() {
331 let mut patchwork = Patchwork::new("one two three".to_string());
332 patchwork.patch(4..7, "zwei");
333 patchwork.patch(0..3, "один");
334 patchwork.patch(8..13, "3");
335 expect![[r#"
336 Patchwork {
337 text: "один zwei 3",
338 indels: [
339 (
340 0..3,
341 8,
342 ),
343 (
344 4..7,
345 4,
346 ),
347 (
348 8..13,
349 1,
350 ),
351 ],
352 }
353 "#]]
354 .assert_debug_eq(&patchwork);
355 }
356}
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index dc26b8ce7..ff8a1e568 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "flycheck" 3name = "flycheck"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -10,7 +11,7 @@ doctest = false
10[dependencies] 11[dependencies]
11crossbeam-channel = "0.4.0" 12crossbeam-channel = "0.4.0"
12log = "0.4.8" 13log = "0.4.8"
13cargo_metadata = "0.10.0" 14cargo_metadata = "0.11.1"
14serde_json = "1.0.48" 15serde_json = "1.0.48"
15jod-thread = "0.1.1" 16jod-thread = "0.1.1"
16ra_toolchain = { path = "../ra_toolchain" } 17ra_toolchain = { path = "../ra_toolchain" }
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 1023d3040..7c38f5ef9 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -14,14 +14,17 @@ use std::{
14use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; 14use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
15 15
16pub use cargo_metadata::diagnostic::{ 16pub use cargo_metadata::diagnostic::{
17 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, 17 Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
18 DiagnosticSpanMacroExpansion,
18}; 19};
19 20
20#[derive(Clone, Debug, PartialEq, Eq)] 21#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum FlycheckConfig { 22pub enum FlycheckConfig {
22 CargoCommand { 23 CargoCommand {
23 command: String, 24 command: String,
25 target_triple: Option<String>,
24 all_targets: bool, 26 all_targets: bool,
27 no_default_features: bool,
25 all_features: bool, 28 all_features: bool,
26 features: Vec<String>, 29 features: Vec<String>,
27 extra_args: Vec<String>, 30 extra_args: Vec<String>,
@@ -132,6 +135,7 @@ impl FlycheckActor {
132 self.cancel_check_process(); 135 self.cancel_check_process();
133 136
134 let mut command = self.check_command(); 137 let mut command = self.check_command();
138 log::info!("restart flycheck {:?}", command);
135 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); 139 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
136 if let Ok(child) = command.spawn().map(JodChild) { 140 if let Ok(child) = command.spawn().map(JodChild) {
137 self.cargo_handle = Some(CargoHandle::spawn(child)); 141 self.cargo_handle = Some(CargoHandle::spawn(child));
@@ -176,6 +180,8 @@ impl FlycheckActor {
176 let mut cmd = match &self.config { 180 let mut cmd = match &self.config {
177 FlycheckConfig::CargoCommand { 181 FlycheckConfig::CargoCommand {
178 command, 182 command,
183 target_triple,
184 no_default_features,
179 all_targets, 185 all_targets,
180 all_features, 186 all_features,
181 extra_args, 187 extra_args,
@@ -185,14 +191,23 @@ impl FlycheckActor {
185 cmd.arg(command); 191 cmd.arg(command);
186 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) 192 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
187 .arg(self.workspace_root.join("Cargo.toml")); 193 .arg(self.workspace_root.join("Cargo.toml"));
194
195 if let Some(target) = target_triple {
196 cmd.args(&["--target", target.as_str()]);
197 }
188 if *all_targets { 198 if *all_targets {
189 cmd.arg("--all-targets"); 199 cmd.arg("--all-targets");
190 } 200 }
191 if *all_features { 201 if *all_features {
192 cmd.arg("--all-features"); 202 cmd.arg("--all-features");
193 } else if !features.is_empty() { 203 } else {
194 cmd.arg("--features"); 204 if *no_default_features {
195 cmd.arg(features.join(" ")); 205 cmd.arg("--no-default-features");
206 }
207 if !features.is_empty() {
208 cmd.arg("--features");
209 cmd.arg(features.join(" "));
210 }
196 } 211 }
197 cmd.args(extra_args); 212 cmd.args(extra_args);
198 cmd 213 cmd
diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml
index 646ee7fd5..cbe2c26e2 100644
--- a/crates/paths/Cargo.toml
+++ b/crates/paths/Cargo.toml
@@ -3,6 +3,7 @@ name = "paths"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["rust-analyzer developers"] 4authors = ["rust-analyzer developers"]
5edition = "2018" 5edition = "2018"
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_arena/Cargo.toml b/crates/ra_arena/Cargo.toml
index d287dbb73..66c3738f4 100644
--- a/crates/ra_arena/Cargo.toml
+++ b/crates/ra_arena/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_arena" 3name = "ra_arena"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index 3bcf58ba4..bd2905f08 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_assists" 3name = "ra_assists"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_assists/src/assist_config.rs b/crates/ra_assists/src/assist_config.rs
index c0a0226fb..cda2abfb9 100644
--- a/crates/ra_assists/src/assist_config.rs
+++ b/crates/ra_assists/src/assist_config.rs
@@ -4,9 +4,12 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! assists if we are allowed to. 5//! assists if we are allowed to.
6 6
7use crate::AssistKind;
8
7#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct AssistConfig { 10pub struct AssistConfig {
9 pub snippet_cap: Option<SnippetCap>, 11 pub snippet_cap: Option<SnippetCap>,
12 pub allowed: Option<Vec<AssistKind>>,
10} 13}
11 14
12impl AssistConfig { 15impl AssistConfig {
@@ -22,6 +25,6 @@ pub struct SnippetCap {
22 25
23impl Default for AssistConfig { 26impl Default for AssistConfig {
24 fn default() -> Self { 27 fn default() -> Self {
25 AssistConfig { snippet_cap: Some(SnippetCap { _private: () }) } 28 AssistConfig { snippet_cap: Some(SnippetCap { _private: () }), allowed: None }
26 } 29 }
27} 30}
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index ee614de72..3407df856 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -19,7 +19,7 @@ use ra_text_edit::TextEditBuilder;
19 19
20use crate::{ 20use crate::{
21 assist_config::{AssistConfig, SnippetCap}, 21 assist_config::{AssistConfig, SnippetCap},
22 Assist, AssistId, GroupLabel, ResolvedAssist, 22 Assist, AssistId, AssistKind, GroupLabel, ResolvedAssist,
23}; 23};
24 24
25/// `AssistContext` allows to apply an assist or check if it could be applied. 25/// `AssistContext` allows to apply an assist or check if it could be applied.
@@ -55,7 +55,6 @@ use crate::{
55pub(crate) struct AssistContext<'a> { 55pub(crate) struct AssistContext<'a> {
56 pub(crate) config: &'a AssistConfig, 56 pub(crate) config: &'a AssistConfig,
57 pub(crate) sema: Semantics<'a, RootDatabase>, 57 pub(crate) sema: Semantics<'a, RootDatabase>,
58 pub(crate) db: &'a RootDatabase,
59 pub(crate) frange: FileRange, 58 pub(crate) frange: FileRange,
60 source_file: SourceFile, 59 source_file: SourceFile,
61} 60}
@@ -67,8 +66,11 @@ impl<'a> AssistContext<'a> {
67 frange: FileRange, 66 frange: FileRange,
68 ) -> AssistContext<'a> { 67 ) -> AssistContext<'a> {
69 let source_file = sema.parse(frange.file_id); 68 let source_file = sema.parse(frange.file_id);
70 let db = sema.db; 69 AssistContext { config, sema, frange, source_file }
71 AssistContext { config, sema, db, frange, source_file } 70 }
71
72 pub(crate) fn db(&self) -> &RootDatabase {
73 self.sema.db
72 } 74 }
73 75
74 // NB, this ignores active selection. 76 // NB, this ignores active selection.
@@ -101,14 +103,26 @@ pub(crate) struct Assists {
101 resolve: bool, 103 resolve: bool,
102 file: FileId, 104 file: FileId,
103 buf: Vec<(Assist, Option<SourceChange>)>, 105 buf: Vec<(Assist, Option<SourceChange>)>,
106 allowed: Option<Vec<AssistKind>>,
104} 107}
105 108
106impl Assists { 109impl Assists {
107 pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists { 110 pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists {
108 Assists { resolve: true, file: ctx.frange.file_id, buf: Vec::new() } 111 Assists {
112 resolve: true,
113 file: ctx.frange.file_id,
114 buf: Vec::new(),
115 allowed: ctx.config.allowed.clone(),
116 }
109 } 117 }
118
110 pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists { 119 pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists {
111 Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } 120 Assists {
121 resolve: false,
122 file: ctx.frange.file_id,
123 buf: Vec::new(),
124 allowed: ctx.config.allowed.clone(),
125 }
112 } 126 }
113 127
114 pub(crate) fn finish_unresolved(self) -> Vec<Assist> { 128 pub(crate) fn finish_unresolved(self) -> Vec<Assist> {
@@ -137,9 +151,13 @@ impl Assists {
137 target: TextRange, 151 target: TextRange,
138 f: impl FnOnce(&mut AssistBuilder), 152 f: impl FnOnce(&mut AssistBuilder),
139 ) -> Option<()> { 153 ) -> Option<()> {
154 if !self.is_allowed(&id) {
155 return None;
156 }
140 let label = Assist::new(id, label.into(), None, target); 157 let label = Assist::new(id, label.into(), None, target);
141 self.add_impl(label, f) 158 self.add_impl(label, f)
142 } 159 }
160
143 pub(crate) fn add_group( 161 pub(crate) fn add_group(
144 &mut self, 162 &mut self,
145 group: &GroupLabel, 163 group: &GroupLabel,
@@ -148,9 +166,14 @@ impl Assists {
148 target: TextRange, 166 target: TextRange,
149 f: impl FnOnce(&mut AssistBuilder), 167 f: impl FnOnce(&mut AssistBuilder),
150 ) -> Option<()> { 168 ) -> Option<()> {
169 if !self.is_allowed(&id) {
170 return None;
171 }
172
151 let label = Assist::new(id, label.into(), Some(group.clone()), target); 173 let label = Assist::new(id, label.into(), Some(group.clone()), target);
152 self.add_impl(label, f) 174 self.add_impl(label, f)
153 } 175 }
176
154 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { 177 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> {
155 let source_change = if self.resolve { 178 let source_change = if self.resolve {
156 let mut builder = AssistBuilder::new(self.file); 179 let mut builder = AssistBuilder::new(self.file);
@@ -168,13 +191,20 @@ impl Assists {
168 self.buf.sort_by_key(|(label, _edit)| label.target.len()); 191 self.buf.sort_by_key(|(label, _edit)| label.target.len());
169 self.buf 192 self.buf
170 } 193 }
194
195 fn is_allowed(&self, id: &AssistId) -> bool {
196 match &self.allowed {
197 Some(allowed) => allowed.iter().any(|kind| kind.contains(id.1)),
198 None => true,
199 }
200 }
171} 201}
172 202
173pub(crate) struct AssistBuilder { 203pub(crate) struct AssistBuilder {
174 edit: TextEditBuilder, 204 edit: TextEditBuilder,
175 file_id: FileId, 205 file_id: FileId,
176 is_snippet: bool, 206 is_snippet: bool,
177 edits: Vec<SourceFileEdit>, 207 change: SourceChange,
178} 208}
179 209
180impl AssistBuilder { 210impl AssistBuilder {
@@ -183,7 +213,7 @@ impl AssistBuilder {
183 edit: TextEditBuilder::default(), 213 edit: TextEditBuilder::default(),
184 file_id, 214 file_id,
185 is_snippet: false, 215 is_snippet: false,
186 edits: Vec::new(), 216 change: SourceChange::default(),
187 } 217 }
188 } 218 }
189 219
@@ -195,8 +225,8 @@ impl AssistBuilder {
195 let edit = mem::take(&mut self.edit).finish(); 225 let edit = mem::take(&mut self.edit).finish();
196 if !edit.is_empty() { 226 if !edit.is_empty() {
197 let new_edit = SourceFileEdit { file_id: self.file_id, edit }; 227 let new_edit = SourceFileEdit { file_id: self.file_id, edit };
198 assert!(!self.edits.iter().any(|it| it.file_id == new_edit.file_id)); 228 assert!(!self.change.source_file_edits.iter().any(|it| it.file_id == new_edit.file_id));
199 self.edits.push(new_edit); 229 self.change.source_file_edits.push(new_edit);
200 } 230 }
201 } 231 }
202 232
@@ -263,10 +293,10 @@ impl AssistBuilder {
263 293
264 fn finish(mut self) -> SourceChange { 294 fn finish(mut self) -> SourceChange {
265 self.commit(); 295 self.commit();
266 let mut res: SourceChange = mem::take(&mut self.edits).into(); 296 let mut change = mem::take(&mut self.change);
267 if self.is_snippet { 297 if self.is_snippet {
268 res.is_snippet = true; 298 change.is_snippet = true;
269 } 299 }
270 res 300 change
271 } 301 }
272} 302}
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index 00fa95b6c..5ea4f9f5b 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -2,7 +2,6 @@
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use hir::{HirDisplay, PathResolution, SemanticsScope}; 4use hir::{HirDisplay, PathResolution, SemanticsScope};
5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 5use ra_syntax::{
7 algo::SyntaxRewriter, 6 algo::SyntaxRewriter,
8 ast::{self, AstNode}, 7 ast::{self, AstNode},
@@ -32,17 +31,17 @@ impl<'a> AstTransform<'a> for NullTransformer {
32} 31}
33 32
34pub struct SubstituteTypeParams<'a> { 33pub struct SubstituteTypeParams<'a> {
35 source_scope: &'a SemanticsScope<'a, RootDatabase>, 34 source_scope: &'a SemanticsScope<'a>,
36 substs: FxHashMap<hir::TypeParam, ast::TypeRef>, 35 substs: FxHashMap<hir::TypeParam, ast::TypeRef>,
37 previous: Box<dyn AstTransform<'a> + 'a>, 36 previous: Box<dyn AstTransform<'a> + 'a>,
38} 37}
39 38
40impl<'a> SubstituteTypeParams<'a> { 39impl<'a> SubstituteTypeParams<'a> {
41 pub fn for_trait_impl( 40 pub fn for_trait_impl(
42 source_scope: &'a SemanticsScope<'a, RootDatabase>, 41 source_scope: &'a SemanticsScope<'a>,
43 // FIXME: there's implicit invariant that `trait_` and `source_scope` match... 42 // FIXME: there's implicit invariant that `trait_` and `source_scope` match...
44 trait_: hir::Trait, 43 trait_: hir::Trait,
45 impl_def: ast::ImplDef, 44 impl_def: ast::Impl,
46 ) -> SubstituteTypeParams<'a> { 45 ) -> SubstituteTypeParams<'a> {
47 let substs = get_syntactic_substs(impl_def).unwrap_or_default(); 46 let substs = get_syntactic_substs(impl_def).unwrap_or_default();
48 let generic_def: hir::GenericDef = trait_.into(); 47 let generic_def: hir::GenericDef = trait_.into();
@@ -81,7 +80,7 @@ impl<'a> SubstituteTypeParams<'a> {
81 80
82 // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the 81 // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
83 // trait ref, and then go from the types in the substs back to the syntax) 82 // trait ref, and then go from the types in the substs back to the syntax)
84 fn get_syntactic_substs(impl_def: ast::ImplDef) -> Option<Vec<ast::TypeRef>> { 83 fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::TypeRef>> {
85 let target_trait = impl_def.target_trait()?; 84 let target_trait = impl_def.target_trait()?;
86 let path_type = match target_trait { 85 let path_type = match target_trait {
87 ast::TypeRef::PathType(path) => path, 86 ast::TypeRef::PathType(path) => path,
@@ -126,16 +125,13 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
126} 125}
127 126
128pub struct QualifyPaths<'a> { 127pub struct QualifyPaths<'a> {
129 target_scope: &'a SemanticsScope<'a, RootDatabase>, 128 target_scope: &'a SemanticsScope<'a>,
130 source_scope: &'a SemanticsScope<'a, RootDatabase>, 129 source_scope: &'a SemanticsScope<'a>,
131 previous: Box<dyn AstTransform<'a> + 'a>, 130 previous: Box<dyn AstTransform<'a> + 'a>,
132} 131}
133 132
134impl<'a> QualifyPaths<'a> { 133impl<'a> QualifyPaths<'a> {
135 pub fn new( 134 pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
136 target_scope: &'a SemanticsScope<'a, RootDatabase>,
137 source_scope: &'a SemanticsScope<'a, RootDatabase>,
138 ) -> Self {
139 Self { target_scope, source_scope, previous: Box::new(NullTransformer) } 135 Self { target_scope, source_scope, previous: Box::new(NullTransformer) }
140 } 136 }
141 137
@@ -156,7 +152,7 @@ impl<'a> QualifyPaths<'a> {
156 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; 152 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?;
157 match resolution { 153 match resolution {
158 PathResolution::Def(def) => { 154 PathResolution::Def(def) => {
159 let found_path = from.find_use_path(self.source_scope.db, def)?; 155 let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
160 let mut path = path_to_ast(found_path); 156 let mut path = path_to_ast(found_path);
161 157
162 let type_args = p 158 let type_args = p
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index fa70c8496..b67438b6b 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -8,7 +8,7 @@ use stdx::SepBy;
8 8
9use crate::{ 9use crate::{
10 assist_context::{AssistContext, Assists}, 10 assist_context::{AssistContext, Assists},
11 AssistId, 11 AssistId, AssistKind,
12}; 12};
13 13
14// Assist: add_custom_impl 14// Assist: add_custom_impl
@@ -29,8 +29,8 @@ use crate::{
29// } 29// }
30// ``` 30// ```
31pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 let input = ctx.find_node_at_offset::<ast::AttrInput>()?; 32 let attr = ctx.find_node_at_offset::<ast::Attr>()?;
33 let attr = input.syntax().parent().and_then(ast::Attr::cast)?; 33 let input = attr.token_tree()?;
34 34
35 let attr_name = attr 35 let attr_name = attr
36 .syntax() 36 .syntax()
@@ -52,7 +52,7 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
52 format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name); 52 format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
53 53
54 let target = attr.syntax().text_range(); 54 let target = attr.syntax().text_range();
55 acc.add(AssistId("add_custom_impl"), label, target, |builder| { 55 acc.add(AssistId("add_custom_impl", AssistKind::Refactor), label, target, |builder| {
56 let new_attr_input = input 56 let new_attr_input = input
57 .syntax() 57 .syntax()
58 .descendants_with_tokens() 58 .descendants_with_tokens()
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 90b06a625..e69f0a89b 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -1,10 +1,10 @@
1use hir::HirDisplay; 1use hir::HirDisplay;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
4 TextRange, 4 TextRange,
5}; 5};
6 6
7use crate::{AssistContext, AssistId, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
8 8
9// Assist: add_explicit_type 9// Assist: add_explicit_type
10// 10//
@@ -22,11 +22,11 @@ use crate::{AssistContext, AssistId, Assists};
22// } 22// }
23// ``` 23// ```
24pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 24pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let stmt = ctx.find_node_at_offset::<LetStmt>()?; 25 let let_stmt = ctx.find_node_at_offset::<LetStmt>()?;
26 let module = ctx.sema.scope(stmt.syntax()).module()?; 26 let module = ctx.sema.scope(let_stmt.syntax()).module()?;
27 let expr = stmt.initializer()?; 27 let expr = let_stmt.initializer()?;
28 // Must be a binding 28 // Must be a binding
29 let pat = match stmt.pat()? { 29 let pat = match let_stmt.pat()? {
30 ast::Pat::BindPat(bind_pat) => bind_pat, 30 ast::Pat::BindPat(bind_pat) => bind_pat,
31 _ => return None, 31 _ => return None,
32 }; 32 };
@@ -34,8 +34,8 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
34 // The binding must have a name 34 // The binding must have a name
35 let name = pat.name()?; 35 let name = pat.name()?;
36 let name_range = name.syntax().text_range(); 36 let name_range = name.syntax().text_range();
37 let stmt_range = stmt.syntax().text_range(); 37 let stmt_range = let_stmt.syntax().text_range();
38 let eq_range = stmt.eq_token()?.text_range(); 38 let eq_range = let_stmt.eq_token()?.text_range();
39 // Assist should only be applicable if cursor is between 'let' and '=' 39 // Assist should only be applicable if cursor is between 'let' and '='
40 let let_range = TextRange::new(stmt_range.start(), eq_range.start()); 40 let let_range = TextRange::new(stmt_range.start(), eq_range.start());
41 let cursor_in_range = let_range.contains_range(ctx.frange.range); 41 let cursor_in_range = let_range.contains_range(ctx.frange.range);
@@ -44,7 +44,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
44 } 44 }
45 // Assist not applicable if the type has already been specified 45 // Assist not applicable if the type has already been specified
46 // and it has no placeholders 46 // and it has no placeholders
47 let ascribed_ty = stmt.ascribed_type(); 47 let ascribed_ty = let_stmt.ty();
48 if let Some(ty) = &ascribed_ty { 48 if let Some(ty) = &ascribed_ty {
49 if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { 49 if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() {
50 return None; 50 return None;
@@ -57,9 +57,9 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
57 return None; 57 return None;
58 } 58 }
59 59
60 let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?; 60 let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
61 acc.add( 61 acc.add(
62 AssistId("add_explicit_type"), 62 AssistId("add_explicit_type", AssistKind::RefactorRewrite),
63 format!("Insert explicit type `{}`", inferred_type), 63 format!("Insert explicit type `{}`", inferred_type),
64 pat_range, 64 pat_range,
65 |builder| match ascribed_ty { 65 |builder| match ascribed_ty {
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
deleted file mode 100644
index eceba7d0a..000000000
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ /dev/null
@@ -1,98 +0,0 @@
1use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner};
2use stdx::{format_to, SepBy};
3
4use crate::{AssistContext, AssistId, Assists};
5
6// Assist: add_impl
7//
8// Adds a new inherent impl for a type.
9//
10// ```
11// struct Ctx<T: Clone> {
12// data: T,<|>
13// }
14// ```
15// ->
16// ```
17// struct Ctx<T: Clone> {
18// data: T,
19// }
20//
21// impl<T: Clone> Ctx<T> {
22// $0
23// }
24// ```
25pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
27 let name = nominal.name()?;
28 let target = nominal.syntax().text_range();
29 acc.add(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), target, |edit| {
30 let type_params = nominal.type_param_list();
31 let start_offset = nominal.syntax().text_range().end();
32 let mut buf = String::new();
33 buf.push_str("\n\nimpl");
34 if let Some(type_params) = &type_params {
35 format_to!(buf, "{}", type_params.syntax());
36 }
37 buf.push_str(" ");
38 buf.push_str(name.text().as_str());
39 if let Some(type_params) = type_params {
40 let lifetime_params = type_params
41 .lifetime_params()
42 .filter_map(|it| it.lifetime_token())
43 .map(|it| it.text().clone());
44 let type_params =
45 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
46
47 let generic_params = lifetime_params.chain(type_params).sep_by(", ");
48 format_to!(buf, "<{}>", generic_params)
49 }
50 match ctx.config.snippet_cap {
51 Some(cap) => {
52 buf.push_str(" {\n $0\n}");
53 edit.insert_snippet(cap, start_offset, buf);
54 }
55 None => {
56 buf.push_str(" {\n}");
57 edit.insert(start_offset, buf);
58 }
59 }
60 })
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::tests::{check_assist, check_assist_target};
66
67 use super::*;
68
69 #[test]
70 fn test_add_impl() {
71 check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n $0\n}\n");
72 check_assist(
73 add_impl,
74 "struct Foo<T: Clone> {<|>}",
75 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
76 );
77 check_assist(
78 add_impl,
79 "struct Foo<'a, T: Foo<'a>> {<|>}",
80 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
81 );
82 }
83
84 #[test]
85 fn add_impl_target() {
86 check_assist_target(
87 add_impl,
88 "
89struct SomeThingIrrelevant;
90/// Has a lifetime parameter
91struct Foo<'a, T: Foo<'a>> {<|>}
92struct EvenMoreIrrelevant;
93",
94 "/// Has a lifetime parameter
95struct Foo<'a, T: Foo<'a>> {}",
96 );
97 }
98}
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index abacd4065..95a750aee 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -12,7 +12,7 @@ use crate::{
12 assist_context::{AssistContext, Assists}, 12 assist_context::{AssistContext, Assists},
13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
14 utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, 14 utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
15 AssistId, 15 AssistId, AssistKind,
16}; 16};
17 17
18#[derive(PartialEq)] 18#[derive(PartialEq)]
@@ -111,16 +111,17 @@ fn add_missing_impl_members_inner(
111 label: &'static str, 111 label: &'static str,
112) -> Option<()> { 112) -> Option<()> {
113 let _p = ra_prof::profile("add_missing_impl_members_inner"); 113 let _p = ra_prof::profile("add_missing_impl_members_inner");
114 let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; 114 let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
115 let impl_item_list = impl_def.item_list()?; 115 let impl_item_list = impl_def.assoc_item_list()?;
116 116
117 let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; 117 let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
118 118
119 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { 119 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
120 match item { 120 match item {
121 ast::AssocItem::FnDef(def) => def.name(), 121 ast::AssocItem::Fn(def) => def.name(),
122 ast::AssocItem::TypeAliasDef(def) => def.name(), 122 ast::AssocItem::TypeAlias(def) => def.name(),
123 ast::AssocItem::ConstDef(def) => def.name(), 123 ast::AssocItem::Const(def) => def.name(),
124 ast::AssocItem::MacroCall(_) => None,
124 } 125 }
125 .map(|it| it.text().clone()) 126 .map(|it| it.text().clone())
126 }; 127 };
@@ -128,13 +129,13 @@ fn add_missing_impl_members_inner(
128 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) 129 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def)
129 .iter() 130 .iter()
130 .map(|i| match i { 131 .map(|i| match i {
131 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), 132 hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(ctx.db()).value),
132 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db).value), 133 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(ctx.db()).value),
133 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db).value), 134 hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(ctx.db()).value),
134 }) 135 })
135 .filter(|t| def_name(&t).is_some()) 136 .filter(|t| def_name(&t).is_some())
136 .filter(|t| match t { 137 .filter(|t| match t {
137 ast::AssocItem::FnDef(def) => match mode { 138 ast::AssocItem::Fn(def) => match mode {
138 AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), 139 AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(),
139 AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(), 140 AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(),
140 }, 141 },
@@ -147,7 +148,7 @@ fn add_missing_impl_members_inner(
147 } 148 }
148 149
149 let target = impl_def.syntax().text_range(); 150 let target = impl_def.syntax().text_range();
150 acc.add(AssistId(assist_id), label, target, |builder| { 151 acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
151 let n_existing_items = impl_item_list.assoc_items().count(); 152 let n_existing_items = impl_item_list.assoc_items().count();
152 let source_scope = ctx.sema.scope_for_def(trait_); 153 let source_scope = ctx.sema.scope_for_def(trait_);
153 let target_scope = ctx.sema.scope(impl_item_list.syntax()); 154 let target_scope = ctx.sema.scope(impl_item_list.syntax());
@@ -157,7 +158,8 @@ fn add_missing_impl_members_inner(
157 .into_iter() 158 .into_iter()
158 .map(|it| ast_transform::apply(&*ast_transform, it)) 159 .map(|it| ast_transform::apply(&*ast_transform, it))
159 .map(|it| match it { 160 .map(|it| match it {
160 ast::AssocItem::FnDef(def) => ast::AssocItem::FnDef(add_body(def)), 161 ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)),
162 ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()),
161 _ => it, 163 _ => it,
162 }) 164 })
163 .map(|it| edit::remove_attrs_and_docs(&it)); 165 .map(|it| edit::remove_attrs_and_docs(&it));
@@ -170,7 +172,7 @@ fn add_missing_impl_members_inner(
170 Some(cap) => { 172 Some(cap) => {
171 let mut cursor = Cursor::Before(first_new_item.syntax()); 173 let mut cursor = Cursor::Before(first_new_item.syntax());
172 let placeholder; 174 let placeholder;
173 if let ast::AssocItem::FnDef(func) = &first_new_item { 175 if let ast::AssocItem::Fn(func) = &first_new_item {
174 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { 176 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) {
175 if m.syntax().text() == "todo!()" { 177 if m.syntax().text() == "todo!()" {
176 placeholder = m; 178 placeholder = m;
@@ -188,7 +190,7 @@ fn add_missing_impl_members_inner(
188 }) 190 })
189} 191}
190 192
191fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 193fn add_body(fn_def: ast::Fn) -> ast::Fn {
192 if fn_def.body().is_some() { 194 if fn_def.body().is_some() {
193 return fn_def; 195 return fn_def;
194 } 196 }
@@ -684,4 +686,26 @@ impl Foo<T> for S<T> {
684}"#, 686}"#,
685 ) 687 )
686 } 688 }
689
690 #[test]
691 fn test_assoc_type_bounds_are_removed() {
692 check_assist(
693 add_missing_impl_members,
694 r#"
695trait Tr {
696 type Ty: Copy + 'static;
697}
698
699impl Tr for ()<|> {
700}"#,
701 r#"
702trait Tr {
703 type Ty: Copy + 'static;
704}
705
706impl Tr for () {
707 $0type Ty;
708}"#,
709 )
710 }
687} 711}
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs
index 26acf81f2..0c565e89a 100644
--- a/crates/ra_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs
@@ -4,7 +4,7 @@ use test_utils::mark;
4 4
5use crate::{ 5use crate::{
6 assist_context::{AssistContext, Assists}, 6 assist_context::{AssistContext, Assists},
7 AssistId, 7 AssistId, AssistKind,
8}; 8};
9 9
10// Assist: add_turbo_fish 10// Assist: add_turbo_fish
@@ -25,7 +25,14 @@ use crate::{
25// } 25// }
26// ``` 26// ```
27pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 27pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; 28 let ident = ctx.find_token_at_offset(SyntaxKind::IDENT).or_else(|| {
29 let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
30 if arg_list.args().count() > 0 {
31 return None;
32 }
33 mark::hit!(add_turbo_fish_after_call);
34 arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
35 })?;
29 let next_token = ident.next_token()?; 36 let next_token = ident.next_token()?;
30 if next_token.kind() == T![::] { 37 if next_token.kind() == T![::] {
31 mark::hit!(add_turbo_fish_one_fish_is_enough); 38 mark::hit!(add_turbo_fish_one_fish_is_enough);
@@ -45,12 +52,15 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
45 mark::hit!(add_turbo_fish_non_generic); 52 mark::hit!(add_turbo_fish_non_generic);
46 return None; 53 return None;
47 } 54 }
48 acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { 55 acc.add(
49 match ctx.config.snippet_cap { 56 AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
57 "Add `::<>`",
58 ident.text_range(),
59 |builder| match ctx.config.snippet_cap {
50 Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"), 60 Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
51 None => builder.insert(ident.text_range().end(), "::<_>"), 61 None => builder.insert(ident.text_range().end(), "::<_>"),
52 } 62 },
53 }) 63 )
54} 64}
55 65
56#[cfg(test)] 66#[cfg(test)]
@@ -80,6 +90,26 @@ fn main() {
80 } 90 }
81 91
82 #[test] 92 #[test]
93 fn add_turbo_fish_after_call() {
94 mark::check!(add_turbo_fish_after_call);
95 check_assist(
96 add_turbo_fish,
97 r#"
98fn make<T>() -> T {}
99fn main() {
100 make()<|>;
101}
102"#,
103 r#"
104fn make<T>() -> T {}
105fn main() {
106 make::<${0:_}>();
107}
108"#,
109 );
110 }
111
112 #[test]
83 fn add_turbo_fish_method() { 113 fn add_turbo_fish_method() {
84 check_assist( 114 check_assist(
85 add_turbo_fish, 115 add_turbo_fish,
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs
index 233e8fb8e..de701f8b8 100644
--- a/crates/ra_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ra_assists/src/handlers/apply_demorgan.rs
@@ -1,6 +1,6 @@
1use ra_syntax::ast::{self, AstNode}; 1use ra_syntax::ast::{self, AstNode};
2 2
3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, Assists}; 3use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
4 4
5// Assist: apply_demorgan 5// Assist: apply_demorgan
6// 6//
@@ -39,11 +39,16 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<(
39 let rhs_range = rhs.syntax().text_range(); 39 let rhs_range = rhs.syntax().text_range();
40 let not_rhs = invert_boolean_expression(rhs); 40 let not_rhs = invert_boolean_expression(rhs);
41 41
42 acc.add(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { 42 acc.add(
43 edit.replace(op_range, opposite_op); 43 AssistId("apply_demorgan", AssistKind::RefactorRewrite),
44 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); 44 "Apply De Morgan's law",
45 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); 45 op_range,
46 }) 46 |edit| {
47 edit.replace(op_range, opposite_op);
48 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
49 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
50 },
51 )
47} 52}
48 53
49// Return the opposite text for a given logical operator, if it makes sense 54// Return the opposite text for a given logical operator, if it makes sense
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index d1cafa7d9..01e7b7a44 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -5,7 +5,7 @@ use hir::{
5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, 5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait,
6 Type, 6 Type,
7}; 7};
8use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; 8use ra_ide_db::{imports_locator, RootDatabase};
9use ra_prof::profile; 9use ra_prof::profile;
10use ra_syntax::{ 10use ra_syntax::{
11 ast::{self, AstNode}, 11 ast::{self, AstNode},
@@ -13,7 +13,9 @@ use ra_syntax::{
13}; 13};
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15 15
16use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel}; 16use crate::{
17 utils::insert_use_statement, AssistContext, AssistId, AssistKind, Assists, GroupLabel,
18};
17 19
18// Assist: auto_import 20// Assist: auto_import
19// 21//
@@ -35,8 +37,8 @@ use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, Group
35// # pub mod std { pub mod collections { pub struct HashMap { } } } 37// # pub mod std { pub mod collections { pub struct HashMap { } } }
36// ``` 38// ```
37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 39pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let auto_import_assets = AutoImportAssets::new(&ctx)?; 40 let auto_import_assets = AutoImportAssets::new(ctx)?;
39 let proposed_imports = auto_import_assets.search_for_imports(ctx.db); 41 let proposed_imports = auto_import_assets.search_for_imports(ctx);
40 if proposed_imports.is_empty() { 42 if proposed_imports.is_empty() {
41 return None; 43 return None;
42 } 44 }
@@ -46,7 +48,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
46 for import in proposed_imports { 48 for import in proposed_imports {
47 acc.add_group( 49 acc.add_group(
48 &group, 50 &group,
49 AssistId("auto_import"), 51 AssistId("auto_import", AssistKind::QuickFix),
50 format!("Import `{}`", &import), 52 format!("Import `{}`", &import),
51 range, 53 range,
52 |builder| { 54 |builder| {
@@ -90,7 +92,7 @@ impl AutoImportAssets {
90 92
91 fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> { 93 fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> {
92 let syntax_under_caret = path_under_caret.syntax().to_owned(); 94 let syntax_under_caret = path_under_caret.syntax().to_owned();
93 if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { 95 if syntax_under_caret.ancestors().find_map(ast::Use::cast).is_some() {
94 return None; 96 return None;
95 } 97 }
96 98
@@ -127,11 +129,11 @@ impl AutoImportAssets {
127 GroupLabel(name) 129 GroupLabel(name)
128 } 130 }
129 131
130 fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { 132 fn search_for_imports(&self, ctx: &AssistContext) -> BTreeSet<ModPath> {
131 let _p = profile("auto_import::search_for_imports"); 133 let _p = profile("auto_import::search_for_imports");
134 let db = ctx.db();
132 let current_crate = self.module_with_name_to_import.krate(); 135 let current_crate = self.module_with_name_to_import.krate();
133 ImportsLocator::new(db, current_crate) 136 imports_locator::find_imports(&ctx.sema, current_crate, &self.get_search_query())
134 .find_imports(&self.get_search_query())
135 .into_iter() 137 .into_iter()
136 .filter_map(|candidate| match &self.import_candidate { 138 .filter_map(|candidate| match &self.import_candidate {
137 ImportCandidate::TraitAssocItem(assoc_item_type, _) => { 139 ImportCandidate::TraitAssocItem(assoc_item_type, _) => {
@@ -811,6 +813,146 @@ fn main() {
811 } 813 }
812 814
813 #[test] 815 #[test]
816 fn trait_method_cross_crate() {
817 check_assist(
818 auto_import,
819 r"
820 //- /main.rs crate:main deps:dep
821 fn main() {
822 let test_struct = dep::test_mod::TestStruct {};
823 test_struct.test_meth<|>od()
824 }
825 //- /dep.rs crate:dep
826 pub mod test_mod {
827 pub trait TestTrait {
828 fn test_method(&self);
829 }
830 pub struct TestStruct {}
831 impl TestTrait for TestStruct {
832 fn test_method(&self) {}
833 }
834 }
835 ",
836 r"
837 use dep::test_mod::TestTrait;
838
839 fn main() {
840 let test_struct = dep::test_mod::TestStruct {};
841 test_struct.test_method()
842 }
843 ",
844 );
845 }
846
847 #[test]
848 fn assoc_fn_cross_crate() {
849 check_assist(
850 auto_import,
851 r"
852 //- /main.rs crate:main deps:dep
853 fn main() {
854 dep::test_mod::TestStruct::test_func<|>tion
855 }
856 //- /dep.rs crate:dep
857 pub mod test_mod {
858 pub trait TestTrait {
859 fn test_function();
860 }
861 pub struct TestStruct {}
862 impl TestTrait for TestStruct {
863 fn test_function() {}
864 }
865 }
866 ",
867 r"
868 use dep::test_mod::TestTrait;
869
870 fn main() {
871 dep::test_mod::TestStruct::test_function
872 }
873 ",
874 );
875 }
876
877 #[test]
878 fn assoc_const_cross_crate() {
879 check_assist(
880 auto_import,
881 r"
882 //- /main.rs crate:main deps:dep
883 fn main() {
884 dep::test_mod::TestStruct::CONST<|>
885 }
886 //- /dep.rs crate:dep
887 pub mod test_mod {
888 pub trait TestTrait {
889 const CONST: bool;
890 }
891 pub struct TestStruct {}
892 impl TestTrait for TestStruct {
893 const CONST: bool = true;
894 }
895 }
896 ",
897 r"
898 use dep::test_mod::TestTrait;
899
900 fn main() {
901 dep::test_mod::TestStruct::CONST
902 }
903 ",
904 );
905 }
906
907 #[test]
908 fn assoc_fn_as_method_cross_crate() {
909 check_assist_not_applicable(
910 auto_import,
911 r"
912 //- /main.rs crate:main deps:dep
913 fn main() {
914 let test_struct = dep::test_mod::TestStruct {};
915 test_struct.test_func<|>tion()
916 }
917 //- /dep.rs crate:dep
918 pub mod test_mod {
919 pub trait TestTrait {
920 fn test_function();
921 }
922 pub struct TestStruct {}
923 impl TestTrait for TestStruct {
924 fn test_function() {}
925 }
926 }
927 ",
928 );
929 }
930
931 #[test]
932 fn private_trait_cross_crate() {
933 check_assist_not_applicable(
934 auto_import,
935 r"
936 //- /main.rs crate:main deps:dep
937 fn main() {
938 let test_struct = dep::test_mod::TestStruct {};
939 test_struct.test_meth<|>od()
940 }
941 //- /dep.rs crate:dep
942 pub mod test_mod {
943 trait TestTrait {
944 fn test_method(&self);
945 }
946 pub struct TestStruct {}
947 impl TestTrait for TestStruct {
948 fn test_method(&self) {}
949 }
950 }
951 ",
952 );
953 }
954
955 #[test]
814 fn not_applicable_for_imported_trait_for_method() { 956 fn not_applicable_for_imported_trait_for_method() {
815 check_assist_not_applicable( 957 check_assist_not_applicable(
816 auto_import, 958 auto_import,
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs
index 855baf187..167e162d8 100644
--- a/crates/ra_assists/src/handlers/change_return_type_to_result.rs
+++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 AstNode, SyntaxNode, 3 AstNode, SyntaxNode,
4}; 4};
5 5
6use crate::{AssistContext, AssistId, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
7use test_utils::mark; 7use test_utils::mark;
8 8
9// Assist: change_return_type_to_result 9// Assist: change_return_type_to_result
@@ -20,9 +20,9 @@ use test_utils::mark;
20pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 20pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
21 let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; 21 let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
22 // FIXME: extend to lambdas as well 22 // FIXME: extend to lambdas as well
23 let fn_def = ret_type.syntax().parent().and_then(ast::FnDef::cast)?; 23 let fn_def = ret_type.syntax().parent().and_then(ast::Fn::cast)?;
24 24
25 let type_ref = &ret_type.type_ref()?; 25 let type_ref = &ret_type.ty()?;
26 let ret_type_str = type_ref.syntax().text().to_string(); 26 let ret_type_str = type_ref.syntax().text().to_string();
27 let first_part_ret_type = ret_type_str.splitn(2, '<').next(); 27 let first_part_ret_type = ret_type_str.splitn(2, '<').next();
28 if let Some(ret_type_first_part) = first_part_ret_type { 28 if let Some(ret_type_first_part) = first_part_ret_type {
@@ -35,8 +35,8 @@ pub(crate) fn change_return_type_to_result(acc: &mut Assists, ctx: &AssistContex
35 let block_expr = &fn_def.body()?; 35 let block_expr = &fn_def.body()?;
36 36
37 acc.add( 37 acc.add(
38 AssistId("change_return_type_to_result"), 38 AssistId("change_return_type_to_result", AssistKind::RefactorRewrite),
39 "Change return type to Result", 39 "Wrap return type in Result",
40 type_ref.syntax().text_range(), 40 type_ref.syntax().text_range(),
41 |builder| { 41 |builder| {
42 let mut tail_return_expr_collector = TailReturnCollector::new(); 42 let mut tail_return_expr_collector = TailReturnCollector::new();
@@ -240,7 +240,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> {
240 Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 240 Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
241 Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 241 Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
242 Expr::Label(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 242 Expr::Label(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
243 Expr::RecordLit(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 243 Expr::RecordExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
244 Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 244 Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
245 Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 245 Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
246 Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), 246 Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]),
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 157c7b665..724daa93f 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -1,12 +1,12 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY}, 4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, VISIBILITY},
5 T, 5 T,
6}; 6};
7use test_utils::mark; 7use test_utils::mark;
8 8
9use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; 9use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
10 10
11// Assist: change_visibility 11// Assist: change_visibility
12// 12//
@@ -28,12 +28,15 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
28 28
29fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let item_keyword = ctx.token_at_offset().find(|leaf| { 30 let item_keyword = ctx.token_at_offset().find(|leaf| {
31 matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]) 31 matches!(
32 leaf.kind(),
33 T![const] | T![static] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]
34 )
32 }); 35 });
33 36
34 let (offset, target) = if let Some(keyword) = item_keyword { 37 let (offset, target) = if let Some(keyword) = item_keyword {
35 let parent = keyword.parent(); 38 let parent = keyword.parent();
36 let def_kws = vec![CONST_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 39 let def_kws = vec![CONST, STATIC, FN, MODULE, STRUCT, ENUM, TRAIT];
37 // Parent is not a definition, can't add visibility 40 // Parent is not a definition, can't add visibility
38 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 41 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
39 return None; 42 return None;
@@ -44,7 +47,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
44 } 47 }
45 (vis_offset(&parent), keyword.text_range()) 48 (vis_offset(&parent), keyword.text_range())
46 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { 49 } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
47 let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; 50 let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?;
48 if field.name()? != field_name { 51 if field.name()? != field_name {
49 mark::hit!(change_visibility_field_false_positive); 52 mark::hit!(change_visibility_field_false_positive);
50 return None; 53 return None;
@@ -53,7 +56,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
53 return None; 56 return None;
54 } 57 }
55 (vis_offset(field.syntax()), field_name.syntax().text_range()) 58 (vis_offset(field.syntax()), field_name.syntax().text_range())
56 } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() { 59 } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleField>() {
57 if field.visibility().is_some() { 60 if field.visibility().is_some() {
58 return None; 61 return None;
59 } 62 }
@@ -62,16 +65,21 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
62 return None; 65 return None;
63 }; 66 };
64 67
65 acc.add(AssistId("change_visibility"), "Change visibility to pub(crate)", target, |edit| { 68 acc.add(
66 edit.insert(offset, "pub(crate) "); 69 AssistId("change_visibility", AssistKind::RefactorRewrite),
67 }) 70 "Change visibility to pub(crate)",
71 target,
72 |edit| {
73 edit.insert(offset, "pub(crate) ");
74 },
75 )
68} 76}
69 77
70fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { 78fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
71 if vis.syntax().text() == "pub" { 79 if vis.syntax().text() == "pub" {
72 let target = vis.syntax().text_range(); 80 let target = vis.syntax().text_range();
73 return acc.add( 81 return acc.add(
74 AssistId("change_visibility"), 82 AssistId("change_visibility", AssistKind::RefactorRewrite),
75 "Change Visibility to pub(crate)", 83 "Change Visibility to pub(crate)",
76 target, 84 target,
77 |edit| { 85 |edit| {
@@ -82,7 +90,7 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
82 if vis.syntax().text() == "pub(crate)" { 90 if vis.syntax().text() == "pub(crate)" {
83 let target = vis.syntax().text_range(); 91 let target = vis.syntax().text_range();
84 return acc.add( 92 return acc.add(
85 AssistId("change_visibility"), 93 AssistId("change_visibility", AssistKind::RefactorRewrite),
86 "Change visibility to pub", 94 "Change visibility to pub",
87 target, 95 target,
88 |edit| { 96 |edit| {
@@ -147,6 +155,11 @@ mod tests {
147 } 155 }
148 156
149 #[test] 157 #[test]
158 fn change_visibility_static() {
159 check_assist(change_visibility, "<|>static FOO = 3u8;", "pub(crate) static FOO = 3u8;");
160 }
161
162 #[test]
150 fn change_visibility_handles_comment_attrs() { 163 fn change_visibility_handles_comment_attrs() {
151 check_assist( 164 check_assist(
152 change_visibility, 165 change_visibility,
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index dfade7432..3650289fd 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -8,14 +8,14 @@ use ra_syntax::{
8 make, 8 make,
9 }, 9 },
10 AstNode, 10 AstNode,
11 SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, 11 SyntaxKind::{FN, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
12 SyntaxNode, 12 SyntaxNode,
13}; 13};
14 14
15use crate::{ 15use crate::{
16 assist_context::{AssistContext, Assists}, 16 assist_context::{AssistContext, Assists},
17 utils::invert_boolean_expression, 17 utils::invert_boolean_expression,
18 AssistId, 18 AssistId, AssistKind,
19}; 19};
20 20
21// Assist: convert_to_guarded_return 21// Assist: convert_to_guarded_return
@@ -88,7 +88,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
88 88
89 let early_expression: ast::Expr = match parent_container.kind() { 89 let early_expression: ast::Expr = match parent_container.kind() {
90 WHILE_EXPR | LOOP_EXPR => make::expr_continue(), 90 WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
91 FN_DEF => make::expr_return(), 91 FN => make::expr_return(),
92 _ => return None, 92 _ => return None,
93 }; 93 };
94 94
@@ -99,86 +99,92 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
99 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; 99 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
100 100
101 let target = if_expr.syntax().text_range(); 101 let target = if_expr.syntax().text_range();
102 acc.add(AssistId("convert_to_guarded_return"), "Convert to guarded return", target, |edit| { 102 acc.add(
103 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 103 AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
104 let new_block = match if_let_pat { 104 "Convert to guarded return",
105 None => { 105 target,
106 // If. 106 |edit| {
107 let new_expr = { 107 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
108 let then_branch = 108 let new_block = match if_let_pat {
109 make::block_expr(once(make::expr_stmt(early_expression).into()), None); 109 None => {
110 let cond = invert_boolean_expression(cond_expr); 110 // If.
111 make::expr_if(make::condition(cond, None), then_branch).indent(if_indent_level) 111 let new_expr = {
112 }; 112 let then_branch =
113 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) 113 make::block_expr(once(make::expr_stmt(early_expression).into()), None);
114 } 114 let cond = invert_boolean_expression(cond_expr);
115 Some((path, bound_ident)) => { 115 make::expr_if(make::condition(cond, None), then_branch)
116 // If-let. 116 .indent(if_indent_level)
117 let match_expr = {
118 let happy_arm = {
119 let pat = make::tuple_struct_pat(
120 path,
121 once(make::bind_pat(make::name("it")).into()),
122 );
123 let expr = {
124 let name_ref = make::name_ref("it");
125 let segment = make::path_segment(name_ref);
126 let path = make::path_unqualified(segment);
127 make::expr_path(path)
128 };
129 make::match_arm(once(pat.into()), expr)
130 }; 117 };
118 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
119 }
120 Some((path, bound_ident)) => {
121 // If-let.
122 let match_expr = {
123 let happy_arm = {
124 let pat = make::tuple_struct_pat(
125 path,
126 once(make::bind_pat(make::name("it")).into()),
127 );
128 let expr = {
129 let name_ref = make::name_ref("it");
130 let segment = make::path_segment(name_ref);
131 let path = make::path_unqualified(segment);
132 make::expr_path(path)
133 };
134 make::match_arm(once(pat.into()), expr)
135 };
131 136
132 let sad_arm = make::match_arm( 137 let sad_arm = make::match_arm(
133 // FIXME: would be cool to use `None` or `Err(_)` if appropriate 138 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
134 once(make::placeholder_pat().into()), 139 once(make::placeholder_pat().into()),
135 early_expression, 140 early_expression,
136 ); 141 );
137 142
138 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) 143 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
139 }; 144 };
140 145
141 let let_stmt = make::let_stmt( 146 let let_stmt = make::let_stmt(
142 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 147 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
143 Some(match_expr), 148 Some(match_expr),
149 );
150 let let_stmt = let_stmt.indent(if_indent_level);
151 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
152 }
153 };
154 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
155
156 fn replace(
157 new_expr: &SyntaxNode,
158 then_block: &ast::BlockExpr,
159 parent_block: &ast::BlockExpr,
160 if_expr: &ast::IfExpr,
161 ) -> SyntaxNode {
162 let then_block_items = then_block.dedent(IndentLevel(1));
163 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
164 let end_of_then =
165 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
166 end_of_then.prev_sibling_or_token().unwrap()
167 } else {
168 end_of_then
169 };
170 let mut then_statements = new_expr.children_with_tokens().chain(
171 then_block_items
172 .syntax()
173 .children_with_tokens()
174 .skip(1)
175 .take_while(|i| *i != end_of_then),
144 ); 176 );
145 let let_stmt = let_stmt.indent(if_indent_level); 177 replace_children(
146 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) 178 &parent_block.syntax(),
179 RangeInclusive::new(
180 if_expr.clone().syntax().clone().into(),
181 if_expr.syntax().clone().into(),
182 ),
183 &mut then_statements,
184 )
147 } 185 }
148 }; 186 },
149 edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); 187 )
150
151 fn replace(
152 new_expr: &SyntaxNode,
153 then_block: &ast::BlockExpr,
154 parent_block: &ast::BlockExpr,
155 if_expr: &ast::IfExpr,
156 ) -> SyntaxNode {
157 let then_block_items = then_block.dedent(IndentLevel(1));
158 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
159 let end_of_then =
160 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
161 end_of_then.prev_sibling_or_token().unwrap()
162 } else {
163 end_of_then
164 };
165 let mut then_statements = new_expr.children_with_tokens().chain(
166 then_block_items
167 .syntax()
168 .children_with_tokens()
169 .skip(1)
170 .take_while(|i| *i != end_of_then),
171 );
172 replace_children(
173 &parent_block.syntax(),
174 RangeInclusive::new(
175 if_expr.clone().syntax().clone().into(),
176 if_expr.syntax().clone().into(),
177 ),
178 &mut then_statements,
179 )
180 }
181 })
182} 188}
183 189
184#[cfg(test)] 190#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
index 43b4584b4..ccec688ca 100644
--- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -10,7 +10,8 @@ use ra_syntax::{
10use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
11 11
12use crate::{ 12use crate::{
13 assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId, Assists, 13 assist_context::AssistBuilder, utils::insert_use_statement, AssistContext, AssistId,
14 AssistKind, Assists,
14}; 15};
15 16
16// Assist: extract_struct_from_enum_variant 17// Assist: extract_struct_from_enum_variant
@@ -30,30 +31,30 @@ pub(crate) fn extract_struct_from_enum_variant(
30 acc: &mut Assists, 31 acc: &mut Assists,
31 ctx: &AssistContext, 32 ctx: &AssistContext,
32) -> Option<()> { 33) -> Option<()> {
33 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; 34 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
34 let field_list = match variant.kind() { 35 let field_list = match variant.kind() {
35 ast::StructKind::Tuple(field_list) => field_list, 36 ast::StructKind::Tuple(field_list) => field_list,
36 _ => return None, 37 _ => return None,
37 }; 38 };
38 let variant_name = variant.name()?.to_string(); 39 let variant_name = variant.name()?.to_string();
39 let variant_hir = ctx.sema.to_def(&variant)?; 40 let variant_hir = ctx.sema.to_def(&variant)?;
40 if existing_struct_def(ctx.db, &variant_name, &variant_hir) { 41 if existing_struct_def(ctx.db(), &variant_name, &variant_hir) {
41 return None; 42 return None;
42 } 43 }
43 let enum_ast = variant.parent_enum(); 44 let enum_ast = variant.parent_enum();
44 let visibility = enum_ast.visibility(); 45 let visibility = enum_ast.visibility();
45 let enum_hir = ctx.sema.to_def(&enum_ast)?; 46 let enum_hir = ctx.sema.to_def(&enum_ast)?;
46 let variant_hir_name = variant_hir.name(ctx.db); 47 let variant_hir_name = variant_hir.name(ctx.db());
47 let enum_module_def = ModuleDef::from(enum_hir); 48 let enum_module_def = ModuleDef::from(enum_hir);
48 let current_module = enum_hir.module(ctx.db); 49 let current_module = enum_hir.module(ctx.db());
49 let target = variant.syntax().text_range(); 50 let target = variant.syntax().text_range();
50 acc.add( 51 acc.add(
51 AssistId("extract_struct_from_enum_variant"), 52 AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
52 "Extract struct from enum variant", 53 "Extract struct from enum variant",
53 target, 54 target,
54 |builder| { 55 |builder| {
55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); 56 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
56 let res = definition.find_usages(&ctx.db, None); 57 let res = definition.find_usages(&ctx.sema, None);
57 let start_offset = variant.parent_enum().syntax().text_range().start(); 58 let start_offset = variant.parent_enum().syntax().text_range().start();
58 let mut visited_modules_set = FxHashSet::default(); 59 let mut visited_modules_set = FxHashSet::default();
59 visited_modules_set.insert(current_module); 60 visited_modules_set.insert(current_module);
@@ -101,7 +102,7 @@ fn insert_import(
101 enum_module_def: &ModuleDef, 102 enum_module_def: &ModuleDef,
102 variant_hir_name: &Name, 103 variant_hir_name: &Name,
103) -> Option<()> { 104) -> Option<()> {
104 let db = ctx.db; 105 let db = ctx.db();
105 let mod_path = module.find_use_path(db, enum_module_def.clone()); 106 let mod_path = module.find_use_path(db, enum_module_def.clone());
106 if let Some(mut mod_path) = mod_path { 107 if let Some(mut mod_path) = mod_path {
107 mod_path.segments.pop(); 108 mod_path.segments.pop();
diff --git a/crates/ra_assists/src/handlers/extract_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs
index c4150d2bb..b925a2884 100644
--- a/crates/ra_assists/src/handlers/extract_variable.rs
+++ b/crates/ra_assists/src/handlers/extract_variable.rs
@@ -2,14 +2,13 @@ use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 SyntaxKind::{ 3 SyntaxKind::{
4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, 4 BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
5 WHITESPACE,
6 }, 5 },
7 SyntaxNode, 6 SyntaxNode,
8}; 7};
9use stdx::format_to; 8use stdx::format_to;
10use test_utils::mark; 9use test_utils::mark;
11 10
12use crate::{AssistContext, AssistId, Assists}; 11use crate::{AssistContext, AssistId, AssistKind, Assists};
13 12
14// Assist: extract_variable 13// Assist: extract_variable
15// 14//
@@ -36,87 +35,84 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
36 mark::hit!(extract_var_in_comment_is_not_applicable); 35 mark::hit!(extract_var_in_comment_is_not_applicable);
37 return None; 36 return None;
38 } 37 }
39 let expr = node.ancestors().find_map(valid_target_expr)?; 38 let to_extract = node.ancestors().find_map(valid_target_expr)?;
40 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr.clone())?; 39 let anchor = Anchor::from(&to_extract)?;
41 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?.clone(); 40 let indent = anchor.syntax().prev_sibling_or_token()?.as_token()?.clone();
42 if indent.kind() != WHITESPACE { 41 let target = to_extract.syntax().text_range();
43 return None; 42 acc.add(
44 } 43 AssistId("extract_variable", AssistKind::RefactorExtract),
45 let target = expr.syntax().text_range(); 44 "Extract into variable",
46 acc.add(AssistId("extract_variable"), "Extract into variable", target, move |edit| { 45 target,
47 let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { 46 move |edit| {
48 Some(field) => field.name_ref(), 47 let field_shorthand =
49 None => None, 48 match to_extract.syntax().parent().and_then(ast::RecordExprField::cast) {
50 }; 49 Some(field) => field.name_ref(),
51 50 None => None,
52 let mut buf = String::new(); 51 };
53 52
54 let var_name = match &field_shorthand { 53 let mut buf = String::new();
55 Some(it) => it.to_string(), 54
56 None => "var_name".to_string(), 55 let var_name = match &field_shorthand {
57 }; 56 Some(it) => it.to_string(),
58 let expr_range = match &field_shorthand { 57 None => "var_name".to_string(),
59 Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), 58 };
60 None => expr.syntax().text_range(), 59 let expr_range = match &field_shorthand {
61 }; 60 Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()),
62 61 None => to_extract.syntax().text_range(),
63 if wrap_in_block { 62 };
64 format_to!(buf, "{{ let {} = ", var_name); 63
65 } else { 64 if let Anchor::WrapInBlock(_) = anchor {
66 format_to!(buf, "let {} = ", var_name); 65 format_to!(buf, "{{ let {} = ", var_name);
67 }; 66 } else {
68 format_to!(buf, "{}", expr.syntax()); 67 format_to!(buf, "let {} = ", var_name);
69 68 };
70 let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); 69 format_to!(buf, "{}", to_extract.syntax());
71 let is_full_stmt = if let Some(expr_stmt) = &full_stmt { 70
72 Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) 71 if let Anchor::Replace(stmt) = anchor {
73 } else { 72 mark::hit!(test_extract_var_expr_stmt);
74 false 73 if stmt.semicolon_token().is_none() {
75 }; 74 buf.push_str(";");
76 if is_full_stmt { 75 }
77 mark::hit!(test_extract_var_expr_stmt); 76 match ctx.config.snippet_cap {
78 if full_stmt.unwrap().semicolon_token().is_none() { 77 Some(cap) => {
79 buf.push_str(";"); 78 let snip = buf
79 .replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
80 edit.replace_snippet(cap, expr_range, snip)
81 }
82 None => edit.replace(expr_range, buf),
83 }
84 return;
80 } 85 }
86
87 buf.push_str(";");
88
89 // We want to maintain the indent level,
90 // but we do not want to duplicate possible
91 // extra newlines in the indent block
92 let text = indent.text();
93 if text.starts_with('\n') {
94 buf.push_str("\n");
95 buf.push_str(text.trim_start_matches('\n'));
96 } else {
97 buf.push_str(text);
98 }
99
100 edit.replace(expr_range, var_name.clone());
101 let offset = anchor.syntax().text_range().start();
81 match ctx.config.snippet_cap { 102 match ctx.config.snippet_cap {
82 Some(cap) => { 103 Some(cap) => {
83 let snip = 104 let snip =
84 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); 105 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
85 edit.replace_snippet(cap, expr_range, snip) 106 edit.insert_snippet(cap, offset, snip)
86 } 107 }
87 None => edit.replace(expr_range, buf), 108 None => edit.insert(offset, buf),
88 } 109 }
89 return;
90 }
91
92 buf.push_str(";");
93
94 // We want to maintain the indent level,
95 // but we do not want to duplicate possible
96 // extra newlines in the indent block
97 let text = indent.text();
98 if text.starts_with('\n') {
99 buf.push_str("\n");
100 buf.push_str(text.trim_start_matches('\n'));
101 } else {
102 buf.push_str(text);
103 }
104 110
105 edit.replace(expr_range, var_name.clone()); 111 if let Anchor::WrapInBlock(_) = anchor {
106 let offset = anchor_stmt.text_range().start(); 112 edit.insert(anchor.syntax().text_range().end(), " }");
107 match ctx.config.snippet_cap {
108 Some(cap) => {
109 let snip =
110 buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name));
111 edit.insert_snippet(cap, offset, snip)
112 } 113 }
113 None => edit.insert(offset, buf), 114 },
114 } 115 )
115
116 if wrap_in_block {
117 edit.insert(anchor_stmt.text_range().end(), " }");
118 }
119 })
120} 116}
121 117
122/// Check whether the node is a valid expression which can be extracted to a variable. 118/// Check whether the node is a valid expression which can be extracted to a variable.
@@ -133,32 +129,48 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
133 } 129 }
134} 130}
135 131
136/// Returns the syntax node which will follow the freshly extractd var 132enum Anchor {
137/// and a boolean indicating whether we have to wrap it within a { } block 133 Before(SyntaxNode),
138/// to produce correct code. 134 Replace(ast::ExprStmt),
139/// It can be a statement, the last in a block expression or a wanna be block 135 WrapInBlock(SyntaxNode),
140/// expression like a lambda or match arm. 136}
141fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { 137
142 expr.syntax().ancestors().find_map(|node| { 138impl Anchor {
143 if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { 139 fn from(to_extract: &ast::Expr) -> Option<Anchor> {
144 if expr.syntax() == &node { 140 to_extract.syntax().ancestors().find_map(|node| {
145 mark::hit!(test_extract_var_last_expr); 141 if let Some(expr) =
146 return Some((node, false)); 142 node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr())
143 {
144 if expr.syntax() == &node {
145 mark::hit!(test_extract_var_last_expr);
146 return Some(Anchor::Before(node));
147 }
147 } 148 }
148 }
149 149
150 if let Some(parent) = node.parent() { 150 if let Some(parent) = node.parent() {
151 if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR { 151 if parent.kind() == MATCH_ARM || parent.kind() == LAMBDA_EXPR {
152 return Some((node, true)); 152 return Some(Anchor::WrapInBlock(node));
153 }
153 } 154 }
154 }
155 155
156 if ast::Stmt::cast(node.clone()).is_some() { 156 if let Some(stmt) = ast::Stmt::cast(node.clone()) {
157 return Some((node, false)); 157 if let ast::Stmt::ExprStmt(stmt) = stmt {
158 } 158 if stmt.expr().as_ref() == Some(to_extract) {
159 return Some(Anchor::Replace(stmt));
160 }
161 }
162 return Some(Anchor::Before(node));
163 }
164 None
165 })
166 }
159 167
160 None 168 fn syntax(&self) -> &SyntaxNode {
161 }) 169 match self {
170 Anchor::Before(it) | Anchor::WrapInBlock(it) => it,
171 Anchor::Replace(stmt) => stmt.syntax(),
172 }
173 }
162} 174}
163 175
164#[cfg(test)] 176#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 64270c86f..708e1bc6c 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -8,7 +8,7 @@ use test_utils::mark;
8 8
9use crate::{ 9use crate::{
10 utils::{render_snippet, Cursor, FamousDefs}, 10 utils::{render_snippet, Cursor, FamousDefs},
11 AssistContext, AssistId, Assists, 11 AssistContext, AssistId, AssistKind, Assists,
12}; 12};
13 13
14// Assist: fill_match_arms 14// Assist: fill_match_arms
@@ -51,11 +51,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
51 let module = ctx.sema.scope(expr.syntax()).module()?; 51 let module = ctx.sema.scope(expr.syntax()).module()?;
52 52
53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { 53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
54 let variants = enum_def.variants(ctx.db); 54 let variants = enum_def.variants(ctx.db());
55 55
56 let mut variants = variants 56 let mut variants = variants
57 .into_iter() 57 .into_iter()
58 .filter_map(|variant| build_pat(ctx.db, module, variant)) 58 .filter_map(|variant| build_pat(ctx.db(), module, variant))
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
@@ -84,11 +84,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
84 // where each tuple represents a proposed match arm. 84 // where each tuple represents a proposed match arm.
85 enum_defs 85 enum_defs
86 .into_iter() 86 .into_iter()
87 .map(|enum_def| enum_def.variants(ctx.db)) 87 .map(|enum_def| enum_def.variants(ctx.db()))
88 .multi_cartesian_product() 88 .multi_cartesian_product()
89 .map(|variants| { 89 .map(|variants| {
90 let patterns = 90 let patterns =
91 variants.into_iter().filter_map(|variant| build_pat(ctx.db, module, variant)); 91 variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
92 ast::Pat::from(make::tuple_pat(patterns)) 92 ast::Pat::from(make::tuple_pat(patterns))
93 }) 93 })
94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
@@ -103,24 +103,37 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
103 } 103 }
104 104
105 let target = match_expr.syntax().text_range(); 105 let target = match_expr.syntax().text_range();
106 acc.add(AssistId("fill_match_arms"), "Fill match arms", target, |builder| { 106 acc.add(
107 let new_arm_list = match_arm_list.remove_placeholder(); 107 AssistId("fill_match_arms", AssistKind::QuickFix),
108 let n_old_arms = new_arm_list.arms().count(); 108 "Fill match arms",
109 let new_arm_list = new_arm_list.append_arms(missing_arms); 109 target,
110 let first_new_arm = new_arm_list.arms().nth(n_old_arms); 110 |builder| {
111 let old_range = match_arm_list.syntax().text_range(); 111 let new_arm_list = match_arm_list.remove_placeholder();
112 match (first_new_arm, ctx.config.snippet_cap) { 112 let n_old_arms = new_arm_list.arms().count();
113 (Some(first_new_arm), Some(cap)) => { 113 let new_arm_list = new_arm_list.append_arms(missing_arms);
114 let snippet = render_snippet( 114 let first_new_arm = new_arm_list.arms().nth(n_old_arms);
115 cap, 115 let old_range = match_arm_list.syntax().text_range();
116 new_arm_list.syntax(), 116 match (first_new_arm, ctx.config.snippet_cap) {
117 Cursor::Before(first_new_arm.syntax()), 117 (Some(first_new_arm), Some(cap)) => {
118 ); 118 let extend_lifetime;
119 builder.replace_snippet(cap, old_range, snippet); 119 let cursor = match first_new_arm
120 } 120 .syntax()
121 _ => builder.replace(old_range, new_arm_list.to_string()), 121 .descendants()
122 } 122 .find_map(ast::PlaceholderPat::cast)
123 }) 123 {
124 Some(it) => {
125 extend_lifetime = it.syntax().clone();
126 Cursor::Replace(&extend_lifetime)
127 }
128 None => Cursor::Before(first_new_arm.syntax()),
129 };
130 let snippet = render_snippet(cap, new_arm_list.syntax(), cursor);
131 builder.replace_snippet(cap, old_range, snippet);
132 }
133 _ => builder.replace(old_range, new_arm_list.to_string()),
134 }
135 },
136 )
124} 137}
125 138
126fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { 139fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool {
@@ -286,30 +299,22 @@ mod tests {
286 check_assist( 299 check_assist(
287 fill_match_arms, 300 fill_match_arms,
288 r#" 301 r#"
289 enum A { 302enum A { As, Bs, Cs(Option<i32>) }
290 As, 303fn main() {
291 Bs, 304 match A::As<|> {
292 Cs(Option<i32>), 305 A::Cs(_) | A::Bs => {}
293 } 306 }
294 fn main() { 307}
295 match A::As<|> { 308"#,
296 A::Cs(_) | A::Bs => {}
297 }
298 }
299 "#,
300 r#" 309 r#"
301 enum A { 310enum A { As, Bs, Cs(Option<i32>) }
302 As, 311fn main() {
303 Bs, 312 match A::As {
304 Cs(Option<i32>), 313 A::Cs(_) | A::Bs => {}
305 } 314 $0A::As => {}
306 fn main() { 315 }
307 match A::As { 316}
308 A::Cs(_) | A::Bs => {} 317"#,
309 $0A::As => {}
310 }
311 }
312 "#,
313 ); 318 );
314 } 319 }
315 320
@@ -318,47 +323,29 @@ mod tests {
318 check_assist( 323 check_assist(
319 fill_match_arms, 324 fill_match_arms,
320 r#" 325 r#"
321 enum A { 326enum A { As, Bs, Cs, Ds(String), Es(B) }
322 As, 327enum B { Xs, Ys }
323 Bs, 328fn main() {
324 Cs, 329 match A::As<|> {
325 Ds(String), 330 A::Bs if 0 < 1 => {}
326 Es(B), 331 A::Ds(_value) => { let x = 1; }
327 } 332 A::Es(B::Xs) => (),
328 enum B { 333 }
329 Xs, 334}
330 Ys, 335"#,
331 }
332 fn main() {
333 match A::As<|> {
334 A::Bs if 0 < 1 => {}
335 A::Ds(_value) => { let x = 1; }
336 A::Es(B::Xs) => (),
337 }
338 }
339 "#,
340 r#" 336 r#"
341 enum A { 337enum A { As, Bs, Cs, Ds(String), Es(B) }
342 As, 338enum B { Xs, Ys }
343 Bs, 339fn main() {
344 Cs, 340 match A::As {
345 Ds(String), 341 A::Bs if 0 < 1 => {}
346 Es(B), 342 A::Ds(_value) => { let x = 1; }
347 } 343 A::Es(B::Xs) => (),
348 enum B { 344 $0A::As => {}
349 Xs, 345 A::Cs => {}
350 Ys, 346 }
351 } 347}
352 fn main() { 348"#,
353 match A::As {
354 A::Bs if 0 < 1 => {}
355 A::Ds(_value) => { let x = 1; }
356 A::Es(B::Xs) => (),
357 $0A::As => {}
358 A::Cs => {}
359 }
360 }
361 "#,
362 ); 349 );
363 } 350 }
364 351
@@ -367,32 +354,24 @@ mod tests {
367 check_assist( 354 check_assist(
368 fill_match_arms, 355 fill_match_arms,
369 r#" 356 r#"
370 enum A { 357enum A { As, Bs, Cs(Option<i32>) }
371 As, 358fn main() {
372 Bs, 359 match A::As<|> {
373 Cs(Option<i32>), 360 A::As(_) => {}
374 } 361 a @ A::Bs(_) => {}
375 fn main() { 362 }
376 match A::As<|> { 363}
377 A::As(_) => {} 364"#,
378 a @ A::Bs(_) => {}
379 }
380 }
381 "#,
382 r#" 365 r#"
383 enum A { 366enum A { As, Bs, Cs(Option<i32>) }
384 As, 367fn main() {
385 Bs, 368 match A::As {
386 Cs(Option<i32>), 369 A::As(_) => {}
387 } 370 a @ A::Bs(_) => {}
388 fn main() { 371 A::Cs(${0:_}) => {}
389 match A::As { 372 }
390 A::As(_) => {} 373}
391 a @ A::Bs(_) => {} 374"#,
392 $0A::Cs(_) => {}
393 }
394 }
395 "#,
396 ); 375 );
397 } 376 }
398 377
@@ -401,39 +380,27 @@ mod tests {
401 check_assist( 380 check_assist(
402 fill_match_arms, 381 fill_match_arms,
403 r#" 382 r#"
404 enum A { 383enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
405 As,
406 Bs,
407 Cs(String),
408 Ds(String, String),
409 Es { x: usize, y: usize }
410 }
411 384
412 fn main() { 385fn main() {
413 let a = A::As; 386 let a = A::As;
414 match a<|> {} 387 match a<|> {}
415 } 388}
416 "#, 389"#,
417 r#" 390 r#"
418 enum A { 391enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
419 As,
420 Bs,
421 Cs(String),
422 Ds(String, String),
423 Es { x: usize, y: usize }
424 }
425 392
426 fn main() { 393fn main() {
427 let a = A::As; 394 let a = A::As;
428 match a { 395 match a {
429 $0A::As => {} 396 $0A::As => {}
430 A::Bs => {} 397 A::Bs => {}
431 A::Cs(_) => {} 398 A::Cs(_) => {}
432 A::Ds(_, _) => {} 399 A::Ds(_, _) => {}
433 A::Es { x, y } => {} 400 A::Es { x, y } => {}
434 } 401 }
435 } 402}
436 "#, 403"#,
437 ); 404 );
438 } 405 }
439 406
@@ -773,7 +740,7 @@ fn foo(opt: Option<i32>) {
773 r#" 740 r#"
774fn foo(opt: Option<i32>) { 741fn foo(opt: Option<i32>) {
775 match opt { 742 match opt {
776 $0Some(_) => {} 743 Some(${0:_}) => {}
777 None => {} 744 None => {}
778 } 745 }
779} 746}
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 19d4dac5e..1aefa79cc 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -2,7 +2,8 @@ use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ra_db::FileId; 2use ra_db::FileId;
3use ra_syntax::{ast, AstNode, TextRange, TextSize}; 3use ra_syntax::{ast, AstNode, TextRange, TextSize};
4 4
5use crate::{utils::vis_offset, AssistContext, AssistId, Assists}; 5use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
6use ast::VisibilityOwner;
6 7
7// FIXME: this really should be a fix for diagnostic, rather than an assist. 8// FIXME: this really should be a fix for diagnostic, rather than an assist.
8 9
@@ -41,14 +42,15 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
41 }; 42 };
42 43
43 let current_module = ctx.sema.scope(&path.syntax()).module()?; 44 let current_module = ctx.sema.scope(&path.syntax()).module()?;
44 let target_module = def.module(ctx.db)?; 45 let target_module = def.module(ctx.db())?;
45 46
46 let vis = target_module.visibility_of(ctx.db, &def)?; 47 let vis = target_module.visibility_of(ctx.db(), &def)?;
47 if vis.is_visible_from(ctx.db, current_module.into()) { 48 if vis.is_visible_from(ctx.db(), current_module.into()) {
48 return None; 49 return None;
49 }; 50 };
50 51
51 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?; 52 let (offset, current_visibility, target, target_file, target_name) =
53 target_data_for_def(ctx.db(), def)?;
52 54
53 let missing_visibility = 55 let missing_visibility =
54 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 56 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
@@ -58,54 +60,78 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
58 Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), 60 Some(name) => format!("Change visibility of {} to {}", name, missing_visibility),
59 }; 61 };
60 62
61 acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { 63 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
62 builder.edit_file(target_file); 64 builder.edit_file(target_file);
63 match ctx.config.snippet_cap { 65 match ctx.config.snippet_cap {
64 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), 66 Some(cap) => match current_visibility {
65 None => builder.insert(offset, format!("{} ", missing_visibility)), 67 Some(current_visibility) => builder.replace_snippet(
68 cap,
69 current_visibility.syntax().text_range(),
70 format!("$0{}", missing_visibility),
71 ),
72 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
73 },
74 None => match current_visibility {
75 Some(current_visibility) => {
76 builder.replace(current_visibility.syntax().text_range(), missing_visibility)
77 }
78 None => builder.insert(offset, format!("{} ", missing_visibility)),
79 },
66 } 80 }
67 }) 81 })
68} 82}
69 83
70fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 84fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
71 let record_field: ast::RecordField = ctx.find_node_at_offset()?; 85 let record_field: ast::RecordExprField = ctx.find_node_at_offset()?;
72 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; 86 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?;
73 87
74 let current_module = ctx.sema.scope(record_field.syntax()).module()?; 88 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
75 let visibility = record_field_def.visibility(ctx.db); 89 let visibility = record_field_def.visibility(ctx.db());
76 if visibility.is_visible_from(ctx.db, current_module.into()) { 90 if visibility.is_visible_from(ctx.db(), current_module.into()) {
77 return None; 91 return None;
78 } 92 }
79 93
80 let parent = record_field_def.parent_def(ctx.db); 94 let parent = record_field_def.parent_def(ctx.db());
81 let parent_name = parent.name(ctx.db); 95 let parent_name = parent.name(ctx.db());
82 let target_module = parent.module(ctx.db); 96 let target_module = parent.module(ctx.db());
83 97
84 let in_file_source = record_field_def.source(ctx.db); 98 let in_file_source = record_field_def.source(ctx.db());
85 let (offset, target) = match in_file_source.value { 99 let (offset, current_visibility, target) = match in_file_source.value {
86 hir::FieldSource::Named(it) => { 100 hir::FieldSource::Named(it) => {
87 let s = it.syntax(); 101 let s = it.syntax();
88 (vis_offset(s), s.text_range()) 102 (vis_offset(s), it.visibility(), s.text_range())
89 } 103 }
90 hir::FieldSource::Pos(it) => { 104 hir::FieldSource::Pos(it) => {
91 let s = it.syntax(); 105 let s = it.syntax();
92 (vis_offset(s), s.text_range()) 106 (vis_offset(s), it.visibility(), s.text_range())
93 } 107 }
94 }; 108 };
95 109
96 let missing_visibility = 110 let missing_visibility =
97 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 111 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
98 let target_file = in_file_source.file_id.original_file(ctx.db); 112 let target_file = in_file_source.file_id.original_file(ctx.db());
99 113
100 let target_name = record_field_def.name(ctx.db); 114 let target_name = record_field_def.name(ctx.db());
101 let assist_label = 115 let assist_label =
102 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); 116 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
103 117
104 acc.add(AssistId("fix_visibility"), assist_label, target, |builder| { 118 acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
105 builder.edit_file(target_file); 119 builder.edit_file(target_file);
106 match ctx.config.snippet_cap { 120 match ctx.config.snippet_cap {
107 Some(cap) => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), 121 Some(cap) => match current_visibility {
108 None => builder.insert(offset, format!("{} ", missing_visibility)), 122 Some(current_visibility) => builder.replace_snippet(
123 cap,
124 dbg!(current_visibility.syntax()).text_range(),
125 format!("$0{}", missing_visibility),
126 ),
127 None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
128 },
129 None => match current_visibility {
130 Some(current_visibility) => {
131 builder.replace(current_visibility.syntax().text_range(), missing_visibility)
132 }
133 None => builder.insert(offset, format!("{} ", missing_visibility)),
134 },
109 } 135 }
110 }) 136 })
111} 137}
@@ -113,24 +139,30 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
113fn target_data_for_def( 139fn target_data_for_def(
114 db: &dyn HirDatabase, 140 db: &dyn HirDatabase,
115 def: hir::ModuleDef, 141 def: hir::ModuleDef,
116) -> Option<(TextSize, TextRange, FileId, Option<hir::Name>)> { 142) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId, Option<hir::Name>)> {
117 fn offset_target_and_file_id<S, Ast>( 143 fn offset_target_and_file_id<S, Ast>(
118 db: &dyn HirDatabase, 144 db: &dyn HirDatabase,
119 x: S, 145 x: S,
120 ) -> (TextSize, TextRange, FileId) 146 ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId)
121 where 147 where
122 S: HasSource<Ast = Ast>, 148 S: HasSource<Ast = Ast>,
123 Ast: AstNode, 149 Ast: AstNode + ast::VisibilityOwner,
124 { 150 {
125 let source = x.source(db); 151 let source = x.source(db);
126 let in_file_syntax = source.syntax(); 152 let in_file_syntax = source.syntax();
127 let file_id = in_file_syntax.file_id; 153 let file_id = in_file_syntax.file_id;
128 let syntax = in_file_syntax.value; 154 let syntax = in_file_syntax.value;
129 (vis_offset(syntax), syntax.text_range(), file_id.original_file(db.upcast())) 155 let current_visibility = source.value.visibility();
156 (
157 vis_offset(syntax),
158 current_visibility,
159 syntax.text_range(),
160 file_id.original_file(db.upcast()),
161 )
130 } 162 }
131 163
132 let target_name; 164 let target_name;
133 let (offset, target, target_file) = match def { 165 let (offset, current_visibility, target, target_file) = match def {
134 hir::ModuleDef::Function(f) => { 166 hir::ModuleDef::Function(f) => {
135 target_name = Some(f.name(db)); 167 target_name = Some(f.name(db));
136 offset_target_and_file_id(db, f) 168 offset_target_and_file_id(db, f)
@@ -164,13 +196,13 @@ fn target_data_for_def(
164 let in_file_source = m.declaration_source(db)?; 196 let in_file_source = m.declaration_source(db)?;
165 let file_id = in_file_source.file_id.original_file(db.upcast()); 197 let file_id = in_file_source.file_id.original_file(db.upcast());
166 let syntax = in_file_source.value.syntax(); 198 let syntax = in_file_source.value.syntax();
167 (vis_offset(syntax), syntax.text_range(), file_id) 199 (vis_offset(syntax), in_file_source.value.visibility(), syntax.text_range(), file_id)
168 } 200 }
169 // Enum variants can't be private, we can't modify builtin types 201 // Enum variants can't be private, we can't modify builtin types
170 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, 202 hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None,
171 }; 203 };
172 204
173 Some((offset, target, target_file, target_name)) 205 Some((offset, current_visibility, target, target_file, target_name))
174} 206}
175 207
176#[cfg(test)] 208#[cfg(test)]
@@ -523,6 +555,34 @@ struct Bar;
523 } 555 }
524 556
525 #[test] 557 #[test]
558 fn replaces_pub_crate_with_pub() {
559 check_assist(
560 fix_visibility,
561 r"
562//- /main.rs crate:a deps:foo
563foo::Bar<|>
564//- /lib.rs crate:foo
565pub(crate) struct Bar;
566",
567 r"$0pub struct Bar;
568",
569 );
570 check_assist(
571 fix_visibility,
572 r"
573//- /main.rs crate:a deps:foo
574fn main() {
575 foo::Foo { <|>bar: () };
576}
577//- /lib.rs crate:foo
578pub struct Foo { pub(crate) bar: () }
579",
580 r"pub struct Foo { $0pub bar: () }
581",
582 );
583 }
584
585 #[test]
526 #[ignore] 586 #[ignore]
527 // FIXME handle reexports properly 587 // FIXME handle reexports properly
528 fn fix_visibility_of_reexport() { 588 fn fix_visibility_of_reexport() {
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs
index 573196576..3cd532650 100644
--- a/crates/ra_assists/src/handlers/flip_binexpr.rs
+++ b/crates/ra_assists/src/handlers/flip_binexpr.rs
@@ -1,6 +1,6 @@
1use ra_syntax::ast::{AstNode, BinExpr, BinOp}; 1use ra_syntax::ast::{AstNode, BinExpr, BinOp};
2 2
3use crate::{AssistContext, AssistId, Assists}; 3use crate::{AssistContext, AssistId, AssistKind, Assists};
4 4
5// Assist: flip_binexpr 5// Assist: flip_binexpr
6// 6//
@@ -33,13 +33,18 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
33 return None; 33 return None;
34 } 34 }
35 35
36 acc.add(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { 36 acc.add(
37 if let FlipAction::FlipAndReplaceOp(new_op) = action { 37 AssistId("flip_binexpr", AssistKind::RefactorRewrite),
38 edit.replace(op_range, new_op); 38 "Flip binary expression",
39 } 39 op_range,
40 edit.replace(lhs.text_range(), rhs.text()); 40 |edit| {
41 edit.replace(rhs.text_range(), lhs.text()); 41 if let FlipAction::FlipAndReplaceOp(new_op) = action {
42 }) 42 edit.replace(op_range, new_op);
43 }
44 edit.replace(lhs.text_range(), rhs.text());
45 edit.replace(rhs.text_range(), lhs.text());
46 },
47 )
43} 48}
44 49
45enum FlipAction { 50enum FlipAction {
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs
index a57a1c463..55a971dc7 100644
--- a/crates/ra_assists/src/handlers/flip_comma.rs
+++ b/crates/ra_assists/src/handlers/flip_comma.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{algo::non_trivia_sibling, Direction, T}; 1use ra_syntax::{algo::non_trivia_sibling, Direction, T};
2 2
3use crate::{AssistContext, AssistId, Assists}; 3use crate::{AssistContext, AssistId, AssistKind, Assists};
4 4
5// Assist: flip_comma 5// Assist: flip_comma
6// 6//
@@ -28,10 +28,15 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 return None; 28 return None;
29 } 29 }
30 30
31 acc.add(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { 31 acc.add(
32 edit.replace(prev.text_range(), next.to_string()); 32 AssistId("flip_comma", AssistKind::RefactorRewrite),
33 edit.replace(next.text_range(), prev.to_string()); 33 "Flip comma",
34 }) 34 comma.text_range(),
35 |edit| {
36 edit.replace(prev.text_range(), next.to_string());
37 edit.replace(next.text_range(), prev.to_string());
38 },
39 )
35} 40}
36 41
37#[cfg(test)] 42#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs
index 0115adc8b..1234f4d29 100644
--- a/crates/ra_assists/src/handlers/flip_trait_bound.rs
+++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 Direction, T, 4 Direction, T,
5}; 5};
6 6
7use crate::{AssistContext, AssistId, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
8 8
9// Assist: flip_trait_bound 9// Assist: flip_trait_bound
10// 10//
@@ -33,10 +33,15 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext) -> Option
33 ); 33 );
34 34
35 let target = plus.text_range(); 35 let target = plus.text_range();
36 acc.add(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { 36 acc.add(
37 edit.replace(before.text_range(), after.to_string()); 37 AssistId("flip_trait_bound", AssistKind::RefactorRewrite),
38 edit.replace(after.text_range(), before.to_string()); 38 "Flip trait bounds",
39 }) 39 target,
40 |edit| {
41 edit.replace(before.text_range(), after.to_string());
42 edit.replace(after.text_range(), before.to_string());
43 },
44 )
40} 45}
41 46
42#[cfg(test)] 47#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/generate_derive.rs
index b123b8498..90ece9fab 100644
--- a/crates/ra_assists/src/handlers/add_derive.rs
+++ b/crates/ra_assists/src/handlers/generate_derive.rs
@@ -4,9 +4,9 @@ use ra_syntax::{
4 TextSize, 4 TextSize,
5}; 5};
6 6
7use crate::{AssistContext, AssistId, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
8 8
9// Assist: add_derive 9// Assist: generate_derive
10// 10//
11// Adds a new `#[derive()]` clause to a struct or enum. 11// Adds a new `#[derive()]` clause to a struct or enum.
12// 12//
@@ -24,36 +24,41 @@ use crate::{AssistContext, AssistId, Assists};
24// y: u32, 24// y: u32,
25// } 25// }
26// ``` 26// ```
27pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 27pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let cap = ctx.config.snippet_cap?; 28 let cap = ctx.config.snippet_cap?;
29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.find_node_at_offset::<ast::AdtDef>()?;
30 let node_start = derive_insertion_offset(&nominal)?; 30 let node_start = derive_insertion_offset(&nominal)?;
31 let target = nominal.syntax().text_range(); 31 let target = nominal.syntax().text_range();
32 acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| { 32 acc.add(
33 let derive_attr = nominal 33 AssistId("generate_derive", AssistKind::Generate),
34 .attrs() 34 "Add `#[derive]`",
35 .filter_map(|x| x.as_simple_call()) 35 target,
36 .filter(|(name, _arg)| name == "derive") 36 |builder| {
37 .map(|(_name, arg)| arg) 37 let derive_attr = nominal
38 .next(); 38 .attrs()
39 match derive_attr { 39 .filter_map(|x| x.as_simple_call())
40 None => { 40 .filter(|(name, _arg)| name == "derive")
41 builder.insert_snippet(cap, node_start, "#[derive($0)]\n"); 41 .map(|(_name, arg)| arg)
42 } 42 .next();
43 Some(tt) => { 43 match derive_attr {
44 // Just move the cursor. 44 None => {
45 builder.insert_snippet( 45 builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
46 cap, 46 }
47 tt.syntax().text_range().end() - TextSize::of(')'), 47 Some(tt) => {
48 "$0", 48 // Just move the cursor.
49 ) 49 builder.insert_snippet(
50 } 50 cap,
51 }; 51 tt.syntax().text_range().end() - TextSize::of(')'),
52 }) 52 "$0",
53 )
54 }
55 };
56 },
57 )
53} 58}
54 59
55// Insert `derive` after doc comments. 60// Insert `derive` after doc comments.
56fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextSize> { 61fn derive_insertion_offset(nominal: &ast::AdtDef) -> Option<TextSize> {
57 let non_ws_child = nominal 62 let non_ws_child = nominal
58 .syntax() 63 .syntax()
59 .children_with_tokens() 64 .children_with_tokens()
@@ -70,12 +75,12 @@ mod tests {
70 #[test] 75 #[test]
71 fn add_derive_new() { 76 fn add_derive_new() {
72 check_assist( 77 check_assist(
73 add_derive, 78 generate_derive,
74 "struct Foo { a: i32, <|>}", 79 "struct Foo { a: i32, <|>}",
75 "#[derive($0)]\nstruct Foo { a: i32, }", 80 "#[derive($0)]\nstruct Foo { a: i32, }",
76 ); 81 );
77 check_assist( 82 check_assist(
78 add_derive, 83 generate_derive,
79 "struct Foo { <|> a: i32, }", 84 "struct Foo { <|> a: i32, }",
80 "#[derive($0)]\nstruct Foo { a: i32, }", 85 "#[derive($0)]\nstruct Foo { a: i32, }",
81 ); 86 );
@@ -84,7 +89,7 @@ mod tests {
84 #[test] 89 #[test]
85 fn add_derive_existing() { 90 fn add_derive_existing() {
86 check_assist( 91 check_assist(
87 add_derive, 92 generate_derive,
88 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", 93 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
89 "#[derive(Clone$0)]\nstruct Foo { a: i32, }", 94 "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
90 ); 95 );
@@ -93,7 +98,7 @@ mod tests {
93 #[test] 98 #[test]
94 fn add_derive_new_with_doc_comment() { 99 fn add_derive_new_with_doc_comment() {
95 check_assist( 100 check_assist(
96 add_derive, 101 generate_derive,
97 " 102 "
98/// `Foo` is a pretty important struct. 103/// `Foo` is a pretty important struct.
99/// It does stuff. 104/// It does stuff.
@@ -111,7 +116,7 @@ struct Foo { a: i32, }
111 #[test] 116 #[test]
112 fn add_derive_target() { 117 fn add_derive_target() {
113 check_assist_target( 118 check_assist_target(
114 add_derive, 119 generate_derive,
115 " 120 "
116struct SomeThingIrrelevant; 121struct SomeThingIrrelevant;
117/// `Foo` is a pretty important struct. 122/// `Foo` is a pretty important struct.
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs
index b0e56e1b5..9da23640a 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -2,9 +2,9 @@ use ra_ide_db::RootDatabase;
2use ra_syntax::ast::{self, AstNode, NameOwner}; 2use ra_syntax::ast::{self, AstNode, NameOwner};
3use test_utils::mark; 3use test_utils::mark;
4 4
5use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; 5use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists};
6 6
7// Assist: add_from_impl_for_enum 7// Assist: generate_from_impl_for_enum
8// 8//
9// Adds a From impl for an enum variant with one tuple field. 9// Adds a From impl for an enum variant with one tuple field.
10// 10//
@@ -21,8 +21,8 @@ use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};
21// } 21// }
22// } 22// }
23// ``` 23// ```
24pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 24pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?; 25 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
26 let variant_name = variant.name()?; 26 let variant_name = variant.name()?;
27 let enum_name = variant.parent_enum().name()?; 27 let enum_name = variant.parent_enum().name()?;
28 let field_list = match variant.kind() { 28 let field_list = match variant.kind() {
@@ -32,7 +32,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) ->
32 if field_list.fields().count() != 1 { 32 if field_list.fields().count() != 1 {
33 return None; 33 return None;
34 } 34 }
35 let field_type = field_list.fields().next()?.type_ref()?; 35 let field_type = field_list.fields().next()?.ty()?;
36 let path = match field_type { 36 let path = match field_type {
37 ast::TypeRef::PathType(it) => it, 37 ast::TypeRef::PathType(it) => it,
38 _ => return None, 38 _ => return None,
@@ -45,8 +45,8 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) ->
45 45
46 let target = variant.syntax().text_range(); 46 let target = variant.syntax().text_range();
47 acc.add( 47 acc.add(
48 AssistId("add_from_impl_for_enum"), 48 AssistId("generate_from_impl_for_enum", AssistKind::Generate),
49 "Add From impl for this enum variant", 49 "Generate `From` impl for this enum variant",
50 target, 50 target,
51 |edit| { 51 |edit| {
52 let start_offset = variant.parent_enum().syntax().text_range().end(); 52 let start_offset = variant.parent_enum().syntax().text_range().end();
@@ -69,7 +69,7 @@ impl From<{0}> for {1} {{
69 69
70fn existing_from_impl( 70fn existing_from_impl(
71 sema: &'_ hir::Semantics<'_, RootDatabase>, 71 sema: &'_ hir::Semantics<'_, RootDatabase>,
72 variant: &ast::EnumVariant, 72 variant: &ast::Variant,
73) -> Option<()> { 73) -> Option<()> {
74 let variant = sema.to_def(variant)?; 74 let variant = sema.to_def(variant)?;
75 let enum_ = variant.parent_enum(sema.db); 75 let enum_ = variant.parent_enum(sema.db);
@@ -97,9 +97,9 @@ mod tests {
97 use super::*; 97 use super::*;
98 98
99 #[test] 99 #[test]
100 fn test_add_from_impl_for_enum() { 100 fn test_generate_from_impl_for_enum() {
101 check_assist( 101 check_assist(
102 add_from_impl_for_enum, 102 generate_from_impl_for_enum,
103 "enum A { <|>One(u32) }", 103 "enum A { <|>One(u32) }",
104 r#"enum A { One(u32) } 104 r#"enum A { One(u32) }
105 105
@@ -112,9 +112,9 @@ impl From<u32> for A {
112 } 112 }
113 113
114 #[test] 114 #[test]
115 fn test_add_from_impl_for_enum_complicated_path() { 115 fn test_generate_from_impl_for_enum_complicated_path() {
116 check_assist( 116 check_assist(
117 add_from_impl_for_enum, 117 generate_from_impl_for_enum,
118 r#"enum A { <|>One(foo::bar::baz::Boo) }"#, 118 r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
119 r#"enum A { One(foo::bar::baz::Boo) } 119 r#"enum A { One(foo::bar::baz::Boo) }
120 120
@@ -129,7 +129,7 @@ impl From<foo::bar::baz::Boo> for A {
129 fn check_not_applicable(ra_fixture: &str) { 129 fn check_not_applicable(ra_fixture: &str) {
130 let fixture = 130 let fixture =
131 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); 131 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
132 check_assist_not_applicable(add_from_impl_for_enum, &fixture) 132 check_assist_not_applicable(generate_from_impl_for_enum, &fixture)
133 } 133 }
134 134
135 #[test] 135 #[test]
@@ -166,7 +166,7 @@ impl From<u32> for A {
166 #[test] 166 #[test]
167 fn test_add_from_impl_different_variant_impl_exists() { 167 fn test_add_from_impl_different_variant_impl_exists() {
168 check_assist( 168 check_assist(
169 add_from_impl_for_enum, 169 generate_from_impl_for_enum,
170 r#"enum A { <|>One(u32), Two(String), } 170 r#"enum A { <|>One(u32), Two(String), }
171 171
172impl From<String> for A { 172impl From<String> for A {
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/generate_function.rs
index 1cfbd75aa..56510861d 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/generate_function.rs
@@ -13,10 +13,10 @@ use rustc_hash::{FxHashMap, FxHashSet};
13use crate::{ 13use crate::{
14 assist_config::SnippetCap, 14 assist_config::SnippetCap,
15 utils::{render_snippet, Cursor}, 15 utils::{render_snippet, Cursor},
16 AssistContext, AssistId, Assists, 16 AssistContext, AssistId, AssistKind, Assists,
17}; 17};
18 18
19// Assist: add_function 19// Assist: generate_function
20// 20//
21// Adds a stub function with a signature matching the function under the cursor. 21// Adds a stub function with a signature matching the function under the cursor.
22// 22//
@@ -41,7 +41,7 @@ use crate::{
41// } 41// }
42// 42//
43// ``` 43// ```
44pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 44pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
45 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; 45 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
46 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; 46 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
47 let path = path_expr.path()?; 47 let path = path_expr.path()?;
@@ -62,22 +62,27 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
62 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; 62 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
63 63
64 let target = call.syntax().text_range(); 64 let target = call.syntax().text_range();
65 acc.add(AssistId("add_function"), "Add function", target, |builder| { 65 acc.add(
66 let function_template = function_builder.render(); 66 AssistId("generate_function", AssistKind::Generate),
67 builder.edit_file(function_template.file); 67 format!("Generate `{}` function", function_builder.fn_name),
68 let new_fn = function_template.to_string(ctx.config.snippet_cap); 68 target,
69 match ctx.config.snippet_cap { 69 |builder| {
70 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), 70 let function_template = function_builder.render();
71 None => builder.insert(function_template.insert_offset, new_fn), 71 builder.edit_file(function_template.file);
72 } 72 let new_fn = function_template.to_string(ctx.config.snippet_cap);
73 }) 73 match ctx.config.snippet_cap {
74 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
75 None => builder.insert(function_template.insert_offset, new_fn),
76 }
77 },
78 )
74} 79}
75 80
76struct FunctionTemplate { 81struct FunctionTemplate {
77 insert_offset: TextSize, 82 insert_offset: TextSize,
78 placeholder_expr: ast::MacroCall, 83 placeholder_expr: ast::MacroCall,
79 leading_ws: String, 84 leading_ws: String,
80 fn_def: ast::FnDef, 85 fn_def: ast::Fn,
81 trailing_ws: String, 86 trailing_ws: String,
82 file: FileId, 87 file: FileId,
83} 88}
@@ -99,7 +104,7 @@ impl FunctionTemplate {
99struct FunctionBuilder { 104struct FunctionBuilder {
100 target: GeneratedFunctionTarget, 105 target: GeneratedFunctionTarget,
101 fn_name: ast::Name, 106 fn_name: ast::Name,
102 type_params: Option<ast::TypeParamList>, 107 type_params: Option<ast::GenericParamList>,
103 params: ast::ParamList, 108 params: ast::ParamList,
104 file: FileId, 109 file: FileId,
105 needs_pub: bool, 110 needs_pub: bool,
@@ -117,7 +122,7 @@ impl FunctionBuilder {
117 let mut file = ctx.frange.file_id; 122 let mut file = ctx.frange.file_id;
118 let target = match &target_module { 123 let target = match &target_module {
119 Some(target_module) => { 124 Some(target_module) => {
120 let module_source = target_module.definition_source(ctx.db); 125 let module_source = target_module.definition_source(ctx.db());
121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?; 126 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
122 file = in_file; 127 file = in_file;
123 target 128 target
@@ -195,7 +200,7 @@ fn fn_args(
195 ctx: &AssistContext, 200 ctx: &AssistContext,
196 target_module: hir::Module, 201 target_module: hir::Module,
197 call: &ast::CallExpr, 202 call: &ast::CallExpr,
198) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> { 203) -> Option<(Option<ast::GenericParamList>, ast::ParamList)> {
199 let mut arg_names = Vec::new(); 204 let mut arg_names = Vec::new();
200 let mut arg_types = Vec::new(); 205 let mut arg_types = Vec::new();
201 for arg in call.arg_list()?.args() { 206 for arg in call.arg_list()?.args() {
@@ -269,7 +274,7 @@ fn fn_arg_type(
269 return None; 274 return None;
270 } 275 }
271 276
272 if let Ok(rendered) = ty.display_source_code(ctx.db, target_module.into()) { 277 if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) {
273 Some(rendered) 278 Some(rendered)
274 } else { 279 } else {
275 None 280 None
@@ -333,7 +338,7 @@ mod tests {
333 #[test] 338 #[test]
334 fn add_function_with_no_args() { 339 fn add_function_with_no_args() {
335 check_assist( 340 check_assist(
336 add_function, 341 generate_function,
337 r" 342 r"
338fn foo() { 343fn foo() {
339 bar<|>(); 344 bar<|>();
@@ -356,7 +361,7 @@ fn bar() {
356 // This ensures that the function is correctly generated 361 // This ensures that the function is correctly generated
357 // in the next outer mod or file 362 // in the next outer mod or file
358 check_assist( 363 check_assist(
359 add_function, 364 generate_function,
360 r" 365 r"
361impl Foo { 366impl Foo {
362 fn foo() { 367 fn foo() {
@@ -382,7 +387,7 @@ fn bar() {
382 fn add_function_directly_after_current_block() { 387 fn add_function_directly_after_current_block() {
383 // The new fn should not be created at the end of the file or module 388 // The new fn should not be created at the end of the file or module
384 check_assist( 389 check_assist(
385 add_function, 390 generate_function,
386 r" 391 r"
387fn foo1() { 392fn foo1() {
388 bar<|>(); 393 bar<|>();
@@ -407,7 +412,7 @@ fn foo2() {}
407 #[test] 412 #[test]
408 fn add_function_with_no_args_in_same_module() { 413 fn add_function_with_no_args_in_same_module() {
409 check_assist( 414 check_assist(
410 add_function, 415 generate_function,
411 r" 416 r"
412mod baz { 417mod baz {
413 fn foo() { 418 fn foo() {
@@ -432,7 +437,7 @@ mod baz {
432 #[test] 437 #[test]
433 fn add_function_with_function_call_arg() { 438 fn add_function_with_function_call_arg() {
434 check_assist( 439 check_assist(
435 add_function, 440 generate_function,
436 r" 441 r"
437struct Baz; 442struct Baz;
438fn baz() -> Baz { todo!() } 443fn baz() -> Baz { todo!() }
@@ -457,7 +462,7 @@ fn bar(baz: Baz) {
457 #[test] 462 #[test]
458 fn add_function_with_method_call_arg() { 463 fn add_function_with_method_call_arg() {
459 check_assist( 464 check_assist(
460 add_function, 465 generate_function,
461 r" 466 r"
462struct Baz; 467struct Baz;
463impl Baz { 468impl Baz {
@@ -490,7 +495,7 @@ fn bar(baz: Baz) {
490 #[test] 495 #[test]
491 fn add_function_with_string_literal_arg() { 496 fn add_function_with_string_literal_arg() {
492 check_assist( 497 check_assist(
493 add_function, 498 generate_function,
494 r#" 499 r#"
495fn foo() { 500fn foo() {
496 <|>bar("bar") 501 <|>bar("bar")
@@ -511,7 +516,7 @@ fn bar(arg: &str) {
511 #[test] 516 #[test]
512 fn add_function_with_char_literal_arg() { 517 fn add_function_with_char_literal_arg() {
513 check_assist( 518 check_assist(
514 add_function, 519 generate_function,
515 r#" 520 r#"
516fn foo() { 521fn foo() {
517 <|>bar('x') 522 <|>bar('x')
@@ -532,7 +537,7 @@ fn bar(arg: char) {
532 #[test] 537 #[test]
533 fn add_function_with_int_literal_arg() { 538 fn add_function_with_int_literal_arg() {
534 check_assist( 539 check_assist(
535 add_function, 540 generate_function,
536 r" 541 r"
537fn foo() { 542fn foo() {
538 <|>bar(42) 543 <|>bar(42)
@@ -553,7 +558,7 @@ fn bar(arg: i32) {
553 #[test] 558 #[test]
554 fn add_function_with_cast_int_literal_arg() { 559 fn add_function_with_cast_int_literal_arg() {
555 check_assist( 560 check_assist(
556 add_function, 561 generate_function,
557 r" 562 r"
558fn foo() { 563fn foo() {
559 <|>bar(42 as u8) 564 <|>bar(42 as u8)
@@ -576,7 +581,7 @@ fn bar(arg: u8) {
576 // Ensures that the name of the cast type isn't used 581 // Ensures that the name of the cast type isn't used
577 // in the generated function signature. 582 // in the generated function signature.
578 check_assist( 583 check_assist(
579 add_function, 584 generate_function,
580 r" 585 r"
581fn foo() { 586fn foo() {
582 let x = 42; 587 let x = 42;
@@ -599,7 +604,7 @@ fn bar(x: u8) {
599 #[test] 604 #[test]
600 fn add_function_with_variable_arg() { 605 fn add_function_with_variable_arg() {
601 check_assist( 606 check_assist(
602 add_function, 607 generate_function,
603 r" 608 r"
604fn foo() { 609fn foo() {
605 let worble = (); 610 let worble = ();
@@ -622,7 +627,7 @@ fn bar(worble: ()) {
622 #[test] 627 #[test]
623 fn add_function_with_impl_trait_arg() { 628 fn add_function_with_impl_trait_arg() {
624 check_assist( 629 check_assist(
625 add_function, 630 generate_function,
626 r" 631 r"
627trait Foo {} 632trait Foo {}
628fn foo() -> impl Foo { 633fn foo() -> impl Foo {
@@ -651,7 +656,7 @@ fn bar(foo: impl Foo) {
651 #[test] 656 #[test]
652 fn borrowed_arg() { 657 fn borrowed_arg() {
653 check_assist( 658 check_assist(
654 add_function, 659 generate_function,
655 r" 660 r"
656struct Baz; 661struct Baz;
657fn baz() -> Baz { todo!() } 662fn baz() -> Baz { todo!() }
@@ -678,7 +683,7 @@ fn bar(baz: &Baz) {
678 #[test] 683 #[test]
679 fn add_function_with_qualified_path_arg() { 684 fn add_function_with_qualified_path_arg() {
680 check_assist( 685 check_assist(
681 add_function, 686 generate_function,
682 r" 687 r"
683mod Baz { 688mod Baz {
684 pub struct Bof; 689 pub struct Bof;
@@ -709,7 +714,7 @@ fn bar(baz: Baz::Bof) {
709 // FIXME fix printing the generics of a `Ty` to make this test pass 714 // FIXME fix printing the generics of a `Ty` to make this test pass
710 fn add_function_with_generic_arg() { 715 fn add_function_with_generic_arg() {
711 check_assist( 716 check_assist(
712 add_function, 717 generate_function,
713 r" 718 r"
714fn foo<T>(t: T) { 719fn foo<T>(t: T) {
715 <|>bar(t) 720 <|>bar(t)
@@ -732,7 +737,7 @@ fn bar<T>(t: T) {
732 // FIXME Fix function type printing to make this test pass 737 // FIXME Fix function type printing to make this test pass
733 fn add_function_with_fn_arg() { 738 fn add_function_with_fn_arg() {
734 check_assist( 739 check_assist(
735 add_function, 740 generate_function,
736 r" 741 r"
737struct Baz; 742struct Baz;
738impl Baz { 743impl Baz {
@@ -763,7 +768,7 @@ fn bar(arg: fn() -> Baz) {
763 // FIXME Fix closure type printing to make this test pass 768 // FIXME Fix closure type printing to make this test pass
764 fn add_function_with_closure_arg() { 769 fn add_function_with_closure_arg() {
765 check_assist( 770 check_assist(
766 add_function, 771 generate_function,
767 r" 772 r"
768fn foo() { 773fn foo() {
769 let closure = |x: i64| x - 1; 774 let closure = |x: i64| x - 1;
@@ -786,7 +791,7 @@ fn bar(closure: impl Fn(i64) -> i64) {
786 #[test] 791 #[test]
787 fn unresolveable_types_default_to_unit() { 792 fn unresolveable_types_default_to_unit() {
788 check_assist( 793 check_assist(
789 add_function, 794 generate_function,
790 r" 795 r"
791fn foo() { 796fn foo() {
792 <|>bar(baz) 797 <|>bar(baz)
@@ -807,7 +812,7 @@ fn bar(baz: ()) {
807 #[test] 812 #[test]
808 fn arg_names_dont_overlap() { 813 fn arg_names_dont_overlap() {
809 check_assist( 814 check_assist(
810 add_function, 815 generate_function,
811 r" 816 r"
812struct Baz; 817struct Baz;
813fn baz() -> Baz { Baz } 818fn baz() -> Baz { Baz }
@@ -832,7 +837,7 @@ fn bar(baz_1: Baz, baz_2: Baz) {
832 #[test] 837 #[test]
833 fn arg_name_counters_start_at_1_per_name() { 838 fn arg_name_counters_start_at_1_per_name() {
834 check_assist( 839 check_assist(
835 add_function, 840 generate_function,
836 r#" 841 r#"
837struct Baz; 842struct Baz;
838fn baz() -> Baz { Baz } 843fn baz() -> Baz { Baz }
@@ -857,7 +862,7 @@ fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
857 #[test] 862 #[test]
858 fn add_function_in_module() { 863 fn add_function_in_module() {
859 check_assist( 864 check_assist(
860 add_function, 865 generate_function,
861 r" 866 r"
862mod bar {} 867mod bar {}
863 868
@@ -885,7 +890,7 @@ fn foo() {
885 // See https://github.com/rust-analyzer/rust-analyzer/issues/1165 890 // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
886 fn qualified_path_uses_correct_scope() { 891 fn qualified_path_uses_correct_scope() {
887 check_assist( 892 check_assist(
888 add_function, 893 generate_function,
889 " 894 "
890mod foo { 895mod foo {
891 pub struct Foo; 896 pub struct Foo;
@@ -916,7 +921,7 @@ fn baz(foo: foo::Foo) {
916 #[test] 921 #[test]
917 fn add_function_in_module_containing_other_items() { 922 fn add_function_in_module_containing_other_items() {
918 check_assist( 923 check_assist(
919 add_function, 924 generate_function,
920 r" 925 r"
921mod bar { 926mod bar {
922 fn something_else() {} 927 fn something_else() {}
@@ -945,7 +950,7 @@ fn foo() {
945 #[test] 950 #[test]
946 fn add_function_in_nested_module() { 951 fn add_function_in_nested_module() {
947 check_assist( 952 check_assist(
948 add_function, 953 generate_function,
949 r" 954 r"
950mod bar { 955mod bar {
951 mod baz {} 956 mod baz {}
@@ -974,7 +979,7 @@ fn foo() {
974 #[test] 979 #[test]
975 fn add_function_in_another_file() { 980 fn add_function_in_another_file() {
976 check_assist( 981 check_assist(
977 add_function, 982 generate_function,
978 r" 983 r"
979//- /main.rs 984//- /main.rs
980mod foo; 985mod foo;
@@ -996,7 +1001,7 @@ pub(crate) fn bar() {
996 #[test] 1001 #[test]
997 fn add_function_not_applicable_if_function_already_exists() { 1002 fn add_function_not_applicable_if_function_already_exists() {
998 check_assist_not_applicable( 1003 check_assist_not_applicable(
999 add_function, 1004 generate_function,
1000 r" 1005 r"
1001fn foo() { 1006fn foo() {
1002 bar<|>(); 1007 bar<|>();
@@ -1013,7 +1018,7 @@ fn bar() {}
1013 // bar is resolved, but baz isn't. 1018 // bar is resolved, but baz isn't.
1014 // The assist is only active if the cursor is on an unresolved path, 1019 // The assist is only active if the cursor is on an unresolved path,
1015 // but the assist should only be offered if the path is a function call. 1020 // but the assist should only be offered if the path is a function call.
1016 add_function, 1021 generate_function,
1017 r" 1022 r"
1018fn foo() { 1023fn foo() {
1019 bar(b<|>az); 1024 bar(b<|>az);
@@ -1028,7 +1033,7 @@ fn bar(baz: ()) {}
1028 #[ignore] 1033 #[ignore]
1029 fn create_method_with_no_args() { 1034 fn create_method_with_no_args() {
1030 check_assist( 1035 check_assist(
1031 add_function, 1036 generate_function,
1032 r" 1037 r"
1033struct Foo; 1038struct Foo;
1034impl Foo { 1039impl Foo {
diff --git a/crates/ra_assists/src/handlers/generate_impl.rs b/crates/ra_assists/src/handlers/generate_impl.rs
new file mode 100644
index 000000000..d9b87c9c0
--- /dev/null
+++ b/crates/ra_assists/src/handlers/generate_impl.rs
@@ -0,0 +1,109 @@
1use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner};
2use stdx::{format_to, SepBy};
3
4use crate::{AssistContext, AssistId, AssistKind, Assists};
5
6// Assist: generate_impl
7//
8// Adds a new inherent impl for a type.
9//
10// ```
11// struct Ctx<T: Clone> {
12// data: T,<|>
13// }
14// ```
15// ->
16// ```
17// struct Ctx<T: Clone> {
18// data: T,
19// }
20//
21// impl<T: Clone> Ctx<T> {
22// $0
23// }
24// ```
25pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let nominal = ctx.find_node_at_offset::<ast::AdtDef>()?;
27 let name = nominal.name()?;
28 let target = nominal.syntax().text_range();
29 acc.add(
30 AssistId("generate_impl", AssistKind::Generate),
31 format!("Generate impl for `{}`", name),
32 target,
33 |edit| {
34 let type_params = nominal.generic_param_list();
35 let start_offset = nominal.syntax().text_range().end();
36 let mut buf = String::new();
37 buf.push_str("\n\nimpl");
38 if let Some(type_params) = &type_params {
39 format_to!(buf, "{}", type_params.syntax());
40 }
41 buf.push_str(" ");
42 buf.push_str(name.text().as_str());
43 if let Some(type_params) = type_params {
44 let lifetime_params = type_params
45 .lifetime_params()
46 .filter_map(|it| it.lifetime_token())
47 .map(|it| it.text().clone());
48 let type_params = type_params
49 .type_params()
50 .filter_map(|it| it.name())
51 .map(|it| it.text().clone());
52
53 let generic_params = lifetime_params.chain(type_params).sep_by(", ");
54 format_to!(buf, "<{}>", generic_params)
55 }
56 match ctx.config.snippet_cap {
57 Some(cap) => {
58 buf.push_str(" {\n $0\n}");
59 edit.insert_snippet(cap, start_offset, buf);
60 }
61 None => {
62 buf.push_str(" {\n}");
63 edit.insert(start_offset, buf);
64 }
65 }
66 },
67 )
68}
69
70#[cfg(test)]
71mod tests {
72 use crate::tests::{check_assist, check_assist_target};
73
74 use super::*;
75
76 #[test]
77 fn test_add_impl() {
78 check_assist(
79 generate_impl,
80 "struct Foo {<|>}\n",
81 "struct Foo {}\n\nimpl Foo {\n $0\n}\n",
82 );
83 check_assist(
84 generate_impl,
85 "struct Foo<T: Clone> {<|>}",
86 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
87 );
88 check_assist(
89 generate_impl,
90 "struct Foo<'a, T: Foo<'a>> {<|>}",
91 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
92 );
93 }
94
95 #[test]
96 fn add_impl_target() {
97 check_assist_target(
98 generate_impl,
99 "
100struct SomeThingIrrelevant;
101/// Has a lifetime parameter
102struct Foo<'a, T: Foo<'a>> {<|>}
103struct EvenMoreIrrelevant;
104",
105 "/// Has a lifetime parameter
106struct Foo<'a, T: Foo<'a>> {}",
107 );
108 }
109}
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/generate_new.rs
index 837aa8377..b84aa24b6 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/generate_new.rs
@@ -1,15 +1,13 @@
1use hir::Adt; 1use hir::Adt;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{ 3 ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner},
4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
5 },
6 T, 4 T,
7}; 5};
8use stdx::{format_to, SepBy}; 6use stdx::{format_to, SepBy};
9 7
10use crate::{AssistContext, AssistId, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
11 9
12// Assist: add_new 10// Assist: generate_new
13// 11//
14// Adds a new inherent impl for a type. 12// Adds a new inherent impl for a type.
15// 13//
@@ -29,8 +27,8 @@ use crate::{AssistContext, AssistId, Assists};
29// } 27// }
30// 28//
31// ``` 29// ```
32pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 30pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; 31 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
34 32
35 // We want to only apply this to non-union structs with named fields 33 // We want to only apply this to non-union structs with named fields
36 let field_list = match strukt.kind() { 34 let field_list = match strukt.kind() {
@@ -42,7 +40,7 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42 let impl_def = find_struct_impl(&ctx, &strukt)?; 40 let impl_def = find_struct_impl(&ctx, &strukt)?;
43 41
44 let target = strukt.syntax().text_range(); 42 let target = strukt.syntax().text_range();
45 acc.add(AssistId("add_new"), "Add default constructor", target, |builder| { 43 acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
46 let mut buf = String::with_capacity(512); 44 let mut buf = String::with_capacity(512);
47 45
48 if impl_def.is_some() { 46 if impl_def.is_some() {
@@ -53,9 +51,7 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
53 51
54 let params = field_list 52 let params = field_list
55 .fields() 53 .fields()
56 .filter_map(|f| { 54 .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax())))
57 Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax()))
58 })
59 .sep_by(", "); 55 .sep_by(", ");
60 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); 56 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", ");
61 57
@@ -90,8 +86,8 @@ pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
90 86
91// Generates the surrounding `impl Type { <code> }` including type and lifetime 87// Generates the surrounding `impl Type { <code> }` including type and lifetime
92// parameters 88// parameters
93fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { 89fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String {
94 let type_params = strukt.type_param_list(); 90 let type_params = strukt.generic_param_list();
95 let mut buf = String::with_capacity(code.len()); 91 let mut buf = String::with_capacity(code.len());
96 buf.push_str("\n\nimpl"); 92 buf.push_str("\n\nimpl");
97 if let Some(type_params) = &type_params { 93 if let Some(type_params) = &type_params {
@@ -121,15 +117,15 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
121// 117//
122// FIXME: change the new fn checking to a more semantic approach when that's more 118// FIXME: change the new fn checking to a more semantic approach when that's more
123// viable (e.g. we process proc macros, etc) 119// viable (e.g. we process proc macros, etc)
124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { 120fn find_struct_impl(ctx: &AssistContext, strukt: &ast::Struct) -> Option<Option<ast::Impl>> {
125 let db = ctx.db; 121 let db = ctx.db();
126 let module = strukt.syntax().ancestors().find(|node| { 122 let module = strukt.syntax().ancestors().find(|node| {
127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 123 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
128 })?; 124 })?;
129 125
130 let struct_def = ctx.sema.to_def(strukt)?; 126 let struct_def = ctx.sema.to_def(strukt)?;
131 127
132 let block = module.descendants().filter_map(ast::ImplDef::cast).find_map(|impl_blk| { 128 let block = module.descendants().filter_map(ast::Impl::cast).find_map(|impl_blk| {
133 let blk = ctx.sema.to_def(&impl_blk)?; 129 let blk = ctx.sema.to_def(&impl_blk)?;
134 130
135 // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}` 131 // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}`
@@ -157,10 +153,10 @@ fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Opti
157 Some(block) 153 Some(block)
158} 154}
159 155
160fn has_new_fn(imp: &ast::ImplDef) -> bool { 156fn has_new_fn(imp: &ast::Impl) -> bool {
161 if let Some(il) = imp.item_list() { 157 if let Some(il) = imp.assoc_item_list() {
162 for item in il.assoc_items() { 158 for item in il.assoc_items() {
163 if let ast::AssocItem::FnDef(f) = item { 159 if let ast::AssocItem::Fn(f) = item {
164 if let Some(name) = f.name() { 160 if let Some(name) = f.name() {
165 if name.text().eq_ignore_ascii_case("new") { 161 if name.text().eq_ignore_ascii_case("new") {
166 return true; 162 return true;
@@ -181,10 +177,10 @@ mod tests {
181 177
182 #[test] 178 #[test]
183 #[rustfmt::skip] 179 #[rustfmt::skip]
184 fn test_add_new() { 180 fn test_generate_new() {
185 // Check output of generation 181 // Check output of generation
186 check_assist( 182 check_assist(
187 add_new, 183 generate_new,
188"struct Foo {<|>}", 184"struct Foo {<|>}",
189"struct Foo {} 185"struct Foo {}
190 186
@@ -194,7 +190,7 @@ impl Foo {
194", 190",
195 ); 191 );
196 check_assist( 192 check_assist(
197 add_new, 193 generate_new,
198"struct Foo<T: Clone> {<|>}", 194"struct Foo<T: Clone> {<|>}",
199"struct Foo<T: Clone> {} 195"struct Foo<T: Clone> {}
200 196
@@ -204,7 +200,7 @@ impl<T: Clone> Foo<T> {
204", 200",
205 ); 201 );
206 check_assist( 202 check_assist(
207 add_new, 203 generate_new,
208"struct Foo<'a, T: Foo<'a>> {<|>}", 204"struct Foo<'a, T: Foo<'a>> {<|>}",
209"struct Foo<'a, T: Foo<'a>> {} 205"struct Foo<'a, T: Foo<'a>> {}
210 206
@@ -214,7 +210,7 @@ impl<'a, T: Foo<'a>> Foo<'a, T> {
214", 210",
215 ); 211 );
216 check_assist( 212 check_assist(
217 add_new, 213 generate_new,
218"struct Foo { baz: String <|>}", 214"struct Foo { baz: String <|>}",
219"struct Foo { baz: String } 215"struct Foo { baz: String }
220 216
@@ -224,7 +220,7 @@ impl Foo {
224", 220",
225 ); 221 );
226 check_assist( 222 check_assist(
227 add_new, 223 generate_new,
228"struct Foo { baz: String, qux: Vec<i32> <|>}", 224"struct Foo { baz: String, qux: Vec<i32> <|>}",
229"struct Foo { baz: String, qux: Vec<i32> } 225"struct Foo { baz: String, qux: Vec<i32> }
230 226
@@ -236,7 +232,7 @@ impl Foo {
236 232
237 // Check that visibility modifiers don't get brought in for fields 233 // Check that visibility modifiers don't get brought in for fields
238 check_assist( 234 check_assist(
239 add_new, 235 generate_new,
240"struct Foo { pub baz: String, pub qux: Vec<i32> <|>}", 236"struct Foo { pub baz: String, pub qux: Vec<i32> <|>}",
241"struct Foo { pub baz: String, pub qux: Vec<i32> } 237"struct Foo { pub baz: String, pub qux: Vec<i32> }
242 238
@@ -248,7 +244,7 @@ impl Foo {
248 244
249 // Check that it reuses existing impls 245 // Check that it reuses existing impls
250 check_assist( 246 check_assist(
251 add_new, 247 generate_new,
252"struct Foo {<|>} 248"struct Foo {<|>}
253 249
254impl Foo {} 250impl Foo {}
@@ -261,7 +257,7 @@ impl Foo {
261", 257",
262 ); 258 );
263 check_assist( 259 check_assist(
264 add_new, 260 generate_new,
265"struct Foo {<|>} 261"struct Foo {<|>}
266 262
267impl Foo { 263impl Foo {
@@ -279,7 +275,7 @@ impl Foo {
279 ); 275 );
280 276
281 check_assist( 277 check_assist(
282 add_new, 278 generate_new,
283"struct Foo {<|>} 279"struct Foo {<|>}
284 280
285impl Foo { 281impl Foo {
@@ -304,7 +300,7 @@ impl Foo {
304 300
305 // Check visibility of new fn based on struct 301 // Check visibility of new fn based on struct
306 check_assist( 302 check_assist(
307 add_new, 303 generate_new,
308"pub struct Foo {<|>}", 304"pub struct Foo {<|>}",
309"pub struct Foo {} 305"pub struct Foo {}
310 306
@@ -314,7 +310,7 @@ impl Foo {
314", 310",
315 ); 311 );
316 check_assist( 312 check_assist(
317 add_new, 313 generate_new,
318"pub(crate) struct Foo {<|>}", 314"pub(crate) struct Foo {<|>}",
319"pub(crate) struct Foo {} 315"pub(crate) struct Foo {}
320 316
@@ -326,9 +322,9 @@ impl Foo {
326 } 322 }
327 323
328 #[test] 324 #[test]
329 fn add_new_not_applicable_if_fn_exists() { 325 fn generate_new_not_applicable_if_fn_exists() {
330 check_assist_not_applicable( 326 check_assist_not_applicable(
331 add_new, 327 generate_new,
332 " 328 "
333struct Foo {<|>} 329struct Foo {<|>}
334 330
@@ -340,7 +336,7 @@ impl Foo {
340 ); 336 );
341 337
342 check_assist_not_applicable( 338 check_assist_not_applicable(
343 add_new, 339 generate_new,
344 " 340 "
345struct Foo {<|>} 341struct Foo {<|>}
346 342
@@ -353,9 +349,9 @@ impl Foo {
353 } 349 }
354 350
355 #[test] 351 #[test]
356 fn add_new_target() { 352 fn generate_new_target() {
357 check_assist_target( 353 check_assist_target(
358 add_new, 354 generate_new,
359 " 355 "
360struct SomeThingIrrelevant; 356struct SomeThingIrrelevant;
361/// Has a lifetime parameter 357/// Has a lifetime parameter
@@ -370,7 +366,7 @@ struct Foo<'a, T: Foo<'a>> {}",
370 #[test] 366 #[test]
371 fn test_unrelated_new() { 367 fn test_unrelated_new() {
372 check_assist( 368 check_assist(
373 add_new, 369 generate_new,
374 r##" 370 r##"
375pub struct AstId<N: AstNode> { 371pub struct AstId<N: AstNode> {
376 file_id: HirFileId, 372 file_id: HirFileId,
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index d26e68847..2fdfabaf5 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -7,7 +7,7 @@ use test_utils::mark;
7 7
8use crate::{ 8use crate::{
9 assist_context::{AssistContext, Assists}, 9 assist_context::{AssistContext, Assists},
10 AssistId, 10 AssistId, AssistKind,
11}; 11};
12 12
13// Assist: inline_local_variable 13// Assist: inline_local_variable
@@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
44 44
45 let def = ctx.sema.to_def(&bind_pat)?; 45 let def = ctx.sema.to_def(&bind_pat)?;
46 let def = Definition::Local(def); 46 let def = Definition::Local(def);
47 let refs = def.find_usages(ctx.db, None); 47 let refs = def.find_usages(&ctx.sema, None);
48 if refs.is_empty() { 48 if refs.is_empty() {
49 mark::hit!(test_not_applicable_if_variable_unused); 49 mark::hit!(test_not_applicable_if_variable_unused);
50 return None; 50 return None;
@@ -110,13 +110,19 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
110 let init_in_paren = format!("({})", &init_str); 110 let init_in_paren = format!("({})", &init_str);
111 111
112 let target = bind_pat.syntax().text_range(); 112 let target = bind_pat.syntax().text_range();
113 acc.add(AssistId("inline_local_variable"), "Inline variable", target, move |builder| { 113 acc.add(
114 builder.delete(delete_range); 114 AssistId("inline_local_variable", AssistKind::RefactorInline),
115 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 115 "Inline variable",
116 let replacement = if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 116 target,
117 builder.replace(desc.file_range.range, replacement) 117 move |builder| {
118 } 118 builder.delete(delete_range);
119 }) 119 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
120 let replacement =
121 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
122 builder.replace(desc.file_range.range, replacement)
123 }
124 },
125 )
120} 126}
121 127
122#[cfg(test)] 128#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
index 28fcbc9ba..c3134f64d 100644
--- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
@@ -1,10 +1,10 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, 2 ast::{self, GenericParamsOwner, NameOwner},
3 AstNode, SyntaxKind, TextRange, TextSize, 3 AstNode, SyntaxKind, TextRange, TextSize,
4}; 4};
5use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
6 6
7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, Assists}; 7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
8 8
9static ASSIST_NAME: &str = "introduce_named_lifetime"; 9static ASSIST_NAME: &str = "introduce_named_lifetime";
10static ASSIST_LABEL: &str = "Introduce named lifetime"; 10static ASSIST_LABEL: &str = "Introduce named lifetime";
@@ -38,9 +38,9 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -
38 let lifetime_token = ctx 38 let lifetime_token = ctx
39 .find_token_at_offset(SyntaxKind::LIFETIME) 39 .find_token_at_offset(SyntaxKind::LIFETIME)
40 .filter(|lifetime| lifetime.text() == "'_")?; 40 .filter(|lifetime| lifetime.text() == "'_")?;
41 if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { 41 if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::Fn::cast) {
42 generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) 42 generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range())
43 } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { 43 } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::Impl::cast) {
44 generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) 44 generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range())
45 } else { 45 } else {
46 None 46 None
@@ -50,11 +50,11 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -
50/// Generate the assist for the fn def case 50/// Generate the assist for the fn def case
51fn generate_fn_def_assist( 51fn generate_fn_def_assist(
52 acc: &mut Assists, 52 acc: &mut Assists,
53 fn_def: &ast::FnDef, 53 fn_def: &ast::Fn,
54 lifetime_loc: TextRange, 54 lifetime_loc: TextRange,
55) -> Option<()> { 55) -> Option<()> {
56 let param_list: ast::ParamList = fn_def.param_list()?; 56 let param_list: ast::ParamList = fn_def.param_list()?;
57 let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.type_param_list())?; 57 let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.generic_param_list())?;
58 let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end(); 58 let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end();
59 let self_param = 59 let self_param =
60 // use the self if it's a reference and has no explicit lifetime 60 // use the self if it's a reference and has no explicit lifetime
@@ -67,7 +67,7 @@ fn generate_fn_def_assist(
67 // otherwise, if there's a single reference parameter without a named liftime, use that 67 // otherwise, if there's a single reference parameter without a named liftime, use that
68 let fn_params_without_lifetime: Vec<_> = param_list 68 let fn_params_without_lifetime: Vec<_> = param_list
69 .params() 69 .params()
70 .filter_map(|param| match param.ascribed_type() { 70 .filter_map(|param| match param.ty() {
71 Some(ast::TypeRef::ReferenceType(ascribed_type)) 71 Some(ast::TypeRef::ReferenceType(ascribed_type))
72 if ascribed_type.lifetime_token() == None => 72 if ascribed_type.lifetime_token() == None =>
73 { 73 {
@@ -83,7 +83,7 @@ fn generate_fn_def_assist(
83 _ => return None, 83 _ => return None,
84 } 84 }
85 }; 85 };
86 acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { 86 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
87 add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); 87 add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param);
88 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); 88 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
89 loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); 89 loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param)));
@@ -93,12 +93,12 @@ fn generate_fn_def_assist(
93/// Generate the assist for the impl def case 93/// Generate the assist for the impl def case
94fn generate_impl_def_assist( 94fn generate_impl_def_assist(
95 acc: &mut Assists, 95 acc: &mut Assists,
96 impl_def: &ast::ImplDef, 96 impl_def: &ast::Impl,
97 lifetime_loc: TextRange, 97 lifetime_loc: TextRange,
98) -> Option<()> { 98) -> Option<()> {
99 let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?; 99 let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.generic_param_list())?;
100 let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); 100 let end_of_impl_kw = impl_def.impl_token()?.text_range().end();
101 acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { 101 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
102 add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); 102 add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param);
103 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); 103 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
104 }) 104 })
@@ -107,7 +107,7 @@ fn generate_impl_def_assist(
107/// Given a type parameter list, generate a unique lifetime parameter name 107/// Given a type parameter list, generate a unique lifetime parameter name
108/// which is not in the list 108/// which is not in the list
109fn generate_unique_lifetime_param_name( 109fn generate_unique_lifetime_param_name(
110 existing_type_param_list: &Option<ast::TypeParamList>, 110 existing_type_param_list: &Option<ast::GenericParamList>,
111) -> Option<char> { 111) -> Option<char> {
112 match existing_type_param_list { 112 match existing_type_param_list {
113 Some(type_params) => { 113 Some(type_params) => {
@@ -123,13 +123,13 @@ fn generate_unique_lifetime_param_name(
123 123
124/// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise 124/// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise
125/// add new type params brackets with the lifetime parameter at `new_type_params_loc`. 125/// add new type params brackets with the lifetime parameter at `new_type_params_loc`.
126fn add_lifetime_param<TypeParamsOwner: ast::TypeParamsOwner>( 126fn add_lifetime_param<TypeParamsOwner: ast::GenericParamsOwner>(
127 type_params_owner: &TypeParamsOwner, 127 type_params_owner: &TypeParamsOwner,
128 builder: &mut AssistBuilder, 128 builder: &mut AssistBuilder,
129 new_type_params_loc: TextSize, 129 new_type_params_loc: TextSize,
130 new_lifetime_param: char, 130 new_lifetime_param: char,
131) { 131) {
132 match type_params_owner.type_param_list() { 132 match type_params_owner.generic_param_list() {
133 // add the new lifetime parameter to an existing type param list 133 // add the new lifetime parameter to an existing type param list
134 Some(type_params) => { 134 Some(type_params) => {
135 builder.insert( 135 builder.insert(
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs
index 59d278eb9..bbe3f3643 100644
--- a/crates/ra_assists/src/handlers/invert_if.rs
+++ b/crates/ra_assists/src/handlers/invert_if.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
6use crate::{ 6use crate::{
7 assist_context::{AssistContext, Assists}, 7 assist_context::{AssistContext, Assists},
8 utils::invert_boolean_expression, 8 utils::invert_boolean_expression,
9 AssistId, 9 AssistId, AssistKind,
10}; 10};
11 11
12// Assist: invert_if 12// Assist: invert_if
@@ -54,7 +54,7 @@ pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
54 let else_node = else_block.syntax(); 54 let else_node = else_block.syntax();
55 let else_range = else_node.text_range(); 55 let else_range = else_node.text_range();
56 let then_range = then_node.text_range(); 56 let then_range = then_node.text_range();
57 acc.add(AssistId("invert_if"), "Invert if", if_range, |edit| { 57 acc.add(AssistId("invert_if", AssistKind::RefactorRewrite), "Invert if", if_range, |edit| {
58 edit.replace(cond_range, flip_cond.syntax().text()); 58 edit.replace(cond_range, flip_cond.syntax().text());
59 edit.replace(else_range, then_node.text()); 59 edit.replace(else_range, then_node.text());
60 edit.replace(then_range, else_node.text()); 60 edit.replace(then_range, else_node.text());
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index ac0b3035c..c775fe25c 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -8,7 +8,7 @@ use ra_syntax::{
8 8
9use crate::{ 9use crate::{
10 assist_context::{AssistContext, Assists}, 10 assist_context::{AssistContext, Assists},
11 AssistId, 11 AssistId, AssistKind,
12}; 12};
13 13
14// Assist: merge_imports 14// Assist: merge_imports
@@ -28,7 +28,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
28 let mut rewriter = SyntaxRewriter::default(); 28 let mut rewriter = SyntaxRewriter::default();
29 let mut offset = ctx.offset(); 29 let mut offset = ctx.offset();
30 30
31 if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) { 31 if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) {
32 let (merged, to_delete) = next_prev() 32 let (merged, to_delete) = next_prev()
33 .filter_map(|dir| neighbor(&use_item, dir)) 33 .filter_map(|dir| neighbor(&use_item, dir))
34 .filter_map(|it| Some((it.clone(), it.use_tree()?))) 34 .filter_map(|it| Some((it.clone(), it.use_tree()?)))
@@ -56,9 +56,14 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
56 }; 56 };
57 57
58 let target = tree.syntax().text_range(); 58 let target = tree.syntax().text_range();
59 acc.add(AssistId("merge_imports"), "Merge imports", target, |builder| { 59 acc.add(
60 builder.rewrite(rewriter); 60 AssistId("merge_imports", AssistKind::RefactorRewrite),
61 }) 61 "Merge imports",
62 target,
63 |builder| {
64 builder.rewrite(rewriter);
65 },
66 )
62} 67}
63 68
64fn next_prev() -> impl Iterator<Item = Direction> { 69fn next_prev() -> impl Iterator<Item = Direction> {
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index 90ce66378..186a1f618 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -6,7 +6,7 @@ use ra_syntax::{
6 Direction, 6 Direction,
7}; 7};
8 8
9use crate::{AssistContext, AssistId, Assists, TextRange}; 9use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};
10 10
11// Assist: merge_match_arms 11// Assist: merge_match_arms
12// 12//
@@ -59,25 +59,30 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
59 return None; 59 return None;
60 } 60 }
61 61
62 acc.add(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { 62 acc.add(
63 let pats = if arms_to_merge.iter().any(contains_placeholder) { 63 AssistId("merge_match_arms", AssistKind::RefactorRewrite),
64 "_".into() 64 "Merge match arms",
65 } else { 65 current_text_range,
66 arms_to_merge 66 |edit| {
67 .iter() 67 let pats = if arms_to_merge.iter().any(contains_placeholder) {
68 .filter_map(ast::MatchArm::pat) 68 "_".into()
69 .map(|x| x.syntax().to_string()) 69 } else {
70 .collect::<Vec<String>>() 70 arms_to_merge
71 .join(" | ") 71 .iter()
72 }; 72 .filter_map(ast::MatchArm::pat)
73 73 .map(|x| x.syntax().to_string())
74 let arm = format!("{} => {}", pats, current_expr.syntax().text()); 74 .collect::<Vec<String>>()
75 75 .join(" | ")
76 let start = arms_to_merge.first().unwrap().syntax().text_range().start(); 76 };
77 let end = arms_to_merge.last().unwrap().syntax().text_range().end(); 77
78 78 let arm = format!("{} => {}", pats, current_expr.syntax().text());
79 edit.replace(TextRange::new(start, end), arm); 79
80 }) 80 let start = arms_to_merge.first().unwrap().syntax().text_range().start();
81 let end = arms_to_merge.last().unwrap().syntax().text_range().end();
82
83 edit.replace(TextRange::new(start, end), arm);
84 },
85 )
81} 86}
82 87
83fn contains_placeholder(a: &ast::MatchArm) -> bool { 88fn contains_placeholder(a: &ast::MatchArm) -> bool {
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs
index be2a7eddc..6d394443e 100644
--- a/crates/ra_assists/src/handlers/move_bounds.rs
+++ b/crates/ra_assists/src/handlers/move_bounds.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
5 T, 5 T,
6}; 6};
7 7
8use crate::{AssistContext, AssistId, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
9 9
10// Assist: move_bounds_to_where_clause 10// Assist: move_bounds_to_where_clause
11// 11//
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists};
23// } 23// }
24// ``` 24// ```
25pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?; 26 let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
27 27
28 let mut type_params = type_param_list.type_params(); 28 let mut type_params = type_param_list.type_params();
29 if type_params.all(|p| p.type_bound_list().is_none()) { 29 if type_params.all(|p| p.type_bound_list().is_none()) {
@@ -37,42 +37,49 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext
37 37
38 let anchor = match_ast! { 38 let anchor = match_ast! {
39 match parent { 39 match parent {
40 ast::FnDef(it) => it.body()?.syntax().clone().into(), 40 ast::Fn(it) => it.body()?.syntax().clone().into(),
41 ast::TraitDef(it) => it.item_list()?.syntax().clone().into(), 41 ast::Trait(it) => it.assoc_item_list()?.syntax().clone().into(),
42 ast::ImplDef(it) => it.item_list()?.syntax().clone().into(), 42 ast::Impl(it) => it.assoc_item_list()?.syntax().clone().into(),
43 ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), 43 ast::Enum(it) => it.variant_list()?.syntax().clone().into(),
44 ast::StructDef(it) => { 44 ast::Struct(it) => {
45 it.syntax().children_with_tokens() 45 it.syntax().children_with_tokens()
46 .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == T![;])? 46 .find(|it| it.kind() == RECORD_FIELD_LIST || it.kind() == T![;])?
47 }, 47 },
48 _ => return None 48 _ => return None
49 } 49 }
50 }; 50 };
51 51
52 let target = type_param_list.syntax().text_range(); 52 let target = type_param_list.syntax().text_range();
53 acc.add(AssistId("move_bounds_to_where_clause"), "Move to where clause", target, |edit| { 53 acc.add(
54 let new_params = type_param_list 54 AssistId("move_bounds_to_where_clause", AssistKind::RefactorRewrite),
55 .type_params() 55 "Move to where clause",
56 .filter(|it| it.type_bound_list().is_some()) 56 target,
57 .map(|type_param| { 57 |edit| {
58 let without_bounds = type_param.remove_bounds(); 58 let new_params = type_param_list
59 (type_param, without_bounds) 59 .type_params()
60 }); 60 .filter(|it| it.type_bound_list().is_some())
61 61 .map(|type_param| {
62 let new_type_param_list = type_param_list.replace_descendants(new_params); 62 let without_bounds = type_param.remove_bounds();
63 edit.replace_ast(type_param_list.clone(), new_type_param_list); 63 (type_param, without_bounds)
64 64 });
65 let where_clause = { 65
66 let predicates = type_param_list.type_params().filter_map(build_predicate); 66 let new_type_param_list = type_param_list.replace_descendants(new_params);
67 make::where_clause(predicates) 67 edit.replace_ast(type_param_list.clone(), new_type_param_list);
68 }; 68
69 69 let where_clause = {
70 let to_insert = match anchor.prev_sibling_or_token() { 70 let predicates = type_param_list.type_params().filter_map(build_predicate);
71 Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), 71 make::where_clause(predicates)
72 _ => format!(" {}", where_clause.syntax()), 72 };
73 }; 73
74 edit.insert(anchor.text_range().start(), to_insert); 74 let to_insert = match anchor.prev_sibling_or_token() {
75 }) 75 Some(ref elem) if elem.kind() == WHITESPACE => {
76 format!("{} ", where_clause.syntax())
77 }
78 _ => format!(" {}", where_clause.syntax()),
79 };
80 edit.insert(anchor.text_range().start(), to_insert);
81 },
82 )
76} 83}
77 84
78fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { 85fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index 7edcf0748..4060d34c6 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -3,7 +3,7 @@ use ra_syntax::{
3 SyntaxKind::WHITESPACE, 3 SyntaxKind::WHITESPACE,
4}; 4};
5 5
6use crate::{AssistContext, AssistId, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
7 7
8// Assist: move_guard_to_arm_body 8// Assist: move_guard_to_arm_body
9// 9//
@@ -40,17 +40,22 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
40 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); 40 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
41 41
42 let target = guard.syntax().text_range(); 42 let target = guard.syntax().text_range();
43 acc.add(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { 43 acc.add(
44 match space_before_guard { 44 AssistId("move_guard_to_arm_body", AssistKind::RefactorRewrite),
45 Some(element) if element.kind() == WHITESPACE => { 45 "Move guard to arm body",
46 edit.delete(element.text_range()); 46 target,
47 } 47 |edit| {
48 _ => (), 48 match space_before_guard {
49 }; 49 Some(element) if element.kind() == WHITESPACE => {
50 edit.delete(element.text_range());
51 }
52 _ => (),
53 };
50 54
51 edit.delete(guard.syntax().text_range()); 55 edit.delete(guard.syntax().text_range());
52 edit.replace_node_and_indent(arm_expr.syntax(), buf); 56 edit.replace_node_and_indent(arm_expr.syntax(), buf);
53 }) 57 },
58 )
54} 59}
55 60
56// Assist: move_arm_cond_to_match_guard 61// Assist: move_arm_cond_to_match_guard
@@ -100,7 +105,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex
100 105
101 let target = if_expr.syntax().text_range(); 106 let target = if_expr.syntax().text_range();
102 acc.add( 107 acc.add(
103 AssistId("move_arm_cond_to_match_guard"), 108 AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite),
104 "Move condition to match guard", 109 "Move condition to match guard",
105 target, 110 target,
106 |edit| { 111 |edit| {
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index d22d0aa55..4e8a0c2db 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -1,11 +1,14 @@
1use std::borrow::Cow;
2
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, HasStringValue}, 4 ast::{self, HasQuotes, HasStringValue},
3 AstToken, 5 AstToken,
4 SyntaxKind::{RAW_STRING, STRING}, 6 SyntaxKind::{RAW_STRING, STRING},
5 TextSize, 7 TextRange, TextSize,
6}; 8};
9use test_utils::mark;
7 10
8use crate::{AssistContext, AssistId, Assists}; 11use crate::{AssistContext, AssistId, AssistKind, Assists};
9 12
10// Assist: make_raw_string 13// Assist: make_raw_string
11// 14//
@@ -26,14 +29,24 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext) -> Option<
26 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; 29 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
27 let value = token.value()?; 30 let value = token.value()?;
28 let target = token.syntax().text_range(); 31 let target = token.syntax().text_range();
29 acc.add(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { 32 acc.add(
30 let max_hash_streak = count_hashes(&value); 33 AssistId("make_raw_string", AssistKind::RefactorRewrite),
31 let mut hashes = String::with_capacity(max_hash_streak + 1); 34 "Rewrite as raw string",
32 for _ in 0..hashes.capacity() { 35 target,
33 hashes.push('#'); 36 |edit| {
34 } 37 let hashes = "#".repeat(required_hashes(&value).max(1));
35 edit.replace(token.syntax().text_range(), format!("r{}\"{}\"{}", hashes, value, hashes)); 38 if matches!(value, Cow::Borrowed(_)) {
36 }) 39 // Avoid replacing the whole string to better position the cursor.
40 edit.insert(token.syntax().text_range().start(), format!("r{}", hashes));
41 edit.insert(token.syntax().text_range().end(), format!("{}", hashes));
42 } else {
43 edit.replace(
44 token.syntax().text_range(),
45 format!("r{}\"{}\"{}", hashes, value, hashes),
46 );
47 }
48 },
49 )
37} 50}
38 51
39// Assist: make_usual_string 52// Assist: make_usual_string
@@ -55,11 +68,24 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio
55 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; 68 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
56 let value = token.value()?; 69 let value = token.value()?;
57 let target = token.syntax().text_range(); 70 let target = token.syntax().text_range();
58 acc.add(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { 71 acc.add(
59 // parse inside string to escape `"` 72 AssistId("make_usual_string", AssistKind::RefactorRewrite),
60 let escaped = value.escape_default().to_string(); 73 "Rewrite as regular string",
61 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); 74 target,
62 }) 75 |edit| {
76 // parse inside string to escape `"`
77 let escaped = value.escape_default().to_string();
78 if let Some(offsets) = token.quote_offsets() {
79 if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped {
80 edit.replace(offsets.quotes.0, "\"");
81 edit.replace(offsets.quotes.1, "\"");
82 return;
83 }
84 }
85
86 edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
87 },
88 )
63} 89}
64 90
65// Assist: add_hash 91// Assist: add_hash
@@ -80,7 +106,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext) -> Optio
80pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 106pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
81 let token = ctx.find_token_at_offset(RAW_STRING)?; 107 let token = ctx.find_token_at_offset(RAW_STRING)?;
82 let target = token.text_range(); 108 let target = token.text_range();
83 acc.add(AssistId("add_hash"), "Add # to raw string", target, |edit| { 109 acc.add(AssistId("add_hash", AssistKind::Refactor), "Add #", target, |edit| {
84 edit.insert(token.text_range().start() + TextSize::of('r'), "#"); 110 edit.insert(token.text_range().start() + TextSize::of('r'), "#");
85 edit.insert(token.text_range().end(), "#"); 111 edit.insert(token.text_range().end(), "#");
86 }) 112 })
@@ -102,44 +128,58 @@ pub(crate) fn add_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
102// } 128// }
103// ``` 129// ```
104pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 130pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
105 let token = ctx.find_token_at_offset(RAW_STRING)?; 131 let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
132
106 let text = token.text().as_str(); 133 let text = token.text().as_str();
107 if text.starts_with("r\"") { 134 if !text.starts_with("r#") && text.ends_with('#') {
108 // no hash to remove
109 return None; 135 return None;
110 } 136 }
111 let target = token.text_range(); 137
112 acc.add(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { 138 let existing_hashes = text.chars().skip(1).take_while(|&it| it == '#').count();
113 let result = &text[2..text.len() - 1]; 139
114 let result = if result.starts_with('\"') { 140 let text_range = token.syntax().text_range();
115 // FIXME: this logic is wrong, not only the last has has to handled specially 141 let internal_text = &text[token.text_range_between_quotes()? - text_range.start()];
116 // no more hash, escape 142
117 let internal_str = &result[1..result.len() - 1]; 143 if existing_hashes == required_hashes(internal_text) {
118 format!("\"{}\"", internal_str.escape_default().to_string()) 144 mark::hit!(cant_remove_required_hash);
119 } else { 145 return None;
120 result.to_owned() 146 }
121 }; 147
122 edit.replace(token.text_range(), format!("r{}", result)); 148 acc.add(AssistId("remove_hash", AssistKind::RefactorRewrite), "Remove #", text_range, |edit| {
149 edit.delete(TextRange::at(text_range.start() + TextSize::of('r'), TextSize::of('#')));
150 edit.delete(TextRange::new(text_range.end() - TextSize::of('#'), text_range.end()));
123 }) 151 })
124} 152}
125 153
126fn count_hashes(s: &str) -> usize { 154fn required_hashes(s: &str) -> usize {
127 let mut max_hash_streak = 0usize; 155 let mut res = 0usize;
128 for idx in s.match_indices("\"#").map(|(i, _)| i) { 156 for idx in s.match_indices('"').map(|(i, _)| i) {
129 let (_, sub) = s.split_at(idx + 1); 157 let (_, sub) = s.split_at(idx + 1);
130 let nb_hash = sub.chars().take_while(|c| *c == '#').count(); 158 let n_hashes = sub.chars().take_while(|c| *c == '#').count();
131 if nb_hash > max_hash_streak { 159 res = res.max(n_hashes + 1)
132 max_hash_streak = nb_hash;
133 }
134 } 160 }
135 max_hash_streak 161 res
162}
163
164#[test]
165fn test_required_hashes() {
166 assert_eq!(0, required_hashes("abc"));
167 assert_eq!(0, required_hashes("###"));
168 assert_eq!(1, required_hashes("\""));
169 assert_eq!(2, required_hashes("\"#abc"));
170 assert_eq!(0, required_hashes("#abc"));
171 assert_eq!(3, required_hashes("#ab\"##c"));
172 assert_eq!(5, required_hashes("#ab\"##\"####c"));
136} 173}
137 174
138#[cfg(test)] 175#[cfg(test)]
139mod test { 176mod test {
140 use super::*; 177 use test_utils::mark;
178
141 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 179 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
142 180
181 use super::*;
182
143 #[test] 183 #[test]
144 fn make_raw_string_target() { 184 fn make_raw_string_target() {
145 check_assist_target( 185 check_assist_target(
@@ -341,33 +381,21 @@ string"###;
341 fn remove_hash_works() { 381 fn remove_hash_works() {
342 check_assist( 382 check_assist(
343 remove_hash, 383 remove_hash,
344 r##" 384 r##"fn f() { let s = <|>r#"random string"#; }"##,
345 fn f() { 385 r#"fn f() { let s = r"random string"; }"#,
346 let s = <|>r#"random string"#;
347 }
348 "##,
349 r#"
350 fn f() {
351 let s = r"random string";
352 }
353 "#,
354 ) 386 )
355 } 387 }
356 388
357 #[test] 389 #[test]
358 fn remove_hash_with_quote_works() { 390 fn cant_remove_required_hash() {
359 check_assist( 391 mark::check!(cant_remove_required_hash);
392 check_assist_not_applicable(
360 remove_hash, 393 remove_hash,
361 r##" 394 r##"
362 fn f() { 395 fn f() {
363 let s = <|>r#"random"str"ing"#; 396 let s = <|>r#"random"str"ing"#;
364 } 397 }
365 "##, 398 "##,
366 r#"
367 fn f() {
368 let s = r"random\"str\"ing";
369 }
370 "#,
371 ) 399 )
372 } 400 }
373 401
@@ -389,27 +417,13 @@ string"###;
389 } 417 }
390 418
391 #[test] 419 #[test]
392 fn remove_hash_not_works() { 420 fn remove_hash_doesnt_work() {
393 check_assist_not_applicable( 421 check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>"random string"; }"#);
394 remove_hash,
395 r#"
396 fn f() {
397 let s = <|>"random string";
398 }
399 "#,
400 );
401 } 422 }
402 423
403 #[test] 424 #[test]
404 fn remove_hash_no_hash_not_works() { 425 fn remove_hash_no_hash_doesnt_work() {
405 check_assist_not_applicable( 426 check_assist_not_applicable(remove_hash, r#"fn f() { let s = <|>r"random string"; }"#);
406 remove_hash,
407 r#"
408 fn f() {
409 let s = <|>r"random string";
410 }
411 "#,
412 );
413 } 427 }
414 428
415 #[test] 429 #[test]
@@ -487,14 +501,4 @@ string"###;
487 "#, 501 "#,
488 ); 502 );
489 } 503 }
490
491 #[test]
492 fn count_hashes_test() {
493 assert_eq!(0, count_hashes("abc"));
494 assert_eq!(0, count_hashes("###"));
495 assert_eq!(1, count_hashes("\"#abc"));
496 assert_eq!(0, count_hashes("#abc"));
497 assert_eq!(2, count_hashes("#ab\"##c"));
498 assert_eq!(4, count_hashes("#ab\"##\"####c"));
499 }
500} 504}
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs
index 961ee1731..9430ce1b5 100644
--- a/crates/ra_assists/src/handlers/remove_dbg.rs
+++ b/crates/ra_assists/src/handlers/remove_dbg.rs
@@ -1,9 +1,9 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 TextSize, T, 3 TextRange, TextSize, T,
4}; 4};
5 5
6use crate::{AssistContext, AssistId, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
7 7
8// Assist: remove_dbg 8// Assist: remove_dbg
9// 9//
@@ -27,19 +27,33 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
27 return None; 27 return None;
28 } 28 }
29 29
30 let macro_range = macro_call.syntax().text_range(); 30 let is_leaf = macro_call.syntax().next_sibling().is_none();
31 31
32 let macro_content = { 32 let macro_end = if macro_call.semicolon_token().is_some() {
33 let macro_args = macro_call.token_tree()?.syntax().clone(); 33 macro_call.syntax().text_range().end() - TextSize::of(';')
34 } else {
35 macro_call.syntax().text_range().end()
36 };
34 37
35 let text = macro_args.text(); 38 // macro_range determines what will be deleted and replaced with macro_content
36 let without_parens = TextSize::of('(')..text.len() - TextSize::of(')'); 39 let macro_range = TextRange::new(macro_call.syntax().text_range().start(), macro_end);
37 text.slice(without_parens).to_string() 40 let paste_instead_of_dbg = {
41 let text = macro_call.token_tree()?.syntax().text();
42
43 // leafiness determines if we should include the parenthesis or not
44 let slice_index: TextRange = if is_leaf {
45 // leaf means - we can extract the contents of the dbg! in text
46 TextRange::new(TextSize::of('('), text.len() - TextSize::of(')'))
47 } else {
48 // not leaf - means we should keep the parens
49 TextRange::up_to(text.len())
50 };
51 text.slice(slice_index).to_string()
38 }; 52 };
39 53
40 let target = macro_call.syntax().text_range(); 54 let target = macro_call.syntax().text_range();
41 acc.add(AssistId("remove_dbg"), "Remove dbg!()", target, |builder| { 55 acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
42 builder.replace(macro_range, macro_content); 56 builder.replace(macro_range, paste_instead_of_dbg);
43 }) 57 })
44} 58}
45 59
@@ -99,6 +113,7 @@ fn foo(n: usize) {
99", 113",
100 ); 114 );
101 } 115 }
116
102 #[test] 117 #[test]
103 fn test_remove_dbg_with_brackets_and_braces() { 118 fn test_remove_dbg_with_brackets_and_braces() {
104 check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1"); 119 check_assist(remove_dbg, "dbg![<|>1 + 1]", "1 + 1");
@@ -113,7 +128,7 @@ fn foo(n: usize) {
113 } 128 }
114 129
115 #[test] 130 #[test]
116 fn remove_dbg_target() { 131 fn test_remove_dbg_target() {
117 check_assist_target( 132 check_assist_target(
118 remove_dbg, 133 remove_dbg,
119 " 134 "
@@ -126,4 +141,65 @@ fn foo(n: usize) {
126 "dbg!(n.checked_sub(4))", 141 "dbg!(n.checked_sub(4))",
127 ); 142 );
128 } 143 }
144
145 #[test]
146 fn test_remove_dbg_keep_semicolon() {
147 // https://github.com/rust-analyzer/rust-analyzer/issues/5129#issuecomment-651399779
148 // not quite though
149 // adding a comment at the end of the line makes
150 // the ast::MacroCall to include the semicolon at the end
151 check_assist(
152 remove_dbg,
153 r#"let res = <|>dbg!(1 * 20); // needless comment"#,
154 r#"let res = 1 * 20; // needless comment"#,
155 );
156 }
157
158 #[test]
159 fn test_remove_dbg_keep_expression() {
160 check_assist(
161 remove_dbg,
162 r#"let res = <|>dbg!(a + b).foo();"#,
163 r#"let res = (a + b).foo();"#,
164 );
165 }
166
167 #[test]
168 fn test_remove_dbg_from_inside_fn() {
169 check_assist_target(
170 remove_dbg,
171 r#"
172fn square(x: u32) -> u32 {
173 x * x
174}
175
176fn main() {
177 let x = square(dbg<|>!(5 + 10));
178 println!("{}", x);
179}"#,
180 "dbg!(5 + 10)",
181 );
182
183 check_assist(
184 remove_dbg,
185 r#"
186fn square(x: u32) -> u32 {
187 x * x
188}
189
190fn main() {
191 let x = square(dbg<|>!(5 + 10));
192 println!("{}", x);
193}"#,
194 r#"
195fn square(x: u32) -> u32 {
196 x * x
197}
198
199fn main() {
200 let x = square(5 + 10);
201 println!("{}", x);
202}"#,
203 );
204 }
129} 205}
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs
index fe4eada03..ef55c354e 100644
--- a/crates/ra_assists/src/handlers/remove_mut.rs
+++ b/crates/ra_assists/src/handlers/remove_mut.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{SyntaxKind, TextRange, T}; 1use ra_syntax::{SyntaxKind, TextRange, T};
2 2
3use crate::{AssistContext, AssistId, Assists}; 3use crate::{AssistContext, AssistId, AssistKind, Assists};
4 4
5// Assist: remove_mut 5// Assist: remove_mut
6// 6//
@@ -26,7 +26,12 @@ pub(crate) fn remove_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 }; 26 };
27 27
28 let target = mut_token.text_range(); 28 let target = mut_token.text_range();
29 acc.add(AssistId("remove_mut"), "Remove `mut` keyword", target, |builder| { 29 acc.add(
30 builder.delete(TextRange::new(delete_from, delete_to)); 30 AssistId("remove_mut", AssistKind::Refactor),
31 }) 31 "Remove `mut` keyword",
32 target,
33 |builder| {
34 builder.delete(TextRange::new(delete_from, delete_to));
35 },
36 )
32} 37}
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index bc58ce5fe..120250e79 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -5,7 +5,7 @@ use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; 6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};
7 7
8use crate::{AssistContext, AssistId, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
9 9
10// Assist: reorder_fields 10// Assist: reorder_fields
11// 11//
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists};
23// ``` 23// ```
24// 24//
25pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) 26 reorder::<ast::RecordExpr>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx))
27} 27}
28 28
29fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -42,16 +42,21 @@ fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
42 } 42 }
43 43
44 let target = record.syntax().text_range(); 44 let target = record.syntax().text_range();
45 acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { 45 acc.add(
46 for (old, new) in fields.iter().zip(&sorted_fields) { 46 AssistId("reorder_fields", AssistKind::RefactorRewrite),
47 algo::diff(old, new).into_text_edit(edit.text_edit_builder()); 47 "Reorder record fields",
48 } 48 target,
49 }) 49 |edit| {
50 for (old, new) in fields.iter().zip(&sorted_fields) {
51 algo::diff(old, new).into_text_edit(edit.text_edit_builder());
52 }
53 },
54 )
50} 55}
51 56
52fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { 57fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
53 match node.kind() { 58 match node.kind() {
54 RECORD_LIT => vec![RECORD_FIELD], 59 RECORD_EXPR => vec![RECORD_EXPR_FIELD],
55 RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], 60 RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
56 _ => vec![], 61 _ => vec![],
57 } 62 }
@@ -60,7 +65,7 @@ fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
60fn get_field_name(node: &SyntaxNode) -> String { 65fn get_field_name(node: &SyntaxNode) -> String {
61 let res = match_ast! { 66 let res = match_ast! {
62 match node { 67 match node {
63 ast::RecordField(field) => field.field_name().map(|it| it.to_string()), 68 ast::RecordExprField(field) => field.field_name().map(|it| it.to_string()),
64 ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()), 69 ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()),
65 _ => None, 70 _ => None,
66 } 71 }
@@ -90,10 +95,10 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option
90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { 95fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
91 Some( 96 Some(
92 struct_definition(path, &ctx.sema)? 97 struct_definition(path, &ctx.sema)?
93 .fields(ctx.db) 98 .fields(ctx.db())
94 .iter() 99 .iter()
95 .enumerate() 100 .enumerate()
96 .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) 101 .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx))
97 .collect(), 102 .collect(),
98 ) 103 )
99} 104}
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index dfcd787de..b7e30a7f2 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -8,7 +8,7 @@ use ra_syntax::{
8 AstNode, 8 AstNode,
9}; 9};
10 10
11use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; 11use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
12 12
13// Assist: replace_if_let_with_match 13// Assist: replace_if_let_with_match
14// 14//
@@ -48,29 +48,35 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
48 }; 48 };
49 49
50 let target = if_expr.syntax().text_range(); 50 let target = if_expr.syntax().text_range();
51 acc.add(AssistId("replace_if_let_with_match"), "Replace with match", target, move |edit| { 51 acc.add(
52 let match_expr = { 52 AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite),
53 let then_arm = { 53 "Replace with match",
54 let then_block = then_block.reset_indent().indent(IndentLevel(1)); 54 target,
55 let then_expr = unwrap_trivial_block(then_block); 55 move |edit| {
56 make::match_arm(vec![pat.clone()], then_expr) 56 let match_expr = {
57 let then_arm = {
58 let then_block = then_block.reset_indent().indent(IndentLevel(1));
59 let then_expr = unwrap_trivial_block(then_block);
60 make::match_arm(vec![pat.clone()], then_expr)
61 };
62 let else_arm = {
63 let pattern = ctx
64 .sema
65 .type_of_pat(&pat)
66 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty))
67 .map(|it| it.sad_pattern())
68 .unwrap_or_else(|| make::placeholder_pat().into());
69 let else_expr = unwrap_trivial_block(else_block);
70 make::match_arm(vec![pattern], else_expr)
71 };
72 let match_expr =
73 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]));
74 match_expr.indent(IndentLevel::from_node(if_expr.syntax()))
57 }; 75 };
58 let else_arm = {
59 let pattern = ctx
60 .sema
61 .type_of_pat(&pat)
62 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty))
63 .map(|it| it.sad_pattern())
64 .unwrap_or_else(|| make::placeholder_pat().into());
65 let else_expr = unwrap_trivial_block(else_block);
66 make::match_arm(vec![pattern], else_expr)
67 };
68 let match_expr = make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]));
69 match_expr.indent(IndentLevel::from_node(if_expr.syntax()))
70 };
71 76
72 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); 77 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
73 }) 78 },
79 )
74} 80}
75 81
76#[cfg(test)] 82#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index 761557ac0..a49292c97 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9 AstNode, T, 9 AstNode, T,
10}; 10};
11 11
12use crate::{utils::TryEnum, AssistContext, AssistId, Assists}; 12use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
13 13
14// Assist: replace_let_with_if_let 14// Assist: replace_let_with_if_let
15// 15//
@@ -44,24 +44,31 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
44 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty).map(|it| it.happy_case()); 44 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty).map(|it| it.happy_case());
45 45
46 let target = let_kw.text_range(); 46 let target = let_kw.text_range();
47 acc.add(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { 47 acc.add(
48 let with_placeholder: ast::Pat = match happy_variant { 48 AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
49 None => make::placeholder_pat().into(), 49 "Replace with if-let",
50 Some(var_name) => make::tuple_struct_pat( 50 target,
51 make::path_unqualified(make::path_segment(make::name_ref(var_name))), 51 |edit| {
52 once(make::placeholder_pat().into()), 52 let with_placeholder: ast::Pat = match happy_variant {
53 ) 53 None => make::placeholder_pat().into(),
54 .into(), 54 Some(var_name) => make::tuple_struct_pat(
55 }; 55 make::path_unqualified(make::path_segment(make::name_ref(var_name))),
56 let block = make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax())); 56 once(make::placeholder_pat().into()),
57 let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block); 57 )
58 let stmt = make::expr_stmt(if_); 58 .into(),
59 };
60 let block =
61 make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax()));
62 let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block);
63 let stmt = make::expr_stmt(if_);
59 64
60 let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap(); 65 let placeholder =
61 let stmt = stmt.replace_descendant(placeholder.into(), original_pat); 66 stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap();
67 let stmt = stmt.replace_descendant(placeholder.into(), original_pat);
62 68
63 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); 69 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
64 }) 70 },
71 )
65} 72}
66 73
67#[cfg(test)] 74#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index b4784c333..53496ede1 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -3,7 +3,7 @@ use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNo
3 3
4use crate::{ 4use crate::{
5 utils::{find_insert_use_container, insert_use_statement}, 5 utils::{find_insert_use_container, insert_use_statement},
6 AssistContext, AssistId, Assists, 6 AssistContext, AssistId, AssistKind, Assists,
7}; 7};
8 8
9// Assist: replace_qualified_name_with_use 9// Assist: replace_qualified_name_with_use
@@ -25,7 +25,7 @@ pub(crate) fn replace_qualified_name_with_use(
25) -> Option<()> { 25) -> Option<()> {
26 let path: ast::Path = ctx.find_node_at_offset()?; 26 let path: ast::Path = ctx.find_node_at_offset()?;
27 // We don't want to mess with use statements 27 // We don't want to mess with use statements
28 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 28 if path.syntax().ancestors().find_map(ast::Use::cast).is_some() {
29 return None; 29 return None;
30 } 30 }
31 31
@@ -37,7 +37,7 @@ pub(crate) fn replace_qualified_name_with_use(
37 37
38 let target = path.syntax().text_range(); 38 let target = path.syntax().text_range();
39 acc.add( 39 acc.add(
40 AssistId("replace_qualified_name_with_use"), 40 AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
41 "Replace qualified path with use", 41 "Replace qualified path with use",
42 target, 42 target,
43 |builder| { 43 |builder| {
@@ -85,7 +85,7 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
85 match child { 85 match child {
86 // Don't modify `use` items, as this can break the `use` item when injecting a new 86 // Don't modify `use` items, as this can break the `use` item when injecting a new
87 // import into the use tree. 87 // import into the use tree.
88 ast::UseItem(_it) => continue, 88 ast::Use(_it) => continue,
89 // Don't descend into submodules, they don't have the same `use` items in scope. 89 // Don't descend into submodules, they don't have the same `use` items in scope.
90 ast::Module(_it) => continue, 90 ast::Module(_it) => continue,
91 91
@@ -106,7 +106,7 @@ fn maybe_replace_path(
106 path: ast::Path, 106 path: ast::Path,
107 target: ast::Path, 107 target: ast::Path,
108) -> Option<()> { 108) -> Option<()> {
109 if !path_eq(path.clone(), target.clone()) { 109 if !path_eq(path.clone(), target) {
110 return None; 110 return None;
111 } 111 }
112 112
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index cff7dfb81..e5a4bb23c 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 11
12use crate::{ 12use crate::{
13 utils::{render_snippet, Cursor, TryEnum}, 13 utils::{render_snippet, Cursor, TryEnum},
14 AssistContext, AssistId, Assists, 14 AssistContext, AssistId, AssistKind, Assists,
15}; 15};
16 16
17// Assist: replace_unwrap_with_match 17// Assist: replace_unwrap_with_match
@@ -46,37 +46,43 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
46 let ty = ctx.sema.type_of_expr(&caller)?; 46 let ty = ctx.sema.type_of_expr(&caller)?;
47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case(); 47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
48 let target = method_call.syntax().text_range(); 48 let target = method_call.syntax().text_range();
49 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| { 49 acc.add(
50 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); 50 AssistId("replace_unwrap_with_match", AssistKind::RefactorRewrite),
51 let it = make::bind_pat(make::name("a")).into(); 51 "Replace unwrap with match",
52 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); 52 target,
53 |builder| {
54 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
55 let it = make::bind_pat(make::name("a")).into();
56 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
53 57
54 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); 58 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
55 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); 59 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
56 60
57 let unreachable_call = make::expr_unreachable(); 61 let unreachable_call = make::expr_unreachable();
58 let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); 62 let err_arm =
63 make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
59 64
60 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); 65 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
61 let match_expr = make::expr_match(caller.clone(), match_arm_list) 66 let match_expr = make::expr_match(caller.clone(), match_arm_list)
62 .indent(IndentLevel::from_node(method_call.syntax())); 67 .indent(IndentLevel::from_node(method_call.syntax()));
63 68
64 let range = method_call.syntax().text_range(); 69 let range = method_call.syntax().text_range();
65 match ctx.config.snippet_cap { 70 match ctx.config.snippet_cap {
66 Some(cap) => { 71 Some(cap) => {
67 let err_arm = match_expr 72 let err_arm = match_expr
68 .syntax() 73 .syntax()
69 .descendants() 74 .descendants()
70 .filter_map(ast::MatchArm::cast) 75 .filter_map(ast::MatchArm::cast)
71 .last() 76 .last()
72 .unwrap(); 77 .unwrap();
73 let snippet = 78 let snippet =
74 render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax())); 79 render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax()));
75 builder.replace_snippet(cap, range, snippet) 80 builder.replace_snippet(cap, range, snippet)
81 }
82 None => builder.replace(range, match_expr.to_string()),
76 } 83 }
77 None => builder.replace(range, match_expr.to_string()), 84 },
78 } 85 )
79 })
80} 86}
81 87
82#[cfg(test)] 88#[cfg(test)]
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs
index 38aa199a0..4ca5c3ca1 100644
--- a/crates/ra_assists/src/handlers/split_import.rs
+++ b/crates/ra_assists/src/handlers/split_import.rs
@@ -2,7 +2,7 @@ use std::iter::successors;
2 2
3use ra_syntax::{ast, AstNode, T}; 3use ra_syntax::{ast, AstNode, T};
4 4
5use crate::{AssistContext, AssistId, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
6 6
7// Assist: split_import 7// Assist: split_import
8// 8//
@@ -28,7 +28,7 @@ pub(crate) fn split_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
28 } 28 }
29 29
30 let target = colon_colon.text_range(); 30 let target = colon_colon.text_range();
31 acc.add(AssistId("split_import"), "Split import", target, |edit| { 31 acc.add(AssistId("split_import", AssistKind::RefactorRewrite), "Split import", target, |edit| {
32 edit.replace_ast(use_tree, new_tree); 32 edit.replace_ast(use_tree, new_tree);
33 }) 33 })
34} 34}
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs
index 1fb13f481..8b38695a9 100644
--- a/crates/ra_assists/src/handlers/unwrap_block.rs
+++ b/crates/ra_assists/src/handlers/unwrap_block.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7 AstNode, TextRange, T, 7 AstNode, TextRange, T,
8}; 8};
9 9
10use crate::{AssistContext, AssistId, Assists}; 10use crate::{AssistContext, AssistId, AssistKind, Assists};
11 11
12// Assist: unwrap_block 12// Assist: unwrap_block
13// 13//
@@ -27,7 +27,7 @@ use crate::{AssistContext, AssistId, Assists};
27// } 27// }
28// ``` 28// ```
29pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 29pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let assist_id = AssistId("unwrap_block"); 30 let assist_id = AssistId("unwrap_block", AssistKind::RefactorRewrite);
31 let assist_label = "Unwrap block"; 31 let assist_label = "Unwrap block";
32 32
33 let l_curly_token = ctx.find_token_at_offset(T!['{'])?; 33 let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 1745f44a5..465b90415 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -26,10 +26,40 @@ pub(crate) use crate::assist_context::{AssistContext, Assists};
26 26
27pub use assist_config::AssistConfig; 27pub use assist_config::AssistConfig;
28 28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum AssistKind {
31 None,
32 QuickFix,
33 Generate,
34 Refactor,
35 RefactorExtract,
36 RefactorInline,
37 RefactorRewrite,
38}
39
40impl AssistKind {
41 pub fn contains(self, other: AssistKind) -> bool {
42 if self == other {
43 return true;
44 }
45
46 match self {
47 AssistKind::None | AssistKind::Generate => return true,
48 AssistKind::Refactor => match other {
49 AssistKind::RefactorExtract
50 | AssistKind::RefactorInline
51 | AssistKind::RefactorRewrite => return true,
52 _ => return false,
53 },
54 _ => return false,
55 }
56 }
57}
58
29/// Unique identifier of the assist, should not be shown to the user 59/// Unique identifier of the assist, should not be shown to the user
30/// directly. 60/// directly.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)] 61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct AssistId(pub &'static str); 62pub struct AssistId(pub &'static str, pub AssistKind);
33 63
34#[derive(Clone, Debug)] 64#[derive(Clone, Debug)]
35pub struct GroupLabel(pub String); 65pub struct GroupLabel(pub String);
@@ -102,13 +132,8 @@ mod handlers {
102 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>; 132 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>;
103 133
104 mod add_custom_impl; 134 mod add_custom_impl;
105 mod add_derive;
106 mod add_explicit_type; 135 mod add_explicit_type;
107 mod add_from_impl_for_enum;
108 mod add_function;
109 mod add_impl;
110 mod add_missing_impl_members; 136 mod add_missing_impl_members;
111 mod add_new;
112 mod add_turbo_fish; 137 mod add_turbo_fish;
113 mod apply_demorgan; 138 mod apply_demorgan;
114 mod auto_import; 139 mod auto_import;
@@ -122,6 +147,11 @@ mod handlers {
122 mod flip_binexpr; 147 mod flip_binexpr;
123 mod flip_comma; 148 mod flip_comma;
124 mod flip_trait_bound; 149 mod flip_trait_bound;
150 mod generate_derive;
151 mod generate_from_impl_for_enum;
152 mod generate_function;
153 mod generate_impl;
154 mod generate_new;
125 mod inline_local_variable; 155 mod inline_local_variable;
126 mod introduce_named_lifetime; 156 mod introduce_named_lifetime;
127 mod invert_if; 157 mod invert_if;
@@ -144,12 +174,7 @@ mod handlers {
144 &[ 174 &[
145 // These are alphabetic for the foolish consistency 175 // These are alphabetic for the foolish consistency
146 add_custom_impl::add_custom_impl, 176 add_custom_impl::add_custom_impl,
147 add_derive::add_derive,
148 add_explicit_type::add_explicit_type, 177 add_explicit_type::add_explicit_type,
149 add_from_impl_for_enum::add_from_impl_for_enum,
150 add_function::add_function,
151 add_impl::add_impl,
152 add_new::add_new,
153 add_turbo_fish::add_turbo_fish, 178 add_turbo_fish::add_turbo_fish,
154 apply_demorgan::apply_demorgan, 179 apply_demorgan::apply_demorgan,
155 auto_import::auto_import, 180 auto_import::auto_import,
@@ -163,6 +188,11 @@ mod handlers {
163 flip_binexpr::flip_binexpr, 188 flip_binexpr::flip_binexpr,
164 flip_comma::flip_comma, 189 flip_comma::flip_comma,
165 flip_trait_bound::flip_trait_bound, 190 flip_trait_bound::flip_trait_bound,
191 generate_derive::generate_derive,
192 generate_from_impl_for_enum::generate_from_impl_for_enum,
193 generate_function::generate_function,
194 generate_impl::generate_impl,
195 generate_new::generate_new,
166 inline_local_variable::inline_local_variable, 196 inline_local_variable::inline_local_variable,
167 introduce_named_lifetime::introduce_named_lifetime, 197 introduce_named_lifetime::introduce_named_lifetime,
168 invert_if::invert_if, 198 invert_if::invert_if,
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs
index 858f5ca80..18fcb9049 100644
--- a/crates/ra_assists/src/tests.rs
+++ b/crates/ra_assists/src/tests.rs
@@ -6,7 +6,7 @@ use ra_ide_db::RootDatabase;
6use ra_syntax::TextRange; 6use ra_syntax::TextRange;
7use test_utils::{assert_eq_text, extract_offset, extract_range}; 7use test_utils::{assert_eq_text, extract_offset, extract_range};
8 8
9use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; 9use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists};
10use stdx::trim_indent; 10use stdx::trim_indent;
11 11
12pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { 12pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
@@ -134,3 +134,46 @@ fn assist_order_if_expr() {
134 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); 134 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
135 assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); 135 assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match");
136} 136}
137
138#[test]
139fn assist_filter_works() {
140 let before = "
141 pub fn test_some_range(a: int) -> bool {
142 if let 2..6 = <|>5<|> {
143 true
144 } else {
145 false
146 }
147 }";
148 let (range, before) = extract_range(before);
149 let (db, file_id) = with_single_file(&before);
150 let frange = FileRange { file_id, range };
151
152 {
153 let mut cfg = AssistConfig::default();
154 cfg.allowed = Some(vec![AssistKind::Refactor]);
155
156 let assists = Assist::resolved(&db, &cfg, frange);
157 let mut assists = assists.iter();
158
159 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
160 assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match");
161 }
162
163 {
164 let mut cfg = AssistConfig::default();
165 cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
166 let assists = Assist::resolved(&db, &cfg, frange);
167 assert_eq!(assists.len(), 1);
168
169 let mut assists = assists.iter();
170 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
171 }
172
173 {
174 let mut cfg = AssistConfig::default();
175 cfg.allowed = Some(vec![AssistKind::QuickFix]);
176 let assists = Assist::resolved(&db, &cfg, frange);
177 assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out");
178 }
179}
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index 31ea888c5..eff7feded 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -22,26 +22,6 @@ impl Debug for S {
22} 22}
23 23
24#[test] 24#[test]
25fn doctest_add_derive() {
26 check_doc_test(
27 "add_derive",
28 r#####"
29struct Point {
30 x: u32,
31 y: u32,<|>
32}
33"#####,
34 r#####"
35#[derive($0)]
36struct Point {
37 x: u32,
38 y: u32,
39}
40"#####,
41 )
42}
43
44#[test]
45fn doctest_add_explicit_type() { 25fn doctest_add_explicit_type() {
46 check_doc_test( 26 check_doc_test(
47 "add_explicit_type", 27 "add_explicit_type",
@@ -59,52 +39,6 @@ fn main() {
59} 39}
60 40
61#[test] 41#[test]
62fn doctest_add_from_impl_for_enum() {
63 check_doc_test(
64 "add_from_impl_for_enum",
65 r#####"
66enum A { <|>One(u32) }
67"#####,
68 r#####"
69enum A { One(u32) }
70
71impl From<u32> for A {
72 fn from(v: u32) -> Self {
73 A::One(v)
74 }
75}
76"#####,
77 )
78}
79
80#[test]
81fn doctest_add_function() {
82 check_doc_test(
83 "add_function",
84 r#####"
85struct Baz;
86fn baz() -> Baz { Baz }
87fn foo() {
88 bar<|>("", baz());
89}
90
91"#####,
92 r#####"
93struct Baz;
94fn baz() -> Baz { Baz }
95fn foo() {
96 bar("", baz());
97}
98
99fn bar(arg: &str, baz: Baz) {
100 ${0:todo!()}
101}
102
103"#####,
104 )
105}
106
107#[test]
108fn doctest_add_hash() { 42fn doctest_add_hash() {
109 check_doc_test( 43 check_doc_test(
110 "add_hash", 44 "add_hash",
@@ -122,27 +56,6 @@ fn main() {
122} 56}
123 57
124#[test] 58#[test]
125fn doctest_add_impl() {
126 check_doc_test(
127 "add_impl",
128 r#####"
129struct Ctx<T: Clone> {
130 data: T,<|>
131}
132"#####,
133 r#####"
134struct Ctx<T: Clone> {
135 data: T,
136}
137
138impl<T: Clone> Ctx<T> {
139 $0
140}
141"#####,
142 )
143}
144
145#[test]
146fn doctest_add_impl_default_members() { 59fn doctest_add_impl_default_members() {
147 check_doc_test( 60 check_doc_test(
148 "add_impl_default_members", 61 "add_impl_default_members",
@@ -209,28 +122,6 @@ impl Trait<u32> for () {
209} 122}
210 123
211#[test] 124#[test]
212fn doctest_add_new() {
213 check_doc_test(
214 "add_new",
215 r#####"
216struct Ctx<T: Clone> {
217 data: T,<|>
218}
219"#####,
220 r#####"
221struct Ctx<T: Clone> {
222 data: T,
223}
224
225impl<T: Clone> Ctx<T> {
226 fn $0new(data: T) -> Self { Self { data } }
227}
228
229"#####,
230 )
231}
232
233#[test]
234fn doctest_add_turbo_fish() { 125fn doctest_add_turbo_fish() {
235 check_doc_test( 126 check_doc_test(
236 "add_turbo_fish", 127 "add_turbo_fish",
@@ -467,6 +358,115 @@ fn foo<T: Copy + Clone>() { }
467} 358}
468 359
469#[test] 360#[test]
361fn doctest_generate_derive() {
362 check_doc_test(
363 "generate_derive",
364 r#####"
365struct Point {
366 x: u32,
367 y: u32,<|>
368}
369"#####,
370 r#####"
371#[derive($0)]
372struct Point {
373 x: u32,
374 y: u32,
375}
376"#####,
377 )
378}
379
380#[test]
381fn doctest_generate_from_impl_for_enum() {
382 check_doc_test(
383 "generate_from_impl_for_enum",
384 r#####"
385enum A { <|>One(u32) }
386"#####,
387 r#####"
388enum A { One(u32) }
389
390impl From<u32> for A {
391 fn from(v: u32) -> Self {
392 A::One(v)
393 }
394}
395"#####,
396 )
397}
398
399#[test]
400fn doctest_generate_function() {
401 check_doc_test(
402 "generate_function",
403 r#####"
404struct Baz;
405fn baz() -> Baz { Baz }
406fn foo() {
407 bar<|>("", baz());
408}
409
410"#####,
411 r#####"
412struct Baz;
413fn baz() -> Baz { Baz }
414fn foo() {
415 bar("", baz());
416}
417
418fn bar(arg: &str, baz: Baz) {
419 ${0:todo!()}
420}
421
422"#####,
423 )
424}
425
426#[test]
427fn doctest_generate_impl() {
428 check_doc_test(
429 "generate_impl",
430 r#####"
431struct Ctx<T: Clone> {
432 data: T,<|>
433}
434"#####,
435 r#####"
436struct Ctx<T: Clone> {
437 data: T,
438}
439
440impl<T: Clone> Ctx<T> {
441 $0
442}
443"#####,
444 )
445}
446
447#[test]
448fn doctest_generate_new() {
449 check_doc_test(
450 "generate_new",
451 r#####"
452struct Ctx<T: Clone> {
453 data: T,<|>
454}
455"#####,
456 r#####"
457struct Ctx<T: Clone> {
458 data: T,
459}
460
461impl<T: Clone> Ctx<T> {
462 fn $0new(data: T) -> Self { Self { data } }
463}
464
465"#####,
466 )
467}
468
469#[test]
470fn doctest_inline_local_variable() { 470fn doctest_inline_local_variable() {
471 check_doc_test( 471 check_doc_test(
472 "inline_local_variable", 472 "inline_local_variable",
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 02de902d6..bb16ebd4e 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -56,33 +56,34 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
56 56
57pub fn get_missing_assoc_items( 57pub fn get_missing_assoc_items(
58 sema: &Semantics<RootDatabase>, 58 sema: &Semantics<RootDatabase>,
59 impl_def: &ast::ImplDef, 59 impl_def: &ast::Impl,
60) -> Vec<hir::AssocItem> { 60) -> Vec<hir::AssocItem> {
61 // Names must be unique between constants and functions. However, type aliases 61 // Names must be unique between constants and functions. However, type aliases
62 // may share the same name as a function or constant. 62 // may share the same name as a function or constant.
63 let mut impl_fns_consts = FxHashSet::default(); 63 let mut impl_fns_consts = FxHashSet::default();
64 let mut impl_type = FxHashSet::default(); 64 let mut impl_type = FxHashSet::default();
65 65
66 if let Some(item_list) = impl_def.item_list() { 66 if let Some(item_list) = impl_def.assoc_item_list() {
67 for item in item_list.assoc_items() { 67 for item in item_list.assoc_items() {
68 match item { 68 match item {
69 ast::AssocItem::FnDef(f) => { 69 ast::AssocItem::Fn(f) => {
70 if let Some(n) = f.name() { 70 if let Some(n) = f.name() {
71 impl_fns_consts.insert(n.syntax().to_string()); 71 impl_fns_consts.insert(n.syntax().to_string());
72 } 72 }
73 } 73 }
74 74
75 ast::AssocItem::TypeAliasDef(t) => { 75 ast::AssocItem::TypeAlias(t) => {
76 if let Some(n) = t.name() { 76 if let Some(n) = t.name() {
77 impl_type.insert(n.syntax().to_string()); 77 impl_type.insert(n.syntax().to_string());
78 } 78 }
79 } 79 }
80 80
81 ast::AssocItem::ConstDef(c) => { 81 ast::AssocItem::Const(c) => {
82 if let Some(n) = c.name() { 82 if let Some(n) = c.name() {
83 impl_fns_consts.insert(n.syntax().to_string()); 83 impl_fns_consts.insert(n.syntax().to_string());
84 } 84 }
85 } 85 }
86 ast::AssocItem::MacroCall(_) => (),
86 } 87 }
87 } 88 }
88 } 89 }
@@ -108,7 +109,7 @@ pub fn get_missing_assoc_items(
108 109
109pub(crate) fn resolve_target_trait( 110pub(crate) fn resolve_target_trait(
110 sema: &Semantics<RootDatabase>, 111 sema: &Semantics<RootDatabase>,
111 impl_def: &ast::ImplDef, 112 impl_def: &ast::Impl,
112) -> Option<hir::Trait> { 113) -> Option<hir::Trait> {
113 let ast_path = impl_def 114 let ast_path = impl_def
114 .target_trait() 115 .target_trait()
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs
index 8c4f33e59..617afe2e9 100644
--- a/crates/ra_assists/src/utils/insert_use.rs
+++ b/crates/ra_assists/src/utils/insert_use.rs
@@ -215,7 +215,7 @@ fn walk_use_tree_for_best_action(
215 let prev_len = current_path_segments.len(); 215 let prev_len = current_path_segments.len();
216 216
217 let tree_list = current_use_tree.use_tree_list(); 217 let tree_list = current_use_tree.use_tree_list();
218 let alias = current_use_tree.alias(); 218 let alias = current_use_tree.rename();
219 219
220 let path = match current_use_tree.path() { 220 let path = match current_use_tree.path() {
221 Some(path) => path, 221 Some(path) => path,
@@ -225,7 +225,7 @@ fn walk_use_tree_for_best_action(
225 current_use_tree 225 current_use_tree
226 .syntax() 226 .syntax()
227 .ancestors() 227 .ancestors()
228 .find_map(ast::UseItem::cast) 228 .find_map(ast::Use::cast)
229 .map(|it| it.syntax().clone()), 229 .map(|it| it.syntax().clone()),
230 true, 230 true,
231 ); 231 );
@@ -254,7 +254,7 @@ fn walk_use_tree_for_best_action(
254 current_use_tree 254 current_use_tree
255 .syntax() 255 .syntax()
256 .ancestors() 256 .ancestors()
257 .find_map(ast::UseItem::cast) 257 .find_map(ast::Use::cast)
258 .map(|it| it.syntax().clone()), 258 .map(|it| it.syntax().clone()),
259 true, 259 true,
260 ), 260 ),
@@ -304,7 +304,7 @@ fn walk_use_tree_for_best_action(
304 current_use_tree 304 current_use_tree
305 .syntax() 305 .syntax()
306 .ancestors() 306 .ancestors()
307 .find_map(ast::UseItem::cast) 307 .find_map(ast::Use::cast)
308 .map(|it| it.syntax().clone()), 308 .map(|it| it.syntax().clone()),
309 true, 309 true,
310 ); 310 );
@@ -377,7 +377,7 @@ fn best_action_for_target(
377 let mut storage = Vec::with_capacity(16); // this should be the only allocation 377 let mut storage = Vec::with_capacity(16); // this should be the only allocation
378 let best_action = container 378 let best_action = container
379 .children() 379 .children()
380 .filter_map(ast::UseItem::cast) 380 .filter_map(ast::Use::cast)
381 .filter_map(|it| it.use_tree()) 381 .filter_map(|it| it.use_tree())
382 .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target)) 382 .map(|u| walk_use_tree_for_best_action(&mut storage, None, u, target))
383 .fold(None, |best, a| match best { 383 .fold(None, |best, a| match best {
diff --git a/crates/ra_cfg/Cargo.toml b/crates/ra_cfg/Cargo.toml
index 9165076a5..6425cd6d6 100644
--- a/crates/ra_cfg/Cargo.toml
+++ b/crates/ra_cfg/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_cfg" 3name = "ra_cfg"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs
index 85b100c6a..f48928aee 100644
--- a/crates/ra_cfg/src/cfg_expr.rs
+++ b/crates/ra_cfg/src/cfg_expr.rs
@@ -5,7 +5,6 @@
5use std::slice::Iter as SliceIter; 5use std::slice::Iter as SliceIter;
6 6
7use ra_syntax::SmolStr; 7use ra_syntax::SmolStr;
8use tt::{Leaf, Subtree, TokenTree};
9 8
10#[derive(Debug, Clone, PartialEq, Eq)] 9#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum CfgExpr { 10pub enum CfgExpr {
@@ -18,6 +17,9 @@ pub enum CfgExpr {
18} 17}
19 18
20impl CfgExpr { 19impl CfgExpr {
20 pub fn parse(tt: &tt::Subtree) -> CfgExpr {
21 next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
22 }
21 /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. 23 /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
22 pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> { 24 pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> {
23 match self { 25 match self {
@@ -35,22 +37,18 @@ impl CfgExpr {
35 } 37 }
36} 38}
37 39
38pub fn parse_cfg(tt: &Subtree) -> CfgExpr {
39 next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
40}
41
42fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { 40fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> {
43 let name = match it.next() { 41 let name = match it.next() {
44 None => return None, 42 None => return None,
45 Some(TokenTree::Leaf(Leaf::Ident(ident))) => ident.text.clone(), 43 Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(),
46 Some(_) => return Some(CfgExpr::Invalid), 44 Some(_) => return Some(CfgExpr::Invalid),
47 }; 45 };
48 46
49 // Peek 47 // Peek
50 let ret = match it.as_slice().first() { 48 let ret = match it.as_slice().first() {
51 Some(TokenTree::Leaf(Leaf::Punct(punct))) if punct.char == '=' => { 49 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '=' => {
52 match it.as_slice().get(1) { 50 match it.as_slice().get(1) {
53 Some(TokenTree::Leaf(Leaf::Literal(literal))) => { 51 Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => {
54 it.next(); 52 it.next();
55 it.next(); 53 it.next();
56 // FIXME: escape? raw string? 54 // FIXME: escape? raw string?
@@ -61,7 +59,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> {
61 _ => return Some(CfgExpr::Invalid), 59 _ => return Some(CfgExpr::Invalid),
62 } 60 }
63 } 61 }
64 Some(TokenTree::Subtree(subtree)) => { 62 Some(tt::TokenTree::Subtree(subtree)) => {
65 it.next(); 63 it.next();
66 let mut sub_it = subtree.token_trees.iter(); 64 let mut sub_it = subtree.token_trees.iter();
67 let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); 65 let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect();
@@ -76,7 +74,7 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> {
76 }; 74 };
77 75
78 // Eat comma separator 76 // Eat comma separator
79 if let Some(TokenTree::Leaf(Leaf::Punct(punct))) = it.as_slice().first() { 77 if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = it.as_slice().first() {
80 if punct.char == ',' { 78 if punct.char == ',' {
81 it.next(); 79 it.next();
82 } 80 }
@@ -99,7 +97,8 @@ mod tests {
99 97
100 fn assert_parse_result(input: &str, expected: CfgExpr) { 98 fn assert_parse_result(input: &str, expected: CfgExpr) {
101 let (tt, _) = get_token_tree_generated(input); 99 let (tt, _) = get_token_tree_generated(input);
102 assert_eq!(parse_cfg(&tt), expected); 100 let cfg = CfgExpr::parse(&tt);
101 assert_eq!(cfg, expected);
103 } 102 }
104 103
105 #[test] 104 #[test]
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs
index 57feabcb2..cd5a0a7b6 100644
--- a/crates/ra_cfg/src/lib.rs
+++ b/crates/ra_cfg/src/lib.rs
@@ -5,7 +5,7 @@ mod cfg_expr;
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7 7
8pub use cfg_expr::{parse_cfg, CfgExpr}; 8pub use cfg_expr::CfgExpr;
9 9
10/// Configuration options used for conditional compilition on items with `cfg` attributes. 10/// Configuration options used for conditional compilition on items with `cfg` attributes.
11/// We have two kind of options in different namespaces: atomic options like `unix`, and 11/// We have two kind of options in different namespaces: atomic options like `unix`, and
@@ -31,19 +31,21 @@ impl CfgOptions {
31 }) 31 })
32 } 32 }
33 33
34 pub fn is_cfg_enabled(&self, attr: &tt::Subtree) -> Option<bool> {
35 self.check(&parse_cfg(attr))
36 }
37
38 pub fn insert_atom(&mut self, key: SmolStr) { 34 pub fn insert_atom(&mut self, key: SmolStr) {
39 self.atoms.insert(key); 35 self.atoms.insert(key);
40 } 36 }
41 37
42 pub fn remove_atom(&mut self, name: &str) {
43 self.atoms.remove(name);
44 }
45
46 pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) { 38 pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) {
47 self.key_values.insert((key, value)); 39 self.key_values.insert((key, value));
48 } 40 }
41
42 pub fn append(&mut self, other: &CfgOptions) {
43 for atom in &other.atoms {
44 self.atoms.insert(atom.clone());
45 }
46
47 for (key, value) in &other.key_values {
48 self.key_values.insert((key.clone(), value.clone()));
49 }
50 }
49} 51}
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index 372fb242b..5f334d04f 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -3,13 +3,13 @@ edition = "2018"
3name = "ra_db" 3name = "ra_db"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
9 10
10[dependencies] 11[dependencies]
11salsa = "0.14.1" 12salsa = "0.15.0"
12relative-path = "1.0.0"
13rustc-hash = "1.1.0" 13rustc-hash = "1.1.0"
14 14
15ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 4f4fb4494..2aafb9965 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -149,15 +149,17 @@ fn with_files(
149 let crate_id = crate_graph.add_crate_root( 149 let crate_id = crate_graph.add_crate_root(
150 file_id, 150 file_id,
151 meta.edition, 151 meta.edition,
152 Some(CrateName::new(&krate).unwrap()), 152 Some(krate.clone()),
153 meta.cfg, 153 meta.cfg,
154 meta.env, 154 meta.env,
155 Default::default(), 155 Default::default(),
156 ); 156 );
157 let prev = crates.insert(krate.clone(), crate_id); 157 let crate_name = CrateName::new(&krate).unwrap();
158 let prev = crates.insert(crate_name.clone(), crate_id);
158 assert!(prev.is_none()); 159 assert!(prev.is_none());
159 for dep in meta.deps { 160 for dep in meta.deps {
160 crate_deps.push((krate.clone(), dep)) 161 let dep = CrateName::new(&dep).unwrap();
162 crate_deps.push((crate_name.clone(), dep))
161 } 163 }
162 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { 164 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
163 assert!(default_crate_root.is_none()); 165 assert!(default_crate_root.is_none());
@@ -220,7 +222,7 @@ impl From<Fixture> for FileMeta {
220 .edition 222 .edition
221 .as_ref() 223 .as_ref()
222 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), 224 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()),
223 env: Env::from(f.env.iter()), 225 env: f.env.into_iter().collect(),
224 } 226 }
225 } 227 }
226} 228}
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 7f3660118..6f2e5cfc7 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -6,7 +6,7 @@
6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how 6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
7//! actual IO is done and lowered to input. 7//! actual IO is done and lowered to input.
8 8
9use std::{fmt, ops, str::FromStr, sync::Arc}; 9use std::{fmt, iter::FromIterator, ops, str::FromStr, sync::Arc};
10 10
11use ra_cfg::CfgOptions; 11use ra_cfg::CfgOptions;
12use ra_syntax::SmolStr; 12use ra_syntax::SmolStr;
@@ -67,7 +67,7 @@ pub struct CrateGraph {
67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
68pub struct CrateId(pub u32); 68pub struct CrateId(pub u32);
69 69
70#[derive(Debug, Clone, PartialEq, Eq)] 70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub struct CrateName(SmolStr); 71pub struct CrateName(SmolStr);
72 72
73impl CrateName { 73impl CrateName {
@@ -94,6 +94,13 @@ impl fmt::Display for CrateName {
94 } 94 }
95} 95}
96 96
97impl ops::Deref for CrateName {
98 type Target = str;
99 fn deref(&self) -> &Self::Target {
100 &*self.0
101 }
102}
103
97#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 104#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
98pub struct ProcMacroId(pub u32); 105pub struct ProcMacroId(pub u32);
99 106
@@ -117,7 +124,7 @@ pub struct CrateData {
117 /// The name to display to the end user. 124 /// The name to display to the end user.
118 /// This actual crate name can be different in a particular dependent crate 125 /// This actual crate name can be different in a particular dependent crate
119 /// or may even be missing for some cases, such as a dummy crate for the code snippet. 126 /// or may even be missing for some cases, such as a dummy crate for the code snippet.
120 pub display_name: Option<CrateName>, 127 pub display_name: Option<String>,
121 pub cfg_options: CfgOptions, 128 pub cfg_options: CfgOptions,
122 pub env: Env, 129 pub env: Env,
123 pub dependencies: Vec<Dependency>, 130 pub dependencies: Vec<Dependency>,
@@ -138,7 +145,7 @@ pub struct Env {
138#[derive(Debug, Clone, PartialEq, Eq)] 145#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Dependency { 146pub struct Dependency {
140 pub crate_id: CrateId, 147 pub crate_id: CrateId,
141 pub name: SmolStr, 148 pub name: CrateName,
142} 149}
143 150
144impl CrateGraph { 151impl CrateGraph {
@@ -146,7 +153,7 @@ impl CrateGraph {
146 &mut self, 153 &mut self,
147 file_id: FileId, 154 file_id: FileId,
148 edition: Edition, 155 edition: Edition,
149 display_name: Option<CrateName>, 156 display_name: Option<String>,
150 cfg_options: CfgOptions, 157 cfg_options: CfgOptions,
151 env: Env, 158 env: Env,
152 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, 159 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
@@ -178,7 +185,7 @@ impl CrateGraph {
178 if self.dfs_find(from, to, &mut FxHashSet::default()) { 185 if self.dfs_find(from, to, &mut FxHashSet::default()) {
179 return Err(CyclicDependenciesError); 186 return Err(CyclicDependenciesError);
180 } 187 }
181 self.arena.get_mut(&from).unwrap().add_dep(name.0, to); 188 self.arena.get_mut(&from).unwrap().add_dep(name, to);
182 Ok(()) 189 Ok(())
183 } 190 }
184 191
@@ -190,6 +197,23 @@ impl CrateGraph {
190 self.arena.keys().copied() 197 self.arena.keys().copied()
191 } 198 }
192 199
200 /// Returns an iterator over all transitive dependencies of the given crate.
201 pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> + '_ {
202 let mut worklist = vec![of];
203 let mut deps = FxHashSet::default();
204
205 while let Some(krate) = worklist.pop() {
206 if !deps.insert(krate) {
207 continue;
208 }
209
210 worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id));
211 }
212
213 deps.remove(&of);
214 deps.into_iter()
215 }
216
193 // FIXME: this only finds one crate with the given root; we could have multiple 217 // FIXME: this only finds one crate with the given root; we could have multiple
194 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 218 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
195 let (&crate_id, _) = 219 let (&crate_id, _) =
@@ -247,7 +271,7 @@ impl CrateId {
247} 271}
248 272
249impl CrateData { 273impl CrateData {
250 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 274 fn add_dep(&mut self, name: CrateName, crate_id: CrateId) {
251 self.dependencies.push(Dependency { name, crate_id }) 275 self.dependencies.push(Dependency { name, crate_id })
252 } 276 }
253} 277}
@@ -274,18 +298,9 @@ impl fmt::Display for Edition {
274 } 298 }
275} 299}
276 300
277impl<'a, T> From<T> for Env 301impl FromIterator<(String, String)> for Env {
278where 302 fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {
279 T: Iterator<Item = (&'a String, &'a String)>, 303 Env { entries: FromIterator::from_iter(iter) }
280{
281 fn from(iter: T) -> Self {
282 let mut result = Self::default();
283
284 for (k, v) in iter {
285 result.entries.insert(k.to_owned(), v.to_owned());
286 }
287
288 result
289 } 304 }
290} 305}
291 306
@@ -429,7 +444,10 @@ mod tests {
429 .is_ok()); 444 .is_ok());
430 assert_eq!( 445 assert_eq!(
431 graph[crate1].dependencies, 446 graph[crate1].dependencies,
432 vec![Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }] 447 vec![Dependency {
448 crate_id: crate2,
449 name: CrateName::new("crate_name_with_dashes").unwrap()
450 }]
433 ); 451 );
434 } 452 }
435} 453}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 4a3ba57da..f25be24fe 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -16,9 +16,8 @@ pub use crate::{
16 SourceRoot, SourceRootId, 16 SourceRoot, SourceRootId,
17 }, 17 },
18}; 18};
19pub use relative_path::{RelativePath, RelativePathBuf};
20pub use salsa; 19pub use salsa;
21pub use vfs::{file_set::FileSet, AbsPathBuf, VfsPath}; 20pub use vfs::{file_set::FileSet, VfsPath};
22 21
23#[macro_export] 22#[macro_export]
24macro_rules! impl_intern_key { 23macro_rules! impl_intern_key {
@@ -80,7 +79,7 @@ pub struct FilePosition {
80 pub offset: TextSize, 79 pub offset: TextSize,
81} 80}
82 81
83#[derive(Clone, Copy, Debug)] 82#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub struct FileRange { 83pub struct FileRange {
85 pub file_id: FileId, 84 pub file_id: FileId,
86 pub range: TextRange, 85 pub range: TextRange,
@@ -93,9 +92,9 @@ pub trait FileLoader {
93 fn file_text(&self, file_id: FileId) -> Arc<String>; 92 fn file_text(&self, file_id: FileId) -> Arc<String>;
94 /// Note that we intentionally accept a `&str` and not a `&Path` here. This 93 /// Note that we intentionally accept a `&str` and not a `&Path` here. This
95 /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such, 94 /// method exists to handle `#[path = "/some/path.rs"] mod foo;` and such,
96 /// so the input is guaranteed to be utf-8 string. We might introduce 95 /// so the input is guaranteed to be utf-8 string. One might be tempted to
97 /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we 96 /// introduce some kind of "utf-8 path with / separators", but that's a bad idea. Behold
98 /// get by with a `&str` for the time being. 97 /// `#[path = "C://no/way"]`
99 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; 98 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
100 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; 99 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
101} 100}
@@ -113,7 +112,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
113 fn crate_graph(&self) -> Arc<CrateGraph>; 112 fn crate_graph(&self) -> Arc<CrateGraph>;
114} 113}
115 114
116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { 115fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
117 let _p = profile("parse_query").detail(|| format!("{:?}", file_id)); 116 let _p = profile("parse_query").detail(|| format!("{:?}", file_id));
118 let text = db.file_text(file_id); 117 let text = db.file_text(file_id);
119 SourceFile::parse(&*text) 118 SourceFile::parse(&*text)
@@ -136,10 +135,7 @@ pub trait SourceDatabaseExt: SourceDatabase {
136 fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>; 135 fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
137} 136}
138 137
139fn source_root_crates( 138fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHashSet<CrateId>> {
140 db: &(impl SourceDatabaseExt + SourceDatabase),
141 id: SourceRootId,
142) -> Arc<FxHashSet<CrateId>> {
143 let graph = db.crate_graph(); 139 let graph = db.crate_graph();
144 let res = graph 140 let res = graph
145 .iter() 141 .iter()
diff --git a/crates/ra_fmt/Cargo.toml b/crates/ra_fmt/Cargo.toml
index e9d057afc..b4ef93f2b 100644
--- a/crates/ra_fmt/Cargo.toml
+++ b/crates/ra_fmt/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_fmt"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index ba7b39a19..c260bb193 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir" 3name = "ra_hir"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -15,6 +16,7 @@ arrayvec = "0.5.1"
15 16
16itertools = "0.9.0" 17itertools = "0.9.0"
17 18
19stdx = { path = "../stdx" }
18ra_syntax = { path = "../ra_syntax" } 20ra_syntax = { path = "../ra_syntax" }
19ra_db = { path = "../ra_db" } 21ra_db = { path = "../ra_db" }
20ra_prof = { path = "../ra_prof" } 22ra_prof = { path = "../ra_prof" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 8c5e1b746..5d88c5c64 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,5 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::sync::Arc; 2use std::{iter, sync::Arc};
3 3
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
@@ -12,6 +12,7 @@ use hir_def::{
12 import_map, 12 import_map,
13 per_ns::PerNs, 13 per_ns::PerNs,
14 resolver::{HasResolver, Resolver}, 14 resolver::{HasResolver, Resolver},
15 src::HasSource as _,
15 type_ref::{Mutability, TypeRef}, 16 type_ref::{Mutability, TypeRef},
16 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, 17 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
17 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, 18 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId,
@@ -25,21 +26,22 @@ use hir_expand::{
25use hir_ty::{ 26use hir_ty::{
26 autoderef, 27 autoderef,
27 display::{HirDisplayError, HirFormatter}, 28 display::{HirDisplayError, HirFormatter},
28 expr::ExprValidator, 29 method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate,
29 method_resolution, 30 InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
30 unsafe_validation::UnsafeValidator,
31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
32 TyDefId, TypeCtor,
33}; 31};
34use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, Edition, FileId};
35use ra_prof::profile; 33use ra_prof::profile;
36use ra_syntax::ast::{self, AttrsOwner, NameOwner}; 34use ra_syntax::{
35 ast::{self, AttrsOwner, NameOwner},
36 AstNode,
37};
37use rustc_hash::FxHashSet; 38use rustc_hash::FxHashSet;
39use stdx::impl_from;
38 40
39use crate::{ 41use crate::{
40 db::{DefDatabase, HirDatabase}, 42 db::{DefDatabase, HirDatabase},
41 has_source::HasSource, 43 has_source::HasSource,
42 CallableDef, HirDisplay, InFile, Name, 44 HirDisplay, InFile, Name,
43}; 45};
44 46
45/// hir::Crate describes a single crate. It's the main interface with which 47/// hir::Crate describes a single crate. It's the main interface with which
@@ -94,8 +96,8 @@ impl Crate {
94 db.crate_graph()[self.id].edition 96 db.crate_graph()[self.id].edition
95 } 97 }
96 98
97 pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateName> { 99 pub fn display_name(self, db: &dyn HirDatabase) -> Option<String> {
98 db.crate_graph()[self.id].display_name.as_ref().cloned() 100 db.crate_graph()[self.id].display_name.clone()
99 } 101 }
100 102
101 pub fn query_external_importables( 103 pub fn query_external_importables(
@@ -139,8 +141,8 @@ pub enum ModuleDef {
139 TypeAlias(TypeAlias), 141 TypeAlias(TypeAlias),
140 BuiltinType(BuiltinType), 142 BuiltinType(BuiltinType),
141} 143}
142impl_froms!( 144impl_from!(
143 ModuleDef: Module, 145 Module,
144 Function, 146 Function,
145 Adt(Struct, Enum, Union), 147 Adt(Struct, Enum, Union),
146 EnumVariant, 148 EnumVariant,
@@ -149,6 +151,7 @@ impl_froms!(
149 Trait, 151 Trait,
150 TypeAlias, 152 TypeAlias,
151 BuiltinType 153 BuiltinType
154 for ModuleDef
152); 155);
153 156
154impl ModuleDef { 157impl ModuleDef {
@@ -376,8 +379,8 @@ pub struct Field {
376 379
377#[derive(Debug, PartialEq, Eq)] 380#[derive(Debug, PartialEq, Eq)]
378pub enum FieldSource { 381pub enum FieldSource {
379 Named(ast::RecordFieldDef), 382 Named(ast::RecordField),
380 Pos(ast::TupleFieldDef), 383 Pos(ast::TupleField),
381} 384}
382 385
383impl Field { 386impl Field {
@@ -556,7 +559,7 @@ pub enum Adt {
556 Union(Union), 559 Union(Union),
557 Enum(Enum), 560 Enum(Enum),
558} 561}
559impl_froms!(Adt: Struct, Union, Enum); 562impl_from!(Struct, Union, Enum for Adt);
560 563
561impl Adt { 564impl Adt {
562 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { 565 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
@@ -599,7 +602,7 @@ pub enum VariantDef {
599 Union(Union), 602 Union(Union),
600 EnumVariant(EnumVariant), 603 EnumVariant(EnumVariant),
601} 604}
602impl_froms!(VariantDef: Struct, Union, EnumVariant); 605impl_from!(Struct, Union, EnumVariant for VariantDef);
603 606
604impl VariantDef { 607impl VariantDef {
605 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { 608 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
@@ -642,8 +645,7 @@ pub enum DefWithBody {
642 Static(Static), 645 Static(Static),
643 Const(Const), 646 Const(Const),
644} 647}
645 648impl_from!(Function, Const, Static for DefWithBody);
646impl_froms!(DefWithBody: Function, Const, Static);
647 649
648impl DefWithBody { 650impl DefWithBody {
649 pub fn module(self, db: &dyn HirDatabase) -> Module { 651 pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -694,13 +696,7 @@ impl Function {
694 } 696 }
695 697
696 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 698 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
697 let _p = profile("Function::diagnostics"); 699 hir_ty::diagnostics::validate_body(db, self.id.into(), sink)
698 let infer = db.infer(self.id.into());
699 infer.add_diagnostics(db, self.id, sink);
700 let mut validator = ExprValidator::new(self.id, infer.clone(), sink);
701 validator.validate_body(db);
702 let mut validator = UnsafeValidator::new(self.id, infer, sink);
703 validator.validate_body(db);
704 } 700 }
705} 701}
706 702
@@ -945,14 +941,15 @@ pub enum GenericDef {
945 // consts can have type parameters from their parents (i.e. associated consts of traits) 941 // consts can have type parameters from their parents (i.e. associated consts of traits)
946 Const(Const), 942 Const(Const),
947} 943}
948impl_froms!( 944impl_from!(
949 GenericDef: Function, 945 Function,
950 Adt(Struct, Enum, Union), 946 Adt(Struct, Enum, Union),
951 Trait, 947 Trait,
952 TypeAlias, 948 TypeAlias,
953 ImplDef, 949 ImplDef,
954 EnumVariant, 950 EnumVariant,
955 Const 951 Const
952 for GenericDef
956); 953);
957 954
958impl GenericDef { 955impl GenericDef {
@@ -973,6 +970,16 @@ pub struct Local {
973} 970}
974 971
975impl Local { 972impl Local {
973 pub fn is_param(self, db: &dyn HirDatabase) -> bool {
974 let src = self.source(db);
975 match src.value {
976 Either::Left(bind_pat) => {
977 bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind()))
978 }
979 Either::Right(_self_param) => true,
980 }
981 }
982
976 // FIXME: why is this an option? It shouldn't be? 983 // FIXME: why is this an option? It shouldn't be?
977 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 984 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
978 let body = db.body(self.parent.into()); 985 let body = db.body(self.parent.into());
@@ -1071,12 +1078,14 @@ pub struct ImplDef {
1071 1078
1072impl ImplDef { 1079impl ImplDef {
1073 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> { 1080 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> {
1074 let impls = db.impls_in_crate(krate.id); 1081 let inherent = db.inherent_impls_in_crate(krate.id);
1075 impls.all_impls().map(Self::from).collect() 1082 let trait_ = db.trait_impls_in_crate(krate.id);
1083
1084 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1076 } 1085 }
1077 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> { 1086 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> {
1078 let impls = db.impls_in_crate(krate.id); 1087 let impls = db.trait_impls_in_crate(krate.id);
1079 impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect() 1088 impls.for_trait(trait_.id).map(Self::from).collect()
1080 } 1089 }
1081 1090
1082 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1091 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1178,6 +1187,12 @@ impl Type {
1178 Type::new(db, krate, def, ty) 1187 Type::new(db, krate, def, ty)
1179 } 1188 }
1180 1189
1190 pub fn is_unit(&self) -> bool {
1191 matches!(
1192 self.ty.value,
1193 Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. })
1194 )
1195 }
1181 pub fn is_bool(&self) -> bool { 1196 pub fn is_bool(&self) -> bool {
1182 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) 1197 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }))
1183 } 1198 }
@@ -1205,7 +1220,7 @@ impl Type {
1205 None => return false, 1220 None => return false,
1206 }; 1221 };
1207 1222
1208 let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1223 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1209 method_resolution::implements_trait( 1224 method_resolution::implements_trait(
1210 &canonical_ty, 1225 &canonical_ty,
1211 db, 1226 db,
@@ -1229,15 +1244,20 @@ impl Type {
1229 self.ty.environment.clone(), 1244 self.ty.environment.clone(),
1230 hir_ty::Obligation::Trait(trait_ref), 1245 hir_ty::Obligation::Trait(trait_ref),
1231 ), 1246 ),
1232 num_vars: 0, 1247 kinds: Arc::new([]),
1233 }; 1248 };
1234 1249
1235 db.trait_solve(self.krate, goal).is_some() 1250 db.trait_solve(self.krate, goal).is_some()
1236 } 1251 }
1237 1252
1238 // FIXME: this method is broken, as it doesn't take closures into account. 1253 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1239 pub fn as_callable(&self) -> Option<CallableDef> { 1254 let def = match self.ty.value {
1240 Some(self.ty.value.as_callable()?.0) 1255 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def),
1256 _ => None,
1257 };
1258
1259 let sig = self.ty.value.callable_sig(db)?;
1260 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1241 } 1261 }
1242 1262
1243 pub fn is_closure(&self) -> bool { 1263 pub fn is_closure(&self) -> bool {
@@ -1304,7 +1324,7 @@ impl Type {
1304 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { 1324 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1305 // There should be no inference vars in types passed here 1325 // There should be no inference vars in types passed here
1306 // FIXME check that? 1326 // FIXME check that?
1307 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1327 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1308 let environment = self.ty.environment.clone(); 1328 let environment = self.ty.environment.clone();
1309 let ty = InEnvironment { value: canonical, environment }; 1329 let ty = InEnvironment { value: canonical, environment };
1310 autoderef(db, Some(self.krate), ty) 1330 autoderef(db, Some(self.krate), ty)
@@ -1321,10 +1341,10 @@ impl Type {
1321 mut callback: impl FnMut(AssocItem) -> Option<T>, 1341 mut callback: impl FnMut(AssocItem) -> Option<T>,
1322 ) -> Option<T> { 1342 ) -> Option<T> {
1323 for krate in self.ty.value.def_crates(db, krate.id)? { 1343 for krate in self.ty.value.def_crates(db, krate.id)? {
1324 let impls = db.impls_in_crate(krate); 1344 let impls = db.inherent_impls_in_crate(krate);
1325 1345
1326 for impl_def in impls.lookup_impl_defs(&self.ty.value) { 1346 for impl_def in impls.for_self_ty(&self.ty.value) {
1327 for &item in db.impl_data(impl_def).items.iter() { 1347 for &item in db.impl_data(*impl_def).items.iter() {
1328 if let Some(result) = callback(item.into()) { 1348 if let Some(result) = callback(item.into()) {
1329 return Some(result); 1349 return Some(result);
1330 } 1350 }
@@ -1345,7 +1365,7 @@ impl Type {
1345 // There should be no inference vars in types passed here 1365 // There should be no inference vars in types passed here
1346 // FIXME check that? 1366 // FIXME check that?
1347 // FIXME replace Unknown by bound vars here 1367 // FIXME replace Unknown by bound vars here
1348 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1368 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1349 1369
1350 let env = self.ty.environment.clone(); 1370 let env = self.ty.environment.clone();
1351 let krate = krate.id; 1371 let krate = krate.id;
@@ -1376,7 +1396,7 @@ impl Type {
1376 // There should be no inference vars in types passed here 1396 // There should be no inference vars in types passed here
1377 // FIXME check that? 1397 // FIXME check that?
1378 // FIXME replace Unknown by bound vars here 1398 // FIXME replace Unknown by bound vars here
1379 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1399 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1380 1400
1381 let env = self.ty.environment.clone(); 1401 let env = self.ty.environment.clone();
1382 let krate = krate.id; 1402 let krate = krate.id;
@@ -1522,6 +1542,74 @@ impl HirDisplay for Type {
1522 } 1542 }
1523} 1543}
1524 1544
1545// FIXME: closures
1546#[derive(Debug)]
1547pub struct Callable {
1548 ty: Type,
1549 sig: FnSig,
1550 def: Option<CallableDefId>,
1551 pub(crate) is_bound_method: bool,
1552}
1553
1554pub enum CallableKind {
1555 Function(Function),
1556 TupleStruct(Struct),
1557 TupleEnumVariant(EnumVariant),
1558 Closure,
1559}
1560
1561impl Callable {
1562 pub fn kind(&self) -> CallableKind {
1563 match self.def {
1564 Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
1565 Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
1566 Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
1567 None => CallableKind::Closure,
1568 }
1569 }
1570 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
1571 let func = match self.def {
1572 Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
1573 _ => return None,
1574 };
1575 let src = func.lookup(db.upcast()).source(db.upcast());
1576 let param_list = src.value.param_list()?;
1577 param_list.self_param()
1578 }
1579 pub fn n_params(&self) -> usize {
1580 self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
1581 }
1582 pub fn params(
1583 &self,
1584 db: &dyn HirDatabase,
1585 ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
1586 let types = self
1587 .sig
1588 .params()
1589 .iter()
1590 .skip(if self.is_bound_method { 1 } else { 0 })
1591 .map(|ty| self.ty.derived(ty.clone()));
1592 let patterns = match self.def {
1593 Some(CallableDefId::FunctionId(func)) => {
1594 let src = func.lookup(db.upcast()).source(db.upcast());
1595 src.value.param_list().map(|param_list| {
1596 param_list
1597 .self_param()
1598 .map(|it| Some(Either::Left(it)))
1599 .filter(|_| !self.is_bound_method)
1600 .into_iter()
1601 .chain(param_list.params().map(|it| it.pat().map(Either::Right)))
1602 })
1603 }
1604 _ => None,
1605 };
1606 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
1607 }
1608 pub fn return_type(&self) -> Type {
1609 self.ty.derived(self.sig.ret().clone())
1610 }
1611}
1612
1525/// For IDE only 1613/// For IDE only
1526#[derive(Debug)] 1614#[derive(Debug)]
1527pub enum ScopeDef { 1615pub enum ScopeDef {
@@ -1581,8 +1669,8 @@ pub enum AttrDef {
1581 MacroDef(MacroDef), 1669 MacroDef(MacroDef),
1582} 1670}
1583 1671
1584impl_froms!( 1672impl_from!(
1585 AttrDef: Module, 1673 Module,
1586 Field, 1674 Field,
1587 Adt(Struct, Enum, Union), 1675 Adt(Struct, Enum, Union),
1588 EnumVariant, 1676 EnumVariant,
@@ -1592,6 +1680,7 @@ impl_froms!(
1592 Trait, 1680 Trait,
1593 TypeAlias, 1681 TypeAlias,
1594 MacroDef 1682 MacroDef
1683 for AttrDef
1595); 1684);
1596 1685
1597pub trait HasAttrs { 1686pub trait HasAttrs {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index bb67952de..a2b9f3e35 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -11,15 +11,15 @@ pub use hir_def::db::{
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, 13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery,
14 MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, 14 MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery,
15}; 15};
16pub use hir_ty::db::{ 16pub use hir_ty::db::{
17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, 17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, 18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery, 19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery,
20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, 20 InherentImplsInCrateQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
21 InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, 21 TraitDatumQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
22 TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, 22 ValueTyQuery,
23}; 23};
24 24
25#[test] 25#[test]
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index c82883d0c..266b513dc 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,4 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2pub use hir_def::diagnostics::UnresolvedModule; 2pub use hir_def::diagnostics::UnresolvedModule;
3pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 3pub use hir_expand::diagnostics::{
4pub use hir_ty::diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField}; 4 AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder,
5};
6pub use hir_ty::diagnostics::{
7 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
8};
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
index 76c32fc17..1c691d961 100644
--- a/crates/ra_hir/src/has_source.rs
+++ b/crates/ra_hir/src/has_source.rs
@@ -57,56 +57,56 @@ impl HasSource for Field {
57 } 57 }
58} 58}
59impl HasSource for Struct { 59impl HasSource for Struct {
60 type Ast = ast::StructDef; 60 type Ast = ast::Struct;
61 fn source(self, db: &dyn HirDatabase) -> InFile<ast::StructDef> { 61 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
62 self.id.lookup(db.upcast()).source(db.upcast()) 62 self.id.lookup(db.upcast()).source(db.upcast())
63 } 63 }
64} 64}
65impl HasSource for Union { 65impl HasSource for Union {
66 type Ast = ast::UnionDef; 66 type Ast = ast::Union;
67 fn source(self, db: &dyn HirDatabase) -> InFile<ast::UnionDef> { 67 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
68 self.id.lookup(db.upcast()).source(db.upcast()) 68 self.id.lookup(db.upcast()).source(db.upcast())
69 } 69 }
70} 70}
71impl HasSource for Enum { 71impl HasSource for Enum {
72 type Ast = ast::EnumDef; 72 type Ast = ast::Enum;
73 fn source(self, db: &dyn HirDatabase) -> InFile<ast::EnumDef> { 73 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
74 self.id.lookup(db.upcast()).source(db.upcast()) 74 self.id.lookup(db.upcast()).source(db.upcast())
75 } 75 }
76} 76}
77impl HasSource for EnumVariant { 77impl HasSource for EnumVariant {
78 type Ast = ast::EnumVariant; 78 type Ast = ast::Variant;
79 fn source(self, db: &dyn HirDatabase) -> InFile<ast::EnumVariant> { 79 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
80 self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) 80 self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
81 } 81 }
82} 82}
83impl HasSource for Function { 83impl HasSource for Function {
84 type Ast = ast::FnDef; 84 type Ast = ast::Fn;
85 fn source(self, db: &dyn HirDatabase) -> InFile<ast::FnDef> { 85 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
86 self.id.lookup(db.upcast()).source(db.upcast()) 86 self.id.lookup(db.upcast()).source(db.upcast())
87 } 87 }
88} 88}
89impl HasSource for Const { 89impl HasSource for Const {
90 type Ast = ast::ConstDef; 90 type Ast = ast::Const;
91 fn source(self, db: &dyn HirDatabase) -> InFile<ast::ConstDef> { 91 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
92 self.id.lookup(db.upcast()).source(db.upcast()) 92 self.id.lookup(db.upcast()).source(db.upcast())
93 } 93 }
94} 94}
95impl HasSource for Static { 95impl HasSource for Static {
96 type Ast = ast::StaticDef; 96 type Ast = ast::Static;
97 fn source(self, db: &dyn HirDatabase) -> InFile<ast::StaticDef> { 97 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
98 self.id.lookup(db.upcast()).source(db.upcast()) 98 self.id.lookup(db.upcast()).source(db.upcast())
99 } 99 }
100} 100}
101impl HasSource for Trait { 101impl HasSource for Trait {
102 type Ast = ast::TraitDef; 102 type Ast = ast::Trait;
103 fn source(self, db: &dyn HirDatabase) -> InFile<ast::TraitDef> { 103 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
104 self.id.lookup(db.upcast()).source(db.upcast()) 104 self.id.lookup(db.upcast()).source(db.upcast())
105 } 105 }
106} 106}
107impl HasSource for TypeAlias { 107impl HasSource for TypeAlias {
108 type Ast = ast::TypeAliasDef; 108 type Ast = ast::TypeAlias;
109 fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAliasDef> { 109 fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
110 self.id.lookup(db.upcast()).source(db.upcast()) 110 self.id.lookup(db.upcast()).source(db.upcast())
111 } 111 }
112} 112}
@@ -120,14 +120,14 @@ impl HasSource for MacroDef {
120 } 120 }
121} 121}
122impl HasSource for ImplDef { 122impl HasSource for ImplDef {
123 type Ast = ast::ImplDef; 123 type Ast = ast::Impl;
124 fn source(self, db: &dyn HirDatabase) -> InFile<ast::ImplDef> { 124 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
125 self.id.lookup(db.upcast()).source(db.upcast()) 125 self.id.lookup(db.upcast()).source(db.upcast())
126 } 126 }
127} 127}
128 128
129impl HasSource for TypeParam { 129impl HasSource for TypeParam {
130 type Ast = Either<ast::TraitDef, ast::TypeParam>; 130 type Ast = Either<ast::Trait, ast::TypeParam>;
131 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { 131 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
132 let child_source = self.id.parent.child_source(db.upcast()); 132 let child_source = self.id.parent.child_source(db.upcast());
133 child_source.map(|it| it[self.id.local_id].clone()) 133 child_source.map(|it| it[self.id.local_id].clone())
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index fe34b30bc..e2d13dbfd 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -19,25 +19,6 @@
19 19
20#![recursion_limit = "512"] 20#![recursion_limit = "512"]
21 21
22macro_rules! impl_froms {
23 ($e:ident: $($v:ident $(($($sv:ident),*))?),*$(,)?) => {
24 $(
25 impl From<$v> for $e {
26 fn from(it: $v) -> $e {
27 $e::$v(it)
28 }
29 }
30 $($(
31 impl From<$sv> for $e {
32 fn from(it: $sv) -> $e {
33 $e::$v($v::$sv(it))
34 }
35 }
36 )*)?
37 )*
38 }
39}
40
41mod semantics; 22mod semantics;
42pub mod db; 23pub mod db;
43mod source_analyzer; 24mod source_analyzer;
@@ -51,10 +32,10 @@ mod has_source;
51 32
52pub use crate::{ 33pub use crate::{
53 code_model::{ 34 code_model::{
54 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, 35 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
55 DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, 36 Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
56 HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 37 GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
57 Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, 38 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
58 }, 39 },
59 has_source::HasSource, 40 has_source::HasSource,
60 semantics::{original_range, PathResolution, Semantics, SemanticsScope}, 41 semantics::{original_range, PathResolution, Semantics, SemanticsScope},
@@ -74,6 +55,7 @@ pub use hir_def::{
74pub use hir_expand::{ 55pub use hir_expand::{
75 hygiene::Hygiene, 56 hygiene::Hygiene,
76 name::{AsName, Name}, 57 name::{AsName, Name},
77 HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, 58 HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, /* FIXME */
59 MacroFile, Origin,
78}; 60};
79pub use hir_ty::{display::HirDisplay, CallableDef}; 61pub use hir_ty::display::HirDisplay;
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 6a49c424a..6f3b3dc9a 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use hir_def::{ 7use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, TraitId, VariantId, 9 AsMacroCall, FunctionId, TraitId, VariantId,
10}; 10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
@@ -24,8 +24,8 @@ use crate::{
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, 27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, 28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
29}; 29};
30use resolver::TypeNs; 30use resolver::TypeNs;
31 31
@@ -83,7 +83,13 @@ impl PathResolution {
83/// Primary API to get semantic information, like types, from syntax trees. 83/// Primary API to get semantic information, like types, from syntax trees.
84pub struct Semantics<'db, DB> { 84pub struct Semantics<'db, DB> {
85 pub db: &'db DB, 85 pub db: &'db DB,
86 imp: SemanticsImpl<'db>,
87}
88
89pub struct SemanticsImpl<'db> {
90 pub db: &'db dyn HirDatabase,
86 s2d_cache: RefCell<SourceToDefCache>, 91 s2d_cache: RefCell<SourceToDefCache>,
92 expansion_info_cache: RefCell<FxHashMap<HirFileId, Option<ExpansionInfo>>>,
87 cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, 93 cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
88} 94}
89 95
@@ -95,23 +101,199 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
95 101
96impl<'db, DB: HirDatabase> Semantics<'db, DB> { 102impl<'db, DB: HirDatabase> Semantics<'db, DB> {
97 pub fn new(db: &DB) -> Semantics<DB> { 103 pub fn new(db: &DB) -> Semantics<DB> {
98 Semantics { db, s2d_cache: Default::default(), cache: Default::default() } 104 let impl_ = SemanticsImpl::new(db);
105 Semantics { db, imp: impl_ }
99 } 106 }
100 107
101 pub fn parse(&self, file_id: FileId) -> ast::SourceFile { 108 pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
102 let tree = self.db.parse(file_id).tree(); 109 self.imp.parse(file_id)
103 self.cache(tree.syntax().clone(), file_id.into());
104 tree
105 } 110 }
106 111
107 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { 112 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
108 let file_id = d.source().file_id; 113 let file_id = d.source().file_id;
109 let root = self.db.parse_or_expand(file_id).unwrap(); 114 let root = self.db.parse_or_expand(file_id).unwrap();
110 self.cache(root, file_id); 115 self.imp.cache(root, file_id);
111 d.ast(self.db) 116 d.ast(self.db.upcast())
112 } 117 }
113 118
114 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 119 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
120 self.imp.expand(macro_call)
121 }
122
123 pub fn expand_hypothetical(
124 &self,
125 actual_macro_call: &ast::MacroCall,
126 hypothetical_args: &ast::TokenTree,
127 token_to_map: SyntaxToken,
128 ) -> Option<(SyntaxNode, SyntaxToken)> {
129 self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map)
130 }
131
132 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
133 self.imp.descend_into_macros(token)
134 }
135
136 pub fn descend_node_at_offset<N: ast::AstNode>(
137 &self,
138 node: &SyntaxNode,
139 offset: TextSize,
140 ) -> Option<N> {
141 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
142 }
143
144 pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
145 self.imp.original_range(node)
146 }
147
148 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
149 self.imp.diagnostics_range(diagnostics)
150 }
151
152 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
153 self.imp.ancestors_with_macros(node)
154 }
155
156 pub fn ancestors_at_offset_with_macros(
157 &self,
158 node: &SyntaxNode,
159 offset: TextSize,
160 ) -> impl Iterator<Item = SyntaxNode> + '_ {
161 self.imp.ancestors_at_offset_with_macros(node, offset)
162 }
163
164 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
165 /// search up until it is of the target AstNode type
166 pub fn find_node_at_offset_with_macros<N: AstNode>(
167 &self,
168 node: &SyntaxNode,
169 offset: TextSize,
170 ) -> Option<N> {
171 self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
172 }
173
174 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
175 /// descend it and find again
176 pub fn find_node_at_offset_with_descend<N: AstNode>(
177 &self,
178 node: &SyntaxNode,
179 offset: TextSize,
180 ) -> Option<N> {
181 if let Some(it) = find_node_at_offset(&node, offset) {
182 return Some(it);
183 }
184
185 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
186 }
187
188 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
189 self.imp.type_of_expr(expr)
190 }
191
192 pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
193 self.imp.type_of_pat(pat)
194 }
195
196 pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
197 self.imp.type_of_self(param)
198 }
199
200 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
201 self.imp.resolve_method_call(call).map(Function::from)
202 }
203
204 pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
205 self.imp.resolve_method_call_as_callable(call)
206 }
207
208 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
209 self.imp.resolve_field(field)
210 }
211
212 pub fn resolve_record_field(
213 &self,
214 field: &ast::RecordExprField,
215 ) -> Option<(Field, Option<Local>)> {
216 self.imp.resolve_record_field(field)
217 }
218
219 pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
220 self.imp.resolve_record_field_pat(field)
221 }
222
223 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
224 self.imp.resolve_macro_call(macro_call)
225 }
226
227 pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
228 self.imp.resolve_path(path)
229 }
230
231 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
232 self.imp.resolve_variant(record_lit).map(VariantDef::from)
233 }
234
235 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> {
236 self.imp.lower_path(path)
237 }
238
239 pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
240 self.imp.resolve_bind_pat_to_const(pat)
241 }
242
243 // FIXME: use this instead?
244 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
245
246 pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
247 self.imp.record_literal_missing_fields(literal)
248 }
249
250 pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
251 self.imp.record_pattern_missing_fields(pattern)
252 }
253
254 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
255 let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned();
256 T::to_def(&self.imp, src)
257 }
258
259 pub fn to_module_def(&self, file: FileId) -> Option<Module> {
260 self.imp.to_module_def(file)
261 }
262
263 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
264 self.imp.scope(node)
265 }
266
267 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
268 self.imp.scope_at_offset(node, offset)
269 }
270
271 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
272 self.imp.scope_for_def(def)
273 }
274
275 pub fn assert_contains_node(&self, node: &SyntaxNode) {
276 self.imp.assert_contains_node(node)
277 }
278}
279
280impl<'db> SemanticsImpl<'db> {
281 fn new(db: &'db dyn HirDatabase) -> Self {
282 SemanticsImpl {
283 db,
284 s2d_cache: Default::default(),
285 cache: Default::default(),
286 expansion_info_cache: Default::default(),
287 }
288 }
289
290 fn parse(&self, file_id: FileId) -> ast::SourceFile {
291 let tree = self.db.parse(file_id).tree();
292 self.cache(tree.syntax().clone(), file_id.into());
293 tree
294 }
295
296 fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
115 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 297 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
116 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); 298 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
117 let file_id = sa.expand(self.db, macro_call)?; 299 let file_id = sa.expand(self.db, macro_call)?;
@@ -120,7 +302,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
120 Some(node) 302 Some(node)
121 } 303 }
122 304
123 pub fn expand_hypothetical( 305 fn expand_hypothetical(
124 &self, 306 &self,
125 actual_macro_call: &ast::MacroCall, 307 actual_macro_call: &ast::MacroCall,
126 hypothetical_args: &ast::TokenTree, 308 hypothetical_args: &ast::TokenTree,
@@ -130,24 +312,38 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
130 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); 312 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
131 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); 313 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
132 let krate = sa.resolver.krate()?; 314 let krate = sa.resolver.krate()?;
133 let macro_call_id = macro_call 315 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
134 .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; 316 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
135 hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) 317 })?;
136 } 318 hir_expand::db::expand_hypothetical(
137 319 self.db.upcast(),
138 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 320 macro_call_id,
321 hypothetical_args,
322 token_to_map,
323 )
324 }
325
326 fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
327 let _p = profile("descend_into_macros");
139 let parent = token.parent(); 328 let parent = token.parent();
140 let parent = self.find_file(parent); 329 let parent = self.find_file(parent);
141 let sa = self.analyze2(parent.as_ref(), None); 330 let sa = self.analyze2(parent.as_ref(), None);
142 331
143 let token = successors(Some(parent.with_value(token)), |token| { 332 let token = successors(Some(parent.with_value(token)), |token| {
333 self.db.check_canceled();
144 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 334 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
145 let tt = macro_call.token_tree()?; 335 let tt = macro_call.token_tree()?;
146 if !tt.syntax().text_range().contains_range(token.value.text_range()) { 336 if !tt.syntax().text_range().contains_range(token.value.text_range()) {
147 return None; 337 return None;
148 } 338 }
149 let file_id = sa.expand(self.db, token.with_value(&macro_call))?; 339 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
150 let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?; 340 let token = self
341 .expansion_info_cache
342 .borrow_mut()
343 .entry(file_id)
344 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
345 .as_ref()?
346 .map_token_down(token.as_ref())?;
151 347
152 self.cache(find_root(&token.value.parent()), token.file_id); 348 self.cache(find_root(&token.value.parent()), token.file_id);
153 349
@@ -159,35 +355,36 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
159 token.value 355 token.value
160 } 356 }
161 357
162 pub fn descend_node_at_offset<N: ast::AstNode>( 358 fn descend_node_at_offset(
163 &self, 359 &self,
164 node: &SyntaxNode, 360 node: &SyntaxNode,
165 offset: TextSize, 361 offset: TextSize,
166 ) -> Option<N> { 362 ) -> impl Iterator<Item = SyntaxNode> + '_ {
167 // Handle macro token cases 363 // Handle macro token cases
168 node.token_at_offset(offset) 364 node.token_at_offset(offset)
169 .map(|token| self.descend_into_macros(token)) 365 .map(|token| self.descend_into_macros(token))
170 .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) 366 .map(|it| self.ancestors_with_macros(it.parent()))
367 .flatten()
171 } 368 }
172 369
173 pub fn original_range(&self, node: &SyntaxNode) -> FileRange { 370 fn original_range(&self, node: &SyntaxNode) -> FileRange {
174 let node = self.find_file(node.clone()); 371 let node = self.find_file(node.clone());
175 original_range(self.db, node.as_ref()) 372 original_range(self.db, node.as_ref())
176 } 373 }
177 374
178 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { 375 fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
179 let src = diagnostics.source(); 376 let src = diagnostics.source();
180 let root = self.db.parse_or_expand(src.file_id).unwrap(); 377 let root = self.db.parse_or_expand(src.file_id).unwrap();
181 let node = src.value.to_node(&root); 378 let node = src.value.to_node(&root);
182 original_range(self.db, src.with_value(&node)) 379 original_range(self.db, src.with_value(&node))
183 } 380 }
184 381
185 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { 382 fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
186 let node = self.find_file(node); 383 let node = self.find_file(node);
187 node.ancestors_with_macros(self.db).map(|it| it.value) 384 node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
188 } 385 }
189 386
190 pub fn ancestors_at_offset_with_macros( 387 fn ancestors_at_offset_with_macros(
191 &self, 388 &self,
192 node: &SyntaxNode, 389 node: &SyntaxNode,
193 offset: TextSize, 390 offset: TextSize,
@@ -197,120 +394,104 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
197 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) 394 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
198 } 395 }
199 396
200 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, 397 fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
201 /// search up until it is of the target AstNode type 398 self.analyze(expr.syntax()).type_of_expr(self.db, &expr)
202 pub fn find_node_at_offset_with_macros<N: AstNode>(
203 &self,
204 node: &SyntaxNode,
205 offset: TextSize,
206 ) -> Option<N> {
207 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
208 } 399 }
209 400
210 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, 401 fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
211 /// descend it and find again 402 self.analyze(pat.syntax()).type_of_pat(self.db, &pat)
212 pub fn find_node_at_offset_with_descend<N: AstNode>(
213 &self,
214 node: &SyntaxNode,
215 offset: TextSize,
216 ) -> Option<N> {
217 if let Some(it) = find_node_at_offset(&node, offset) {
218 return Some(it);
219 }
220 self.descend_node_at_offset(&node, offset)
221 } 403 }
222 404
223 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { 405 fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
224 self.analyze(expr.syntax()).type_of(self.db, &expr) 406 self.analyze(param.syntax()).type_of_self(self.db, &param)
225 } 407 }
226 408
227 pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { 409 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
228 self.analyze(pat.syntax()).type_of_pat(self.db, &pat) 410 self.analyze(call.syntax()).resolve_method_call(self.db, call)
229 } 411 }
230 412
231 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 413 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
232 self.analyze(call.syntax()).resolve_method_call(self.db, call) 414 // FIXME: this erases Substs
415 let func = self.resolve_method_call(call)?;
416 let ty = self.db.value_ty(func.into());
417 let resolver = self.analyze(call.syntax()).resolver;
418 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?;
419 let mut res = ty.as_callable(self.db)?;
420 res.is_bound_method = true;
421 Some(res)
233 } 422 }
234 423
235 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { 424 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
236 self.analyze(field.syntax()).resolve_field(self.db, field) 425 self.analyze(field.syntax()).resolve_field(self.db, field)
237 } 426 }
238 427
239 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> { 428 fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> {
240 self.analyze(field.syntax()).resolve_record_field(self.db, field) 429 self.analyze(field.syntax()).resolve_record_field(self.db, field)
241 } 430 }
242 431
243 pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { 432 fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
244 self.analyze(field.syntax()).resolve_record_field_pat(self.db, field) 433 self.analyze(field.syntax()).resolve_record_field_pat(self.db, field)
245 } 434 }
246 435
247 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { 436 fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
248 let sa = self.analyze(macro_call.syntax()); 437 let sa = self.analyze(macro_call.syntax());
249 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 438 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
250 sa.resolve_macro_call(self.db, macro_call) 439 sa.resolve_macro_call(self.db, macro_call)
251 } 440 }
252 441
253 pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { 442 fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
254 self.analyze(path.syntax()).resolve_path(self.db, path) 443 self.analyze(path.syntax()).resolve_path(self.db, path)
255 } 444 }
256 445
257 pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { 446 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
258 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) 447 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
259 } 448 }
260 449
261 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { 450 fn lower_path(&self, path: &ast::Path) -> Option<Path> {
262 let src = self.find_file(path.syntax().clone()); 451 let src = self.find_file(path.syntax().clone());
263 Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) 452 Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into()))
264 } 453 }
265 454
266 pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { 455 fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
267 self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) 456 self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
268 } 457 }
269 458
270 // FIXME: use this instead? 459 fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
271 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
272
273 pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> {
274 self.analyze(literal.syntax()) 460 self.analyze(literal.syntax())
275 .record_literal_missing_fields(self.db, literal) 461 .record_literal_missing_fields(self.db, literal)
276 .unwrap_or_default() 462 .unwrap_or_default()
277 } 463 }
278 464
279 pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { 465 fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
280 self.analyze(pattern.syntax()) 466 self.analyze(pattern.syntax())
281 .record_pattern_missing_fields(self.db, pattern) 467 .record_pattern_missing_fields(self.db, pattern)
282 .unwrap_or_default() 468 .unwrap_or_default()
283 } 469 }
284 470
285 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
286 let src = self.find_file(src.syntax().clone()).with_value(src).cloned();
287 T::to_def(self, src)
288 }
289
290 fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { 471 fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T {
291 let mut cache = self.s2d_cache.borrow_mut(); 472 let mut cache = self.s2d_cache.borrow_mut();
292 let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; 473 let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
293 f(&mut ctx) 474 f(&mut ctx)
294 } 475 }
295 476
296 pub fn to_module_def(&self, file: FileId) -> Option<Module> { 477 fn to_module_def(&self, file: FileId) -> Option<Module> {
297 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) 478 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
298 } 479 }
299 480
300 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db, DB> { 481 fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
301 let node = self.find_file(node.clone()); 482 let node = self.find_file(node.clone());
302 let resolver = self.analyze2(node.as_ref(), None).resolver; 483 let resolver = self.analyze2(node.as_ref(), None).resolver;
303 SemanticsScope { db: self.db, resolver } 484 SemanticsScope { db: self.db, resolver }
304 } 485 }
305 486
306 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db, DB> { 487 fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
307 let node = self.find_file(node.clone()); 488 let node = self.find_file(node.clone());
308 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; 489 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
309 SemanticsScope { db: self.db, resolver } 490 SemanticsScope { db: self.db, resolver }
310 } 491 }
311 492
312 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db, DB> { 493 fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
313 let resolver = def.id.resolver(self.db); 494 let resolver = def.id.resolver(self.db.upcast());
314 SemanticsScope { db: self.db, resolver } 495 SemanticsScope { db: self.db, resolver }
315 } 496 }
316 497
@@ -331,12 +512,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
331 ChildContainer::DefWithBodyId(def) => { 512 ChildContainer::DefWithBodyId(def) => {
332 return SourceAnalyzer::new_for_body(self.db, def, src, offset) 513 return SourceAnalyzer::new_for_body(self.db, def, src, offset)
333 } 514 }
334 ChildContainer::TraitId(it) => it.resolver(self.db), 515 ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
335 ChildContainer::ImplId(it) => it.resolver(self.db), 516 ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
336 ChildContainer::ModuleId(it) => it.resolver(self.db), 517 ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()),
337 ChildContainer::EnumId(it) => it.resolver(self.db), 518 ChildContainer::EnumId(it) => it.resolver(self.db.upcast()),
338 ChildContainer::VariantId(it) => it.resolver(self.db), 519 ChildContainer::VariantId(it) => it.resolver(self.db.upcast()),
339 ChildContainer::GenericDefId(it) => it.resolver(self.db), 520 ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
521 ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
340 }; 522 };
341 SourceAnalyzer::new_for_resolver(resolver, src) 523 SourceAnalyzer::new_for_resolver(resolver, src)
342 } 524 }
@@ -348,7 +530,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
348 assert!(prev == None || prev == Some(file_id)) 530 assert!(prev == None || prev == Some(file_id))
349 } 531 }
350 532
351 pub fn assert_contains_node(&self, node: &SyntaxNode) { 533 fn assert_contains_node(&self, node: &SyntaxNode) {
352 self.find_file(node.clone()); 534 self.find_file(node.clone());
353 } 535 }
354 536
@@ -382,14 +564,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
382pub trait ToDef: AstNode + Clone { 564pub trait ToDef: AstNode + Clone {
383 type Def; 565 type Def;
384 566
385 fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def>; 567 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>;
386} 568}
387 569
388macro_rules! to_def_impls { 570macro_rules! to_def_impls {
389 ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( 571 ($(($def:path, $ast:path, $meth:ident)),* ,) => {$(
390 impl ToDef for $ast { 572 impl ToDef for $ast {
391 type Def = $def; 573 type Def = $def;
392 fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def> { 574 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> {
393 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) 575 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
394 } 576 }
395 } 577 }
@@ -398,18 +580,18 @@ macro_rules! to_def_impls {
398 580
399to_def_impls![ 581to_def_impls![
400 (crate::Module, ast::Module, module_to_def), 582 (crate::Module, ast::Module, module_to_def),
401 (crate::Struct, ast::StructDef, struct_to_def), 583 (crate::Struct, ast::Struct, struct_to_def),
402 (crate::Enum, ast::EnumDef, enum_to_def), 584 (crate::Enum, ast::Enum, enum_to_def),
403 (crate::Union, ast::UnionDef, union_to_def), 585 (crate::Union, ast::Union, union_to_def),
404 (crate::Trait, ast::TraitDef, trait_to_def), 586 (crate::Trait, ast::Trait, trait_to_def),
405 (crate::ImplDef, ast::ImplDef, impl_to_def), 587 (crate::ImplDef, ast::Impl, impl_to_def),
406 (crate::TypeAlias, ast::TypeAliasDef, type_alias_to_def), 588 (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
407 (crate::Const, ast::ConstDef, const_to_def), 589 (crate::Const, ast::Const, const_to_def),
408 (crate::Static, ast::StaticDef, static_to_def), 590 (crate::Static, ast::Static, static_to_def),
409 (crate::Function, ast::FnDef, fn_to_def), 591 (crate::Function, ast::Fn, fn_to_def),
410 (crate::Field, ast::RecordFieldDef, record_field_to_def), 592 (crate::Field, ast::RecordField, record_field_to_def),
411 (crate::Field, ast::TupleFieldDef, tuple_field_to_def), 593 (crate::Field, ast::TupleField, tuple_field_to_def),
412 (crate::EnumVariant, ast::EnumVariant, enum_variant_to_def), 594 (crate::EnumVariant, ast::Variant, enum_variant_to_def),
413 (crate::TypeParam, ast::TypeParam, type_param_to_def), 595 (crate::TypeParam, ast::TypeParam, type_param_to_def),
414 (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros 596 (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
415 (crate::Local, ast::BindPat, bind_pat_to_def), 597 (crate::Local, ast::BindPat, bind_pat_to_def),
@@ -419,12 +601,13 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
419 node.ancestors().last().unwrap() 601 node.ancestors().last().unwrap()
420} 602}
421 603
422pub struct SemanticsScope<'a, DB> { 604#[derive(Debug)]
423 pub db: &'a DB, 605pub struct SemanticsScope<'a> {
606 pub db: &'a dyn HirDatabase,
424 resolver: Resolver, 607 resolver: Resolver,
425} 608}
426 609
427impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { 610impl<'a> SemanticsScope<'a> {
428 pub fn module(&self) -> Option<Module> { 611 pub fn module(&self) -> Option<Module> {
429 Some(Module { id: self.resolver.module()? }) 612 Some(Module { id: self.resolver.module()? })
430 } 613 }
@@ -433,13 +616,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
433 // FIXME: rename to visible_traits to not repeat scope? 616 // FIXME: rename to visible_traits to not repeat scope?
434 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { 617 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
435 let resolver = &self.resolver; 618 let resolver = &self.resolver;
436 resolver.traits_in_scope(self.db) 619 resolver.traits_in_scope(self.db.upcast())
437 } 620 }
438 621
439 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { 622 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
440 let resolver = &self.resolver; 623 let resolver = &self.resolver;
441 624
442 resolver.process_all_names(self.db, &mut |name, def| { 625 resolver.process_all_names(self.db.upcast(), &mut |name, def| {
443 let def = match def { 626 let def = match def {
444 resolver::ScopeDef::PerNs(it) => { 627 resolver::ScopeDef::PerNs(it) => {
445 let items = ScopeDef::all_items(it); 628 let items = ScopeDef::all_items(it);
diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs
index 8af64fdc1..d1994e2e7 100644
--- a/crates/ra_hir/src/semantics/source_to_def.rs
+++ b/crates/ra_hir/src/semantics/source_to_def.rs
@@ -16,6 +16,7 @@ use ra_syntax::{
16 match_ast, AstNode, SyntaxNode, 16 match_ast, AstNode, SyntaxNode,
17}; 17};
18use rustc_hash::FxHashMap; 18use rustc_hash::FxHashMap;
19use stdx::impl_from;
19 20
20use crate::{db::HirDatabase, InFile, MacroDefId}; 21use crate::{db::HirDatabase, InFile, MacroDefId};
21 22
@@ -64,53 +65,44 @@ impl SourceToDefCtx<'_, '_> {
64 Some(ModuleId { krate: parent_module.krate, local_id: child_id }) 65 Some(ModuleId { krate: parent_module.krate, local_id: child_id })
65 } 66 }
66 67
67 pub(super) fn trait_to_def(&mut self, src: InFile<ast::TraitDef>) -> Option<TraitId> { 68 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
68 self.to_def(src, keys::TRAIT) 69 self.to_def(src, keys::TRAIT)
69 } 70 }
70 pub(super) fn impl_to_def(&mut self, src: InFile<ast::ImplDef>) -> Option<ImplId> { 71 pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> {
71 self.to_def(src, keys::IMPL) 72 self.to_def(src, keys::IMPL)
72 } 73 }
73 pub(super) fn fn_to_def(&mut self, src: InFile<ast::FnDef>) -> Option<FunctionId> { 74 pub(super) fn fn_to_def(&mut self, src: InFile<ast::Fn>) -> Option<FunctionId> {
74 self.to_def(src, keys::FUNCTION) 75 self.to_def(src, keys::FUNCTION)
75 } 76 }
76 pub(super) fn struct_to_def(&mut self, src: InFile<ast::StructDef>) -> Option<StructId> { 77 pub(super) fn struct_to_def(&mut self, src: InFile<ast::Struct>) -> Option<StructId> {
77 self.to_def(src, keys::STRUCT) 78 self.to_def(src, keys::STRUCT)
78 } 79 }
79 pub(super) fn enum_to_def(&mut self, src: InFile<ast::EnumDef>) -> Option<EnumId> { 80 pub(super) fn enum_to_def(&mut self, src: InFile<ast::Enum>) -> Option<EnumId> {
80 self.to_def(src, keys::ENUM) 81 self.to_def(src, keys::ENUM)
81 } 82 }
82 pub(super) fn union_to_def(&mut self, src: InFile<ast::UnionDef>) -> Option<UnionId> { 83 pub(super) fn union_to_def(&mut self, src: InFile<ast::Union>) -> Option<UnionId> {
83 self.to_def(src, keys::UNION) 84 self.to_def(src, keys::UNION)
84 } 85 }
85 pub(super) fn static_to_def(&mut self, src: InFile<ast::StaticDef>) -> Option<StaticId> { 86 pub(super) fn static_to_def(&mut self, src: InFile<ast::Static>) -> Option<StaticId> {
86 self.to_def(src, keys::STATIC) 87 self.to_def(src, keys::STATIC)
87 } 88 }
88 pub(super) fn const_to_def(&mut self, src: InFile<ast::ConstDef>) -> Option<ConstId> { 89 pub(super) fn const_to_def(&mut self, src: InFile<ast::Const>) -> Option<ConstId> {
89 self.to_def(src, keys::CONST) 90 self.to_def(src, keys::CONST)
90 } 91 }
91 pub(super) fn type_alias_to_def( 92 pub(super) fn type_alias_to_def(&mut self, src: InFile<ast::TypeAlias>) -> Option<TypeAliasId> {
92 &mut self,
93 src: InFile<ast::TypeAliasDef>,
94 ) -> Option<TypeAliasId> {
95 self.to_def(src, keys::TYPE_ALIAS) 93 self.to_def(src, keys::TYPE_ALIAS)
96 } 94 }
97 pub(super) fn record_field_to_def( 95 pub(super) fn record_field_to_def(&mut self, src: InFile<ast::RecordField>) -> Option<FieldId> {
98 &mut self,
99 src: InFile<ast::RecordFieldDef>,
100 ) -> Option<FieldId> {
101 self.to_def(src, keys::RECORD_FIELD) 96 self.to_def(src, keys::RECORD_FIELD)
102 } 97 }
103 pub(super) fn tuple_field_to_def( 98 pub(super) fn tuple_field_to_def(&mut self, src: InFile<ast::TupleField>) -> Option<FieldId> {
104 &mut self,
105 src: InFile<ast::TupleFieldDef>,
106 ) -> Option<FieldId> {
107 self.to_def(src, keys::TUPLE_FIELD) 99 self.to_def(src, keys::TUPLE_FIELD)
108 } 100 }
109 pub(super) fn enum_variant_to_def( 101 pub(super) fn enum_variant_to_def(
110 &mut self, 102 &mut self,
111 src: InFile<ast::EnumVariant>, 103 src: InFile<ast::Variant>,
112 ) -> Option<EnumVariantId> { 104 ) -> Option<EnumVariantId> {
113 self.to_def(src, keys::ENUM_VARIANT) 105 self.to_def(src, keys::VARIANT)
114 } 106 }
115 pub(super) fn bind_pat_to_def( 107 pub(super) fn bind_pat_to_def(
116 &mut self, 108 &mut self,
@@ -162,38 +154,42 @@ impl SourceToDefCtx<'_, '_> {
162 let def = self.module_to_def(container.with_value(it))?; 154 let def = self.module_to_def(container.with_value(it))?;
163 def.into() 155 def.into()
164 }, 156 },
165 ast::TraitDef(it) => { 157 ast::Trait(it) => {
166 let def = self.trait_to_def(container.with_value(it))?; 158 let def = self.trait_to_def(container.with_value(it))?;
167 def.into() 159 def.into()
168 }, 160 },
169 ast::ImplDef(it) => { 161 ast::Impl(it) => {
170 let def = self.impl_to_def(container.with_value(it))?; 162 let def = self.impl_to_def(container.with_value(it))?;
171 def.into() 163 def.into()
172 }, 164 },
173 ast::FnDef(it) => { 165 ast::Fn(it) => {
174 let def = self.fn_to_def(container.with_value(it))?; 166 let def = self.fn_to_def(container.with_value(it))?;
175 DefWithBodyId::from(def).into() 167 DefWithBodyId::from(def).into()
176 }, 168 },
177 ast::StructDef(it) => { 169 ast::Struct(it) => {
178 let def = self.struct_to_def(container.with_value(it))?; 170 let def = self.struct_to_def(container.with_value(it))?;
179 VariantId::from(def).into() 171 VariantId::from(def).into()
180 }, 172 },
181 ast::EnumDef(it) => { 173 ast::Enum(it) => {
182 let def = self.enum_to_def(container.with_value(it))?; 174 let def = self.enum_to_def(container.with_value(it))?;
183 def.into() 175 def.into()
184 }, 176 },
185 ast::UnionDef(it) => { 177 ast::Union(it) => {
186 let def = self.union_to_def(container.with_value(it))?; 178 let def = self.union_to_def(container.with_value(it))?;
187 VariantId::from(def).into() 179 VariantId::from(def).into()
188 }, 180 },
189 ast::StaticDef(it) => { 181 ast::Static(it) => {
190 let def = self.static_to_def(container.with_value(it))?; 182 let def = self.static_to_def(container.with_value(it))?;
191 DefWithBodyId::from(def).into() 183 DefWithBodyId::from(def).into()
192 }, 184 },
193 ast::ConstDef(it) => { 185 ast::Const(it) => {
194 let def = self.const_to_def(container.with_value(it))?; 186 let def = self.const_to_def(container.with_value(it))?;
195 DefWithBodyId::from(def).into() 187 DefWithBodyId::from(def).into()
196 }, 188 },
189 ast::TypeAlias(it) => {
190 let def = self.type_alias_to_def(container.with_value(it))?;
191 def.into()
192 },
197 _ => continue, 193 _ => continue,
198 } 194 }
199 }; 195 };
@@ -208,12 +204,12 @@ impl SourceToDefCtx<'_, '_> {
208 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 204 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
209 let res: GenericDefId = match_ast! { 205 let res: GenericDefId = match_ast! {
210 match (container.value) { 206 match (container.value) {
211 ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(), 207 ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
212 ast::StructDef(it) => self.struct_to_def(container.with_value(it))?.into(), 208 ast::Struct(it) => self.struct_to_def(container.with_value(it))?.into(),
213 ast::EnumDef(it) => self.enum_to_def(container.with_value(it))?.into(), 209 ast::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
214 ast::TraitDef(it) => self.trait_to_def(container.with_value(it))?.into(), 210 ast::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
215 ast::TypeAliasDef(it) => self.type_alias_to_def(container.with_value(it))?.into(), 211 ast::TypeAlias(it) => self.type_alias_to_def(container.with_value(it))?.into(),
216 ast::ImplDef(it) => self.impl_to_def(container.with_value(it))?.into(), 212 ast::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
217 _ => continue, 213 _ => continue,
218 } 214 }
219 }; 215 };
@@ -226,9 +222,9 @@ impl SourceToDefCtx<'_, '_> {
226 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 222 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
227 let res: DefWithBodyId = match_ast! { 223 let res: DefWithBodyId = match_ast! {
228 match (container.value) { 224 match (container.value) {
229 ast::ConstDef(it) => self.const_to_def(container.with_value(it))?.into(), 225 ast::Const(it) => self.const_to_def(container.with_value(it))?.into(),
230 ast::StaticDef(it) => self.static_to_def(container.with_value(it))?.into(), 226 ast::Static(it) => self.static_to_def(container.with_value(it))?.into(),
231 ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(), 227 ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
232 _ => continue, 228 _ => continue,
233 } 229 }
234 }; 230 };
@@ -246,19 +242,21 @@ pub(crate) enum ChildContainer {
246 ImplId(ImplId), 242 ImplId(ImplId),
247 EnumId(EnumId), 243 EnumId(EnumId),
248 VariantId(VariantId), 244 VariantId(VariantId),
245 TypeAliasId(TypeAliasId),
249 /// XXX: this might be the same def as, for example an `EnumId`. However, 246 /// XXX: this might be the same def as, for example an `EnumId`. However,
250 /// here the children generic parameters, and not, eg enum variants. 247 /// here the children generic parameters, and not, eg enum variants.
251 GenericDefId(GenericDefId), 248 GenericDefId(GenericDefId),
252} 249}
253impl_froms! { 250impl_from! {
254 ChildContainer:
255 DefWithBodyId, 251 DefWithBodyId,
256 ModuleId, 252 ModuleId,
257 TraitId, 253 TraitId,
258 ImplId, 254 ImplId,
259 EnumId, 255 EnumId,
260 VariantId, 256 VariantId,
257 TypeAliasId,
261 GenericDefId 258 GenericDefId
259 for ChildContainer
262} 260}
263 261
264impl ChildContainer { 262impl ChildContainer {
@@ -271,6 +269,7 @@ impl ChildContainer {
271 ChildContainer::ImplId(it) => it.child_by_source(db), 269 ChildContainer::ImplId(it) => it.child_by_source(db),
272 ChildContainer::EnumId(it) => it.child_by_source(db), 270 ChildContainer::EnumId(it) => it.child_by_source(db),
273 ChildContainer::VariantId(it) => it.child_by_source(db), 271 ChildContainer::VariantId(it) => it.child_by_source(db),
272 ChildContainer::TypeAliasId(_) => DynMap::default(),
274 ChildContainer::GenericDefId(it) => it.child_by_source(db), 273 ChildContainer::GenericDefId(it) => it.child_by_source(db),
275 } 274 }
276 } 275 }
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 1d6c47103..f2e630ef1 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -14,11 +14,11 @@ use hir_def::{
14 }, 14 },
15 expr::{ExprId, Pat, PatId}, 15 expr::{ExprId, Pat, PatId},
16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, 16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
17 AsMacroCall, DefWithBodyId, FieldId, LocalFieldId, VariantId, 17 AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId,
18}; 18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::{ 20use hir_ty::{
21 expr::{record_literal_missing_fields, record_pattern_missing_fields}, 21 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
22 InferenceResult, Substs, Ty, 22 InferenceResult, Substs, Ty,
23}; 23};
24use ra_syntax::{ 24use ra_syntax::{
@@ -115,7 +115,7 @@ impl SourceAnalyzer {
115 Some(res) 115 Some(res)
116 } 116 }
117 117
118 pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { 118 pub(crate) fn type_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> {
119 let expr_id = self.expr_id(db, expr)?; 119 let expr_id = self.expr_id(db, expr)?;
120 let ty = self.infer.as_ref()?[expr_id].clone(); 120 let ty = self.infer.as_ref()?[expr_id].clone();
121 Type::new_with_resolver(db, &self.resolver, ty) 121 Type::new_with_resolver(db, &self.resolver, ty)
@@ -127,13 +127,24 @@ impl SourceAnalyzer {
127 Type::new_with_resolver(db, &self.resolver, ty) 127 Type::new_with_resolver(db, &self.resolver, ty)
128 } 128 }
129 129
130 pub(crate) fn type_of_self(
131 &self,
132 db: &dyn HirDatabase,
133 param: &ast::SelfParam,
134 ) -> Option<Type> {
135 let src = InFile { file_id: self.file_id, value: param };
136 let pat_id = self.body_source_map.as_ref()?.node_self_param(src)?;
137 let ty = self.infer.as_ref()?[pat_id].clone();
138 Type::new_with_resolver(db, &self.resolver, ty)
139 }
140
130 pub(crate) fn resolve_method_call( 141 pub(crate) fn resolve_method_call(
131 &self, 142 &self,
132 db: &dyn HirDatabase, 143 db: &dyn HirDatabase,
133 call: &ast::MethodCallExpr, 144 call: &ast::MethodCallExpr,
134 ) -> Option<Function> { 145 ) -> Option<FunctionId> {
135 let expr_id = self.expr_id(db, &call.clone().into())?; 146 let expr_id = self.expr_id(db, &call.clone().into())?;
136 self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) 147 self.infer.as_ref()?.method_resolution(expr_id)
137 } 148 }
138 149
139 pub(crate) fn resolve_field( 150 pub(crate) fn resolve_field(
@@ -148,7 +159,7 @@ impl SourceAnalyzer {
148 pub(crate) fn resolve_record_field( 159 pub(crate) fn resolve_record_field(
149 &self, 160 &self,
150 db: &dyn HirDatabase, 161 db: &dyn HirDatabase,
151 field: &ast::RecordField, 162 field: &ast::RecordExprField,
152 ) -> Option<(Field, Option<Local>)> { 163 ) -> Option<(Field, Option<Local>)> {
153 let expr = field.expr()?; 164 let expr = field.expr()?;
154 let expr_id = self.expr_id(db, &expr)?; 165 let expr_id = self.expr_id(db, &expr)?;
@@ -235,7 +246,7 @@ impl SourceAnalyzer {
235 } 246 }
236 } 247 }
237 248
238 if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordLit::cast) { 249 if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordExpr::cast) {
239 let expr_id = self.expr_id(db, &rec_lit.into())?; 250 let expr_id = self.expr_id(db, &rec_lit.into())?;
240 if let Some(VariantId::EnumVariantId(variant)) = 251 if let Some(VariantId::EnumVariantId(variant)) =
241 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 252 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
@@ -273,7 +284,7 @@ impl SourceAnalyzer {
273 pub(crate) fn record_literal_missing_fields( 284 pub(crate) fn record_literal_missing_fields(
274 &self, 285 &self,
275 db: &dyn HirDatabase, 286 db: &dyn HirDatabase,
276 literal: &ast::RecordLit, 287 literal: &ast::RecordExpr,
277 ) -> Option<Vec<(Field, Type)>> { 288 ) -> Option<Vec<(Field, Type)>> {
278 let krate = self.resolver.krate()?; 289 let krate = self.resolver.krate()?;
279 let body = self.body.as_ref()?; 290 let body = self.body.as_ref()?;
@@ -341,13 +352,13 @@ impl SourceAnalyzer {
341 let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { 352 let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
342 self.resolver.resolve_path_as_macro(db.upcast(), &path) 353 self.resolver.resolve_path_as_macro(db.upcast(), &path)
343 })?; 354 })?;
344 Some(macro_call_id.as_file()) 355 Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
345 } 356 }
346 357
347 pub(crate) fn resolve_variant( 358 pub(crate) fn resolve_variant(
348 &self, 359 &self,
349 db: &dyn HirDatabase, 360 db: &dyn HirDatabase,
350 record_lit: ast::RecordLit, 361 record_lit: ast::RecordExpr,
351 ) -> Option<VariantId> { 362 ) -> Option<VariantId> {
352 let infer = self.infer.as_ref()?; 363 let infer = self.infer.as_ref()?;
353 let expr_id = self.expr_id(db, &record_lit.into())?; 364 let expr_id = self.expr_id(db, &record_lit.into())?;
@@ -394,8 +405,7 @@ fn scope_for_offset(
394 ) 405 )
395 }) 406 })
396 .map(|(expr_range, scope)| { 407 .map(|(expr_range, scope)| {
397 adjust(db, scopes, source_map, expr_range, offset.file_id, offset.value) 408 adjust(db, scopes, source_map, expr_range, offset).unwrap_or(*scope)
398 .unwrap_or(*scope)
399 }) 409 })
400} 410}
401 411
@@ -406,8 +416,7 @@ fn adjust(
406 scopes: &ExprScopes, 416 scopes: &ExprScopes,
407 source_map: &BodySourceMap, 417 source_map: &BodySourceMap,
408 expr_range: TextRange, 418 expr_range: TextRange,
409 file_id: HirFileId, 419 offset: InFile<TextSize>,
410 offset: TextSize,
411) -> Option<ScopeId> { 420) -> Option<ScopeId> {
412 let child_scopes = scopes 421 let child_scopes = scopes
413 .scope_by_expr() 422 .scope_by_expr()
@@ -415,7 +424,7 @@ fn adjust(
415 .filter_map(|(id, scope)| { 424 .filter_map(|(id, scope)| {
416 let source = source_map.expr_syntax(*id).ok()?; 425 let source = source_map.expr_syntax(*id).ok()?;
417 // FIXME: correctly handle macro expansion 426 // FIXME: correctly handle macro expansion
418 if source.file_id != file_id { 427 if source.file_id != offset.file_id {
419 return None; 428 return None;
420 } 429 }
421 let root = source.file_syntax(db.upcast()); 430 let root = source.file_syntax(db.upcast());
@@ -423,7 +432,7 @@ fn adjust(
423 Some((node.syntax().text_range(), scope)) 432 Some((node.syntax().text_range(), scope))
424 }) 433 })
425 .filter(|&(range, _)| { 434 .filter(|&(range, _)| {
426 range.start() <= offset && expr_range.contains_range(range) && range != expr_range 435 range.start() <= offset.value && expr_range.contains_range(range) && range != expr_range
427 }); 436 });
428 437
429 child_scopes 438 child_scopes
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 6d43924e3..d96a86b80 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir_def" 3name = "ra_hir_def"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -32,4 +33,4 @@ ra_cfg = { path = "../ra_cfg" }
32tt = { path = "../ra_tt", package = "ra_tt" } 33tt = { path = "../ra_tt", package = "ra_tt" }
33 34
34[dev-dependencies] 35[dev-dependencies]
35insta = "0.16.0" 36expect = { path = "../expect" }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 4994a2125..6cb56a1cd 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -8,7 +8,7 @@ use hir_expand::{
8 InFile, 8 InFile,
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 11use ra_syntax::ast::{self, NameOwner, VisibilityOwner};
12 12
13use crate::{ 13use crate::{
14 body::{CfgExpander, LowerCtx}, 14 body::{CfgExpander, LowerCtx},
@@ -112,7 +112,7 @@ impl EnumData {
112 112
113impl HasChildSource for EnumId { 113impl HasChildSource for EnumId {
114 type ChildId = LocalEnumVariantId; 114 type ChildId = LocalEnumVariantId;
115 type Value = ast::EnumVariant; 115 type Value = ast::Variant;
116 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 116 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
117 let src = self.lookup(db).source(db); 117 let src = self.lookup(db).source(db);
118 let mut trace = Trace::new_for_map(); 118 let mut trace = Trace::new_for_map();
@@ -123,8 +123,8 @@ impl HasChildSource for EnumId {
123 123
124fn lower_enum( 124fn lower_enum(
125 db: &dyn DefDatabase, 125 db: &dyn DefDatabase,
126 trace: &mut Trace<EnumVariantData, ast::EnumVariant>, 126 trace: &mut Trace<EnumVariantData, ast::Variant>,
127 ast: &InFile<ast::EnumDef>, 127 ast: &InFile<ast::Enum>,
128 module_id: ModuleId, 128 module_id: ModuleId,
129) { 129) {
130 let expander = CfgExpander::new(db, ast.file_id, module_id.krate); 130 let expander = CfgExpander::new(db, ast.file_id, module_id.krate);
@@ -179,7 +179,7 @@ impl VariantData {
179 179
180impl HasChildSource for VariantId { 180impl HasChildSource for VariantId {
181 type ChildId = LocalFieldId; 181 type ChildId = LocalFieldId;
182 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; 182 type Value = Either<ast::TupleField, ast::RecordField>;
183 183
184 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 184 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
185 let (src, module_id) = match self { 185 let (src, module_id) = match self {
@@ -194,7 +194,7 @@ impl HasChildSource for VariantId {
194 } 194 }
195 VariantId::UnionId(it) => ( 195 VariantId::UnionId(it) => (
196 it.lookup(db).source(db).map(|it| { 196 it.lookup(db).source(db).map(|it| {
197 it.record_field_def_list() 197 it.record_field_list()
198 .map(ast::StructKind::Record) 198 .map(ast::StructKind::Record)
199 .unwrap_or(ast::StructKind::Unit) 199 .unwrap_or(ast::StructKind::Unit)
200 }), 200 }),
@@ -218,7 +218,7 @@ pub enum StructKind {
218fn lower_struct( 218fn lower_struct(
219 db: &dyn DefDatabase, 219 db: &dyn DefDatabase,
220 expander: &mut CfgExpander, 220 expander: &mut CfgExpander,
221 trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, 221 trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>,
222 ast: &InFile<ast::StructKind>, 222 ast: &InFile<ast::StructKind>,
223) -> StructKind { 223) -> StructKind {
224 let ctx = LowerCtx::new(db, ast.file_id); 224 let ctx = LowerCtx::new(db, ast.file_id);
@@ -234,7 +234,7 @@ fn lower_struct(
234 || Either::Left(fd.clone()), 234 || Either::Left(fd.clone()),
235 || FieldData { 235 || FieldData {
236 name: Name::new_tuple_field(i), 236 name: Name::new_tuple_field(i),
237 type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()), 237 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
238 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 238 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
239 }, 239 },
240 ); 240 );
@@ -251,7 +251,7 @@ fn lower_struct(
251 || Either::Right(fd.clone()), 251 || Either::Right(fd.clone()),
252 || FieldData { 252 || FieldData {
253 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 253 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
254 type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()), 254 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
255 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 255 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
256 }, 256 },
257 ); 257 );
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index e228e2145..050832ce0 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -5,7 +5,7 @@ use std::{ops, sync::Arc};
5use either::Either; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile}; 6use hir_expand::{hygiene::Hygiene, AstId, InFile};
7use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
8use ra_cfg::CfgOptions; 8use ra_cfg::{CfgExpr, CfgOptions};
9use ra_syntax::{ 9use ra_syntax::{
10 ast::{self, AstNode, AttrsOwner}, 10 ast::{self, AstNode, AttrsOwner},
11 SmolStr, 11 SmolStr,
@@ -125,9 +125,12 @@ impl Attrs {
125 AttrQuery { attrs: self, key } 125 AttrQuery { attrs: self, key }
126 } 126 }
127 127
128 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { 128 pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ {
129 // FIXME: handle cfg_attr :-) 129 // FIXME: handle cfg_attr :-)
130 self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) 130 self.by_key("cfg").tt_values().map(CfgExpr::parse)
131 }
132 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
133 self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false))
131 } 134 }
132} 135}
133 136
@@ -148,18 +151,15 @@ pub enum AttrInput {
148impl Attr { 151impl Attr {
149 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 152 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
150 let path = ModPath::from_src(ast.path()?, hygiene)?; 153 let path = ModPath::from_src(ast.path()?, hygiene)?;
151 let input = match ast.input() { 154 let input = if let Some(lit) = ast.literal() {
152 None => None, 155 // FIXME: escape? raw string?
153 Some(ast::AttrInput::Literal(lit)) => { 156 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
154 // FIXME: escape? raw string? 157 Some(AttrInput::Literal(value))
155 let value = lit.syntax().first_token()?.text().trim_matches('"').into(); 158 } else if let Some(tt) = ast.token_tree() {
156 Some(AttrInput::Literal(value)) 159 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
157 } 160 } else {
158 Some(ast::AttrInput::TokenTree(tt)) => { 161 None
159 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
160 }
161 }; 162 };
162
163 Some(Attr { path, input }) 163 Some(Attr { path, input })
164 } 164 }
165} 165}
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 4f2350915..d5f18b920 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -14,6 +14,7 @@ use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
16use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
17use test_utils::mark;
17 18
18pub(crate) use lower::LowerCtx; 19pub(crate) use lower::LowerCtx;
19 20
@@ -42,9 +43,15 @@ pub(crate) struct Expander {
42 current_file_id: HirFileId, 43 current_file_id: HirFileId,
43 ast_id_map: Arc<AstIdMap>, 44 ast_id_map: Arc<AstIdMap>,
44 module: ModuleId, 45 module: ModuleId,
45 recursive_limit: usize, 46 recursion_limit: usize,
46} 47}
47 48
49#[cfg(test)]
50const EXPANSION_RECURSION_LIMIT: usize = 32;
51
52#[cfg(not(test))]
53const EXPANSION_RECURSION_LIMIT: usize = 128;
54
48impl CfgExpander { 55impl CfgExpander {
49 pub(crate) fn new( 56 pub(crate) fn new(
50 db: &dyn DefDatabase, 57 db: &dyn DefDatabase,
@@ -81,7 +88,7 @@ impl Expander {
81 current_file_id, 88 current_file_id,
82 ast_id_map, 89 ast_id_map,
83 module, 90 module,
84 recursive_limit: 0, 91 recursion_limit: 0,
85 } 92 }
86 } 93 }
87 94
@@ -91,7 +98,9 @@ impl Expander {
91 local_scope: Option<&ItemScope>, 98 local_scope: Option<&ItemScope>,
92 macro_call: ast::MacroCall, 99 macro_call: ast::MacroCall,
93 ) -> Option<(Mark, T)> { 100 ) -> Option<(Mark, T)> {
94 if self.recursive_limit > 1024 { 101 self.recursion_limit += 1;
102 if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
103 mark::hit!(your_stack_belongs_to_me);
95 return None; 104 return None;
96 } 105 }
97 106
@@ -118,8 +127,6 @@ impl Expander {
118 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); 127 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
119 self.current_file_id = file_id; 128 self.current_file_id = file_id;
120 self.ast_id_map = db.ast_id_map(file_id); 129 self.ast_id_map = db.ast_id_map(file_id);
121 self.recursive_limit += 1;
122
123 return Some((mark, expr)); 130 return Some((mark, expr));
124 } 131 }
125 } 132 }
@@ -134,7 +141,7 @@ impl Expander {
134 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 141 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
135 self.current_file_id = mark.file_id; 142 self.current_file_id = mark.file_id;
136 self.ast_id_map = mem::take(&mut mark.ast_id_map); 143 self.ast_id_map = mem::take(&mut mark.ast_id_map);
137 self.recursive_limit -= 1; 144 self.recursion_limit -= 1;
138 mark.bomb.defuse(); 145 mark.bomb.defuse();
139 } 146 }
140 147
@@ -209,7 +216,7 @@ pub struct BodySourceMap {
209 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, 216 expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
210 pat_map: FxHashMap<PatSource, PatId>, 217 pat_map: FxHashMap<PatSource, PatId>,
211 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, 218 pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
212 field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>, 219 field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>,
213 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, 220 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
214} 221}
215 222
@@ -302,7 +309,53 @@ impl BodySourceMap {
302 self.pat_map.get(&src).cloned() 309 self.pat_map.get(&src).cloned()
303 } 310 }
304 311
305 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { 312 pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
313 let src = node.map(|it| Either::Right(AstPtr::new(it)));
314 self.pat_map.get(&src).cloned()
315 }
316
317 pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> {
306 self.field_map[&(expr, field)].clone() 318 self.field_map[&(expr, field)].clone()
307 } 319 }
308} 320}
321
322#[cfg(test)]
323mod tests {
324 use ra_db::{fixture::WithFixture, SourceDatabase};
325 use test_utils::mark;
326
327 use crate::ModuleDefId;
328
329 use super::*;
330
331 fn lower(ra_fixture: &str) -> Arc<Body> {
332 let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);
333
334 let krate = db.crate_graph().iter().next().unwrap();
335 let def_map = db.crate_def_map(krate);
336 let module = def_map.modules_for_file(file_id).next().unwrap();
337 let module = &def_map[module];
338 let fn_def = match module.scope.declarations().next().unwrap() {
339 ModuleDefId::FunctionId(it) => it,
340 _ => panic!(),
341 };
342
343 db.body(fn_def.into())
344 }
345
346 #[test]
347 fn your_stack_belongs_to_me() {
348 mark::check!(your_stack_belongs_to_me);
349 lower(
350 "
351macro_rules! n_nuple {
352 ($e:tt) => ();
353 ($($rest:tt)*) => {{
354 (n_nuple!($($rest)*)None,)
355 }};
356}
357fn main() { n_nuple!(1,2,3); }
358",
359 );
360 }
361}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index c6bc85e2f..827ced4ad 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -11,7 +11,7 @@ use ra_arena::Arena;
11use ra_syntax::{ 11use ra_syntax::{
12 ast::{ 12 ast::{
13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, 13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
14 SlicePatComponents, TypeAscriptionOwner, 14 SlicePatComponents,
15 }, 15 },
16 AstNode, AstPtr, 16 AstNode, AstPtr,
17}; 17};
@@ -379,10 +379,10 @@ impl ExprCollector<'_> {
379 let expr = e.expr().map(|e| self.collect_expr(e)); 379 let expr = e.expr().map(|e| self.collect_expr(e));
380 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 380 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
381 } 381 }
382 ast::Expr::RecordLit(e) => { 382 ast::Expr::RecordExpr(e) => {
383 let path = e.path().and_then(|path| self.expander.parse_path(path)); 383 let path = e.path().and_then(|path| self.expander.parse_path(path));
384 let mut field_ptrs = Vec::new(); 384 let mut field_ptrs = Vec::new();
385 let record_lit = if let Some(nfl) = e.record_field_list() { 385 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
386 let fields = nfl 386 let fields = nfl
387 .fields() 387 .fields()
388 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 388 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
@@ -432,7 +432,7 @@ impl ExprCollector<'_> {
432 } 432 }
433 ast::Expr::CastExpr(e) => { 433 ast::Expr::CastExpr(e) => {
434 let expr = self.collect_expr_opt(e.expr()); 434 let expr = self.collect_expr_opt(e.expr());
435 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref()); 435 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
436 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 436 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
437 } 437 }
438 ast::Expr::RefExpr(e) => { 438 ast::Expr::RefExpr(e) => {
@@ -466,16 +466,13 @@ impl ExprCollector<'_> {
466 if let Some(pl) = e.param_list() { 466 if let Some(pl) = e.param_list() {
467 for param in pl.params() { 467 for param in pl.params() {
468 let pat = self.collect_pat_opt(param.pat()); 468 let pat = self.collect_pat_opt(param.pat());
469 let type_ref = 469 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
470 param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
471 args.push(pat); 470 args.push(pat);
472 arg_types.push(type_ref); 471 arg_types.push(type_ref);
473 } 472 }
474 } 473 }
475 let ret_type = e 474 let ret_type =
476 .ret_type() 475 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it));
477 .and_then(|r| r.type_ref())
478 .map(|it| TypeRef::from_ast(&self.ctx(), it));
479 let body = self.collect_expr_opt(e.body()); 476 let body = self.collect_expr_opt(e.body());
480 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 477 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
481 } 478 }
@@ -607,8 +604,7 @@ impl ExprCollector<'_> {
607 .map(|s| match s { 604 .map(|s| match s {
608 ast::Stmt::LetStmt(stmt) => { 605 ast::Stmt::LetStmt(stmt) => {
609 let pat = self.collect_pat_opt(stmt.pat()); 606 let pat = self.collect_pat_opt(stmt.pat());
610 let type_ref = 607 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
611 stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
612 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 608 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
613 Statement::Let { pat, type_ref, initializer } 609 Statement::Let { pat, type_ref, initializer }
614 } 610 }
@@ -627,53 +623,53 @@ impl ExprCollector<'_> {
627 .items() 623 .items()
628 .filter_map(|item| { 624 .filter_map(|item| {
629 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 625 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
630 ast::ModuleItem::FnDef(def) => { 626 ast::Item::Fn(def) => {
631 let id = self.find_inner_item(&def)?; 627 let id = self.find_inner_item(&def)?;
632 ( 628 (
633 FunctionLoc { container: container.into(), id }.intern(self.db).into(), 629 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
634 def.name(), 630 def.name(),
635 ) 631 )
636 } 632 }
637 ast::ModuleItem::TypeAliasDef(def) => { 633 ast::Item::TypeAlias(def) => {
638 let id = self.find_inner_item(&def)?; 634 let id = self.find_inner_item(&def)?;
639 ( 635 (
640 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), 636 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
641 def.name(), 637 def.name(),
642 ) 638 )
643 } 639 }
644 ast::ModuleItem::ConstDef(def) => { 640 ast::Item::Const(def) => {
645 let id = self.find_inner_item(&def)?; 641 let id = self.find_inner_item(&def)?;
646 ( 642 (
647 ConstLoc { container: container.into(), id }.intern(self.db).into(), 643 ConstLoc { container: container.into(), id }.intern(self.db).into(),
648 def.name(), 644 def.name(),
649 ) 645 )
650 } 646 }
651 ast::ModuleItem::StaticDef(def) => { 647 ast::Item::Static(def) => {
652 let id = self.find_inner_item(&def)?; 648 let id = self.find_inner_item(&def)?;
653 (StaticLoc { container, id }.intern(self.db).into(), def.name()) 649 (StaticLoc { container, id }.intern(self.db).into(), def.name())
654 } 650 }
655 ast::ModuleItem::StructDef(def) => { 651 ast::Item::Struct(def) => {
656 let id = self.find_inner_item(&def)?; 652 let id = self.find_inner_item(&def)?;
657 (StructLoc { container, id }.intern(self.db).into(), def.name()) 653 (StructLoc { container, id }.intern(self.db).into(), def.name())
658 } 654 }
659 ast::ModuleItem::EnumDef(def) => { 655 ast::Item::Enum(def) => {
660 let id = self.find_inner_item(&def)?; 656 let id = self.find_inner_item(&def)?;
661 (EnumLoc { container, id }.intern(self.db).into(), def.name()) 657 (EnumLoc { container, id }.intern(self.db).into(), def.name())
662 } 658 }
663 ast::ModuleItem::UnionDef(def) => { 659 ast::Item::Union(def) => {
664 let id = self.find_inner_item(&def)?; 660 let id = self.find_inner_item(&def)?;
665 (UnionLoc { container, id }.intern(self.db).into(), def.name()) 661 (UnionLoc { container, id }.intern(self.db).into(), def.name())
666 } 662 }
667 ast::ModuleItem::TraitDef(def) => { 663 ast::Item::Trait(def) => {
668 let id = self.find_inner_item(&def)?; 664 let id = self.find_inner_item(&def)?;
669 (TraitLoc { container, id }.intern(self.db).into(), def.name()) 665 (TraitLoc { container, id }.intern(self.db).into(), def.name())
670 } 666 }
671 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks 667 ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
672 ast::ModuleItem::ImplDef(_) 668 ast::Item::Impl(_)
673 | ast::ModuleItem::UseItem(_) 669 | ast::Item::Use(_)
674 | ast::ModuleItem::ExternCrateItem(_) 670 | ast::Item::ExternCrate(_)
675 | ast::ModuleItem::Module(_) 671 | ast::Item::Module(_)
676 | ast::ModuleItem::MacroCall(_) => return None, 672 | ast::Item::MacroCall(_) => return None,
677 }; 673 };
678 674
679 Some((def, name)) 675 Some((def, name))
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
index a885ec96d..dcb00a1d9 100644
--- a/crates/ra_hir_def/src/child_by_source.rs
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -162,7 +162,7 @@ impl ChildBySource for EnumId {
162 let arena_map = arena_map.as_ref(); 162 let arena_map = arena_map.as_ref();
163 for (local_id, source) in arena_map.value.iter() { 163 for (local_id, source) in arena_map.value.iter() {
164 let id = EnumVariantId { parent: *self, local_id }; 164 let id = EnumVariantId { parent: *self, local_id };
165 res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id) 165 res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
166 } 166 }
167 167
168 res 168 res
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 282ade2a3..88a8ef9bf 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -27,11 +27,12 @@ pub struct FunctionData {
27 /// can be called as a method. 27 /// can be called as a method.
28 pub has_self_param: bool, 28 pub has_self_param: bool,
29 pub is_unsafe: bool, 29 pub is_unsafe: bool,
30 pub is_varargs: bool,
30 pub visibility: RawVisibility, 31 pub visibility: RawVisibility,
31} 32}
32 33
33impl FunctionData { 34impl FunctionData {
34 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { 35 pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
35 let loc = func.lookup(db); 36 let loc = func.lookup(db);
36 let item_tree = db.item_tree(loc.id.file_id); 37 let item_tree = db.item_tree(loc.id.file_id);
37 let func = &item_tree[loc.id.value]; 38 let func = &item_tree[loc.id.value];
@@ -43,6 +44,7 @@ impl FunctionData {
43 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), 44 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
44 has_self_param: func.has_self_param, 45 has_self_param: func.has_self_param,
45 is_unsafe: func.is_unsafe, 46 is_unsafe: func.is_unsafe,
47 is_varargs: func.is_varargs,
46 visibility: item_tree[func.visibility].clone(), 48 visibility: item_tree[func.visibility].clone(),
47 }) 49 })
48 } 50 }
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 6a0f493a7..8ea61fcf2 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -12,7 +12,7 @@ use hir_expand::{
12use ra_arena::{map::ArenaMap, Arena}; 12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId; 13use ra_db::FileId;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 15use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
16 16
17use crate::{ 17use crate::{
18 body::LowerCtx, 18 body::LowerCtx,
@@ -66,7 +66,7 @@ pub enum WherePredicateTarget {
66 TypeParam(LocalTypeParamId), 66 TypeParam(LocalTypeParamId),
67} 67}
68 68
69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; 69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
70 70
71impl GenericParams { 71impl GenericParams {
72 pub(crate) fn generic_params_query( 72 pub(crate) fn generic_params_query(
@@ -205,9 +205,9 @@ impl GenericParams {
205 &mut self, 205 &mut self,
206 lower_ctx: &LowerCtx, 206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap, 207 sm: &mut SourceMap,
208 node: &dyn TypeParamsOwner, 208 node: &dyn GenericParamsOwner,
209 ) { 209 ) {
210 if let Some(params) = node.type_param_list() { 210 if let Some(params) = node.generic_param_list() {
211 self.fill_params(lower_ctx, sm, params) 211 self.fill_params(lower_ctx, sm, params)
212 } 212 }
213 if let Some(where_clause) = node.where_clause() { 213 if let Some(where_clause) = node.where_clause() {
@@ -232,7 +232,7 @@ impl GenericParams {
232 &mut self, 232 &mut self,
233 lower_ctx: &LowerCtx, 233 lower_ctx: &LowerCtx,
234 sm: &mut SourceMap, 234 sm: &mut SourceMap,
235 params: ast::TypeParamList, 235 params: ast::GenericParamList,
236 ) { 236 ) {
237 for type_param in params.type_params() { 237 for type_param in params.type_params() {
238 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 238 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
@@ -317,7 +317,7 @@ impl GenericParams {
317 317
318impl HasChildSource for GenericDefId { 318impl HasChildSource for GenericDefId {
319 type ChildId = LocalTypeParamId; 319 type ChildId = LocalTypeParamId;
320 type Value = Either<ast::TraitDef, ast::TypeParam>; 320 type Value = Either<ast::Trait, ast::TypeParam>;
321 fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> { 321 fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> {
322 let (_, sm) = GenericParams::new(db, *self); 322 let (_, sm) = GenericParams::new(db, *self);
323 sm 323 sm
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs
index 68e20d06b..9e4c30b1a 100644
--- a/crates/ra_hir_def/src/import_map.rs
+++ b/crates/ra_hir_def/src/import_map.rs
@@ -5,14 +5,16 @@ use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc};
5use fst::{self, Streamer}; 5use fst::{self, Streamer};
6use indexmap::{map::Entry, IndexMap}; 6use indexmap::{map::Entry, IndexMap};
7use ra_db::CrateId; 7use ra_db::CrateId;
8use rustc_hash::FxHasher; 8use ra_syntax::SmolStr;
9use rustc_hash::{FxHashMap, FxHasher};
10use smallvec::SmallVec;
9 11
10use crate::{ 12use crate::{
11 db::DefDatabase, 13 db::DefDatabase,
12 item_scope::ItemInNs, 14 item_scope::ItemInNs,
13 path::{ModPath, PathKind}, 15 path::{ModPath, PathKind},
14 visibility::Visibility, 16 visibility::Visibility,
15 ModuleDefId, ModuleId, 17 AssocItemId, ModuleDefId, ModuleId, TraitId,
16}; 18};
17 19
18type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; 20type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
@@ -34,6 +36,7 @@ pub struct ImportInfo {
34/// 36///
35/// Note that all paths are relative to the containing crate's root, so the crate name still needs 37/// Note that all paths are relative to the containing crate's root, so the crate name still needs
36/// to be prepended to the `ModPath` before the path is valid. 38/// to be prepended to the `ModPath` before the path is valid.
39#[derive(Default)]
37pub struct ImportMap { 40pub struct ImportMap {
38 map: FxIndexMap<ItemInNs, ImportInfo>, 41 map: FxIndexMap<ItemInNs, ImportInfo>,
39 42
@@ -45,13 +48,17 @@ pub struct ImportMap {
45 /// the index of the first one. 48 /// the index of the first one.
46 importables: Vec<ItemInNs>, 49 importables: Vec<ItemInNs>,
47 fst: fst::Map<Vec<u8>>, 50 fst: fst::Map<Vec<u8>>,
51
52 /// Maps names of associated items to the item's ID. Only includes items whose defining trait is
53 /// exported.
54 assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>,
48} 55}
49 56
50impl ImportMap { 57impl ImportMap {
51 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 58 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
52 let _p = ra_prof::profile("import_map_query"); 59 let _p = ra_prof::profile("import_map_query");
53 let def_map = db.crate_def_map(krate); 60 let def_map = db.crate_def_map(krate);
54 let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); 61 let mut import_map = Self::default();
55 62
56 // We look only into modules that are public(ly reexported), starting with the crate root. 63 // We look only into modules that are public(ly reexported), starting with the crate root.
57 let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; 64 let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
@@ -85,7 +92,7 @@ impl ImportMap {
85 92
86 for item in per_ns.iter_items() { 93 for item in per_ns.iter_items() {
87 let path = mk_path(); 94 let path = mk_path();
88 match import_map.entry(item) { 95 match import_map.map.entry(item) {
89 Entry::Vacant(entry) => { 96 Entry::Vacant(entry) => {
90 entry.insert(ImportInfo { path, container: module }); 97 entry.insert(ImportInfo { path, container: module });
91 } 98 }
@@ -105,11 +112,16 @@ impl ImportMap {
105 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { 112 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
106 worklist.push((mod_id, mk_path())); 113 worklist.push((mod_id, mk_path()));
107 } 114 }
115
116 // If we've added a path to a trait, add the trait's methods to the method map.
117 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
118 import_map.collect_trait_methods(db, tr);
119 }
108 } 120 }
109 } 121 }
110 } 122 }
111 123
112 let mut importables = import_map.iter().collect::<Vec<_>>(); 124 let mut importables = import_map.map.iter().collect::<Vec<_>>();
113 125
114 importables.sort_by(cmp); 126 importables.sort_by(cmp);
115 127
@@ -133,10 +145,10 @@ impl ImportMap {
133 builder.insert(key, start as u64).unwrap(); 145 builder.insert(key, start as u64).unwrap();
134 } 146 }
135 147
136 let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); 148 import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap();
137 let importables = importables.iter().map(|(item, _)| **item).collect(); 149 import_map.importables = importables.iter().map(|(item, _)| **item).collect();
138 150
139 Arc::new(Self { map: import_map, fst, importables }) 151 Arc::new(import_map)
140 } 152 }
141 153
142 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. 154 /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
@@ -147,6 +159,13 @@ impl ImportMap {
147 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { 159 pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> {
148 self.map.get(&item) 160 self.map.get(&item)
149 } 161 }
162
163 fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) {
164 let data = db.trait_data(tr);
165 for (name, item) in data.items.iter() {
166 self.assoc_map.entry(name.to_string().into()).or_default().push(*item);
167 }
168 }
150} 169}
151 170
152impl PartialEq for ImportMap { 171impl PartialEq for ImportMap {
@@ -290,37 +309,32 @@ pub fn search_dependencies<'a>(
290 } 309 }
291 } 310 }
292 311
312 // Add all exported associated items whose names match the query (exactly).
313 for map in &import_maps {
314 if let Some(v) = map.assoc_map.get(&*query.query) {
315 res.extend(v.iter().map(|&assoc| {
316 ItemInNs::Types(match assoc {
317 AssocItemId::FunctionId(it) => it.into(),
318 AssocItemId::ConstId(it) => it.into(),
319 AssocItemId::TypeAliasId(it) => it.into(),
320 })
321 }));
322 }
323 }
324
293 res 325 res
294} 326}
295 327
296#[cfg(test)] 328#[cfg(test)]
297mod tests { 329mod tests {
298 use super::*; 330 use expect::{expect, Expect};
299 use crate::test_db::TestDB; 331 use ra_db::{fixture::WithFixture, SourceDatabase, Upcast};
300 use insta::assert_snapshot;
301 use itertools::Itertools;
302 use ra_db::fixture::WithFixture;
303 use ra_db::{SourceDatabase, Upcast};
304 332
305 fn import_map(ra_fixture: &str) -> String { 333 use crate::{test_db::TestDB, AssocContainerId, Lookup};
306 let db = TestDB::with_files(ra_fixture);
307 let crate_graph = db.crate_graph();
308 334
309 let s = crate_graph 335 use super::*;
310 .iter()
311 .filter_map(|krate| {
312 let cdata = &crate_graph[krate];
313 let name = cdata.display_name.as_ref()?;
314
315 let map = db.import_map(krate);
316
317 Some(format!("{}:\n{:?}", name, map))
318 })
319 .join("\n");
320 s
321 }
322 336
323 fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { 337 fn check_search(ra_fixture: &str, krate_name: &str, query: Query, expect: Expect) {
324 let db = TestDB::with_files(ra_fixture); 338 let db = TestDB::with_files(ra_fixture);
325 let crate_graph = db.crate_graph(); 339 let crate_graph = db.crate_graph();
326 let krate = crate_graph 340 let krate = crate_graph
@@ -331,7 +345,7 @@ mod tests {
331 }) 345 })
332 .unwrap(); 346 .unwrap();
333 347
334 search_dependencies(db.upcast(), krate, query) 348 let actual = search_dependencies(db.upcast(), krate, query)
335 .into_iter() 349 .into_iter()
336 .filter_map(|item| { 350 .filter_map(|item| {
337 let mark = match item { 351 let mark = match item {
@@ -339,23 +353,67 @@ mod tests {
339 ItemInNs::Values(_) => "v", 353 ItemInNs::Values(_) => "v",
340 ItemInNs::Macros(_) => "m", 354 ItemInNs::Macros(_) => "m",
341 }; 355 };
356 let item = assoc_to_trait(&db, item);
342 item.krate(db.upcast()).map(|krate| { 357 item.krate(db.upcast()).map(|krate| {
343 let map = db.import_map(krate); 358 let map = db.import_map(krate);
344 let path = map.path_of(item).unwrap(); 359 let path = map.path_of(item).unwrap();
345 format!( 360 format!(
346 "{}::{} ({})", 361 "{}::{} ({})\n",
347 crate_graph[krate].display_name.as_ref().unwrap(), 362 crate_graph[krate].display_name.as_ref().unwrap(),
348 path, 363 path,
349 mark 364 mark
350 ) 365 )
351 }) 366 })
352 }) 367 })
353 .join("\n") 368 .collect::<String>();
369 expect.assert_eq(&actual)
370 }
371
372 fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs {
373 let assoc: AssocItemId = match item {
374 ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
375 ModuleDefId::TypeAliasId(it) => it.into(),
376 ModuleDefId::FunctionId(it) => it.into(),
377 ModuleDefId::ConstId(it) => it.into(),
378 _ => return item,
379 },
380 _ => return item,
381 };
382
383 let container = match assoc {
384 AssocItemId::FunctionId(it) => it.lookup(db).container,
385 AssocItemId::ConstId(it) => it.lookup(db).container,
386 AssocItemId::TypeAliasId(it) => it.lookup(db).container,
387 };
388
389 match container {
390 AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()),
391 _ => item,
392 }
393 }
394
395 fn check(ra_fixture: &str, expect: Expect) {
396 let db = TestDB::with_files(ra_fixture);
397 let crate_graph = db.crate_graph();
398
399 let actual = crate_graph
400 .iter()
401 .filter_map(|krate| {
402 let cdata = &crate_graph[krate];
403 let name = cdata.display_name.as_ref()?;
404
405 let map = db.import_map(krate);
406
407 Some(format!("{}:\n{:?}\n", name, map))
408 })
409 .collect::<String>();
410
411 expect.assert_eq(&actual)
354 } 412 }
355 413
356 #[test] 414 #[test]
357 fn smoke() { 415 fn smoke() {
358 let map = import_map( 416 check(
359 r" 417 r"
360 //- /main.rs crate:main deps:lib 418 //- /main.rs crate:main deps:lib
361 419
@@ -380,24 +438,23 @@ mod tests {
380 pub struct Pub2; // t + v 438 pub struct Pub2; // t + v
381 struct Priv; 439 struct Priv;
382 ", 440 ",
441 expect![[r#"
442 main:
443 - publ1 (t)
444 - real_pu2 (t)
445 - real_pub (t)
446 - real_pub::Pub (t)
447 lib:
448 - Pub (t)
449 - Pub2 (t)
450 - Pub2 (v)
451 "#]],
383 ); 452 );
384
385 assert_snapshot!(map, @r###"
386 main:
387 - publ1 (t)
388 - real_pu2 (t)
389 - real_pub (t)
390 - real_pub::Pub (t)
391 lib:
392 - Pub (t)
393 - Pub2 (t)
394 - Pub2 (v)
395 "###);
396 } 453 }
397 454
398 #[test] 455 #[test]
399 fn prefers_shortest_path() { 456 fn prefers_shortest_path() {
400 let map = import_map( 457 check(
401 r" 458 r"
402 //- /main.rs crate:main 459 //- /main.rs crate:main
403 460
@@ -409,21 +466,20 @@ mod tests {
409 pub use super::sub::subsub::Def; 466 pub use super::sub::subsub::Def;
410 } 467 }
411 ", 468 ",
469 expect![[r#"
470 main:
471 - sub (t)
472 - sub::Def (t)
473 - sub::subsub (t)
474 "#]],
412 ); 475 );
413
414 assert_snapshot!(map, @r###"
415 main:
416 - sub (t)
417 - sub::Def (t)
418 - sub::subsub (t)
419 "###);
420 } 476 }
421 477
422 #[test] 478 #[test]
423 fn type_reexport_cross_crate() { 479 fn type_reexport_cross_crate() {
424 // Reexports need to be visible from a crate, even if the original crate exports the item 480 // Reexports need to be visible from a crate, even if the original crate exports the item
425 // at a shorter path. 481 // at a shorter path.
426 let map = import_map( 482 check(
427 r" 483 r"
428 //- /main.rs crate:main deps:lib 484 //- /main.rs crate:main deps:lib
429 pub mod m { 485 pub mod m {
@@ -432,22 +488,21 @@ mod tests {
432 //- /lib.rs crate:lib 488 //- /lib.rs crate:lib
433 pub struct S; 489 pub struct S;
434 ", 490 ",
491 expect![[r#"
492 main:
493 - m (t)
494 - m::S (t)
495 - m::S (v)
496 lib:
497 - S (t)
498 - S (v)
499 "#]],
435 ); 500 );
436
437 assert_snapshot!(map, @r###"
438 main:
439 - m (t)
440 - m::S (t)
441 - m::S (v)
442 lib:
443 - S (t)
444 - S (v)
445 "###);
446 } 501 }
447 502
448 #[test] 503 #[test]
449 fn macro_reexport() { 504 fn macro_reexport() {
450 let map = import_map( 505 check(
451 r" 506 r"
452 //- /main.rs crate:main deps:lib 507 //- /main.rs crate:main deps:lib
453 pub mod m { 508 pub mod m {
@@ -459,21 +514,20 @@ mod tests {
459 () => {}; 514 () => {};
460 } 515 }
461 ", 516 ",
517 expect![[r#"
518 main:
519 - m (t)
520 - m::pub_macro (m)
521 lib:
522 - pub_macro (m)
523 "#]],
462 ); 524 );
463
464 assert_snapshot!(map, @r###"
465 main:
466 - m (t)
467 - m::pub_macro (m)
468 lib:
469 - pub_macro (m)
470 "###);
471 } 525 }
472 526
473 #[test] 527 #[test]
474 fn module_reexport() { 528 fn module_reexport() {
475 // Reexporting modules from a dependency adds all contents to the import map. 529 // Reexporting modules from a dependency adds all contents to the import map.
476 let map = import_map( 530 check(
477 r" 531 r"
478 //- /main.rs crate:main deps:lib 532 //- /main.rs crate:main deps:lib
479 pub use lib::module as reexported_module; 533 pub use lib::module as reexported_module;
@@ -482,24 +536,23 @@ mod tests {
482 pub struct S; 536 pub struct S;
483 } 537 }
484 ", 538 ",
539 expect![[r#"
540 main:
541 - reexported_module (t)
542 - reexported_module::S (t)
543 - reexported_module::S (v)
544 lib:
545 - module (t)
546 - module::S (t)
547 - module::S (v)
548 "#]],
485 ); 549 );
486
487 assert_snapshot!(map, @r###"
488 main:
489 - reexported_module (t)
490 - reexported_module::S (t)
491 - reexported_module::S (v)
492 lib:
493 - module (t)
494 - module::S (t)
495 - module::S (v)
496 "###);
497 } 550 }
498 551
499 #[test] 552 #[test]
500 fn cyclic_module_reexport() { 553 fn cyclic_module_reexport() {
501 // A cyclic reexport does not hang. 554 // A cyclic reexport does not hang.
502 let map = import_map( 555 check(
503 r" 556 r"
504 //- /lib.rs crate:lib 557 //- /lib.rs crate:lib
505 pub mod module { 558 pub mod module {
@@ -511,36 +564,35 @@ mod tests {
511 pub use super::module; 564 pub use super::module;
512 } 565 }
513 ", 566 ",
567 expect![[r#"
568 lib:
569 - module (t)
570 - module::S (t)
571 - module::S (v)
572 - sub (t)
573 "#]],
514 ); 574 );
515
516 assert_snapshot!(map, @r###"
517 lib:
518 - module (t)
519 - module::S (t)
520 - module::S (v)
521 - sub (t)
522 "###);
523 } 575 }
524 576
525 #[test] 577 #[test]
526 fn private_macro() { 578 fn private_macro() {
527 let map = import_map( 579 check(
528 r" 580 r"
529 //- /lib.rs crate:lib 581 //- /lib.rs crate:lib
530 macro_rules! private_macro { 582 macro_rules! private_macro {
531 () => {}; 583 () => {};
532 } 584 }
533 ", 585 ",
534 ); 586 expect![[r#"
587 lib:
535 588
536 assert_snapshot!(map, @r###" 589 "#]],
537 lib: 590 );
538 "###);
539 } 591 }
540 592
541 #[test] 593 #[test]
542 fn namespacing() { 594 fn namespacing() {
543 let map = import_map( 595 check(
544 r" 596 r"
545 //- /lib.rs crate:lib 597 //- /lib.rs crate:lib
546 pub struct Thing; // t + v 598 pub struct Thing; // t + v
@@ -549,16 +601,15 @@ mod tests {
549 () => {}; 601 () => {};
550 } 602 }
551 ", 603 ",
604 expect![[r#"
605 lib:
606 - Thing (m)
607 - Thing (t)
608 - Thing (v)
609 "#]],
552 ); 610 );
553 611
554 assert_snapshot!(map, @r###" 612 check(
555 lib:
556 - Thing (m)
557 - Thing (t)
558 - Thing (v)
559 "###);
560
561 let map = import_map(
562 r" 613 r"
563 //- /lib.rs crate:lib 614 //- /lib.rs crate:lib
564 pub mod Thing {} // t 615 pub mod Thing {} // t
@@ -567,13 +618,12 @@ mod tests {
567 () => {}; 618 () => {};
568 } 619 }
569 ", 620 ",
621 expect![[r#"
622 lib:
623 - Thing (m)
624 - Thing (t)
625 "#]],
570 ); 626 );
571
572 assert_snapshot!(map, @r###"
573 lib:
574 - Thing (m)
575 - Thing (t)
576 "###);
577 } 627 }
578 628
579 #[test] 629 #[test]
@@ -602,23 +652,33 @@ mod tests {
602 } 652 }
603 "#; 653 "#;
604 654
605 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); 655 check_search(
606 assert_snapshot!(res, @r###" 656 ra_fixture,
607 dep::fmt (t) 657 "main",
608 dep::Fmt (t) 658 Query::new("fmt"),
609 dep::Fmt (v) 659 expect![[r#"
610 dep::Fmt (m) 660 dep::fmt (t)
611 dep::fmt::Display (t) 661 dep::Fmt (t)
612 dep::format (v) 662 dep::Fmt (v)
613 "###); 663 dep::Fmt (m)
614 664 dep::fmt::Display (t)
615 let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); 665 dep::format (v)
616 assert_snapshot!(res, @r###" 666 dep::fmt::Display (t)
617 dep::fmt (t) 667 "#]],
618 dep::Fmt (t) 668 );
619 dep::Fmt (v) 669
620 dep::Fmt (m) 670 check_search(
621 "###); 671 ra_fixture,
672 "main",
673 Query::new("fmt").anchor_end(),
674 expect![[r#"
675 dep::fmt (t)
676 dep::Fmt (t)
677 dep::Fmt (v)
678 dep::Fmt (m)
679 dep::fmt::Display (t)
680 "#]],
681 );
622 } 682 }
623 683
624 #[test] 684 #[test]
@@ -631,26 +691,32 @@ mod tests {
631 pub struct FMT; 691 pub struct FMT;
632 "#; 692 "#;
633 693
634 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); 694 check_search(
635 695 ra_fixture,
636 assert_snapshot!(res, @r###" 696 "main",
637 dep::fmt (t) 697 Query::new("FMT"),
638 dep::fmt (v) 698 expect![[r#"
639 dep::FMT (t) 699 dep::fmt (t)
640 dep::FMT (v) 700 dep::fmt (v)
641 "###); 701 dep::FMT (t)
642 702 dep::FMT (v)
643 let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); 703 "#]],
704 );
644 705
645 assert_snapshot!(res, @r###" 706 check_search(
646 dep::FMT (t) 707 ra_fixture,
647 dep::FMT (v) 708 "main",
648 "###); 709 Query::new("FMT").case_sensitive(),
710 expect![[r#"
711 dep::FMT (t)
712 dep::FMT (v)
713 "#]],
714 );
649 } 715 }
650 716
651 #[test] 717 #[test]
652 fn search_limit() { 718 fn search_limit() {
653 let res = search_dependencies_of( 719 check_search(
654 r#" 720 r#"
655 //- /main.rs crate:main deps:dep 721 //- /main.rs crate:main deps:dep
656 //- /dep.rs crate:dep 722 //- /dep.rs crate:dep
@@ -670,10 +736,10 @@ mod tests {
670 "#, 736 "#,
671 "main", 737 "main",
672 Query::new("").limit(2), 738 Query::new("").limit(2),
739 expect![[r#"
740 dep::fmt (t)
741 dep::Fmt (t)
742 "#]],
673 ); 743 );
674 assert_snapshot!(res, @r###"
675 dep::fmt (t)
676 dep::Fmt (t)
677 "###);
678 } 744 }
679} 745}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 4d446c707..8fee4b15e 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -1,6 +1,8 @@
1//! Describes items defined or visible (ie, imported) in a certain scope. 1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks. 2//! This is shared between modules and blocks.
3 3
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use ra_db::CrateId; 8use ra_db::CrateId;
@@ -27,9 +29,15 @@ pub struct PerNsGlobImports {
27 29
28#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
29pub struct ItemScope { 31pub struct ItemScope {
30 visible: FxHashMap<Name, PerNs>, 32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
31 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
32 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
33 /// Macros visible in current module in legacy textual scope 41 /// Macros visible in current module in legacy textual scope
34 /// 42 ///
35 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. 43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -65,14 +73,16 @@ pub(crate) enum BuiltinShadowMode {
65/// Other methods will only resolve values, types and module scoped macros only. 73/// Other methods will only resolve values, types and module scoped macros only.
66impl ItemScope { 74impl ItemScope {
67 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 75 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
68 //FIXME: shadowing 76 // FIXME: shadowing
69 self.visible.iter().map(|(n, def)| (n, *def)) 77 let keys: FxHashSet<_> = self
70 } 78 .types
71 79 .keys()
72 pub fn entries_without_primitives<'a>( 80 .chain(self.values.keys())
73 &'a self, 81 .chain(self.macros.keys())
74 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 82 .chain(self.unresolved.iter())
75 self.visible.iter().map(|(n, def)| (n, *def)) 83 .collect();
84
85 keys.into_iter().map(move |name| (name, self.get(name)))
76 } 86 }
77 87
78 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 88 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -91,7 +101,7 @@ impl ItemScope {
91 101
92 /// Iterate over all module scoped macros 102 /// Iterate over all module scoped macros
93 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 103 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
94 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 104 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
95 } 105 }
96 106
97 /// Iterate over all legacy textual scoped macros visible at the end of the module 107 /// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -101,12 +111,16 @@ impl ItemScope {
101 111
102 /// Get a name from current module scope, legacy macros are not included 112 /// Get a name from current module scope, legacy macros are not included
103 pub(crate) fn get(&self, name: &Name) -> PerNs { 113 pub(crate) fn get(&self, name: &Name) -> PerNs {
104 self.visible.get(name).copied().unwrap_or_else(PerNs::none) 114 PerNs {
115 types: self.types.get(name).copied(),
116 values: self.values.get(name).copied(),
117 macros: self.macros.get(name).copied(),
118 }
105 } 119 }
106 120
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 121 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108 for (name, per_ns) in &self.visible { 122 for (name, per_ns) in self.entries() {
109 if let Some(vis) = item.match_with(*per_ns) { 123 if let Some(vis) = item.match_with(per_ns) {
110 return Some((name, vis)); 124 return Some((name, vis));
111 } 125 }
112 } 126 }
@@ -114,10 +128,13 @@ impl ItemScope {
114 } 128 }
115 129
116 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
117 self.visible.values().filter_map(|def| match def.take_types() { 131 self.types
118 Some(ModuleDefId::TraitId(t)) => Some(t), 132 .values()
119 _ => None, 133 .filter_map(|(def, _)| match def {
120 }) 134 ModuleDefId::TraitId(t) => Some(*t),
135 _ => None,
136 })
137 .chain(self.unnamed_trait_imports.keys().copied())
121 } 138 }
122 139
123 pub(crate) fn define_def(&mut self, def: ModuleDefId) { 140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
@@ -136,23 +153,40 @@ impl ItemScope {
136 self.legacy_macros.insert(name, mac); 153 self.legacy_macros.insert(name, mac);
137 } 154 }
138 155
156 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157 self.unnamed_trait_imports.get(&tr).copied()
158 }
159
160 pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161 self.unnamed_trait_imports.insert(tr, vis);
162 }
163
139 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
140 let mut changed = false; 165 let mut changed = false;
141 let existing = self.visible.entry(name).or_default();
142 166
143 if existing.types.is_none() && def.types.is_some() { 167 if let Some(types) = def.types {
144 existing.types = def.types; 168 self.types.entry(name.clone()).or_insert_with(|| {
145 changed = true; 169 changed = true;
170 types
171 });
146 } 172 }
147 173 if let Some(values) = def.values {
148 if existing.values.is_none() && def.values.is_some() { 174 self.values.entry(name.clone()).or_insert_with(|| {
149 existing.values = def.values; 175 changed = true;
150 changed = true; 176 values
177 });
178 }
179 if let Some(macros) = def.macros {
180 self.macros.entry(name.clone()).or_insert_with(|| {
181 changed = true;
182 macros
183 });
151 } 184 }
152 185
153 if existing.macros.is_none() && def.macros.is_some() { 186 if def.is_none() {
154 existing.macros = def.macros; 187 if self.unresolved.insert(name) {
155 changed = true; 188 changed = true;
189 }
156 } 190 }
157 191
158 changed 192 changed
@@ -166,17 +200,17 @@ impl ItemScope {
166 def_import_type: ImportType, 200 def_import_type: ImportType,
167 ) -> bool { 201 ) -> bool {
168 let mut changed = false; 202 let mut changed = false;
169 let existing = self.visible.entry(lookup.1.clone()).or_default();
170 203
171 macro_rules! check_changed { 204 macro_rules! check_changed {
172 ( 205 (
173 $changed:ident, 206 $changed:ident,
174 ( $existing:ident / $def:ident ) . $field:ident, 207 ( $this:ident / $def:ident ) . $field:ident,
175 $glob_imports:ident [ $lookup:ident ], 208 $glob_imports:ident [ $lookup:ident ],
176 $def_import_type:ident 209 $def_import_type:ident
177 ) => { 210 ) => {{
178 match ($existing.$field, $def.$field) { 211 let existing = $this.$field.entry($lookup.1.clone());
179 (None, Some(_)) => { 212 match (existing, $def.$field) {
213 (Entry::Vacant(entry), Some(_)) => {
180 match $def_import_type { 214 match $def_import_type {
181 ImportType::Glob => { 215 ImportType::Glob => {
182 $glob_imports.$field.insert($lookup.clone()); 216 $glob_imports.$field.insert($lookup.clone());
@@ -186,32 +220,46 @@ impl ItemScope {
186 } 220 }
187 } 221 }
188 222
189 $existing.$field = $def.$field; 223 if let Some(fld) = $def.$field {
224 entry.insert(fld);
225 }
190 $changed = true; 226 $changed = true;
191 } 227 }
192 (Some(_), Some(_)) 228 (Entry::Occupied(mut entry), Some(_))
193 if $glob_imports.$field.contains(&$lookup) 229 if $glob_imports.$field.contains(&$lookup)
194 && matches!($def_import_type, ImportType::Named) => 230 && matches!($def_import_type, ImportType::Named) =>
195 { 231 {
196 mark::hit!(import_shadowed); 232 mark::hit!(import_shadowed);
197 $glob_imports.$field.remove(&$lookup); 233 $glob_imports.$field.remove(&$lookup);
198 $existing.$field = $def.$field; 234 if let Some(fld) = $def.$field {
235 entry.insert(fld);
236 }
199 $changed = true; 237 $changed = true;
200 } 238 }
201 _ => {} 239 _ => {}
202 } 240 }
203 }; 241 }};
204 } 242 }
205 243
206 check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); 244 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
207 check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); 245 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
208 check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); 246 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
247
248 if def.is_none() {
249 if self.unresolved.insert(lookup.1) {
250 changed = true;
251 }
252 }
209 253
210 changed 254 changed
211 } 255 }
212 256
213 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
214 self.visible.iter().map(|(name, res)| (name.clone(), *res)) 258 self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259 self.unnamed_trait_imports
260 .iter()
261 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
262 )
215 } 263 }
216 264
217 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index 3e603bd55..a67e75dac 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -13,7 +13,7 @@ use std::{
13 sync::Arc, 13 sync::Arc,
14}; 14};
15 15
16use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; 16use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
17use either::Either; 17use either::Either;
18use hir_expand::{ 18use hir_expand::{
19 ast_id_map::FileAstId, 19 ast_id_map::FileAstId,
@@ -70,7 +70,7 @@ impl GenericParamsId {
70pub struct ItemTree { 70pub struct ItemTree {
71 top_level: SmallVec<[ModItem; 1]>, 71 top_level: SmallVec<[ModItem; 1]>,
72 attrs: FxHashMap<AttrOwner, Attrs>, 72 attrs: FxHashMap<AttrOwner, Attrs>,
73 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>, 73 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
74 74
75 data: Option<Box<ItemTreeData>>, 75 data: Option<Box<ItemTreeData>>,
76} 76}
@@ -187,7 +187,7 @@ impl ItemTree {
187 /// 187 ///
188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered 188 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
189 /// to multiple items in the `ItemTree`. 189 /// to multiple items in the `ItemTree`.
190 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] { 190 pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
191 &self.inner_items[&ast] 191 &self.inner_items[&ast]
192 } 192 }
193 193
@@ -310,7 +310,7 @@ from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
310 310
311/// Trait implemented by all item nodes in the item tree. 311/// Trait implemented by all item nodes in the item tree.
312pub trait ItemTreeNode: Clone { 312pub trait ItemTreeNode: Clone {
313 type Source: AstNode + Into<ast::ModuleItem>; 313 type Source: AstNode + Into<ast::Item>;
314 314
315 fn ast_id(&self) -> FileAstId<Self::Source>; 315 fn ast_id(&self) -> FileAstId<Self::Source>;
316 316
@@ -411,17 +411,17 @@ macro_rules! mod_items {
411} 411}
412 412
413mod_items! { 413mod_items! {
414 Import in imports -> ast::UseItem, 414 Import in imports -> ast::Use,
415 ExternCrate in extern_crates -> ast::ExternCrateItem, 415 ExternCrate in extern_crates -> ast::ExternCrate,
416 Function in functions -> ast::FnDef, 416 Function in functions -> ast::Fn,
417 Struct in structs -> ast::StructDef, 417 Struct in structs -> ast::Struct,
418 Union in unions -> ast::UnionDef, 418 Union in unions -> ast::Union,
419 Enum in enums -> ast::EnumDef, 419 Enum in enums -> ast::Enum,
420 Const in consts -> ast::ConstDef, 420 Const in consts -> ast::Const,
421 Static in statics -> ast::StaticDef, 421 Static in statics -> ast::Static,
422 Trait in traits -> ast::TraitDef, 422 Trait in traits -> ast::Trait,
423 Impl in impls -> ast::ImplDef, 423 Impl in impls -> ast::Impl,
424 TypeAlias in type_aliases -> ast::TypeAliasDef, 424 TypeAlias in type_aliases -> ast::TypeAlias,
425 Mod in mods -> ast::Module, 425 Mod in mods -> ast::Module,
426 MacroCall in macro_calls -> ast::MacroCall, 426 MacroCall in macro_calls -> ast::MacroCall,
427} 427}
@@ -482,7 +482,7 @@ pub struct Import {
482 pub is_prelude: bool, 482 pub is_prelude: bool,
483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many 483 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
484 /// `Import`s can map to the same `use` item. 484 /// `Import`s can map to the same `use` item.
485 pub ast_id: FileAstId<ast::UseItem>, 485 pub ast_id: FileAstId<ast::Use>,
486} 486}
487 487
488#[derive(Debug, Clone, Eq, PartialEq)] 488#[derive(Debug, Clone, Eq, PartialEq)]
@@ -492,7 +492,7 @@ pub struct ExternCrate {
492 pub visibility: RawVisibilityId, 492 pub visibility: RawVisibilityId,
493 /// Whether this is a `#[macro_use] extern crate ...`. 493 /// Whether this is a `#[macro_use] extern crate ...`.
494 pub is_macro_use: bool, 494 pub is_macro_use: bool,
495 pub ast_id: FileAstId<ast::ExternCrateItem>, 495 pub ast_id: FileAstId<ast::ExternCrate>,
496} 496}
497 497
498#[derive(Debug, Clone, Eq, PartialEq)] 498#[derive(Debug, Clone, Eq, PartialEq)]
@@ -503,8 +503,9 @@ pub struct Function {
503 pub has_self_param: bool, 503 pub has_self_param: bool,
504 pub is_unsafe: bool, 504 pub is_unsafe: bool,
505 pub params: Box<[TypeRef]>, 505 pub params: Box<[TypeRef]>,
506 pub is_varargs: bool,
506 pub ret_type: TypeRef, 507 pub ret_type: TypeRef,
507 pub ast_id: FileAstId<ast::FnDef>, 508 pub ast_id: FileAstId<ast::Fn>,
508} 509}
509 510
510#[derive(Debug, Clone, Eq, PartialEq)] 511#[derive(Debug, Clone, Eq, PartialEq)]
@@ -513,7 +514,7 @@ pub struct Struct {
513 pub visibility: RawVisibilityId, 514 pub visibility: RawVisibilityId,
514 pub generic_params: GenericParamsId, 515 pub generic_params: GenericParamsId,
515 pub fields: Fields, 516 pub fields: Fields,
516 pub ast_id: FileAstId<ast::StructDef>, 517 pub ast_id: FileAstId<ast::Struct>,
517 pub kind: StructDefKind, 518 pub kind: StructDefKind,
518} 519}
519 520
@@ -533,7 +534,7 @@ pub struct Union {
533 pub visibility: RawVisibilityId, 534 pub visibility: RawVisibilityId,
534 pub generic_params: GenericParamsId, 535 pub generic_params: GenericParamsId,
535 pub fields: Fields, 536 pub fields: Fields,
536 pub ast_id: FileAstId<ast::UnionDef>, 537 pub ast_id: FileAstId<ast::Union>,
537} 538}
538 539
539#[derive(Debug, Clone, Eq, PartialEq)] 540#[derive(Debug, Clone, Eq, PartialEq)]
@@ -542,7 +543,7 @@ pub struct Enum {
542 pub visibility: RawVisibilityId, 543 pub visibility: RawVisibilityId,
543 pub generic_params: GenericParamsId, 544 pub generic_params: GenericParamsId,
544 pub variants: IdRange<Variant>, 545 pub variants: IdRange<Variant>,
545 pub ast_id: FileAstId<ast::EnumDef>, 546 pub ast_id: FileAstId<ast::Enum>,
546} 547}
547 548
548#[derive(Debug, Clone, Eq, PartialEq)] 549#[derive(Debug, Clone, Eq, PartialEq)]
@@ -551,7 +552,7 @@ pub struct Const {
551 pub name: Option<Name>, 552 pub name: Option<Name>,
552 pub visibility: RawVisibilityId, 553 pub visibility: RawVisibilityId,
553 pub type_ref: TypeRef, 554 pub type_ref: TypeRef,
554 pub ast_id: FileAstId<ast::ConstDef>, 555 pub ast_id: FileAstId<ast::Const>,
555} 556}
556 557
557#[derive(Debug, Clone, Eq, PartialEq)] 558#[derive(Debug, Clone, Eq, PartialEq)]
@@ -560,7 +561,7 @@ pub struct Static {
560 pub visibility: RawVisibilityId, 561 pub visibility: RawVisibilityId,
561 pub mutable: bool, 562 pub mutable: bool,
562 pub type_ref: TypeRef, 563 pub type_ref: TypeRef,
563 pub ast_id: FileAstId<ast::StaticDef>, 564 pub ast_id: FileAstId<ast::Static>,
564} 565}
565 566
566#[derive(Debug, Clone, Eq, PartialEq)] 567#[derive(Debug, Clone, Eq, PartialEq)]
@@ -570,7 +571,7 @@ pub struct Trait {
570 pub generic_params: GenericParamsId, 571 pub generic_params: GenericParamsId,
571 pub auto: bool, 572 pub auto: bool,
572 pub items: Box<[AssocItem]>, 573 pub items: Box<[AssocItem]>,
573 pub ast_id: FileAstId<ast::TraitDef>, 574 pub ast_id: FileAstId<ast::Trait>,
574} 575}
575 576
576#[derive(Debug, Clone, Eq, PartialEq)] 577#[derive(Debug, Clone, Eq, PartialEq)]
@@ -580,7 +581,7 @@ pub struct Impl {
580 pub target_type: TypeRef, 581 pub target_type: TypeRef,
581 pub is_negative: bool, 582 pub is_negative: bool,
582 pub items: Box<[AssocItem]>, 583 pub items: Box<[AssocItem]>,
583 pub ast_id: FileAstId<ast::ImplDef>, 584 pub ast_id: FileAstId<ast::Impl>,
584} 585}
585 586
586#[derive(Debug, Clone, PartialEq, Eq)] 587#[derive(Debug, Clone, PartialEq, Eq)]
@@ -591,7 +592,7 @@ pub struct TypeAlias {
591 pub bounds: Box<[TypeBound]>, 592 pub bounds: Box<[TypeBound]>,
592 pub generic_params: GenericParamsId, 593 pub generic_params: GenericParamsId,
593 pub type_ref: Option<TypeRef>, 594 pub type_ref: Option<TypeRef>,
594 pub ast_id: FileAstId<ast::TypeAliasDef>, 595 pub ast_id: FileAstId<ast::TypeAlias>,
595} 596}
596 597
597#[derive(Debug, Clone, Eq, PartialEq)] 598#[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 5149dd141..feb31579e 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -1,10 +1,7 @@
1//! AST -> `ItemTree` lowering code. 1//! AST -> `ItemTree` lowering code.
2 2
3use super::*; 3use std::{collections::hash_map::Entry, mem, sync::Arc};
4use crate::{ 4
5 attr::Attrs,
6 generics::{GenericParams, TypeParamData, TypeParamProvenance},
7};
8use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; 5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
9use ra_arena::map::ArenaMap; 6use ra_arena::map::ArenaMap;
10use ra_syntax::{ 7use ra_syntax::{
@@ -12,7 +9,13 @@ use ra_syntax::{
12 SyntaxNode, 9 SyntaxNode,
13}; 10};
14use smallvec::SmallVec; 11use smallvec::SmallVec;
15use std::{collections::hash_map::Entry, mem, sync::Arc}; 12
13use crate::{
14 attr::Attrs,
15 generics::{GenericParams, TypeParamData, TypeParamProvenance},
16};
17
18use super::*;
16 19
17fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { 20fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
18 FileItemTreeId { index, _p: PhantomData } 21 FileItemTreeId { index, _p: PhantomData }
@@ -70,19 +73,19 @@ impl Ctx {
70 self.tree.data_mut() 73 self.tree.data_mut()
71 } 74 }
72 75
73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { 76 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> {
74 assert!(inner || self.inner_items.is_empty()); 77 assert!(inner || self.inner_items.is_empty());
75 78
76 // Collect inner items for 1-to-1-lowered items. 79 // Collect inner items for 1-to-1-lowered items.
77 match item { 80 match item {
78 ast::ModuleItem::StructDef(_) 81 ast::Item::Struct(_)
79 | ast::ModuleItem::UnionDef(_) 82 | ast::Item::Union(_)
80 | ast::ModuleItem::EnumDef(_) 83 | ast::Item::Enum(_)
81 | ast::ModuleItem::FnDef(_) 84 | ast::Item::Fn(_)
82 | ast::ModuleItem::TypeAliasDef(_) 85 | ast::Item::TypeAlias(_)
83 | ast::ModuleItem::ConstDef(_) 86 | ast::Item::Const(_)
84 | ast::ModuleItem::StaticDef(_) 87 | ast::Item::Static(_)
85 | ast::ModuleItem::MacroCall(_) => { 88 | ast::Item::MacroCall(_) => {
86 // Skip this if we're already collecting inner items. We'll descend into all nodes 89 // Skip this if we're already collecting inner items. We'll descend into all nodes
87 // already. 90 // already.
88 if !inner { 91 if !inner {
@@ -92,34 +95,30 @@ impl Ctx {
92 95
93 // These are handled in their respective `lower_X` method (since we can't just blindly 96 // These are handled in their respective `lower_X` method (since we can't just blindly
94 // walk them). 97 // walk them).
95 ast::ModuleItem::TraitDef(_) 98 ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}
96 | ast::ModuleItem::ImplDef(_)
97 | ast::ModuleItem::ExternBlock(_) => {}
98 99
99 // These don't have inner items. 100 // These don't have inner items.
100 ast::ModuleItem::Module(_) 101 ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
101 | ast::ModuleItem::ExternCrateItem(_)
102 | ast::ModuleItem::UseItem(_) => {}
103 }; 102 };
104 103
105 let attrs = Attrs::new(item, &self.hygiene); 104 let attrs = Attrs::new(item, &self.hygiene);
106 let items = match item { 105 let items = match item {
107 ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), 106 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
108 ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), 107 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
109 ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), 108 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into),
110 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), 109 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into),
111 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), 110 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
112 ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), 111 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into),
113 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), 112 ast::Item::Const(ast) => Some(self.lower_const(ast).into()),
114 ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), 113 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into),
115 ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), 114 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into),
116 ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), 115 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into),
117 ast::ModuleItem::UseItem(ast) => Some(ModItems( 116 ast::Item::Use(ast) => Some(ModItems(
118 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), 117 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
119 )), 118 )),
120 ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), 119 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
121 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 120 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
122 ast::ModuleItem::ExternBlock(ast) => { 121 ast::Item::ExternBlock(ast) => {
123 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) 122 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
124 } 123 }
125 }; 124 };
@@ -147,27 +146,26 @@ impl Ctx {
147 fn collect_inner_items(&mut self, container: &SyntaxNode) { 146 fn collect_inner_items(&mut self, container: &SyntaxNode) {
148 let forced_vis = self.forced_visibility.take(); 147 let forced_vis = self.forced_visibility.take();
149 let mut inner_items = mem::take(&mut self.tree.inner_items); 148 let mut inner_items = mem::take(&mut self.tree.inner_items);
150 inner_items.extend( 149 inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map(
151 container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { 150 |item| {
152 let ast_id = self.source_ast_id_map.ast_id(&item); 151 let ast_id = self.source_ast_id_map.ast_id(&item);
153 Some((ast_id, self.lower_mod_item(&item, true)?.0)) 152 Some((ast_id, self.lower_mod_item(&item, true)?.0))
154 }), 153 },
155 ); 154 ));
156 self.tree.inner_items = inner_items; 155 self.tree.inner_items = inner_items;
157 self.forced_visibility = forced_vis; 156 self.forced_visibility = forced_vis;
158 } 157 }
159 158
160 fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> { 159 fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> {
161 match item { 160 match item {
162 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), 161 ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
163 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), 162 ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
164 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), 163 ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
165 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 164 ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
166 _ => None,
167 } 165 }
168 } 166 }
169 167
170 fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> { 168 fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
171 let visibility = self.lower_visibility(strukt); 169 let visibility = self.lower_visibility(strukt);
172 let name = strukt.name()?.as_name(); 170 let name = strukt.name()?.as_name();
173 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); 171 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
@@ -196,7 +194,7 @@ impl Ctx {
196 } 194 }
197 } 195 }
198 196
199 fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> IdRange<Field> { 197 fn lower_record_fields(&mut self, fields: &ast::RecordFieldList) -> IdRange<Field> {
200 let start = self.next_field_idx(); 198 let start = self.next_field_idx();
201 for field in fields.fields() { 199 for field in fields.fields() {
202 if let Some(data) = self.lower_record_field(&field) { 200 if let Some(data) = self.lower_record_field(&field) {
@@ -208,42 +206,39 @@ impl Ctx {
208 IdRange::new(start..end) 206 IdRange::new(start..end)
209 } 207 }
210 208
211 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> { 209 fn lower_record_field(&mut self, field: &ast::RecordField) -> Option<Field> {
212 let name = field.name()?.as_name(); 210 let name = field.name()?.as_name();
213 let visibility = self.lower_visibility(field); 211 let visibility = self.lower_visibility(field);
214 let type_ref = self.lower_type_ref(&field.ascribed_type()?); 212 let type_ref = self.lower_type_ref_opt(field.ty());
215 let res = Field { name, type_ref, visibility }; 213 let res = Field { name, type_ref, visibility };
216 Some(res) 214 Some(res)
217 } 215 }
218 216
219 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> IdRange<Field> { 217 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldList) -> IdRange<Field> {
220 let start = self.next_field_idx(); 218 let start = self.next_field_idx();
221 for (i, field) in fields.fields().enumerate() { 219 for (i, field) in fields.fields().enumerate() {
222 if let Some(data) = self.lower_tuple_field(i, &field) { 220 let data = self.lower_tuple_field(i, &field);
223 let idx = self.data().fields.alloc(data); 221 let idx = self.data().fields.alloc(data);
224 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); 222 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene));
225 }
226 } 223 }
227 let end = self.next_field_idx(); 224 let end = self.next_field_idx();
228 IdRange::new(start..end) 225 IdRange::new(start..end)
229 } 226 }
230 227
231 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> { 228 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
232 let name = Name::new_tuple_field(idx); 229 let name = Name::new_tuple_field(idx);
233 let visibility = self.lower_visibility(field); 230 let visibility = self.lower_visibility(field);
234 let type_ref = self.lower_type_ref(&field.type_ref()?); 231 let type_ref = self.lower_type_ref_opt(field.ty());
235 let res = Field { name, type_ref, visibility }; 232 let res = Field { name, type_ref, visibility };
236 Some(res) 233 res
237 } 234 }
238 235
239 fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> { 236 fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
240 let visibility = self.lower_visibility(union); 237 let visibility = self.lower_visibility(union);
241 let name = union.name()?.as_name(); 238 let name = union.name()?.as_name();
242 let generic_params = self.lower_generic_params(GenericsOwner::Union, union); 239 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
243 let fields = match union.record_field_def_list() { 240 let fields = match union.record_field_list() {
244 Some(record_field_def_list) => { 241 Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
245 self.lower_fields(&StructKind::Record(record_field_def_list))
246 }
247 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())), 242 None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())),
248 }; 243 };
249 let ast_id = self.source_ast_id_map.ast_id(union); 244 let ast_id = self.source_ast_id_map.ast_id(union);
@@ -251,7 +246,7 @@ impl Ctx {
251 Some(id(self.data().unions.alloc(res))) 246 Some(id(self.data().unions.alloc(res)))
252 } 247 }
253 248
254 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { 249 fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
255 let visibility = self.lower_visibility(enum_); 250 let visibility = self.lower_visibility(enum_);
256 let name = enum_.name()?.as_name(); 251 let name = enum_.name()?.as_name();
257 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); 252 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
@@ -264,7 +259,7 @@ impl Ctx {
264 Some(id(self.data().enums.alloc(res))) 259 Some(id(self.data().enums.alloc(res)))
265 } 260 }
266 261
267 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> IdRange<Variant> { 262 fn lower_variants(&mut self, variants: &ast::VariantList) -> IdRange<Variant> {
268 let start = self.next_variant_idx(); 263 let start = self.next_variant_idx();
269 for variant in variants.variants() { 264 for variant in variants.variants() {
270 if let Some(data) = self.lower_variant(&variant) { 265 if let Some(data) = self.lower_variant(&variant) {
@@ -276,14 +271,14 @@ impl Ctx {
276 IdRange::new(start..end) 271 IdRange::new(start..end)
277 } 272 }
278 273
279 fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> { 274 fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
280 let name = variant.name()?.as_name(); 275 let name = variant.name()?.as_name();
281 let fields = self.lower_fields(&variant.kind()); 276 let fields = self.lower_fields(&variant.kind());
282 let res = Variant { name, fields }; 277 let res = Variant { name, fields };
283 Some(res) 278 Some(res)
284 } 279 }
285 280
286 fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> { 281 fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
287 let visibility = self.lower_visibility(func); 282 let visibility = self.lower_visibility(func);
288 let name = func.name()?.as_name(); 283 let name = func.name()?.as_name();
289 284
@@ -291,7 +286,7 @@ impl Ctx {
291 let mut has_self_param = false; 286 let mut has_self_param = false;
292 if let Some(param_list) = func.param_list() { 287 if let Some(param_list) = func.param_list() {
293 if let Some(self_param) = param_list.self_param() { 288 if let Some(self_param) = param_list.self_param() {
294 let self_type = match self_param.ascribed_type() { 289 let self_type = match self_param.ty() {
295 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), 290 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
296 None => { 291 None => {
297 let self_type = TypeRef::Path(name![Self].into()); 292 let self_type = TypeRef::Path(name![Self].into());
@@ -310,11 +305,19 @@ impl Ctx {
310 has_self_param = true; 305 has_self_param = true;
311 } 306 }
312 for param in param_list.params() { 307 for param in param_list.params() {
313 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); 308 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
314 params.push(type_ref); 309 params.push(type_ref);
315 } 310 }
316 } 311 }
317 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { 312
313 let mut is_varargs = false;
314 if let Some(params) = func.param_list() {
315 if let Some(last) = params.params().last() {
316 is_varargs = last.dotdotdot_token().is_some();
317 }
318 }
319
320 let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
318 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), 321 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
319 _ => TypeRef::unit(), 322 _ => TypeRef::unit(),
320 }; 323 };
@@ -335,6 +338,7 @@ impl Ctx {
335 has_self_param, 338 has_self_param,
336 is_unsafe: func.unsafe_token().is_some(), 339 is_unsafe: func.unsafe_token().is_some(),
337 params: params.into_boxed_slice(), 340 params: params.into_boxed_slice(),
341 is_varargs,
338 ret_type, 342 ret_type,
339 ast_id, 343 ast_id,
340 }; 344 };
@@ -345,10 +349,10 @@ impl Ctx {
345 349
346 fn lower_type_alias( 350 fn lower_type_alias(
347 &mut self, 351 &mut self,
348 type_alias: &ast::TypeAliasDef, 352 type_alias: &ast::TypeAlias,
349 ) -> Option<FileItemTreeId<TypeAlias>> { 353 ) -> Option<FileItemTreeId<TypeAlias>> {
350 let name = type_alias.name()?.as_name(); 354 let name = type_alias.name()?.as_name();
351 let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); 355 let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
352 let visibility = self.lower_visibility(type_alias); 356 let visibility = self.lower_visibility(type_alias);
353 let bounds = self.lower_type_bounds(type_alias); 357 let bounds = self.lower_type_bounds(type_alias);
354 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); 358 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
@@ -364,9 +368,9 @@ impl Ctx {
364 Some(id(self.data().type_aliases.alloc(res))) 368 Some(id(self.data().type_aliases.alloc(res)))
365 } 369 }
366 370
367 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { 371 fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
368 let name = static_.name()?.as_name(); 372 let name = static_.name()?.as_name();
369 let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); 373 let type_ref = self.lower_type_ref_opt(static_.ty());
370 let visibility = self.lower_visibility(static_); 374 let visibility = self.lower_visibility(static_);
371 let mutable = static_.mut_token().is_some(); 375 let mutable = static_.mut_token().is_some();
372 let ast_id = self.source_ast_id_map.ast_id(static_); 376 let ast_id = self.source_ast_id_map.ast_id(static_);
@@ -374,9 +378,9 @@ impl Ctx {
374 Some(id(self.data().statics.alloc(res))) 378 Some(id(self.data().statics.alloc(res)))
375 } 379 }
376 380
377 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { 381 fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
378 let name = konst.name().map(|it| it.as_name()); 382 let name = konst.name().map(|it| it.as_name());
379 let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); 383 let type_ref = self.lower_type_ref_opt(konst.ty());
380 let visibility = self.lower_visibility(konst); 384 let visibility = self.lower_visibility(konst);
381 let ast_id = self.source_ast_id_map.ast_id(konst); 385 let ast_id = self.source_ast_id_map.ast_id(konst);
382 let res = Const { name, visibility, type_ref, ast_id }; 386 let res = Const { name, visibility, type_ref, ast_id };
@@ -409,15 +413,15 @@ impl Ctx {
409 Some(id(self.data().mods.alloc(res))) 413 Some(id(self.data().mods.alloc(res)))
410 } 414 }
411 415
412 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { 416 fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
413 let name = trait_def.name()?.as_name(); 417 let name = trait_def.name()?.as_name();
414 let visibility = self.lower_visibility(trait_def); 418 let visibility = self.lower_visibility(trait_def);
415 let generic_params = 419 let generic_params =
416 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 420 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
417 let auto = trait_def.auto_token().is_some(); 421 let auto = trait_def.auto_token().is_some();
418 let items = trait_def.item_list().map(|list| { 422 let items = trait_def.assoc_item_list().map(|list| {
419 self.with_inherited_visibility(visibility, |this| { 423 self.with_inherited_visibility(visibility, |this| {
420 list.items() 424 list.assoc_items()
421 .filter_map(|item| { 425 .filter_map(|item| {
422 let attrs = Attrs::new(&item, &this.hygiene); 426 let attrs = Attrs::new(&item, &this.hygiene);
423 this.collect_inner_items(item.syntax()); 427 this.collect_inner_items(item.syntax());
@@ -441,7 +445,7 @@ impl Ctx {
441 Some(id(self.data().traits.alloc(res))) 445 Some(id(self.data().traits.alloc(res)))
442 } 446 }
443 447
444 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { 448 fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
445 let generic_params = 449 let generic_params =
446 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); 450 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
447 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); 451 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr));
@@ -450,8 +454,9 @@ impl Ctx {
450 454
451 // We cannot use `assoc_items()` here as that does not include macro calls. 455 // We cannot use `assoc_items()` here as that does not include macro calls.
452 let items = impl_def 456 let items = impl_def
453 .item_list()? 457 .assoc_item_list()
454 .items() 458 .into_iter()
459 .flat_map(|it| it.assoc_items())
455 .filter_map(|item| { 460 .filter_map(|item| {
456 self.collect_inner_items(item.syntax()); 461 self.collect_inner_items(item.syntax());
457 let assoc = self.lower_assoc_item(&item)?; 462 let assoc = self.lower_assoc_item(&item)?;
@@ -465,7 +470,7 @@ impl Ctx {
465 Some(id(self.data().impls.alloc(res))) 470 Some(id(self.data().impls.alloc(res)))
466 } 471 }
467 472
468 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { 473 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> {
469 // FIXME: cfg_attr 474 // FIXME: cfg_attr
470 let is_prelude = use_item.has_atom_attr("prelude_import"); 475 let is_prelude = use_item.has_atom_attr("prelude_import");
471 let visibility = self.lower_visibility(use_item); 476 let visibility = self.lower_visibility(use_item);
@@ -494,10 +499,10 @@ impl Ctx {
494 499
495 fn lower_extern_crate( 500 fn lower_extern_crate(
496 &mut self, 501 &mut self,
497 extern_crate: &ast::ExternCrateItem, 502 extern_crate: &ast::ExternCrate,
498 ) -> Option<FileItemTreeId<ExternCrate>> { 503 ) -> Option<FileItemTreeId<ExternCrate>> {
499 let path = ModPath::from_name_ref(&extern_crate.name_ref()?); 504 let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
500 let alias = extern_crate.alias().map(|a| { 505 let alias = extern_crate.rename().map(|a| {
501 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) 506 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
502 }); 507 });
503 let visibility = self.lower_visibility(extern_crate); 508 let visibility = self.lower_visibility(extern_crate);
@@ -543,14 +548,16 @@ impl Ctx {
543 self.collect_inner_items(item.syntax()); 548 self.collect_inner_items(item.syntax());
544 let attrs = Attrs::new(&item, &self.hygiene); 549 let attrs = Attrs::new(&item, &self.hygiene);
545 let id: ModItem = match item { 550 let id: ModItem = match item {
546 ast::ExternItem::FnDef(ast) => { 551 ast::ExternItem::Fn(ast) => {
547 let func = self.lower_function(&ast)?; 552 let func = self.lower_function(&ast)?;
553 self.data().functions[func.index].is_unsafe = true;
548 func.into() 554 func.into()
549 } 555 }
550 ast::ExternItem::StaticDef(ast) => { 556 ast::ExternItem::Static(ast) => {
551 let statik = self.lower_static(&ast)?; 557 let statik = self.lower_static(&ast)?;
552 statik.into() 558 statik.into()
553 } 559 }
560 ast::ExternItem::MacroCall(_) => return None,
554 }; 561 };
555 self.add_attrs(id.into(), attrs); 562 self.add_attrs(id.into(), attrs);
556 Some(id) 563 Some(id)
@@ -563,10 +570,10 @@ impl Ctx {
563 fn lower_generic_params_and_inner_items( 570 fn lower_generic_params_and_inner_items(
564 &mut self, 571 &mut self,
565 owner: GenericsOwner<'_>, 572 owner: GenericsOwner<'_>,
566 node: &impl ast::TypeParamsOwner, 573 node: &impl ast::GenericParamsOwner,
567 ) -> GenericParamsId { 574 ) -> GenericParamsId {
568 // Generics are part of item headers and may contain inner items we need to collect. 575 // Generics are part of item headers and may contain inner items we need to collect.
569 if let Some(params) = node.type_param_list() { 576 if let Some(params) = node.generic_param_list() {
570 self.collect_inner_items(params.syntax()); 577 self.collect_inner_items(params.syntax());
571 } 578 }
572 if let Some(clause) = node.where_clause() { 579 if let Some(clause) = node.where_clause() {
@@ -579,7 +586,7 @@ impl Ctx {
579 fn lower_generic_params( 586 fn lower_generic_params(
580 &mut self, 587 &mut self,
581 owner: GenericsOwner<'_>, 588 owner: GenericsOwner<'_>,
582 node: &impl ast::TypeParamsOwner, 589 node: &impl ast::GenericParamsOwner,
583 ) -> GenericParamsId { 590 ) -> GenericParamsId {
584 let mut sm = &mut ArenaMap::default(); 591 let mut sm = &mut ArenaMap::default();
585 let mut generics = GenericParams::default(); 592 let mut generics = GenericParams::default();
@@ -692,7 +699,7 @@ enum GenericsOwner<'a> {
692 Enum, 699 Enum,
693 Union, 700 Union,
694 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. 701 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
695 Trait(&'a ast::TraitDef), 702 Trait(&'a ast::Trait),
696 TypeAlias, 703 TypeAlias,
697 Impl, 704 Impl,
698} 705}
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs
index 08559fb92..a81497fa8 100644
--- a/crates/ra_hir_def/src/item_tree/tests.rs
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -1,13 +1,15 @@
1use super::{ItemTree, ModItem, ModKind}; 1use expect::{expect, Expect};
2use crate::{db::DefDatabase, test_db::TestDB};
3use hir_expand::{db::AstDatabase, HirFileId, InFile}; 2use hir_expand::{db::AstDatabase, HirFileId, InFile};
4use insta::assert_snapshot;
5use ra_db::fixture::WithFixture; 3use ra_db::fixture::WithFixture;
6use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode};
7use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
8use std::sync::Arc; 6use std::sync::Arc;
9use stdx::format_to; 7use stdx::format_to;
10 8
9use crate::{db::DefDatabase, test_db::TestDB};
10
11use super::{ItemTree, ModItem, ModKind};
12
11fn test_inner_items(ra_fixture: &str) { 13fn test_inner_items(ra_fixture: &str) {
12 let (db, file_id) = TestDB::with_single_file(ra_fixture); 14 let (db, file_id) = TestDB::with_single_file(ra_fixture);
13 let file_id = HirFileId::from(file_id); 15 let file_id = HirFileId::from(file_id);
@@ -19,7 +21,7 @@ fn test_inner_items(ra_fixture: &str) {
19 let mut outer_items = FxHashSet::default(); 21 let mut outer_items = FxHashSet::default();
20 let mut worklist = tree.top_level_items().to_vec(); 22 let mut worklist = tree.top_level_items().to_vec();
21 while let Some(item) = worklist.pop() { 23 while let Some(item) = worklist.pop() {
22 let node: ast::ModuleItem = match item { 24 let node: ast::Item = match item {
23 ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), 25 ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(),
24 ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), 26 ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(),
25 ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), 27 ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(),
@@ -51,7 +53,7 @@ fn test_inner_items(ra_fixture: &str) {
51 53
52 // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or 54 // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or
53 // registered as inner items. 55 // registered as inner items.
54 for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { 56 for item in root.descendants().skip(1).filter_map(ast::Item::cast) {
55 if outer_items.contains(&item) { 57 if outer_items.contains(&item) {
56 continue; 58 continue;
57 } 59 }
@@ -162,9 +164,15 @@ fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) {
162 } 164 }
163} 165}
164 166
167fn check(ra_fixture: &str, expect: Expect) {
168 let actual = print_item_tree(ra_fixture);
169 expect.assert_eq(&actual);
170}
171
165#[test] 172#[test]
166fn smoke() { 173fn smoke() {
167 assert_snapshot!(print_item_tree(r" 174 check(
175 r"
168 #![attr] 176 #![attr]
169 177
170 #[attr_on_use] 178 #[attr_on_use]
@@ -214,42 +222,44 @@ fn smoke() {
214 #[union_fld] 222 #[union_fld]
215 fld: u16, 223 fld: u16,
216 } 224 }
217 "), @r###" 225 ",
218inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } 226 expect![[r##"
219 227 inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) }
220top-level items: 228
221#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] 229 top-level items:
222Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } 230 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
223#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] 231 Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
224Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } 232 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
225#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] 233 Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Use>(0) }
226ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) } 234 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
227#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] 235 ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrate>(1) }
228Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) } 236 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
229> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] 237 Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Trait>(2) }
230> TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) } 238 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }]
231> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] 239 > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAlias>(8) }
232> Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) } 240 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }]
233> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] 241 > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Const>(9) }
234> Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) } 242 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }]
235> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] 243 > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(10) }
236> Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) } 244 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }]
237#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] 245 > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(11) }
238Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit } 246 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }]
239#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] 247 Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(3), kind: Unit }
240Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::<ra_hir_def::item_tree::Field>(0..1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple } 248 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }]
241#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] 249 Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(IdRange::<ra_hir_def::item_tree::Field>(0..1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(4), kind: Tuple }
242Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(1..2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record } 250 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }]
243#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] 251 Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(1..2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Struct>(5), kind: Record }
244Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::<ra_hir_def::item_tree::Variant>(0..1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) } 252 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }]
245#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] 253 Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: IdRange::<ra_hir_def::item_tree::Variant>(0..1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Enum>(6) }
246Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(3..4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) } 254 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }]
247 "###); 255 Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(IdRange::<ra_hir_def::item_tree::Field>(3..4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Union>(7) }
256 "##]],
257 );
248} 258}
249 259
250#[test] 260#[test]
251fn simple_inner_items() { 261fn simple_inner_items() {
252 let tree = print_item_tree( 262 check(
253 r" 263 r"
254 impl<T:A> D for Response<T> { 264 impl<T:A> D for Response<T> {
255 fn foo() { 265 fn foo() {
@@ -260,26 +270,25 @@ fn simple_inner_items() {
260 } 270 }
261 } 271 }
262 ", 272 ",
263 ); 273 expect![[r#"
274 inner attrs: Attrs { entries: None }
264 275
265 assert_snapshot!(tree, @r###" 276 top-level items:
266inner attrs: Attrs { entries: None } 277 Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
278 > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
267 279
268top-level items: 280 inner items:
269Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
270> Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
271 281
272inner items: 282 for AST FileAstId::<ra_syntax::ast::generated::nodes::Item>(2):
283 Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
273 284
274for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2): 285 "#]],
275Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } 286 );
276
277 "###);
278} 287}
279 288
280#[test] 289#[test]
281fn extern_attrs() { 290fn extern_attrs() {
282 let tree = print_item_tree( 291 check(
283 r#" 292 r#"
284 #[block_attr] 293 #[block_attr]
285 extern "C" { 294 extern "C" {
@@ -289,22 +298,21 @@ fn extern_attrs() {
289 fn b() {} 298 fn b() {}
290 } 299 }
291 "#, 300 "#,
301 expect![[r##"
302 inner attrs: Attrs { entries: None }
303
304 top-level items:
305 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
306 Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
307 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
308 Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: true, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
309 "##]],
292 ); 310 );
293
294 assert_snapshot!(tree, @r###"
295inner attrs: Attrs { entries: None }
296
297top-level items:
298#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
299Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
300#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }]
301Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
302 "###);
303} 311}
304 312
305#[test] 313#[test]
306fn trait_attrs() { 314fn trait_attrs() {
307 let tree = print_item_tree( 315 check(
308 r#" 316 r#"
309 #[trait_attr] 317 #[trait_attr]
310 trait Tr { 318 trait Tr {
@@ -314,24 +322,23 @@ fn trait_attrs() {
314 fn b() {} 322 fn b() {}
315 } 323 }
316 "#, 324 "#,
325 expect![[r##"
326 inner attrs: Attrs { entries: None }
327
328 top-level items:
329 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
330 Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Trait>(0) }
331 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
332 > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
333 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
334 > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
335 "##]],
317 ); 336 );
318
319 assert_snapshot!(tree, @r###"
320inner attrs: Attrs { entries: None }
321
322top-level items:
323#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }]
324Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) }
325> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
326> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
327> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
328> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
329 "###);
330} 337}
331 338
332#[test] 339#[test]
333fn impl_attrs() { 340fn impl_attrs() {
334 let tree = print_item_tree( 341 check(
335 r#" 342 r#"
336 #[impl_attr] 343 #[impl_attr]
337 impl Ty { 344 impl Ty {
@@ -341,19 +348,18 @@ fn impl_attrs() {
341 fn b() {} 348 fn b() {}
342 } 349 }
343 "#, 350 "#,
351 expect![[r##"
352 inner attrs: Attrs { entries: None }
353
354 top-level items:
355 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
356 Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
357 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
358 > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
359 > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
360 > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(2) }
361 "##]],
344 ); 362 );
345
346 assert_snapshot!(tree, @r###"
347inner attrs: Attrs { entries: None }
348
349top-level items:
350#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }]
351Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) }
352> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }]
353> Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) }
354> #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }]
355> Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) }
356 "###);
357} 363}
358 364
359#[test] 365#[test]
@@ -391,45 +397,43 @@ fn cursed_inner_items() {
391 397
392#[test] 398#[test]
393fn inner_item_attrs() { 399fn inner_item_attrs() {
394 let tree = print_item_tree( 400 check(
395 r" 401 r"
396 fn foo() { 402 fn foo() {
397 #[on_inner] 403 #[on_inner]
398 fn inner() {} 404 fn inner() {}
399 } 405 }
400 ", 406 ",
401 ); 407 expect![[r##"
402 408 inner attrs: Attrs { entries: None }
403 assert_snapshot!(tree, @r###"
404inner attrs: Attrs { entries: None }
405 409
406top-level items: 410 top-level items:
407Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) } 411 Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(0) }
408 412
409inner items: 413 inner items:
410 414
411for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1): 415 for AST FileAstId::<ra_syntax::ast::generated::nodes::Item>(1):
412#[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] 416 #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }]
413Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } 417 Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], is_varargs: false, ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Fn>(1) }
414 418
415 "###); 419 "##]],
420 );
416} 421}
417 422
418#[test] 423#[test]
419fn assoc_item_macros() { 424fn assoc_item_macros() {
420 let tree = print_item_tree( 425 check(
421 r" 426 r"
422 impl S { 427 impl S {
423 items!(); 428 items!();
424 } 429 }
425 ", 430 ",
426 ); 431 expect![[r#"
427 432 inner attrs: Attrs { entries: None }
428 assert_snapshot!(tree, @r###"
429inner attrs: Attrs { entries: None }
430 433
431top-level items: 434 top-level items:
432Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } 435 Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::Impl>(0) }
433> MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) } 436 > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) }
434 "###); 437 "#]],
438 );
435} 439}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
index a7349a21d..441bdbead 100644
--- a/crates/ra_hir_def/src/keys.rs
+++ b/crates/ra_hir_def/src/keys.rs
@@ -14,19 +14,19 @@ use crate::{
14 14
15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; 15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
16 16
17pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new(); 17pub const FUNCTION: Key<ast::Fn, FunctionId> = Key::new();
18pub const CONST: Key<ast::ConstDef, ConstId> = Key::new(); 18pub const CONST: Key<ast::Const, ConstId> = Key::new();
19pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new(); 19pub const STATIC: Key<ast::Static, StaticId> = Key::new();
20pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new(); 20pub const TYPE_ALIAS: Key<ast::TypeAlias, TypeAliasId> = Key::new();
21pub const IMPL: Key<ast::ImplDef, ImplId> = Key::new(); 21pub const IMPL: Key<ast::Impl, ImplId> = Key::new();
22pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new(); 22pub const TRAIT: Key<ast::Trait, TraitId> = Key::new();
23pub const STRUCT: Key<ast::StructDef, StructId> = Key::new(); 23pub const STRUCT: Key<ast::Struct, StructId> = Key::new();
24pub const UNION: Key<ast::UnionDef, UnionId> = Key::new(); 24pub const UNION: Key<ast::Union, UnionId> = Key::new();
25pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new(); 25pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
26 26
27pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new(); 27pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
28pub const TUPLE_FIELD: Key<ast::TupleFieldDef, FieldId> = Key::new(); 28pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
29pub const RECORD_FIELD: Key<ast::RecordFieldDef, FieldId> = Key::new(); 29pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); 30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
31 31
32pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); 32pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 564434ccc..237b1038a 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -65,6 +65,7 @@ use item_tree::{
65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, 65 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
66 TypeAlias, Union, 66 TypeAlias, Union,
67}; 67};
68use stdx::impl_from;
68 69
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70pub struct ModuleId { 71pub struct ModuleId {
@@ -158,17 +159,17 @@ pub struct FunctionId(salsa::InternId);
158type FunctionLoc = AssocItemLoc<Function>; 159type FunctionLoc = AssocItemLoc<Function>;
159impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); 160impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
160 161
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
162pub struct StructId(salsa::InternId); 163pub struct StructId(salsa::InternId);
163type StructLoc = ItemLoc<Struct>; 164type StructLoc = ItemLoc<Struct>;
164impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); 165impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
165 166
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
167pub struct UnionId(salsa::InternId); 168pub struct UnionId(salsa::InternId);
168pub type UnionLoc = ItemLoc<Union>; 169pub type UnionLoc = ItemLoc<Union>;
169impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); 170impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
170 171
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 172#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
172pub struct EnumId(salsa::InternId); 173pub struct EnumId(salsa::InternId);
173pub type EnumLoc = ItemLoc<Enum>; 174pub type EnumLoc = ItemLoc<Enum>;
174impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); 175impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
@@ -223,25 +224,6 @@ pub struct TypeParamId {
223 224
224pub type LocalTypeParamId = Idx<generics::TypeParamData>; 225pub type LocalTypeParamId = Idx<generics::TypeParamData>;
225 226
226macro_rules! impl_froms {
227 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
228 $(
229 impl From<$v> for $e {
230 fn from(it: $v) -> $e {
231 $e::$v(it)
232 }
233 }
234 $($(
235 impl From<$sv> for $e {
236 fn from(it: $sv) -> $e {
237 $e::$v($v::$sv(it))
238 }
239 }
240 )*)?
241 )*
242 }
243}
244
245#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
246pub enum ContainerId { 228pub enum ContainerId {
247 ModuleId(ModuleId), 229 ModuleId(ModuleId),
@@ -254,16 +236,16 @@ pub enum AssocContainerId {
254 ImplId(ImplId), 236 ImplId(ImplId),
255 TraitId(TraitId), 237 TraitId(TraitId),
256} 238}
257impl_froms!(AssocContainerId: ContainerId); 239impl_from!(ContainerId for AssocContainerId);
258 240
259/// A Data Type 241/// A Data Type
260#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
261pub enum AdtId { 243pub enum AdtId {
262 StructId(StructId), 244 StructId(StructId),
263 UnionId(UnionId), 245 UnionId(UnionId),
264 EnumId(EnumId), 246 EnumId(EnumId),
265} 247}
266impl_froms!(AdtId: StructId, UnionId, EnumId); 248impl_from!(StructId, UnionId, EnumId for AdtId);
267 249
268/// The defs which can be visible in the module. 250/// The defs which can be visible in the module.
269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -279,8 +261,8 @@ pub enum ModuleDefId {
279 TypeAliasId(TypeAliasId), 261 TypeAliasId(TypeAliasId),
280 BuiltinType(BuiltinType), 262 BuiltinType(BuiltinType),
281} 263}
282impl_froms!( 264impl_from!(
283 ModuleDefId: ModuleId, 265 ModuleId,
284 FunctionId, 266 FunctionId,
285 AdtId(StructId, EnumId, UnionId), 267 AdtId(StructId, EnumId, UnionId),
286 EnumVariantId, 268 EnumVariantId,
@@ -289,6 +271,7 @@ impl_froms!(
289 TraitId, 271 TraitId,
290 TypeAliasId, 272 TypeAliasId,
291 BuiltinType 273 BuiltinType
274 for ModuleDefId
292); 275);
293 276
294/// The defs which have a body. 277/// The defs which have a body.
@@ -299,7 +282,7 @@ pub enum DefWithBodyId {
299 ConstId(ConstId), 282 ConstId(ConstId),
300} 283}
301 284
302impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); 285impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
303 286
304#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 287#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
305pub enum AssocItemId { 288pub enum AssocItemId {
@@ -311,7 +294,7 @@ pub enum AssocItemId {
311// sure that you can only turn actual assoc items into AssocItemIds. This would 294// sure that you can only turn actual assoc items into AssocItemIds. This would
312// require not implementing From, and instead having some checked way of 295// require not implementing From, and instead having some checked way of
313// casting them, and somehow making the constructors private, which would be annoying. 296// casting them, and somehow making the constructors private, which would be annoying.
314impl_froms!(AssocItemId: FunctionId, ConstId, TypeAliasId); 297impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
315 298
316#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 299#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
317pub enum GenericDefId { 300pub enum GenericDefId {
@@ -326,14 +309,15 @@ pub enum GenericDefId {
326 // consts can have type parameters from their parents (i.e. associated consts of traits) 309 // consts can have type parameters from their parents (i.e. associated consts of traits)
327 ConstId(ConstId), 310 ConstId(ConstId),
328} 311}
329impl_froms!( 312impl_from!(
330 GenericDefId: FunctionId, 313 FunctionId,
331 AdtId(StructId, EnumId, UnionId), 314 AdtId(StructId, EnumId, UnionId),
332 TraitId, 315 TraitId,
333 TypeAliasId, 316 TypeAliasId,
334 ImplId, 317 ImplId,
335 EnumVariantId, 318 EnumVariantId,
336 ConstId 319 ConstId
320 for GenericDefId
337); 321);
338 322
339impl From<AssocItemId> for GenericDefId { 323impl From<AssocItemId> for GenericDefId {
@@ -361,8 +345,8 @@ pub enum AttrDefId {
361 ImplId(ImplId), 345 ImplId(ImplId),
362} 346}
363 347
364impl_froms!( 348impl_from!(
365 AttrDefId: ModuleId, 349 ModuleId,
366 FieldId, 350 FieldId,
367 AdtId(StructId, EnumId, UnionId), 351 AdtId(StructId, EnumId, UnionId),
368 EnumVariantId, 352 EnumVariantId,
@@ -373,6 +357,7 @@ impl_froms!(
373 TypeAliasId, 357 TypeAliasId,
374 MacroDefId, 358 MacroDefId,
375 ImplId 359 ImplId
360 for AttrDefId
376); 361);
377 362
378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -381,7 +366,7 @@ pub enum VariantId {
381 StructId(StructId), 366 StructId(StructId),
382 UnionId(UnionId), 367 UnionId(UnionId),
383} 368}
384impl_froms!(VariantId: EnumVariantId, StructId, UnionId); 369impl_from!(EnumVariantId, StructId, UnionId for VariantId);
385 370
386trait Intern { 371trait Intern {
387 type ID; 372 type ID;
@@ -536,7 +521,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
536 } 521 }
537} 522}
538 523
539impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { 524impl AsMacroCall for AstIdWithPath<ast::Item> {
540 fn as_call_id( 525 fn as_call_id(
541 &self, 526 &self,
542 db: &dyn db::DefDatabase, 527 db: &dyn db::DefDatabase,
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index b279bdeef..3d9b55a73 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -229,37 +229,37 @@ impl CrateDefMap {
229 // even), as this should be a great debugging aid. 229 // even), as this should be a great debugging aid.
230 pub fn dump(&self) -> String { 230 pub fn dump(&self) -> String {
231 let mut buf = String::new(); 231 let mut buf = String::new();
232 go(&mut buf, self, "\ncrate", self.root); 232 go(&mut buf, self, "crate", self.root);
233 return buf.trim().to_string(); 233 return buf;
234 234
235 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { 235 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
236 *buf += path; 236 format_to!(buf, "{}\n", path);
237 *buf += "\n";
238 237
239 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); 238 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
240 entries.sort_by_key(|(name, _)| name.clone()); 239 entries.sort_by_key(|(name, _)| name.clone());
241 240
242 for (name, def) in entries { 241 for (name, def) in entries {
243 format_to!(buf, "{}:", name); 242 format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
244 243
245 if def.types.is_some() { 244 if def.types.is_some() {
246 *buf += " t"; 245 buf.push_str(" t");
247 } 246 }
248 if def.values.is_some() { 247 if def.values.is_some() {
249 *buf += " v"; 248 buf.push_str(" v");
250 } 249 }
251 if def.macros.is_some() { 250 if def.macros.is_some() {
252 *buf += " m"; 251 buf.push_str(" m");
253 } 252 }
254 if def.is_none() { 253 if def.is_none() {
255 *buf += " _"; 254 buf.push_str(" _");
256 } 255 }
257 256
258 *buf += "\n"; 257 buf.push_str("\n");
259 } 258 }
260 259
261 for (name, child) in map.modules[module].children.iter() { 260 for (name, child) in map.modules[module].children.iter() {
262 let path = &format!("{}::{}", path, name); 261 let path = format!("{}::{}", path, name);
262 buf.push('\n');
263 go(buf, map, &path, *child); 263 go(buf, map, &path, *child);
264 } 264 }
265 } 265 }
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index a35ac1024..28b7a20c5 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -36,6 +36,10 @@ use crate::{
36 TraitLoc, TypeAliasLoc, UnionLoc, 36 TraitLoc, TypeAliasLoc, UnionLoc,
37}; 37};
38 38
39const GLOB_RECURSION_LIMIT: usize = 100;
40const EXPANSION_DEPTH_LIMIT: usize = 128;
41const FIXED_POINT_LIMIT: usize = 8192;
42
39pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 43pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
40 let crate_graph = db.crate_graph(); 44 let crate_graph = db.crate_graph();
41 45
@@ -166,7 +170,7 @@ struct MacroDirective {
166#[derive(Clone, Debug, Eq, PartialEq)] 170#[derive(Clone, Debug, Eq, PartialEq)]
167struct DeriveDirective { 171struct DeriveDirective {
168 module_id: LocalModuleId, 172 module_id: LocalModuleId,
169 ast_id: AstIdWithPath<ast::ModuleItem>, 173 ast_id: AstIdWithPath<ast::Item>,
170} 174}
171 175
172struct DefData<'a> { 176struct DefData<'a> {
@@ -217,7 +221,7 @@ impl DefCollector<'_> {
217 ReachedFixedPoint::Yes => break, 221 ReachedFixedPoint::Yes => break,
218 ReachedFixedPoint::No => i += 1, 222 ReachedFixedPoint::No => i += 1,
219 } 223 }
220 if i == 10000 { 224 if i == FIXED_POINT_LIMIT {
221 log::error!("name resolution is stuck"); 225 log::error!("name resolution is stuck");
222 break; 226 break;
223 } 227 }
@@ -306,7 +310,7 @@ impl DefCollector<'_> {
306 if export { 310 if export {
307 self.update( 311 self.update(
308 self.def_map.root, 312 self.def_map.root,
309 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
310 Visibility::Public, 314 Visibility::Public,
311 ImportType::Named, 315 ImportType::Named,
312 ); 316 );
@@ -332,7 +336,7 @@ impl DefCollector<'_> {
332 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { 336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
333 self.update( 337 self.update(
334 self.def_map.root, 338 self.def_map.root,
335 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
336 Visibility::Public, 340 Visibility::Public,
337 ImportType::Named, 341 ImportType::Named,
338 ); 342 );
@@ -530,7 +534,7 @@ impl DefCollector<'_> {
530 let name = variant_data.name.clone(); 534 let name = variant_data.name.clone();
531 let variant = EnumVariantId { parent: e, local_id }; 535 let variant = EnumVariantId { parent: e, local_id };
532 let res = PerNs::both(variant.into(), variant.into(), vis); 536 let res = PerNs::both(variant.into(), variant.into(), vis);
533 (name, res) 537 (Some(name), res)
534 }) 538 })
535 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
536 self.update(module_id, &resolutions, vis, ImportType::Glob); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -546,15 +550,15 @@ impl DefCollector<'_> {
546 match import.path.segments.last() { 550 match import.path.segments.last() {
547 Some(last_segment) => { 551 Some(last_segment) => {
548 let name = match &import.alias { 552 let name = match &import.alias {
549 Some(ImportAlias::Alias(name)) => name.clone(), 553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
550 Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 554 Some(ImportAlias::Underscore) => None,
551 None => last_segment.clone(), 555 None => Some(last_segment.clone()),
552 }; 556 };
553 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
554 558
555 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
556 if import.is_extern_crate && module_id == self.def_map.root { 560 if import.is_extern_crate && module_id == self.def_map.root {
557 if let Some(def) = def.take_types() { 561 if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
558 self.def_map.extern_prelude.insert(name.clone(), def); 562 self.def_map.extern_prelude.insert(name.clone(), def);
559 } 563 }
560 } 564 }
@@ -569,36 +573,73 @@ impl DefCollector<'_> {
569 fn update( 573 fn update(
570 &mut self, 574 &mut self,
571 module_id: LocalModuleId, 575 module_id: LocalModuleId,
572 resolutions: &[(Name, PerNs)], 576 resolutions: &[(Option<Name>, PerNs)],
573 vis: Visibility, 577 vis: Visibility,
574 import_type: ImportType, 578 import_type: ImportType,
575 ) { 579 ) {
580 self.db.check_canceled();
576 self.update_recursive(module_id, resolutions, vis, import_type, 0) 581 self.update_recursive(module_id, resolutions, vis, import_type, 0)
577 } 582 }
578 583
579 fn update_recursive( 584 fn update_recursive(
580 &mut self, 585 &mut self,
581 module_id: LocalModuleId, 586 module_id: LocalModuleId,
582 resolutions: &[(Name, PerNs)], 587 resolutions: &[(Option<Name>, PerNs)],
583 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
584 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
585 vis: Visibility, 590 vis: Visibility,
586 import_type: ImportType, 591 import_type: ImportType,
587 depth: usize, 592 depth: usize,
588 ) { 593 ) {
589 if depth > 100 { 594 if depth > GLOB_RECURSION_LIMIT {
590 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
591 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
592 } 597 }
593 let scope = &mut self.def_map.modules[module_id].scope;
594 let mut changed = false; 598 let mut changed = false;
599
595 for (name, res) in resolutions { 600 for (name, res) in resolutions {
596 changed |= scope.push_res_with_import( 601 match name {
597 &mut self.from_glob_import, 602 Some(name) => {
598 (module_id, name.clone()), 603 let scope = &mut self.def_map.modules[module_id].scope;
599 res.with_visibility(vis), 604 changed |= scope.push_res_with_import(
600 import_type, 605 &mut self.from_glob_import,
601 ); 606 (module_id, name.clone()),
607 res.with_visibility(vis),
608 import_type,
609 );
610 }
611 None => {
612 let tr = match res.take_types() {
613 Some(ModuleDefId::TraitId(tr)) => tr,
614 Some(other) => {
615 log::debug!("non-trait `_` import of {:?}", other);
616 continue;
617 }
618 None => continue,
619 };
620 let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621 let should_update = match old_vis {
622 None => true,
623 Some(old_vis) => {
624 let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625 panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626 });
627
628 if max_vis == old_vis {
629 false
630 } else {
631 mark::hit!(upgrade_underscore_visibility);
632 true
633 }
634 }
635 };
636
637 if should_update {
638 changed = true;
639 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640 }
641 }
642 }
602 } 643 }
603 644
604 if !changed { 645 if !changed {
@@ -609,14 +650,15 @@ impl DefCollector<'_> {
609 .get(&module_id) 650 .get(&module_id)
610 .into_iter() 651 .into_iter()
611 .flat_map(|v| v.iter()) 652 .flat_map(|v| v.iter())
653 .filter(|(glob_importing_module, _)| {
654 // we know all resolutions have the same visibility (`vis`), so we
655 // just need to check that once
656 vis.is_visible_from_def_map(&self.def_map, *glob_importing_module)
657 })
612 .cloned() 658 .cloned()
613 .collect::<Vec<_>>(); 659 .collect::<Vec<_>>();
660
614 for (glob_importing_module, glob_import_vis) in glob_imports { 661 for (glob_importing_module, glob_import_vis) in glob_imports {
615 // we know all resolutions have the same visibility (`vis`), so we
616 // just need to check that once
617 if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) {
618 continue;
619 }
620 self.update_recursive( 662 self.update_recursive(
621 glob_importing_module, 663 glob_importing_module,
622 resolutions, 664 resolutions,
@@ -677,10 +719,6 @@ impl DefCollector<'_> {
677 self.unexpanded_attribute_macros = attribute_macros; 719 self.unexpanded_attribute_macros = attribute_macros;
678 720
679 for (module_id, macro_call_id, depth) in resolved { 721 for (module_id, macro_call_id, depth) in resolved {
680 if depth > 1024 {
681 log::debug!("Max macro expansion depth reached");
682 continue;
683 }
684 self.collect_macro_expansion(module_id, macro_call_id, depth); 722 self.collect_macro_expansion(module_id, macro_call_id, depth);
685 } 723 }
686 724
@@ -717,6 +755,11 @@ impl DefCollector<'_> {
717 macro_call_id: MacroCallId, 755 macro_call_id: MacroCallId,
718 depth: usize, 756 depth: usize,
719 ) { 757 ) {
758 if depth > EXPANSION_DEPTH_LIMIT {
759 mark::hit!(macro_expansion_overflow);
760 log::warn!("macro expansion is too deep");
761 return;
762 }
720 let file_id: HirFileId = macro_call_id.as_file(); 763 let file_id: HirFileId = macro_call_id.as_file();
721 let item_tree = self.db.item_tree(file_id); 764 let item_tree = self.db.item_tree(file_id);
722 let mod_dir = self.mod_dirs[&module_id].clone(); 765 let mod_dir = self.mod_dirs[&module_id].clone();
@@ -943,7 +986,7 @@ impl ModCollector<'_, '_> {
943 .unwrap_or(Visibility::Public); 986 .unwrap_or(Visibility::Public);
944 self.def_collector.update( 987 self.def_collector.update(
945 self.module_id, 988 self.module_id,
946 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], 989 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
947 vis, 990 vis,
948 ImportType::Named, 991 ImportType::Named,
949 ) 992 )
@@ -1050,14 +1093,14 @@ impl ModCollector<'_, '_> {
1050 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1093 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1051 self.def_collector.update( 1094 self.def_collector.update(
1052 self.module_id, 1095 self.module_id,
1053 &[(name, PerNs::from_def(def, vis, false))], 1096 &[(Some(name), PerNs::from_def(def, vis, false))],
1054 vis, 1097 vis,
1055 ImportType::Named, 1098 ImportType::Named,
1056 ); 1099 );
1057 res 1100 res
1058 } 1101 }
1059 1102
1060 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) { 1103 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1061 for derive_subtree in attrs.by_key("derive").tt_values() { 1104 for derive_subtree in attrs.by_key("derive").tt_values() {
1062 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1105 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
1063 for tt in &derive_subtree.token_trees { 1106 for tt in &derive_subtree.token_trees {
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index 39e9a6d97..953961632 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -1,23 +1,24 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use hir_expand::name::Name; 2use hir_expand::name::Name;
3use ra_db::{FileId, RelativePathBuf}; 3use ra_db::FileId;
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5 5
6use crate::{db::DefDatabase, HirFileId}; 6use crate::{db::DefDatabase, HirFileId};
7 7
8#[derive(Clone, Debug)] 8#[derive(Clone, Debug)]
9pub(super) struct ModDir { 9pub(super) struct ModDir {
10 /// `.` for `mod.rs`, `lib.rs` 10 /// `` for `mod.rs`, `lib.rs`
11 /// `./foo` for `foo.rs` 11 /// `foo/` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` 12 /// `foo/bar/` for `mod bar { mod x; }` nested in `foo.rs`
13 path: RelativePathBuf, 13 /// Invariant: path.is_empty() || path.ends_with('/')
14 dir_path: DirPath,
14 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` 15 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
15 root_non_dir_owner: bool, 16 root_non_dir_owner: bool,
16} 17}
17 18
18impl ModDir { 19impl ModDir {
19 pub(super) fn root() -> ModDir { 20 pub(super) fn root() -> ModDir {
20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } 21 ModDir { dir_path: DirPath::empty(), root_non_dir_owner: false }
21 } 22 }
22 23
23 pub(super) fn descend_into_definition( 24 pub(super) fn descend_into_definition(
@@ -25,17 +26,21 @@ impl ModDir {
25 name: &Name, 26 name: &Name,
26 attr_path: Option<&SmolStr>, 27 attr_path: Option<&SmolStr>,
27 ) -> ModDir { 28 ) -> ModDir {
28 let mut path = self.path.clone(); 29 let path = match attr_path.map(|it| it.as_str()) {
29 match attr_to_path(attr_path) { 30 None => {
30 None => path.push(&name.to_string()), 31 let mut path = self.dir_path.clone();
32 path.push(&name.to_string());
33 path
34 }
31 Some(attr_path) => { 35 Some(attr_path) => {
32 if self.root_non_dir_owner { 36 let mut path = self.dir_path.join_attr(attr_path, self.root_non_dir_owner);
33 assert!(path.pop()); 37 if !(path.is_empty() || path.ends_with('/')) {
38 path.push('/')
34 } 39 }
35 path.push(attr_path); 40 DirPath::new(path)
36 } 41 }
37 } 42 };
38 ModDir { path, root_non_dir_owner: false } 43 ModDir { dir_path: path, root_non_dir_owner: false }
39 } 44 }
40 45
41 pub(super) fn resolve_declaration( 46 pub(super) fn resolve_declaration(
@@ -48,34 +53,87 @@ impl ModDir {
48 let file_id = file_id.original_file(db.upcast()); 53 let file_id = file_id.original_file(db.upcast());
49 54
50 let mut candidate_files = Vec::new(); 55 let mut candidate_files = Vec::new();
51 match attr_to_path(attr_path) { 56 match attr_path {
52 Some(attr_path) => { 57 Some(attr_path) => {
53 let base = 58 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
54 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path };
55 candidate_files.push(base.join(attr_path).to_string())
56 } 59 }
57 None => { 60 None => {
58 candidate_files.push(self.path.join(&format!("{}.rs", name)).to_string()); 61 candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
59 candidate_files.push(self.path.join(&format!("{}/mod.rs", name)).to_string()); 62 candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
60 } 63 }
61 }; 64 };
62 65
63 for candidate in candidate_files.iter() { 66 for candidate in candidate_files.iter() {
64 if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) { 67 if let Some(file_id) = db.resolve_path(file_id, candidate.as_str()) {
65 let mut root_non_dir_owner = false;
66 let mut mod_path = RelativePathBuf::new();
67 let is_mod_rs = candidate.ends_with("mod.rs"); 68 let is_mod_rs = candidate.ends_with("mod.rs");
68 if !(is_mod_rs || attr_path.is_some()) { 69
69 root_non_dir_owner = true; 70 let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
70 mod_path.push(&name.to_string()); 71 (DirPath::empty(), false)
71 } 72 } else {
72 return Ok((file_id, is_mod_rs, ModDir { path: mod_path, root_non_dir_owner })); 73 (DirPath::new(format!("{}/", name)), true)
74 };
75 return Ok((file_id, is_mod_rs, ModDir { dir_path, root_non_dir_owner }));
73 } 76 }
74 } 77 }
75 Err(candidate_files.remove(0)) 78 Err(candidate_files.remove(0))
76 } 79 }
77} 80}
78 81
79fn attr_to_path(attr: Option<&SmolStr>) -> Option<RelativePathBuf> { 82#[derive(Clone, Debug)]
80 attr.and_then(|it| RelativePathBuf::from_path(&it.replace("\\", "/")).ok()) 83struct DirPath(String);
84
85impl DirPath {
86 fn assert_invariant(&self) {
87 assert!(self.0.is_empty() || self.0.ends_with('/'));
88 }
89 fn new(repr: String) -> DirPath {
90 let res = DirPath(repr);
91 res.assert_invariant();
92 res
93 }
94 fn empty() -> DirPath {
95 DirPath::new(String::new())
96 }
97 fn push(&mut self, name: &str) {
98 self.0.push_str(name);
99 self.0.push('/');
100 self.assert_invariant();
101 }
102 fn parent(&self) -> Option<&str> {
103 if self.0.is_empty() {
104 return None;
105 };
106 let idx =
107 self.0[..self.0.len() - '/'.len_utf8()].rfind('/').map_or(0, |it| it + '/'.len_utf8());
108 Some(&self.0[..idx])
109 }
110 /// So this is the case which doesn't really work I think if we try to be
111 /// 100% platform agnostic:
112 ///
113 /// ```
114 /// mod a {
115 /// #[path="C://sad/face"]
116 /// mod b { mod c; }
117 /// }
118 /// ```
119 ///
120 /// Here, we need to join logical dir path to a string path from an
121 /// attribute. Ideally, we should somehow losslessly communicate the whole
122 /// construction to `FileLoader`.
123 fn join_attr(&self, mut attr: &str, relative_to_parent: bool) -> String {
124 let base = if relative_to_parent { self.parent().unwrap() } else { &self.0 };
125
126 if attr.starts_with("./") {
127 attr = &attr["./".len()..];
128 }
129 let tmp;
130 let attr = if attr.contains('\\') {
131 tmp = attr.replace('\\', "/");
132 &tmp
133 } else {
134 attr
135 };
136 let res = format!("{}{}", base, attr);
137 res
138 }
81} 139}
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 19692e70c..dbfa7fccb 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -226,7 +226,15 @@ impl CrateDefMap {
226 match enum_data.variant(&segment) { 226 match enum_data.variant(&segment) {
227 Some(local_id) => { 227 Some(local_id) => {
228 let variant = EnumVariantId { parent: e, local_id }; 228 let variant = EnumVariantId { parent: e, local_id };
229 PerNs::both(variant.into(), variant.into(), Visibility::Public) 229 match &*enum_data.variants[local_id].variant_data {
230 crate::adt::VariantData::Record(_) => {
231 PerNs::types(variant.into(), Visibility::Public)
232 }
233 crate::adt::VariantData::Tuple(_)
234 | crate::adt::VariantData::Unit => {
235 PerNs::both(variant.into(), variant.into(), Visibility::Public)
236 }
237 }
230 } 238 }
231 None => { 239 None => {
232 return ResolvePathResult::with( 240 return ResolvePathResult::with(
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 503099fb7..839b1de57 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -6,558 +6,531 @@ mod primitives;
6 6
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use expect::{expect, Expect};
10use ra_db::{fixture::WithFixture, SourceDatabase}; 10use ra_db::{fixture::WithFixture, SourceDatabase};
11use test_utils::mark; 11use test_utils::mark;
12 12
13use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
14 14
15fn def_map(ra_fixture: &str) -> String {
16 compute_crate_def_map(ra_fixture).dump()
17}
18
19fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { 15fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
20 let db = TestDB::with_files(fixture); 16 let db = TestDB::with_files(fixture);
21 let krate = db.crate_graph().iter().next().unwrap(); 17 let krate = db.crate_graph().iter().next().unwrap();
22 db.crate_def_map(krate) 18 db.crate_def_map(krate)
23} 19}
24 20
21fn check(ra_fixture: &str, expect: Expect) {
22 let db = TestDB::with_files(ra_fixture);
23 let krate = db.crate_graph().iter().next().unwrap();
24 let actual = db.crate_def_map(krate).dump();
25 expect.assert_eq(&actual);
26}
27
25#[test] 28#[test]
26fn crate_def_map_smoke_test() { 29fn crate_def_map_smoke_test() {
27 let map = def_map( 30 check(
28 r" 31 r#"
29 //- /lib.rs 32//- /lib.rs
30 mod foo; 33mod foo;
31 struct S; 34struct S;
32 use crate::foo::bar::E; 35use crate::foo::bar::E;
33 use self::E::V; 36use self::E::V;
34
35 //- /foo/mod.rs
36 pub mod bar;
37 fn f() {}
38
39 //- /foo/bar.rs
40 pub struct Baz;
41
42 union U {
43 to_be: bool,
44 not_to_be: u8,
45 }
46 37
47 enum E { V } 38//- /foo/mod.rs
39pub mod bar;
40fn f() {}
48 41
49 extern { 42//- /foo/bar.rs
50 static EXT: u8; 43pub struct Baz;
51 fn ext(); 44
52 } 45union U { to_be: bool, not_to_be: u8 }
53 ", 46enum E { V }
47
48extern {
49 static EXT: u8;
50 fn ext();
51}
52"#,
53 expect![[r#"
54 crate
55 E: t
56 S: t v
57 V: t v
58 foo: t
59
60 crate::foo
61 bar: t
62 f: v
63
64 crate::foo::bar
65 Baz: t v
66 E: t
67 EXT: v
68 U: t
69 ext: v
70 "#]],
54 ); 71 );
55 assert_snapshot!(map, @r###"
56 ⋮crate
57 ⋮E: t
58 ⋮S: t v
59 ⋮V: t v
60 ⋮foo: t
61
62 ⋮crate::foo
63 ⋮bar: t
64 ⋮f: v
65
66 ⋮crate::foo::bar
67 ⋮Baz: t v
68 ⋮E: t
69 ⋮EXT: v
70 ⋮U: t
71 ⋮ext: v
72 "###)
73} 72}
74 73
75#[test] 74#[test]
76fn crate_def_map_super_super() { 75fn crate_def_map_super_super() {
77 let map = def_map( 76 check(
78 " 77 r#"
79 //- /lib.rs 78mod a {
80 mod a { 79 const A: usize = 0;
81 const A: usize = 0; 80 mod b {
82 81 const B: usize = 0;
83 mod b { 82 mod c {
84 const B: usize = 0; 83 use super::super::*;
85
86 mod c {
87 use super::super::*;
88 }
89 }
90 } 84 }
91 ", 85 }
86}
87"#,
88 expect![[r#"
89 crate
90 a: t
91
92 crate::a
93 A: v
94 b: t
95
96 crate::a::b
97 B: v
98 c: t
99
100 crate::a::b::c
101 A: v
102 b: t
103 "#]],
92 ); 104 );
93 assert_snapshot!(map, @r###"
94 ⋮crate
95 ⋮a: t
96
97 ⋮crate::a
98 ⋮A: v
99 ⋮b: t
100
101 ⋮crate::a::b
102 ⋮B: v
103 ⋮c: t
104
105 ⋮crate::a::b::c
106 ⋮A: v
107 ⋮b: t
108 "###)
109} 105}
110 106
111#[test] 107#[test]
112fn crate_def_map_fn_mod_same_name() { 108fn crate_def_map_fn_mod_same_name() {
113 let map = def_map( 109 check(
114 " 110 r#"
115 //- /lib.rs 111mod m {
116 mod m { 112 pub mod z {}
117 pub mod z {} 113 pub fn z() {}
118 pub fn z() {} 114}
119 } 115"#,
120 ", 116 expect![[r#"
117 crate
118 m: t
119
120 crate::m
121 z: t v
122
123 crate::m::z
124 "#]],
121 ); 125 );
122 assert_snapshot!(map, @r###"
123 ⋮crate
124 ⋮m: t
125
126 ⋮crate::m
127 ⋮z: t v
128
129 ⋮crate::m::z
130 "###)
131} 126}
132 127
133#[test] 128#[test]
134fn bogus_paths() { 129fn bogus_paths() {
135 mark::check!(bogus_paths); 130 mark::check!(bogus_paths);
136 let map = def_map( 131 check(
137 " 132 r#"
138 //- /lib.rs 133//- /lib.rs
139 mod foo; 134mod foo;
140 struct S; 135struct S;
141 use self; 136use self;
142 137
143 //- /foo/mod.rs 138//- /foo/mod.rs
144 use super; 139use super;
145 use crate; 140use crate;
146 141"#,
147 ", 142 expect![[r#"
143 crate
144 S: t v
145 foo: t
146
147 crate::foo
148 "#]],
148 ); 149 );
149 assert_snapshot!(map, @r###"
150 ⋮crate
151 ⋮S: t v
152 ⋮foo: t
153
154 ⋮crate::foo
155 "###
156 )
157} 150}
158 151
159#[test] 152#[test]
160fn use_as() { 153fn use_as() {
161 let map = def_map( 154 check(
162 " 155 r#"
163 //- /lib.rs 156//- /lib.rs
164 mod foo; 157mod foo;
165 158use crate::foo::Baz as Foo;
166 use crate::foo::Baz as Foo;
167 159
168 //- /foo/mod.rs 160//- /foo/mod.rs
169 pub struct Baz; 161pub struct Baz;
170 ", 162"#,
171 ); 163 expect![[r#"
172 assert_snapshot!(map, 164 crate
173 @r###" 165 Foo: t v
174 ⋮crate 166 foo: t
175 ⋮Foo: t v 167
176 ⋮foo: t 168 crate::foo
177 169 Baz: t v
178 ⋮crate::foo 170 "#]],
179 ⋮Baz: t v
180 "###
181 ); 171 );
182} 172}
183 173
184#[test] 174#[test]
185fn use_trees() { 175fn use_trees() {
186 let map = def_map( 176 check(
187 " 177 r#"
188 //- /lib.rs 178//- /lib.rs
189 mod foo; 179mod foo;
190 180use crate::foo::bar::{Baz, Quux};
191 use crate::foo::bar::{Baz, Quux};
192 181
193 //- /foo/mod.rs 182//- /foo/mod.rs
194 pub mod bar; 183pub mod bar;
195 184
196 //- /foo/bar.rs 185//- /foo/bar.rs
197 pub struct Baz; 186pub struct Baz;
198 pub enum Quux {}; 187pub enum Quux {};
199 ", 188"#,
189 expect![[r#"
190 crate
191 Baz: t v
192 Quux: t
193 foo: t
194
195 crate::foo
196 bar: t
197
198 crate::foo::bar
199 Baz: t v
200 Quux: t
201 "#]],
200 ); 202 );
201 assert_snapshot!(map, @r###"
202 ⋮crate
203 ⋮Baz: t v
204 ⋮Quux: t
205 ⋮foo: t
206
207 ⋮crate::foo
208 ⋮bar: t
209
210 ⋮crate::foo::bar
211 ⋮Baz: t v
212 ⋮Quux: t
213 "###);
214} 203}
215 204
216#[test] 205#[test]
217fn re_exports() { 206fn re_exports() {
218 let map = def_map( 207 check(
219 " 208 r#"
220 //- /lib.rs 209//- /lib.rs
221 mod foo; 210mod foo;
222 211use self::foo::Baz;
223 use self::foo::Baz;
224
225 //- /foo/mod.rs
226 pub mod bar;
227 212
228 pub use self::bar::Baz; 213//- /foo/mod.rs
214pub mod bar;
215pub use self::bar::Baz;
229 216
230 //- /foo/bar.rs 217//- /foo/bar.rs
231 pub struct Baz; 218pub struct Baz;
232 ", 219"#,
220 expect![[r#"
221 crate
222 Baz: t v
223 foo: t
224
225 crate::foo
226 Baz: t v
227 bar: t
228
229 crate::foo::bar
230 Baz: t v
231 "#]],
233 ); 232 );
234 assert_snapshot!(map, @r###"
235 ⋮crate
236 ⋮Baz: t v
237 ⋮foo: t
238
239 ⋮crate::foo
240 ⋮Baz: t v
241 ⋮bar: t
242
243 ⋮crate::foo::bar
244 ⋮Baz: t v
245 "###);
246} 233}
247 234
248#[test] 235#[test]
249fn std_prelude() { 236fn std_prelude() {
250 mark::check!(std_prelude); 237 mark::check!(std_prelude);
251 let map = def_map( 238 check(
252 " 239 r#"
253 //- /main.rs crate:main deps:test_crate 240//- /main.rs crate:main deps:test_crate
254 use Foo::*; 241use Foo::*;
255 242
256 //- /lib.rs crate:test_crate 243//- /lib.rs crate:test_crate
257 mod prelude; 244mod prelude;
258 #[prelude_import] 245#[prelude_import]
259 use prelude::*; 246use prelude::*;
260 247
261 //- /prelude.rs 248//- /prelude.rs
262 pub enum Foo { Bar, Baz }; 249pub enum Foo { Bar, Baz };
263 ", 250"#,
251 expect![[r#"
252 crate
253 Bar: t v
254 Baz: t v
255 "#]],
264 ); 256 );
265 assert_snapshot!(map, @r###"
266 ⋮crate
267 ⋮Bar: t v
268 ⋮Baz: t v
269 "###);
270} 257}
271 258
272#[test] 259#[test]
273fn can_import_enum_variant() { 260fn can_import_enum_variant() {
274 mark::check!(can_import_enum_variant); 261 mark::check!(can_import_enum_variant);
275 let map = def_map( 262 check(
276 " 263 r#"
277 //- /lib.rs 264enum E { V }
278 enum E { V } 265use self::E::V;
279 use self::E::V; 266"#,
280 ", 267 expect![[r#"
281 ); 268 crate
282 assert_snapshot!(map, @r###" 269 E: t
283 ⋮crate 270 V: t v
284 ⋮E: t 271 "#]],
285 ⋮V: t v
286 "###
287 ); 272 );
288} 273}
289 274
290#[test] 275#[test]
291fn edition_2015_imports() { 276fn edition_2015_imports() {
292 let map = def_map( 277 check(
293 " 278 r#"
294 //- /main.rs crate:main deps:other_crate edition:2015 279//- /main.rs crate:main deps:other_crate edition:2015
295 mod foo; 280mod foo;
296 mod bar; 281mod bar;
297
298 //- /bar.rs
299 struct Bar;
300
301 //- /foo.rs
302 use bar::Bar;
303 use other_crate::FromLib;
304
305 //- /lib.rs crate:other_crate edition:2018
306 struct FromLib;
307 ",
308 );
309 282
310 assert_snapshot!(map, @r###" 283//- /bar.rs
311 ⋮crate 284struct Bar;
312 ⋮bar: t 285
313 ⋮foo: t 286//- /foo.rs
314 287use bar::Bar;
315 ⋮crate::bar 288use other_crate::FromLib;
316 ⋮Bar: t v 289
317 290//- /lib.rs crate:other_crate edition:2018
318 ⋮crate::foo 291struct FromLib;
319 ⋮Bar: t v 292"#,
320 ⋮FromLib: t v 293 expect![[r#"
321 "###); 294 crate
295 bar: t
296 foo: t
297
298 crate::bar
299 Bar: t v
300
301 crate::foo
302 Bar: t v
303 FromLib: t v
304 "#]],
305 );
322} 306}
323 307
324#[test] 308#[test]
325fn item_map_using_self() { 309fn item_map_using_self() {
326 let map = def_map( 310 check(
327 " 311 r#"
328 //- /lib.rs 312//- /lib.rs
329 mod foo; 313mod foo;
330 use crate::foo::bar::Baz::{self}; 314use crate::foo::bar::Baz::{self};
331 //- /foo/mod.rs 315
332 pub mod bar; 316//- /foo/mod.rs
333 //- /foo/bar.rs 317pub mod bar;
334 pub struct Baz; 318
335 ", 319//- /foo/bar.rs
320pub struct Baz;
321"#,
322 expect![[r#"
323 crate
324 Baz: t v
325 foo: t
326
327 crate::foo
328 bar: t
329
330 crate::foo::bar
331 Baz: t v
332 "#]],
336 ); 333 );
337 assert_snapshot!(map, @r###"
338 ⋮crate
339 ⋮Baz: t v
340 ⋮foo: t
341
342 ⋮crate::foo
343 ⋮bar: t
344
345 ⋮crate::foo::bar
346 ⋮Baz: t v
347 "###);
348} 334}
349 335
350#[test] 336#[test]
351fn item_map_across_crates() { 337fn item_map_across_crates() {
352 let map = def_map( 338 check(
353 " 339 r#"
354 //- /main.rs crate:main deps:test_crate 340//- /main.rs crate:main deps:test_crate
355 use test_crate::Baz; 341use test_crate::Baz;
356
357 //- /lib.rs crate:test_crate
358 pub struct Baz;
359 ",
360 );
361 342
362 assert_snapshot!(map, @r###" 343//- /lib.rs crate:test_crate
363 ⋮crate 344pub struct Baz;
364 ⋮Baz: t v 345"#,
365 "###); 346 expect![[r#"
347 crate
348 Baz: t v
349 "#]],
350 );
366} 351}
367 352
368#[test] 353#[test]
369fn extern_crate_rename() { 354fn extern_crate_rename() {
370 let map = def_map( 355 check(
371 " 356 r#"
372 //- /main.rs crate:main deps:alloc 357//- /main.rs crate:main deps:alloc
373 extern crate alloc as alloc_crate; 358extern crate alloc as alloc_crate;
374 359mod alloc;
375 mod alloc; 360mod sync;
376 mod sync;
377 361
378 //- /sync.rs 362//- /sync.rs
379 use alloc_crate::Arc; 363use alloc_crate::Arc;
380 364
381 //- /lib.rs crate:alloc 365//- /lib.rs crate:alloc
382 struct Arc; 366struct Arc;
383 ", 367"#,
368 expect![[r#"
369 crate
370 alloc_crate: t
371 sync: t
372
373 crate::sync
374 Arc: t v
375 "#]],
384 ); 376 );
385
386 assert_snapshot!(map, @r###"
387 ⋮crate
388 ⋮alloc_crate: t
389 ⋮sync: t
390
391 ⋮crate::sync
392 ⋮Arc: t v
393 "###);
394} 377}
395 378
396#[test] 379#[test]
397fn extern_crate_rename_2015_edition() { 380fn extern_crate_rename_2015_edition() {
398 let map = def_map( 381 check(
399 " 382 r#"
400 //- /main.rs crate:main deps:alloc edition:2015 383//- /main.rs crate:main deps:alloc edition:2015
401 extern crate alloc as alloc_crate; 384extern crate alloc as alloc_crate;
402 385mod alloc;
403 mod alloc; 386mod sync;
404 mod sync;
405
406 //- /sync.rs
407 use alloc_crate::Arc;
408 387
409 //- /lib.rs crate:alloc 388//- /sync.rs
410 struct Arc; 389use alloc_crate::Arc;
411 ",
412 );
413 390
414 assert_snapshot!(map, 391//- /lib.rs crate:alloc
415 @r###" 392struct Arc;
416 ⋮crate 393"#,
417 ⋮alloc_crate: t 394 expect![[r#"
418 ⋮sync: t 395 crate
419 396 alloc_crate: t
420 ⋮crate::sync 397 sync: t
421 ⋮Arc: t v 398
422 "### 399 crate::sync
400 Arc: t v
401 "#]],
423 ); 402 );
424} 403}
425 404
426#[test] 405#[test]
427fn reexport_across_crates() { 406fn reexport_across_crates() {
428 let map = def_map( 407 check(
429 " 408 r#"
430 //- /main.rs crate:main deps:test_crate 409//- /main.rs crate:main deps:test_crate
431 use test_crate::Baz; 410use test_crate::Baz;
432
433 //- /lib.rs crate:test_crate
434 pub use foo::Baz;
435 411
436 mod foo; 412//- /lib.rs crate:test_crate
413pub use foo::Baz;
414mod foo;
437 415
438 //- /foo.rs 416//- /foo.rs
439 pub struct Baz; 417pub struct Baz;
440 ", 418"#,
419 expect![[r#"
420 crate
421 Baz: t v
422 "#]],
441 ); 423 );
442
443 assert_snapshot!(map, @r###"
444 ⋮crate
445 ⋮Baz: t v
446 "###);
447} 424}
448 425
449#[test] 426#[test]
450fn values_dont_shadow_extern_crates() { 427fn values_dont_shadow_extern_crates() {
451 let map = def_map( 428 check(
452 " 429 r#"
453 //- /main.rs crate:main deps:foo 430//- /main.rs crate:main deps:foo
454 fn foo() {} 431fn foo() {}
455 use foo::Bar; 432use foo::Bar;
456
457 //- /foo/lib.rs crate:foo
458 pub struct Bar;
459 ",
460 );
461 433
462 assert_snapshot!(map, @r###" 434//- /foo/lib.rs crate:foo
463 ⋮crate 435pub struct Bar;
464 ⋮Bar: t v 436"#,
465 ⋮foo: v 437 expect![[r#"
466 "###); 438 crate
439 Bar: t v
440 foo: v
441 "#]],
442 );
467} 443}
468 444
469#[test] 445#[test]
470fn std_prelude_takes_precedence_above_core_prelude() { 446fn std_prelude_takes_precedence_above_core_prelude() {
471 let map = def_map( 447 check(
472 r#" 448 r#"
473 //- /main.rs crate:main deps:core,std 449//- /main.rs crate:main deps:core,std
474 use {Foo, Bar}; 450use {Foo, Bar};
475 451
476 //- /std.rs crate:std deps:core 452//- /std.rs crate:std deps:core
477 #[prelude_import] 453#[prelude_import]
478 pub use self::prelude::*; 454pub use self::prelude::*;
479 mod prelude { 455mod prelude {
480 pub struct Foo; 456 pub struct Foo;
481 pub use core::prelude::Bar; 457 pub use core::prelude::Bar;
482 } 458}
483 459
484 //- /core.rs crate:core 460//- /core.rs crate:core
485 #[prelude_import] 461#[prelude_import]
486 pub use self::prelude::*; 462pub use self::prelude::*;
487 mod prelude { 463mod prelude {
488 pub struct Bar; 464 pub struct Bar;
489 } 465}
490 "#, 466"#,
467 expect![[r#"
468 crate
469 Bar: t v
470 Foo: t v
471 "#]],
491 ); 472 );
492
493 assert_snapshot!(map, @r###"
494 ⋮crate
495 ⋮Bar: t v
496 ⋮Foo: t v
497 "###);
498} 473}
499 474
500#[test] 475#[test]
501fn cfg_not_test() { 476fn cfg_not_test() {
502 let map = def_map( 477 check(
503 r#" 478 r#"
504 //- /main.rs crate:main deps:std 479//- /main.rs crate:main deps:std
505 use {Foo, Bar, Baz}; 480use {Foo, Bar, Baz};
506 481
507 //- /lib.rs crate:std 482//- /lib.rs crate:std
508 #[prelude_import] 483#[prelude_import]
509 pub use self::prelude::*; 484pub use self::prelude::*;
510 mod prelude { 485mod prelude {
511 #[cfg(test)] 486 #[cfg(test)]
512 pub struct Foo; 487 pub struct Foo;
513 #[cfg(not(test))] 488 #[cfg(not(test))]
514 pub struct Bar; 489 pub struct Bar;
515 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] 490 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
516 pub struct Baz; 491 pub struct Baz;
517 } 492}
518 "#, 493"#,
494 expect![[r#"
495 crate
496 Bar: t v
497 Baz: _
498 Foo: _
499 "#]],
519 ); 500 );
520
521 assert_snapshot!(map, @r###"
522 ⋮crate
523 ⋮Bar: t v
524 ⋮Baz: _
525 ⋮Foo: _
526 "###);
527} 501}
528 502
529#[test] 503#[test]
530fn cfg_test() { 504fn cfg_test() {
531 let map = def_map( 505 check(
532 r#" 506 r#"
533 //- /main.rs crate:main deps:std 507//- /main.rs crate:main deps:std
534 use {Foo, Bar, Baz}; 508use {Foo, Bar, Baz};
535 509
536 //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 510//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
537 #[prelude_import] 511#[prelude_import]
538 pub use self::prelude::*; 512pub use self::prelude::*;
539 mod prelude { 513mod prelude {
540 #[cfg(test)] 514 #[cfg(test)]
541 pub struct Foo; 515 pub struct Foo;
542 #[cfg(not(test))] 516 #[cfg(not(test))]
543 pub struct Bar; 517 pub struct Bar;
544 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] 518 #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))]
545 pub struct Baz; 519 pub struct Baz;
546 } 520}
547 "#, 521"#,
522 expect![[r#"
523 crate
524 Bar: _
525 Baz: t v
526 Foo: t v
527 "#]],
548 ); 528 );
549
550 assert_snapshot!(map, @r###"
551 ⋮crate
552 ⋮Bar: _
553 ⋮Baz: t v
554 ⋮Foo: t v
555 "###);
556} 529}
557 530
558#[test] 531#[test]
559fn infer_multiple_namespace() { 532fn infer_multiple_namespace() {
560 let map = def_map( 533 check(
561 r#" 534 r#"
562//- /main.rs 535//- /main.rs
563mod a { 536mod a {
@@ -571,18 +544,147 @@ mod b {
571 pub const T: () = (); 544 pub const T: () = ();
572} 545}
573"#, 546"#,
547 expect![[r#"
548 crate
549 T: t v
550 a: t
551 b: t
552
553 crate::b
554 T: v
555
556 crate::a
557 T: t v
558 "#]],
559 );
560}
561
562#[test]
563fn underscore_import() {
564 check(
565 r#"
566//- /main.rs
567use tr::Tr as _;
568use tr::Tr2 as _;
569
570mod tr {
571 pub trait Tr {}
572 pub trait Tr2 {}
573}
574 "#,
575 expect![[r#"
576 crate
577 _: t
578 _: t
579 tr: t
580
581 crate::tr
582 Tr: t
583 Tr2: t
584 "#]],
585 );
586}
587
588#[test]
589fn underscore_reexport() {
590 check(
591 r#"
592//- /main.rs
593mod tr {
594 pub trait PubTr {}
595 pub trait PrivTr {}
596}
597mod reex {
598 use crate::tr::PrivTr as _;
599 pub use crate::tr::PubTr as _;
600}
601use crate::reex::*;
602 "#,
603 expect![[r#"
604 crate
605 _: t
606 reex: t
607 tr: t
608
609 crate::tr
610 PrivTr: t
611 PubTr: t
612
613 crate::reex
614 _: t
615 _: t
616 "#]],
617 );
618}
619
620#[test]
621fn underscore_pub_crate_reexport() {
622 mark::check!(upgrade_underscore_visibility);
623 check(
624 r#"
625//- /main.rs crate:main deps:lib
626use lib::*;
627
628//- /lib.rs crate:lib
629use tr::Tr as _;
630pub use tr::Tr as _;
631
632mod tr {
633 pub trait Tr {}
634}
635 "#,
636 expect![[r#"
637 crate
638 _: t
639 "#]],
640 );
641}
642
643#[test]
644fn underscore_nontrait() {
645 check(
646 r#"
647//- /main.rs
648mod m {
649 pub struct Struct;
650 pub enum Enum {}
651 pub const CONST: () = ();
652}
653use crate::m::{Struct as _, Enum as _, CONST as _};
654 "#,
655 expect![[r#"
656 crate
657 m: t
658
659 crate::m
660 CONST: v
661 Enum: t
662 Struct: t v
663 "#]],
574 ); 664 );
665}
666
667#[test]
668fn underscore_name_conflict() {
669 check(
670 r#"
671//- /main.rs
672struct Tr;
673
674use tr::Tr as _;
575 675
576 assert_snapshot!(map, @r###" 676mod tr {
577 ⋮crate 677 pub trait Tr {}
578 ⋮T: t v 678}
579 ⋮a: t 679 "#,
580 ⋮b: t 680 expect![[r#"
581 681 crate
582 ⋮crate::b 682 _: t
583 ⋮T: v 683 Tr: t v
584 684 tr: t
585 ⋮crate::a 685
586 ⋮T: t v 686 crate::tr
587"###); 687 Tr: t
688 "#]],
689 );
588} 690}
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 7f3d7509c..2ae836e3c 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -2,367 +2,337 @@ use super::*;
2 2
3#[test] 3#[test]
4fn glob_1() { 4fn glob_1() {
5 let map = def_map( 5 check(
6 r" 6 r#"
7 //- /lib.rs 7//- /lib.rs
8 mod foo; 8mod foo;
9 use foo::*; 9use foo::*;
10 10
11 //- /foo/mod.rs 11//- /foo/mod.rs
12 pub mod bar; 12pub mod bar;
13 pub use self::bar::Baz; 13pub use self::bar::Baz;
14 pub struct Foo; 14pub struct Foo;
15 15
16 //- /foo/bar.rs 16//- /foo/bar.rs
17 pub struct Baz; 17pub struct Baz;
18 ", 18"#,
19 ); 19 expect![[r#"
20 assert_snapshot!(map, @r###" 20 crate
21 ⋮crate 21 Baz: t v
22 ⋮Baz: t v 22 Foo: t v
23 ⋮Foo: t v 23 bar: t
24 ⋮bar: t 24 foo: t
25 ⋮foo: t 25
26 26 crate::foo
27 ⋮crate::foo 27 Baz: t v
28 ⋮Baz: t v 28 Foo: t v
29 ⋮Foo: t v 29 bar: t
30 ⋮bar: t 30
31 31 crate::foo::bar
32 ⋮crate::foo::bar 32 Baz: t v
33 ⋮Baz: t v 33 "#]],
34 "###
35 ); 34 );
36} 35}
37 36
38#[test] 37#[test]
39fn glob_2() { 38fn glob_2() {
40 let map = def_map( 39 check(
41 " 40 r#"
42 //- /lib.rs 41//- /lib.rs
43 mod foo; 42mod foo;
44 use foo::*; 43use foo::*;
45 44
46 //- /foo/mod.rs 45//- /foo/mod.rs
47 pub mod bar; 46pub mod bar;
48 pub use self::bar::*; 47pub use self::bar::*;
49 pub struct Foo; 48pub struct Foo;
50 49
51 //- /foo/bar.rs 50//- /foo/bar.rs
52 pub struct Baz; 51pub struct Baz;
53 pub use super::*; 52pub use super::*;
54 ", 53"#,
55 ); 54 expect![[r#"
56 assert_snapshot!(map, @r###" 55 crate
57 ⋮crate 56 Baz: t v
58 ⋮Baz: t v 57 Foo: t v
59 ⋮Foo: t v 58 bar: t
60 ⋮bar: t 59 foo: t
61 ⋮foo: t 60
62 61 crate::foo
63 ⋮crate::foo 62 Baz: t v
64 ⋮Baz: t v 63 Foo: t v
65 ⋮Foo: t v 64 bar: t
66 ⋮bar: t 65
67 66 crate::foo::bar
68 ⋮crate::foo::bar 67 Baz: t v
69 ⋮Baz: t v 68 Foo: t v
70 ⋮Foo: t v 69 bar: t
71 ⋮bar: t 70 "#]],
72 "###
73 ); 71 );
74} 72}
75 73
76#[test] 74#[test]
77fn glob_privacy_1() { 75fn glob_privacy_1() {
78 let map = def_map( 76 check(
79 r" 77 r"
80 //- /lib.rs 78//- /lib.rs
81 mod foo; 79mod foo;
82 use foo::*; 80use foo::*;
83 81
84 //- /foo/mod.rs 82//- /foo/mod.rs
85 pub mod bar; 83pub mod bar;
86 pub use self::bar::*; 84pub use self::bar::*;
87 struct PrivateStructFoo; 85struct PrivateStructFoo;
88 86
89 //- /foo/bar.rs 87//- /foo/bar.rs
90 pub struct Baz; 88pub struct Baz;
91 struct PrivateStructBar; 89struct PrivateStructBar;
92 pub use super::*; 90pub use super::*;
93 ", 91",
94 ); 92 expect![[r#"
95 assert_snapshot!(map, @r###" 93 crate
96 ⋮crate 94 Baz: t v
97 ⋮Baz: t v 95 bar: t
98 ⋮bar: t 96 foo: t
99 ⋮foo: t 97
100 98 crate::foo
101 ⋮crate::foo 99 Baz: t v
102 ⋮Baz: t v 100 PrivateStructFoo: t v
103 ⋮PrivateStructFoo: t v 101 bar: t
104 ⋮bar: t 102
105 103 crate::foo::bar
106 ⋮crate::foo::bar 104 Baz: t v
107 ⋮Baz: t v 105 PrivateStructBar: t v
108 ⋮PrivateStructBar: t v 106 PrivateStructFoo: t v
109 ⋮PrivateStructFoo: t v 107 bar: t
110 ⋮bar: t 108 "#]],
111 "###
112 ); 109 );
113} 110}
114 111
115#[test] 112#[test]
116fn glob_privacy_2() { 113fn glob_privacy_2() {
117 let map = def_map( 114 check(
118 r" 115 r"
119 //- /lib.rs 116//- /lib.rs
120 mod foo; 117mod foo;
121 use foo::*; 118use foo::*;
122 use foo::bar::*; 119use foo::bar::*;
123 120
124 //- /foo/mod.rs 121//- /foo/mod.rs
125 mod bar; 122mod bar;
126 fn Foo() {}; 123fn Foo() {};
127 pub struct Foo {}; 124pub struct Foo {};
128 125
129 //- /foo/bar.rs 126//- /foo/bar.rs
130 pub(super) struct PrivateBaz; 127pub(super) struct PrivateBaz;
131 struct PrivateBar; 128struct PrivateBar;
132 pub(crate) struct PubCrateStruct; 129pub(crate) struct PubCrateStruct;
133 ", 130",
134 ); 131 expect![[r#"
135 assert_snapshot!(map, @r###" 132 crate
136 ⋮crate 133 Foo: t
137 ⋮Foo: t 134 PubCrateStruct: t v
138 ⋮PubCrateStruct: t v 135 foo: t
139 ⋮foo: t 136
140 137 crate::foo
141 ⋮crate::foo 138 Foo: t v
142 ⋮Foo: t v 139 bar: t
143 ⋮bar: t 140
144 141 crate::foo::bar
145 ⋮crate::foo::bar 142 PrivateBar: t v
146 ⋮PrivateBar: t v 143 PrivateBaz: t v
147 ⋮PrivateBaz: t v 144 PubCrateStruct: t v
148 ⋮PubCrateStruct: t v 145 "#]],
149 "###
150 ); 146 );
151} 147}
152 148
153#[test] 149#[test]
154fn glob_across_crates() { 150fn glob_across_crates() {
155 mark::check!(glob_across_crates); 151 mark::check!(glob_across_crates);
156 let map = def_map( 152 check(
157 r" 153 r#"
158 //- /main.rs crate:main deps:test_crate 154//- /main.rs crate:main deps:test_crate
159 use test_crate::*; 155use test_crate::*;
160 156
161 //- /lib.rs crate:test_crate 157//- /lib.rs crate:test_crate
162 pub struct Baz; 158pub struct Baz;
163 ", 159"#,
164 ); 160 expect![[r#"
165 assert_snapshot!(map, @r###" 161 crate
166 ⋮crate 162 Baz: t v
167 ⋮Baz: t v 163 "#]],
168 "###
169 ); 164 );
170} 165}
171 166
172#[test] 167#[test]
173fn glob_privacy_across_crates() { 168fn glob_privacy_across_crates() {
174 let map = def_map( 169 check(
175 r" 170 r#"
176 //- /main.rs crate:main deps:test_crate 171//- /main.rs crate:main deps:test_crate
177 use test_crate::*; 172use test_crate::*;
178 173
179 //- /lib.rs crate:test_crate 174//- /lib.rs crate:test_crate
180 pub struct Baz; 175pub struct Baz;
181 struct Foo; 176struct Foo;
182 ", 177"#,
183 ); 178 expect![[r#"
184 assert_snapshot!(map, @r###" 179 crate
185 ⋮crate 180 Baz: t v
186 ⋮Baz: t v 181 "#]],
187 "###
188 ); 182 );
189} 183}
190 184
191#[test] 185#[test]
192fn glob_enum() { 186fn glob_enum() {
193 mark::check!(glob_enum); 187 mark::check!(glob_enum);
194 let map = def_map( 188 check(
195 " 189 r#"
196 //- /lib.rs 190enum Foo { Bar, Baz }
197 enum Foo { 191use self::Foo::*;
198 Bar, Baz 192"#,
199 } 193 expect![[r#"
200 use self::Foo::*; 194 crate
201 ", 195 Bar: t v
202 ); 196 Baz: t v
203 assert_snapshot!(map, @r###" 197 Foo: t
204 ⋮crate 198 "#]],
205 ⋮Bar: t v
206 ⋮Baz: t v
207 ⋮Foo: t
208 "###
209 ); 199 );
210} 200}
211 201
212#[test] 202#[test]
213fn glob_enum_group() { 203fn glob_enum_group() {
214 mark::check!(glob_enum_group); 204 mark::check!(glob_enum_group);
215 let map = def_map( 205 check(
216 r" 206 r#"
217 //- /lib.rs 207enum Foo { Bar, Baz }
218 enum Foo { 208use self::Foo::{*};
219 Bar, Baz 209"#,
220 } 210 expect![[r#"
221 use self::Foo::{*}; 211 crate
222 ", 212 Bar: t v
223 ); 213 Baz: t v
224 assert_snapshot!(map, @r###" 214 Foo: t
225 ⋮crate 215 "#]],
226 ⋮Bar: t v
227 ⋮Baz: t v
228 ⋮Foo: t
229 "###
230 ); 216 );
231} 217}
232 218
233#[test] 219#[test]
234fn glob_shadowed_def() { 220fn glob_shadowed_def() {
235 mark::check!(import_shadowed); 221 mark::check!(import_shadowed);
236 let map = def_map( 222 check(
237 r###" 223 r#"
238 //- /lib.rs 224//- /lib.rs
239 mod foo; 225mod foo;
240 mod bar; 226mod bar;
241 227use foo::*;
242 use foo::*; 228use bar::baz;
243 use bar::baz; 229use baz::Bar;
244 230
245 use baz::Bar; 231//- /foo.rs
246 232pub mod baz { pub struct Foo; }
247 //- /foo.rs 233
248 pub mod baz { 234//- /bar.rs
249 pub struct Foo; 235pub mod baz { pub struct Bar; }
250 } 236"#,
251 237 expect![[r#"
252 //- /bar.rs 238 crate
253 pub mod baz { 239 Bar: t v
254 pub struct Bar; 240 bar: t
255 } 241 baz: t
256 "###, 242 foo: t
257 ); 243
258 assert_snapshot!(map, @r###" 244 crate::bar
259 ⋮crate 245 baz: t
260 ⋮Bar: t v 246
261 ⋮bar: t 247 crate::bar::baz
262 ⋮baz: t 248 Bar: t v
263 ⋮foo: t 249
264 250 crate::foo
265 ⋮crate::bar 251 baz: t
266 ⋮baz: t 252
267 253 crate::foo::baz
268 ⋮crate::bar::baz 254 Foo: t v
269 ⋮Bar: t v 255 "#]],
270
271 ⋮crate::foo
272 ⋮baz: t
273
274 ⋮crate::foo::baz
275 ⋮Foo: t v
276 "###
277 ); 256 );
278} 257}
279 258
280#[test] 259#[test]
281fn glob_shadowed_def_reversed() { 260fn glob_shadowed_def_reversed() {
282 let map = def_map( 261 check(
283 r###" 262 r#"
284 //- /lib.rs 263//- /lib.rs
285 mod foo; 264mod foo;
286 mod bar; 265mod bar;
287 266use bar::baz;
288 use bar::baz; 267use foo::*;
289 use foo::*; 268use baz::Bar;
290 269
291 use baz::Bar; 270//- /foo.rs
292 271pub mod baz { pub struct Foo; }
293 //- /foo.rs 272
294 pub mod baz { 273//- /bar.rs
295 pub struct Foo; 274pub mod baz { pub struct Bar; }
296 } 275"#,
297 276 expect![[r#"
298 //- /bar.rs 277 crate
299 pub mod baz { 278 Bar: t v
300 pub struct Bar; 279 bar: t
301 } 280 baz: t
302 "###, 281 foo: t
303 ); 282
304 assert_snapshot!(map, @r###" 283 crate::bar
305 ⋮crate 284 baz: t
306 ⋮Bar: t v 285
307 ⋮bar: t 286 crate::bar::baz
308 ⋮baz: t 287 Bar: t v
309 ⋮foo: t 288
310 289 crate::foo
311 ⋮crate::bar 290 baz: t
312 ⋮baz: t 291
313 292 crate::foo::baz
314 ⋮crate::bar::baz 293 Foo: t v
315 ⋮Bar: t v 294 "#]],
316
317 ⋮crate::foo
318 ⋮baz: t
319
320 ⋮crate::foo::baz
321 ⋮Foo: t v
322 "###
323 ); 295 );
324} 296}
325 297
326#[test] 298#[test]
327fn glob_shadowed_def_dependencies() { 299fn glob_shadowed_def_dependencies() {
328 let map = def_map( 300 check(
329 r###" 301 r#"
330 //- /lib.rs 302mod a { pub mod foo { pub struct X; } }
331 mod a { pub mod foo { pub struct X; } } 303mod b { pub use super::a::foo; }
332 mod b { pub use super::a::foo; } 304mod c { pub mod foo { pub struct Y; } }
333 mod c { pub mod foo { pub struct Y; } } 305mod d {
334 mod d { 306 use super::c::foo;
335 use super::c::foo; 307 use super::b::*;
336 use super::b::*; 308 use foo::Y;
337 use foo::Y; 309}
338 } 310"#,
339 "###, 311 expect![[r#"
340 ); 312 crate
341 assert_snapshot!(map, @r###" 313 a: t
342 ⋮crate 314 b: t
343 ⋮a: t 315 c: t
344 ⋮b: t 316 d: t
345 ⋮c: t 317
346 ⋮d: t 318 crate::d
347 319 Y: t v
348 ⋮crate::d 320 foo: t
349 ⋮Y: t v 321
350 ⋮foo: t 322 crate::c
351 323 foo: t
352 ⋮crate::c 324
353 ⋮foo: t 325 crate::c::foo
354 326 Y: t v
355 ⋮crate::c::foo 327
356 ⋮Y: t v 328 crate::b
357 329 foo: t
358 ⋮crate::b 330
359 ⋮foo: t 331 crate::a
360 332 foo: t
361 ⋮crate::a 333
362 ⋮foo: t 334 crate::a::foo
363 335 X: t v
364 ⋮crate::a::foo 336 "#]],
365 ⋮X: t v
366 "###
367 ); 337 );
368} 338}
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 84480d9f6..e0fb8bdef 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -2,639 +2,631 @@ use super::*;
2 2
3#[test] 3#[test]
4fn macro_rules_are_globally_visible() { 4fn macro_rules_are_globally_visible() {
5 let map = def_map( 5 check(
6 r" 6 r#"
7 //- /lib.rs 7//- /lib.rs
8 macro_rules! structs { 8macro_rules! structs {
9 ($($i:ident),*) => { 9 ($($i:ident),*) => {
10 $(struct $i { field: u32 } )* 10 $(struct $i { field: u32 } )*
11 } 11 }
12 } 12}
13 structs!(Foo); 13structs!(Foo);
14 mod nested; 14mod nested;
15 15
16 //- /nested.rs 16//- /nested.rs
17 structs!(Bar, Baz); 17structs!(Bar, Baz);
18 ", 18"#,
19 expect![[r#"
20 crate
21 Foo: t
22 nested: t
23
24 crate::nested
25 Bar: t
26 Baz: t
27 "#]],
19 ); 28 );
20 assert_snapshot!(map, @r###"
21 ⋮crate
22 ⋮Foo: t
23 ⋮nested: t
24
25 ⋮crate::nested
26 ⋮Bar: t
27 ⋮Baz: t
28 "###);
29} 29}
30 30
31#[test] 31#[test]
32fn macro_rules_can_define_modules() { 32fn macro_rules_can_define_modules() {
33 let map = def_map( 33 check(
34 r" 34 r#"
35 //- /lib.rs 35//- /lib.rs
36 macro_rules! m { 36macro_rules! m {
37 ($name:ident) => { mod $name; } 37 ($name:ident) => { mod $name; }
38 } 38}
39 m!(n1); 39m!(n1);
40 40mod m { m!(n3) }
41 mod m { 41
42 m!(n3) 42//- /n1.rs
43 } 43m!(n2)
44 44//- /n1/n2.rs
45 //- /n1.rs 45struct X;
46 m!(n2) 46//- /m/n3.rs
47 //- /n1/n2.rs 47struct Y;
48 struct X; 48"#,
49 //- /m/n3.rs 49 expect![[r#"
50 struct Y; 50 crate
51 ", 51 m: t
52 n1: t
53
54 crate::m
55 n3: t
56
57 crate::m::n3
58 Y: t v
59
60 crate::n1
61 n2: t
62
63 crate::n1::n2
64 X: t v
65 "#]],
52 ); 66 );
53 assert_snapshot!(map, @r###"
54 ⋮crate
55 ⋮m: t
56 ⋮n1: t
57
58 ⋮crate::m
59 ⋮n3: t
60
61 ⋮crate::m::n3
62 ⋮Y: t v
63
64 ⋮crate::n1
65 ⋮n2: t
66
67 ⋮crate::n1::n2
68 ⋮X: t v
69 "###);
70} 67}
71 68
72#[test] 69#[test]
73fn macro_rules_from_other_crates_are_visible() { 70fn macro_rules_from_other_crates_are_visible() {
74 let map = def_map( 71 check(
75 " 72 r#"
76 //- /main.rs crate:main deps:foo 73//- /main.rs crate:main deps:foo
77 foo::structs!(Foo, Bar) 74foo::structs!(Foo, Bar)
78 mod bar; 75mod bar;
79 76
80 //- /bar.rs 77//- /bar.rs
81 use crate::*; 78use crate::*;
82 79
83 //- /lib.rs crate:foo 80//- /lib.rs crate:foo
84 #[macro_export] 81#[macro_export]
85 macro_rules! structs { 82macro_rules! structs {
86 ($($i:ident),*) => { 83 ($($i:ident),*) => {
87 $(struct $i { field: u32 } )* 84 $(struct $i { field: u32 } )*
88 } 85 }
89 } 86}
90 ", 87"#,
88 expect![[r#"
89 crate
90 Bar: t
91 Foo: t
92 bar: t
93
94 crate::bar
95 Bar: t
96 Foo: t
97 bar: t
98 "#]],
91 ); 99 );
92 assert_snapshot!(map, @r###"
93 ⋮crate
94 ⋮Bar: t
95 ⋮Foo: t
96 ⋮bar: t
97
98 ⋮crate::bar
99 ⋮Bar: t
100 ⋮Foo: t
101 ⋮bar: t
102 "###);
103} 100}
104 101
105#[test] 102#[test]
106fn macro_rules_export_with_local_inner_macros_are_visible() { 103fn macro_rules_export_with_local_inner_macros_are_visible() {
107 let map = def_map( 104 check(
108 " 105 r#"
109 //- /main.rs crate:main deps:foo 106//- /main.rs crate:main deps:foo
110 foo::structs!(Foo, Bar) 107foo::structs!(Foo, Bar)
111 mod bar; 108mod bar;
112 109
113 //- /bar.rs 110//- /bar.rs
114 use crate::*; 111use crate::*;
115 112
116 //- /lib.rs crate:foo 113//- /lib.rs crate:foo
117 #[macro_export(local_inner_macros)] 114#[macro_export(local_inner_macros)]
118 macro_rules! structs { 115macro_rules! structs {
119 ($($i:ident),*) => { 116 ($($i:ident),*) => {
120 $(struct $i { field: u32 } )* 117 $(struct $i { field: u32 } )*
121 } 118 }
122 } 119}
123 ", 120"#,
121 expect![[r#"
122 crate
123 Bar: t
124 Foo: t
125 bar: t
126
127 crate::bar
128 Bar: t
129 Foo: t
130 bar: t
131 "#]],
124 ); 132 );
125 assert_snapshot!(map, @r###"
126 ⋮crate
127 ⋮Bar: t
128 ⋮Foo: t
129 ⋮bar: t
130
131 ⋮crate::bar
132 ⋮Bar: t
133 ⋮Foo: t
134 ⋮bar: t
135 "###);
136} 133}
137 134
138#[test] 135#[test]
139fn local_inner_macros_makes_local_macros_usable() { 136fn local_inner_macros_makes_local_macros_usable() {
140 let map = def_map( 137 check(
141 " 138 r#"
142 //- /main.rs crate:main deps:foo 139//- /main.rs crate:main deps:foo
143 foo::structs!(Foo, Bar); 140foo::structs!(Foo, Bar);
144 mod bar; 141mod bar;
145 //- /bar.rs 142
146 use crate::*; 143//- /bar.rs
147 //- /lib.rs crate:foo 144use crate::*;
148 #[macro_export(local_inner_macros)] 145
149 macro_rules! structs { 146//- /lib.rs crate:foo
150 ($($i:ident),*) => { 147#[macro_export(local_inner_macros)]
151 inner!($($i),*); 148macro_rules! structs {
152 } 149 ($($i:ident),*) => {
153 } 150 inner!($($i),*);
154 #[macro_export] 151 }
155 macro_rules! inner { 152}
156 ($($i:ident),*) => { 153#[macro_export]
157 $(struct $i { field: u32 } )* 154macro_rules! inner {
158 } 155 ($($i:ident),*) => {
159 } 156 $(struct $i { field: u32 } )*
160 ", 157 }
158}
159"#,
160 expect![[r#"
161 crate
162 Bar: t
163 Foo: t
164 bar: t
165
166 crate::bar
167 Bar: t
168 Foo: t
169 bar: t
170 "#]],
161 ); 171 );
162 assert_snapshot!(map, @r###"
163 ⋮crate
164 ⋮Bar: t
165 ⋮Foo: t
166 ⋮bar: t
167
168 ⋮crate::bar
169 ⋮Bar: t
170 ⋮Foo: t
171 ⋮bar: t
172 "###);
173} 172}
174 173
175#[test] 174#[test]
176fn unexpanded_macro_should_expand_by_fixedpoint_loop() { 175fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
177 let map = def_map( 176 check(
178 " 177 r#"
179 //- /main.rs crate:main deps:foo 178//- /main.rs crate:main deps:foo
180 macro_rules! baz { 179macro_rules! baz {
181 () => { 180 () => {
182 use foo::bar; 181 use foo::bar;
183 } 182 }
184 } 183}
185 184foo!();
186 foo!(); 185bar!();
187 bar!(); 186baz!();
188 baz!(); 187
189 188//- /lib.rs crate:foo
190 //- /lib.rs crate:foo 189#[macro_export]
191 #[macro_export] 190macro_rules! foo {
192 macro_rules! foo { 191 () => {
193 () => { 192 struct Foo { field: u32 }
194 struct Foo { field: u32 } 193 }
195 } 194}
196 } 195#[macro_export]
197 #[macro_export] 196macro_rules! bar {
198 macro_rules! bar { 197 () => {
199 () => { 198 use foo::foo;
200 use foo::foo; 199 }
201 } 200}
202 } 201"#,
203 ", 202 expect![[r#"
203 crate
204 Foo: t
205 bar: m
206 foo: m
207 "#]],
204 ); 208 );
205 assert_snapshot!(map, @r###"
206 ⋮crate
207 ⋮Foo: t
208 ⋮bar: m
209 ⋮foo: m
210 "###);
211} 209}
212 210
213#[test] 211#[test]
214fn macro_rules_from_other_crates_are_visible_with_macro_use() { 212fn macro_rules_from_other_crates_are_visible_with_macro_use() {
215 mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); 213 mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use);
216 let map = def_map( 214 check(
217 " 215 r#"
218 //- /main.rs crate:main deps:foo 216//- /main.rs crate:main deps:foo
219 structs!(Foo); 217structs!(Foo);
220 structs_priv!(Bar); 218structs_priv!(Bar);
221 structs_not_exported!(MacroNotResolved1); 219structs_not_exported!(MacroNotResolved1);
222 crate::structs!(MacroNotResolved2); 220crate::structs!(MacroNotResolved2);
223 221
224 mod bar; 222mod bar;
225 223
226 #[macro_use] 224#[macro_use]
227 extern crate foo; 225extern crate foo;
228 226
229 //- /bar.rs 227//- /bar.rs
230 structs!(Baz); 228structs!(Baz);
231 crate::structs!(MacroNotResolved3); 229crate::structs!(MacroNotResolved3);
232 230
233 //- /lib.rs crate:foo 231//- /lib.rs crate:foo
234 #[macro_export] 232#[macro_export]
235 macro_rules! structs { 233macro_rules! structs {
236 ($i:ident) => { struct $i; } 234 ($i:ident) => { struct $i; }
237 } 235}
238 236
239 macro_rules! structs_not_exported { 237macro_rules! structs_not_exported {
240 ($i:ident) => { struct $i; } 238 ($i:ident) => { struct $i; }
241 } 239}
242 240
243 mod priv_mod { 241mod priv_mod {
244 #[macro_export] 242 #[macro_export]
245 macro_rules! structs_priv { 243 macro_rules! structs_priv {
246 ($i:ident) => { struct $i; } 244 ($i:ident) => { struct $i; }
247 } 245 }
248 } 246}
249 ", 247"#,
248 expect![[r#"
249 crate
250 Bar: t v
251 Foo: t v
252 bar: t
253 foo: t
254
255 crate::bar
256 Baz: t v
257 "#]],
250 ); 258 );
251 assert_snapshot!(map, @r###"
252 ⋮crate
253 ⋮Bar: t v
254 ⋮Foo: t v
255 ⋮bar: t
256 ⋮foo: t
257
258 ⋮crate::bar
259 ⋮Baz: t v
260 "###);
261} 259}
262 260
263#[test] 261#[test]
264fn prelude_is_macro_use() { 262fn prelude_is_macro_use() {
265 mark::check!(prelude_is_macro_use); 263 mark::check!(prelude_is_macro_use);
266 let map = def_map( 264 check(
267 " 265 r#"
268 //- /main.rs crate:main deps:foo 266//- /main.rs crate:main deps:foo
269 structs!(Foo); 267structs!(Foo);
270 structs_priv!(Bar); 268structs_priv!(Bar);
271 structs_outside!(Out); 269structs_outside!(Out);
272 crate::structs!(MacroNotResolved2); 270crate::structs!(MacroNotResolved2);
273 271
274 mod bar; 272mod bar;
275
276 //- /bar.rs
277 structs!(Baz);
278 crate::structs!(MacroNotResolved3);
279
280 //- /lib.rs crate:foo
281 #[prelude_import]
282 use self::prelude::*;
283
284 mod prelude {
285 #[macro_export]
286 macro_rules! structs {
287 ($i:ident) => { struct $i; }
288 }
289
290 mod priv_mod {
291 #[macro_export]
292 macro_rules! structs_priv {
293 ($i:ident) => { struct $i; }
294 }
295 }
296 }
297 273
274//- /bar.rs
275structs!(Baz);
276crate::structs!(MacroNotResolved3);
277
278//- /lib.rs crate:foo
279#[prelude_import]
280use self::prelude::*;
281
282mod prelude {
283 #[macro_export]
284 macro_rules! structs {
285 ($i:ident) => { struct $i; }
286 }
287
288 mod priv_mod {
298 #[macro_export] 289 #[macro_export]
299 macro_rules! structs_outside { 290 macro_rules! structs_priv {
300 ($i:ident) => { struct $i; } 291 ($i:ident) => { struct $i; }
301 } 292 }
302 ", 293 }
294}
295
296#[macro_export]
297macro_rules! structs_outside {
298 ($i:ident) => { struct $i; }
299}
300"#,
301 expect![[r#"
302 crate
303 Bar: t v
304 Foo: t v
305 Out: t v
306 bar: t
307
308 crate::bar
309 Baz: t v
310 "#]],
303 ); 311 );
304 assert_snapshot!(map, @r###"
305 ⋮crate
306 ⋮Bar: t v
307 ⋮Foo: t v
308 ⋮Out: t v
309 ⋮bar: t
310
311 ⋮crate::bar
312 ⋮Baz: t v
313 "###);
314} 312}
315 313
316#[test] 314#[test]
317fn prelude_cycle() { 315fn prelude_cycle() {
318 let map = def_map( 316 check(
319 " 317 r#"
320 //- /lib.rs 318#[prelude_import]
321 #[prelude_import] 319use self::prelude::*;
322 use self::prelude::*;
323 320
324 declare_mod!(); 321declare_mod!();
325 322
326 mod prelude { 323mod prelude {
327 macro_rules! declare_mod { 324 macro_rules! declare_mod {
328 () => (mod foo {}) 325 () => (mod foo {})
329 } 326 }
330 } 327}
331 ", 328"#,
329 expect![[r#"
330 crate
331 prelude: t
332
333 crate::prelude
334 "#]],
332 ); 335 );
333 assert_snapshot!(map, @r###"
334 ⋮crate
335 ⋮prelude: t
336
337 ⋮crate::prelude
338 "###);
339} 336}
340 337
341#[test] 338#[test]
342fn plain_macros_are_legacy_textual_scoped() { 339fn plain_macros_are_legacy_textual_scoped() {
343 let map = def_map( 340 check(
344 r#" 341 r#"
345 //- /main.rs 342//- /main.rs
346 mod m1; 343mod m1;
347 bar!(NotFoundNotMacroUse); 344bar!(NotFoundNotMacroUse);
348 345
349 mod m2 { 346mod m2 { foo!(NotFoundBeforeInside2); }
350 foo!(NotFoundBeforeInside2);
351 }
352 347
353 macro_rules! foo { 348macro_rules! foo {
354 ($x:ident) => { struct $x; } 349 ($x:ident) => { struct $x; }
355 } 350}
356 foo!(Ok); 351foo!(Ok);
357
358 mod m3;
359 foo!(OkShadowStop);
360 bar!(NotFoundMacroUseStop);
361
362 #[macro_use]
363 mod m5 {
364 #[macro_use]
365 mod m6 {
366 macro_rules! foo {
367 ($x:ident) => { fn $x() {} }
368 }
369 }
370 }
371 foo!(ok_double_macro_use_shadow);
372
373 baz!(NotFoundBefore);
374 #[macro_use]
375 mod m7 {
376 macro_rules! baz {
377 ($x:ident) => { struct $x; }
378 }
379 }
380 baz!(OkAfter);
381 352
382 //- /m1.rs 353mod m3;
383 foo!(NotFoundBeforeInside1); 354foo!(OkShadowStop);
384 macro_rules! bar { 355bar!(NotFoundMacroUseStop);
385 ($x:ident) => { struct $x; }
386 }
387 356
388 //- /m3/mod.rs 357#[macro_use]
389 foo!(OkAfterInside); 358mod m5 {
359 #[macro_use]
360 mod m6 {
390 macro_rules! foo { 361 macro_rules! foo {
391 ($x:ident) => { fn $x() {} } 362 ($x:ident) => { fn $x() {} }
392 } 363 }
393 foo!(ok_shadow); 364 }
365}
366foo!(ok_double_macro_use_shadow);
367
368baz!(NotFoundBefore);
369#[macro_use]
370mod m7 {
371 macro_rules! baz {
372 ($x:ident) => { struct $x; }
373 }
374}
375baz!(OkAfter);
394 376
395 #[macro_use] 377//- /m1.rs
396 mod m4; 378foo!(NotFoundBeforeInside1);
397 bar!(OkMacroUse); 379macro_rules! bar {
380 ($x:ident) => { struct $x; }
381}
398 382
399 //- /m3/m4.rs 383//- /m3/mod.rs
400 foo!(ok_shadow_deep); 384foo!(OkAfterInside);
401 macro_rules! bar { 385macro_rules! foo {
402 ($x:ident) => { struct $x; } 386 ($x:ident) => { fn $x() {} }
403 } 387}
404 "#, 388foo!(ok_shadow);
389
390#[macro_use]
391mod m4;
392bar!(OkMacroUse);
393
394//- /m3/m4.rs
395foo!(ok_shadow_deep);
396macro_rules! bar {
397 ($x:ident) => { struct $x; }
398}
399"#,
400 expect![[r#"
401 crate
402 Ok: t v
403 OkAfter: t v
404 OkShadowStop: t v
405 m1: t
406 m2: t
407 m3: t
408 m5: t
409 m7: t
410 ok_double_macro_use_shadow: v
411
412 crate::m7
413
414 crate::m1
415
416 crate::m5
417 m6: t
418
419 crate::m5::m6
420
421 crate::m2
422
423 crate::m3
424 OkAfterInside: t v
425 OkMacroUse: t v
426 m4: t
427 ok_shadow: v
428
429 crate::m3::m4
430 ok_shadow_deep: v
431 "#]],
405 ); 432 );
406 assert_snapshot!(map, @r###"
407 ⋮crate
408 ⋮Ok: t v
409 ⋮OkAfter: t v
410 ⋮OkShadowStop: t v
411 ⋮m1: t
412 ⋮m2: t
413 ⋮m3: t
414 ⋮m5: t
415 ⋮m7: t
416 ⋮ok_double_macro_use_shadow: v
417
418 ⋮crate::m7
419
420 ⋮crate::m1
421
422 ⋮crate::m5
423 ⋮m6: t
424
425 ⋮crate::m5::m6
426
427 ⋮crate::m2
428
429 ⋮crate::m3
430 ⋮OkAfterInside: t v
431 ⋮OkMacroUse: t v
432 ⋮m4: t
433 ⋮ok_shadow: v
434
435 ⋮crate::m3::m4
436 ⋮ok_shadow_deep: v
437 "###);
438} 433}
439 434
440#[test] 435#[test]
441fn type_value_macro_live_in_different_scopes() { 436fn type_value_macro_live_in_different_scopes() {
442 let map = def_map( 437 check(
443 " 438 r#"
444 //- /main.rs 439#[macro_export]
445 #[macro_export] 440macro_rules! foo {
446 macro_rules! foo { 441 ($x:ident) => { type $x = (); }
447 ($x:ident) => { type $x = (); } 442}
448 }
449
450 foo!(foo);
451 use foo as bar;
452 443
453 use self::foo as baz; 444foo!(foo);
454 fn baz() {} 445use foo as bar;
455 ", 446
447use self::foo as baz;
448fn baz() {}
449"#,
450 expect![[r#"
451 crate
452 bar: t m
453 baz: t v m
454 foo: t m
455 "#]],
456 ); 456 );
457 assert_snapshot!(map, @r###"
458 ⋮crate
459 ⋮bar: t m
460 ⋮baz: t v m
461 ⋮foo: t m
462 "###);
463} 457}
464 458
465#[test] 459#[test]
466fn macro_use_can_be_aliased() { 460fn macro_use_can_be_aliased() {
467 let map = def_map( 461 check(
468 " 462 r#"
469 //- /main.rs crate:main deps:foo 463//- /main.rs crate:main deps:foo
470 #[macro_use] 464#[macro_use]
471 extern crate foo; 465extern crate foo;
472 466
473 foo!(Direct); 467foo!(Direct);
474 bar!(Alias); 468bar!(Alias);
475 469
476 //- /lib.rs crate:foo 470//- /lib.rs crate:foo
477 use crate::foo as bar; 471use crate::foo as bar;
478 472
479 mod m { 473mod m {
480 #[macro_export] 474 #[macro_export]
481 macro_rules! foo { 475 macro_rules! foo {
482 ($x:ident) => { struct $x; } 476 ($x:ident) => { struct $x; }
483 } 477 }
484 } 478}
485 ", 479"#,
480 expect![[r#"
481 crate
482 Alias: t v
483 Direct: t v
484 foo: t
485 "#]],
486 ); 486 );
487 assert_snapshot!(map, @r###"
488 ⋮crate
489 ⋮Alias: t v
490 ⋮Direct: t v
491 ⋮foo: t
492 "###);
493} 487}
494 488
495#[test] 489#[test]
496fn path_qualified_macros() { 490fn path_qualified_macros() {
497 let map = def_map( 491 check(
498 " 492 r#"
499 //- /main.rs 493macro_rules! foo {
500 macro_rules! foo { 494 ($x:ident) => { struct $x; }
501 ($x:ident) => { struct $x; } 495}
502 }
503 496
504 crate::foo!(NotResolved); 497crate::foo!(NotResolved);
505 498
506 crate::bar!(OkCrate); 499crate::bar!(OkCrate);
507 bar!(OkPlain); 500bar!(OkPlain);
508 alias1!(NotHere); 501alias1!(NotHere);
509 m::alias1!(OkAliasPlain); 502m::alias1!(OkAliasPlain);
510 m::alias2!(OkAliasSuper); 503m::alias2!(OkAliasSuper);
511 m::alias3!(OkAliasCrate); 504m::alias3!(OkAliasCrate);
512 not_found!(NotFound); 505not_found!(NotFound);
513 506
514 mod m { 507mod m {
515 #[macro_export] 508 #[macro_export]
516 macro_rules! bar { 509 macro_rules! bar {
517 ($x:ident) => { struct $x; } 510 ($x:ident) => { struct $x; }
518 } 511 }
519 512 pub use bar as alias1;
520 pub use bar as alias1; 513 pub use super::bar as alias2;
521 pub use super::bar as alias2; 514 pub use crate::bar as alias3;
522 pub use crate::bar as alias3; 515 pub use self::bar as not_found;
523 pub use self::bar as not_found; 516}
524 } 517"#,
525 ", 518 expect![[r#"
519 crate
520 OkAliasCrate: t v
521 OkAliasPlain: t v
522 OkAliasSuper: t v
523 OkCrate: t v
524 OkPlain: t v
525 bar: m
526 m: t
527
528 crate::m
529 alias1: m
530 alias2: m
531 alias3: m
532 not_found: _
533 "#]],
526 ); 534 );
527 assert_snapshot!(map, @r###"
528 ⋮crate
529 ⋮OkAliasCrate: t v
530 ⋮OkAliasPlain: t v
531 ⋮OkAliasSuper: t v
532 ⋮OkCrate: t v
533 ⋮OkPlain: t v
534 ⋮bar: m
535 ⋮m: t
536
537 ⋮crate::m
538 ⋮alias1: m
539 ⋮alias2: m
540 ⋮alias3: m
541 ⋮not_found: _
542 "###);
543} 535}
544 536
545#[test] 537#[test]
546fn macro_dollar_crate_is_correct_in_item() { 538fn macro_dollar_crate_is_correct_in_item() {
547 mark::check!(macro_dollar_crate_self); 539 mark::check!(macro_dollar_crate_self);
548 let map = def_map( 540 check(
549 " 541 r#"
550 //- /main.rs crate:main deps:foo 542//- /main.rs crate:main deps:foo
551 #[macro_use] 543#[macro_use]
552 extern crate foo; 544extern crate foo;
553 545
554 #[macro_use] 546#[macro_use]
555 mod m { 547mod m {
556 macro_rules! current { 548 macro_rules! current {
557 () => { 549 () => {
558 use $crate::Foo as FooSelf; 550 use $crate::Foo as FooSelf;
559 }
560 }
561 } 551 }
552 }
553}
562 554
563 struct Foo; 555struct Foo;
564 556
565 current!(); 557current!();
566 not_current1!(); 558not_current1!();
567 foo::not_current2!(); 559foo::not_current2!();
568
569 //- /lib.rs crate:foo
570 mod m {
571 #[macro_export]
572 macro_rules! not_current1 {
573 () => {
574 use $crate::Bar;
575 }
576 }
577 }
578 560
579 #[macro_export] 561//- /lib.rs crate:foo
580 macro_rules! not_current2 { 562mod m {
581 () => { 563 #[macro_export]
582 use $crate::Baz; 564 macro_rules! not_current1 {
583 } 565 () => {
566 use $crate::Bar;
584 } 567 }
568 }
569}
585 570
586 struct Bar; 571#[macro_export]
587 struct Baz; 572macro_rules! not_current2 {
588 ", 573 () => {
574 use $crate::Baz;
575 }
576}
577
578struct Bar;
579struct Baz;
580"#,
581 expect![[r#"
582 crate
583 Bar: t v
584 Baz: t v
585 Foo: t v
586 FooSelf: t v
587 foo: t
588 m: t
589
590 crate::m
591 "#]],
589 ); 592 );
590 assert_snapshot!(map, @r###"
591 ⋮crate
592 ⋮Bar: t v
593 ⋮Baz: t v
594 ⋮Foo: t v
595 ⋮FooSelf: t v
596 ⋮foo: t
597 ⋮m: t
598
599 ⋮crate::m
600 "###);
601} 593}
602 594
603#[test] 595#[test]
604fn macro_dollar_crate_is_correct_in_indirect_deps() { 596fn macro_dollar_crate_is_correct_in_indirect_deps() {
605 mark::check!(macro_dollar_crate_other); 597 mark::check!(macro_dollar_crate_other);
606 // From std 598 // From std
607 let map = def_map( 599 check(
608 r#" 600 r#"
609 //- /main.rs crate:main deps:std 601//- /main.rs crate:main deps:std
610 foo!(); 602foo!();
611 603
612 //- /std.rs crate:std deps:core 604//- /std.rs crate:std deps:core
613 #[prelude_import] 605#[prelude_import]
614 use self::prelude::*; 606use self::prelude::*;
615 607
616 pub use core::foo; 608pub use core::foo;
617 609
618 mod prelude {} 610mod prelude {}
619 611
620 #[macro_use] 612#[macro_use]
621 mod std_macros; 613mod std_macros;
622 614
623 //- /core.rs crate:core 615//- /core.rs crate:core
624 #[macro_export] 616#[macro_export]
625 macro_rules! foo { 617macro_rules! foo {
626 () => { 618 () => {
627 use $crate::bar; 619 use $crate::bar;
628 } 620 }
629 } 621}
630 622
631 pub struct bar; 623pub struct bar;
632 "#, 624"#,
625 expect![[r#"
626 crate
627 bar: t v
628 "#]],
633 ); 629 );
634 assert_snapshot!(map, @r###"
635 ⋮crate
636 ⋮bar: t v
637 "###);
638} 630}
639 631
640#[test] 632#[test]
@@ -642,21 +634,36 @@ fn expand_derive() {
642 let map = compute_crate_def_map( 634 let map = compute_crate_def_map(
643 " 635 "
644 //- /main.rs 636 //- /main.rs
645 #[derive(Clone)] 637 #[derive(Copy, Clone)]
646 struct Foo; 638 struct Foo;
647 ", 639 ",
648 ); 640 );
649 assert_eq!(map.modules[map.root].scope.impls().len(), 1); 641 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
650} 642}
651 643
652#[test] 644#[test]
653fn expand_multiple_derive() { 645fn macro_expansion_overflow() {
654 let map = compute_crate_def_map( 646 mark::check!(macro_expansion_overflow);
655 " 647 check(
656 //- /main.rs 648 r#"
657 #[derive(Copy, Clone)] 649macro_rules! a {
658 struct Foo; 650 ($e:expr; $($t:tt)*) => {
659 ", 651 b!($($t)*);
652 };
653 () => {};
654}
655
656macro_rules! b {
657 (static = $e:expr; $($t:tt)*) => {
658 a!($e; $($t)*);
659 };
660 () => {};
661}
662
663b! { static = #[] (); }
664"#,
665 expect![[r#"
666 crate
667 "#]],
660 ); 668 );
661 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
662} 669}
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index 753684201..ae58948c4 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -3,710 +3,672 @@ use super::*;
3#[test] 3#[test]
4fn name_res_works_for_broken_modules() { 4fn name_res_works_for_broken_modules() {
5 mark::check!(name_res_works_for_broken_modules); 5 mark::check!(name_res_works_for_broken_modules);
6 let map = def_map( 6 check(
7 r" 7 r"
8 //- /lib.rs 8//- /lib.rs
9 mod foo // no `;`, no body 9mod foo // no `;`, no body
10 10use self::foo::Baz;
11 use self::foo::Baz; 11
12 12//- /foo/mod.rs
13 //- /foo/mod.rs 13pub mod bar;
14 pub mod bar; 14pub use self::bar::Baz;
15 15
16 pub use self::bar::Baz; 16//- /foo/bar.rs
17 17pub struct Baz;
18 //- /foo/bar.rs 18",
19 pub struct Baz; 19 expect![[r#"
20 ", 20 crate
21 Baz: _
22 foo: t
23
24 crate::foo
25 "#]],
21 ); 26 );
22 assert_snapshot!(map, @r###"
23crate
24Baz: _
25foo: t
26
27crate::foo
28 "###);
29} 27}
30 28
31#[test] 29#[test]
32fn nested_module_resolution() { 30fn nested_module_resolution() {
33 let map = def_map( 31 check(
34 r" 32 r#"
35 //- /lib.rs 33//- /lib.rs
36 mod n1; 34mod n1;
37 35
38 //- /n1.rs 36//- /n1.rs
39 mod n2; 37mod n2;
40 38
41 //- /n1/n2.rs 39//- /n1/n2.rs
42 struct X; 40struct X;
43 ", 41"#,
42 expect![[r#"
43 crate
44 n1: t
45
46 crate::n1
47 n2: t
48
49 crate::n1::n2
50 X: t v
51 "#]],
44 ); 52 );
45
46 assert_snapshot!(map, @r###"
47 ⋮crate
48 ⋮n1: t
49
50 ⋮crate::n1
51 ⋮n2: t
52
53 ⋮crate::n1::n2
54 ⋮X: t v
55 "###);
56} 53}
57 54
58#[test] 55#[test]
59fn nested_module_resolution_2() { 56fn nested_module_resolution_2() {
60 let map = def_map( 57 check(
61 r" 58 r#"
62 //- /lib.rs 59//- /lib.rs
63 mod prelude; 60mod prelude;
64 mod iter; 61mod iter;
65 62
66 //- /prelude.rs 63//- /prelude.rs
67 pub use crate::iter::Iterator; 64pub use crate::iter::Iterator;
68 65
69 //- /iter.rs 66//- /iter.rs
70 pub use self::traits::Iterator; 67pub use self::traits::Iterator;
71 mod traits; 68mod traits;
72 69
73 //- /iter/traits.rs 70//- /iter/traits.rs
74 pub use self::iterator::Iterator; 71pub use self::iterator::Iterator;
75 mod iterator; 72mod iterator;
76 73
77 //- /iter/traits/iterator.rs 74//- /iter/traits/iterator.rs
78 pub trait Iterator; 75pub trait Iterator;
79 ", 76"#,
77 expect![[r#"
78 crate
79 iter: t
80 prelude: t
81
82 crate::iter
83 Iterator: t
84 traits: t
85
86 crate::iter::traits
87 Iterator: t
88 iterator: t
89
90 crate::iter::traits::iterator
91 Iterator: t
92
93 crate::prelude
94 Iterator: t
95 "#]],
80 ); 96 );
81
82 assert_snapshot!(map, @r###"
83 ⋮crate
84 ⋮iter: t
85 ⋮prelude: t
86
87 ⋮crate::iter
88 ⋮Iterator: t
89 ⋮traits: t
90
91 ⋮crate::iter::traits
92 ⋮Iterator: t
93 ⋮iterator: t
94
95 ⋮crate::iter::traits::iterator
96 ⋮Iterator: t
97
98 ⋮crate::prelude
99 ⋮Iterator: t
100 "###);
101} 97}
102 98
103#[test] 99#[test]
104fn module_resolution_works_for_non_standard_filenames() { 100fn module_resolution_works_for_non_standard_filenames() {
105 let map = def_map( 101 check(
106 " 102 r#"
107 //- /my_library.rs crate:my_library 103//- /my_library.rs crate:my_library
108 mod foo; 104mod foo;
109 use self::foo::Bar; 105use self::foo::Bar;
110 106
111 //- /foo/mod.rs 107//- /foo/mod.rs
112 pub struct Bar; 108pub struct Bar;
113 ", 109"#,
110 expect![[r#"
111 crate
112 Bar: t v
113 foo: t
114
115 crate::foo
116 Bar: t v
117 "#]],
114 ); 118 );
115
116 assert_snapshot!(map, @r###"
117 ⋮crate
118 ⋮Bar: t v
119 ⋮foo: t
120
121 ⋮crate::foo
122 ⋮Bar: t v
123 "###);
124} 119}
125 120
126#[test] 121#[test]
127fn module_resolution_works_for_raw_modules() { 122fn module_resolution_works_for_raw_modules() {
128 let map = def_map( 123 check(
129 " 124 r#"
130 //- /lib.rs 125//- /lib.rs
131 mod r#async; 126mod r#async;
132 use self::r#async::Bar; 127use self::r#async::Bar;
133 128
134 //- /async.rs 129//- /async.rs
135 pub struct Bar; 130pub struct Bar;
136 ", 131"#,
132 expect![[r#"
133 crate
134 Bar: t v
135 async: t
136
137 crate::async
138 Bar: t v
139 "#]],
137 ); 140 );
138
139 assert_snapshot!(map, @r###"
140 ⋮crate
141 ⋮Bar: t v
142 ⋮async: t
143
144 ⋮crate::async
145 ⋮Bar: t v
146 "###);
147} 141}
148 142
149#[test] 143#[test]
150fn module_resolution_decl_path() { 144fn module_resolution_decl_path() {
151 let map = def_map( 145 check(
152 r###" 146 r#"
153 //- /lib.rs 147//- /lib.rs
154 #[path = "bar/baz/foo.rs"] 148#[path = "bar/baz/foo.rs"]
155 mod foo; 149mod foo;
156 use self::foo::Bar; 150use self::foo::Bar;
157 151
158 //- /bar/baz/foo.rs 152//- /bar/baz/foo.rs
159 pub struct Bar; 153pub struct Bar;
160 "###, 154"#,
155 expect![[r#"
156 crate
157 Bar: t v
158 foo: t
159
160 crate::foo
161 Bar: t v
162 "#]],
161 ); 163 );
162
163 assert_snapshot!(map, @r###"
164 ⋮crate
165 ⋮Bar: t v
166 ⋮foo: t
167
168 ⋮crate::foo
169 ⋮Bar: t v
170 "###);
171} 164}
172 165
173#[test] 166#[test]
174fn module_resolution_module_with_path_in_mod_rs() { 167fn module_resolution_module_with_path_in_mod_rs() {
175 let map = def_map( 168 check(
176 r###" 169 r#"
177 //- /main.rs 170//- /main.rs
178 mod foo; 171mod foo;
179 172
180 //- /foo/mod.rs 173//- /foo/mod.rs
181 #[path = "baz.rs"] 174#[path = "baz.rs"]
182 pub mod bar; 175pub mod bar;
183 176use self::bar::Baz;
184 use self::bar::Baz; 177
185 178//- /foo/baz.rs
186 //- /foo/baz.rs 179pub struct Baz;
187 pub struct Baz; 180"#,
188 "###, 181 expect![[r#"
182 crate
183 foo: t
184
185 crate::foo
186 Baz: t v
187 bar: t
188
189 crate::foo::bar
190 Baz: t v
191 "#]],
189 ); 192 );
190
191 assert_snapshot!(map, @r###"
192 ⋮crate
193 ⋮foo: t
194
195 ⋮crate::foo
196 ⋮Baz: t v
197 ⋮bar: t
198
199 ⋮crate::foo::bar
200 ⋮Baz: t v
201 "###);
202} 193}
203 194
204#[test] 195#[test]
205fn module_resolution_module_with_path_non_crate_root() { 196fn module_resolution_module_with_path_non_crate_root() {
206 let map = def_map( 197 check(
207 r###" 198 r#"
208 //- /main.rs 199//- /main.rs
209 mod foo; 200mod foo;
210 201
211 //- /foo.rs 202//- /foo.rs
212 #[path = "baz.rs"] 203#[path = "baz.rs"]
213 pub mod bar; 204pub mod bar;
214 205use self::bar::Baz;
215 use self::bar::Baz; 206
216 207//- /baz.rs
217 //- /baz.rs 208pub struct Baz;
218 pub struct Baz; 209"#,
219 "###, 210 expect![[r#"
211 crate
212 foo: t
213
214 crate::foo
215 Baz: t v
216 bar: t
217
218 crate::foo::bar
219 Baz: t v
220 "#]],
220 ); 221 );
221
222 assert_snapshot!(map, @r###"
223 ⋮crate
224 ⋮foo: t
225
226 ⋮crate::foo
227 ⋮Baz: t v
228 ⋮bar: t
229
230 ⋮crate::foo::bar
231 ⋮Baz: t v
232 "###);
233} 222}
234 223
235#[test] 224#[test]
236fn module_resolution_module_decl_path_super() { 225fn module_resolution_module_decl_path_super() {
237 let map = def_map( 226 check(
238 r###" 227 r#"
239 //- /main.rs 228//- /main.rs
240 #[path = "bar/baz/module.rs"] 229#[path = "bar/baz/module.rs"]
241 mod foo; 230mod foo;
242 pub struct Baz; 231pub struct Baz;
243 232
244 //- /bar/baz/module.rs 233//- /bar/baz/module.rs
245 use super::Baz; 234use super::Baz;
246 "###, 235"#,
236 expect![[r#"
237 crate
238 Baz: t v
239 foo: t
240
241 crate::foo
242 Baz: t v
243 "#]],
247 ); 244 );
248
249 assert_snapshot!(map, @r###"
250 ⋮crate
251 ⋮Baz: t v
252 ⋮foo: t
253
254 ⋮crate::foo
255 ⋮Baz: t v
256 "###);
257} 245}
258 246
259#[test] 247#[test]
260fn module_resolution_explicit_path_mod_rs() { 248fn module_resolution_explicit_path_mod_rs() {
261 let map = def_map( 249 check(
262 r###" 250 r#"
263 //- /main.rs 251//- /main.rs
264 #[path = "module/mod.rs"] 252#[path = "module/mod.rs"]
265 mod foo; 253mod foo;
266 254
267 //- /module/mod.rs 255//- /module/mod.rs
268 pub struct Baz; 256pub struct Baz;
269 "###, 257"#,
258 expect![[r#"
259 crate
260 foo: t
261
262 crate::foo
263 Baz: t v
264 "#]],
270 ); 265 );
271
272 assert_snapshot!(map, @r###"
273 ⋮crate
274 ⋮foo: t
275
276 ⋮crate::foo
277 ⋮Baz: t v
278 "###);
279} 266}
280 267
281#[test] 268#[test]
282fn module_resolution_relative_path() { 269fn module_resolution_relative_path() {
283 let map = def_map( 270 check(
284 r###" 271 r#"
285 //- /main.rs 272//- /main.rs
286 mod foo; 273mod foo;
287 274
288 //- /foo.rs 275//- /foo.rs
289 #[path = "./sub.rs"] 276#[path = "./sub.rs"]
290 pub mod foo_bar; 277pub mod foo_bar;
291 278
292 //- /sub.rs 279//- /sub.rs
293 pub struct Baz; 280pub struct Baz;
294 "###, 281"#,
282 expect![[r#"
283 crate
284 foo: t
285
286 crate::foo
287 foo_bar: t
288
289 crate::foo::foo_bar
290 Baz: t v
291 "#]],
295 ); 292 );
296
297 assert_snapshot!(map, @r###"
298 ⋮crate
299 ⋮foo: t
300
301 ⋮crate::foo
302 ⋮foo_bar: t
303
304 ⋮crate::foo::foo_bar
305 ⋮Baz: t v
306 "###);
307} 293}
308 294
309#[test] 295#[test]
310fn module_resolution_relative_path_2() { 296fn module_resolution_relative_path_2() {
311 let map = def_map( 297 check(
312 r###" 298 r#"
313 //- /main.rs 299//- /main.rs
314 mod foo; 300mod foo;
315 301
316 //- /foo/mod.rs 302//- /foo/mod.rs
317 #[path="../sub.rs"] 303#[path="../sub.rs"]
318 pub mod foo_bar; 304pub mod foo_bar;
319 305
320 //- /sub.rs 306//- /sub.rs
321 pub struct Baz; 307pub struct Baz;
322 "###, 308"#,
309 expect![[r#"
310 crate
311 foo: t
312
313 crate::foo
314 foo_bar: t
315
316 crate::foo::foo_bar
317 Baz: t v
318 "#]],
323 ); 319 );
324
325 assert_snapshot!(map, @r###"
326 ⋮crate
327 ⋮foo: t
328
329 ⋮crate::foo
330 ⋮foo_bar: t
331
332 ⋮crate::foo::foo_bar
333 ⋮Baz: t v
334 "###);
335} 320}
336 321
337#[test] 322#[test]
338fn module_resolution_relative_path_outside_root() { 323fn module_resolution_relative_path_outside_root() {
339 let map = def_map( 324 check(
340 r###" 325 r#"
341 //- /main.rs 326//- /main.rs
342 327#[path="../../../../../outside.rs"]
343 #[path="../../../../../outside.rs"] 328mod foo;
344 mod foo; 329"#,
345 "###, 330 expect![[r#"
331 crate
332 "#]],
346 ); 333 );
347
348 assert_snapshot!(map, @r###"
349 ⋮crate
350 "###);
351} 334}
352 335
353#[test] 336#[test]
354fn module_resolution_explicit_path_mod_rs_2() { 337fn module_resolution_explicit_path_mod_rs_2() {
355 let map = def_map( 338 check(
356 r###" 339 r#"
357 //- /main.rs 340//- /main.rs
358 #[path = "module/bar/mod.rs"] 341#[path = "module/bar/mod.rs"]
359 mod foo; 342mod foo;
360 343
361 //- /module/bar/mod.rs 344//- /module/bar/mod.rs
362 pub struct Baz; 345pub struct Baz;
363 "###, 346"#,
347 expect![[r#"
348 crate
349 foo: t
350
351 crate::foo
352 Baz: t v
353 "#]],
364 ); 354 );
365
366 assert_snapshot!(map, @r###"
367 ⋮crate
368 ⋮foo: t
369
370 ⋮crate::foo
371 ⋮Baz: t v
372 "###);
373} 355}
374 356
375#[test] 357#[test]
376fn module_resolution_explicit_path_mod_rs_with_win_separator() { 358fn module_resolution_explicit_path_mod_rs_with_win_separator() {
377 let map = def_map( 359 check(
378 r###" 360 r#"
379 //- /main.rs 361//- /main.rs
380 #[path = "module\bar\mod.rs"] 362#[path = "module\bar\mod.rs"]
381 mod foo; 363mod foo;
382 364
383 //- /module/bar/mod.rs 365//- /module/bar/mod.rs
384 pub struct Baz; 366pub struct Baz;
385 "###, 367"#,
368 expect![[r#"
369 crate
370 foo: t
371
372 crate::foo
373 Baz: t v
374 "#]],
386 ); 375 );
387
388 assert_snapshot!(map, @r###"
389 ⋮crate
390 ⋮foo: t
391
392 ⋮crate::foo
393 ⋮Baz: t v
394 "###);
395} 376}
396 377
397#[test] 378#[test]
398fn module_resolution_decl_inside_inline_module_with_path_attribute() { 379fn module_resolution_decl_inside_inline_module_with_path_attribute() {
399 let map = def_map( 380 check(
400 r###" 381 r#"
401 //- /main.rs 382//- /main.rs
402 #[path = "models"] 383#[path = "models"]
403 mod foo { 384mod foo { mod bar; }
404 mod bar; 385
405 } 386//- /models/bar.rs
406 387pub struct Baz;
407 //- /models/bar.rs 388"#,
408 pub struct Baz; 389 expect![[r#"
409 "###, 390 crate
391 foo: t
392
393 crate::foo
394 bar: t
395
396 crate::foo::bar
397 Baz: t v
398 "#]],
410 ); 399 );
411
412 assert_snapshot!(map, @r###"
413 ⋮crate
414 ⋮foo: t
415
416 ⋮crate::foo
417 ⋮bar: t
418
419 ⋮crate::foo::bar
420 ⋮Baz: t v
421 "###);
422} 400}
423 401
424#[test] 402#[test]
425fn module_resolution_decl_inside_inline_module() { 403fn module_resolution_decl_inside_inline_module() {
426 let map = def_map( 404 check(
427 r###" 405 r#"
428 //- /main.rs 406//- /main.rs
429 mod foo { 407mod foo { mod bar; }
430 mod bar; 408
431 } 409//- /foo/bar.rs
432 410pub struct Baz;
433 //- /foo/bar.rs 411"#,
434 pub struct Baz; 412 expect![[r#"
435 "###, 413 crate
414 foo: t
415
416 crate::foo
417 bar: t
418
419 crate::foo::bar
420 Baz: t v
421 "#]],
436 ); 422 );
437
438 assert_snapshot!(map, @r###"
439 ⋮crate
440 ⋮foo: t
441
442 ⋮crate::foo
443 ⋮bar: t
444
445 ⋮crate::foo::bar
446 ⋮Baz: t v
447 "###);
448} 423}
449 424
450#[test] 425#[test]
451fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { 426fn module_resolution_decl_inside_inline_module_2_with_path_attribute() {
452 let map = def_map( 427 check(
453 r###" 428 r#"
454 //- /main.rs 429//- /main.rs
455 #[path = "models/db"] 430#[path = "models/db"]
456 mod foo { 431mod foo { mod bar; }
457 mod bar; 432
458 } 433//- /models/db/bar.rs
459 434pub struct Baz;
460 //- /models/db/bar.rs 435"#,
461 pub struct Baz; 436 expect![[r#"
462 "###, 437 crate
438 foo: t
439
440 crate::foo
441 bar: t
442
443 crate::foo::bar
444 Baz: t v
445 "#]],
463 ); 446 );
464
465 assert_snapshot!(map, @r###"
466 ⋮crate
467 ⋮foo: t
468
469 ⋮crate::foo
470 ⋮bar: t
471
472 ⋮crate::foo::bar
473 ⋮Baz: t v
474 "###);
475} 447}
476 448
477#[test] 449#[test]
478fn module_resolution_decl_inside_inline_module_3() { 450fn module_resolution_decl_inside_inline_module_3() {
479 let map = def_map( 451 check(
480 r###" 452 r#"
481 //- /main.rs 453//- /main.rs
482 #[path = "models/db"] 454#[path = "models/db"]
483 mod foo { 455mod foo {
484 #[path = "users.rs"] 456 #[path = "users.rs"]
485 mod bar; 457 mod bar;
486 } 458}
487 459
488 //- /models/db/users.rs 460//- /models/db/users.rs
489 pub struct Baz; 461pub struct Baz;
490 "###, 462"#,
491 ); 463 expect![[r#"
464 crate
465 foo: t
492 466
493 assert_snapshot!(map, @r###" 467 crate::foo
494 ⋮crate 468 bar: t
495 ⋮foo: t 469
496 470 crate::foo::bar
497 ⋮crate::foo 471 Baz: t v
498 ⋮bar: t 472 "#]],
499 473 );
500 ⋮crate::foo::bar
501 ⋮Baz: t v
502 "###);
503} 474}
504 475
505#[test] 476#[test]
506fn module_resolution_decl_inside_inline_module_empty_path() { 477fn module_resolution_decl_inside_inline_module_empty_path() {
507 let map = def_map( 478 check(
508 r###" 479 r#"
509 //- /main.rs 480//- /main.rs
510 #[path = ""] 481#[path = ""]
511 mod foo { 482mod foo {
512 #[path = "users.rs"] 483 #[path = "users.rs"]
513 mod bar; 484 mod bar;
514 } 485}
515
516 //- /users.rs
517 pub struct Baz;
518 "###,
519 );
520 486
521 assert_snapshot!(map, @r###" 487//- /users.rs
522 ⋮crate 488pub struct Baz;
523 ⋮foo: t 489"#,
524 490 expect![[r#"
525 ⋮crate::foo 491 crate
526 ⋮bar: t 492 foo: t
527 493
528 ⋮crate::foo::bar 494 crate::foo
529 ⋮Baz: t v 495 bar: t
530 "###); 496
497 crate::foo::bar
498 Baz: t v
499 "#]],
500 );
531} 501}
532 502
533#[test] 503#[test]
534fn module_resolution_decl_empty_path() { 504fn module_resolution_decl_empty_path() {
535 let map = def_map( 505 check(
536 r###" 506 r#"
537 //- /main.rs 507//- /main.rs
538 #[path = ""] // Should try to read `/` (a directory) 508#[path = ""] // Should try to read `/` (a directory)
539 mod foo; 509mod foo;
540 510
541 //- /foo.rs 511//- /foo.rs
542 pub struct Baz; 512pub struct Baz;
543 "###, 513"#,
514 expect![[r#"
515 crate
516 "#]],
544 ); 517 );
545
546 assert_snapshot!(map, @r###"
547 ⋮crate
548 "###);
549} 518}
550 519
551#[test] 520#[test]
552fn module_resolution_decl_inside_inline_module_relative_path() { 521fn module_resolution_decl_inside_inline_module_relative_path() {
553 let map = def_map( 522 check(
554 r###" 523 r#"
555 //- /main.rs 524//- /main.rs
556 #[path = "./models"] 525#[path = "./models"]
557 mod foo { 526mod foo { mod bar; }
558 mod bar; 527
559 } 528//- /models/bar.rs
560 529pub struct Baz;
561 //- /models/bar.rs 530"#,
562 pub struct Baz; 531 expect![[r#"
563 "###, 532 crate
533 foo: t
534
535 crate::foo
536 bar: t
537
538 crate::foo::bar
539 Baz: t v
540 "#]],
564 ); 541 );
565
566 assert_snapshot!(map, @r###"
567 ⋮crate
568 ⋮foo: t
569
570 ⋮crate::foo
571 ⋮bar: t
572
573 ⋮crate::foo::bar
574 ⋮Baz: t v
575 "###);
576} 542}
577 543
578#[test] 544#[test]
579fn module_resolution_decl_inside_inline_module_in_crate_root() { 545fn module_resolution_decl_inside_inline_module_in_crate_root() {
580 let map = def_map( 546 check(
581 r###" 547 r#"
582 //- /main.rs 548//- /main.rs
583 mod foo { 549mod foo {
584 #[path = "baz.rs"] 550 #[path = "baz.rs"]
585 mod bar; 551 mod bar;
586 } 552}
587 use self::foo::bar::Baz; 553use self::foo::bar::Baz;
588 554
589 //- /foo/baz.rs 555//- /foo/baz.rs
590 pub struct Baz; 556pub struct Baz;
591 "###, 557"#,
558 expect![[r#"
559 crate
560 Baz: t v
561 foo: t
562
563 crate::foo
564 bar: t
565
566 crate::foo::bar
567 Baz: t v
568 "#]],
592 ); 569 );
593
594 assert_snapshot!(map, @r###"
595 ⋮crate
596 ⋮Baz: t v
597 ⋮foo: t
598
599 ⋮crate::foo
600 ⋮bar: t
601
602 ⋮crate::foo::bar
603 ⋮Baz: t v
604 "###);
605} 570}
606 571
607#[test] 572#[test]
608fn module_resolution_decl_inside_inline_module_in_mod_rs() { 573fn module_resolution_decl_inside_inline_module_in_mod_rs() {
609 let map = def_map( 574 check(
610 r###" 575 r#"
611 //- /main.rs 576//- /main.rs
612 mod foo; 577mod foo;
578
579//- /foo/mod.rs
580mod bar {
581 #[path = "qwe.rs"]
582 pub mod baz;
583}
584use self::bar::baz::Baz;
613 585
614 //- /foo/mod.rs 586//- /foo/bar/qwe.rs
615 mod bar { 587pub struct Baz;
616 #[path = "qwe.rs"] 588"#,
617 pub mod baz; 589 expect![[r#"
618 } 590 crate
619 use self::bar::baz::Baz; 591 foo: t
620 592
621 //- /foo/bar/qwe.rs 593 crate::foo
622 pub struct Baz; 594 Baz: t v
623 "###, 595 bar: t
624 ); 596
597 crate::foo::bar
598 baz: t
625 599
626 assert_snapshot!(map, @r###" 600 crate::foo::bar::baz
627 ⋮crate 601 Baz: t v
628 ⋮foo: t 602 "#]],
629 603 );
630 ⋮crate::foo
631 ⋮Baz: t v
632 ⋮bar: t
633
634 ⋮crate::foo::bar
635 ⋮baz: t
636
637 ⋮crate::foo::bar::baz
638 ⋮Baz: t v
639 "###);
640} 604}
641 605
642#[test] 606#[test]
643fn module_resolution_decl_inside_inline_module_in_non_crate_root() { 607fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
644 let map = def_map( 608 check(
645 r###" 609 r#"
646 //- /main.rs 610//- /main.rs
647 mod foo; 611mod foo;
612
613//- /foo.rs
614mod bar {
615 #[path = "qwe.rs"]
616 pub mod baz;
617}
618use self::bar::baz::Baz;
648 619
649 //- /foo.rs 620//- /foo/bar/qwe.rs
650 mod bar { 621pub struct Baz;
651 #[path = "qwe.rs"] 622"#,
652 pub mod baz; 623 expect![[r#"
653 } 624 crate
654 use self::bar::baz::Baz; 625 foo: t
655
656 //- /foo/bar/qwe.rs
657 pub struct Baz;
658 "###,
659 );
660 626
661 assert_snapshot!(map, @r###" 627 crate::foo
662 ⋮crate 628 Baz: t v
663 ⋮foo: t 629 bar: t
664 630
665 ⋮crate::foo 631 crate::foo::bar
666 ⋮Baz: t v 632 baz: t
667 ⋮bar: t 633
668 634 crate::foo::bar::baz
669 ⋮crate::foo::bar 635 Baz: t v
670 ⋮baz: t 636 "#]],
671 637 );
672 ⋮crate::foo::bar::baz
673 ⋮Baz: t v
674 "###);
675} 638}
676 639
677#[test] 640#[test]
678fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { 641fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {
679 let map = def_map( 642 check(
680 r###" 643 r#"
681 //- /main.rs 644//- /main.rs
682 mod foo; 645mod foo;
646
647//- /foo.rs
648#[path = "bar"]
649mod bar {
650 pub mod baz;
651}
652use self::bar::baz::Baz;
683 653
684 //- /foo.rs 654//- /bar/baz.rs
685 #[path = "bar"] 655pub struct Baz;
686 mod bar { 656"#,
687 pub mod baz; 657 expect![[r#"
688 } 658 crate
689 use self::bar::baz::Baz; 659 foo: t
690 660
691 //- /bar/baz.rs 661 crate::foo
692 pub struct Baz; 662 Baz: t v
693 "###, 663 bar: t
694 );
695 664
696 assert_snapshot!(map, @r###" 665 crate::foo::bar
697 ⋮crate 666 baz: t
698 ⋮foo: t 667
699 668 crate::foo::bar::baz
700 ⋮crate::foo 669 Baz: t v
701 ⋮Baz: t v 670 "#]],
702 ⋮bar: t 671 );
703
704 ⋮crate::foo::bar
705 ⋮baz: t
706
707 ⋮crate::foo::bar::baz
708 ⋮Baz: t v
709 "###);
710} 672}
711 673
712#[test] 674#[test]
@@ -724,116 +686,111 @@ fn unresolved_module_diagnostics() {
724 686
725 let crate_def_map = db.crate_def_map(krate); 687 let crate_def_map = db.crate_def_map(krate);
726 688
727 insta::assert_debug_snapshot!( 689 expect![[r#"
728 crate_def_map.diagnostics, 690 [
729 @r###" 691 UnresolvedModule {
730 [ 692 module: Idx::<ModuleData>(0),
731 UnresolvedModule { 693 declaration: InFile {
732 module: Idx::<ModuleData>(0), 694 file_id: HirFileId(
733 declaration: InFile {
734 file_id: HirFileId(
735 FileId(
736 FileId( 695 FileId(
737 0, 696 FileId(
697 0,
698 ),
738 ), 699 ),
739 ), 700 ),
740 ), 701 value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1),
741 value: FileAstId::<ra_syntax::ast::generated::nodes::Module>(1), 702 },
703 candidate: "bar.rs",
742 }, 704 },
743 candidate: "bar.rs", 705 ]
744 }, 706 "#]]
745 ] 707 .assert_debug_eq(&crate_def_map.diagnostics);
746 "###
747 );
748} 708}
749 709
750#[test] 710#[test]
751fn module_resolution_decl_inside_module_in_non_crate_root_2() { 711fn module_resolution_decl_inside_module_in_non_crate_root_2() {
752 let map = def_map( 712 check(
753 r###" 713 r#"
754 //- /main.rs 714//- /main.rs
755 #[path="module/m2.rs"] 715#[path="module/m2.rs"]
756 mod module; 716mod module;
757 717
758 //- /module/m2.rs 718//- /module/m2.rs
759 pub mod submod; 719pub mod submod;
760 720
761 //- /module/submod.rs 721//- /module/submod.rs
762 pub struct Baz; 722pub struct Baz;
763 "###, 723"#,
724 expect![[r#"
725 crate
726 module: t
727
728 crate::module
729 submod: t
730
731 crate::module::submod
732 Baz: t v
733 "#]],
764 ); 734 );
765
766 assert_snapshot!(map, @r###"
767 ⋮crate
768 ⋮module: t
769
770 ⋮crate::module
771 ⋮submod: t
772
773 ⋮crate::module::submod
774 ⋮Baz: t v
775 "###);
776} 735}
777 736
778#[test] 737#[test]
779fn nested_out_of_line_module() { 738fn nested_out_of_line_module() {
780 let map = def_map( 739 check(
781 r###" 740 r#"
782 //- /lib.rs 741//- /lib.rs
783 mod a { 742mod a {
784 mod b { 743 mod b {
785 mod c; 744 mod c;
786 } 745 }
787 } 746}
788
789 //- /a/b/c.rs
790 struct X;
791 "###,
792 );
793 747
794 assert_snapshot!(map, @r###" 748//- /a/b/c.rs
795 ⋮crate 749struct X;
796 ⋮a: t 750"#,
797 751 expect![[r#"
798 ⋮crate::a 752 crate
799 ⋮b: t 753 a: t
800 754
801 ⋮crate::a::b 755 crate::a
802 ⋮c: t 756 b: t
803 757
804 ⋮crate::a::b::c 758 crate::a::b
805 ⋮X: t v 759 c: t
806 "###); 760
761 crate::a::b::c
762 X: t v
763 "#]],
764 );
807} 765}
808 766
809#[test] 767#[test]
810fn nested_out_of_line_module_with_path() { 768fn nested_out_of_line_module_with_path() {
811 let map = def_map( 769 check(
812 r###" 770 r#"
813 //- /lib.rs 771//- /lib.rs
814 mod a { 772mod a {
815 #[path = "d/e"] 773 #[path = "d/e"]
816 mod b { 774 mod b {
817 mod c; 775 mod c;
818 } 776 }
819 } 777}
820 778
821 //- /a/d/e/c.rs 779//- /a/d/e/c.rs
822 struct X; 780struct X;
823 "###, 781"#,
824 ); 782 expect![[r#"
783 crate
784 a: t
825 785
826 assert_snapshot!(map, @r###" 786 crate::a
827 ⋮crate 787 b: t
828 ⋮a: t 788
829 789 crate::a::b
830 ⋮crate::a 790 c: t
831 ⋮b: t 791
832 792 crate::a::b::c
833 ⋮crate::a::b 793 X: t v
834 ⋮c: t 794 "#]],
835 795 );
836 ⋮crate::a::b::c
837 ⋮X: t v
838 "###);
839} 796}
diff --git a/crates/ra_hir_def/src/nameres/tests/primitives.rs b/crates/ra_hir_def/src/nameres/tests/primitives.rs
index 0e2708658..215e8952d 100644
--- a/crates/ra_hir_def/src/nameres/tests/primitives.rs
+++ b/crates/ra_hir_def/src/nameres/tests/primitives.rs
@@ -2,23 +2,22 @@ use super::*;
2 2
3#[test] 3#[test]
4fn primitive_reexport() { 4fn primitive_reexport() {
5 let map = def_map( 5 check(
6 " 6 r#"
7 //- /lib.rs 7//- /lib.rs
8 mod foo; 8mod foo;
9 use foo::int; 9use foo::int;
10 10
11 //- /foo.rs 11//- /foo.rs
12 pub use i32 as int; 12pub use i32 as int;
13 ", 13"#,
14 ); 14 expect![[r#"
15 assert_snapshot!(map, @r###" 15 crate
16 ⋮crate 16 foo: t
17 ⋮foo: t 17 int: t
18 ⋮int: t 18
19 19 crate::foo
20 ⋮crate::foo 20 int: t
21 ⋮int: t 21 "#]],
22 "###
23 ); 22 );
24} 23}
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 190d6d98d..68b9f89c3 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -67,7 +67,7 @@ impl ModPath {
67 67
68 /// Calls `cb` with all paths, represented by this use item. 68 /// Calls `cb` with all paths, represented by this use item.
69 pub(crate) fn expand_use_item( 69 pub(crate) fn expand_use_item(
70 item_src: InFile<ast::UseItem>, 70 item_src: InFile<ast::Use>,
71 hygiene: &Hygiene, 71 hygiene: &Hygiene,
72 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), 72 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
73 ) { 73 ) {
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
index 6a0c019fd..07d17916a 100644
--- a/crates/ra_hir_def/src/path/lower.rs
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -9,7 +9,7 @@ use hir_expand::{
9 hygiene::Hygiene, 9 hygiene::Hygiene,
10 name::{name, AsName}, 10 name::{name, AsName},
11}; 11};
12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; 12use ra_syntax::ast::{self, AstNode, TypeBoundsOwner};
13 13
14use super::AssociatedTypeBinding; 14use super::AssociatedTypeBinding;
15use crate::{ 15use crate::{
@@ -189,14 +189,14 @@ fn lower_generic_args_from_fn_path(
189 if let Some(params) = params { 189 if let Some(params) = params {
190 let mut param_types = Vec::new(); 190 let mut param_types = Vec::new();
191 for param in params.params() { 191 for param in params.params() {
192 let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); 192 let type_ref = TypeRef::from_ast_opt(&ctx, param.ty());
193 param_types.push(type_ref); 193 param_types.push(type_ref);
194 } 194 }
195 let arg = GenericArg::Type(TypeRef::Tuple(param_types)); 195 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
196 args.push(arg); 196 args.push(arg);
197 } 197 }
198 if let Some(ret_type) = ret_type { 198 if let Some(ret_type) = ret_type {
199 let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.type_ref()); 199 let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty());
200 bindings.push(AssociatedTypeBinding { 200 bindings.push(AssociatedTypeBinding {
201 name: name![Output], 201 name: name![Output],
202 type_ref: Some(type_ref), 202 type_ref: Some(type_ref),
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
index 7cc655487..794be45e8 100644
--- a/crates/ra_hir_def/src/path/lower/lower_use.rs
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -31,7 +31,7 @@ pub(crate) fn lower_use_tree(
31 lower_use_tree(prefix.clone(), child_tree, hygiene, cb); 31 lower_use_tree(prefix.clone(), child_tree, hygiene, cb);
32 } 32 }
33 } else { 33 } else {
34 let alias = tree.alias().map(|a| { 34 let alias = tree.rename().map(|a| {
35 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) 35 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
36 }); 36 });
37 let is_glob = tree.star_token().is_some(); 37 let is_glob = tree.star_token().is_some();
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 15fdd9019..0bf51eb7b 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -511,11 +511,9 @@ impl Scope {
511 }); 511 });
512 } 512 }
513 } 513 }
514 Scope::LocalItemsScope(body) => { 514 Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| {
515 body.item_scope.entries_without_primitives().for_each(|(name, def)| { 515 f(name.clone(), ScopeDef::PerNs(def));
516 f(name.clone(), ScopeDef::PerNs(def)); 516 }),
517 })
518 }
519 Scope::GenericParams { params, def } => { 517 Scope::GenericParams { params, def } => {
520 for (local_id, param) in params.types.iter() { 518 for (local_id, param) in params.types.iter() {
521 if let Some(name) = &param.name { 519 if let Some(name) = &param.name {
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index 4581d8745..339f819b8 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -1,7 +1,7 @@
1//! Database used for testing `hir_def`. 1//! Database used for testing `hir_def`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
@@ -18,10 +18,10 @@ use crate::db::DefDatabase;
18 crate::db::InternDatabaseStorage, 18 crate::db::InternDatabaseStorage,
19 crate::db::DefDatabaseStorage 19 crate::db::DefDatabaseStorage
20)] 20)]
21#[derive(Debug, Default)] 21#[derive(Default)]
22pub struct TestDB { 22pub struct TestDB {
23 runtime: salsa::Runtime<TestDB>, 23 storage: salsa::Storage<TestDB>,
24 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 24 events: Mutex<Option<Vec<salsa::Event>>>,
25} 25}
26 26
27impl Upcast<dyn AstDatabase> for TestDB { 27impl Upcast<dyn AstDatabase> for TestDB {
@@ -37,20 +37,20 @@ impl Upcast<dyn DefDatabase> for TestDB {
37} 37}
38 38
39impl salsa::Database for TestDB { 39impl salsa::Database for TestDB {
40 fn salsa_runtime(&self) -> &salsa::Runtime<Self> { 40 fn salsa_event(&self, event: salsa::Event) {
41 &self.runtime
42 }
43 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
44 &mut self.runtime
45 }
46 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
47 let mut events = self.events.lock().unwrap(); 41 let mut events = self.events.lock().unwrap();
48 if let Some(events) = &mut *events { 42 if let Some(events) = &mut *events {
49 events.push(event()); 43 events.push(event);
50 } 44 }
51 } 45 }
52} 46}
53 47
48impl fmt::Debug for TestDB {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.debug_struct("TestDB").finish()
51 }
52}
53
54impl panic::RefUnwindSafe for TestDB {} 54impl panic::RefUnwindSafe for TestDB {}
55 55
56impl FileLoader for TestDB { 56impl FileLoader for TestDB {
@@ -78,7 +78,7 @@ impl TestDB {
78 panic!("Can't find module for file") 78 panic!("Can't find module for file")
79 } 79 }
80 80
81 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { 81 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
82 *self.events.lock().unwrap() = Some(Vec::new()); 82 *self.events.lock().unwrap() = Some(Vec::new());
83 f(); 83 f();
84 self.events.lock().unwrap().take().unwrap() 84 self.events.lock().unwrap().take().unwrap()
@@ -92,7 +92,7 @@ impl TestDB {
92 // This pretty horrible, but `Debug` is the only way to inspect 92 // This pretty horrible, but `Debug` is the only way to inspect
93 // QueryDescriptor at the moment. 93 // QueryDescriptor at the moment.
94 salsa::EventKind::WillExecute { database_key } => { 94 salsa::EventKind::WillExecute { database_key } => {
95 Some(format!("{:?}", database_key)) 95 Some(format!("{:?}", database_key.debug(self)))
96 } 96 }
97 _ => None, 97 _ => None,
98 }) 98 })
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index 86a77b704..a5dc10eac 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -1,7 +1,7 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3 3
4use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; 4use ra_syntax::ast::{self};
5 5
6use crate::{body::LowerCtx, path::Path}; 6use crate::{body::LowerCtx, path::Path};
7 7
@@ -63,7 +63,7 @@ pub enum TypeRef {
63 Array(Box<TypeRef> /*, Expr*/), 63 Array(Box<TypeRef> /*, Expr*/),
64 Slice(Box<TypeRef>), 64 Slice(Box<TypeRef>),
65 /// A fn pointer. Last element of the vector is the return type. 65 /// A fn pointer. Last element of the vector is the return type.
66 Fn(Vec<TypeRef>), 66 Fn(Vec<TypeRef>, bool /*varargs*/),
67 // For 67 // For
68 ImplTrait(Vec<TypeBound>), 68 ImplTrait(Vec<TypeBound>),
69 DynTrait(Vec<TypeBound>), 69 DynTrait(Vec<TypeBound>),
@@ -82,7 +82,7 @@ impl TypeRef {
82 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 82 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
83 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self { 83 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self {
84 match node { 84 match node {
85 ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), 85 ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
86 ast::TypeRef::TupleType(inner) => { 86 ast::TypeRef::TupleType(inner) => {
87 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) 87 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
88 } 88 }
@@ -96,18 +96,18 @@ impl TypeRef {
96 .unwrap_or(TypeRef::Error) 96 .unwrap_or(TypeRef::Error)
97 } 97 }
98 ast::TypeRef::PointerType(inner) => { 98 ast::TypeRef::PointerType(inner) => {
99 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); 99 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
100 let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 100 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
101 TypeRef::RawPtr(Box::new(inner_ty), mutability) 101 TypeRef::RawPtr(Box::new(inner_ty), mutability)
102 } 102 }
103 ast::TypeRef::ArrayType(inner) => { 103 ast::TypeRef::ArrayType(inner) => {
104 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) 104 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
105 } 105 }
106 ast::TypeRef::SliceType(inner) => { 106 ast::TypeRef::SliceType(inner) => {
107 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) 107 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
108 } 108 }
109 ast::TypeRef::ReferenceType(inner) => { 109 ast::TypeRef::ReferenceType(inner) => {
110 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); 110 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
111 let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 111 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
112 TypeRef::Reference(Box::new(inner_ty), mutability) 112 TypeRef::Reference(Box::new(inner_ty), mutability)
113 } 113 }
@@ -115,22 +115,24 @@ impl TypeRef {
115 ast::TypeRef::FnPointerType(inner) => { 115 ast::TypeRef::FnPointerType(inner) => {
116 let ret_ty = inner 116 let ret_ty = inner
117 .ret_type() 117 .ret_type()
118 .and_then(|rt| rt.type_ref()) 118 .and_then(|rt| rt.ty())
119 .map(|it| TypeRef::from_ast(ctx, it)) 119 .map(|it| TypeRef::from_ast(ctx, it))
120 .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); 120 .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
121 let mut is_varargs = false;
121 let mut params = if let Some(pl) = inner.param_list() { 122 let mut params = if let Some(pl) = inner.param_list() {
122 pl.params() 123 if let Some(param) = pl.params().last() {
123 .map(|p| p.ascribed_type()) 124 is_varargs = param.dotdotdot_token().is_some();
124 .map(|it| TypeRef::from_ast_opt(&ctx, it)) 125 }
125 .collect() 126
127 pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect()
126 } else { 128 } else {
127 Vec::new() 129 Vec::new()
128 }; 130 };
129 params.push(ret_ty); 131 params.push(ret_ty);
130 TypeRef::Fn(params) 132 TypeRef::Fn(params, is_varargs)
131 } 133 }
132 // for types are close enough for our purposes to the inner type for now... 134 // for types are close enough for our purposes to the inner type for now...
133 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), 135 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
134 ast::TypeRef::ImplTraitType(inner) => { 136 ast::TypeRef::ImplTraitType(inner) => {
135 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 137 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
136 } 138 }
@@ -158,7 +160,9 @@ impl TypeRef {
158 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { 160 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
159 f(type_ref); 161 f(type_ref);
160 match type_ref { 162 match type_ref {
161 TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), 163 TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
164 types.iter().for_each(|t| go(t, f))
165 }
162 TypeRef::RawPtr(type_ref, _) 166 TypeRef::RawPtr(type_ref, _)
163 | TypeRef::Reference(type_ref, _) 167 | TypeRef::Reference(type_ref, _)
164 | TypeRef::Array(type_ref) 168 | TypeRef::Array(type_ref)
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs
index 8136cb50c..1abffb4c3 100644
--- a/crates/ra_hir_def/src/visibility.rs
+++ b/crates/ra_hir_def/src/visibility.rs
@@ -5,6 +5,7 @@ use ra_syntax::ast;
5 5
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 nameres::CrateDefMap,
8 path::{ModPath, PathKind}, 9 path::{ModPath, PathKind},
9 ModuleId, 10 ModuleId,
10}; 11};
@@ -115,7 +116,7 @@ impl Visibility {
115 116
116 pub(crate) fn is_visible_from_def_map( 117 pub(crate) fn is_visible_from_def_map(
117 self, 118 self,
118 def_map: &crate::nameres::CrateDefMap, 119 def_map: &CrateDefMap,
119 from_module: crate::LocalModuleId, 120 from_module: crate::LocalModuleId,
120 ) -> bool { 121 ) -> bool {
121 let to_module = match self { 122 let to_module = match self {
@@ -129,4 +130,42 @@ impl Visibility {
129 }); 130 });
130 ancestors.any(|m| m == to_module.local_id) 131 ancestors.any(|m| m == to_module.local_id)
131 } 132 }
133
134 /// Returns the most permissive visibility of `self` and `other`.
135 ///
136 /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
137 /// visible in unrelated modules).
138 pub(crate) fn max(self, other: Visibility, def_map: &CrateDefMap) -> Option<Visibility> {
139 match (self, other) {
140 (Visibility::Module(_), Visibility::Public)
141 | (Visibility::Public, Visibility::Module(_))
142 | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
143 (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
144 if mod_a.krate != mod_b.krate {
145 return None;
146 }
147
148 let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
149 let parent_id = def_map[*m].parent?;
150 Some(parent_id)
151 });
152 let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
153 let parent_id = def_map[*m].parent?;
154 Some(parent_id)
155 });
156
157 if a_ancestors.any(|m| m == mod_b.local_id) {
158 // B is above A
159 return Some(Visibility::Module(mod_b));
160 }
161
162 if b_ancestors.any(|m| m == mod_a.local_id) {
163 // A is above B
164 return Some(Visibility::Module(mod_a));
165 }
166
167 None
168 }
169 }
170 }
132} 171}
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index e5c9f3e99..6da0e2a16 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir_expand" 3name = "ra_hir_expand"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index f4d31526a..8bfe1b4ba 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -73,7 +73,7 @@ impl AstIdMap {
73 // change parent's id. This means that, say, adding a new function to a 73 // change parent's id. This means that, say, adding a new function to a
74 // trait does not change ids of top-level items, which helps caching. 74 // trait does not change ids of top-level items, which helps caching.
75 bfs(node, |it| { 75 bfs(node, |it| {
76 if let Some(module_item) = ast::ModuleItem::cast(it) { 76 if let Some(module_item) = ast::Item::cast(it) {
77 res.alloc(module_item.syntax()); 77 res.alloc(module_item.syntax());
78 } 78 }
79 }); 79 });
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 26b667b55..69fa907cb 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -4,7 +4,7 @@ use log::debug;
4 4
5use ra_parser::FragmentKind; 5use ra_parser::FragmentKind;
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner}, 7 ast::{self, AstNode, GenericParamsOwner, ModuleItemOwner, NameOwner},
8 match_ast, 8 match_ast,
9}; 9};
10 10
@@ -72,9 +72,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
72 let node = item.syntax(); 72 let node = item.syntax();
73 let (name, params) = match_ast! { 73 let (name, params) = match_ast! {
74 match node { 74 match node {
75 ast::StructDef(it) => (it.name(), it.type_param_list()), 75 ast::Struct(it) => (it.name(), it.generic_param_list()),
76 ast::EnumDef(it) => (it.name(), it.type_param_list()), 76 ast::Enum(it) => (it.name(), it.generic_param_list()),
77 ast::UnionDef(it) => (it.name(), it.type_param_list()), 77 ast::Union(it) => (it.name(), it.generic_param_list()),
78 _ => { 78 _ => {
79 debug!("unexpected node is {:?}", node); 79 debug!("unexpected node is {:?}", node);
80 return Err(mbe::ExpandError::ConversionError) 80 return Err(mbe::ExpandError::ConversionError)
@@ -161,7 +161,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
161 // XXX 161 // XXX
162 // All crates except core itself should have a dependency on core, 162 // All crates except core itself should have a dependency on core,
163 // We detect `core` by seeing whether it doesn't have such a dependency. 163 // We detect `core` by seeing whether it doesn't have such a dependency.
164 let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { 164 let tt = if cg[krate].dependencies.iter().any(|dep| &*dep.name == "core") {
165 quote! { core } 165 quote! { core }
166 } else { 166 } else {
167 quote! { crate } 167 quote! { crate }
@@ -276,7 +276,7 @@ mod tests {
276 let file_id = file_pos.file_id; 276 let file_id = file_pos.file_id;
277 let parsed = db.parse(file_id); 277 let parsed = db.parse(file_id);
278 let items: Vec<_> = 278 let items: Vec<_> =
279 parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); 279 parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
280 280
281 let ast_id_map = db.ast_id_map(file_id.into()); 281 let ast_id_map = db.ast_id_map(file_id.into());
282 282
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 626f9efd0..9f50569dc 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -272,7 +272,7 @@ fn format_args_expand(
272fn unquote_str(lit: &tt::Literal) -> Option<String> { 272fn unquote_str(lit: &tt::Literal) -> Option<String> {
273 let lit = ast::make::tokens::literal(&lit.to_string()); 273 let lit = ast::make::tokens::literal(&lit.to_string());
274 let token = ast::String::cast(lit)?; 274 let token = ast::String::cast(lit)?;
275 token.value() 275 token.value().map(|it| it.into_owned())
276} 276}
277 277
278fn concat_expand( 278fn concat_expand(
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index bf30d7151..41df66696 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,7 +6,7 @@ use mbe::{ExpandResult, MacroRules};
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode}; 9use ra_syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
@@ -72,6 +72,8 @@ pub trait AstDatabase: SourceDatabase {
72 72
73 #[salsa::interned] 73 #[salsa::interned]
74 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId; 74 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
75 fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
76 #[salsa::transparent]
75 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; 77 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
76 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; 78 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
77 fn parse_macro(&self, macro_file: MacroFile) 79 fn parse_macro(&self, macro_file: MacroFile)
@@ -148,10 +150,7 @@ pub(crate) fn macro_def(
148 } 150 }
149} 151}
150 152
151pub(crate) fn macro_arg( 153pub(crate) fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
152 db: &dyn AstDatabase,
153 id: MacroCallId,
154) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
155 let id = match id { 154 let id = match id {
156 MacroCallId::LazyMacro(id) => id, 155 MacroCallId::LazyMacro(id) => id,
157 MacroCallId::EagerMacro(_id) => { 156 MacroCallId::EagerMacro(_id) => {
@@ -161,7 +160,15 @@ pub(crate) fn macro_arg(
161 }; 160 };
162 let loc = db.lookup_intern_macro(id); 161 let loc = db.lookup_intern_macro(id);
163 let arg = loc.kind.arg(db)?; 162 let arg = loc.kind.arg(db)?;
164 let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?; 163 Some(arg.green().clone())
164}
165
166pub(crate) fn macro_arg(
167 db: &dyn AstDatabase,
168 id: MacroCallId,
169) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
170 let arg = db.macro_arg_text(id)?;
171 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg))?;
165 Some(Arc::new((tt, tmap))) 172 Some(Arc::new((tt, tmap)))
166} 173}
167 174
@@ -379,7 +386,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
379 MATCH_EXPR => FragmentKind::Expr, 386 MATCH_EXPR => FragmentKind::Expr,
380 MATCH_ARM => FragmentKind::Expr, 387 MATCH_ARM => FragmentKind::Expr,
381 MATCH_GUARD => FragmentKind::Expr, 388 MATCH_GUARD => FragmentKind::Expr,
382 RECORD_FIELD => FragmentKind::Expr, 389 RECORD_EXPR_FIELD => FragmentKind::Expr,
383 CALL_EXPR => FragmentKind::Expr, 390 CALL_EXPR => FragmentKind::Expr,
384 INDEX_EXPR => FragmentKind::Expr, 391 INDEX_EXPR => FragmentKind::Expr,
385 METHOD_CALL_EXPR => FragmentKind::Expr, 392 METHOD_CALL_EXPR => FragmentKind::Expr,
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 99209c6e8..84ba97b14 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -24,11 +24,14 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> InFile<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn as_any(&self) -> &(dyn Any + Send + 'static); 26 fn as_any(&self) -> &(dyn Any + Send + 'static);
27 fn is_experimental(&self) -> bool {
28 false
29 }
27} 30}
28 31
29pub trait AstDiagnostic { 32pub trait AstDiagnostic {
30 type AST; 33 type AST;
31 fn ast(&self, db: &impl AstDatabase) -> Self::AST; 34 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
32} 35}
33 36
34impl dyn Diagnostic { 37impl dyn Diagnostic {
@@ -44,16 +47,48 @@ impl dyn Diagnostic {
44 47
45pub struct DiagnosticSink<'a> { 48pub struct DiagnosticSink<'a> {
46 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, 49 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
50 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
47 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, 51 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
48} 52}
49 53
50impl<'a> DiagnosticSink<'a> { 54impl<'a> DiagnosticSink<'a> {
51 /// FIXME: split `new` and `on` into a separate builder type 55 pub fn push(&mut self, d: impl Diagnostic) {
52 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { 56 let d: &dyn Diagnostic = &d;
53 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } 57 self._push(d);
58 }
59
60 fn _push(&mut self, d: &dyn Diagnostic) {
61 for filter in &mut self.filters {
62 if !filter(d) {
63 return;
64 }
65 }
66 for cb in &mut self.callbacks {
67 match cb(d) {
68 Ok(()) => return,
69 Err(()) => (),
70 }
71 }
72 (self.default_callback)(d)
54 } 73 }
74}
55 75
56 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> { 76pub struct DiagnosticSinkBuilder<'a> {
77 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
78 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
79}
80
81impl<'a> DiagnosticSinkBuilder<'a> {
82 pub fn new() -> Self {
83 Self { callbacks: Vec::new(), filters: Vec::new() }
84 }
85
86 pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
87 self.filters.push(Box::new(cb));
88 self
89 }
90
91 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
57 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { 92 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
58 Some(d) => { 93 Some(d) => {
59 cb(d); 94 cb(d);
@@ -65,18 +100,11 @@ impl<'a> DiagnosticSink<'a> {
65 self 100 self
66 } 101 }
67 102
68 pub fn push(&mut self, d: impl Diagnostic) { 103 pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
69 let d: &dyn Diagnostic = &d; 104 DiagnosticSink {
70 self._push(d); 105 callbacks: self.callbacks,
71 } 106 filters: self.filters,
72 107 default_callback: Box::new(default_callback),
73 fn _push(&mut self, d: &dyn Diagnostic) {
74 for cb in self.callbacks.iter_mut() {
75 match cb(d) {
76 Ok(()) => return,
77 Err(()) => (),
78 }
79 } 108 }
80 (self.default_callback)(d)
81 } 109 }
82} 110}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 5eac2605b..2e8d63691 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -88,6 +88,25 @@ impl HirFileId {
88 } 88 }
89 } 89 }
90 90
91 pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
92 let mut level = 0;
93 let mut curr = self;
94 while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
95 level += 1;
96 curr = match macro_file.macro_call_id {
97 MacroCallId::LazyMacro(id) => {
98 let loc = db.lookup_intern_macro(id);
99 loc.kind.file_id()
100 }
101 MacroCallId::EagerMacro(id) => {
102 let loc = db.lookup_intern_eager_expansion(id);
103 loc.file_id
104 }
105 };
106 }
107 level
108 }
109
91 /// If this is a macro call, returns the syntax node of the call. 110 /// If this is a macro call, returns the syntax node of the call.
92 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { 111 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
93 match self.0 { 112 match self.0 {
@@ -140,7 +159,7 @@ impl HirFileId {
140 } 159 }
141 160
142 /// Indicate it is macro file generated for builtin derive 161 /// Indicate it is macro file generated for builtin derive
143 pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::ModuleItem>> { 162 pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Item>> {
144 match self.0 { 163 match self.0 {
145 HirFileIdRepr::FileId(_) => None, 164 HirFileIdRepr::FileId(_) => None,
146 HirFileIdRepr::MacroFile(macro_file) => { 165 HirFileIdRepr::MacroFile(macro_file) => {
@@ -155,7 +174,7 @@ impl HirFileId {
155 MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), 174 MacroDefKind::BuiltInDerive(_) => loc.kind.node(db),
156 _ => return None, 175 _ => return None,
157 }; 176 };
158 Some(item.with_value(ast::ModuleItem::cast(item.value.clone())?)) 177 Some(item.with_value(ast::Item::cast(item.value.clone())?))
159 } 178 }
160 } 179 }
161 } 180 }
@@ -239,18 +258,18 @@ pub struct MacroCallLoc {
239#[derive(Debug, Clone, PartialEq, Eq, Hash)] 258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub enum MacroCallKind { 259pub enum MacroCallKind {
241 FnLike(AstId<ast::MacroCall>), 260 FnLike(AstId<ast::MacroCall>),
242 Attr(AstId<ast::ModuleItem>, String), 261 Attr(AstId<ast::Item>, String),
243} 262}
244 263
245impl MacroCallKind { 264impl MacroCallKind {
246 pub fn file_id(&self) -> HirFileId { 265 fn file_id(&self) -> HirFileId {
247 match self { 266 match self {
248 MacroCallKind::FnLike(ast_id) => ast_id.file_id, 267 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
249 MacroCallKind::Attr(ast_id, _) => ast_id.file_id, 268 MacroCallKind::Attr(ast_id, _) => ast_id.file_id,
250 } 269 }
251 } 270 }
252 271
253 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { 272 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
254 match self { 273 match self {
255 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), 274 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
256 MacroCallKind::Attr(ast_id, _) => { 275 MacroCallKind::Attr(ast_id, _) => {
@@ -259,7 +278,7 @@ impl MacroCallKind {
259 } 278 }
260 } 279 }
261 280
262 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 281 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
263 match self { 282 match self {
264 MacroCallKind::FnLike(ast_id) => { 283 MacroCallKind::FnLike(ast_id) => {
265 Some(ast_id.to_node(db).token_tree()?.syntax().clone()) 284 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 1b0303685..969a2e5b8 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -117,7 +117,7 @@ impl AsName for ast::FieldKind {
117 117
118impl AsName for ra_db::Dependency { 118impl AsName for ra_db::Dependency {
119 fn as_name(&self) -> Name { 119 fn as_name(&self) -> Name {
120 Name::new_text(self.name.clone()) 120 Name::new_text(SmolStr::new(&*self.name))
121 } 121 }
122} 122}
123 123
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index 09fc18c36..332fa556f 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -1,7 +1,7 @@
1//! Database used for testing `hir_expand`. 1//! Database used for testing `hir_expand`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
@@ -13,25 +13,23 @@ use rustc_hash::FxHashSet;
13 ra_db::SourceDatabaseStorage, 13 ra_db::SourceDatabaseStorage,
14 crate::db::AstDatabaseStorage 14 crate::db::AstDatabaseStorage
15)] 15)]
16#[derive(Debug, Default)] 16#[derive(Default)]
17pub struct TestDB { 17pub struct TestDB {
18 runtime: salsa::Runtime<TestDB>, 18 storage: salsa::Storage<TestDB>,
19 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 19 events: Mutex<Option<Vec<salsa::Event>>>,
20} 20}
21 21
22impl salsa::Database for TestDB { 22impl fmt::Debug for TestDB {
23 fn salsa_runtime(&self) -> &salsa::Runtime<Self> { 23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 &self.runtime 24 f.debug_struct("TestDB").finish()
25 }
26
27 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
28 &mut self.runtime
29 } 25 }
26}
30 27
31 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { 28impl salsa::Database for TestDB {
29 fn salsa_event(&self, event: salsa::Event) {
32 let mut events = self.events.lock().unwrap(); 30 let mut events = self.events.lock().unwrap();
33 if let Some(events) = &mut *events { 31 if let Some(events) = &mut *events {
34 events.push(event()); 32 events.push(event);
35 } 33 }
36 } 34 }
37} 35}
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index d6df48db2..623ce261a 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir_ty" 3name = "ra_hir_ty"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -27,8 +28,13 @@ test_utils = { path = "../test_utils" }
27 28
28scoped-tls = "1" 29scoped-tls = "1"
29 30
30chalk-solve = { version = "0.15.0" } 31chalk-solve = { version = "0.19.0" }
31chalk-ir = { version = "0.15.0" } 32chalk-ir = { version = "0.19.0" }
33chalk-recursive = { version = "0.19.0" }
32 34
33[dev-dependencies] 35[dev-dependencies]
34insta = "0.16.0" 36expect = { path = "../expect" }
37
38tracing = "0.1"
39tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
40tracing-tree = { version = "0.1.4" }
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 1b0f84c5c..c727012c6 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -37,7 +37,7 @@ pub(crate) fn deref(
37 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
38) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
39 if let Some(derefed) = ty.value.value.builtin_deref() { 39 if let Some(derefed) = ty.value.value.builtin_deref() {
40 Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) 40 Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() })
41 } else { 41 } else {
42 deref_by_trait(db, krate, ty) 42 deref_by_trait(db, krate, ty)
43 } 43 }
@@ -68,8 +68,8 @@ fn deref_by_trait(
68 68
69 // Check that the type implements Deref at all 69 // Check that the type implements Deref at all
70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; 70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
71 let implements_goal = super::Canonical { 71 let implements_goal = Canonical {
72 num_vars: ty.value.num_vars, 72 kinds: ty.value.kinds.clone(),
73 value: InEnvironment { 73 value: InEnvironment {
74 value: Obligation::Trait(trait_ref), 74 value: Obligation::Trait(trait_ref),
75 environment: ty.environment.clone(), 75 environment: ty.environment.clone(),
@@ -81,7 +81,7 @@ fn deref_by_trait(
81 81
82 // Now do the assoc type projection 82 // Now do the assoc type projection
83 let projection = super::traits::ProjectionPredicate { 83 let projection = super::traits::ProjectionPredicate {
84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), 84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
85 projection_ty: super::ProjectionTy { associated_ty: target, parameters }, 85 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
86 }; 86 };
87 87
@@ -89,7 +89,8 @@ fn deref_by_trait(
89 89
90 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 90 let in_env = InEnvironment { value: obligation, environment: ty.environment };
91 91
92 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; 92 let canonical =
93 Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General)));
93 94
94 let solution = db.trait_solve(krate, canonical)?; 95 let solution = db.trait_solve(krate, canonical)?;
95 96
@@ -110,7 +111,7 @@ fn deref_by_trait(
110 // assumptions will be broken. We would need to properly introduce 111 // assumptions will be broken. We would need to properly introduce
111 // new variables in that case 112 // new variables in that case
112 113
113 for i in 1..vars.0.num_vars { 114 for i in 1..vars.0.kinds.len() {
114 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 115 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
115 { 116 {
116 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 117 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
@@ -119,7 +120,7 @@ fn deref_by_trait(
119 } 120 }
120 Some(Canonical { 121 Some(Canonical {
121 value: vars.0.value[vars.0.value.len() - 1].clone(), 122 value: vars.0.value[vars.0.value.len() - 1].clone(),
122 num_vars: vars.0.num_vars, 123 kinds: vars.0.kinds.clone(),
123 }) 124 })
124 } 125 }
125 Solution::Ambig(_) => { 126 Solution::Ambig(_) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index cad553273..c773adc67 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -3,23 +3,22 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TypeParamId, 6 db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId,
7 VariantId, 7 TypeParamId, VariantId,
8}; 8};
9use ra_arena::map::ArenaMap; 9use ra_arena::map::ArenaMap;
10use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; 10use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{InherentImpls, TraitImpls},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::chalk,
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDefId, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
18}; 18};
19use hir_expand::name::Name; 19use hir_expand::name::Name;
20 20
21#[salsa::query_group(HirDatabaseStorage)] 21#[salsa::query_group(HirDatabaseStorage)]
22#[salsa::requires(salsa::Database)]
23pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { 22pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
24 #[salsa::invoke(infer_wait)] 23 #[salsa::invoke(infer_wait)]
25 #[salsa::transparent] 24 #[salsa::transparent]
@@ -46,7 +45,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
46 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; 45 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
47 46
48 #[salsa::invoke(crate::callable_item_sig)] 47 #[salsa::invoke(crate::callable_item_sig)]
49 fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig; 48 fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
50 49
51 #[salsa::invoke(crate::lower::return_type_impl_traits)] 50 #[salsa::invoke(crate::lower::return_type_impl_traits)]
52 fn return_type_impl_traits( 51 fn return_type_impl_traits(
@@ -67,25 +66,24 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 66 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; 67 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 68
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 69 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 70 fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
72 71
73 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] 72 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
74 fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; 73 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
74
75 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
76 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
75 77
76 // Interned IDs for Chalk integration 78 // Interned IDs for Chalk integration
77 #[salsa::interned] 79 #[salsa::interned]
78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 80 fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
79 #[salsa::interned]
80 fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
81 #[salsa::interned] 81 #[salsa::interned]
82 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; 82 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
83 #[salsa::interned] 83 #[salsa::interned]
84 fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId; 84 fn intern_impl_trait_id(&self, id: OpaqueTyId) -> InternedOpaqueTyId;
85 #[salsa::interned] 85 #[salsa::interned]
86 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 86 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> ClosureId;
87 #[salsa::interned]
88 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
89 87
90 #[salsa::invoke(chalk::associated_ty_data_query)] 88 #[salsa::invoke(chalk::associated_ty_data_query)]
91 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; 89 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>;
@@ -149,3 +147,13 @@ impl_intern_key!(GlobalTypeParamId);
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
150pub struct InternedOpaqueTyId(salsa::InternId); 148pub struct InternedOpaqueTyId(salsa::InternId);
151impl_intern_key!(InternedOpaqueTyId); 149impl_intern_key!(InternedOpaqueTyId);
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
152pub struct ClosureId(salsa::InternId);
153impl_intern_key!(ClosureId);
154
155/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
156/// we have different IDs for struct and enum variant constructors.
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
158pub struct InternedCallableDefId(salsa::InternId);
159impl_intern_key!(InternedCallableDefId);
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index a59efb347..f210c305a 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -1,18 +1,35 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2mod expr;
3mod match_check;
4mod unsafe_check;
2 5
3use std::any::Any; 6use std::any::Any;
4 7
8use hir_def::DefWithBodyId;
9use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
5use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; 10use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
11use ra_prof::profile;
6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 12use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
7use stdx::format_to; 13use stdx::format_to;
8 14
9pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; 15use crate::db::HirDatabase;
10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 16
17pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields};
18
19pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
20 let _p = profile("validate_body");
21 let infer = db.infer(owner);
22 infer.add_diagnostics(db, owner, sink);
23 let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
24 validator.validate_body(db);
25 let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
26 validator.validate_body(db);
27}
11 28
12#[derive(Debug)] 29#[derive(Debug)]
13pub struct NoSuchField { 30pub struct NoSuchField {
14 pub file: HirFileId, 31 pub file: HirFileId,
15 pub field: AstPtr<ast::RecordField>, 32 pub field: AstPtr<ast::RecordExprField>,
16} 33}
17 34
18impl Diagnostic for NoSuchField { 35impl Diagnostic for NoSuchField {
@@ -30,19 +47,19 @@ impl Diagnostic for NoSuchField {
30} 47}
31 48
32impl AstDiagnostic for NoSuchField { 49impl AstDiagnostic for NoSuchField {
33 type AST = ast::RecordField; 50 type AST = ast::RecordExprField;
34 51
35 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 52 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
36 let root = db.parse_or_expand(self.source().file_id).unwrap(); 53 let root = db.parse_or_expand(self.source().file_id).unwrap();
37 let node = self.source().value.to_node(&root); 54 let node = self.source().value.to_node(&root);
38 ast::RecordField::cast(node).unwrap() 55 ast::RecordExprField::cast(node).unwrap()
39 } 56 }
40} 57}
41 58
42#[derive(Debug)] 59#[derive(Debug)]
43pub struct MissingFields { 60pub struct MissingFields {
44 pub file: HirFileId, 61 pub file: HirFileId,
45 pub field_list: AstPtr<ast::RecordFieldList>, 62 pub field_list: AstPtr<ast::RecordExprFieldList>,
46 pub missed_fields: Vec<Name>, 63 pub missed_fields: Vec<Name>,
47} 64}
48 65
@@ -63,12 +80,12 @@ impl Diagnostic for MissingFields {
63} 80}
64 81
65impl AstDiagnostic for MissingFields { 82impl AstDiagnostic for MissingFields {
66 type AST = ast::RecordFieldList; 83 type AST = ast::RecordExprFieldList;
67 84
68 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 85 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
69 let root = db.parse_or_expand(self.source().file_id).unwrap(); 86 let root = db.parse_or_expand(self.source().file_id).unwrap();
70 let node = self.source().value.to_node(&root); 87 let node = self.source().value.to_node(&root);
71 ast::RecordFieldList::cast(node).unwrap() 88 ast::RecordExprFieldList::cast(node).unwrap()
72 } 89 }
73} 90}
74 91
@@ -135,7 +152,7 @@ impl Diagnostic for MissingOkInTailExpr {
135impl AstDiagnostic for MissingOkInTailExpr { 152impl AstDiagnostic for MissingOkInTailExpr {
136 type AST = ast::Expr; 153 type AST = ast::Expr;
137 154
138 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 155 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
139 let root = db.parse_or_expand(self.file).unwrap(); 156 let root = db.parse_or_expand(self.file).unwrap();
140 let node = self.source().value.to_node(&root); 157 let node = self.source().value.to_node(&root);
141 ast::Expr::cast(node).unwrap() 158 ast::Expr::cast(node).unwrap()
@@ -163,7 +180,7 @@ impl Diagnostic for BreakOutsideOfLoop {
163impl AstDiagnostic for BreakOutsideOfLoop { 180impl AstDiagnostic for BreakOutsideOfLoop {
164 type AST = ast::Expr; 181 type AST = ast::Expr;
165 182
166 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 183 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
167 let root = db.parse_or_expand(self.file).unwrap(); 184 let root = db.parse_or_expand(self.file).unwrap();
168 let node = self.source().value.to_node(&root); 185 let node = self.source().value.to_node(&root);
169 ast::Expr::cast(node).unwrap() 186 ast::Expr::cast(node).unwrap()
@@ -191,9 +208,274 @@ impl Diagnostic for MissingUnsafe {
191impl AstDiagnostic for MissingUnsafe { 208impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr; 209 type AST = ast::Expr;
193 210
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 211 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap(); 212 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root); 213 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap() 214 ast::Expr::cast(node).unwrap()
198 } 215 }
199} 216}
217
218#[derive(Debug)]
219pub struct MismatchedArgCount {
220 pub file: HirFileId,
221 pub call_expr: AstPtr<ast::Expr>,
222 pub expected: usize,
223 pub found: usize,
224}
225
226impl Diagnostic for MismatchedArgCount {
227 fn message(&self) -> String {
228 let s = if self.expected == 1 { "" } else { "s" };
229 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
230 }
231 fn source(&self) -> InFile<SyntaxNodePtr> {
232 InFile { file_id: self.file, value: self.call_expr.clone().into() }
233 }
234 fn as_any(&self) -> &(dyn Any + Send + 'static) {
235 self
236 }
237 fn is_experimental(&self) -> bool {
238 true
239 }
240}
241
242impl AstDiagnostic for MismatchedArgCount {
243 type AST = ast::CallExpr;
244 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
245 let root = db.parse_or_expand(self.source().file_id).unwrap();
246 let node = self.source().value.to_node(&root);
247 ast::CallExpr::cast(node).unwrap()
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
254 use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder};
255 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
256 use ra_syntax::{TextRange, TextSize};
257 use rustc_hash::FxHashMap;
258
259 use crate::{diagnostics::validate_body, test_db::TestDB};
260
261 impl TestDB {
262 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
263 let crate_graph = self.crate_graph();
264 for krate in crate_graph.iter() {
265 let crate_def_map = self.crate_def_map(krate);
266
267 let mut fns = Vec::new();
268 for (module_id, _) in crate_def_map.modules.iter() {
269 for decl in crate_def_map[module_id].scope.declarations() {
270 if let ModuleDefId::FunctionId(f) = decl {
271 fns.push(f)
272 }
273 }
274
275 for impl_id in crate_def_map[module_id].scope.impls() {
276 let impl_data = self.impl_data(impl_id);
277 for item in impl_data.items.iter() {
278 if let AssocItemId::FunctionId(f) = item {
279 fns.push(*f)
280 }
281 }
282 }
283 }
284
285 for f in fns {
286 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
287 validate_body(self, f.into(), &mut sink);
288 }
289 }
290 }
291 }
292
293 pub(crate) fn check_diagnostics(ra_fixture: &str) {
294 let db = TestDB::with_files(ra_fixture);
295 let annotations = db.extract_annotations();
296
297 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
298 db.diagnostics(|d| {
299 // FXIME: macros...
300 let file_id = d.source().file_id.original_file(&db);
301 let range = d.syntax_node(&db).text_range();
302 let message = d.message().to_owned();
303 actual.entry(file_id).or_default().push((range, message));
304 });
305
306 for (file_id, diags) in actual.iter_mut() {
307 diags.sort_by_key(|it| it.0.start());
308 let text = db.file_text(*file_id);
309 // For multiline spans, place them on line start
310 for (range, content) in diags {
311 if text[*range].contains('\n') {
312 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
313 *content = format!("... {}", content);
314 }
315 }
316 }
317
318 assert_eq!(annotations, actual);
319 }
320
321 #[test]
322 fn no_such_field_diagnostics() {
323 check_diagnostics(
324 r#"
325struct S { foo: i32, bar: () }
326impl S {
327 fn new() -> S {
328 S {
329 //^... Missing structure fields:
330 //| - bar
331 foo: 92,
332 baz: 62,
333 //^^^^^^^ no such field
334 }
335 }
336}
337"#,
338 );
339 }
340 #[test]
341 fn no_such_field_with_feature_flag_diagnostics() {
342 check_diagnostics(
343 r#"
344//- /lib.rs crate:foo cfg:feature=foo
345struct MyStruct {
346 my_val: usize,
347 #[cfg(feature = "foo")]
348 bar: bool,
349}
350
351impl MyStruct {
352 #[cfg(feature = "foo")]
353 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
354 Self { my_val, bar }
355 }
356 #[cfg(not(feature = "foo"))]
357 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
358 Self { my_val }
359 }
360}
361"#,
362 );
363 }
364
365 #[test]
366 fn no_such_field_enum_with_feature_flag_diagnostics() {
367 check_diagnostics(
368 r#"
369//- /lib.rs crate:foo cfg:feature=foo
370enum Foo {
371 #[cfg(not(feature = "foo"))]
372 Buz,
373 #[cfg(feature = "foo")]
374 Bar,
375 Baz
376}
377
378fn test_fn(f: Foo) {
379 match f {
380 Foo::Bar => {},
381 Foo::Baz => {},
382 }
383}
384"#,
385 );
386 }
387
388 #[test]
389 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
390 check_diagnostics(
391 r#"
392//- /lib.rs crate:foo cfg:feature=foo
393struct S {
394 #[cfg(feature = "foo")]
395 foo: u32,
396 #[cfg(not(feature = "foo"))]
397 bar: u32,
398}
399
400impl S {
401 #[cfg(feature = "foo")]
402 fn new(foo: u32) -> Self {
403 Self { foo }
404 }
405 #[cfg(not(feature = "foo"))]
406 fn new(bar: u32) -> Self {
407 Self { bar }
408 }
409 fn new2(bar: u32) -> Self {
410 #[cfg(feature = "foo")]
411 { Self { foo: bar } }
412 #[cfg(not(feature = "foo"))]
413 { Self { bar } }
414 }
415 fn new2(val: u32) -> Self {
416 Self {
417 #[cfg(feature = "foo")]
418 foo: val,
419 #[cfg(not(feature = "foo"))]
420 bar: val,
421 }
422 }
423}
424"#,
425 );
426 }
427
428 #[test]
429 fn no_such_field_with_type_macro() {
430 check_diagnostics(
431 r#"
432macro_rules! Type { () => { u32 }; }
433struct Foo { bar: Type![] }
434
435impl Foo {
436 fn new() -> Self {
437 Foo { bar: 0 }
438 }
439}
440"#,
441 );
442 }
443
444 #[test]
445 fn missing_record_pat_field_diagnostic() {
446 check_diagnostics(
447 r#"
448struct S { foo: i32, bar: () }
449fn baz(s: S) {
450 let S { foo: _ } = s;
451 //^^^^^^^^^^ Missing structure fields:
452 // | - bar
453}
454"#,
455 );
456 }
457
458 #[test]
459 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
460 check_diagnostics(
461 r"
462struct S { foo: i32, bar: () }
463fn baz(s: S) -> i32 {
464 match s {
465 S { foo, .. } => foo,
466 }
467}
468",
469 )
470 }
471
472 #[test]
473 fn break_outside_of_loop() {
474 check_diagnostics(
475 r#"
476fn foo() { break; }
477 //^^^^^ break outside of loop
478"#,
479 );
480 }
481}
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 7db928dde..f0e0f2988 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -2,17 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId}; 5use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId};
6use hir_expand::diagnostics::DiagnosticSink; 6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::{ast, AstPtr}; 7use ra_syntax::{ast, AstPtr};
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, 12 diagnostics::{
13 match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields,
15 },
13 utils::variant_data, 16 utils::variant_data,
14 ApplicationTy, InferenceResult, Ty, TypeCtor, 17 ApplicationTy, InferenceResult, Ty, TypeCtor,
15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
16}; 18};
17 19
18pub use hir_def::{ 20pub use hir_def::{
@@ -24,26 +26,27 @@ pub use hir_def::{
24 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, 26 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
25 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, 27 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
26 }, 28 },
27 LocalFieldId, VariantId, 29 src::HasSource,
30 LocalFieldId, Lookup, VariantId,
28}; 31};
29 32
30pub struct ExprValidator<'a, 'b: 'a> { 33pub(super) struct ExprValidator<'a, 'b: 'a> {
31 func: FunctionId, 34 owner: DefWithBodyId,
32 infer: Arc<InferenceResult>, 35 infer: Arc<InferenceResult>,
33 sink: &'a mut DiagnosticSink<'b>, 36 sink: &'a mut DiagnosticSink<'b>,
34} 37}
35 38
36impl<'a, 'b> ExprValidator<'a, 'b> { 39impl<'a, 'b> ExprValidator<'a, 'b> {
37 pub fn new( 40 pub(super) fn new(
38 func: FunctionId, 41 owner: DefWithBodyId,
39 infer: Arc<InferenceResult>, 42 infer: Arc<InferenceResult>,
40 sink: &'a mut DiagnosticSink<'b>, 43 sink: &'a mut DiagnosticSink<'b>,
41 ) -> ExprValidator<'a, 'b> { 44 ) -> ExprValidator<'a, 'b> {
42 ExprValidator { func, infer, sink } 45 ExprValidator { owner, infer, sink }
43 } 46 }
44 47
45 pub fn validate_body(&mut self, db: &dyn HirDatabase) { 48 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
46 let body = db.body(self.func.into()); 49 let body = db.body(self.owner.into());
47 50
48 for (id, expr) in body.exprs.iter() { 51 for (id, expr) in body.exprs.iter() {
49 if let Some((variant_def, missed_fields, true)) = 52 if let Some((variant_def, missed_fields, true)) =
@@ -56,8 +59,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
56 missed_fields, 59 missed_fields,
57 ); 60 );
58 } 61 }
59 if let Expr::Match { expr, arms } = expr { 62
60 self.validate_match(id, *expr, arms, db, self.infer.clone()); 63 match expr {
64 Expr::Match { expr, arms } => {
65 self.validate_match(id, *expr, arms, db, self.infer.clone());
66 }
67 Expr::Call { .. } | Expr::MethodCall { .. } => {
68 self.validate_call(db, id, expr);
69 }
70 _ => {}
61 } 71 }
62 } 72 }
63 for (id, pat) in body.pats.iter() { 73 for (id, pat) in body.pats.iter() {
@@ -86,12 +96,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
86 missed_fields: Vec<LocalFieldId>, 96 missed_fields: Vec<LocalFieldId>,
87 ) { 97 ) {
88 // XXX: only look at source_map if we do have missing fields 98 // XXX: only look at source_map if we do have missing fields
89 let (_, source_map) = db.body_with_source_map(self.func.into()); 99 let (_, source_map) = db.body_with_source_map(self.owner.into());
90 100
91 if let Ok(source_ptr) = source_map.expr_syntax(id) { 101 if let Ok(source_ptr) = source_map.expr_syntax(id) {
92 let root = source_ptr.file_syntax(db.upcast()); 102 let root = source_ptr.file_syntax(db.upcast());
93 if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) { 103 if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) {
94 if let Some(field_list) = record_lit.record_field_list() { 104 if let Some(field_list) = record_lit.record_expr_field_list() {
95 let variant_data = variant_data(db.upcast(), variant_def); 105 let variant_data = variant_data(db.upcast(), variant_def);
96 let missed_fields = missed_fields 106 let missed_fields = missed_fields
97 .into_iter() 107 .into_iter()
@@ -115,7 +125,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
115 missed_fields: Vec<LocalFieldId>, 125 missed_fields: Vec<LocalFieldId>,
116 ) { 126 ) {
117 // XXX: only look at source_map if we do have missing fields 127 // XXX: only look at source_map if we do have missing fields
118 let (_, source_map) = db.body_with_source_map(self.func.into()); 128 let (_, source_map) = db.body_with_source_map(self.owner.into());
119 129
120 if let Ok(source_ptr) = source_map.pat_syntax(id) { 130 if let Ok(source_ptr) = source_map.pat_syntax(id) {
121 if let Some(expr) = source_ptr.value.as_ref().left() { 131 if let Some(expr) = source_ptr.value.as_ref().left() {
@@ -138,6 +148,65 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
138 } 148 }
139 } 149 }
140 150
151 fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> {
152 // Check that the number of arguments matches the number of parameters.
153
154 // FIXME: Due to shortcomings in the current type system implementation, only emit this
155 // diagnostic if there are no type mismatches in the containing function.
156 if self.infer.type_mismatches.iter().next().is_some() {
157 return Some(());
158 }
159
160 let is_method_call = matches!(expr, Expr::MethodCall { .. });
161 let (sig, args) = match expr {
162 Expr::Call { callee, args } => {
163 let callee = &self.infer.type_of_expr[*callee];
164 let sig = callee.callable_sig(db)?;
165 (sig, args.clone())
166 }
167 Expr::MethodCall { receiver, args, .. } => {
168 let mut args = args.clone();
169 args.insert(0, *receiver);
170
171 // FIXME: note that we erase information about substs here. This
172 // is not right, but, luckily, doesn't matter as we care only
173 // about the number of params
174 let callee = self.infer.method_resolution(call_id)?;
175 let sig = db.callable_item_signature(callee.into()).value;
176
177 (sig, args)
178 }
179 _ => return None,
180 };
181
182 if sig.is_varargs {
183 return None;
184 }
185
186 let params = sig.params();
187
188 let mut param_count = params.len();
189 let mut arg_count = args.len();
190
191 if arg_count != param_count {
192 let (_, source_map) = db.body_with_source_map(self.owner.into());
193 if let Ok(source_ptr) = source_map.expr_syntax(call_id) {
194 if is_method_call {
195 param_count -= 1;
196 arg_count -= 1;
197 }
198 self.sink.push(MismatchedArgCount {
199 file: source_ptr.file_id,
200 call_expr: source_ptr.value,
201 expected: param_count,
202 found: arg_count,
203 });
204 }
205 }
206
207 None
208 }
209
141 fn validate_match( 210 fn validate_match(
142 &mut self, 211 &mut self,
143 id: ExprId, 212 id: ExprId,
@@ -147,7 +216,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
147 infer: Arc<InferenceResult>, 216 infer: Arc<InferenceResult>,
148 ) { 217 ) {
149 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = 218 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
150 db.body_with_source_map(self.func.into()); 219 db.body_with_source_map(self.owner.into());
151 220
152 let match_expr_ty = match infer.type_of_expr.get(match_expr) { 221 let match_expr_ty = match infer.type_of_expr.get(match_expr) {
153 Some(ty) => ty, 222 Some(ty) => ty,
@@ -228,7 +297,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
228 297
229 let core_result_path = path![core::result::Result]; 298 let core_result_path = path![core::result::Result];
230 299
231 let resolver = self.func.resolver(db.upcast()); 300 let resolver = self.owner.resolver(db.upcast());
232 let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { 301 let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) {
233 Some(it) => it, 302 Some(it) => it,
234 _ => return, 303 _ => return,
@@ -243,7 +312,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
243 }; 312 };
244 313
245 if params.len() == 2 && params[0] == mismatch.actual { 314 if params.len() == 2 && params[0] == mismatch.actual {
246 let (_, source_map) = db.body_with_source_map(self.func.into()); 315 let (_, source_map) = db.body_with_source_map(self.owner.into());
247 316
248 if let Ok(source_ptr) = source_map.expr_syntax(id) { 317 if let Ok(source_ptr) = source_map.expr_syntax(id) {
249 self.sink 318 self.sink
@@ -312,3 +381,185 @@ pub fn record_pattern_missing_fields(
312 } 381 }
313 Some((variant_def, missed_fields, exhaustive)) 382 Some((variant_def, missed_fields, exhaustive))
314} 383}
384
385#[cfg(test)]
386mod tests {
387 use crate::diagnostics::tests::check_diagnostics;
388
389 #[test]
390 fn simple_free_fn_zero() {
391 check_diagnostics(
392 r#"
393fn zero() {}
394fn f() { zero(1); }
395 //^^^^^^^ Expected 0 arguments, found 1
396"#,
397 );
398
399 check_diagnostics(
400 r#"
401fn zero() {}
402fn f() { zero(); }
403"#,
404 );
405 }
406
407 #[test]
408 fn simple_free_fn_one() {
409 check_diagnostics(
410 r#"
411fn one(arg: u8) {}
412fn f() { one(); }
413 //^^^^^ Expected 1 argument, found 0
414"#,
415 );
416
417 check_diagnostics(
418 r#"
419fn one(arg: u8) {}
420fn f() { one(1); }
421"#,
422 );
423 }
424
425 #[test]
426 fn method_as_fn() {
427 check_diagnostics(
428 r#"
429struct S;
430impl S { fn method(&self) {} }
431
432fn f() {
433 S::method();
434} //^^^^^^^^^^^ Expected 1 argument, found 0
435"#,
436 );
437
438 check_diagnostics(
439 r#"
440struct S;
441impl S { fn method(&self) {} }
442
443fn f() {
444 S::method(&S);
445 S.method();
446}
447"#,
448 );
449 }
450
451 #[test]
452 fn method_with_arg() {
453 check_diagnostics(
454 r#"
455struct S;
456impl S { fn method(&self, arg: u8) {} }
457
458 fn f() {
459 S.method();
460 } //^^^^^^^^^^ Expected 1 argument, found 0
461 "#,
462 );
463
464 check_diagnostics(
465 r#"
466struct S;
467impl S { fn method(&self, arg: u8) {} }
468
469fn f() {
470 S::method(&S, 0);
471 S.method(1);
472}
473"#,
474 );
475 }
476
477 #[test]
478 fn tuple_struct() {
479 check_diagnostics(
480 r#"
481struct Tup(u8, u16);
482fn f() {
483 Tup(0);
484} //^^^^^^ Expected 2 arguments, found 1
485"#,
486 )
487 }
488
489 #[test]
490 fn enum_variant() {
491 check_diagnostics(
492 r#"
493enum En { Variant(u8, u16), }
494fn f() {
495 En::Variant(0);
496} //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
497"#,
498 )
499 }
500
501 #[test]
502 fn enum_variant_type_macro() {
503 check_diagnostics(
504 r#"
505macro_rules! Type {
506 () => { u32 };
507}
508enum Foo {
509 Bar(Type![])
510}
511impl Foo {
512 fn new() {
513 Foo::Bar(0);
514 Foo::Bar(0, 1);
515 //^^^^^^^^^^^^^^ Expected 1 argument, found 2
516 Foo::Bar();
517 //^^^^^^^^^^ Expected 1 argument, found 0
518 }
519}
520 "#,
521 );
522 }
523
524 #[test]
525 fn varargs() {
526 check_diagnostics(
527 r#"
528extern "C" {
529 fn fixed(fixed: u8);
530 fn varargs(fixed: u8, ...);
531 fn varargs2(...);
532}
533
534fn f() {
535 unsafe {
536 fixed(0);
537 fixed(0, 1);
538 //^^^^^^^^^^^ Expected 1 argument, found 2
539 varargs(0);
540 varargs(0, 1);
541 varargs2();
542 varargs2(0);
543 varargs2(0, 1);
544 }
545}
546 "#,
547 )
548 }
549
550 #[test]
551 fn arg_count_lambda() {
552 check_diagnostics(
553 r#"
554fn main() {
555 let f = |()| ();
556 f();
557 //^^^ Expected 1 argument, found 0
558 f(());
559 f((), ());
560 //^^^^^^^^^ Expected 1 argument, found 2
561}
562"#,
563 )
564 }
565}
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 5495ce284..507edcb7d 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -41,9 +41,9 @@
41//! ```ignore 41//! ```ignore
42//! // x: (Option<bool>, Result<()>) 42//! // x: (Option<bool>, Result<()>)
43//! match x { 43//! match x {
44//! (Some(true), _) => {} 44//! (Some(true), _) => (),
45//! (None, Err(())) => {} 45//! (None, Err(())) => (),
46//! (None, Err(_)) => {} 46//! (None, Err(_)) => (),
47//! } 47//! }
48//! ``` 48//! ```
49//! 49//!
@@ -218,15 +218,16 @@
218//! ``` 218//! ```
219use std::sync::Arc; 219use std::sync::Arc;
220 220
221use smallvec::{smallvec, SmallVec}; 221use hir_def::{
222 222 adt::VariantData,
223use crate::{ 223 body::Body,
224 db::HirDatabase, 224 expr::{Expr, Literal, Pat, PatId},
225 expr::{Body, Expr, Literal, Pat, PatId}, 225 AdtId, EnumVariantId, VariantId,
226 ApplicationTy, InferenceResult, Ty, TypeCtor,
227}; 226};
228use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
229use ra_arena::Idx; 227use ra_arena::Idx;
228use smallvec::{smallvec, SmallVec};
229
230use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor};
230 231
231#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
232/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
@@ -271,7 +272,7 @@ impl From<&PatId> for PatIdOrWild {
271} 272}
272 273
273#[derive(Debug, Clone, Copy, PartialEq)] 274#[derive(Debug, Clone, Copy, PartialEq)]
274pub enum MatchCheckErr { 275pub(super) enum MatchCheckErr {
275 NotImplemented, 276 NotImplemented,
276 MalformedMatchArm, 277 MalformedMatchArm,
277 /// Used when type inference cannot resolve the type of 278 /// Used when type inference cannot resolve the type of
@@ -286,21 +287,21 @@ pub enum MatchCheckErr {
286/// 287///
287/// The `std::result::Result` type is used here rather than a custom enum 288/// The `std::result::Result` type is used here rather than a custom enum
288/// to allow the use of `?`. 289/// to allow the use of `?`.
289pub type MatchCheckResult<T> = Result<T, MatchCheckErr>; 290pub(super) type MatchCheckResult<T> = Result<T, MatchCheckErr>;
290 291
291#[derive(Debug)] 292#[derive(Debug)]
292/// A row in a Matrix. 293/// A row in a Matrix.
293/// 294///
294/// This type is modeled from the struct of the same name in `rustc`. 295/// This type is modeled from the struct of the same name in `rustc`.
295pub(crate) struct PatStack(PatStackInner); 296pub(super) struct PatStack(PatStackInner);
296type PatStackInner = SmallVec<[PatIdOrWild; 2]>; 297type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
297 298
298impl PatStack { 299impl PatStack {
299 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack { 300 pub(super) fn from_pattern(pat_id: PatId) -> PatStack {
300 Self(smallvec!(pat_id.into())) 301 Self(smallvec!(pat_id.into()))
301 } 302 }
302 303
303 pub(crate) fn from_wild() -> PatStack { 304 pub(super) fn from_wild() -> PatStack {
304 Self(smallvec!(PatIdOrWild::Wild)) 305 Self(smallvec!(PatIdOrWild::Wild))
305 } 306 }
306 307
@@ -509,14 +510,14 @@ impl PatStack {
509/// A collection of PatStack. 510/// A collection of PatStack.
510/// 511///
511/// This type is modeled from the struct of the same name in `rustc`. 512/// This type is modeled from the struct of the same name in `rustc`.
512pub(crate) struct Matrix(Vec<PatStack>); 513pub(super) struct Matrix(Vec<PatStack>);
513 514
514impl Matrix { 515impl Matrix {
515 pub(crate) fn empty() -> Self { 516 pub(super) fn empty() -> Self {
516 Self(vec![]) 517 Self(vec![])
517 } 518 }
518 519
519 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { 520 pub(super) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) {
520 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { 521 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
521 // Or patterns are expanded here 522 // Or patterns are expanded here
522 for pat_id in pat_ids { 523 for pat_id in pat_ids {
@@ -578,16 +579,16 @@ impl Matrix {
578/// not matched by an prior match arms. 579/// not matched by an prior match arms.
579/// 580///
580/// We may eventually need an `Unknown` variant here. 581/// We may eventually need an `Unknown` variant here.
581pub enum Usefulness { 582pub(super) enum Usefulness {
582 Useful, 583 Useful,
583 NotUseful, 584 NotUseful,
584} 585}
585 586
586pub struct MatchCheckCtx<'a> { 587pub(super) struct MatchCheckCtx<'a> {
587 pub match_expr: Idx<Expr>, 588 pub(super) match_expr: Idx<Expr>,
588 pub body: Arc<Body>, 589 pub(super) body: Arc<Body>,
589 pub infer: Arc<InferenceResult>, 590 pub(super) infer: Arc<InferenceResult>,
590 pub db: &'a dyn HirDatabase, 591 pub(super) db: &'a dyn HirDatabase,
591} 592}
592 593
593/// Given a set of patterns `matrix`, and pattern to consider `v`, determines 594/// Given a set of patterns `matrix`, and pattern to consider `v`, determines
@@ -598,7 +599,7 @@ pub struct MatchCheckCtx<'a> {
598/// expected that you have already type checked the match arms. All patterns in 599/// expected that you have already type checked the match arms. All patterns in
599/// matrix should be the same type as v, as well as they should all be the same 600/// matrix should be the same type as v, as well as they should all be the same
600/// type as the match expression. 601/// type as the match expression.
601pub(crate) fn is_useful( 602pub(super) fn is_useful(
602 cx: &MatchCheckCtx, 603 cx: &MatchCheckCtx,
603 matrix: &Matrix, 604 matrix: &Matrix,
604 v: &PatStack, 605 v: &PatStack,
@@ -836,685 +837,251 @@ fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: Enum
836 837
837#[cfg(test)] 838#[cfg(test)]
838mod tests { 839mod tests {
839 pub(super) use insta::assert_snapshot; 840 use crate::diagnostics::tests::check_diagnostics;
840 pub(super) use ra_db::fixture::WithFixture;
841
842 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
843
844 pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String {
845 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0
846 }
847
848 pub(super) fn check_diagnostic(ra_fixture: &str) {
849 let diagnostic_count =
850 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
851
852 assert_eq!(1, diagnostic_count, "no diagnostic reported");
853 }
854
855 pub(super) fn check_no_diagnostic(ra_fixture: &str) {
856 let (s, diagnostic_count) =
857 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>();
858
859 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one: {}", s);
860 }
861
862 #[test]
863 fn empty_tuple_no_arms_diagnostic_message() {
864 assert_snapshot!(
865 check_diagnostic_message(r"
866 fn test_fn() {
867 match () {
868 }
869 }
870 "),
871 @"\"()\": Missing match arm\n"
872 );
873 }
874
875 #[test]
876 fn empty_tuple_no_arms() {
877 check_diagnostic(
878 r"
879 fn test_fn() {
880 match () {
881 }
882 }
883 ",
884 );
885 }
886
887 #[test]
888 fn empty_tuple_wild() {
889 check_no_diagnostic(
890 r"
891 fn test_fn() {
892 match () {
893 _ => {}
894 }
895 }
896 ",
897 );
898 }
899
900 #[test]
901 fn empty_tuple_no_diagnostic() {
902 check_no_diagnostic(
903 r"
904 fn test_fn() {
905 match () {
906 () => {}
907 }
908 }
909 ",
910 );
911 }
912
913 #[test]
914 fn tuple_of_empty_tuple_no_arms() {
915 check_diagnostic(
916 r"
917 fn test_fn() {
918 match (()) {
919 }
920 }
921 ",
922 );
923 }
924
925 #[test]
926 fn tuple_of_empty_tuple_no_diagnostic() {
927 check_no_diagnostic(
928 r"
929 fn test_fn() {
930 match (()) {
931 (()) => {}
932 }
933 }
934 ",
935 );
936 }
937 841
938 #[test] 842 #[test]
939 fn tuple_of_two_empty_tuple_no_arms() { 843 fn empty_tuple() {
940 check_diagnostic( 844 check_diagnostics(
941 r" 845 r#"
942 fn test_fn() { 846fn main() {
943 match ((), ()) { 847 match () { }
944 } 848 //^^ Missing match arm
945 } 849 match (()) { }
946 ", 850 //^^^^ Missing match arm
947 );
948 }
949 851
950 #[test] 852 match () { _ => (), }
951 fn tuple_of_two_empty_tuple_no_diagnostic() { 853 match () { () => (), }
952 check_no_diagnostic( 854 match (()) { (()) => (), }
953 r" 855}
954 fn test_fn() { 856"#,
955 match ((), ()) {
956 ((), ()) => {}
957 }
958 }
959 ",
960 );
961 }
962
963 #[test]
964 fn bool_no_arms() {
965 check_diagnostic(
966 r"
967 fn test_fn() {
968 match false {
969 }
970 }
971 ",
972 );
973 }
974
975 #[test]
976 fn bool_missing_arm() {
977 check_diagnostic(
978 r"
979 fn test_fn() {
980 match false {
981 true => {}
982 }
983 }
984 ",
985 );
986 }
987
988 #[test]
989 fn bool_no_diagnostic() {
990 check_no_diagnostic(
991 r"
992 fn test_fn() {
993 match false {
994 true => {}
995 false => {}
996 }
997 }
998 ",
999 );
1000 }
1001
1002 #[test]
1003 fn tuple_of_bools_no_arms() {
1004 check_diagnostic(
1005 r"
1006 fn test_fn() {
1007 match (false, true) {
1008 }
1009 }
1010 ",
1011 );
1012 }
1013
1014 #[test]
1015 fn tuple_of_bools_missing_arms() {
1016 check_diagnostic(
1017 r"
1018 fn test_fn() {
1019 match (false, true) {
1020 (true, true) => {},
1021 }
1022 }
1023 ",
1024 );
1025 }
1026
1027 #[test]
1028 fn tuple_of_bools_missing_arm() {
1029 check_diagnostic(
1030 r"
1031 fn test_fn() {
1032 match (false, true) {
1033 (false, true) => {},
1034 (false, false) => {},
1035 (true, false) => {},
1036 }
1037 }
1038 ",
1039 );
1040 }
1041
1042 #[test]
1043 fn tuple_of_bools_with_wilds() {
1044 check_no_diagnostic(
1045 r"
1046 fn test_fn() {
1047 match (false, true) {
1048 (false, _) => {},
1049 (true, false) => {},
1050 (_, true) => {},
1051 }
1052 }
1053 ",
1054 ); 857 );
1055 } 858 }
1056 859
1057 #[test] 860 #[test]
1058 fn tuple_of_bools_no_diagnostic() { 861 fn tuple_of_two_empty_tuple() {
1059 check_no_diagnostic( 862 check_diagnostics(
1060 r" 863 r#"
1061 fn test_fn() { 864fn main() {
1062 match (false, true) { 865 match ((), ()) { }
1063 (true, true) => {}, 866 //^^^^^^^^ Missing match arm
1064 (true, false) => {},
1065 (false, true) => {},
1066 (false, false) => {},
1067 }
1068 }
1069 ",
1070 );
1071 }
1072 867
1073 #[test] 868 match ((), ()) { ((), ()) => (), }
1074 fn tuple_of_bools_binding_missing_arms() { 869}
1075 check_diagnostic( 870"#,
1076 r" 871 );
1077 fn test_fn() { 872 }
1078 match (false, true) { 873
1079 (true, _x) => {}, 874 #[test]
1080 } 875 fn boolean() {
1081 } 876 check_diagnostics(
1082 ", 877 r#"
1083 ); 878fn test_main() {
1084 } 879 match false { }
1085 880 //^^^^^ Missing match arm
1086 #[test] 881 match false { true => (), }
1087 fn tuple_of_bools_binding_no_diagnostic() { 882 //^^^^^ Missing match arm
1088 check_no_diagnostic( 883 match (false, true) {}
1089 r" 884 //^^^^^^^^^^^^^ Missing match arm
1090 fn test_fn() { 885 match (false, true) { (true, true) => (), }
1091 match (false, true) { 886 //^^^^^^^^^^^^^ Missing match arm
1092 (true, _x) => {}, 887 match (false, true) {
1093 (false, true) => {}, 888 //^^^^^^^^^^^^^ Missing match arm
1094 (false, false) => {}, 889 (false, true) => (),
1095 } 890 (false, false) => (),
1096 } 891 (true, false) => (),
1097 ", 892 }
893 match (false, true) { (true, _x) => (), }
894 //^^^^^^^^^^^^^ Missing match arm
895
896 match false { true => (), false => (), }
897 match (false, true) {
898 (false, _) => (),
899 (true, false) => (),
900 (_, true) => (),
901 }
902 match (false, true) {
903 (true, true) => (),
904 (true, false) => (),
905 (false, true) => (),
906 (false, false) => (),
907 }
908 match (false, true) {
909 (true, _x) => (),
910 (false, true) => (),
911 (false, false) => (),
912 }
913 match (false, true, false) {
914 (false, ..) => (),
915 (true, ..) => (),
916 }
917 match (false, true, false) {
918 (.., false) => (),
919 (.., true) => (),
920 }
921 match (false, true, false) { (..) => (), }
922}
923"#,
1098 ); 924 );
1099 } 925 }
1100 926
1101 #[test] 927 #[test]
1102 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { 928 fn tuple_of_tuple_and_bools() {
1103 check_no_diagnostic( 929 check_diagnostics(
1104 r" 930 r#"
1105 fn test_fn() { 931fn main() {
1106 match (false, true, false) { 932 match (false, ((), false)) {}
1107 (false, ..) => {}, 933 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1108 (true, ..) => {}, 934 match (false, ((), false)) { (true, ((), true)) => (), }
1109 } 935 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1110 } 936 match (false, ((), false)) { (true, _) => (), }
1111 ", 937 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1112 );
1113 }
1114 938
1115 #[test] 939 match (false, ((), false)) {
1116 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { 940 (true, ((), true)) => (),
1117 check_no_diagnostic( 941 (true, ((), false)) => (),
1118 r" 942 (false, ((), true)) => (),
1119 fn test_fn() { 943 (false, ((), false)) => (),
1120 match (false, true, false) {
1121 (.., false) => {},
1122 (.., true) => {},
1123 }
1124 }
1125 ",
1126 );
1127 } 944 }
1128 945 match (false, ((), false)) {
1129 #[test] 946 (true, ((), true)) => (),
1130 fn tuple_of_bools_with_ellipsis_no_diagnostic() { 947 (true, ((), false)) => (),
1131 check_no_diagnostic( 948 (false, _) => (),
1132 r"
1133 fn test_fn() {
1134 match (false, true, false) {
1135 (..) => {},
1136 }
1137 }
1138 ",
1139 );
1140 } 949 }
1141 950}
1142 #[test] 951"#,
1143 fn tuple_of_tuple_and_bools_no_arms() {
1144 check_diagnostic(
1145 r"
1146 fn test_fn() {
1147 match (false, ((), false)) {
1148 }
1149 }
1150 ",
1151 ); 952 );
1152 } 953 }
1153 954
1154 #[test] 955 #[test]
1155 fn tuple_of_tuple_and_bools_missing_arms() { 956 fn enums() {
1156 check_diagnostic( 957 check_diagnostics(
1157 r" 958 r#"
1158 fn test_fn() { 959enum Either { A, B, }
1159 match (false, ((), false)) {
1160 (true, ((), true)) => {},
1161 }
1162 }
1163 ",
1164 );
1165 }
1166 960
1167 #[test] 961fn main() {
1168 fn tuple_of_tuple_and_bools_no_diagnostic() { 962 match Either::A { }
1169 check_no_diagnostic( 963 //^^^^^^^^^ Missing match arm
1170 r" 964 match Either::B { Either::A => (), }
1171 fn test_fn() { 965 //^^^^^^^^^ Missing match arm
1172 match (false, ((), false)) {
1173 (true, ((), true)) => {},
1174 (true, ((), false)) => {},
1175 (false, ((), true)) => {},
1176 (false, ((), false)) => {},
1177 }
1178 }
1179 ",
1180 );
1181 }
1182 966
1183 #[test] 967 match &Either::B {
1184 fn tuple_of_tuple_and_bools_wildcard_missing_arms() { 968 //^^^^^^^^^^ Missing match arm
1185 check_diagnostic( 969 Either::A => (),
1186 r"
1187 fn test_fn() {
1188 match (false, ((), false)) {
1189 (true, _) => {},
1190 }
1191 }
1192 ",
1193 );
1194 } 970 }
1195 971
1196 #[test] 972 match Either::B {
1197 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { 973 Either::A => (), Either::B => (),
1198 check_no_diagnostic(
1199 r"
1200 fn test_fn() {
1201 match (false, ((), false)) {
1202 (true, ((), true)) => {},
1203 (true, ((), false)) => {},
1204 (false, _) => {},
1205 }
1206 }
1207 ",
1208 );
1209 } 974 }
1210 975 match &Either::B {
1211 #[test] 976 Either::A => (), Either::B => (),
1212 fn enum_no_arms() {
1213 check_diagnostic(
1214 r"
1215 enum Either {
1216 A,
1217 B,
1218 }
1219 fn test_fn() {
1220 match Either::A {
1221 }
1222 }
1223 ",
1224 );
1225 } 977 }
1226 978}
1227 #[test] 979"#,
1228 fn enum_missing_arms() {
1229 check_diagnostic(
1230 r"
1231 enum Either {
1232 A,
1233 B,
1234 }
1235 fn test_fn() {
1236 match Either::B {
1237 Either::A => {},
1238 }
1239 }
1240 ",
1241 ); 980 );
1242 } 981 }
1243 982
1244 #[test] 983 #[test]
1245 fn enum_no_diagnostic() { 984 fn enum_containing_bool() {
1246 check_no_diagnostic( 985 check_diagnostics(
1247 r" 986 r#"
1248 enum Either { 987enum Either { A(bool), B }
1249 A,
1250 B,
1251 }
1252 fn test_fn() {
1253 match Either::B {
1254 Either::A => {},
1255 Either::B => {},
1256 }
1257 }
1258 ",
1259 );
1260 }
1261 988
1262 #[test] 989fn main() {
1263 fn enum_ref_missing_arms() { 990 match Either::B { }
1264 check_diagnostic( 991 //^^^^^^^^^ Missing match arm
1265 r" 992 match Either::B {
1266 enum Either { 993 //^^^^^^^^^ Missing match arm
1267 A, 994 Either::A(true) => (), Either::B => ()
1268 B,
1269 }
1270 fn test_fn() {
1271 match &Either::B {
1272 Either::A => {},
1273 }
1274 }
1275 ",
1276 );
1277 } 995 }
1278 996
1279 #[test] 997 match Either::B {
1280 fn enum_ref_no_diagnostic() { 998 Either::A(true) => (),
1281 check_no_diagnostic( 999 Either::A(false) => (),
1282 r" 1000 Either::B => (),
1283 enum Either {
1284 A,
1285 B,
1286 }
1287 fn test_fn() {
1288 match &Either::B {
1289 Either::A => {},
1290 Either::B => {},
1291 }
1292 }
1293 ",
1294 );
1295 } 1001 }
1296 1002 match Either::B {
1297 #[test] 1003 Either::B => (),
1298 fn enum_containing_bool_no_arms() { 1004 _ => (),
1299 check_diagnostic(
1300 r"
1301 enum Either {
1302 A(bool),
1303 B,
1304 }
1305 fn test_fn() {
1306 match Either::B {
1307 }
1308 }
1309 ",
1310 );
1311 } 1005 }
1312 1006 match Either::B {
1313 #[test] 1007 Either::A(_) => (),
1314 fn enum_containing_bool_missing_arms() { 1008 Either::B => (),
1315 check_diagnostic(
1316 r"
1317 enum Either {
1318 A(bool),
1319 B,
1320 }
1321 fn test_fn() {
1322 match Either::B {
1323 Either::A(true) => (),
1324 Either::B => (),
1325 }
1326 }
1327 ",
1328 );
1329 } 1009 }
1330 1010
1331 #[test] 1011}
1332 fn enum_containing_bool_no_diagnostic() { 1012 "#,
1333 check_no_diagnostic(
1334 r"
1335 enum Either {
1336 A(bool),
1337 B,
1338 }
1339 fn test_fn() {
1340 match Either::B {
1341 Either::A(true) => (),
1342 Either::A(false) => (),
1343 Either::B => (),
1344 }
1345 }
1346 ",
1347 ); 1013 );
1348 } 1014 }
1349 1015
1350 #[test] 1016 #[test]
1351 fn enum_containing_bool_with_wild_no_diagnostic() { 1017 fn enum_different_sizes() {
1352 check_no_diagnostic( 1018 check_diagnostics(
1353 r" 1019 r#"
1354 enum Either { 1020enum Either { A(bool), B(bool, bool) }
1355 A(bool),
1356 B,
1357 }
1358 fn test_fn() {
1359 match Either::B {
1360 Either::B => (),
1361 _ => (),
1362 }
1363 }
1364 ",
1365 );
1366 }
1367 1021
1368 #[test] 1022fn main() {
1369 fn enum_containing_bool_with_wild_2_no_diagnostic() { 1023 match Either::A(false) {
1370 check_no_diagnostic( 1024 //^^^^^^^^^^^^^^^^ Missing match arm
1371 r" 1025 Either::A(_) => (),
1372 enum Either { 1026 Either::B(false, _) => (),
1373 A(bool),
1374 B,
1375 }
1376 fn test_fn() {
1377 match Either::B {
1378 Either::A(_) => (),
1379 Either::B => (),
1380 }
1381 }
1382 ",
1383 );
1384 } 1027 }
1385 1028
1386 #[test] 1029 match Either::A(false) {
1387 fn enum_different_sizes_missing_arms() { 1030 Either::A(_) => (),
1388 check_diagnostic( 1031 Either::B(true, _) => (),
1389 r" 1032 Either::B(false, _) => (),
1390 enum Either {
1391 A(bool),
1392 B(bool, bool),
1393 }
1394 fn test_fn() {
1395 match Either::A(false) {
1396 Either::A(_) => (),
1397 Either::B(false, _) => (),
1398 }
1399 }
1400 ",
1401 );
1402 } 1033 }
1403 1034 match Either::A(false) {
1404 #[test] 1035 Either::A(true) | Either::A(false) => (),
1405 fn enum_different_sizes_no_diagnostic() { 1036 Either::B(true, _) => (),
1406 check_no_diagnostic( 1037 Either::B(false, _) => (),
1407 r"
1408 enum Either {
1409 A(bool),
1410 B(bool, bool),
1411 }
1412 fn test_fn() {
1413 match Either::A(false) {
1414 Either::A(_) => (),
1415 Either::B(true, _) => (),
1416 Either::B(false, _) => (),
1417 }
1418 }
1419 ",
1420 );
1421 } 1038 }
1422 1039}
1423 #[test] 1040"#,
1424 fn or_no_diagnostic() {
1425 check_no_diagnostic(
1426 r"
1427 enum Either {
1428 A(bool),
1429 B(bool, bool),
1430 }
1431 fn test_fn() {
1432 match Either::A(false) {
1433 Either::A(true) | Either::A(false) => (),
1434 Either::B(true, _) => (),
1435 Either::B(false, _) => (),
1436 }
1437 }
1438 ",
1439 ); 1041 );
1440 } 1042 }
1441 1043
1442 #[test] 1044 #[test]
1443 fn tuple_of_enum_no_diagnostic() { 1045 fn tuple_of_enum_no_diagnostic() {
1444 check_no_diagnostic( 1046 check_diagnostics(
1445 r" 1047 r#"
1446 enum Either { 1048enum Either { A(bool), B(bool, bool) }
1447 A(bool), 1049enum Either2 { C, D }
1448 B(bool, bool), 1050
1449 } 1051fn main() {
1450 enum Either2 { 1052 match (Either::A(false), Either2::C) {
1451 C, 1053 (Either::A(true), _) | (Either::A(false), _) => (),
1452 D, 1054 (Either::B(true, _), Either2::C) => (),
1453 } 1055 (Either::B(false, _), Either2::C) => (),
1454 fn test_fn() { 1056 (Either::B(_, _), Either2::D) => (),
1455 match (Either::A(false), Either2::C) {
1456 (Either::A(true), _) | (Either::A(false), _) => (),
1457 (Either::B(true, _), Either2::C) => (),
1458 (Either::B(false, _), Either2::C) => (),
1459 (Either::B(_, _), Either2::D) => (),
1460 }
1461 }
1462 ",
1463 );
1464 }
1465
1466 #[test]
1467 fn mismatched_types() {
1468 // Match statements with arms that don't match the
1469 // expression pattern do not fire this diagnostic.
1470 check_no_diagnostic(
1471 r"
1472 enum Either {
1473 A,
1474 B,
1475 }
1476 enum Either2 {
1477 C,
1478 D,
1479 }
1480 fn test_fn() {
1481 match Either::A {
1482 Either2::C => (),
1483 Either2::D => (),
1484 }
1485 }
1486 ",
1487 );
1488 } 1057 }
1489 1058}
1490 #[test] 1059"#,
1491 fn mismatched_types_with_different_arity() {
1492 // Match statements with arms that don't match the
1493 // expression pattern do not fire this diagnostic.
1494 check_no_diagnostic(
1495 r"
1496 fn test_fn() {
1497 match (true, false) {
1498 (true, false, true) => (),
1499 (true) => (),
1500 }
1501 }
1502 ",
1503 ); 1060 );
1504 } 1061 }
1505 1062
1506 #[test] 1063 #[test]
1507 fn malformed_match_arm_tuple_missing_pattern() { 1064 fn mismatched_types() {
1508 // Match statements with arms that don't match the 1065 // Match statements with arms that don't match the
1509 // expression pattern do not fire this diagnostic. 1066 // expression pattern do not fire this diagnostic.
1510 check_no_diagnostic( 1067 check_diagnostics(
1511 r" 1068 r#"
1512 fn test_fn() { 1069enum Either { A, B }
1513 match (0) { 1070enum Either2 { C, D }
1514 () => (), 1071
1515 } 1072fn main() {
1516 } 1073 match Either::A {
1517 ", 1074 Either2::C => (),
1075 Either2::D => (),
1076 }
1077 match (true, false) {
1078 (true, false, true) => (),
1079 (true) => (),
1080 }
1081 match (0) { () => () }
1082 match Unresolved::Bar { Unresolved::Baz => () }
1083}
1084 "#,
1518 ); 1085 );
1519 } 1086 }
1520 1087
@@ -1522,636 +1089,333 @@ mod tests {
1522 fn malformed_match_arm_tuple_enum_missing_pattern() { 1089 fn malformed_match_arm_tuple_enum_missing_pattern() {
1523 // We are testing to be sure we don't panic here when the match 1090 // We are testing to be sure we don't panic here when the match
1524 // arm `Either::B` is missing its pattern. 1091 // arm `Either::B` is missing its pattern.
1525 check_no_diagnostic( 1092 check_diagnostics(
1526 r" 1093 r#"
1527 enum Either { 1094enum Either { A, B(u32) }
1528 A,
1529 B(u32),
1530 }
1531 fn test_fn() {
1532 match Either::A {
1533 Either::A => (),
1534 Either::B() => (),
1535 }
1536 }
1537 ",
1538 );
1539 }
1540 1095
1541 #[test] 1096fn main() {
1542 fn enum_not_in_scope() { 1097 match Either::A {
1543 // The enum is not in scope so we don't perform exhaustiveness 1098 Either::A => (),
1544 // checking, but we want to be sure we don't panic here (and 1099 Either::B() => (),
1545 // we don't create a diagnostic). 1100 }
1546 check_no_diagnostic( 1101}
1547 r" 1102"#,
1548 fn test_fn() {
1549 match Foo::Bar {
1550 Foo::Baz => (),
1551 }
1552 }
1553 ",
1554 ); 1103 );
1555 } 1104 }
1556 1105
1557 #[test] 1106 #[test]
1558 fn expr_diverges() { 1107 fn expr_diverges() {
1559 check_no_diagnostic( 1108 check_diagnostics(
1560 r" 1109 r#"
1561 enum Either { 1110enum Either { A, B }
1562 A,
1563 B,
1564 }
1565 fn test_fn() {
1566 match loop {} {
1567 Either::A => (),
1568 Either::B => (),
1569 }
1570 }
1571 ",
1572 );
1573 }
1574 1111
1575 #[test] 1112fn main() {
1576 fn expr_loop_with_break() { 1113 match loop {} {
1577 check_no_diagnostic( 1114 Either::A => (),
1578 r" 1115 Either::B => (),
1579 enum Either { 1116 }
1580 A, 1117 match loop {} {
1581 B, 1118 Either::A => (),
1582 } 1119 }
1583 fn test_fn() { 1120 match loop { break Foo::A } {
1584 match loop { break Foo::A } { 1121 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1585 Either::A => (), 1122 Either::A => (),
1586 Either::B => (), 1123 }
1587 } 1124 match loop { break Foo::A } {
1588 } 1125 Either::A => (),
1589 ", 1126 Either::B => (),
1127 }
1128}
1129"#,
1590 ); 1130 );
1591 } 1131 }
1592 1132
1593 #[test] 1133 #[test]
1594 fn expr_partially_diverges() { 1134 fn expr_partially_diverges() {
1595 check_no_diagnostic( 1135 check_diagnostics(
1596 r" 1136 r#"
1597 enum Either<T> { 1137enum Either<T> { A(T), B }
1598 A(T),
1599 B,
1600 }
1601 fn foo() -> Either<!> {
1602 Either::B
1603 }
1604 fn test_fn() -> u32 {
1605 match foo() {
1606 Either::A(val) => val,
1607 Either::B => 0,
1608 }
1609 }
1610 ",
1611 );
1612 }
1613 1138
1614 #[test] 1139fn foo() -> Either<!> { Either::B }
1615 fn enum_record_no_arms() { 1140fn main() -> u32 {
1616 check_diagnostic( 1141 match foo() {
1617 r" 1142 Either::A(val) => val,
1618 enum Either { 1143 Either::B => 0,
1619 A { foo: bool },
1620 B,
1621 }
1622 fn test_fn() {
1623 let a = Either::A { foo: true };
1624 match a {
1625 }
1626 }
1627 ",
1628 );
1629 } 1144 }
1630 1145}
1631 #[test] 1146"#,
1632 fn enum_record_missing_arms() {
1633 check_diagnostic(
1634 r"
1635 enum Either {
1636 A { foo: bool },
1637 B,
1638 }
1639 fn test_fn() {
1640 let a = Either::A { foo: true };
1641 match a {
1642 Either::A { foo: true } => (),
1643 }
1644 }
1645 ",
1646 ); 1147 );
1647 } 1148 }
1648 1149
1649 #[test] 1150 #[test]
1650 fn enum_record_no_diagnostic() { 1151 fn enum_record() {
1651 check_no_diagnostic( 1152 check_diagnostics(
1652 r" 1153 r#"
1653 enum Either { 1154enum Either { A { foo: bool }, B }
1654 A { foo: bool },
1655 B,
1656 }
1657 fn test_fn() {
1658 let a = Either::A { foo: true };
1659 match a {
1660 Either::A { foo: true } => (),
1661 Either::A { foo: false } => (),
1662 Either::B => (),
1663 }
1664 }
1665 ",
1666 );
1667 }
1668 1155
1669 #[test] 1156fn main() {
1670 fn enum_record_missing_field_no_diagnostic() { 1157 let a = Either::A { foo: true };
1671 // When `Either::A` is missing a struct member, we don't want 1158 match a { }
1672 // to fire the missing match arm diagnostic. This should fire 1159 //^ Missing match arm
1673 // some other diagnostic. 1160 match a { Either::A { foo: true } => () }
1674 check_no_diagnostic( 1161 //^ Missing match arm
1675 r" 1162 match a {
1676 enum Either { 1163 Either::A { } => (),
1677 A { foo: bool }, 1164 //^^^ Missing structure fields:
1678 B, 1165 // | - foo
1679 } 1166 Either::B => (),
1680 fn test_fn() {
1681 let a = Either::B;
1682 match a {
1683 Either::A { } => (),
1684 Either::B => (),
1685 }
1686 }
1687 ",
1688 );
1689 } 1167 }
1168 match a {
1169 //^ Missing match arm
1170 Either::A { } => (),
1171 } //^^^ Missing structure fields:
1172 // | - foo
1690 1173
1691 #[test] 1174 match a {
1692 fn enum_record_missing_field_missing_match_arm() { 1175 Either::A { foo: true } => (),
1693 // Even though `Either::A` is missing fields, we still want to fire 1176 Either::A { foo: false } => (),
1694 // the missing arm diagnostic here, since we know `Either::B` is missing. 1177 Either::B => (),
1695 check_diagnostic(
1696 r"
1697 enum Either {
1698 A { foo: bool },
1699 B,
1700 }
1701 fn test_fn() {
1702 let a = Either::B;
1703 match a {
1704 Either::A { } => (),
1705 }
1706 }
1707 ",
1708 );
1709 } 1178 }
1710 1179 match a {
1711 #[test] 1180 Either::A { foo: _ } => (),
1712 fn enum_record_no_diagnostic_wild() { 1181 Either::B => (),
1713 check_no_diagnostic(
1714 r"
1715 enum Either {
1716 A { foo: bool },
1717 B,
1718 }
1719 fn test_fn() {
1720 let a = Either::A { foo: true };
1721 match a {
1722 Either::A { foo: _ } => (),
1723 Either::B => (),
1724 }
1725 }
1726 ",
1727 );
1728 } 1182 }
1729 1183}
1730 #[test] 1184"#,
1731 fn enum_record_fields_out_of_order_missing_arm() {
1732 check_diagnostic(
1733 r"
1734 enum Either {
1735 A { foo: bool, bar: () },
1736 B,
1737 }
1738 fn test_fn() {
1739 let a = Either::A { foo: true };
1740 match a {
1741 Either::A { bar: (), foo: false } => (),
1742 Either::A { foo: true, bar: () } => (),
1743 }
1744 }
1745 ",
1746 ); 1185 );
1747 } 1186 }
1748 1187
1749 #[test] 1188 #[test]
1750 fn enum_record_fields_out_of_order_no_diagnostic() { 1189 fn enum_record_fields_out_of_order() {
1751 check_no_diagnostic( 1190 check_diagnostics(
1752 r" 1191 r#"
1753 enum Either { 1192enum Either {
1754 A { foo: bool, bar: () }, 1193 A { foo: bool, bar: () },
1755 B, 1194 B,
1756 } 1195}
1757 fn test_fn() {
1758 let a = Either::A { foo: true };
1759 match a {
1760 Either::A { bar: (), foo: false } => (),
1761 Either::A { foo: true, bar: () } => (),
1762 Either::B => (),
1763 }
1764 }
1765 ",
1766 );
1767 }
1768 1196
1769 #[test] 1197fn main() {
1770 fn enum_record_ellipsis_missing_arm() { 1198 let a = Either::A { foo: true, bar: () };
1771 check_diagnostic( 1199 match a {
1772 r" 1200 //^ Missing match arm
1773 enum Either { 1201 Either::A { bar: (), foo: false } => (),
1774 A { foo: bool, bar: bool }, 1202 Either::A { foo: true, bar: () } => (),
1775 B,
1776 }
1777 fn test_fn() {
1778 match Either::B {
1779 Either::A { foo: true, .. } => (),
1780 Either::B => (),
1781 }
1782 }
1783 ",
1784 );
1785 } 1203 }
1786 1204
1787 #[test] 1205 match a {
1788 fn enum_record_ellipsis_no_diagnostic() { 1206 Either::A { bar: (), foo: false } => (),
1789 check_no_diagnostic( 1207 Either::A { foo: true, bar: () } => (),
1790 r" 1208 Either::B => (),
1791 enum Either {
1792 A { foo: bool, bar: bool },
1793 B,
1794 }
1795 fn test_fn() {
1796 let a = Either::A { foo: true };
1797 match a {
1798 Either::A { foo: true, .. } => (),
1799 Either::A { foo: false, .. } => (),
1800 Either::B => (),
1801 }
1802 }
1803 ",
1804 );
1805 } 1209 }
1806 1210}
1807 #[test] 1211"#,
1808 fn enum_record_ellipsis_all_fields_missing_arm() {
1809 check_diagnostic(
1810 r"
1811 enum Either {
1812 A { foo: bool, bar: bool },
1813 B,
1814 }
1815 fn test_fn() {
1816 let a = Either::B;
1817 match a {
1818 Either::A { .. } => (),
1819 }
1820 }
1821 ",
1822 ); 1212 );
1823 } 1213 }
1824 1214
1825 #[test] 1215 #[test]
1826 fn enum_record_ellipsis_all_fields_no_diagnostic() { 1216 fn enum_record_ellipsis() {
1827 check_no_diagnostic( 1217 check_diagnostics(
1828 r" 1218 r#"
1829 enum Either { 1219enum Either {
1830 A { foo: bool, bar: bool }, 1220 A { foo: bool, bar: bool },
1831 B, 1221 B,
1832 } 1222}
1833 fn test_fn() {
1834 let a = Either::B;
1835 match a {
1836 Either::A { .. } => (),
1837 Either::B => (),
1838 }
1839 }
1840 ",
1841 );
1842 }
1843 1223
1844 #[test] 1224fn main() {
1845 fn enum_tuple_partial_ellipsis_no_diagnostic() { 1225 let a = Either::B;
1846 check_no_diagnostic( 1226 match a {
1847 r" 1227 //^ Missing match arm
1848 enum Either { 1228 Either::A { foo: true, .. } => (),
1849 A(bool, bool, bool, bool), 1229 Either::B => (),
1850 B,
1851 }
1852 fn test_fn() {
1853 match Either::B {
1854 Either::A(true, .., true) => {},
1855 Either::A(true, .., false) => {},
1856 Either::A(false, .., true) => {},
1857 Either::A(false, .., false) => {},
1858 Either::B => {},
1859 }
1860 }
1861 ",
1862 );
1863 } 1230 }
1864 1231 match a {
1865 #[test] 1232 //^ Missing match arm
1866 fn enum_tuple_partial_ellipsis_2_no_diagnostic() { 1233 Either::A { .. } => (),
1867 check_no_diagnostic(
1868 r"
1869 enum Either {
1870 A(bool, bool, bool, bool),
1871 B,
1872 }
1873 fn test_fn() {
1874 match Either::B {
1875 Either::A(true, .., true) => {},
1876 Either::A(true, .., false) => {},
1877 Either::A(.., true) => {},
1878 Either::A(.., false) => {},
1879 Either::B => {},
1880 }
1881 }
1882 ",
1883 );
1884 } 1234 }
1885 1235
1886 #[test] 1236 match a {
1887 fn enum_tuple_partial_ellipsis_missing_arm() { 1237 Either::A { foo: true, .. } => (),
1888 check_diagnostic( 1238 Either::A { foo: false, .. } => (),
1889 r" 1239 Either::B => (),
1890 enum Either {
1891 A(bool, bool, bool, bool),
1892 B,
1893 }
1894 fn test_fn() {
1895 match Either::B {
1896 Either::A(true, .., true) => {},
1897 Either::A(true, .., false) => {},
1898 Either::A(false, .., false) => {},
1899 Either::B => {},
1900 }
1901 }
1902 ",
1903 );
1904 } 1240 }
1905 1241
1906 #[test] 1242 match a {
1907 fn enum_tuple_partial_ellipsis_2_missing_arm() { 1243 Either::A { .. } => (),
1908 check_diagnostic( 1244 Either::B => (),
1909 r"
1910 enum Either {
1911 A(bool, bool, bool, bool),
1912 B,
1913 }
1914 fn test_fn() {
1915 match Either::B {
1916 Either::A(true, .., true) => {},
1917 Either::A(true, .., false) => {},
1918 Either::A(.., true) => {},
1919 Either::B => {},
1920 }
1921 }
1922 ",
1923 );
1924 } 1245 }
1925 1246}
1926 #[test] 1247"#,
1927 fn enum_tuple_ellipsis_no_diagnostic() {
1928 check_no_diagnostic(
1929 r"
1930 enum Either {
1931 A(bool, bool, bool, bool),
1932 B,
1933 }
1934 fn test_fn() {
1935 match Either::B {
1936 Either::A(..) => {},
1937 Either::B => {},
1938 }
1939 }
1940 ",
1941 ); 1248 );
1942 } 1249 }
1943 1250
1944 #[test] 1251 #[test]
1945 fn enum_never() { 1252 fn enum_tuple_partial_ellipsis() {
1946 check_no_diagnostic( 1253 check_diagnostics(
1947 r" 1254 r#"
1948 enum Never {} 1255enum Either {
1256 A(bool, bool, bool, bool),
1257 B,
1258}
1949 1259
1950 fn test_fn(never: Never) { 1260fn main() {
1951 match never {} 1261 match Either::B {
1952 } 1262 //^^^^^^^^^ Missing match arm
1953 ", 1263 Either::A(true, .., true) => (),
1954 ); 1264 Either::A(true, .., false) => (),
1265 Either::A(false, .., false) => (),
1266 Either::B => (),
1267 }
1268 match Either::B {
1269 //^^^^^^^^^ Missing match arm
1270 Either::A(true, .., true) => (),
1271 Either::A(true, .., false) => (),
1272 Either::A(.., true) => (),
1273 Either::B => (),
1274 }
1275
1276 match Either::B {
1277 Either::A(true, .., true) => (),
1278 Either::A(true, .., false) => (),
1279 Either::A(false, .., true) => (),
1280 Either::A(false, .., false) => (),
1281 Either::B => (),
1282 }
1283 match Either::B {
1284 Either::A(true, .., true) => (),
1285 Either::A(true, .., false) => (),
1286 Either::A(.., true) => (),
1287 Either::A(.., false) => (),
1288 Either::B => (),
1955 } 1289 }
1956 1290}
1957 #[test] 1291"#,
1958 fn type_never() {
1959 check_no_diagnostic(
1960 r"
1961 fn test_fn(never: !) {
1962 match never {}
1963 }
1964 ",
1965 ); 1292 );
1966 } 1293 }
1967 1294
1968 #[test] 1295 #[test]
1969 fn enum_never_ref() { 1296 fn never() {
1970 check_no_diagnostic( 1297 check_diagnostics(
1971 r" 1298 r#"
1972 enum Never {} 1299enum Never {}
1973 1300
1974 fn test_fn(never: &Never) { 1301fn enum_(never: Never) {
1975 match never {} 1302 match never {}
1976 } 1303}
1977 ", 1304fn enum_ref(never: &Never) {
1978 ); 1305 match never {}
1979 } 1306}
1980 1307fn bang(never: !) {
1981 #[test] 1308 match never {}
1982 fn expr_diverges_missing_arm() { 1309}
1983 check_no_diagnostic( 1310"#,
1984 r"
1985 enum Either {
1986 A,
1987 B,
1988 }
1989 fn test_fn() {
1990 match loop {} {
1991 Either::A => (),
1992 }
1993 }
1994 ",
1995 ); 1311 );
1996 } 1312 }
1997 1313
1998 #[test] 1314 #[test]
1999 fn or_pattern_panic() { 1315 fn or_pattern_panic() {
2000 check_no_diagnostic( 1316 check_diagnostics(
2001 r" 1317 r#"
2002 pub enum Category { 1318pub enum Category { Infinity, Zero }
2003 Infinity,
2004 Zero,
2005 }
2006 1319
2007 fn panic(a: Category, b: Category) { 1320fn panic(a: Category, b: Category) {
2008 match (a, b) { 1321 match (a, b) {
2009 (Category::Zero | Category::Infinity, _) => {} 1322 (Category::Zero | Category::Infinity, _) => (),
2010 (_, Category::Zero | Category::Infinity) => {} 1323 (_, Category::Zero | Category::Infinity) => (),
2011 }
2012 }
2013 ",
2014 );
2015 } 1324 }
2016 1325
2017 #[test] 1326 // FIXME: This is a false positive, but the code used to cause a panic in the match checker,
2018 fn or_pattern_panic_2() { 1327 // so this acts as a regression test for that.
2019 // FIXME: This is a false positive, but the code used to cause a panic in the match checker, 1328 match (a, b) {
2020 // so this acts as a regression test for that. 1329 //^^^^^^ Missing match arm
2021 check_diagnostic( 1330 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (),
2022 r" 1331 (Category::Infinity | Category::Zero, _) => (),
2023 pub enum Category {
2024 Infinity,
2025 Zero,
2026 }
2027
2028 fn panic(a: Category, b: Category) {
2029 match (a, b) {
2030 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {}
2031
2032 (Category::Infinity | Category::Zero, _) => {}
2033 }
2034 }
2035 ",
2036 );
2037 } 1332 }
2038} 1333}
2039 1334"#,
2040#[cfg(test)] 1335 );
2041mod false_negatives { 1336 }
2042 //! The implementation of match checking here is a work in progress. As we roll this out, we 1337
2043 //! prefer false negatives to false positives (ideally there would be no false positives). This 1338 mod false_negatives {
2044 //! test module should document known false negatives. Eventually we will have a complete 1339 //! The implementation of match checking here is a work in progress. As we roll this out, we
2045 //! implementation of match checking and this module will be empty. 1340 //! prefer false negatives to false positives (ideally there would be no false positives). This
2046 //! 1341 //! test module should document known false negatives. Eventually we will have a complete
2047 //! The reasons for documenting known false negatives: 1342 //! implementation of match checking and this module will be empty.
2048 //! 1343 //!
2049 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. 1344 //! The reasons for documenting known false negatives:
2050 //! 2. It ensures the code doesn't panic when handling these cases. 1345 //!
2051 1346 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
2052 use super::tests::*; 1347 //! 2. It ensures the code doesn't panic when handling these cases.
2053 1348 use super::*;
2054 #[test] 1349
2055 fn integers() { 1350 #[test]
2056 // This is a false negative. 1351 fn integers() {
2057 // We don't currently check integer exhaustiveness. 1352 // We don't currently check integer exhaustiveness.
2058 check_no_diagnostic( 1353 check_diagnostics(
2059 r" 1354 r#"
2060 fn test_fn() { 1355fn main() {
2061 match 5 { 1356 match 5 {
2062 10 => (), 1357 10 => (),
2063 11..20 => (), 1358 11..20 => (),
2064 }
2065 }
2066 ",
2067 );
2068 }
2069
2070 #[test]
2071 fn internal_or() {
2072 // This is a false negative.
2073 // We do not currently handle patterns with internal `or`s.
2074 check_no_diagnostic(
2075 r"
2076 fn test_fn() {
2077 enum Either {
2078 A(bool),
2079 B,
2080 }
2081 match Either::B {
2082 Either::A(true | false) => (),
2083 }
2084 }
2085 ",
2086 );
2087 } 1359 }
1360}
1361"#,
1362 );
1363 }
2088 1364
2089 #[test] 1365 #[test]
2090 fn expr_loop_missing_arm() { 1366 fn internal_or() {
2091 // This is a false negative. 1367 // We do not currently handle patterns with internal `or`s.
2092 // We currently infer the type of `loop { break Foo::A }` to `!`, which 1368 check_diagnostics(
2093 // causes us to skip the diagnostic since `Either::A` doesn't type check 1369 r#"
2094 // with `!`. 1370fn main() {
2095 check_diagnostic( 1371 enum Either { A(bool), B }
2096 r" 1372 match Either::B {
2097 enum Either { 1373 Either::A(true | false) => (),
2098 A,
2099 B,
2100 }
2101 fn test_fn() {
2102 match loop { break Foo::A } {
2103 Either::A => (),
2104 }
2105 }
2106 ",
2107 );
2108 } 1374 }
1375}
1376"#,
1377 );
1378 }
2109 1379
2110 #[test] 1380 #[test]
2111 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { 1381 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
2112 // This is a false negative. 1382 // We don't currently handle tuple patterns with ellipsis.
2113 // We don't currently handle tuple patterns with ellipsis. 1383 check_diagnostics(
2114 check_no_diagnostic( 1384 r#"
2115 r" 1385fn main() {
2116 fn test_fn() { 1386 match (false, true, false) {
2117 match (false, true, false) { 1387 (false, ..) => (),
2118 (false, ..) => {},
2119 }
2120 }
2121 ",
2122 );
2123 } 1388 }
1389}
1390"#,
1391 );
1392 }
2124 1393
2125 #[test] 1394 #[test]
2126 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { 1395 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
2127 // This is a false negative. 1396 // We don't currently handle tuple patterns with ellipsis.
2128 // We don't currently handle tuple patterns with ellipsis. 1397 check_diagnostics(
2129 check_no_diagnostic( 1398 r#"
2130 r" 1399fn main() {
2131 fn test_fn() { 1400 match (false, true, false) {
2132 match (false, true, false) { 1401 (.., false) => (),
2133 (.., false) => {},
2134 }
2135 }
2136 ",
2137 );
2138 } 1402 }
1403}
1404"#,
1405 );
1406 }
2139 1407
2140 #[test] 1408 #[test]
2141 fn struct_missing_arm() { 1409 fn struct_missing_arm() {
2142 // This is a false negative. 1410 // We don't currently handle structs.
2143 // We don't currently handle structs. 1411 check_diagnostics(
2144 check_no_diagnostic( 1412 r#"
2145 r" 1413struct Foo { a: bool }
2146 struct Foo { 1414fn main(f: Foo) {
2147 a: bool, 1415 match f { Foo { a: true } => () }
2148 } 1416}
2149 fn test_fn(f: Foo) { 1417"#,
2150 match f { 1418 );
2151 Foo { a: true } => {}, 1419 }
2152 }
2153 }
2154 ",
2155 );
2156 } 1420 }
2157} 1421}
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index c512c4f8e..5cc76bdce 100644
--- a/crates/ra_hir_ty/src/unsafe_validation.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,35 +6,38 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 body::Body, 7 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 8 expr::{Expr, ExprId, UnaryOp},
9 DefWithBodyId, FunctionId, 9 DefWithBodyId,
10}; 10};
11use hir_expand::diagnostics::DiagnosticSink; 11use hir_expand::diagnostics::DiagnosticSink;
12 12
13use crate::{ 13use crate::{
14 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, 14 db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDefId, ApplicationTy,
15 InferenceResult, Ty, TypeCtor, 15 InferenceResult, Ty, TypeCtor,
16}; 16};
17 17
18pub struct UnsafeValidator<'a, 'b: 'a> { 18pub(super) struct UnsafeValidator<'a, 'b: 'a> {
19 func: FunctionId, 19 owner: DefWithBodyId,
20 infer: Arc<InferenceResult>, 20 infer: Arc<InferenceResult>,
21 sink: &'a mut DiagnosticSink<'b>, 21 sink: &'a mut DiagnosticSink<'b>,
22} 22}
23 23
24impl<'a, 'b> UnsafeValidator<'a, 'b> { 24impl<'a, 'b> UnsafeValidator<'a, 'b> {
25 pub fn new( 25 pub(super) fn new(
26 func: FunctionId, 26 owner: DefWithBodyId,
27 infer: Arc<InferenceResult>, 27 infer: Arc<InferenceResult>,
28 sink: &'a mut DiagnosticSink<'b>, 28 sink: &'a mut DiagnosticSink<'b>,
29 ) -> UnsafeValidator<'a, 'b> { 29 ) -> UnsafeValidator<'a, 'b> {
30 UnsafeValidator { func, infer, sink } 30 UnsafeValidator { owner, infer, sink }
31 } 31 }
32 32
33 pub fn validate_body(&mut self, db: &dyn HirDatabase) { 33 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
34 let def = self.func.into(); 34 let def = self.owner.into();
35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
36 let func_data = db.function_data(self.func); 36 let is_unsafe = match self.owner {
37 if func_data.is_unsafe 37 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe,
38 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
39 };
40 if is_unsafe
38 || unsafe_expressions 41 || unsafe_expressions
39 .iter() 42 .iter()
40 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) 43 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
@@ -85,7 +88,7 @@ fn walk_unsafe(
85 Expr::Call { callee, .. } => { 88 Expr::Call { callee, .. } => {
86 let ty = &infer[*callee]; 89 let ty = &infer[*callee];
87 if let &Ty::Apply(ApplicationTy { 90 if let &Ty::Apply(ApplicationTy {
88 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), 91 ctor: TypeCtor::FnDef(CallableDefId::FunctionId(func)),
89 .. 92 ..
90 }) = ty 93 }) = ty
91 { 94 {
@@ -118,3 +121,53 @@ fn walk_unsafe(
118 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block);
119 }); 122 });
120} 123}
124
125#[cfg(test)]
126mod tests {
127 use crate::diagnostics::tests::check_diagnostics;
128
129 #[test]
130 fn missing_unsafe_diagnostic_with_raw_ptr() {
131 check_diagnostics(
132 r#"
133fn main() {
134 let x = &5 as *const usize;
135 unsafe { let y = *x; }
136 let z = *x;
137} //^^ This operation is unsafe and requires an unsafe function or block
138"#,
139 )
140 }
141
142 #[test]
143 fn missing_unsafe_diagnostic_with_unsafe_call() {
144 check_diagnostics(
145 r#"
146struct HasUnsafe;
147
148impl HasUnsafe {
149 unsafe fn unsafe_fn(&self) {
150 let x = &5 as *const usize;
151 let y = *x;
152 }
153}
154
155unsafe fn unsafe_fn() {
156 let x = &5 as *const usize;
157 let y = *x;
158}
159
160fn main() {
161 unsafe_fn();
162 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
163 HasUnsafe.unsafe_fn();
164 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
165 unsafe {
166 unsafe_fn();
167 HasUnsafe.unsafe_fn();
168 }
169}
170"#,
171 );
172 }
173}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 23cea1a2a..19770e609 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -3,7 +3,7 @@
3use std::fmt; 3use std::fmt;
4 4
5use crate::{ 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, 6 db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate,
7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 7 Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8}; 8};
9use hir_def::{ 9use hir_def::{
@@ -243,22 +243,36 @@ impl HirDisplay for ApplicationTy {
243 write!(f, ")")?; 243 write!(f, ")")?;
244 } 244 }
245 } 245 }
246 TypeCtor::FnPtr { .. } => { 246 TypeCtor::FnPtr { is_varargs, .. } => {
247 let sig = FnSig::from_fn_ptr_substs(&self.parameters); 247 let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs);
248 write!(f, "fn(")?; 248 write!(f, "fn(")?;
249 f.write_joined(sig.params(), ", ")?; 249 f.write_joined(sig.params(), ", ")?;
250 if is_varargs {
251 if sig.params().is_empty() {
252 write!(f, "...")?;
253 } else {
254 write!(f, ", ...")?;
255 }
256 }
250 write!(f, ")")?; 257 write!(f, ")")?;
251 let ret = sig.ret(); 258 let ret = sig.ret();
252 if *ret != Ty::unit() { 259 if *ret != Ty::unit() {
253 write!(f, " -> {}", ret.display(f.db))?; 260 let ret_display = if f.omit_verbose_types() {
261 ret.display_truncated(f.db, f.max_size)
262 } else {
263 ret.display(f.db)
264 };
265 write!(f, " -> {}", ret_display)?;
254 } 266 }
255 } 267 }
256 TypeCtor::FnDef(def) => { 268 TypeCtor::FnDef(def) => {
257 let sig = f.db.callable_item_signature(def).subst(&self.parameters); 269 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
258 match def { 270 match def {
259 CallableDef::FunctionId(ff) => write!(f, "fn {}", f.db.function_data(ff).name)?, 271 CallableDefId::FunctionId(ff) => {
260 CallableDef::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?, 272 write!(f, "fn {}", f.db.function_data(ff).name)?
261 CallableDef::EnumVariantId(e) => { 273 }
274 CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
275 CallableDefId::EnumVariantId(e) => {
262 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? 276 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
263 } 277 }
264 }; 278 };
@@ -279,7 +293,12 @@ impl HirDisplay for ApplicationTy {
279 write!(f, ")")?; 293 write!(f, ")")?;
280 let ret = sig.ret(); 294 let ret = sig.ret();
281 if *ret != Ty::unit() { 295 if *ret != Ty::unit() {
282 write!(f, " -> {}", ret.display(f.db))?; 296 let ret_display = if f.omit_verbose_types() {
297 ret.display_truncated(f.db, f.max_size)
298 } else {
299 ret.display(f.db)
300 };
301 write!(f, " -> {}", ret_display)?;
283 } 302 }
284 } 303 }
285 TypeCtor::Adt(def_id) => { 304 TypeCtor::Adt(def_id) => {
@@ -369,7 +388,7 @@ impl HirDisplay for ApplicationTy {
369 let data = (*datas) 388 let data = (*datas)
370 .as_ref() 389 .as_ref()
371 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 390 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
372 data.clone().subst(&self.parameters) 391 data.subst(&self.parameters)
373 } 392 }
374 }; 393 };
375 write!(f, "impl ")?; 394 write!(f, "impl ")?;
@@ -388,7 +407,13 @@ impl HirDisplay for ApplicationTy {
388 f.write_joined(sig.params(), ", ")?; 407 f.write_joined(sig.params(), ", ")?;
389 write!(f, "|")?; 408 write!(f, "|")?;
390 }; 409 };
391 write!(f, " -> {}", sig.ret().display(f.db))?; 410
411 let ret_display = if f.omit_verbose_types() {
412 sig.ret().display_truncated(f.db, f.max_size)
413 } else {
414 sig.ret().display(f.db)
415 };
416 write!(f, " -> {}", ret_display)?;
392 } else { 417 } else {
393 write!(f, "{{closure}}")?; 418 write!(f, "{{closure}}")?;
394 } 419 }
@@ -456,7 +481,7 @@ impl HirDisplay for Ty {
456 let data = (*datas) 481 let data = (*datas)
457 .as_ref() 482 .as_ref()
458 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 483 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
459 data.clone().subst(&opaque_ty.parameters) 484 data.subst(&opaque_ty.parameters)
460 } 485 }
461 }; 486 };
462 write!(f, "impl ")?; 487 write!(f, "impl ")?;
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 3719f76a6..28f32a0a4 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -18,8 +18,6 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use rustc_hash::FxHashMap;
22
23use hir_def::{ 21use hir_def::{
24 body::Body, 22 body::Body,
25 data::{ConstData, FunctionData, StaticData}, 23 data::{ConstData, FunctionData, StaticData},
@@ -28,13 +26,15 @@ use hir_def::{
28 path::{path, Path}, 26 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 27 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 28 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId, 29 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId,
32 VariantId, 30 TypeAliasId, VariantId,
33}; 31};
34use hir_expand::{diagnostics::DiagnosticSink, name::name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
35use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
36use ra_prof::profile; 34use ra_prof::profile;
37use ra_syntax::SmolStr; 35use ra_syntax::SmolStr;
36use rustc_hash::FxHashMap;
37use stdx::impl_from;
38 38
39use super::{ 39use super::{
40 primitive::{FloatTy, IntTy}, 40 primitive::{FloatTy, IntTy},
@@ -84,8 +84,7 @@ enum ExprOrPatId {
84 ExprId(ExprId), 84 ExprId(ExprId),
85 PatId(PatId), 85 PatId(PatId),
86} 86}
87 87impl_from!(ExprId, PatId for ExprOrPatId);
88impl_froms!(ExprOrPatId: ExprId, PatId);
89 88
90/// Binding modes inferred for patterns. 89/// Binding modes inferred for patterns.
91/// https://doc.rust-lang.org/reference/patterns.html#binding-modes 90/// https://doc.rust-lang.org/reference/patterns.html#binding-modes
@@ -169,7 +168,7 @@ impl InferenceResult {
169 pub fn add_diagnostics( 168 pub fn add_diagnostics(
170 &self, 169 &self,
171 db: &dyn HirDatabase, 170 db: &dyn HirDatabase,
172 owner: FunctionId, 171 owner: DefWithBodyId,
173 sink: &mut DiagnosticSink, 172 sink: &mut DiagnosticSink,
174 ) { 173 ) {
175 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink)) 174 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
@@ -376,17 +375,21 @@ impl<'a> InferenceContext<'a> {
376 ) -> Ty { 375 ) -> Ty {
377 match assoc_ty { 376 match assoc_ty {
378 Some(res_assoc_ty) => { 377 Some(res_assoc_ty) => {
378 let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
379 hir_def::AssocContainerId::TraitId(trait_) => trait_,
380 _ => panic!("resolve_associated_type called with non-associated type"),
381 };
379 let ty = self.table.new_type_var(); 382 let ty = self.table.new_type_var();
380 let builder = Substs::build_for_def(self.db, res_assoc_ty) 383 let substs = Substs::build_for_def(self.db, res_assoc_ty)
381 .push(inner_ty) 384 .push(inner_ty)
382 .fill(params.iter().cloned()); 385 .fill(params.iter().cloned())
386 .build();
387 let trait_ref = TraitRef { trait_, substs: substs.clone() };
383 let projection = ProjectionPredicate { 388 let projection = ProjectionPredicate {
384 ty: ty.clone(), 389 ty: ty.clone(),
385 projection_ty: ProjectionTy { 390 projection_ty: ProjectionTy { associated_ty: res_assoc_ty, parameters: substs },
386 associated_ty: res_assoc_ty,
387 parameters: builder.build(),
388 },
389 }; 391 };
392 self.obligations.push(Obligation::Trait(trait_ref));
390 self.obligations.push(Obligation::Projection(projection)); 393 self.obligations.push(Obligation::Projection(projection));
391 self.resolve_ty_as_possible(ty) 394 self.resolve_ty_as_possible(ty)
392 } 395 }
@@ -757,7 +760,7 @@ impl std::ops::BitOrAssign for Diverges {
757} 760}
758 761
759mod diagnostics { 762mod diagnostics {
760 use hir_def::{expr::ExprId, FunctionId}; 763 use hir_def::{expr::ExprId, DefWithBodyId};
761 use hir_expand::diagnostics::DiagnosticSink; 764 use hir_expand::diagnostics::DiagnosticSink;
762 765
763 use crate::{ 766 use crate::{
@@ -775,17 +778,17 @@ mod diagnostics {
775 pub(super) fn add_to( 778 pub(super) fn add_to(
776 &self, 779 &self,
777 db: &dyn HirDatabase, 780 db: &dyn HirDatabase,
778 owner: FunctionId, 781 owner: DefWithBodyId,
779 sink: &mut DiagnosticSink, 782 sink: &mut DiagnosticSink,
780 ) { 783 ) {
781 match self { 784 match self {
782 InferenceDiagnostic::NoSuchField { expr, field } => { 785 InferenceDiagnostic::NoSuchField { expr, field } => {
783 let (_, source_map) = db.body_with_source_map(owner.into()); 786 let (_, source_map) = db.body_with_source_map(owner);
784 let field = source_map.field_syntax(*expr, *field); 787 let field = source_map.field_syntax(*expr, *field);
785 sink.push(NoSuchField { file: field.file_id, field: field.value }) 788 sink.push(NoSuchField { file: field.file_id, field: field.value })
786 } 789 }
787 InferenceDiagnostic::BreakOutsideOfLoop { expr } => { 790 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
788 let (_, source_map) = db.body_with_source_map(owner.into()); 791 let (_, source_map) = db.body_with_source_map(owner);
789 let ptr = source_map 792 let ptr = source_map
790 .expr_syntax(*expr) 793 .expr_syntax(*expr)
791 .expect("break outside of loop in synthetic syntax"); 794 .expect("break outside of loop in synthetic syntax");
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 22884522a..731b062c2 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -17,7 +17,7 @@ use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::{FnTrait, InEnvironment}, 18 traits::{FnTrait, InEnvironment},
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, 20 ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
21 TraitRef, Ty, TypeCtor, 21 TraitRef, Ty, TypeCtor,
22}; 22};
23 23
@@ -85,10 +85,8 @@ impl<'a> InferenceContext<'a> {
85 ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, 85 ctor: TypeCtor::Tuple { cardinality: num_args as u16 },
86 parameters, 86 parameters,
87 }); 87 });
88 let substs = Substs::build_for_generics(&generic_params) 88 let substs =
89 .push(ty.clone()) 89 Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
90 .push(arg_ty.clone())
91 .build();
92 90
93 let trait_env = Arc::clone(&self.trait_env); 91 let trait_env = Arc::clone(&self.trait_env);
94 let implements_fn_trait = 92 let implements_fn_trait =
@@ -222,7 +220,7 @@ impl<'a> InferenceContext<'a> {
222 }; 220 };
223 sig_tys.push(ret_ty.clone()); 221 sig_tys.push(ret_ty.clone());
224 let sig_ty = Ty::apply( 222 let sig_ty = Ty::apply(
225 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 223 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false },
226 Substs(sig_tys.clone().into()), 224 Substs(sig_tys.clone().into()),
227 ); 225 );
228 let closure_ty = 226 let closure_ty =
@@ -407,8 +405,15 @@ impl<'a> InferenceContext<'a> {
407 .subst(&a_ty.parameters) 405 .subst(&a_ty.parameters)
408 }) 406 })
409 } 407 }
410 // FIXME: 408 TypeCtor::Adt(AdtId::UnionId(u)) => {
411 TypeCtor::Adt(AdtId::UnionId(_)) => None, 409 self.db.union_data(u).variant_data.field(name).map(|local_id| {
410 let field = FieldId { parent: u.into(), local_id };
411 self.write_field_resolution(tgt_expr, field);
412 self.db.field_types(u.into())[field.local_id]
413 .clone()
414 .subst(&a_ty.parameters)
415 })
416 }
412 _ => None, 417 _ => None,
413 }, 418 },
414 _ => None, 419 _ => None,
@@ -849,7 +854,7 @@ impl<'a> InferenceContext<'a> {
849 } 854 }
850 // add obligation for trait implementation, if this is a trait method 855 // add obligation for trait implementation, if this is a trait method
851 match def { 856 match def {
852 CallableDef::FunctionId(f) => { 857 CallableDefId::FunctionId(f) => {
853 if let AssocContainerId::TraitId(trait_) = 858 if let AssocContainerId::TraitId(trait_) =
854 f.lookup(self.db.upcast()).container 859 f.lookup(self.db.upcast()).container
855 { 860 {
@@ -860,7 +865,7 @@ impl<'a> InferenceContext<'a> {
860 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); 865 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
861 } 866 }
862 } 867 }
863 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {} 868 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}
864 } 869 }
865 } 870 }
866 } 871 }
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 269495ca0..2e895d911 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, 11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
12 TypeCtor, TypeWalk, 12 TyKind, TypeCtor, TypeWalk,
13}; 13};
14 14
15impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
@@ -86,10 +86,20 @@ where
86 } 86 }
87 87
88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
89 Canonicalized { 89 let kinds = self
90 value: Canonical { value: result, num_vars: self.free_vars.len() }, 90 .free_vars
91 free_vars: self.free_vars, 91 .iter()
92 } 92 .map(|v| match v {
93 // mapping MaybeNeverTypeVar to the same kind as general ones
94 // should be fine, because as opposed to int or float type vars,
95 // they don't restrict what kind of type can go into them, they
96 // just affect fallback.
97 InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
98 InferTy::IntVar(_) => TyKind::Integer,
99 InferTy::FloatVar(_) => TyKind::Float,
100 })
101 .collect();
102 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
93 } 103 }
94 104
95 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { 105 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> {
131 ty 141 ty
132 } 142 }
133 143
134 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { 144 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) {
135 // the solution may contain new variables, which we need to convert to new inference vars 145 // the solution may contain new variables, which we need to convert to new inference vars
136 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); 146 let new_vars = Substs(
147 solution
148 .kinds
149 .iter()
150 .map(|k| match k {
151 TyKind::General => ctx.table.new_type_var(),
152 TyKind::Integer => ctx.table.new_integer_var(),
153 TyKind::Float => ctx.table.new_float_var(),
154 })
155 .collect(),
156 );
137 for (i, ty) in solution.value.into_iter().enumerate() { 157 for (i, ty) in solution.value.into_iter().enumerate() {
138 let var = self.free_vars[i]; 158 let var = self.free_vars[i];
139 // eagerly replace projections in the type; we may be getting types 159 // eagerly replace projections in the type; we may be getting types
140 // e.g. from where clauses where this hasn't happened yet 160 // e.g. from where clauses where this hasn't happened yet
141 let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); 161 let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
142 ctx.table.unify(&Ty::Infer(var), &ty); 162 ctx.table.unify(&Ty::Infer(var), &ty);
143 } 163 }
144 } 164 }
145} 165}
146 166
147pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { 167pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
148 let mut table = InferenceTable::new(); 168 let mut table = InferenceTable::new();
149 let num_vars = ty1.num_vars.max(ty2.num_vars); 169 let vars = Substs(
150 let vars = 170 tys.kinds
151 Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); 171 .iter()
152 let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); 172 // we always use type vars here because we want everything to
153 let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); 173 // fallback to Unknown in the end (kind of hacky, as below)
174 .map(|_| table.new_type_var())
175 .collect(),
176 );
177 let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
178 let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
154 if !table.unify(&ty1_with_vars, &ty2_with_vars) { 179 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
155 return None; 180 return None;
156 } 181 }
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
162 } 187 }
163 } 188 }
164 Some( 189 Some(
165 Substs::builder(ty1.num_vars) 190 Substs::builder(tys.kinds.len())
166 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) 191 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
167 .build(), 192 .build(),
168 ) 193 )
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c9513b752..7698cb0d4 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -6,25 +6,6 @@ macro_rules! eprintln {
6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
7} 7}
8 8
9macro_rules! impl_froms {
10 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
11 $(
12 impl From<$v> for $e {
13 fn from(it: $v) -> $e {
14 $e::$v(it)
15 }
16 }
17 $($(
18 impl From<$sv> for $e {
19 fn from(it: $sv) -> $e {
20 $e::$v($v::$sv(it))
21 }
22 }
23 )*)?
24 )*
25 }
26}
27
28mod autoderef; 9mod autoderef;
29pub mod primitive; 10pub mod primitive;
30pub mod traits; 11pub mod traits;
@@ -32,22 +13,18 @@ pub mod method_resolution;
32mod op; 13mod op;
33mod lower; 14mod lower;
34pub(crate) mod infer; 15pub(crate) mod infer;
35pub mod display;
36pub(crate) mod utils; 16pub(crate) mod utils;
17
18pub mod display;
37pub mod db; 19pub mod db;
38pub mod diagnostics; 20pub mod diagnostics;
39pub mod expr;
40pub mod unsafe_validation;
41 21
42#[cfg(test)] 22#[cfg(test)]
43mod tests; 23mod tests;
44#[cfg(test)] 24#[cfg(test)]
45mod test_db; 25mod test_db;
46mod _match;
47 26
48use std::ops::Deref; 27use std::{iter, mem, ops::Deref, sync::Arc};
49use std::sync::Arc;
50use std::{iter, mem};
51 28
52use hir_def::{ 29use hir_def::{
53 expr::ExprId, 30 expr::ExprId,
@@ -55,18 +32,19 @@ use hir_def::{
55 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 32 AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId,
56 TypeParamId, 33 TypeParamId,
57}; 34};
58use ra_db::{impl_intern_key, salsa, CrateId}; 35use itertools::Itertools;
36use ra_db::{salsa, CrateId};
59 37
60use crate::{ 38use crate::{
61 db::HirDatabase, 39 db::HirDatabase,
40 display::HirDisplay,
62 primitive::{FloatTy, IntTy}, 41 primitive::{FloatTy, IntTy},
63 utils::{generics, make_mut_slice, Generics}, 42 utils::{generics, make_mut_slice, Generics},
64}; 43};
65use display::HirDisplay;
66 44
67pub use autoderef::autoderef; 45pub use autoderef::autoderef;
68pub use infer::{InferTy, InferenceResult}; 46pub use infer::{InferTy, InferenceResult};
69pub use lower::CallableDef; 47pub use lower::CallableDefId;
70pub use lower::{ 48pub use lower::{
71 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, 49 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId,
72 TyLoweringContext, ValueTyDefId, 50 TyLoweringContext, ValueTyDefId,
@@ -74,7 +52,6 @@ pub use lower::{
74pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 52pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
75 53
76pub use chalk_ir::{BoundVar, DebruijnIndex}; 54pub use chalk_ir::{BoundVar, DebruijnIndex};
77use itertools::Itertools;
78 55
79/// A type constructor or type name: this might be something like the primitive 56/// A type constructor or type name: this might be something like the primitive
80/// type `bool`, a struct like `Vec`, or things like function pointers or 57/// type `bool`, a struct like `Vec`, or things like function pointers or
@@ -125,7 +102,7 @@ pub enum TypeCtor {
125 /// fn foo() -> i32 { 1 } 102 /// fn foo() -> i32 { 1 }
126 /// let bar = foo; // bar: fn() -> i32 {foo} 103 /// let bar = foo; // bar: fn() -> i32 {foo}
127 /// ``` 104 /// ```
128 FnDef(CallableDef), 105 FnDef(CallableDefId),
129 106
130 /// A pointer to a function. Written as `fn() -> i32`. 107 /// A pointer to a function. Written as `fn() -> i32`.
131 /// 108 ///
@@ -135,7 +112,8 @@ pub enum TypeCtor {
135 /// fn foo() -> i32 { 1 } 112 /// fn foo() -> i32 { 1 }
136 /// let bar: fn() -> i32 = foo; 113 /// let bar: fn() -> i32 = foo;
137 /// ``` 114 /// ```
138 FnPtr { num_args: u16 }, 115 // FIXME make this a Ty variant like in Chalk
116 FnPtr { num_args: u16, is_varargs: bool },
139 117
140 /// The never type `!`. 118 /// The never type `!`.
141 Never, 119 Never,
@@ -162,19 +140,6 @@ pub enum TypeCtor {
162 Closure { def: DefWithBodyId, expr: ExprId }, 140 Closure { def: DefWithBodyId, expr: ExprId },
163} 141}
164 142
165/// This exists just for Chalk, because Chalk just has a single `StructId` where
166/// we have different kinds of ADTs, primitive types and special type
167/// constructors like tuples and function pointers.
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
169pub struct TypeCtorId(salsa::InternId);
170impl_intern_key!(TypeCtorId);
171
172/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
173/// we have different IDs for struct and enum variant constructors.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
175pub struct CallableDefId(salsa::InternId);
176impl_intern_key!(CallableDefId);
177
178impl TypeCtor { 143impl TypeCtor {
179 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { 144 pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
180 match self { 145 match self {
@@ -210,7 +175,7 @@ impl TypeCtor {
210 } 175 }
211 } 176 }
212 } 177 }
213 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 178 TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
214 TypeCtor::Tuple { cardinality } => cardinality as usize, 179 TypeCtor::Tuple { cardinality } => cardinality as usize,
215 } 180 }
216 } 181 }
@@ -662,13 +627,27 @@ impl TypeWalk for GenericPredicate {
662 627
663/// Basically a claim (currently not validated / checked) that the contained 628/// Basically a claim (currently not validated / checked) that the contained
664/// type / trait ref contains no inference variables; any inference variables it 629/// type / trait ref contains no inference variables; any inference variables it
665/// contained have been replaced by bound variables, and `num_vars` tells us how 630/// contained have been replaced by bound variables, and `kinds` tells us how
666/// many there are. This is used to erase irrelevant differences between types 631/// many there are and whether they were normal or float/int variables. This is
667/// before using them in queries. 632/// used to erase irrelevant differences between types before using them in
633/// queries.
668#[derive(Debug, Clone, PartialEq, Eq, Hash)] 634#[derive(Debug, Clone, PartialEq, Eq, Hash)]
669pub struct Canonical<T> { 635pub struct Canonical<T> {
670 pub value: T, 636 pub value: T,
671 pub num_vars: usize, 637 pub kinds: Arc<[TyKind]>,
638}
639
640impl<T> Canonical<T> {
641 pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self {
642 Self { value, kinds: kinds.into_iter().collect() }
643 }
644}
645
646#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
647pub enum TyKind {
648 General,
649 Integer,
650 Float,
672} 651}
673 652
674/// A function signature as seen by type inference: Several parameter types and 653/// A function signature as seen by type inference: Several parameter types and
@@ -676,19 +655,20 @@ pub struct Canonical<T> {
676#[derive(Clone, PartialEq, Eq, Debug)] 655#[derive(Clone, PartialEq, Eq, Debug)]
677pub struct FnSig { 656pub struct FnSig {
678 params_and_return: Arc<[Ty]>, 657 params_and_return: Arc<[Ty]>,
658 is_varargs: bool,
679} 659}
680 660
681/// A polymorphic function signature. 661/// A polymorphic function signature.
682pub type PolyFnSig = Binders<FnSig>; 662pub type PolyFnSig = Binders<FnSig>;
683 663
684impl FnSig { 664impl FnSig {
685 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { 665 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig {
686 params.push(ret); 666 params.push(ret);
687 FnSig { params_and_return: params.into() } 667 FnSig { params_and_return: params.into(), is_varargs }
688 } 668 }
689 669
690 pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig { 670 pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig {
691 FnSig { params_and_return: Arc::clone(&substs.0) } 671 FnSig { params_and_return: Arc::clone(&substs.0), is_varargs }
692 } 672 }
693 673
694 pub fn params(&self) -> &[Ty] { 674 pub fn params(&self) -> &[Ty] {
@@ -733,7 +713,7 @@ impl Ty {
733 } 713 }
734 pub fn fn_ptr(sig: FnSig) -> Self { 714 pub fn fn_ptr(sig: FnSig) -> Self {
735 Ty::apply( 715 Ty::apply(
736 TypeCtor::FnPtr { num_args: sig.params().len() as u16 }, 716 TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs },
737 Substs(sig.params_and_return), 717 Substs(sig.params_and_return),
738 ) 718 )
739 } 719 }
@@ -787,15 +767,6 @@ impl Ty {
787 } 767 }
788 } 768 }
789 769
790 pub fn as_callable(&self) -> Option<(CallableDef, &Substs)> {
791 match self {
792 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => {
793 Some((*callable_def, parameters))
794 }
795 _ => None,
796 }
797 }
798
799 pub fn is_never(&self) -> bool { 770 pub fn is_never(&self) -> bool {
800 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) 771 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
801 } 772 }
@@ -827,10 +798,12 @@ impl Ty {
827 } 798 }
828 } 799 }
829 800
830 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { 801 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
831 match self { 802 match self {
832 Ty::Apply(a_ty) => match a_ty.ctor { 803 Ty::Apply(a_ty) => match a_ty.ctor {
833 TypeCtor::FnPtr { .. } => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), 804 TypeCtor::FnPtr { is_varargs, .. } => {
805 Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs))
806 }
834 TypeCtor::FnDef(def) => { 807 TypeCtor::FnDef(def) => {
835 let sig = db.callable_item_signature(def); 808 let sig = db.callable_item_signature(def);
836 Some(sig.subst(&a_ty.parameters)) 809 Some(sig.subst(&a_ty.parameters))
@@ -877,7 +850,7 @@ impl Ty {
877 let data = (*it) 850 let data = (*it)
878 .as_ref() 851 .as_ref()
879 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 852 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
880 data.clone().subst(&opaque_ty.parameters) 853 data.subst(&opaque_ty.parameters)
881 }) 854 })
882 } 855 }
883 }; 856 };
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 3dc154e92..1eacc6f95 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -5,10 +5,7 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::iter; 8use std::{iter, sync::Arc};
9use std::sync::Arc;
10
11use smallvec::SmallVec;
12 9
13use hir_def::{ 10use hir_def::{
14 adt::StructKind, 11 adt::StructKind,
@@ -24,6 +21,8 @@ use hir_def::{
24use hir_expand::name::Name; 21use hir_expand::name::Name;
25use ra_arena::map::ArenaMap; 22use ra_arena::map::ArenaMap;
26use ra_db::CrateId; 23use ra_db::CrateId;
24use smallvec::SmallVec;
25use stdx::impl_from;
27use test_utils::mark; 26use test_utils::mark;
28 27
29use crate::{ 28use crate::{
@@ -177,9 +176,12 @@ impl Ty {
177 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
178 } 177 }
179 TypeRef::Placeholder => Ty::Unknown, 178 TypeRef::Placeholder => Ty::Unknown,
180 TypeRef::Fn(params) => { 179 TypeRef::Fn(params, is_varargs) => {
181 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); 180 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
182 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) 181 Ty::apply(
182 TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs },
183 sig,
184 )
183 } 185 }
184 TypeRef::DynTrait(bounds) => { 186 TypeRef::DynTrait(bounds) => {
185 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 187 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
@@ -339,7 +341,7 @@ impl Ty {
339 let segment = remaining_segments.first().unwrap(); 341 let segment = remaining_segments.first().unwrap();
340 let found = associated_type_by_name_including_super_traits( 342 let found = associated_type_by_name_including_super_traits(
341 ctx.db, 343 ctx.db,
342 trait_ref.clone(), 344 trait_ref,
343 &segment.name, 345 &segment.name,
344 ); 346 );
345 match found { 347 match found {
@@ -720,8 +722,7 @@ fn assoc_type_bindings_from_type_bound<'a>(
720 None => return SmallVec::<[GenericPredicate; 1]>::new(), 722 None => return SmallVec::<[GenericPredicate; 1]>::new(),
721 Some(t) => t, 723 Some(t) => t,
722 }; 724 };
723 let projection_ty = 725 let projection_ty = ProjectionTy { associated_ty, parameters: super_trait_ref.substs };
724 ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() };
725 let mut preds = SmallVec::with_capacity( 726 let mut preds = SmallVec::with_capacity(
726 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), 727 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
727 ); 728 );
@@ -767,11 +768,11 @@ fn count_impl_traits(type_ref: &TypeRef) -> usize {
767} 768}
768 769
769/// Build the signature of a callable item (function, struct or enum variant). 770/// Build the signature of a callable item (function, struct or enum variant).
770pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { 771pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
771 match def { 772 match def {
772 CallableDef::FunctionId(f) => fn_sig_for_fn(db, f), 773 CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
773 CallableDef::StructId(s) => fn_sig_for_struct_constructor(db, s), 774 CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
774 CallableDef::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), 775 CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
775 } 776 }
776} 777}
777 778
@@ -998,7 +999,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
998 let ret = Ty::from_hir(&ctx_ret, &data.ret_type); 999 let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
999 let generics = generics(db.upcast(), def.into()); 1000 let generics = generics(db.upcast(), def.into());
1000 let num_binders = generics.len(); 1001 let num_binders = generics.len();
1001 Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) 1002 Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs))
1002} 1003}
1003 1004
1004/// Build the declared type of a function. This should not need to look at the 1005/// Build the declared type of a function. This should not need to look at the
@@ -1049,7 +1050,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
1049 let params = 1050 let params =
1050 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1051 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
1051 let ret = type_for_adt(db, def.into()); 1052 let ret = type_for_adt(db, def.into());
1052 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1053 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1053} 1054}
1054 1055
1055/// Build the type of a tuple struct constructor. 1056/// Build the type of a tuple struct constructor.
@@ -1073,7 +1074,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
1073 let params = 1074 let params =
1074 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1075 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
1075 let ret = type_for_adt(db, def.parent.into()); 1076 let ret = type_for_adt(db, def.parent.into());
1076 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1077 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1077} 1078}
1078 1079
1079/// Build the type of a tuple enum variant constructor. 1080/// Build the type of a tuple enum variant constructor.
@@ -1106,31 +1107,31 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
1106} 1107}
1107 1108
1108#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1109#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1109pub enum CallableDef { 1110pub enum CallableDefId {
1110 FunctionId(FunctionId), 1111 FunctionId(FunctionId),
1111 StructId(StructId), 1112 StructId(StructId),
1112 EnumVariantId(EnumVariantId), 1113 EnumVariantId(EnumVariantId),
1113} 1114}
1114impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId); 1115impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
1115 1116
1116impl CallableDef { 1117impl CallableDefId {
1117 pub fn krate(self, db: &dyn HirDatabase) -> CrateId { 1118 pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
1118 let db = db.upcast(); 1119 let db = db.upcast();
1119 match self { 1120 match self {
1120 CallableDef::FunctionId(f) => f.lookup(db).module(db), 1121 CallableDefId::FunctionId(f) => f.lookup(db).module(db),
1121 CallableDef::StructId(s) => s.lookup(db).container.module(db), 1122 CallableDefId::StructId(s) => s.lookup(db).container.module(db),
1122 CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db), 1123 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db),
1123 } 1124 }
1124 .krate 1125 .krate
1125 } 1126 }
1126} 1127}
1127 1128
1128impl From<CallableDef> for GenericDefId { 1129impl From<CallableDefId> for GenericDefId {
1129 fn from(def: CallableDef) -> GenericDefId { 1130 fn from(def: CallableDefId) -> GenericDefId {
1130 match def { 1131 match def {
1131 CallableDef::FunctionId(f) => f.into(), 1132 CallableDefId::FunctionId(f) => f.into(),
1132 CallableDef::StructId(s) => s.into(), 1133 CallableDefId::StructId(s) => s.into(),
1133 CallableDef::EnumVariantId(e) => e.into(), 1134 CallableDefId::EnumVariantId(e) => e.into(),
1134 } 1135 }
1135 } 1136 }
1136} 1137}
@@ -1141,7 +1142,7 @@ pub enum TyDefId {
1141 AdtId(AdtId), 1142 AdtId(AdtId),
1142 TypeAliasId(TypeAliasId), 1143 TypeAliasId(TypeAliasId),
1143} 1144}
1144impl_froms!(TyDefId: BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId); 1145impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId);
1145 1146
1146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1147pub enum ValueTyDefId { 1148pub enum ValueTyDefId {
@@ -1151,7 +1152,7 @@ pub enum ValueTyDefId {
1151 ConstId(ConstId), 1152 ConstId(ConstId),
1152 StaticId(StaticId), 1153 StaticId(StaticId),
1153} 1154}
1154impl_froms!(ValueTyDefId: FunctionId, StructId, EnumVariantId, ConstId, StaticId); 1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1155 1156
1156/// Build the declared type of an item. This depends on the namespace; e.g. for 1157/// Build the declared type of an item. This depends on the namespace; e.g. for
1157/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1216,7 +1217,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
1216} 1217}
1217 1218
1218pub(crate) fn return_type_impl_traits( 1219pub(crate) fn return_type_impl_traits(
1219 db: &impl HirDatabase, 1220 db: &dyn HirDatabase,
1220 def: hir_def::FunctionId, 1221 def: hir_def::FunctionId,
1221) -> Option<Arc<Binders<ReturnTypeImplTraits>>> { 1222) -> Option<Arc<Binders<ReturnTypeImplTraits>>> {
1222 // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe 1223 // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index c19519cf1..fb4b30a13 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -2,12 +2,14 @@
2//! For details about how this works in rustc, see the method lookup page in the 2//! For details about how this works in rustc, see the method lookup page in the
3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) 3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. 4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
5use std::sync::Arc; 5use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId, 9 builtin_type::{IntBitness, Signedness},
10 HasModule, ImplId, Lookup, TraitId, 10 lang_item::LangItemTarget,
11 type_ref::Mutability,
12 AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 13};
12use hir_expand::name::Name; 14use hir_expand::name::Name;
13use ra_db::CrateId; 15use ra_db::CrateId;
@@ -16,8 +18,12 @@ use rustc_hash::{FxHashMap, FxHashSet};
16 18
17use super::Substs; 19use super::Substs;
18use crate::{ 20use crate::{
19 autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, 21 autoderef,
20 Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 22 db::HirDatabase,
23 primitive::{FloatBitness, FloatTy, IntTy},
24 utils::all_super_traits,
25 ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind,
26 TypeCtor, TypeWalk,
21}; 27};
22 28
23/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
@@ -38,136 +44,187 @@ impl TyFingerprint {
38 } 44 }
39} 45}
40 46
41/// A queryable and mergeable collection of impls. 47pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
42#[derive(Debug, PartialEq, Eq)] 48 TyFingerprint::Apply(TypeCtor::Int(IntTy {
43pub struct CrateImplDefs { 49 signedness: Signedness::Unsigned,
44 inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 50 bitness: IntBitness::X8,
45 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, 51 })),
52 TyFingerprint::Apply(TypeCtor::Int(IntTy {
53 signedness: Signedness::Unsigned,
54 bitness: IntBitness::X16,
55 })),
56 TyFingerprint::Apply(TypeCtor::Int(IntTy {
57 signedness: Signedness::Unsigned,
58 bitness: IntBitness::X32,
59 })),
60 TyFingerprint::Apply(TypeCtor::Int(IntTy {
61 signedness: Signedness::Unsigned,
62 bitness: IntBitness::X64,
63 })),
64 TyFingerprint::Apply(TypeCtor::Int(IntTy {
65 signedness: Signedness::Unsigned,
66 bitness: IntBitness::X128,
67 })),
68 TyFingerprint::Apply(TypeCtor::Int(IntTy {
69 signedness: Signedness::Unsigned,
70 bitness: IntBitness::Xsize,
71 })),
72 TyFingerprint::Apply(TypeCtor::Int(IntTy {
73 signedness: Signedness::Signed,
74 bitness: IntBitness::X8,
75 })),
76 TyFingerprint::Apply(TypeCtor::Int(IntTy {
77 signedness: Signedness::Signed,
78 bitness: IntBitness::X16,
79 })),
80 TyFingerprint::Apply(TypeCtor::Int(IntTy {
81 signedness: Signedness::Signed,
82 bitness: IntBitness::X32,
83 })),
84 TyFingerprint::Apply(TypeCtor::Int(IntTy {
85 signedness: Signedness::Signed,
86 bitness: IntBitness::X64,
87 })),
88 TyFingerprint::Apply(TypeCtor::Int(IntTy {
89 signedness: Signedness::Signed,
90 bitness: IntBitness::X128,
91 })),
92 TyFingerprint::Apply(TypeCtor::Int(IntTy {
93 signedness: Signedness::Signed,
94 bitness: IntBitness::Xsize,
95 })),
96];
97
98pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
99 TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })),
100 TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })),
101];
102
103/// Trait impls defined or available in some crate.
104#[derive(Debug, Eq, PartialEq)]
105pub struct TraitImpls {
106 // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
107 map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
46} 108}
47 109
48impl CrateImplDefs { 110impl TraitImpls {
49 pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { 111 pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
50 let _p = profile("impls_in_crate_query"); 112 let _p = profile("trait_impls_in_crate_query");
51 let mut res = CrateImplDefs { 113 let mut impls = Self { map: FxHashMap::default() };
52 inherent_impls: FxHashMap::default(),
53 impls_by_trait: FxHashMap::default(),
54 };
55 res.fill(db, krate);
56 114
57 Arc::new(res) 115 let crate_def_map = db.crate_def_map(krate);
116 for (_module_id, module_data) in crate_def_map.modules.iter() {
117 for impl_id in module_data.scope.impls() {
118 let target_trait = match db.impl_trait(impl_id) {
119 Some(tr) => tr.value.trait_,
120 None => continue,
121 };
122 let self_ty = db.impl_self_ty(impl_id);
123 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
124 impls
125 .map
126 .entry(target_trait)
127 .or_default()
128 .entry(self_ty_fp)
129 .or_default()
130 .push(impl_id);
131 }
132 }
133
134 Arc::new(impls)
58 } 135 }
59 136
60 /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. 137 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
61 /// 138 let _p = profile("trait_impls_in_deps_query");
62 /// The full set of impls that can be used by `krate` is the returned map plus all the impls
63 /// from `krate` itself.
64 pub(crate) fn impls_from_deps_query(
65 db: &dyn HirDatabase,
66 krate: CrateId,
67 ) -> Arc<CrateImplDefs> {
68 let _p = profile("impls_from_deps_query");
69 let crate_graph = db.crate_graph(); 139 let crate_graph = db.crate_graph();
70 let mut res = CrateImplDefs { 140 let mut res = Self { map: FxHashMap::default() };
71 inherent_impls: FxHashMap::default(),
72 impls_by_trait: FxHashMap::default(),
73 };
74 141
75 // For each dependency, calculate `impls_from_deps` recursively, then add its own 142 for krate in crate_graph.transitive_deps(krate) {
76 // `impls_in_crate`. 143 res.merge(&db.trait_impls_in_crate(krate));
77 // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
78 // wasting memory.
79 for dep in &crate_graph[krate].dependencies {
80 res.merge(&db.impls_from_deps(dep.crate_id));
81 res.merge(&db.impls_in_crate(dep.crate_id));
82 } 144 }
83 145
84 Arc::new(res) 146 Arc::new(res)
85 } 147 }
86 148
87 fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
88 let crate_def_map = db.crate_def_map(krate);
89 for (_module_id, module_data) in crate_def_map.modules.iter() {
90 for impl_id in module_data.scope.impls() {
91 match db.impl_trait(impl_id) {
92 Some(tr) => {
93 let self_ty = db.impl_self_ty(impl_id);
94 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
95 self.impls_by_trait
96 .entry(tr.value.trait_)
97 .or_default()
98 .entry(self_ty_fp)
99 .or_default()
100 .push(impl_id);
101 }
102 None => {
103 let self_ty = db.impl_self_ty(impl_id);
104 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
105 self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
106 }
107 }
108 }
109 }
110 }
111 }
112
113 fn merge(&mut self, other: &Self) { 149 fn merge(&mut self, other: &Self) {
114 for (fp, impls) in &other.inherent_impls { 150 for (trait_, other_map) in &other.map {
115 let vec = self.inherent_impls.entry(*fp).or_default(); 151 let map = self.map.entry(*trait_).or_default();
116 vec.extend(impls);
117 vec.sort();
118 vec.dedup();
119 }
120
121 for (trait_, other_map) in &other.impls_by_trait {
122 let map = self.impls_by_trait.entry(*trait_).or_default();
123 for (fp, impls) in other_map { 152 for (fp, impls) in other_map {
124 let vec = map.entry(*fp).or_default(); 153 let vec = map.entry(*fp).or_default();
125 vec.extend(impls); 154 vec.extend(impls);
126 vec.sort();
127 vec.dedup();
128 } 155 }
129 } 156 }
130 } 157 }
131 158
132 pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { 159 /// Queries all impls of the given trait.
133 let fingerprint = TyFingerprint::for_impl(ty); 160 pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
134 fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() 161 self.map
135 } 162 .get(&trait_)
136
137 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
138 self.impls_by_trait
139 .get(&tr)
140 .into_iter() 163 .into_iter()
141 .flat_map(|m| m.values().flat_map(|v| v.iter().copied())) 164 .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
142 } 165 }
143 166
144 pub fn lookup_impl_defs_for_trait_and_ty( 167 /// Queries all impls of `trait_` that may apply to `self_ty`.
168 pub fn for_trait_and_self_ty(
145 &self, 169 &self,
146 tr: TraitId, 170 trait_: TraitId,
147 fp: TyFingerprint, 171 self_ty: TyFingerprint,
148 ) -> impl Iterator<Item = ImplId> + '_ { 172 ) -> impl Iterator<Item = ImplId> + '_ {
149 self.impls_by_trait 173 self.map
150 .get(&tr) 174 .get(&trait_)
151 .and_then(|m| m.get(&Some(fp)))
152 .into_iter() 175 .into_iter()
153 .flatten() 176 .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
154 .copied() 177 .flat_map(|v| v.iter().copied())
155 .chain( 178 }
156 self.impls_by_trait 179
157 .get(&tr) 180 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
158 .and_then(|m| m.get(&None)) 181 self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
159 .into_iter() 182 }
160 .flatten() 183}
161 .copied(), 184
162 ) 185/// Inherent impls defined in some crate.
186///
187/// Inherent impls can only be defined in the crate that also defines the self type of the impl
188/// (note that some primitives are considered to be defined by both libcore and liballoc).
189///
190/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
191/// single crate.
192#[derive(Debug, Eq, PartialEq)]
193pub struct InherentImpls {
194 map: FxHashMap<TyFingerprint, Vec<ImplId>>,
195}
196
197impl InherentImpls {
198 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
199 let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
200
201 let crate_def_map = db.crate_def_map(krate);
202 for (_module_id, module_data) in crate_def_map.modules.iter() {
203 for impl_id in module_data.scope.impls() {
204 let data = db.impl_data(impl_id);
205 if data.target_trait.is_some() {
206 continue;
207 }
208
209 let self_ty = db.impl_self_ty(impl_id);
210 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
211 map.entry(fp).or_default().push(impl_id);
212 }
213 }
214 }
215
216 Arc::new(Self { map })
217 }
218
219 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
220 match TyFingerprint::for_impl(self_ty) {
221 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
222 None => &[],
223 }
163 } 224 }
164 225
165 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 226 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
166 self.inherent_impls 227 self.map.values().flat_map(|v| v.iter().copied())
167 .values()
168 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
169 .flatten()
170 .copied()
171 } 228 }
172} 229}
173 230
@@ -377,7 +434,7 @@ fn iterate_method_candidates_with_autoref(
377 return true; 434 return true;
378 } 435 }
379 let refed = Canonical { 436 let refed = Canonical {
380 num_vars: deref_chain[0].num_vars, 437 kinds: deref_chain[0].kinds.clone(),
381 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), 438 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
382 }; 439 };
383 if iterate_method_candidates_by_receiver( 440 if iterate_method_candidates_by_receiver(
@@ -393,7 +450,7 @@ fn iterate_method_candidates_with_autoref(
393 return true; 450 return true;
394 } 451 }
395 let ref_muted = Canonical { 452 let ref_muted = Canonical {
396 num_vars: deref_chain[0].num_vars, 453 kinds: deref_chain[0].kinds.clone(),
397 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), 454 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
398 }; 455 };
399 if iterate_method_candidates_by_receiver( 456 if iterate_method_candidates_by_receiver(
@@ -524,9 +581,9 @@ fn iterate_inherent_methods(
524 None => return false, 581 None => return false,
525 }; 582 };
526 for krate in def_crates { 583 for krate in def_crates {
527 let impls = db.impls_in_crate(krate); 584 let impls = db.inherent_impls_in_crate(krate);
528 585
529 for impl_def in impls.lookup_impl_defs(&self_ty.value) { 586 for &impl_def in impls.for_self_ty(&self_ty.value) {
530 for &item in db.impl_data(impl_def).items.iter() { 587 for &item in db.impl_data(impl_def).items.iter() {
531 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { 588 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
532 continue; 589 continue;
@@ -612,18 +669,19 @@ pub(crate) fn inherent_impl_substs(
612 // we create a var for each type parameter of the impl; we need to keep in 669 // we create a var for each type parameter of the impl; we need to keep in
613 // mind here that `self_ty` might have vars of its own 670 // mind here that `self_ty` might have vars of its own
614 let vars = Substs::build_for_def(db, impl_id) 671 let vars = Substs::build_for_def(db, impl_id)
615 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars) 672 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len())
616 .build(); 673 .build();
617 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 674 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
618 let self_ty_with_vars = 675 let mut kinds = self_ty.kinds.to_vec();
619 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; 676 kinds.extend(iter::repeat(TyKind::General).take(vars.len()));
620 let substs = super::infer::unify(&self_ty_with_vars, self_ty); 677 let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) };
678 let substs = super::infer::unify(&tys);
621 // We only want the substs for the vars we added, not the ones from self_ty. 679 // We only want the substs for the vars we added, not the ones from self_ty.
622 // Also, if any of the vars we added are still in there, we replace them by 680 // Also, if any of the vars we added are still in there, we replace them by
623 // Unknown. I think this can only really happen if self_ty contained 681 // Unknown. I think this can only really happen if self_ty contained
624 // Unknown, and in that case we want the result to contain Unknown in those 682 // Unknown, and in that case we want the result to contain Unknown in those
625 // places again. 683 // places again.
626 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars)) 684 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
627} 685}
628 686
629/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 687/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@@ -683,15 +741,15 @@ fn generic_implements_goal(
683 trait_: TraitId, 741 trait_: TraitId,
684 self_ty: Canonical<Ty>, 742 self_ty: Canonical<Ty>,
685) -> Canonical<InEnvironment<super::Obligation>> { 743) -> Canonical<InEnvironment<super::Obligation>> {
686 let num_vars = self_ty.num_vars; 744 let mut kinds = self_ty.kinds.to_vec();
687 let substs = super::Substs::build_for_def(db, trait_) 745 let substs = super::Substs::build_for_def(db, trait_)
688 .push(self_ty.value) 746 .push(self_ty.value)
689 .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars) 747 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
690 .build(); 748 .build();
691 let num_vars = substs.len() - 1 + self_ty.num_vars; 749 kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1));
692 let trait_ref = TraitRef { trait_, substs }; 750 let trait_ref = TraitRef { trait_, substs };
693 let obligation = super::Obligation::Trait(trait_ref); 751 let obligation = super::Obligation::Trait(trait_ref);
694 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 752 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
695} 753}
696 754
697fn autoderef_method_receiver( 755fn autoderef_method_receiver(
@@ -704,9 +762,9 @@ fn autoderef_method_receiver(
704 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = 762 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
705 deref_chain.last().map(|ty| &ty.value) 763 deref_chain.last().map(|ty| &ty.value)
706 { 764 {
707 let num_vars = deref_chain.last().unwrap().num_vars; 765 let kinds = deref_chain.last().unwrap().kinds.clone();
708 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); 766 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
709 deref_chain.push(Canonical { value: unsized_ty, num_vars }) 767 deref_chain.push(Canonical { value: unsized_ty, kinds })
710 } 768 }
711 deref_chain 769 deref_chain
712} 770}
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 0481a7b12..a1714ff0f 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -1,20 +1,16 @@
1//! Database used for testing `hir`. 1//! Database used for testing `hir`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, ModuleId};
9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; 9use hir_expand::db::AstDatabase;
10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
11use rustc_hash::FxHashSet; 11use ra_syntax::TextRange;
12use stdx::format_to; 12use rustc_hash::{FxHashMap, FxHashSet};
13 13use test_utils::extract_annotations;
14use crate::{
15 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
16 unsafe_validation::UnsafeValidator,
17};
18 14
19#[salsa::database( 15#[salsa::database(
20 ra_db::SourceDatabaseExtStorage, 16 ra_db::SourceDatabaseExtStorage,
@@ -24,10 +20,15 @@ use crate::{
24 hir_def::db::DefDatabaseStorage, 20 hir_def::db::DefDatabaseStorage,
25 crate::db::HirDatabaseStorage 21 crate::db::HirDatabaseStorage
26)] 22)]
27#[derive(Debug, Default)] 23#[derive(Default)]
28pub struct TestDB { 24pub struct TestDB {
29 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 25 storage: salsa::Storage<TestDB>,
30 runtime: salsa::Runtime<TestDB>, 26 events: Mutex<Option<Vec<salsa::Event>>>,
27}
28impl fmt::Debug for TestDB {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("TestDB").finish()
31 }
31} 32}
32 33
33impl Upcast<dyn AstDatabase> for TestDB { 34impl Upcast<dyn AstDatabase> for TestDB {
@@ -43,18 +44,10 @@ impl Upcast<dyn DefDatabase> for TestDB {
43} 44}
44 45
45impl salsa::Database for TestDB { 46impl salsa::Database for TestDB {
46 fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { 47 fn salsa_event(&self, event: salsa::Event) {
47 &self.runtime
48 }
49
50 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
51 &mut self.runtime
52 }
53
54 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
55 let mut events = self.events.lock().unwrap(); 48 let mut events = self.events.lock().unwrap();
56 if let Some(events) = &mut *events { 49 if let Some(events) = &mut *events {
57 events.push(event()); 50 events.push(event);
58 } 51 }
59 } 52 }
60} 53}
@@ -62,8 +55,8 @@ impl salsa::Database for TestDB {
62impl salsa::ParallelDatabase for TestDB { 55impl salsa::ParallelDatabase for TestDB {
63 fn snapshot(&self) -> salsa::Snapshot<TestDB> { 56 fn snapshot(&self) -> salsa::Snapshot<TestDB> {
64 salsa::Snapshot::new(TestDB { 57 salsa::Snapshot::new(TestDB {
58 storage: self.storage.snapshot(),
65 events: Default::default(), 59 events: Default::default(),
66 runtime: self.runtime.snapshot(self),
67 }) 60 })
68 } 61 }
69} 62}
@@ -83,7 +76,7 @@ impl FileLoader for TestDB {
83} 76}
84 77
85impl TestDB { 78impl TestDB {
86 pub fn module_for_file(&self, file_id: FileId) -> ModuleId { 79 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
87 for &krate in self.relevant_crates(file_id).iter() { 80 for &krate in self.relevant_crates(file_id).iter() {
88 let crate_def_map = self.crate_def_map(krate); 81 let crate_def_map = self.crate_def_map(krate);
89 for (local_id, data) in crate_def_map.modules.iter() { 82 for (local_id, data) in crate_def_map.modules.iter() {
@@ -95,82 +88,32 @@ impl TestDB {
95 panic!("Can't find module for file") 88 panic!("Can't find module for file")
96 } 89 }
97 90
98 fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { 91 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
99 let crate_graph = self.crate_graph(); 92 let mut files = Vec::new();
100 for krate in crate_graph.iter() {
101 let crate_def_map = self.crate_def_map(krate);
102
103 let mut fns = Vec::new();
104 for (module_id, _) in crate_def_map.modules.iter() {
105 for decl in crate_def_map[module_id].scope.declarations() {
106 if let ModuleDefId::FunctionId(f) = decl {
107 fns.push(f)
108 }
109 }
110
111 for impl_id in crate_def_map[module_id].scope.impls() {
112 let impl_data = self.impl_data(impl_id);
113 for item in impl_data.items.iter() {
114 if let AssocItemId::FunctionId(f) = item {
115 fns.push(*f)
116 }
117 }
118 }
119 }
120
121 for f in fns {
122 let infer = self.infer(f.into());
123 let mut sink = DiagnosticSink::new(&mut cb);
124 infer.add_diagnostics(self, f, &mut sink);
125 let mut validator = ExprValidator::new(f, infer.clone(), &mut sink);
126 validator.validate_body(self);
127 let mut validator = UnsafeValidator::new(f, infer, &mut sink);
128 validator.validate_body(self);
129 }
130 }
131 }
132
133 pub fn diagnostics(&self) -> (String, u32) {
134 let mut buf = String::new();
135 let mut count = 0;
136 self.diag(|d| {
137 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
138 count += 1;
139 });
140 (buf, count)
141 }
142
143 /// Like `diagnostics`, but filtered for a single diagnostic.
144 pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) {
145 let mut buf = String::new();
146 let mut count = 0;
147 self.diag(|d| {
148 // We want to filter diagnostics by the particular one we are testing for, to
149 // avoid surprising results in tests.
150 if d.downcast_ref::<D>().is_some() {
151 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
152 count += 1;
153 };
154 });
155 (buf, count)
156 }
157
158 pub fn all_files(&self) -> Vec<FileId> {
159 let mut res = Vec::new();
160 let crate_graph = self.crate_graph(); 93 let crate_graph = self.crate_graph();
161 for krate in crate_graph.iter() { 94 for krate in crate_graph.iter() {
162 let crate_def_map = self.crate_def_map(krate); 95 let crate_def_map = self.crate_def_map(krate);
163 for (module_id, _) in crate_def_map.modules.iter() { 96 for (module_id, _) in crate_def_map.modules.iter() {
164 let file_id = crate_def_map[module_id].origin.file_id(); 97 let file_id = crate_def_map[module_id].origin.file_id();
165 res.extend(file_id) 98 files.extend(file_id)
166 } 99 }
167 } 100 }
168 res 101 files
102 .into_iter()
103 .filter_map(|file_id| {
104 let text = self.file_text(file_id);
105 let annotations = extract_annotations(&text);
106 if annotations.is_empty() {
107 return None;
108 }
109 Some((file_id, annotations))
110 })
111 .collect()
169 } 112 }
170} 113}
171 114
172impl TestDB { 115impl TestDB {
173 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { 116 pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
174 *self.events.lock().unwrap() = Some(Vec::new()); 117 *self.events.lock().unwrap() = Some(Vec::new());
175 f(); 118 f();
176 self.events.lock().unwrap().take().unwrap() 119 self.events.lock().unwrap().take().unwrap()
@@ -184,7 +127,7 @@ impl TestDB {
184 // This pretty horrible, but `Debug` is the only way to inspect 127 // This pretty horrible, but `Debug` is the only way to inspect
185 // QueryDescriptor at the moment. 128 // QueryDescriptor at the moment.
186 salsa::EventKind::WillExecute { database_key } => { 129 salsa::EventKind::WillExecute { database_key } => {
187 Some(format!("{:?}", database_key)) 130 Some(format!("{:?}", database_key.debug(self)))
188 } 131 }
189 _ => None, 132 _ => None,
190 }) 133 })
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 5424e6bb1..016e689ff 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -10,6 +10,7 @@ mod display_source_code;
10 10
11use std::sync::Arc; 11use std::sync::Arc;
12 12
13use expect::Expect;
13use hir_def::{ 14use hir_def::{
14 body::{BodySourceMap, SyntheticSyntax}, 15 body::{BodySourceMap, SyntheticSyntax},
15 child_by_source::ChildBySource, 16 child_by_source::ChildBySource,
@@ -20,23 +21,34 @@ use hir_def::{
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 21 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 22};
22use hir_expand::{db::AstDatabase, InFile}; 23use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot; 24use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
24use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
25use ra_syntax::{ 25use ra_syntax::{
26 algo, 26 algo,
27 ast::{self, AstNode}, 27 ast::{self, AstNode},
28 SyntaxNode, 28 SyntaxNode,
29}; 29};
30use stdx::format_to; 30use stdx::format_to;
31use test_utils::extract_annotations;
32 31
33use crate::{ 32use crate::{
34 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, 33 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
35}; 34};
36 35
37// These tests compare the inference results for all expressions in a file 36// These tests compare the inference results for all expressions in a file
38// against snapshots of the expected results using insta. Use cargo-insta to 37// against snapshots of the expected results using expect. Use
39// update the snapshots. 38// `env UPDATE_EXPECT=1 cargo test -p ra_hir_ty` to update the snapshots.
39
40fn setup_tracing() -> tracing::subscriber::DefaultGuard {
41 use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
42 use tracing_tree::HierarchicalLayer;
43 let filter = EnvFilter::from_env("CHALK_DEBUG");
44 let layer = HierarchicalLayer::default()
45 .with_indent_lines(true)
46 .with_ansi(false)
47 .with_indent_amount(2)
48 .with_writer(std::io::stderr);
49 let subscriber = Registry::default().with(filter).with(layer);
50 tracing::subscriber::set_default(subscriber)
51}
40 52
41fn check_types(ra_fixture: &str) { 53fn check_types(ra_fixture: &str) {
42 check_types_impl(ra_fixture, false) 54 check_types_impl(ra_fixture, false)
@@ -47,11 +59,10 @@ fn check_types_source_code(ra_fixture: &str) {
47} 59}
48 60
49fn check_types_impl(ra_fixture: &str, display_source: bool) { 61fn check_types_impl(ra_fixture: &str, display_source: bool) {
62 let _tracing = setup_tracing();
50 let db = TestDB::with_files(ra_fixture); 63 let db = TestDB::with_files(ra_fixture);
51 let mut checked_one = false; 64 let mut checked_one = false;
52 for file_id in db.all_files() { 65 for (file_id, annotations) in db.extract_annotations() {
53 let text = db.parse(file_id).syntax_node().to_string();
54 let annotations = extract_annotations(&text);
55 for (range, expected) in annotations { 66 for (range, expected) in annotations {
56 let ty = type_at_range(&db, FileRange { file_id, range }); 67 let ty = type_at_range(&db, FileRange { file_id, range });
57 let actual = if display_source { 68 let actual = if display_source {
@@ -70,7 +81,7 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
70fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 81fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
71 let file = db.parse(pos.file_id).ok().unwrap(); 82 let file = db.parse(pos.file_id).ok().unwrap();
72 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 83 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
73 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 84 let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap();
74 let module = db.module_for_file(pos.file_id); 85 let module = db.module_for_file(pos.file_id);
75 let func = *module.child_by_source(db)[keys::FUNCTION] 86 let func = *module.child_by_source(db)[keys::FUNCTION]
76 .get(&InFile::new(pos.file_id.into(), fn_def)) 87 .get(&InFile::new(pos.file_id.into(), fn_def))
@@ -89,6 +100,7 @@ fn infer(ra_fixture: &str) -> String {
89} 100}
90 101
91fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { 102fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
103 let _tracing = setup_tracing();
92 let (db, file_id) = TestDB::with_single_file(content); 104 let (db, file_id) = TestDB::with_single_file(content);
93 105
94 let mut buf = String::new(); 106 let mut buf = String::new();
@@ -320,7 +332,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
320 " 332 "
321 .to_string(); 333 .to_string();
322 334
323 db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); 335 db.set_file_text(pos.file_id, Arc::new(new_text));
324 336
325 { 337 {
326 let events = db.log_executed(|| { 338 let events = db.log_executed(|| {
@@ -334,385 +346,14 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
334 } 346 }
335} 347}
336 348
337#[test] 349fn check_infer(ra_fixture: &str, expect: Expect) {
338fn no_such_field_diagnostics() { 350 let mut actual = infer(ra_fixture);
339 let diagnostics = TestDB::with_files( 351 actual.push('\n');
340 r" 352 expect.assert_eq(&actual);
341 //- /lib.rs
342 struct S { foo: i32, bar: () }
343 impl S {
344 fn new() -> S {
345 S {
346 foo: 92,
347 baz: 62,
348 }
349 }
350 }
351 ",
352 )
353 .diagnostics()
354 .0;
355
356 assert_snapshot!(diagnostics, @r###"
357 "baz: 62": no such field
358 "{\n foo: 92,\n baz: 62,\n }": Missing structure fields:
359 - bar
360 "###
361 );
362}
363
364#[test]
365fn no_such_field_with_feature_flag_diagnostics() {
366 let diagnostics = TestDB::with_files(
367 r#"
368 //- /lib.rs crate:foo cfg:feature=foo
369 struct MyStruct {
370 my_val: usize,
371 #[cfg(feature = "foo")]
372 bar: bool,
373 }
374
375 impl MyStruct {
376 #[cfg(feature = "foo")]
377 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
378 Self { my_val, bar }
379 }
380
381 #[cfg(not(feature = "foo"))]
382 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
383 Self { my_val }
384 }
385 }
386 "#,
387 )
388 .diagnostics()
389 .0;
390
391 assert_snapshot!(diagnostics, @r###""###);
392}
393
394#[test]
395fn no_such_field_enum_with_feature_flag_diagnostics() {
396 let diagnostics = TestDB::with_files(
397 r#"
398 //- /lib.rs crate:foo cfg:feature=foo
399 enum Foo {
400 #[cfg(not(feature = "foo"))]
401 Buz,
402 #[cfg(feature = "foo")]
403 Bar,
404 Baz
405 }
406
407 fn test_fn(f: Foo) {
408 match f {
409 Foo::Bar => {},
410 Foo::Baz => {},
411 }
412 }
413 "#,
414 )
415 .diagnostics()
416 .0;
417
418 assert_snapshot!(diagnostics, @r###""###);
419}
420
421#[test]
422fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
423 let diagnostics = TestDB::with_files(
424 r#"
425 //- /lib.rs crate:foo cfg:feature=foo
426 struct S {
427 #[cfg(feature = "foo")]
428 foo: u32,
429 #[cfg(not(feature = "foo"))]
430 bar: u32,
431 }
432
433 impl S {
434 #[cfg(feature = "foo")]
435 fn new(foo: u32) -> Self {
436 Self { foo }
437 }
438 #[cfg(not(feature = "foo"))]
439 fn new(bar: u32) -> Self {
440 Self { bar }
441 }
442 }
443 "#,
444 )
445 .diagnostics()
446 .0;
447
448 assert_snapshot!(diagnostics, @r###""###);
449}
450
451#[test]
452fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
453 let diagnostics = TestDB::with_files(
454 r#"
455 //- /lib.rs crate:foo cfg:feature=foo
456 struct S {
457 #[cfg(feature = "foo")]
458 foo: u32,
459 #[cfg(not(feature = "foo"))]
460 bar: u32,
461 }
462
463 impl S {
464 fn new(bar: u32) -> Self {
465 #[cfg(feature = "foo")]
466 {
467 Self { foo: bar }
468 }
469 #[cfg(not(feature = "foo"))]
470 {
471 Self { bar }
472 }
473 }
474 }
475 "#,
476 )
477 .diagnostics()
478 .0;
479
480 assert_snapshot!(diagnostics, @r###""###);
481}
482
483#[test]
484fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
485 let diagnostics = TestDB::with_files(
486 r#"
487 //- /lib.rs crate:foo cfg:feature=foo
488 struct S {
489 #[cfg(feature = "foo")]
490 foo: u32,
491 #[cfg(not(feature = "foo"))]
492 bar: u32,
493 }
494
495 impl S {
496 fn new(val: u32) -> Self {
497 Self {
498 #[cfg(feature = "foo")]
499 foo: val,
500 #[cfg(not(feature = "foo"))]
501 bar: val,
502 }
503 }
504 }
505 "#,
506 )
507 .diagnostics()
508 .0;
509
510 assert_snapshot!(diagnostics, @r###""###);
511}
512
513#[test]
514fn missing_record_pat_field_diagnostic() {
515 let diagnostics = TestDB::with_files(
516 r"
517 //- /lib.rs
518 struct S { foo: i32, bar: () }
519 fn baz(s: S) {
520 let S { foo: _ } = s;
521 }
522 ",
523 )
524 .diagnostics()
525 .0;
526
527 assert_snapshot!(diagnostics, @r###"
528 "{ foo: _ }": Missing structure fields:
529 - bar
530 "###
531 );
532}
533
534#[test]
535fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
536 let diagnostics = TestDB::with_files(
537 r"
538 //- /lib.rs
539 struct S { foo: i32, bar: () }
540 fn baz(s: S) -> i32 {
541 match s {
542 S { foo, .. } => foo,
543 }
544 }
545 ",
546 )
547 .diagnostics()
548 .0;
549
550 assert_snapshot!(diagnostics, @"");
551}
552
553#[test]
554fn missing_unsafe_diagnostic_with_raw_ptr() {
555 let diagnostics = TestDB::with_files(
556 r"
557//- /lib.rs
558fn missing_unsafe() {
559 let x = &5 as *const usize;
560 let y = *x;
561}
562",
563 )
564 .diagnostics()
565 .0;
566
567 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
568}
569
570#[test]
571fn missing_unsafe_diagnostic_with_unsafe_call() {
572 let diagnostics = TestDB::with_files(
573 r"
574//- /lib.rs
575unsafe fn unsafe_fn() {
576 let x = &5 as *const usize;
577 let y = *x;
578}
579
580fn missing_unsafe() {
581 unsafe_fn();
582}
583",
584 )
585 .diagnostics()
586 .0;
587
588 assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
589}
590
591#[test]
592fn missing_unsafe_diagnostic_with_unsafe_method_call() {
593 let diagnostics = TestDB::with_files(
594 r"
595struct HasUnsafe;
596
597impl HasUnsafe {
598 unsafe fn unsafe_fn(&self) {
599 let x = &5 as *const usize;
600 let y = *x;
601 }
602}
603
604fn missing_unsafe() {
605 HasUnsafe.unsafe_fn();
606} 353}
607 354
608", 355fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) {
609 ) 356 let mut actual = infer_with_mismatches(ra_fixture, true);
610 .diagnostics() 357 actual.push('\n');
611 .0; 358 expect.assert_eq(&actual);
612
613 assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
614}
615
616#[test]
617fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
618 let diagnostics = TestDB::with_files(
619 r"
620fn nothing_to_see_move_along() {
621 let x = &5 as *const usize;
622 unsafe {
623 let y = *x;
624 }
625}
626",
627 )
628 .diagnostics()
629 .0;
630
631 assert_snapshot!(diagnostics, @"");
632}
633
634#[test]
635fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
636 let diagnostics = TestDB::with_files(
637 r"
638fn nothing_to_see_move_along() {
639 let x = &5 as *const usize;
640 unsafe {
641 let y = *x;
642 }
643 let z = *x;
644}
645",
646 )
647 .diagnostics()
648 .0;
649
650 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
651}
652
653#[test]
654fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
655 let diagnostics = TestDB::with_files(
656 r"
657unsafe fn unsafe_fn() {
658 let x = &5 as *const usize;
659 let y = *x;
660}
661
662fn nothing_to_see_move_along() {
663 unsafe {
664 unsafe_fn();
665 }
666}
667",
668 )
669 .diagnostics()
670 .0;
671
672 assert_snapshot!(diagnostics, @"");
673}
674
675#[test]
676fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
677 let diagnostics = TestDB::with_files(
678 r"
679struct HasUnsafe;
680
681impl HasUnsafe {
682 unsafe fn unsafe_fn() {
683 let x = &5 as *const usize;
684 let y = *x;
685 }
686}
687
688fn nothing_to_see_move_along() {
689 unsafe {
690 HasUnsafe.unsafe_fn();
691 }
692}
693
694",
695 )
696 .diagnostics()
697 .0;
698
699 assert_snapshot!(diagnostics, @"");
700}
701
702#[test]
703fn break_outside_of_loop() {
704 let diagnostics = TestDB::with_files(
705 r"
706 //- /lib.rs
707 fn foo() {
708 break;
709 }
710 ",
711 )
712 .diagnostics()
713 .0;
714
715 assert_snapshot!(diagnostics, @r###""break": break outside of loop
716 "###
717 );
718} 359}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 136d28a91..17efd75cb 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,345 +1,381 @@
1use insta::assert_snapshot; 1use expect::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::infer_with_mismatches; 4use super::{check_infer, check_infer_with_mismatches};
5
6// Infer with some common definitions and impls.
7fn infer(source: &str) -> String {
8 let defs = r#"
9 #[lang = "sized"]
10 pub trait Sized {}
11 #[lang = "unsize"]
12 pub trait Unsize<T: ?Sized> {}
13 #[lang = "coerce_unsized"]
14 pub trait CoerceUnsized<T> {}
15
16 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
17 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
18 "#;
19
20 // Append to the end to keep positions unchanged.
21 super::infer(&format!("{}{}", source, defs))
22}
23 5
24#[test] 6#[test]
25fn infer_block_expr_type_mismatch() { 7fn infer_block_expr_type_mismatch() {
26 assert_snapshot!( 8 check_infer(
27 infer(r#" 9 r"
28fn test() { 10 fn test() {
29 let a: i32 = { 1i64 }; 11 let a: i32 = { 1i64 };
30} 12 }
31"#), 13 ",
32 @r###" 14 expect![[r"
33 10..40 '{ ...4 }; }': () 15 10..40 '{ ...4 }; }': ()
34 20..21 'a': i32 16 20..21 'a': i32
35 29..37 '{ 1i64 }': i64 17 29..37 '{ 1i64 }': i64
36 31..35 '1i64': i64 18 31..35 '1i64': i64
37 "###); 19 "]],
20 );
38} 21}
39 22
40#[test] 23#[test]
41fn coerce_places() { 24fn coerce_places() {
42 assert_snapshot!( 25 check_infer(
43 infer(r#" 26 r#"
44struct S<T> { a: T } 27 struct S<T> { a: T }
45 28
46fn f<T>(_: &[T]) -> T { loop {} } 29 fn f<T>(_: &[T]) -> T { loop {} }
47fn g<T>(_: S<&[T]>) -> T { loop {} } 30 fn g<T>(_: S<&[T]>) -> T { loop {} }
48 31
49fn gen<T>() -> *mut [T; 2] { loop {} } 32 fn gen<T>() -> *mut [T; 2] { loop {} }
50fn test1<U>() -> *mut [U] { 33 fn test1<U>() -> *mut [U] {
51 gen() 34 gen()
52} 35 }
53 36
54fn test2() { 37 fn test2() {
55 let arr: &[u8; 1] = &[1]; 38 let arr: &[u8; 1] = &[1];
56 39
57 let a: &[_] = arr; 40 let a: &[_] = arr;
58 let b = f(arr); 41 let b = f(arr);
59 let c: &[_] = { arr }; 42 let c: &[_] = { arr };
60 let d = g(S { a: arr }); 43 let d = g(S { a: arr });
61 let e: [&[_]; 1] = [arr]; 44 let e: [&[_]; 1] = [arr];
62 let f: [&[_]; 2] = [arr; 2]; 45 let f: [&[_]; 2] = [arr; 2];
63 let g: (&[_], &[_]) = (arr, arr); 46 let g: (&[_], &[_]) = (arr, arr);
64} 47 }
65"#), 48
66 @r###" 49 #[lang = "sized"]
67 30..31 '_': &[T] 50 pub trait Sized {}
68 44..55 '{ loop {} }': T 51 #[lang = "unsize"]
69 46..53 'loop {}': ! 52 pub trait Unsize<T: ?Sized> {}
70 51..53 '{}': () 53 #[lang = "coerce_unsized"]
71 64..65 '_': S<&[T]> 54 pub trait CoerceUnsized<T> {}
72 81..92 '{ loop {} }': T 55
73 83..90 'loop {}': ! 56 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
74 88..90 '{}': () 57 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
75 121..132 '{ loop {} }': *mut [T; _] 58 "#,
76 123..130 'loop {}': ! 59 expect![[r"
77 128..130 '{}': () 60 30..31 '_': &[T]
78 159..172 '{ gen() }': *mut [U] 61 44..55 '{ loop {} }': T
79 165..168 'gen': fn gen<U>() -> *mut [U; _] 62 46..53 'loop {}': !
80 165..170 'gen()': *mut [U; _] 63 51..53 '{}': ()
81 185..419 '{ ...rr); }': () 64 64..65 '_': S<&[T]>
82 195..198 'arr': &[u8; _] 65 81..92 '{ loop {} }': T
83 211..215 '&[1]': &[u8; _] 66 83..90 'loop {}': !
84 212..215 '[1]': [u8; _] 67 88..90 '{}': ()
85 213..214 '1': u8 68 121..132 '{ loop {} }': *mut [T; _]
86 226..227 'a': &[u8] 69 123..130 'loop {}': !
87 236..239 'arr': &[u8; _] 70 128..130 '{}': ()
88 249..250 'b': u8 71 159..172 '{ gen() }': *mut [U]
89 253..254 'f': fn f<u8>(&[u8]) -> u8 72 165..168 'gen': fn gen<U>() -> *mut [U; _]
90 253..259 'f(arr)': u8 73 165..170 'gen()': *mut [U; _]
91 255..258 'arr': &[u8; _] 74 185..419 '{ ...rr); }': ()
92 269..270 'c': &[u8] 75 195..198 'arr': &[u8; _]
93 279..286 '{ arr }': &[u8] 76 211..215 '&[1]': &[u8; _]
94 281..284 'arr': &[u8; _] 77 212..215 '[1]': [u8; _]
95 296..297 'd': u8 78 213..214 '1': u8
96 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 79 226..227 'a': &[u8]
97 300..315 'g(S { a: arr })': u8 80 236..239 'arr': &[u8; _]
98 302..314 'S { a: arr }': S<&[u8]> 81 249..250 'b': u8
99 309..312 'arr': &[u8; _] 82 253..254 'f': fn f<u8>(&[u8]) -> u8
100 325..326 'e': [&[u8]; _] 83 253..259 'f(arr)': u8
101 340..345 '[arr]': [&[u8]; _] 84 255..258 'arr': &[u8; _]
102 341..344 'arr': &[u8; _] 85 269..270 'c': &[u8]
103 355..356 'f': [&[u8]; _] 86 279..286 '{ arr }': &[u8]
104 370..378 '[arr; 2]': [&[u8]; _] 87 281..284 'arr': &[u8; _]
105 371..374 'arr': &[u8; _] 88 296..297 'd': u8
106 376..377 '2': usize 89 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
107 388..389 'g': (&[u8], &[u8]) 90 300..315 'g(S { a: arr })': u8
108 406..416 '(arr, arr)': (&[u8], &[u8]) 91 302..314 'S { a: arr }': S<&[u8]>
109 407..410 'arr': &[u8; _] 92 309..312 'arr': &[u8; _]
110 412..415 'arr': &[u8; _] 93 325..326 'e': [&[u8]; _]
111 "### 94 340..345 '[arr]': [&[u8]; _]
95 341..344 'arr': &[u8; _]
96 355..356 'f': [&[u8]; _]
97 370..378 '[arr; 2]': [&[u8]; _]
98 371..374 'arr': &[u8; _]
99 376..377 '2': usize
100 388..389 'g': (&[u8], &[u8])
101 406..416 '(arr, arr)': (&[u8], &[u8])
102 407..410 'arr': &[u8; _]
103 412..415 'arr': &[u8; _]
104 "]],
112 ); 105 );
113} 106}
114 107
115#[test] 108#[test]
116fn infer_let_stmt_coerce() { 109fn infer_let_stmt_coerce() {
117 assert_snapshot!( 110 check_infer(
118 infer(r#" 111 r"
119fn test() { 112 fn test() {
120 let x: &[isize] = &[1]; 113 let x: &[isize] = &[1];
121 let x: *const [isize] = &[1]; 114 let x: *const [isize] = &[1];
122} 115 }
123"#), 116 ",
124 @r###" 117 expect![[r"
125 10..75 '{ ...[1]; }': () 118 10..75 '{ ...[1]; }': ()
126 20..21 'x': &[isize] 119 20..21 'x': &[isize]
127 34..38 '&[1]': &[isize; _] 120 34..38 '&[1]': &[isize; _]
128 35..38 '[1]': [isize; _] 121 35..38 '[1]': [isize; _]
129 36..37 '1': isize 122 36..37 '1': isize
130 48..49 'x': *const [isize] 123 48..49 'x': *const [isize]
131 68..72 '&[1]': &[isize; _] 124 68..72 '&[1]': &[isize; _]
132 69..72 '[1]': [isize; _] 125 69..72 '[1]': [isize; _]
133 70..71 '1': isize 126 70..71 '1': isize
134 "###); 127 "]],
128 );
135} 129}
136 130
137#[test] 131#[test]
138fn infer_custom_coerce_unsized() { 132fn infer_custom_coerce_unsized() {
139 assert_snapshot!( 133 check_infer(
140 infer(r#" 134 r#"
141struct A<T: ?Sized>(*const T); 135 struct A<T: ?Sized>(*const T);
142struct B<T: ?Sized>(*const T); 136 struct B<T: ?Sized>(*const T);
143struct C<T: ?Sized> { inner: *const T } 137 struct C<T: ?Sized> { inner: *const T }
144 138
145impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} 139 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {}
146impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} 140 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {}
147 141
148fn foo1<T>(x: A<[T]>) -> A<[T]> { x } 142 fn foo1<T>(x: A<[T]>) -> A<[T]> { x }
149fn foo2<T>(x: B<[T]>) -> B<[T]> { x } 143 fn foo2<T>(x: B<[T]>) -> B<[T]> { x }
150fn foo3<T>(x: C<[T]>) -> C<[T]> { x } 144 fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
151 145
152fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { 146 fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
153 let d = foo1(a); 147 let d = foo1(a);
154 let e = foo2(b); 148 let e = foo2(b);
155 let f = foo3(c); 149 let f = foo3(c);
156} 150 }
157"#), 151
158 @r###" 152
159 257..258 'x': A<[T]> 153 #[lang = "sized"]
160 278..283 '{ x }': A<[T]> 154 pub trait Sized {}
161 280..281 'x': A<[T]> 155 #[lang = "unsize"]
162 295..296 'x': B<[T]> 156 pub trait Unsize<T: ?Sized> {}
163 316..321 '{ x }': B<[T]> 157 #[lang = "coerce_unsized"]
164 318..319 'x': B<[T]> 158 pub trait CoerceUnsized<T> {}
165 333..334 'x': C<[T]> 159
166 354..359 '{ x }': C<[T]> 160 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
167 356..357 'x': C<[T]> 161 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
168 369..370 'a': A<[u8; _]> 162 "#,
169 384..385 'b': B<[u8; _]> 163 expect![[r"
170 399..400 'c': C<[u8; _]> 164 257..258 'x': A<[T]>
171 414..480 '{ ...(c); }': () 165 278..283 '{ x }': A<[T]>
172 424..425 'd': A<[{unknown}]> 166 280..281 'x': A<[T]>
173 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 167 295..296 'x': B<[T]>
174 428..435 'foo1(a)': A<[{unknown}]> 168 316..321 '{ x }': B<[T]>
175 433..434 'a': A<[u8; _]> 169 318..319 'x': B<[T]>
176 445..446 'e': B<[u8]> 170 333..334 'x': C<[T]>
177 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> 171 354..359 '{ x }': C<[T]>
178 449..456 'foo2(b)': B<[u8]> 172 356..357 'x': C<[T]>
179 454..455 'b': B<[u8; _]> 173 369..370 'a': A<[u8; _]>
180 466..467 'f': C<[u8]> 174 384..385 'b': B<[u8; _]>
181 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> 175 399..400 'c': C<[u8; _]>
182 470..477 'foo3(c)': C<[u8]> 176 414..480 '{ ...(c); }': ()
183 475..476 'c': C<[u8; _]> 177 424..425 'd': A<[{unknown}]>
184 "### 178 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
179 428..435 'foo1(a)': A<[{unknown}]>
180 433..434 'a': A<[u8; _]>
181 445..446 'e': B<[u8]>
182 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
183 449..456 'foo2(b)': B<[u8]>
184 454..455 'b': B<[u8; _]>
185 466..467 'f': C<[u8]>
186 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
187 470..477 'foo3(c)': C<[u8]>
188 475..476 'c': C<[u8; _]>
189 "]],
185 ); 190 );
186} 191}
187 192
188#[test] 193#[test]
189fn infer_if_coerce() { 194fn infer_if_coerce() {
190 assert_snapshot!( 195 check_infer(
191 infer(r#" 196 r#"
192fn foo<T>(x: &[T]) -> &[T] { loop {} } 197 fn foo<T>(x: &[T]) -> &[T] { loop {} }
193fn test() { 198 fn test() {
194 let x = if true { 199 let x = if true {
195 foo(&[1]) 200 foo(&[1])
196 } else { 201 } else {
197 &[1] 202 &[1]
198 }; 203 };
199} 204 }
200"#), 205
201 @r###" 206
202 10..11 'x': &[T] 207 #[lang = "sized"]
203 27..38 '{ loop {} }': &[T] 208 pub trait Sized {}
204 29..36 'loop {}': ! 209 #[lang = "unsize"]
205 34..36 '{}': () 210 pub trait Unsize<T: ?Sized> {}
206 49..125 '{ ... }; }': () 211 "#,
207 59..60 'x': &[i32] 212 expect![[r"
208 63..122 'if tru... }': &[i32] 213 10..11 'x': &[T]
209 66..70 'true': bool 214 27..38 '{ loop {} }': &[T]
210 71..96 '{ ... }': &[i32] 215 29..36 'loop {}': !
211 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] 216 34..36 '{}': ()
212 81..90 'foo(&[1])': &[i32] 217 49..125 '{ ... }; }': ()
213 85..89 '&[1]': &[i32; _] 218 59..60 'x': &[i32]
214 86..89 '[1]': [i32; _] 219 63..122 'if tru... }': &[i32]
215 87..88 '1': i32 220 66..70 'true': bool
216 102..122 '{ ... }': &[i32; _] 221 71..96 '{ ... }': &[i32]
217 112..116 '&[1]': &[i32; _] 222 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
218 113..116 '[1]': [i32; _] 223 81..90 'foo(&[1])': &[i32]
219 114..115 '1': i32 224 85..89 '&[1]': &[i32; _]
220 "### 225 86..89 '[1]': [i32; _]
226 87..88 '1': i32
227 102..122 '{ ... }': &[i32; _]
228 112..116 '&[1]': &[i32; _]
229 113..116 '[1]': [i32; _]
230 114..115 '1': i32
231 "]],
221 ); 232 );
222} 233}
223 234
224#[test] 235#[test]
225fn infer_if_else_coerce() { 236fn infer_if_else_coerce() {
226 assert_snapshot!( 237 check_infer(
227 infer(r#" 238 r#"
228fn foo<T>(x: &[T]) -> &[T] { loop {} } 239 fn foo<T>(x: &[T]) -> &[T] { loop {} }
229fn test() { 240 fn test() {
230 let x = if true { 241 let x = if true {
231 &[1] 242 &[1]
232 } else { 243 } else {
233 foo(&[1]) 244 foo(&[1])
234 }; 245 };
235} 246 }
236"#), 247
237 @r###" 248 #[lang = "sized"]
238 10..11 'x': &[T] 249 pub trait Sized {}
239 27..38 '{ loop {} }': &[T] 250 #[lang = "unsize"]
240 29..36 'loop {}': ! 251 pub trait Unsize<T: ?Sized> {}
241 34..36 '{}': () 252 #[lang = "coerce_unsized"]
242 49..125 '{ ... }; }': () 253 pub trait CoerceUnsized<T> {}
243 59..60 'x': &[i32] 254
244 63..122 'if tru... }': &[i32] 255 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
245 66..70 'true': bool 256 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
246 71..91 '{ ... }': &[i32; _] 257 "#,
247 81..85 '&[1]': &[i32; _] 258 expect![[r"
248 82..85 '[1]': [i32; _] 259 10..11 'x': &[T]
249 83..84 '1': i32 260 27..38 '{ loop {} }': &[T]
250 97..122 '{ ... }': &[i32] 261 29..36 'loop {}': !
251 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] 262 34..36 '{}': ()
252 107..116 'foo(&[1])': &[i32] 263 49..125 '{ ... }; }': ()
253 111..115 '&[1]': &[i32; _] 264 59..60 'x': &[i32]
254 112..115 '[1]': [i32; _] 265 63..122 'if tru... }': &[i32]
255 113..114 '1': i32 266 66..70 'true': bool
256 "### 267 71..91 '{ ... }': &[i32; _]
257 ); 268 81..85 '&[1]': &[i32; _]
269 82..85 '[1]': [i32; _]
270 83..84 '1': i32
271 97..122 '{ ... }': &[i32]
272 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
273 107..116 'foo(&[1])': &[i32]
274 111..115 '&[1]': &[i32; _]
275 112..115 '[1]': [i32; _]
276 113..114 '1': i32
277 "]],
278 )
258} 279}
259 280
260#[test] 281#[test]
261fn infer_match_first_coerce() { 282fn infer_match_first_coerce() {
262 assert_snapshot!( 283 check_infer(
263 infer(r#" 284 r#"
264fn foo<T>(x: &[T]) -> &[T] { loop {} } 285 fn foo<T>(x: &[T]) -> &[T] { loop {} }
265fn test(i: i32) { 286 fn test(i: i32) {
266 let x = match i { 287 let x = match i {
267 2 => foo(&[2]), 288 2 => foo(&[2]),
268 1 => &[1], 289 1 => &[1],
269 _ => &[3], 290 _ => &[3],
270 }; 291 };
271} 292 }
272"#), 293
273 @r###" 294 #[lang = "sized"]
274 10..11 'x': &[T] 295 pub trait Sized {}
275 27..38 '{ loop {} }': &[T] 296 #[lang = "unsize"]
276 29..36 'loop {}': ! 297 pub trait Unsize<T: ?Sized> {}
277 34..36 '{}': () 298 "#,
278 47..48 'i': i32 299 expect![[r"
279 55..149 '{ ... }; }': () 300 10..11 'x': &[T]
280 65..66 'x': &[i32] 301 27..38 '{ loop {} }': &[T]
281 69..146 'match ... }': &[i32] 302 29..36 'loop {}': !
282 75..76 'i': i32 303 34..36 '{}': ()
283 87..88 '2': i32 304 47..48 'i': i32
284 87..88 '2': i32 305 55..149 '{ ... }; }': ()
285 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] 306 65..66 'x': &[i32]
286 92..101 'foo(&[2])': &[i32] 307 69..146 'match ... }': &[i32]
287 96..100 '&[2]': &[i32; _] 308 75..76 'i': i32
288 97..100 '[2]': [i32; _] 309 87..88 '2': i32
289 98..99 '2': i32 310 87..88 '2': i32
290 111..112 '1': i32 311 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
291 111..112 '1': i32 312 92..101 'foo(&[2])': &[i32]
292 116..120 '&[1]': &[i32; _] 313 96..100 '&[2]': &[i32; _]
293 117..120 '[1]': [i32; _] 314 97..100 '[2]': [i32; _]
294 118..119 '1': i32 315 98..99 '2': i32
295 130..131 '_': i32 316 111..112 '1': i32
296 135..139 '&[3]': &[i32; _] 317 111..112 '1': i32
297 136..139 '[3]': [i32; _] 318 116..120 '&[1]': &[i32; _]
298 137..138 '3': i32 319 117..120 '[1]': [i32; _]
299 "### 320 118..119 '1': i32
321 130..131 '_': i32
322 135..139 '&[3]': &[i32; _]
323 136..139 '[3]': [i32; _]
324 137..138 '3': i32
325 "]],
300 ); 326 );
301} 327}
302 328
303#[test] 329#[test]
304fn infer_match_second_coerce() { 330fn infer_match_second_coerce() {
305 assert_snapshot!( 331 check_infer(
306 infer(r#" 332 r#"
307fn foo<T>(x: &[T]) -> &[T] { loop {} } 333 fn foo<T>(x: &[T]) -> &[T] { loop {} }
308fn test(i: i32) { 334 fn test(i: i32) {
309 let x = match i { 335 let x = match i {
310 1 => &[1], 336 1 => &[1],
311 2 => foo(&[2]), 337 2 => foo(&[2]),
312 _ => &[3], 338 _ => &[3],
313 }; 339 };
314} 340 }
315"#), 341
316 @r###" 342 #[lang = "sized"]
317 10..11 'x': &[T] 343 pub trait Sized {}
318 27..38 '{ loop {} }': &[T] 344 #[lang = "unsize"]
319 29..36 'loop {}': ! 345 pub trait Unsize<T: ?Sized> {}
320 34..36 '{}': () 346 #[lang = "coerce_unsized"]
321 47..48 'i': i32 347 pub trait CoerceUnsized<T> {}
322 55..149 '{ ... }; }': () 348
323 65..66 'x': &[i32] 349 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
324 69..146 'match ... }': &[i32] 350 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
325 75..76 'i': i32 351 "#,
326 87..88 '1': i32 352 expect![[r"
327 87..88 '1': i32 353 10..11 'x': &[T]
328 92..96 '&[1]': &[i32; _] 354 27..38 '{ loop {} }': &[T]
329 93..96 '[1]': [i32; _] 355 29..36 'loop {}': !
330 94..95 '1': i32 356 34..36 '{}': ()
331 106..107 '2': i32 357 47..48 'i': i32
332 106..107 '2': i32 358 55..149 '{ ... }; }': ()
333 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] 359 65..66 'x': &[i32]
334 111..120 'foo(&[2])': &[i32] 360 69..146 'match ... }': &[i32]
335 115..119 '&[2]': &[i32; _] 361 75..76 'i': i32
336 116..119 '[2]': [i32; _] 362 87..88 '1': i32
337 117..118 '2': i32 363 87..88 '1': i32
338 130..131 '_': i32 364 92..96 '&[1]': &[i32; _]
339 135..139 '&[3]': &[i32; _] 365 93..96 '[1]': [i32; _]
340 136..139 '[3]': [i32; _] 366 94..95 '1': i32
341 137..138 '3': i32 367 106..107 '2': i32
342 "### 368 106..107 '2': i32
369 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
370 111..120 'foo(&[2])': &[i32]
371 115..119 '&[2]': &[i32; _]
372 116..119 '[2]': [i32; _]
373 117..118 '2': i32
374 130..131 '_': i32
375 135..139 '&[3]': &[i32; _]
376 136..139 '[3]': [i32; _]
377 137..138 '3': i32
378 "]],
343 ); 379 );
344} 380}
345 381
@@ -347,405 +383,453 @@ fn test(i: i32) {
347fn coerce_merge_one_by_one1() { 383fn coerce_merge_one_by_one1() {
348 mark::check!(coerce_merge_fail_fallback); 384 mark::check!(coerce_merge_fail_fallback);
349 385
350 assert_snapshot!( 386 check_infer(
351 infer(r#" 387 r"
352fn test() { 388 fn test() {
353 let t = &mut 1; 389 let t = &mut 1;
354 let x = match 1 { 390 let x = match 1 {
355 1 => t as *mut i32, 391 1 => t as *mut i32,
356 2 => t as &i32, 392 2 => t as &i32,
357 _ => t as *const i32, 393 _ => t as *const i32,
358 }; 394 };
359} 395 }
360"#), 396 ",
361 @r###" 397 expect![[r"
362 10..144 '{ ... }; }': () 398 10..144 '{ ... }; }': ()
363 20..21 't': &mut i32 399 20..21 't': &mut i32
364 24..30 '&mut 1': &mut i32 400 24..30 '&mut 1': &mut i32
365 29..30 '1': i32 401 29..30 '1': i32
366 40..41 'x': *const i32 402 40..41 'x': *const i32
367 44..141 'match ... }': *const i32 403 44..141 'match ... }': *const i32
368 50..51 '1': i32 404 50..51 '1': i32
369 62..63 '1': i32 405 62..63 '1': i32
370 62..63 '1': i32 406 62..63 '1': i32
371 67..68 't': &mut i32 407 67..68 't': &mut i32
372 67..80 't as *mut i32': *mut i32 408 67..80 't as *mut i32': *mut i32
373 90..91 '2': i32 409 90..91 '2': i32
374 90..91 '2': i32 410 90..91 '2': i32
375 95..96 't': &mut i32 411 95..96 't': &mut i32
376 95..104 't as &i32': &i32 412 95..104 't as &i32': &i32
377 114..115 '_': i32 413 114..115 '_': i32
378 119..120 't': &mut i32 414 119..120 't': &mut i32
379 119..134 't as *const i32': *const i32 415 119..134 't as *const i32': *const i32
380 "### 416 "]],
381 ); 417 );
382} 418}
383 419
384#[test] 420#[test]
385fn return_coerce_unknown() { 421fn return_coerce_unknown() {
386 assert_snapshot!( 422 check_infer_with_mismatches(
387 infer_with_mismatches(r#" 423 r"
388fn foo() -> u32 { 424 fn foo() -> u32 {
389 return unknown; 425 return unknown;
390} 426 }
391"#, true), 427 ",
392 @r###" 428 expect![[r"
393 16..39 '{ ...own; }': u32 429 16..39 '{ ...own; }': u32
394 22..36 'return unknown': ! 430 22..36 'return unknown': !
395 29..36 'unknown': u32 431 29..36 'unknown': u32
396 "### 432 "]],
397 ); 433 );
398} 434}
399 435
400#[test] 436#[test]
401fn coerce_autoderef() { 437fn coerce_autoderef() {
402 assert_snapshot!( 438 check_infer_with_mismatches(
403 infer_with_mismatches(r#" 439 r"
404struct Foo; 440 struct Foo;
405fn takes_ref_foo(x: &Foo) {} 441 fn takes_ref_foo(x: &Foo) {}
406fn test() { 442 fn test() {
407 takes_ref_foo(&Foo); 443 takes_ref_foo(&Foo);
408 takes_ref_foo(&&Foo); 444 takes_ref_foo(&&Foo);
409 takes_ref_foo(&&&Foo); 445 takes_ref_foo(&&&Foo);
410} 446 }
411"#, true), 447 ",
412 @r###" 448 expect![[r"
413 29..30 'x': &Foo 449 29..30 'x': &Foo
414 38..40 '{}': () 450 38..40 '{}': ()
415 51..132 '{ ...oo); }': () 451 51..132 '{ ...oo); }': ()
416 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) 452 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo)
417 57..76 'takes_...(&Foo)': () 453 57..76 'takes_...(&Foo)': ()
418 71..75 '&Foo': &Foo 454 71..75 '&Foo': &Foo
419 72..75 'Foo': Foo 455 72..75 'Foo': Foo
420 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) 456 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo)
421 82..102 'takes_...&&Foo)': () 457 82..102 'takes_...&&Foo)': ()
422 96..101 '&&Foo': &&Foo 458 96..101 '&&Foo': &&Foo
423 97..101 '&Foo': &Foo 459 97..101 '&Foo': &Foo
424 98..101 'Foo': Foo 460 98..101 'Foo': Foo
425 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) 461 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo)
426 108..129 'takes_...&&Foo)': () 462 108..129 'takes_...&&Foo)': ()
427 122..128 '&&&Foo': &&&Foo 463 122..128 '&&&Foo': &&&Foo
428 123..128 '&&Foo': &&Foo 464 123..128 '&&Foo': &&Foo
429 124..128 '&Foo': &Foo 465 124..128 '&Foo': &Foo
430 125..128 'Foo': Foo 466 125..128 'Foo': Foo
431 "### 467 "]],
432 ); 468 );
433} 469}
434 470
435#[test] 471#[test]
436fn coerce_autoderef_generic() { 472fn coerce_autoderef_generic() {
437 assert_snapshot!( 473 check_infer_with_mismatches(
438 infer_with_mismatches(r#" 474 r"
439struct Foo; 475 struct Foo;
440fn takes_ref<T>(x: &T) -> T { *x } 476 fn takes_ref<T>(x: &T) -> T { *x }
441fn test() { 477 fn test() {
442 takes_ref(&Foo); 478 takes_ref(&Foo);
443 takes_ref(&&Foo); 479 takes_ref(&&Foo);
444 takes_ref(&&&Foo); 480 takes_ref(&&&Foo);
445} 481 }
446"#, true), 482 ",
447 @r###" 483 expect![[r"
448 28..29 'x': &T 484 28..29 'x': &T
449 40..46 '{ *x }': T 485 40..46 '{ *x }': T
450 42..44 '*x': T 486 42..44 '*x': T
451 43..44 'x': &T 487 43..44 'x': &T
452 57..126 '{ ...oo); }': () 488 57..126 '{ ...oo); }': ()
453 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo 489 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo
454 63..78 'takes_ref(&Foo)': Foo 490 63..78 'takes_ref(&Foo)': Foo
455 73..77 '&Foo': &Foo 491 73..77 '&Foo': &Foo
456 74..77 'Foo': Foo 492 74..77 'Foo': Foo
457 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo 493 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo
458 84..100 'takes_...&&Foo)': &Foo 494 84..100 'takes_...&&Foo)': &Foo
459 94..99 '&&Foo': &&Foo 495 94..99 '&&Foo': &&Foo
460 95..99 '&Foo': &Foo 496 95..99 '&Foo': &Foo
461 96..99 'Foo': Foo 497 96..99 'Foo': Foo
462 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo 498 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo
463 106..123 'takes_...&&Foo)': &&Foo 499 106..123 'takes_...&&Foo)': &&Foo
464 116..122 '&&&Foo': &&&Foo 500 116..122 '&&&Foo': &&&Foo
465 117..122 '&&Foo': &&Foo 501 117..122 '&&Foo': &&Foo
466 118..122 '&Foo': &Foo 502 118..122 '&Foo': &Foo
467 119..122 'Foo': Foo 503 119..122 'Foo': Foo
468 "### 504 "]],
469 ); 505 );
470} 506}
471 507
472#[test] 508#[test]
473fn coerce_autoderef_block() { 509fn coerce_autoderef_block() {
474 assert_snapshot!( 510 check_infer_with_mismatches(
475 infer_with_mismatches(r#" 511 r#"
476struct String {} 512 struct String {}
477#[lang = "deref"] 513 #[lang = "deref"]
478trait Deref { type Target; } 514 trait Deref { type Target; }
479impl Deref for String { type Target = str; } 515 impl Deref for String { type Target = str; }
480fn takes_ref_str(x: &str) {} 516 fn takes_ref_str(x: &str) {}
481fn returns_string() -> String { loop {} } 517 fn returns_string() -> String { loop {} }
482fn test() { 518 fn test() {
483 takes_ref_str(&{ returns_string() }); 519 takes_ref_str(&{ returns_string() });
484} 520 }
485"#, true), 521 "#,
486 @r###" 522 expect![[r"
487 126..127 'x': &str 523 126..127 'x': &str
488 135..137 '{}': () 524 135..137 '{}': ()
489 168..179 '{ loop {} }': String 525 168..179 '{ loop {} }': String
490 170..177 'loop {}': ! 526 170..177 'loop {}': !
491 175..177 '{}': () 527 175..177 '{}': ()
492 190..235 '{ ... }); }': () 528 190..235 '{ ... }); }': ()
493 196..209 'takes_ref_str': fn takes_ref_str(&str) 529 196..209 'takes_ref_str': fn takes_ref_str(&str)
494 196..232 'takes_...g() })': () 530 196..232 'takes_...g() })': ()
495 210..231 '&{ ret...ng() }': &String 531 210..231 '&{ ret...ng() }': &String
496 211..231 '{ retu...ng() }': String 532 211..231 '{ retu...ng() }': String
497 213..227 'returns_string': fn returns_string() -> String 533 213..227 'returns_string': fn returns_string() -> String
498 213..229 'return...ring()': String 534 213..229 'return...ring()': String
499 "### 535 "]],
500 ); 536 );
501} 537}
502 538
503#[test] 539#[test]
504fn closure_return_coerce() { 540fn closure_return_coerce() {
505 assert_snapshot!( 541 check_infer_with_mismatches(
506 infer_with_mismatches(r#" 542 r"
507fn foo() { 543 fn foo() {
508 let x = || { 544 let x = || {
509 if true { 545 if true {
510 return &1u32; 546 return &1u32;
547 }
548 &&1u32
549 };
511 } 550 }
512 &&1u32 551 ",
513 }; 552 expect![[r"
514} 553 9..105 '{ ... }; }': ()
515"#, true), 554 19..20 'x': || -> &u32
516 @r###" 555 23..102 '|| { ... }': || -> &u32
517 9..105 '{ ... }; }': () 556 26..102 '{ ... }': &u32
518 19..20 'x': || -> &u32 557 36..81 'if tru... }': ()
519 23..102 '|| { ... }': || -> &u32 558 39..43 'true': bool
520 26..102 '{ ... }': &u32 559 44..81 '{ ... }': ()
521 36..81 'if tru... }': () 560 58..70 'return &1u32': !
522 39..43 'true': bool 561 65..70 '&1u32': &u32
523 44..81 '{ ... }': () 562 66..70 '1u32': u32
524 58..70 'return &1u32': ! 563 90..96 '&&1u32': &&u32
525 65..70 '&1u32': &u32 564 91..96 '&1u32': &u32
526 66..70 '1u32': u32 565 92..96 '1u32': u32
527 90..96 '&&1u32': &&u32 566 "]],
528 91..96 '&1u32': &u32
529 92..96 '1u32': u32
530 "###
531 ); 567 );
532} 568}
533 569
534#[test] 570#[test]
535fn coerce_fn_item_to_fn_ptr() { 571fn coerce_fn_item_to_fn_ptr() {
536 assert_snapshot!( 572 check_infer_with_mismatches(
537 infer_with_mismatches(r#" 573 r"
538fn foo(x: u32) -> isize { 1 } 574 fn foo(x: u32) -> isize { 1 }
539fn test() { 575 fn test() {
540 let f: fn(u32) -> isize = foo; 576 let f: fn(u32) -> isize = foo;
541} 577 }
542"#, true), 578 ",
543 @r###" 579 expect![[r"
544 7..8 'x': u32 580 7..8 'x': u32
545 24..29 '{ 1 }': isize 581 24..29 '{ 1 }': isize
546 26..27 '1': isize 582 26..27 '1': isize
547 40..78 '{ ...foo; }': () 583 40..78 '{ ...foo; }': ()
548 50..51 'f': fn(u32) -> isize 584 50..51 'f': fn(u32) -> isize
549 72..75 'foo': fn foo(u32) -> isize 585 72..75 'foo': fn foo(u32) -> isize
550 "### 586 "]],
551 ); 587 );
552} 588}
553 589
554#[test] 590#[test]
555fn coerce_fn_items_in_match_arms() { 591fn coerce_fn_items_in_match_arms() {
556 mark::check!(coerce_fn_reification); 592 mark::check!(coerce_fn_reification);
557 assert_snapshot!( 593
558 infer_with_mismatches(r#" 594 check_infer_with_mismatches(
559fn foo1(x: u32) -> isize { 1 } 595 r"
560fn foo2(x: u32) -> isize { 2 } 596 fn foo1(x: u32) -> isize { 1 }
561fn foo3(x: u32) -> isize { 3 } 597 fn foo2(x: u32) -> isize { 2 }
562fn test() { 598 fn foo3(x: u32) -> isize { 3 }
563 let x = match 1 { 599 fn test() {
564 1 => foo1, 600 let x = match 1 {
565 2 => foo2, 601 1 => foo1,
566 _ => foo3, 602 2 => foo2,
567 }; 603 _ => foo3,
568} 604 };
569"#, true), 605 }
570 @r###" 606 ",
571 8..9 'x': u32 607 expect![[r"
572 25..30 '{ 1 }': isize 608 8..9 'x': u32
573 27..28 '1': isize 609 25..30 '{ 1 }': isize
574 39..40 'x': u32 610 27..28 '1': isize
575 56..61 '{ 2 }': isize 611 39..40 'x': u32
576 58..59 '2': isize 612 56..61 '{ 2 }': isize
577 70..71 'x': u32 613 58..59 '2': isize
578 87..92 '{ 3 }': isize 614 70..71 'x': u32
579 89..90 '3': isize 615 87..92 '{ 3 }': isize
580 103..192 '{ ... }; }': () 616 89..90 '3': isize
581 113..114 'x': fn(u32) -> isize 617 103..192 '{ ... }; }': ()
582 117..189 'match ... }': fn(u32) -> isize 618 113..114 'x': fn(u32) -> isize
583 123..124 '1': i32 619 117..189 'match ... }': fn(u32) -> isize
584 135..136 '1': i32 620 123..124 '1': i32
585 135..136 '1': i32 621 135..136 '1': i32
586 140..144 'foo1': fn foo1(u32) -> isize 622 135..136 '1': i32
587 154..155 '2': i32 623 140..144 'foo1': fn foo1(u32) -> isize
588 154..155 '2': i32 624 154..155 '2': i32
589 159..163 'foo2': fn foo2(u32) -> isize 625 154..155 '2': i32
590 173..174 '_': i32 626 159..163 'foo2': fn foo2(u32) -> isize
591 178..182 'foo3': fn foo3(u32) -> isize 627 173..174 '_': i32
592 "### 628 178..182 'foo3': fn foo3(u32) -> isize
629 "]],
593 ); 630 );
594} 631}
595 632
596#[test] 633#[test]
597fn coerce_closure_to_fn_ptr() { 634fn coerce_closure_to_fn_ptr() {
598 assert_snapshot!( 635 check_infer_with_mismatches(
599 infer_with_mismatches(r#" 636 r"
600fn test() { 637 fn test() {
601 let f: fn(u32) -> isize = |x| { 1 }; 638 let f: fn(u32) -> isize = |x| { 1 };
602} 639 }
603"#, true), 640 ",
604 @r###" 641 expect![[r"
605 10..54 '{ ...1 }; }': () 642 10..54 '{ ...1 }; }': ()
606 20..21 'f': fn(u32) -> isize 643 20..21 'f': fn(u32) -> isize
607 42..51 '|x| { 1 }': |u32| -> isize 644 42..51 '|x| { 1 }': |u32| -> isize
608 43..44 'x': u32 645 43..44 'x': u32
609 46..51 '{ 1 }': isize 646 46..51 '{ 1 }': isize
610 48..49 '1': isize 647 48..49 '1': isize
611 "### 648 "]],
612 ); 649 );
613} 650}
614 651
615#[test] 652#[test]
616fn coerce_placeholder_ref() { 653fn coerce_placeholder_ref() {
617 // placeholders should unify, even behind references 654 // placeholders should unify, even behind references
618 assert_snapshot!( 655 check_infer_with_mismatches(
619 infer_with_mismatches(r#" 656 r"
620struct S<T> { t: T } 657 struct S<T> { t: T }
621impl<TT> S<TT> { 658 impl<TT> S<TT> {
622 fn get(&self) -> &TT { 659 fn get(&self) -> &TT {
623 &self.t 660 &self.t
624 } 661 }
625} 662 }
626"#, true), 663 ",
627 @r###" 664 expect![[r"
628 50..54 'self': &S<TT> 665 50..54 'self': &S<TT>
629 63..86 '{ ... }': &TT 666 63..86 '{ ... }': &TT
630 73..80 '&self.t': &TT 667 73..80 '&self.t': &TT
631 74..78 'self': &S<TT> 668 74..78 'self': &S<TT>
632 74..80 'self.t': TT 669 74..80 'self.t': TT
633 "### 670 "]],
634 ); 671 );
635} 672}
636 673
637#[test] 674#[test]
638fn coerce_unsize_array() { 675fn coerce_unsize_array() {
639 assert_snapshot!( 676 check_infer_with_mismatches(
640 infer_with_mismatches(r#" 677 r#"
641#[lang = "unsize"] 678 #[lang = "unsize"]
642pub trait Unsize<T> {} 679 pub trait Unsize<T> {}
643#[lang = "coerce_unsized"] 680 #[lang = "coerce_unsized"]
644pub trait CoerceUnsized<T> {} 681 pub trait CoerceUnsized<T> {}
645 682
646impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 683 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
647 684
648fn test() { 685 fn test() {
649 let f: &[usize] = &[1, 2, 3]; 686 let f: &[usize] = &[1, 2, 3];
650} 687 }
651"#, true), 688 "#,
652 @r###" 689 expect![[r"
653 161..198 '{ ... 3]; }': () 690 161..198 '{ ... 3]; }': ()
654 171..172 'f': &[usize] 691 171..172 'f': &[usize]
655 185..195 '&[1, 2, 3]': &[usize; _] 692 185..195 '&[1, 2, 3]': &[usize; _]
656 186..195 '[1, 2, 3]': [usize; _] 693 186..195 '[1, 2, 3]': [usize; _]
657 187..188 '1': usize 694 187..188 '1': usize
658 190..191 '2': usize 695 190..191 '2': usize
659 193..194 '3': usize 696 193..194 '3': usize
660 "### 697 "]],
661 ); 698 );
662} 699}
663 700
664#[test] 701#[test]
665fn coerce_unsize_trait_object() { 702fn coerce_unsize_trait_object_simple() {
666 assert_snapshot!( 703 check_infer_with_mismatches(
667 infer_with_mismatches(r#" 704 r#"
668#[lang = "sized"] 705 #[lang = "sized"]
669pub trait Sized {} 706 pub trait Sized {}
670#[lang = "unsize"] 707 #[lang = "unsize"]
671pub trait Unsize<T> {} 708 pub trait Unsize<T> {}
672#[lang = "coerce_unsized"] 709 #[lang = "coerce_unsized"]
673pub trait CoerceUnsized<T> {} 710 pub trait CoerceUnsized<T> {}
674 711
675impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 712 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
676 713
677trait Foo<T, U> {} 714 trait Foo<T, U> {}
678trait Bar<U, T, X>: Foo<T, U> {} 715 trait Bar<U, T, X>: Foo<T, U> {}
679trait Baz<T, X>: Bar<usize, T, X> {} 716 trait Baz<T, X>: Bar<usize, T, X> {}
680 717
681struct S<T, X>; 718 struct S<T, X>;
682impl<T, X> Foo<T, usize> for S<T, X> {} 719 impl<T, X> Foo<T, usize> for S<T, X> {}
683impl<T, X> Bar<usize, T, X> for S<T, X> {} 720 impl<T, X> Bar<usize, T, X> for S<T, X> {}
684impl<T, X> Baz<T, X> for S<T, X> {} 721 impl<T, X> Baz<T, X> for S<T, X> {}
685 722
686fn test() { 723 fn test() {
687 let obj: &dyn Baz<i8, i16> = &S; 724 let obj: &dyn Baz<i8, i16> = &S;
688 let obj: &dyn Bar<_, _, _> = obj; 725 let obj: &dyn Bar<_, i8, i16> = &S;
689 let obj: &dyn Foo<_, _> = obj; 726 let obj: &dyn Foo<i8, _> = &S;
690 let obj2: &dyn Baz<i8, i16> = &S; 727 }
691 let _: &dyn Foo<_, _> = obj2; 728 "#,
729 expect![[r"
730 424..539 '{ ... &S; }': ()
731 434..437 'obj': &dyn Baz<i8, i16>
732 459..461 '&S': &S<i8, i16>
733 460..461 'S': S<i8, i16>
734 471..474 'obj': &dyn Bar<usize, i8, i16>
735 499..501 '&S': &S<i8, i16>
736 500..501 'S': S<i8, i16>
737 511..514 'obj': &dyn Foo<i8, usize>
738 534..536 '&S': &S<i8, {unknown}>
739 535..536 'S': S<i8, {unknown}>
740 "]],
741 );
692} 742}
693"#, true), 743
694 @r###" 744#[test]
695 424..609 '{ ...bj2; }': () 745// The rust reference says this should be possible, but rustc doesn't implement
696 434..437 'obj': &dyn Baz<i8, i16> 746// it. We used to support it, but Chalk doesn't.
697 459..461 '&S': &S<i8, i16> 747#[ignore]
698 460..461 'S': S<i8, i16> 748fn coerce_unsize_trait_object_to_trait_object() {
699 471..474 'obj': &dyn Bar<usize, i8, i16> 749 check_infer_with_mismatches(
700 496..499 'obj': &dyn Baz<i8, i16> 750 r#"
701 509..512 'obj': &dyn Foo<i8, usize> 751 #[lang = "sized"]
702 531..534 'obj': &dyn Bar<usize, i8, i16> 752 pub trait Sized {}
703 544..548 'obj2': &dyn Baz<i8, i16> 753 #[lang = "unsize"]
704 570..572 '&S': &S<i8, i16> 754 pub trait Unsize<T> {}
705 571..572 'S': S<i8, i16> 755 #[lang = "coerce_unsized"]
706 582..583 '_': &dyn Foo<i8, usize> 756 pub trait CoerceUnsized<T> {}
707 602..606 'obj2': &dyn Baz<i8, i16> 757
708 "### 758 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
759
760 trait Foo<T, U> {}
761 trait Bar<U, T, X>: Foo<T, U> {}
762 trait Baz<T, X>: Bar<usize, T, X> {}
763
764 struct S<T, X>;
765 impl<T, X> Foo<T, usize> for S<T, X> {}
766 impl<T, X> Bar<usize, T, X> for S<T, X> {}
767 impl<T, X> Baz<T, X> for S<T, X> {}
768
769 fn test() {
770 let obj: &dyn Baz<i8, i16> = &S;
771 let obj: &dyn Bar<_, _, _> = obj;
772 let obj: &dyn Foo<_, _> = obj;
773 let obj2: &dyn Baz<i8, i16> = &S;
774 let _: &dyn Foo<_, _> = obj2;
775 }
776 "#,
777 expect![[r"
778 424..609 '{ ...bj2; }': ()
779 434..437 'obj': &dyn Baz<i8, i16>
780 459..461 '&S': &S<i8, i16>
781 460..461 'S': S<i8, i16>
782 471..474 'obj': &dyn Bar<usize, i8, i16>
783 496..499 'obj': &dyn Baz<i8, i16>
784 509..512 'obj': &dyn Foo<i8, usize>
785 531..534 'obj': &dyn Bar<usize, i8, i16>
786 544..548 'obj2': &dyn Baz<i8, i16>
787 570..572 '&S': &S<i8, i16>
788 571..572 'S': S<i8, i16>
789 582..583 '_': &dyn Foo<i8, usize>
790 602..606 'obj2': &dyn Baz<i8, i16>
791 "]],
709 ); 792 );
710} 793}
711 794
712#[test] 795#[test]
713fn coerce_unsize_super_trait_cycle() { 796fn coerce_unsize_super_trait_cycle() {
714 assert_snapshot!( 797 check_infer_with_mismatches(
715 infer_with_mismatches(r#" 798 r#"
716#[lang = "sized"] 799 #[lang = "sized"]
717pub trait Sized {} 800 pub trait Sized {}
718#[lang = "unsize"] 801 #[lang = "unsize"]
719pub trait Unsize<T> {} 802 pub trait Unsize<T> {}
720#[lang = "coerce_unsized"] 803 #[lang = "coerce_unsized"]
721pub trait CoerceUnsized<T> {} 804 pub trait CoerceUnsized<T> {}
722 805
723impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 806 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
724 807
725trait A {} 808 trait A {}
726trait B: C + A {} 809 trait B: C + A {}
727trait C: B {} 810 trait C: B {}
728trait D: C 811 trait D: C
729 812
730struct S; 813 struct S;
731impl A for S {} 814 impl A for S {}
732impl B for S {} 815 impl B for S {}
733impl C for S {} 816 impl C for S {}
734impl D for S {} 817 impl D for S {}
735 818
736fn test() { 819 fn test() {
737 let obj: &dyn D = &S; 820 let obj: &dyn D = &S;
738 let obj: &dyn A = obj; 821 let obj: &dyn A = &S;
739} 822 }
740"#, true), 823 "#,
741 @r###" 824 expect![[r"
742 328..384 '{ ...obj; }': () 825 328..383 '{ ... &S; }': ()
743 338..341 'obj': &dyn D 826 338..341 'obj': &dyn D
744 352..354 '&S': &S 827 352..354 '&S': &S
745 353..354 'S': S 828 353..354 'S': S
746 364..367 'obj': &dyn A 829 364..367 'obj': &dyn A
747 378..381 'obj': &dyn D 830 378..380 '&S': &S
748 "### 831 379..380 'S': S
832 "]],
749 ); 833 );
750} 834}
751 835
@@ -754,24 +838,24 @@ fn test() {
754fn coerce_unsize_generic() { 838fn coerce_unsize_generic() {
755 // FIXME: Implement this 839 // FIXME: Implement this
756 // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions 840 // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
757 assert_snapshot!( 841 check_infer_with_mismatches(
758 infer_with_mismatches(r#" 842 r#"
759#[lang = "unsize"] 843 #[lang = "unsize"]
760pub trait Unsize<T> {} 844 pub trait Unsize<T> {}
761#[lang = "coerce_unsized"] 845 #[lang = "coerce_unsized"]
762pub trait CoerceUnsized<T> {} 846 pub trait CoerceUnsized<T> {}
763 847
764impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 848 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
765 849
766struct Foo<T> { t: T }; 850 struct Foo<T> { t: T };
767struct Bar<T>(Foo<T>); 851 struct Bar<T>(Foo<T>);
768 852
769fn test() { 853 fn test() {
770 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; 854 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
771 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); 855 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
772} 856 }
773"#, true), 857 "#,
774 @r###" 858 expect![[r"
775 "### 859 "]],
776 ); 860 );
777} 861}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 45c4e309e..24c53eb02 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,9 +1,9 @@
1use std::fs; 1use std::fs;
2 2
3use insta::assert_snapshot; 3use expect::expect;
4use test_utils::project_dir; 4use test_utils::project_dir;
5 5
6use super::{check_types, infer}; 6use super::{check_infer, check_types};
7 7
8#[test] 8#[test]
9fn cfg_impl_def() { 9fn cfg_impl_def() {
@@ -46,204 +46,204 @@ impl S {
46 46
47#[test] 47#[test]
48fn infer_macros_expanded() { 48fn infer_macros_expanded() {
49 assert_snapshot!( 49 check_infer(
50 infer(r#" 50 r#"
51struct Foo(Vec<i32>); 51 struct Foo(Vec<i32>);
52 52
53macro_rules! foo { 53 macro_rules! foo {
54 ($($item:expr),*) => { 54 ($($item:expr),*) => {
55 { 55 {
56 Foo(vec![$($item,)*]) 56 Foo(vec![$($item,)*])
57 } 57 }
58 }; 58 };
59} 59 }
60 60
61fn main() { 61 fn main() {
62 let x = foo!(1,2); 62 let x = foo!(1,2);
63} 63 }
64"#), 64 "#,
65 @r###" 65 expect![[r#"
66 !0..17 '{Foo(v...,2,])}': Foo 66 !0..17 '{Foo(v...,2,])}': Foo
67 !1..4 'Foo': Foo({unknown}) -> Foo 67 !1..4 'Foo': Foo({unknown}) -> Foo
68 !1..16 'Foo(vec![1,2,])': Foo 68 !1..16 'Foo(vec![1,2,])': Foo
69 !5..15 'vec![1,2,]': {unknown} 69 !5..15 'vec![1,2,]': {unknown}
70 155..181 '{ ...,2); }': () 70 155..181 '{ ...,2); }': ()
71 165..166 'x': Foo 71 165..166 'x': Foo
72 "### 72 "#]],
73 ); 73 );
74} 74}
75 75
76#[test] 76#[test]
77fn infer_legacy_textual_scoped_macros_expanded() { 77fn infer_legacy_textual_scoped_macros_expanded() {
78 assert_snapshot!( 78 check_infer(
79 infer(r#" 79 r#"
80struct Foo(Vec<i32>); 80 struct Foo(Vec<i32>);
81 81
82#[macro_use] 82 #[macro_use]
83mod m { 83 mod m {
84 macro_rules! foo { 84 macro_rules! foo {
85 ($($item:expr),*) => { 85 ($($item:expr),*) => {
86 { 86 {
87 Foo(vec![$($item,)*]) 87 Foo(vec![$($item,)*])
88 }
89 };
88 } 90 }
89 }; 91 }
90 }
91}
92 92
93fn main() { 93 fn main() {
94 let x = foo!(1,2); 94 let x = foo!(1,2);
95 let y = crate::foo!(1,2); 95 let y = crate::foo!(1,2);
96} 96 }
97"#), 97 "#,
98 @r###" 98 expect![[r#"
99 !0..17 '{Foo(v...,2,])}': Foo 99 !0..17 '{Foo(v...,2,])}': Foo
100 !1..4 'Foo': Foo({unknown}) -> Foo 100 !1..4 'Foo': Foo({unknown}) -> Foo
101 !1..16 'Foo(vec![1,2,])': Foo 101 !1..16 'Foo(vec![1,2,])': Foo
102 !5..15 'vec![1,2,]': {unknown} 102 !5..15 'vec![1,2,]': {unknown}
103 194..250 '{ ...,2); }': () 103 194..250 '{ ...,2); }': ()
104 204..205 'x': Foo 104 204..205 'x': Foo
105 227..228 'y': {unknown} 105 227..228 'y': {unknown}
106 231..247 'crate:...!(1,2)': {unknown} 106 231..247 'crate:...!(1,2)': {unknown}
107 "### 107 "#]],
108 ); 108 );
109} 109}
110 110
111#[test] 111#[test]
112fn infer_path_qualified_macros_expanded() { 112fn infer_path_qualified_macros_expanded() {
113 assert_snapshot!( 113 check_infer(
114 infer(r#" 114 r#"
115#[macro_export] 115 #[macro_export]
116macro_rules! foo { 116 macro_rules! foo {
117 () => { 42i32 } 117 () => { 42i32 }
118} 118 }
119 119
120mod m { 120 mod m {
121 pub use super::foo as bar; 121 pub use super::foo as bar;
122} 122 }
123 123
124fn main() { 124 fn main() {
125 let x = crate::foo!(); 125 let x = crate::foo!();
126 let y = m::bar!(); 126 let y = m::bar!();
127} 127 }
128"#), 128 "#,
129 @r###" 129 expect![[r#"
130 !0..5 '42i32': i32 130 !0..5 '42i32': i32
131 !0..5 '42i32': i32 131 !0..5 '42i32': i32
132 110..163 '{ ...!(); }': () 132 110..163 '{ ...!(); }': ()
133 120..121 'x': i32 133 120..121 'x': i32
134 147..148 'y': i32 134 147..148 'y': i32
135 "### 135 "#]],
136 ); 136 );
137} 137}
138 138
139#[test] 139#[test]
140fn expr_macro_expanded_in_various_places() { 140fn expr_macro_expanded_in_various_places() {
141 assert_snapshot!( 141 check_infer(
142 infer(r#" 142 r#"
143macro_rules! spam { 143 macro_rules! spam {
144 () => (1isize); 144 () => (1isize);
145} 145 }
146 146
147fn spam() { 147 fn spam() {
148 spam!(); 148 spam!();
149 (spam!()); 149 (spam!());
150 spam!().spam(spam!()); 150 spam!().spam(spam!());
151 for _ in spam!() {} 151 for _ in spam!() {}
152 || spam!(); 152 || spam!();
153 while spam!() {} 153 while spam!() {}
154 break spam!(); 154 break spam!();
155 return spam!(); 155 return spam!();
156 match spam!() { 156 match spam!() {
157 _ if spam!() => spam!(), 157 _ if spam!() => spam!(),
158 } 158 }
159 spam!()(spam!()); 159 spam!()(spam!());
160 Spam { spam: spam!() }; 160 Spam { spam: spam!() };
161 spam!()[spam!()]; 161 spam!()[spam!()];
162 await spam!(); 162 await spam!();
163 spam!() as usize; 163 spam!() as usize;
164 &spam!(); 164 &spam!();
165 -spam!(); 165 -spam!();
166 spam!()..spam!(); 166 spam!()..spam!();
167 spam!() + spam!(); 167 spam!() + spam!();
168} 168 }
169"#), 169 "#,
170 @r###" 170 expect![[r#"
171 !0..6 '1isize': isize 171 !0..6 '1isize': isize
172 !0..6 '1isize': isize 172 !0..6 '1isize': isize
173 !0..6 '1isize': isize 173 !0..6 '1isize': isize
174 !0..6 '1isize': isize 174 !0..6 '1isize': isize
175 !0..6 '1isize': isize 175 !0..6 '1isize': isize
176 !0..6 '1isize': isize 176 !0..6 '1isize': isize
177 !0..6 '1isize': isize 177 !0..6 '1isize': isize
178 !0..6 '1isize': isize 178 !0..6 '1isize': isize
179 !0..6 '1isize': isize 179 !0..6 '1isize': isize
180 !0..6 '1isize': isize 180 !0..6 '1isize': isize
181 !0..6 '1isize': isize 181 !0..6 '1isize': isize
182 !0..6 '1isize': isize 182 !0..6 '1isize': isize
183 !0..6 '1isize': isize 183 !0..6 '1isize': isize
184 !0..6 '1isize': isize 184 !0..6 '1isize': isize
185 !0..6 '1isize': isize 185 !0..6 '1isize': isize
186 !0..6 '1isize': isize 186 !0..6 '1isize': isize
187 !0..6 '1isize': isize 187 !0..6 '1isize': isize
188 !0..6 '1isize': isize 188 !0..6 '1isize': isize
189 !0..6 '1isize': isize 189 !0..6 '1isize': isize
190 !0..6 '1isize': isize 190 !0..6 '1isize': isize
191 !0..6 '1isize': isize 191 !0..6 '1isize': isize
192 !0..6 '1isize': isize 192 !0..6 '1isize': isize
193 !0..6 '1isize': isize 193 !0..6 '1isize': isize
194 !0..6 '1isize': isize 194 !0..6 '1isize': isize
195 !0..6 '1isize': isize 195 !0..6 '1isize': isize
196 53..456 '{ ...!(); }': () 196 53..456 '{ ...!(); }': ()
197 87..108 'spam!(...am!())': {unknown} 197 87..108 'spam!(...am!())': {unknown}
198 114..133 'for _ ...!() {}': () 198 114..133 'for _ ...!() {}': ()
199 118..119 '_': {unknown} 199 118..119 '_': {unknown}
200 131..133 '{}': () 200 131..133 '{}': ()
201 138..148 '|| spam!()': || -> isize 201 138..148 '|| spam!()': || -> isize
202 154..170 'while ...!() {}': () 202 154..170 'while ...!() {}': ()
203 168..170 '{}': () 203 168..170 '{}': ()
204 175..188 'break spam!()': ! 204 175..188 'break spam!()': !
205 194..208 'return spam!()': ! 205 194..208 'return spam!()': !
206 214..268 'match ... }': isize 206 214..268 'match ... }': isize
207 238..239 '_': isize 207 238..239 '_': isize
208 273..289 'spam!(...am!())': {unknown} 208 273..289 'spam!(...am!())': {unknown}
209 295..317 'Spam {...m!() }': {unknown} 209 295..317 'Spam {...m!() }': {unknown}
210 323..339 'spam!(...am!()]': {unknown} 210 323..339 'spam!(...am!()]': {unknown}
211 364..380 'spam!(... usize': usize 211 364..380 'spam!(... usize': usize
212 386..394 '&spam!()': &isize 212 386..394 '&spam!()': &isize
213 400..408 '-spam!()': isize 213 400..408 '-spam!()': isize
214 414..430 'spam!(...pam!()': {unknown} 214 414..430 'spam!(...pam!()': {unknown}
215 436..453 'spam!(...pam!()': isize 215 436..453 'spam!(...pam!()': isize
216 "### 216 "#]],
217 ); 217 );
218} 218}
219 219
220#[test] 220#[test]
221fn infer_type_value_macro_having_same_name() { 221fn infer_type_value_macro_having_same_name() {
222 assert_snapshot!( 222 check_infer(
223 infer(r#" 223 r#"
224#[macro_export] 224 #[macro_export]
225macro_rules! foo { 225 macro_rules! foo {
226 () => { 226 () => {
227 mod foo { 227 mod foo {
228 pub use super::foo; 228 pub use super::foo;
229 }
230 };
231 ($x:tt) => {
232 $x
233 };
229 } 234 }
230 };
231 ($x:tt) => {
232 $x
233 };
234}
235 235
236foo!(); 236 foo!();
237 237
238fn foo() { 238 fn foo() {
239 let foo = foo::foo!(42i32); 239 let foo = foo::foo!(42i32);
240} 240 }
241"#), 241 "#,
242 @r###" 242 expect![[r#"
243 !0..5 '42i32': i32 243 !0..5 '42i32': i32
244 170..205 '{ ...32); }': () 244 170..205 '{ ...32); }': ()
245 180..183 'foo': i32 245 180..183 'foo': i32
246 "### 246 "#]],
247 ); 247 );
248} 248}
249 249
@@ -372,50 +372,50 @@ expand!();
372 372
373#[test] 373#[test]
374fn infer_type_value_non_legacy_macro_use_as() { 374fn infer_type_value_non_legacy_macro_use_as() {
375 assert_snapshot!( 375 check_infer(
376 infer(r#" 376 r#"
377mod m { 377 mod m {
378 macro_rules! _foo { 378 macro_rules! _foo {
379 ($x:ident) => { type $x = u64; } 379 ($x:ident) => { type $x = u64; }
380 } 380 }
381 pub(crate) use _foo as foo; 381 pub(crate) use _foo as foo;
382} 382 }
383 383
384m::foo!(foo); 384 m::foo!(foo);
385use foo as bar; 385 use foo as bar;
386fn f() -> bar { 0 } 386 fn f() -> bar { 0 }
387fn main() { 387 fn main() {
388 let _a = f(); 388 let _a = f();
389} 389 }
390"#), 390 "#,
391 @r###" 391 expect![[r#"
392 158..163 '{ 0 }': u64 392 158..163 '{ 0 }': u64
393 160..161 '0': u64 393 160..161 '0': u64
394 174..196 '{ ...f(); }': () 394 174..196 '{ ...f(); }': ()
395 184..186 '_a': u64 395 184..186 '_a': u64
396 190..191 'f': fn f() -> u64 396 190..191 'f': fn f() -> u64
397 190..193 'f()': u64 397 190..193 'f()': u64
398 "### 398 "#]],
399 ); 399 );
400} 400}
401 401
402#[test] 402#[test]
403fn infer_local_macro() { 403fn infer_local_macro() {
404 assert_snapshot!( 404 check_infer(
405 infer(r#" 405 r#"
406fn main() { 406 fn main() {
407 macro_rules! foo { 407 macro_rules! foo {
408 () => { 1usize } 408 () => { 1usize }
409 } 409 }
410 let _a = foo!(); 410 let _a = foo!();
411} 411 }
412"#), 412 "#,
413 @r###" 413 expect![[r#"
414 !0..6 '1usize': usize 414 !0..6 '1usize': usize
415 10..89 '{ ...!(); }': () 415 10..89 '{ ...!(); }': ()
416 16..65 'macro_... }': {unknown} 416 16..65 'macro_... }': {unknown}
417 74..76 '_a': usize 417 74..76 '_a': usize
418 "### 418 "#]],
419 ); 419 );
420} 420}
421 421
@@ -446,77 +446,77 @@ macro_rules! bar {
446 446
447#[test] 447#[test]
448fn infer_builtin_macros_line() { 448fn infer_builtin_macros_line() {
449 assert_snapshot!( 449 check_infer(
450 infer(r#" 450 r#"
451#[rustc_builtin_macro] 451 #[rustc_builtin_macro]
452macro_rules! line {() => {}} 452 macro_rules! line {() => {}}
453 453
454fn main() { 454 fn main() {
455 let x = line!(); 455 let x = line!();
456} 456 }
457"#), 457 "#,
458 @r###" 458 expect![[r#"
459 !0..1 '0': i32 459 !0..1 '0': i32
460 63..87 '{ ...!(); }': () 460 63..87 '{ ...!(); }': ()
461 73..74 'x': i32 461 73..74 'x': i32
462 "### 462 "#]],
463 ); 463 );
464} 464}
465 465
466#[test] 466#[test]
467fn infer_builtin_macros_file() { 467fn infer_builtin_macros_file() {
468 assert_snapshot!( 468 check_infer(
469 infer(r#" 469 r#"
470#[rustc_builtin_macro] 470 #[rustc_builtin_macro]
471macro_rules! file {() => {}} 471 macro_rules! file {() => {}}
472 472
473fn main() { 473 fn main() {
474 let x = file!(); 474 let x = file!();
475} 475 }
476"#), 476 "#,
477 @r###" 477 expect![[r#"
478 !0..2 '""': &str 478 !0..2 '""': &str
479 63..87 '{ ...!(); }': () 479 63..87 '{ ...!(); }': ()
480 73..74 'x': &str 480 73..74 'x': &str
481 "### 481 "#]],
482 ); 482 );
483} 483}
484 484
485#[test] 485#[test]
486fn infer_builtin_macros_column() { 486fn infer_builtin_macros_column() {
487 assert_snapshot!( 487 check_infer(
488 infer(r#" 488 r#"
489#[rustc_builtin_macro] 489 #[rustc_builtin_macro]
490macro_rules! column {() => {}} 490 macro_rules! column {() => {}}
491 491
492fn main() { 492 fn main() {
493 let x = column!(); 493 let x = column!();
494} 494 }
495"#), 495 "#,
496 @r###" 496 expect![[r#"
497 !0..1 '0': i32 497 !0..1 '0': i32
498 65..91 '{ ...!(); }': () 498 65..91 '{ ...!(); }': ()
499 75..76 'x': i32 499 75..76 'x': i32
500 "### 500 "#]],
501 ); 501 );
502} 502}
503 503
504#[test] 504#[test]
505fn infer_builtin_macros_concat() { 505fn infer_builtin_macros_concat() {
506 assert_snapshot!( 506 check_infer(
507 infer(r#" 507 r#"
508#[rustc_builtin_macro] 508 #[rustc_builtin_macro]
509macro_rules! concat {() => {}} 509 macro_rules! concat {() => {}}
510 510
511fn main() { 511 fn main() {
512 let x = concat!("hello", concat!("world", "!")); 512 let x = concat!("hello", concat!("world", "!"));
513} 513 }
514"#), 514 "#,
515 @r###" 515 expect![[r#"
516 !0..13 '"helloworld!"': &str 516 !0..13 '"helloworld!"': &str
517 65..121 '{ ...")); }': () 517 65..121 '{ ...")); }': ()
518 75..76 'x': &str 518 75..76 'x': &str
519 "### 519 "#]],
520 ); 520 );
521} 521}
522 522
@@ -622,7 +622,7 @@ macro_rules! include {() => {}}
622include!("main.rs"); 622include!("main.rs");
623 623
624fn main() { 624fn main() {
625 0 625 0
626} //^ i32 626} //^ i32
627"#, 627"#,
628 ); 628 );
@@ -630,42 +630,42 @@ fn main() {
630 630
631#[test] 631#[test]
632fn infer_builtin_macros_concat_with_lazy() { 632fn infer_builtin_macros_concat_with_lazy() {
633 assert_snapshot!( 633 check_infer(
634 infer(r#" 634 r#"
635macro_rules! hello {() => {"hello"}} 635 macro_rules! hello {() => {"hello"}}
636 636
637#[rustc_builtin_macro] 637 #[rustc_builtin_macro]
638macro_rules! concat {() => {}} 638 macro_rules! concat {() => {}}
639 639
640fn main() { 640 fn main() {
641 let x = concat!(hello!(), concat!("world", "!")); 641 let x = concat!(hello!(), concat!("world", "!"));
642} 642 }
643"#), 643 "#,
644 @r###" 644 expect![[r#"
645 !0..13 '"helloworld!"': &str 645 !0..13 '"helloworld!"': &str
646 103..160 '{ ...")); }': () 646 103..160 '{ ...")); }': ()
647 113..114 'x': &str 647 113..114 'x': &str
648 "### 648 "#]],
649 ); 649 );
650} 650}
651 651
652#[test] 652#[test]
653fn infer_builtin_macros_env() { 653fn infer_builtin_macros_env() {
654 assert_snapshot!( 654 check_infer(
655 infer(r#" 655 r#"
656//- /main.rs env:foo=bar 656 //- /main.rs env:foo=bar
657#[rustc_builtin_macro] 657 #[rustc_builtin_macro]
658macro_rules! env {() => {}} 658 macro_rules! env {() => {}}
659 659
660fn main() { 660 fn main() {
661 let x = env!("foo"); 661 let x = env!("foo");
662} 662 }
663"#), 663 "#,
664 @r###" 664 expect![[r#"
665 !0..22 '"__RA_...TED__"': &str 665 !0..22 '"__RA_...TED__"': &str
666 62..90 '{ ...o"); }': () 666 62..90 '{ ...o"); }': ()
667 72..73 'x': &str 667 72..73 'x': &str
668 "### 668 "#]],
669 ); 669 );
670} 670}
671 671
@@ -763,25 +763,25 @@ fn test() {
763 763
764#[test] 764#[test]
765fn macro_in_arm() { 765fn macro_in_arm() {
766 assert_snapshot!( 766 check_infer(
767 infer(r#" 767 r#"
768macro_rules! unit { 768 macro_rules! unit {
769 () => { () }; 769 () => { () };
770} 770 }
771 771
772fn main() { 772 fn main() {
773 let x = match () { 773 let x = match () {
774 unit!() => 92u32, 774 unit!() => 92u32,
775 }; 775 };
776} 776 }
777"#), 777 "#,
778 @r###" 778 expect![[r#"
779 51..110 '{ ... }; }': () 779 51..110 '{ ... }; }': ()
780 61..62 'x': u32 780 61..62 'x': u32
781 65..107 'match ... }': u32 781 65..107 'match ... }': u32
782 71..73 '()': () 782 71..73 '()': ()
783 84..91 'unit!()': () 783 84..91 'unit!()': ()
784 95..100 '92u32': u32 784 95..100 '92u32': u32
785 "### 785 "#]],
786 ); 786 );
787} 787}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 9c8f22314..fa68355aa 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1,245 +1,245 @@
1use insta::assert_snapshot; 1use expect::expect;
2 2
3use super::{check_types, infer}; 3use super::{check_infer, check_types};
4 4
5#[test] 5#[test]
6fn infer_slice_method() { 6fn infer_slice_method() {
7 assert_snapshot!( 7 check_infer(
8 infer(r#" 8 r#"
9#[lang = "slice"] 9 #[lang = "slice"]
10impl<T> [T] { 10 impl<T> [T] {
11 fn foo(&self) -> T { 11 fn foo(&self) -> T {
12 loop {} 12 loop {}
13 } 13 }
14} 14 }
15 15
16#[lang = "slice_alloc"] 16 #[lang = "slice_alloc"]
17impl<T> [T] {} 17 impl<T> [T] {}
18 18
19fn test(x: &[u8]) { 19 fn test(x: &[u8]) {
20 <[_]>::foo(x); 20 <[_]>::foo(x);
21} 21 }
22"#), 22 "#,
23 @r###" 23 expect![[r#"
24 44..48 'self': &[T] 24 44..48 'self': &[T]
25 55..78 '{ ... }': T 25 55..78 '{ ... }': T
26 65..72 'loop {}': ! 26 65..72 'loop {}': !
27 70..72 '{}': () 27 70..72 '{}': ()
28 130..131 'x': &[u8] 28 130..131 'x': &[u8]
29 140..162 '{ ...(x); }': () 29 140..162 '{ ...(x); }': ()
30 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8 30 146..156 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
31 146..159 '<[_]>::foo(x)': u8 31 146..159 '<[_]>::foo(x)': u8
32 157..158 'x': &[u8] 32 157..158 'x': &[u8]
33 "### 33 "#]],
34 ); 34 );
35} 35}
36 36
37#[test] 37#[test]
38fn infer_associated_method_struct() { 38fn infer_associated_method_struct() {
39 assert_snapshot!( 39 check_infer(
40 infer(r#" 40 r#"
41struct A { x: u32 } 41 struct A { x: u32 }
42 42
43impl A { 43 impl A {
44 fn new() -> A { 44 fn new() -> A {
45 A { x: 0 } 45 A { x: 0 }
46 } 46 }
47} 47 }
48fn test() { 48 fn test() {
49 let a = A::new(); 49 let a = A::new();
50 a.x; 50 a.x;
51} 51 }
52"#), 52 "#,
53 @r###" 53 expect![[r#"
54 48..74 '{ ... }': A 54 48..74 '{ ... }': A
55 58..68 'A { x: 0 }': A 55 58..68 'A { x: 0 }': A
56 65..66 '0': u32 56 65..66 '0': u32
57 87..121 '{ ...a.x; }': () 57 87..121 '{ ...a.x; }': ()
58 97..98 'a': A 58 97..98 'a': A
59 101..107 'A::new': fn new() -> A 59 101..107 'A::new': fn new() -> A
60 101..109 'A::new()': A 60 101..109 'A::new()': A
61 115..116 'a': A 61 115..116 'a': A
62 115..118 'a.x': u32 62 115..118 'a.x': u32
63 "### 63 "#]],
64 ); 64 );
65} 65}
66 66
67#[test] 67#[test]
68fn infer_associated_method_enum() { 68fn infer_associated_method_enum() {
69 assert_snapshot!( 69 check_infer(
70 infer(r#" 70 r#"
71enum A { B, C } 71 enum A { B, C }
72 72
73impl A { 73 impl A {
74 pub fn b() -> A { 74 pub fn b() -> A {
75 A::B 75 A::B
76 } 76 }
77 pub fn c() -> A { 77 pub fn c() -> A {
78 A::C 78 A::C
79 } 79 }
80} 80 }
81fn test() { 81 fn test() {
82 let a = A::b(); 82 let a = A::b();
83 a; 83 a;
84 let c = A::c(); 84 let c = A::c();
85 c; 85 c;
86} 86 }
87"#), 87 "#,
88 @r###" 88 expect![[r#"
89 46..66 '{ ... }': A 89 46..66 '{ ... }': A
90 56..60 'A::B': A 90 56..60 'A::B': A
91 87..107 '{ ... }': A 91 87..107 '{ ... }': A
92 97..101 'A::C': A 92 97..101 'A::C': A
93 120..177 '{ ... c; }': () 93 120..177 '{ ... c; }': ()
94 130..131 'a': A 94 130..131 'a': A
95 134..138 'A::b': fn b() -> A 95 134..138 'A::b': fn b() -> A
96 134..140 'A::b()': A 96 134..140 'A::b()': A
97 146..147 'a': A 97 146..147 'a': A
98 157..158 'c': A 98 157..158 'c': A
99 161..165 'A::c': fn c() -> A 99 161..165 'A::c': fn c() -> A
100 161..167 'A::c()': A 100 161..167 'A::c()': A
101 173..174 'c': A 101 173..174 'c': A
102 "### 102 "#]],
103 ); 103 );
104} 104}
105 105
106#[test] 106#[test]
107fn infer_associated_method_with_modules() { 107fn infer_associated_method_with_modules() {
108 assert_snapshot!( 108 check_infer(
109 infer(r#" 109 r#"
110mod a { 110 mod a {
111 struct A; 111 struct A;
112 impl A { pub fn thing() -> A { A {} }} 112 impl A { pub fn thing() -> A { A {} }}
113} 113 }
114 114
115mod b { 115 mod b {
116 struct B; 116 struct B;
117 impl B { pub fn thing() -> u32 { 99 }} 117 impl B { pub fn thing() -> u32 { 99 }}
118 118
119 mod c { 119 mod c {
120 struct C; 120 struct C;
121 impl C { pub fn thing() -> C { C {} }} 121 impl C { pub fn thing() -> C { C {} }}
122 } 122 }
123} 123 }
124use b::c; 124 use b::c;
125 125
126fn test() { 126 fn test() {
127 let x = a::A::thing(); 127 let x = a::A::thing();
128 let y = b::B::thing(); 128 let y = b::B::thing();
129 let z = c::C::thing(); 129 let z = c::C::thing();
130} 130 }
131"#), 131 "#,
132 @r###" 132 expect![[r#"
133 55..63 '{ A {} }': A 133 55..63 '{ A {} }': A
134 57..61 'A {}': A 134 57..61 'A {}': A
135 125..131 '{ 99 }': u32 135 125..131 '{ 99 }': u32
136 127..129 '99': u32 136 127..129 '99': u32
137 201..209 '{ C {} }': C 137 201..209 '{ C {} }': C
138 203..207 'C {}': C 138 203..207 'C {}': C
139 240..324 '{ ...g(); }': () 139 240..324 '{ ...g(); }': ()
140 250..251 'x': A 140 250..251 'x': A
141 254..265 'a::A::thing': fn thing() -> A 141 254..265 'a::A::thing': fn thing() -> A
142 254..267 'a::A::thing()': A 142 254..267 'a::A::thing()': A
143 277..278 'y': u32 143 277..278 'y': u32
144 281..292 'b::B::thing': fn thing() -> u32 144 281..292 'b::B::thing': fn thing() -> u32
145 281..294 'b::B::thing()': u32 145 281..294 'b::B::thing()': u32
146 304..305 'z': C 146 304..305 'z': C
147 308..319 'c::C::thing': fn thing() -> C 147 308..319 'c::C::thing': fn thing() -> C
148 308..321 'c::C::thing()': C 148 308..321 'c::C::thing()': C
149 "### 149 "#]],
150 ); 150 );
151} 151}
152 152
153#[test] 153#[test]
154fn infer_associated_method_generics() { 154fn infer_associated_method_generics() {
155 assert_snapshot!( 155 check_infer(
156 infer(r#" 156 r#"
157struct Gen<T> { 157 struct Gen<T> {
158 val: T 158 val: T
159} 159 }
160 160
161impl<T> Gen<T> { 161 impl<T> Gen<T> {
162 pub fn make(val: T) -> Gen<T> { 162 pub fn make(val: T) -> Gen<T> {
163 Gen { val } 163 Gen { val }
164 } 164 }
165} 165 }
166 166
167fn test() { 167 fn test() {
168 let a = Gen::make(0u32); 168 let a = Gen::make(0u32);
169} 169 }
170"#), 170 "#,
171 @r###" 171 expect![[r#"
172 63..66 'val': T 172 63..66 'val': T
173 81..108 '{ ... }': Gen<T> 173 81..108 '{ ... }': Gen<T>
174 91..102 'Gen { val }': Gen<T> 174 91..102 'Gen { val }': Gen<T>
175 97..100 'val': T 175 97..100 'val': T
176 122..154 '{ ...32); }': () 176 122..154 '{ ...32); }': ()
177 132..133 'a': Gen<u32> 177 132..133 'a': Gen<u32>
178 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> 178 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32>
179 136..151 'Gen::make(0u32)': Gen<u32> 179 136..151 'Gen::make(0u32)': Gen<u32>
180 146..150 '0u32': u32 180 146..150 '0u32': u32
181 "### 181 "#]],
182 ); 182 );
183} 183}
184 184
185#[test] 185#[test]
186fn infer_associated_method_generics_without_args() { 186fn infer_associated_method_generics_without_args() {
187 assert_snapshot!( 187 check_infer(
188 infer(r#" 188 r#"
189struct Gen<T> { 189 struct Gen<T> {
190 val: T 190 val: T
191} 191 }
192 192
193impl<T> Gen<T> { 193 impl<T> Gen<T> {
194 pub fn make() -> Gen<T> { 194 pub fn make() -> Gen<T> {
195 loop { } 195 loop { }
196 } 196 }
197} 197 }
198 198
199fn test() { 199 fn test() {
200 let a = Gen::<u32>::make(); 200 let a = Gen::<u32>::make();
201} 201 }
202"#), 202 "#,
203 @r###" 203 expect![[r#"
204 75..99 '{ ... }': Gen<T> 204 75..99 '{ ... }': Gen<T>
205 85..93 'loop { }': ! 205 85..93 'loop { }': !
206 90..93 '{ }': () 206 90..93 '{ }': ()
207 113..148 '{ ...e(); }': () 207 113..148 '{ ...e(); }': ()
208 123..124 'a': Gen<u32> 208 123..124 'a': Gen<u32>
209 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> 209 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32>
210 127..145 'Gen::<...make()': Gen<u32> 210 127..145 'Gen::<...make()': Gen<u32>
211 "### 211 "#]],
212 ); 212 );
213} 213}
214 214
215#[test] 215#[test]
216fn infer_associated_method_generics_2_type_params_without_args() { 216fn infer_associated_method_generics_2_type_params_without_args() {
217 assert_snapshot!( 217 check_infer(
218 infer(r#" 218 r#"
219struct Gen<T, U> { 219 struct Gen<T, U> {
220 val: T, 220 val: T,
221 val2: U, 221 val2: U,
222} 222 }
223 223
224impl<T> Gen<u32, T> { 224 impl<T> Gen<u32, T> {
225 pub fn make() -> Gen<u32,T> { 225 pub fn make() -> Gen<u32,T> {
226 loop { } 226 loop { }
227 } 227 }
228} 228 }
229 229
230fn test() { 230 fn test() {
231 let a = Gen::<u32, u64>::make(); 231 let a = Gen::<u32, u64>::make();
232} 232 }
233"#), 233 "#,
234 @r###" 234 expect![[r#"
235 101..125 '{ ... }': Gen<u32, T> 235 101..125 '{ ... }': Gen<u32, T>
236 111..119 'loop { }': ! 236 111..119 'loop { }': !
237 116..119 '{ }': () 237 116..119 '{ }': ()
238 139..179 '{ ...e(); }': () 238 139..179 '{ ...e(); }': ()
239 149..150 'a': Gen<u32, u64> 239 149..150 'a': Gen<u32, u64>
240 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> 240 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64>
241 153..176 'Gen::<...make()': Gen<u32, u64> 241 153..176 'Gen::<...make()': Gen<u32, u64>
242 "### 242 "#]],
243 ); 243 );
244} 244}
245 245
@@ -267,416 +267,416 @@ mod foo {
267#[test] 267#[test]
268fn infer_trait_method_simple() { 268fn infer_trait_method_simple() {
269 // the trait implementation is intentionally incomplete -- it shouldn't matter 269 // the trait implementation is intentionally incomplete -- it shouldn't matter
270 assert_snapshot!( 270 check_infer(
271 infer(r#" 271 r#"
272trait Trait1 { 272 trait Trait1 {
273 fn method(&self) -> u32; 273 fn method(&self) -> u32;
274} 274 }
275struct S1; 275 struct S1;
276impl Trait1 for S1 {} 276 impl Trait1 for S1 {}
277trait Trait2 { 277 trait Trait2 {
278 fn method(&self) -> i128; 278 fn method(&self) -> i128;
279} 279 }
280struct S2; 280 struct S2;
281impl Trait2 for S2 {} 281 impl Trait2 for S2 {}
282fn test() { 282 fn test() {
283 S1.method(); // -> u32 283 S1.method(); // -> u32
284 S2.method(); // -> i128 284 S2.method(); // -> i128
285} 285 }
286"#), 286 "#,
287 @r###" 287 expect![[r#"
288 30..34 'self': &Self 288 30..34 'self': &Self
289 109..113 'self': &Self 289 109..113 'self': &Self
290 169..227 '{ ...i128 }': () 290 169..227 '{ ...i128 }': ()
291 175..177 'S1': S1 291 175..177 'S1': S1
292 175..186 'S1.method()': u32 292 175..186 'S1.method()': u32
293 202..204 'S2': S2 293 202..204 'S2': S2
294 202..213 'S2.method()': i128 294 202..213 'S2.method()': i128
295 "### 295 "#]],
296 ); 296 );
297} 297}
298 298
299#[test] 299#[test]
300fn infer_trait_method_scoped() { 300fn infer_trait_method_scoped() {
301 // the trait implementation is intentionally incomplete -- it shouldn't matter 301 // the trait implementation is intentionally incomplete -- it shouldn't matter
302 assert_snapshot!( 302 check_infer(
303 infer(r#" 303 r#"
304struct S; 304 struct S;
305mod foo { 305 mod foo {
306 pub trait Trait1 { 306 pub trait Trait1 {
307 fn method(&self) -> u32; 307 fn method(&self) -> u32;
308 } 308 }
309 impl Trait1 for super::S {} 309 impl Trait1 for super::S {}
310} 310 }
311mod bar { 311 mod bar {
312 pub trait Trait2 { 312 pub trait Trait2 {
313 fn method(&self) -> i128; 313 fn method(&self) -> i128;
314 } 314 }
315 impl Trait2 for super::S {} 315 impl Trait2 for super::S {}
316} 316 }
317 317
318mod foo_test { 318 mod foo_test {
319 use super::S; 319 use super::S;
320 use super::foo::Trait1; 320 use super::foo::Trait1;
321 fn test() { 321 fn test() {
322 S.method(); // -> u32 322 S.method(); // -> u32
323 } 323 }
324} 324 }
325 325
326mod bar_test { 326 mod bar_test {
327 use super::S; 327 use super::S;
328 use super::bar::Trait2; 328 use super::bar::Trait2;
329 fn test() { 329 fn test() {
330 S.method(); // -> i128 330 S.method(); // -> i128
331 } 331 }
332} 332 }
333"#), 333 "#,
334 @r###" 334 expect![[r#"
335 62..66 'self': &Self 335 62..66 'self': &Self
336 168..172 'self': &Self 336 168..172 'self': &Self
337 299..336 '{ ... }': () 337 299..336 '{ ... }': ()
338 309..310 'S': S 338 309..310 'S': S
339 309..319 'S.method()': u32 339 309..319 'S.method()': u32
340 415..453 '{ ... }': () 340 415..453 '{ ... }': ()
341 425..426 'S': S 341 425..426 'S': S
342 425..435 'S.method()': i128 342 425..435 'S.method()': i128
343 "### 343 "#]],
344 ); 344 );
345} 345}
346 346
347#[test] 347#[test]
348fn infer_trait_method_generic_1() { 348fn infer_trait_method_generic_1() {
349 // the trait implementation is intentionally incomplete -- it shouldn't matter 349 // the trait implementation is intentionally incomplete -- it shouldn't matter
350 assert_snapshot!( 350 check_infer(
351 infer(r#" 351 r#"
352trait Trait<T> { 352 trait Trait<T> {
353 fn method(&self) -> T; 353 fn method(&self) -> T;
354} 354 }
355struct S; 355 struct S;
356impl Trait<u32> for S {} 356 impl Trait<u32> for S {}
357fn test() { 357 fn test() {
358 S.method(); 358 S.method();
359} 359 }
360"#), 360 "#,
361 @r###" 361 expect![[r#"
362 32..36 'self': &Self 362 32..36 'self': &Self
363 91..110 '{ ...d(); }': () 363 91..110 '{ ...d(); }': ()
364 97..98 'S': S 364 97..98 'S': S
365 97..107 'S.method()': u32 365 97..107 'S.method()': u32
366 "### 366 "#]],
367 ); 367 );
368} 368}
369 369
370#[test] 370#[test]
371fn infer_trait_method_generic_more_params() { 371fn infer_trait_method_generic_more_params() {
372 // the trait implementation is intentionally incomplete -- it shouldn't matter 372 // the trait implementation is intentionally incomplete -- it shouldn't matter
373 assert_snapshot!( 373 check_infer(
374 infer(r#" 374 r#"
375trait Trait<T1, T2, T3> { 375 trait Trait<T1, T2, T3> {
376 fn method1(&self) -> (T1, T2, T3); 376 fn method1(&self) -> (T1, T2, T3);
377 fn method2(&self) -> (T3, T2, T1); 377 fn method2(&self) -> (T3, T2, T1);
378} 378 }
379struct S1; 379 struct S1;
380impl Trait<u8, u16, u32> for S1 {} 380 impl Trait<u8, u16, u32> for S1 {}
381struct S2; 381 struct S2;
382impl<T> Trait<i8, i16, T> for S2 {} 382 impl<T> Trait<i8, i16, T> for S2 {}
383fn test() { 383 fn test() {
384 S1.method1(); // u8, u16, u32 384 S1.method1(); // u8, u16, u32
385 S1.method2(); // u32, u16, u8 385 S1.method2(); // u32, u16, u8
386 S2.method1(); // i8, i16, {unknown} 386 S2.method1(); // i8, i16, {unknown}
387 S2.method2(); // {unknown}, i16, i8 387 S2.method2(); // {unknown}, i16, i8
388} 388 }
389"#), 389 "#,
390 @r###" 390 expect![[r#"
391 42..46 'self': &Self 391 42..46 'self': &Self
392 81..85 'self': &Self 392 81..85 'self': &Self
393 209..360 '{ ..., i8 }': () 393 209..360 '{ ..., i8 }': ()
394 215..217 'S1': S1 394 215..217 'S1': S1
395 215..227 'S1.method1()': (u8, u16, u32) 395 215..227 'S1.method1()': (u8, u16, u32)
396 249..251 'S1': S1 396 249..251 'S1': S1
397 249..261 'S1.method2()': (u32, u16, u8) 397 249..261 'S1.method2()': (u32, u16, u8)
398 283..285 'S2': S2 398 283..285 'S2': S2
399 283..295 'S2.method1()': (i8, i16, {unknown}) 399 283..295 'S2.method1()': (i8, i16, {unknown})
400 323..325 'S2': S2 400 323..325 'S2': S2
401 323..335 'S2.method2()': ({unknown}, i16, i8) 401 323..335 'S2.method2()': ({unknown}, i16, i8)
402 "### 402 "#]],
403 ); 403 );
404} 404}
405 405
406#[test] 406#[test]
407fn infer_trait_method_generic_2() { 407fn infer_trait_method_generic_2() {
408 // the trait implementation is intentionally incomplete -- it shouldn't matter 408 // the trait implementation is intentionally incomplete -- it shouldn't matter
409 assert_snapshot!( 409 check_infer(
410 infer(r#" 410 r#"
411trait Trait<T> { 411 trait Trait<T> {
412 fn method(&self) -> T; 412 fn method(&self) -> T;
413} 413 }
414struct S<T>(T); 414 struct S<T>(T);
415impl<U> Trait<U> for S<U> {} 415 impl<U> Trait<U> for S<U> {}
416fn test() { 416 fn test() {
417 S(1u32).method(); 417 S(1u32).method();
418} 418 }
419"#), 419 "#,
420 @r###" 420 expect![[r#"
421 32..36 'self': &Self 421 32..36 'self': &Self
422 101..126 '{ ...d(); }': () 422 101..126 '{ ...d(); }': ()
423 107..108 'S': S<u32>(u32) -> S<u32> 423 107..108 'S': S<u32>(u32) -> S<u32>
424 107..114 'S(1u32)': S<u32> 424 107..114 'S(1u32)': S<u32>
425 107..123 'S(1u32...thod()': u32 425 107..123 'S(1u32...thod()': u32
426 109..113 '1u32': u32 426 109..113 '1u32': u32
427 "### 427 "#]],
428 ); 428 );
429} 429}
430 430
431#[test] 431#[test]
432fn infer_trait_assoc_method() { 432fn infer_trait_assoc_method() {
433 assert_snapshot!( 433 check_infer(
434 infer(r#" 434 r#"
435trait Default { 435 trait Default {
436 fn default() -> Self; 436 fn default() -> Self;
437} 437 }
438struct S; 438 struct S;
439impl Default for S {} 439 impl Default for S {}
440fn test() { 440 fn test() {
441 let s1: S = Default::default(); 441 let s1: S = Default::default();
442 let s2 = S::default(); 442 let s2 = S::default();
443 let s3 = <S as Default>::default(); 443 let s3 = <S as Default>::default();
444} 444 }
445"#), 445 "#,
446 @r###" 446 expect![[r#"
447 86..192 '{ ...t(); }': () 447 86..192 '{ ...t(); }': ()
448 96..98 's1': S 448 96..98 's1': S
449 104..120 'Defaul...efault': fn default<S>() -> S 449 104..120 'Defaul...efault': fn default<S>() -> S
450 104..122 'Defaul...ault()': S 450 104..122 'Defaul...ault()': S
451 132..134 's2': S 451 132..134 's2': S
452 137..147 'S::default': fn default<S>() -> S 452 137..147 'S::default': fn default<S>() -> S
453 137..149 'S::default()': S 453 137..149 'S::default()': S
454 159..161 's3': S 454 159..161 's3': S
455 164..187 '<S as ...efault': fn default<S>() -> S 455 164..187 '<S as ...efault': fn default<S>() -> S
456 164..189 '<S as ...ault()': S 456 164..189 '<S as ...ault()': S
457 "### 457 "#]],
458 ); 458 );
459} 459}
460 460
461#[test] 461#[test]
462fn infer_trait_assoc_method_generics_1() { 462fn infer_trait_assoc_method_generics_1() {
463 assert_snapshot!( 463 check_infer(
464 infer(r#" 464 r#"
465trait Trait<T> { 465 trait Trait<T> {
466 fn make() -> T; 466 fn make() -> T;
467} 467 }
468struct S; 468 struct S;
469impl Trait<u32> for S {} 469 impl Trait<u32> for S {}
470struct G<T>; 470 struct G<T>;
471impl<T> Trait<T> for G<T> {} 471 impl<T> Trait<T> for G<T> {}
472fn test() { 472 fn test() {
473 let a = S::make(); 473 let a = S::make();
474 let b = G::<u64>::make(); 474 let b = G::<u64>::make();
475 let c: f64 = G::make(); 475 let c: f64 = G::make();
476} 476 }
477"#), 477 "#,
478 @r###" 478 expect![[r#"
479 126..210 '{ ...e(); }': () 479 126..210 '{ ...e(); }': ()
480 136..137 'a': u32 480 136..137 'a': u32
481 140..147 'S::make': fn make<S, u32>() -> u32 481 140..147 'S::make': fn make<S, u32>() -> u32
482 140..149 'S::make()': u32 482 140..149 'S::make()': u32
483 159..160 'b': u64 483 159..160 'b': u64
484 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64 484 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64
485 163..179 'G::<u6...make()': u64 485 163..179 'G::<u6...make()': u64
486 189..190 'c': f64 486 189..190 'c': f64
487 198..205 'G::make': fn make<G<f64>, f64>() -> f64 487 198..205 'G::make': fn make<G<f64>, f64>() -> f64
488 198..207 'G::make()': f64 488 198..207 'G::make()': f64
489 "### 489 "#]],
490 ); 490 );
491} 491}
492 492
493#[test] 493#[test]
494fn infer_trait_assoc_method_generics_2() { 494fn infer_trait_assoc_method_generics_2() {
495 assert_snapshot!( 495 check_infer(
496 infer(r#" 496 r#"
497trait Trait<T> { 497 trait Trait<T> {
498 fn make<U>() -> (T, U); 498 fn make<U>() -> (T, U);
499} 499 }
500struct S; 500 struct S;
501impl Trait<u32> for S {} 501 impl Trait<u32> for S {}
502struct G<T>; 502 struct G<T>;
503impl<T> Trait<T> for G<T> {} 503 impl<T> Trait<T> for G<T> {}
504fn test() { 504 fn test() {
505 let a = S::make::<i64>(); 505 let a = S::make::<i64>();
506 let b: (_, i64) = S::make(); 506 let b: (_, i64) = S::make();
507 let c = G::<u32>::make::<i64>(); 507 let c = G::<u32>::make::<i64>();
508 let d: (u32, _) = G::make::<i64>(); 508 let d: (u32, _) = G::make::<i64>();
509 let e: (u32, i64) = G::make(); 509 let e: (u32, i64) = G::make();
510} 510 }
511"#), 511 "#,
512 @r###" 512 expect![[r#"
513 134..312 '{ ...e(); }': () 513 134..312 '{ ...e(); }': ()
514 144..145 'a': (u32, i64) 514 144..145 'a': (u32, i64)
515 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64) 515 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64)
516 148..164 'S::mak...i64>()': (u32, i64) 516 148..164 'S::mak...i64>()': (u32, i64)
517 174..175 'b': (u32, i64) 517 174..175 'b': (u32, i64)
518 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64) 518 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64)
519 188..197 'S::make()': (u32, i64) 519 188..197 'S::make()': (u32, i64)
520 207..208 'c': (u32, i64) 520 207..208 'c': (u32, i64)
521 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) 521 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
522 211..234 'G::<u3...i64>()': (u32, i64) 522 211..234 'G::<u3...i64>()': (u32, i64)
523 244..245 'd': (u32, i64) 523 244..245 'd': (u32, i64)
524 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) 524 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64)
525 258..274 'G::mak...i64>()': (u32, i64) 525 258..274 'G::mak...i64>()': (u32, i64)
526 284..285 'e': (u32, i64) 526 284..285 'e': (u32, i64)
527 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64) 527 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64)
528 300..309 'G::make()': (u32, i64) 528 300..309 'G::make()': (u32, i64)
529 "### 529 "#]],
530 ); 530 );
531} 531}
532 532
533#[test] 533#[test]
534fn infer_trait_assoc_method_generics_3() { 534fn infer_trait_assoc_method_generics_3() {
535 assert_snapshot!( 535 check_infer(
536 infer(r#" 536 r#"
537trait Trait<T> { 537 trait Trait<T> {
538 fn make() -> (Self, T); 538 fn make() -> (Self, T);
539} 539 }
540struct S<T>; 540 struct S<T>;
541impl Trait<i64> for S<i32> {} 541 impl Trait<i64> for S<i32> {}
542fn test() { 542 fn test() {
543 let a = S::make(); 543 let a = S::make();
544} 544 }
545"#), 545 "#,
546 @r###" 546 expect![[r#"
547 100..126 '{ ...e(); }': () 547 100..126 '{ ...e(); }': ()
548 110..111 'a': (S<i32>, i64) 548 110..111 'a': (S<i32>, i64)
549 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64) 549 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64)
550 114..123 'S::make()': (S<i32>, i64) 550 114..123 'S::make()': (S<i32>, i64)
551 "### 551 "#]],
552 ); 552 );
553} 553}
554 554
555#[test] 555#[test]
556fn infer_trait_assoc_method_generics_4() { 556fn infer_trait_assoc_method_generics_4() {
557 assert_snapshot!( 557 check_infer(
558 infer(r#" 558 r#"
559trait Trait<T> { 559 trait Trait<T> {
560 fn make() -> (Self, T); 560 fn make() -> (Self, T);
561} 561 }
562struct S<T>; 562 struct S<T>;
563impl Trait<i64> for S<u64> {} 563 impl Trait<i64> for S<u64> {}
564impl Trait<i32> for S<u32> {} 564 impl Trait<i32> for S<u32> {}
565fn test() { 565 fn test() {
566 let a: (S<u64>, _) = S::make(); 566 let a: (S<u64>, _) = S::make();
567 let b: (_, i32) = S::make(); 567 let b: (_, i32) = S::make();
568} 568 }
569"#), 569 "#,
570 @r###" 570 expect![[r#"
571 130..202 '{ ...e(); }': () 571 130..202 '{ ...e(); }': ()
572 140..141 'a': (S<u64>, i64) 572 140..141 'a': (S<u64>, i64)
573 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64) 573 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64)
574 157..166 'S::make()': (S<u64>, i64) 574 157..166 'S::make()': (S<u64>, i64)
575 176..177 'b': (S<u32>, i32) 575 176..177 'b': (S<u32>, i32)
576 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32) 576 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32)
577 190..199 'S::make()': (S<u32>, i32) 577 190..199 'S::make()': (S<u32>, i32)
578 "### 578 "#]],
579 ); 579 );
580} 580}
581 581
582#[test] 582#[test]
583fn infer_trait_assoc_method_generics_5() { 583fn infer_trait_assoc_method_generics_5() {
584 assert_snapshot!( 584 check_infer(
585 infer(r#" 585 r#"
586trait Trait<T> { 586 trait Trait<T> {
587 fn make<U>() -> (Self, T, U); 587 fn make<U>() -> (Self, T, U);
588} 588 }
589struct S<T>; 589 struct S<T>;
590impl Trait<i64> for S<u64> {} 590 impl Trait<i64> for S<u64> {}
591fn test() { 591 fn test() {
592 let a = <S as Trait<i64>>::make::<u8>(); 592 let a = <S as Trait<i64>>::make::<u8>();
593 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); 593 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
594} 594 }
595"#), 595 "#,
596 @r###" 596 expect![[r#"
597 106..210 '{ ...>(); }': () 597 106..210 '{ ...>(); }': ()
598 116..117 'a': (S<u64>, i64, u8) 598 116..117 'a': (S<u64>, i64, u8)
599 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) 599 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
600 120..151 '<S as ...<u8>()': (S<u64>, i64, u8) 600 120..151 '<S as ...<u8>()': (S<u64>, i64, u8)
601 161..162 'b': (S<u64>, i64, u8) 601 161..162 'b': (S<u64>, i64, u8)
602 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) 602 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8)
603 181..207 'Trait:...<u8>()': (S<u64>, i64, u8) 603 181..207 'Trait:...<u8>()': (S<u64>, i64, u8)
604 "### 604 "#]],
605 ); 605 );
606} 606}
607 607
608#[test] 608#[test]
609fn infer_call_trait_method_on_generic_param_1() { 609fn infer_call_trait_method_on_generic_param_1() {
610 assert_snapshot!( 610 check_infer(
611 infer(r#" 611 r#"
612trait Trait { 612 trait Trait {
613 fn method(&self) -> u32; 613 fn method(&self) -> u32;
614} 614 }
615fn test<T: Trait>(t: T) { 615 fn test<T: Trait>(t: T) {
616 t.method(); 616 t.method();
617} 617 }
618"#), 618 "#,
619 @r###" 619 expect![[r#"
620 29..33 'self': &Self 620 29..33 'self': &Self
621 63..64 't': T 621 63..64 't': T
622 69..88 '{ ...d(); }': () 622 69..88 '{ ...d(); }': ()
623 75..76 't': T 623 75..76 't': T
624 75..85 't.method()': u32 624 75..85 't.method()': u32
625 "### 625 "#]],
626 ); 626 );
627} 627}
628 628
629#[test] 629#[test]
630fn infer_call_trait_method_on_generic_param_2() { 630fn infer_call_trait_method_on_generic_param_2() {
631 assert_snapshot!( 631 check_infer(
632 infer(r#" 632 r#"
633trait Trait<T> { 633 trait Trait<T> {
634 fn method(&self) -> T; 634 fn method(&self) -> T;
635} 635 }
636fn test<U, T: Trait<U>>(t: T) { 636 fn test<U, T: Trait<U>>(t: T) {
637 t.method(); 637 t.method();
638} 638 }
639"#), 639 "#,
640 @r###" 640 expect![[r#"
641 32..36 'self': &Self 641 32..36 'self': &Self
642 70..71 't': T 642 70..71 't': T
643 76..95 '{ ...d(); }': () 643 76..95 '{ ...d(); }': ()
644 82..83 't': T 644 82..83 't': T
645 82..92 't.method()': U 645 82..92 't.method()': U
646 "### 646 "#]],
647 ); 647 );
648} 648}
649 649
650#[test] 650#[test]
651fn infer_with_multiple_trait_impls() { 651fn infer_with_multiple_trait_impls() {
652 assert_snapshot!( 652 check_infer(
653 infer(r#" 653 r#"
654trait Into<T> { 654 trait Into<T> {
655 fn into(self) -> T; 655 fn into(self) -> T;
656} 656 }
657struct S; 657 struct S;
658impl Into<u32> for S {} 658 impl Into<u32> for S {}
659impl Into<u64> for S {} 659 impl Into<u64> for S {}
660fn test() { 660 fn test() {
661 let x: u32 = S.into(); 661 let x: u32 = S.into();
662 let y: u64 = S.into(); 662 let y: u64 = S.into();
663 let z = Into::<u64>::into(S); 663 let z = Into::<u64>::into(S);
664} 664 }
665"#), 665 "#,
666 @r###" 666 expect![[r#"
667 28..32 'self': Self 667 28..32 'self': Self
668 110..201 '{ ...(S); }': () 668 110..201 '{ ...(S); }': ()
669 120..121 'x': u32 669 120..121 'x': u32
670 129..130 'S': S 670 129..130 'S': S
671 129..137 'S.into()': u32 671 129..137 'S.into()': u32
672 147..148 'y': u64 672 147..148 'y': u64
673 156..157 'S': S 673 156..157 'S': S
674 156..164 'S.into()': u64 674 156..164 'S.into()': u64
675 174..175 'z': u64 675 174..175 'z': u64
676 178..195 'Into::...::into': fn into<S, u64>(S) -> u64 676 178..195 'Into::...::into': fn into<S, u64>(S) -> u64
677 178..198 'Into::...nto(S)': u64 677 178..198 'Into::...nto(S)': u64
678 196..197 'S': S 678 196..197 'S': S
679 "### 679 "#]],
680 ); 680 );
681} 681}
682 682
@@ -1023,31 +1023,31 @@ fn test() { (S {}).method(); }
1023 1023
1024#[test] 1024#[test]
1025fn dyn_trait_super_trait_not_in_scope() { 1025fn dyn_trait_super_trait_not_in_scope() {
1026 assert_snapshot!( 1026 check_infer(
1027 infer(r#" 1027 r#"
1028mod m { 1028 mod m {
1029 pub trait SuperTrait { 1029 pub trait SuperTrait {
1030 fn foo(&self) -> u32 { 0 } 1030 fn foo(&self) -> u32 { 0 }
1031 } 1031 }
1032} 1032 }
1033trait Trait: m::SuperTrait {} 1033 trait Trait: m::SuperTrait {}
1034 1034
1035struct S; 1035 struct S;
1036impl m::SuperTrait for S {} 1036 impl m::SuperTrait for S {}
1037impl Trait for S {} 1037 impl Trait for S {}
1038 1038
1039fn test(d: &dyn Trait) { 1039 fn test(d: &dyn Trait) {
1040 d.foo(); 1040 d.foo();
1041} 1041 }
1042"#), 1042 "#,
1043 @r###" 1043 expect![[r#"
1044 51..55 'self': &Self 1044 51..55 'self': &Self
1045 64..69 '{ 0 }': u32 1045 64..69 '{ 0 }': u32
1046 66..67 '0': u32 1046 66..67 '0': u32
1047 176..177 'd': &dyn Trait 1047 176..177 'd': &dyn Trait
1048 191..207 '{ ...o(); }': () 1048 191..207 '{ ...o(); }': ()
1049 197..198 'd': &dyn Trait 1049 197..198 'd': &dyn Trait
1050 197..204 'd.foo()': u32 1050 197..204 'd.foo()': u32
1051 "### 1051 "#]],
1052 ); 1052 );
1053} 1053}
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index 64d421d40..49538b572 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,6 +1,6 @@
1use insta::assert_snapshot; 1use expect::expect;
2 2
3use super::{check_types, infer_with_mismatches}; 3use super::{check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_never1() { 6fn infer_never1() {
@@ -240,173 +240,170 @@ fn test(a: i32) {
240 240
241#[test] 241#[test]
242fn diverging_expression_1() { 242fn diverging_expression_1() {
243 let t = infer_with_mismatches( 243 check_infer_with_mismatches(
244 r#" 244 r"
245//- /main.rs 245 //- /main.rs
246fn test1() { 246 fn test1() {
247 let x: u32 = return; 247 let x: u32 = return;
248} 248 }
249fn test2() { 249 fn test2() {
250 let x: u32 = { return; }; 250 let x: u32 = { return; };
251} 251 }
252fn test3() { 252 fn test3() {
253 let x: u32 = loop {}; 253 let x: u32 = loop {};
254} 254 }
255fn test4() { 255 fn test4() {
256 let x: u32 = { loop {} }; 256 let x: u32 = { loop {} };
257} 257 }
258fn test5() { 258 fn test5() {
259 let x: u32 = { if true { loop {}; } else { loop {}; } }; 259 let x: u32 = { if true { loop {}; } else { loop {}; } };
260} 260 }
261fn test6() { 261 fn test6() {
262 let x: u32 = { let y: u32 = { loop {}; }; }; 262 let x: u32 = { let y: u32 = { loop {}; }; };
263} 263 }
264"#, 264 ",
265 true, 265 expect![[r"
266 11..39 '{ ...urn; }': ()
267 21..22 'x': u32
268 30..36 'return': !
269 51..84 '{ ...; }; }': ()
270 61..62 'x': u32
271 70..81 '{ return; }': u32
272 72..78 'return': !
273 96..125 '{ ... {}; }': ()
274 106..107 'x': u32
275 115..122 'loop {}': !
276 120..122 '{}': ()
277 137..170 '{ ...} }; }': ()
278 147..148 'x': u32
279 156..167 '{ loop {} }': u32
280 158..165 'loop {}': !
281 163..165 '{}': ()
282 182..246 '{ ...} }; }': ()
283 192..193 'x': u32
284 201..243 '{ if t...}; } }': u32
285 203..241 'if tru... {}; }': u32
286 206..210 'true': bool
287 211..223 '{ loop {}; }': u32
288 213..220 'loop {}': !
289 218..220 '{}': ()
290 229..241 '{ loop {}; }': u32
291 231..238 'loop {}': !
292 236..238 '{}': ()
293 258..310 '{ ...; }; }': ()
294 268..269 'x': u32
295 277..307 '{ let ...; }; }': u32
296 283..284 'y': u32
297 292..304 '{ loop {}; }': u32
298 294..301 'loop {}': !
299 299..301 '{}': ()
300 "]],
266 ); 301 );
267 assert_snapshot!(t, @r###"
268 11..39 '{ ...urn; }': ()
269 21..22 'x': u32
270 30..36 'return': !
271 51..84 '{ ...; }; }': ()
272 61..62 'x': u32
273 70..81 '{ return; }': u32
274 72..78 'return': !
275 96..125 '{ ... {}; }': ()
276 106..107 'x': u32
277 115..122 'loop {}': !
278 120..122 '{}': ()
279 137..170 '{ ...} }; }': ()
280 147..148 'x': u32
281 156..167 '{ loop {} }': u32
282 158..165 'loop {}': !
283 163..165 '{}': ()
284 182..246 '{ ...} }; }': ()
285 192..193 'x': u32
286 201..243 '{ if t...}; } }': u32
287 203..241 'if tru... {}; }': u32
288 206..210 'true': bool
289 211..223 '{ loop {}; }': u32
290 213..220 'loop {}': !
291 218..220 '{}': ()
292 229..241 '{ loop {}; }': u32
293 231..238 'loop {}': !
294 236..238 '{}': ()
295 258..310 '{ ...; }; }': ()
296 268..269 'x': u32
297 277..307 '{ let ...; }; }': u32
298 283..284 'y': u32
299 292..304 '{ loop {}; }': u32
300 294..301 'loop {}': !
301 299..301 '{}': ()
302 "###);
303} 302}
304 303
305#[test] 304#[test]
306fn diverging_expression_2() { 305fn diverging_expression_2() {
307 let t = infer_with_mismatches( 306 check_infer_with_mismatches(
308 r#" 307 r#"
309//- /main.rs 308 //- /main.rs
310fn test1() { 309 fn test1() {
311 // should give type mismatch 310 // should give type mismatch
312 let x: u32 = { loop {}; "foo" }; 311 let x: u32 = { loop {}; "foo" };
313} 312 }
314"#, 313 "#,
315 true, 314 expect![[r#"
315 11..84 '{ ..." }; }': ()
316 54..55 'x': u32
317 63..81 '{ loop...foo" }': &str
318 65..72 'loop {}': !
319 70..72 '{}': ()
320 74..79 '"foo"': &str
321 63..81: expected u32, got &str
322 74..79: expected u32, got &str
323 "#]],
316 ); 324 );
317 assert_snapshot!(t, @r###"
318 11..84 '{ ..." }; }': ()
319 54..55 'x': u32
320 63..81 '{ loop...foo" }': &str
321 65..72 'loop {}': !
322 70..72 '{}': ()
323 74..79 '"foo"': &str
324 63..81: expected u32, got &str
325 74..79: expected u32, got &str
326 "###);
327} 325}
328 326
329#[test] 327#[test]
330fn diverging_expression_3_break() { 328fn diverging_expression_3_break() {
331 let t = infer_with_mismatches( 329 check_infer_with_mismatches(
332 r#" 330 r"
333//- /main.rs 331 //- /main.rs
334fn test1() { 332 fn test1() {
335 // should give type mismatch 333 // should give type mismatch
336 let x: u32 = { loop { break; } }; 334 let x: u32 = { loop { break; } };
337} 335 }
338fn test2() { 336 fn test2() {
339 // should give type mismatch 337 // should give type mismatch
340 let x: u32 = { for a in b { break; }; }; 338 let x: u32 = { for a in b { break; }; };
341 // should give type mismatch as well 339 // should give type mismatch as well
342 let x: u32 = { for a in b {}; }; 340 let x: u32 = { for a in b {}; };
343 // should give type mismatch as well 341 // should give type mismatch as well
344 let x: u32 = { for a in b { return; }; }; 342 let x: u32 = { for a in b { return; }; };
345} 343 }
346fn test3() { 344 fn test3() {
347 // should give type mismatch 345 // should give type mismatch
348 let x: u32 = { while true { break; }; }; 346 let x: u32 = { while true { break; }; };
349 // should give type mismatch as well -- there's an implicit break, even if it's never hit 347 // should give type mismatch as well -- there's an implicit break, even if it's never hit
350 let x: u32 = { while true {}; }; 348 let x: u32 = { while true {}; };
351 // should give type mismatch as well 349 // should give type mismatch as well
352 let x: u32 = { while true { return; }; }; 350 let x: u32 = { while true { return; }; };
353} 351 }
354"#, 352 ",
355 true, 353 expect![[r"
354 11..85 '{ ...} }; }': ()
355 54..55 'x': u32
356 63..82 '{ loop...k; } }': ()
357 65..80 'loop { break; }': ()
358 70..80 '{ break; }': ()
359 72..77 'break': !
360 63..82: expected u32, got ()
361 65..80: expected u32, got ()
362 97..343 '{ ...; }; }': ()
363 140..141 'x': u32
364 149..175 '{ for ...; }; }': ()
365 151..172 'for a ...eak; }': ()
366 155..156 'a': {unknown}
367 160..161 'b': {unknown}
368 162..172 '{ break; }': ()
369 164..169 'break': !
370 226..227 'x': u32
371 235..253 '{ for ... {}; }': ()
372 237..250 'for a in b {}': ()
373 241..242 'a': {unknown}
374 246..247 'b': {unknown}
375 248..250 '{}': ()
376 304..305 'x': u32
377 313..340 '{ for ...; }; }': ()
378 315..337 'for a ...urn; }': ()
379 319..320 'a': {unknown}
380 324..325 'b': {unknown}
381 326..337 '{ return; }': ()
382 328..334 'return': !
383 149..175: expected u32, got ()
384 235..253: expected u32, got ()
385 313..340: expected u32, got ()
386 355..654 '{ ...; }; }': ()
387 398..399 'x': u32
388 407..433 '{ whil...; }; }': ()
389 409..430 'while ...eak; }': ()
390 415..419 'true': bool
391 420..430 '{ break; }': ()
392 422..427 'break': !
393 537..538 'x': u32
394 546..564 '{ whil... {}; }': ()
395 548..561 'while true {}': ()
396 554..558 'true': bool
397 559..561 '{}': ()
398 615..616 'x': u32
399 624..651 '{ whil...; }; }': ()
400 626..648 'while ...urn; }': ()
401 632..636 'true': bool
402 637..648 '{ return; }': ()
403 639..645 'return': !
404 407..433: expected u32, got ()
405 546..564: expected u32, got ()
406 624..651: expected u32, got ()
407 "]],
356 ); 408 );
357 assert_snapshot!(t, @r###"
358 11..85 '{ ...} }; }': ()
359 54..55 'x': u32
360 63..82 '{ loop...k; } }': ()
361 65..80 'loop { break; }': ()
362 70..80 '{ break; }': ()
363 72..77 'break': !
364 63..82: expected u32, got ()
365 65..80: expected u32, got ()
366 97..343 '{ ...; }; }': ()
367 140..141 'x': u32
368 149..175 '{ for ...; }; }': ()
369 151..172 'for a ...eak; }': ()
370 155..156 'a': {unknown}
371 160..161 'b': {unknown}
372 162..172 '{ break; }': ()
373 164..169 'break': !
374 226..227 'x': u32
375 235..253 '{ for ... {}; }': ()
376 237..250 'for a in b {}': ()
377 241..242 'a': {unknown}
378 246..247 'b': {unknown}
379 248..250 '{}': ()
380 304..305 'x': u32
381 313..340 '{ for ...; }; }': ()
382 315..337 'for a ...urn; }': ()
383 319..320 'a': {unknown}
384 324..325 'b': {unknown}
385 326..337 '{ return; }': ()
386 328..334 'return': !
387 149..175: expected u32, got ()
388 235..253: expected u32, got ()
389 313..340: expected u32, got ()
390 355..654 '{ ...; }; }': ()
391 398..399 'x': u32
392 407..433 '{ whil...; }; }': ()
393 409..430 'while ...eak; }': ()
394 415..419 'true': bool
395 420..430 '{ break; }': ()
396 422..427 'break': !
397 537..538 'x': u32
398 546..564 '{ whil... {}; }': ()
399 548..561 'while true {}': ()
400 554..558 'true': bool
401 559..561 '{}': ()
402 615..616 'x': u32
403 624..651 '{ whil...; }; }': ()
404 626..648 'while ...urn; }': ()
405 632..636 'true': bool
406 637..648 '{ return; }': ()
407 639..645 'return': !
408 407..433: expected u32, got ()
409 546..564: expected u32, got ()
410 624..651: expected u32, got ()
411 "###);
412} 409}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index f937426bd..39fabf7eb 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,561 +1,561 @@
1use insta::assert_snapshot; 1use expect::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{infer, infer_with_mismatches}; 4use super::{check_infer, check_infer_with_mismatches};
5 5
6#[test] 6#[test]
7fn infer_pattern() { 7fn infer_pattern() {
8 assert_snapshot!( 8 check_infer(
9 infer(r#" 9 r#"
10fn test(x: &i32) { 10 fn test(x: &i32) {
11 let y = x; 11 let y = x;
12 let &z = x; 12 let &z = x;
13 let a = z; 13 let a = z;
14 let (c, d) = (1, "hello"); 14 let (c, d) = (1, "hello");
15 15
16 for (e, f) in some_iter { 16 for (e, f) in some_iter {
17 let g = e; 17 let g = e;
18 } 18 }
19 19
20 if let [val] = opt { 20 if let [val] = opt {
21 let h = val; 21 let h = val;
22 } 22 }
23 23
24 let lambda = |a: u64, b, c: i32| { a + b; c }; 24 let lambda = |a: u64, b, c: i32| { a + b; c };
25 25
26 let ref ref_to_x = x; 26 let ref ref_to_x = x;
27 let mut mut_x = x; 27 let mut mut_x = x;
28 let ref mut mut_ref_to_x = x; 28 let ref mut mut_ref_to_x = x;
29 let k = mut_ref_to_x; 29 let k = mut_ref_to_x;
30} 30 }
31"#), 31 "#,
32 @r###" 32 expect![[r#"
33 8..9 'x': &i32 33 8..9 'x': &i32
34 17..368 '{ ...o_x; }': () 34 17..368 '{ ...o_x; }': ()
35 27..28 'y': &i32 35 27..28 'y': &i32
36 31..32 'x': &i32 36 31..32 'x': &i32
37 42..44 '&z': &i32 37 42..44 '&z': &i32
38 43..44 'z': i32 38 43..44 'z': i32
39 47..48 'x': &i32 39 47..48 'x': &i32
40 58..59 'a': i32 40 58..59 'a': i32
41 62..63 'z': i32 41 62..63 'z': i32
42 73..79 '(c, d)': (i32, &str) 42 73..79 '(c, d)': (i32, &str)
43 74..75 'c': i32 43 74..75 'c': i32
44 77..78 'd': &str 44 77..78 'd': &str
45 82..94 '(1, "hello")': (i32, &str) 45 82..94 '(1, "hello")': (i32, &str)
46 83..84 '1': i32 46 83..84 '1': i32
47 86..93 '"hello"': &str 47 86..93 '"hello"': &str
48 101..151 'for (e... }': () 48 101..151 'for (e... }': ()
49 105..111 '(e, f)': ({unknown}, {unknown}) 49 105..111 '(e, f)': ({unknown}, {unknown})
50 106..107 'e': {unknown} 50 106..107 'e': {unknown}
51 109..110 'f': {unknown} 51 109..110 'f': {unknown}
52 115..124 'some_iter': {unknown} 52 115..124 'some_iter': {unknown}
53 125..151 '{ ... }': () 53 125..151 '{ ... }': ()
54 139..140 'g': {unknown} 54 139..140 'g': {unknown}
55 143..144 'e': {unknown} 55 143..144 'e': {unknown}
56 157..204 'if let... }': () 56 157..204 'if let... }': ()
57 164..169 '[val]': [{unknown}] 57 164..169 '[val]': [{unknown}]
58 165..168 'val': {unknown} 58 165..168 'val': {unknown}
59 172..175 'opt': [{unknown}] 59 172..175 'opt': [{unknown}]
60 176..204 '{ ... }': () 60 176..204 '{ ... }': ()
61 190..191 'h': {unknown} 61 190..191 'h': {unknown}
62 194..197 'val': {unknown} 62 194..197 'val': {unknown}
63 214..220 'lambda': |u64, u64, i32| -> i32 63 214..220 'lambda': |u64, u64, i32| -> i32
64 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 64 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32
65 224..225 'a': u64 65 224..225 'a': u64
66 232..233 'b': u64 66 232..233 'b': u64
67 235..236 'c': i32 67 235..236 'c': i32
68 243..255 '{ a + b; c }': i32 68 243..255 '{ a + b; c }': i32
69 245..246 'a': u64 69 245..246 'a': u64
70 245..250 'a + b': u64 70 245..250 'a + b': u64
71 249..250 'b': u64 71 249..250 'b': u64
72 252..253 'c': i32 72 252..253 'c': i32
73 266..278 'ref ref_to_x': &&i32 73 266..278 'ref ref_to_x': &&i32
74 281..282 'x': &i32 74 281..282 'x': &i32
75 292..301 'mut mut_x': &i32 75 292..301 'mut mut_x': &i32
76 304..305 'x': &i32 76 304..305 'x': &i32
77 315..335 'ref mu...f_to_x': &mut &i32 77 315..335 'ref mu...f_to_x': &mut &i32
78 338..339 'x': &i32 78 338..339 'x': &i32
79 349..350 'k': &mut &i32 79 349..350 'k': &mut &i32
80 353..365 'mut_ref_to_x': &mut &i32 80 353..365 'mut_ref_to_x': &mut &i32
81 "### 81 "#]],
82 ); 82 );
83} 83}
84 84
85#[test] 85#[test]
86fn infer_literal_pattern() { 86fn infer_literal_pattern() {
87 assert_snapshot!( 87 check_infer_with_mismatches(
88 infer_with_mismatches(r#" 88 r#"
89fn any<T>() -> T { loop {} } 89 fn any<T>() -> T { loop {} }
90fn test(x: &i32) { 90 fn test(x: &i32) {
91 if let "foo" = any() {} 91 if let "foo" = any() {}
92 if let 1 = any() {} 92 if let 1 = any() {}
93 if let 1u32 = any() {} 93 if let 1u32 = any() {}
94 if let 1f32 = any() {} 94 if let 1f32 = any() {}
95 if let 1.0 = any() {} 95 if let 1.0 = any() {}
96 if let true = any() {} 96 if let true = any() {}
97} 97 }
98"#, true), 98 "#,
99 @r###" 99 expect![[r#"
100 17..28 '{ loop {} }': T 100 17..28 '{ loop {} }': T
101 19..26 'loop {}': ! 101 19..26 'loop {}': !
102 24..26 '{}': () 102 24..26 '{}': ()
103 37..38 'x': &i32 103 37..38 'x': &i32
104 46..208 '{ ...) {} }': () 104 46..208 '{ ...) {} }': ()
105 52..75 'if let...y() {}': () 105 52..75 'if let...y() {}': ()
106 59..64 '"foo"': &str 106 59..64 '"foo"': &str
107 59..64 '"foo"': &str 107 59..64 '"foo"': &str
108 67..70 'any': fn any<&str>() -> &str 108 67..70 'any': fn any<&str>() -> &str
109 67..72 'any()': &str 109 67..72 'any()': &str
110 73..75 '{}': () 110 73..75 '{}': ()
111 80..99 'if let...y() {}': () 111 80..99 'if let...y() {}': ()
112 87..88 '1': i32 112 87..88 '1': i32
113 87..88 '1': i32 113 87..88 '1': i32
114 91..94 'any': fn any<i32>() -> i32 114 91..94 'any': fn any<i32>() -> i32
115 91..96 'any()': i32 115 91..96 'any()': i32
116 97..99 '{}': () 116 97..99 '{}': ()
117 104..126 'if let...y() {}': () 117 104..126 'if let...y() {}': ()
118 111..115 '1u32': u32 118 111..115 '1u32': u32
119 111..115 '1u32': u32 119 111..115 '1u32': u32
120 118..121 'any': fn any<u32>() -> u32 120 118..121 'any': fn any<u32>() -> u32
121 118..123 'any()': u32 121 118..123 'any()': u32
122 124..126 '{}': () 122 124..126 '{}': ()
123 131..153 'if let...y() {}': () 123 131..153 'if let...y() {}': ()
124 138..142 '1f32': f32 124 138..142 '1f32': f32
125 138..142 '1f32': f32 125 138..142 '1f32': f32
126 145..148 'any': fn any<f32>() -> f32 126 145..148 'any': fn any<f32>() -> f32
127 145..150 'any()': f32 127 145..150 'any()': f32
128 151..153 '{}': () 128 151..153 '{}': ()
129 158..179 'if let...y() {}': () 129 158..179 'if let...y() {}': ()
130 165..168 '1.0': f64 130 165..168 '1.0': f64
131 165..168 '1.0': f64 131 165..168 '1.0': f64
132 171..174 'any': fn any<f64>() -> f64 132 171..174 'any': fn any<f64>() -> f64
133 171..176 'any()': f64 133 171..176 'any()': f64
134 177..179 '{}': () 134 177..179 '{}': ()
135 184..206 'if let...y() {}': () 135 184..206 'if let...y() {}': ()
136 191..195 'true': bool 136 191..195 'true': bool
137 191..195 'true': bool 137 191..195 'true': bool
138 198..201 'any': fn any<bool>() -> bool 138 198..201 'any': fn any<bool>() -> bool
139 198..203 'any()': bool 139 198..203 'any()': bool
140 204..206 '{}': () 140 204..206 '{}': ()
141 "### 141 "#]],
142 ); 142 );
143} 143}
144 144
145#[test] 145#[test]
146fn infer_range_pattern() { 146fn infer_range_pattern() {
147 assert_snapshot!( 147 check_infer_with_mismatches(
148 infer_with_mismatches(r#" 148 r#"
149fn test(x: &i32) { 149 fn test(x: &i32) {
150 if let 1..76 = 2u32 {} 150 if let 1..76 = 2u32 {}
151 if let 1..=76 = 2u32 {} 151 if let 1..=76 = 2u32 {}
152} 152 }
153"#, true), 153 "#,
154 @r###" 154 expect![[r#"
155 8..9 'x': &i32 155 8..9 'x': &i32
156 17..75 '{ ...2 {} }': () 156 17..75 '{ ...2 {} }': ()
157 23..45 'if let...u32 {}': () 157 23..45 'if let...u32 {}': ()
158 30..35 '1..76': u32 158 30..35 '1..76': u32
159 38..42 '2u32': u32 159 38..42 '2u32': u32
160 43..45 '{}': () 160 43..45 '{}': ()
161 50..73 'if let...u32 {}': () 161 50..73 'if let...u32 {}': ()
162 57..63 '1..=76': u32 162 57..63 '1..=76': u32
163 66..70 '2u32': u32 163 66..70 '2u32': u32
164 71..73 '{}': () 164 71..73 '{}': ()
165 "### 165 "#]],
166 ); 166 );
167} 167}
168 168
169#[test] 169#[test]
170fn infer_pattern_match_ergonomics() { 170fn infer_pattern_match_ergonomics() {
171 assert_snapshot!( 171 check_infer(
172 infer(r#" 172 r#"
173struct A<T>(T); 173 struct A<T>(T);
174 174
175fn test() { 175 fn test() {
176 let A(n) = &A(1); 176 let A(n) = &A(1);
177 let A(n) = &mut A(1); 177 let A(n) = &mut A(1);
178} 178 }
179"#), 179 "#,
180 @r###" 180 expect![[r#"
181 27..78 '{ ...(1); }': () 181 27..78 '{ ...(1); }': ()
182 37..41 'A(n)': A<i32> 182 37..41 'A(n)': A<i32>
183 39..40 'n': &i32 183 39..40 'n': &i32
184 44..49 '&A(1)': &A<i32> 184 44..49 '&A(1)': &A<i32>
185 45..46 'A': A<i32>(i32) -> A<i32> 185 45..46 'A': A<i32>(i32) -> A<i32>
186 45..49 'A(1)': A<i32> 186 45..49 'A(1)': A<i32>
187 47..48 '1': i32 187 47..48 '1': i32
188 59..63 'A(n)': A<i32> 188 59..63 'A(n)': A<i32>
189 61..62 'n': &mut i32 189 61..62 'n': &mut i32
190 66..75 '&mut A(1)': &mut A<i32> 190 66..75 '&mut A(1)': &mut A<i32>
191 71..72 'A': A<i32>(i32) -> A<i32> 191 71..72 'A': A<i32>(i32) -> A<i32>
192 71..75 'A(1)': A<i32> 192 71..75 'A(1)': A<i32>
193 73..74 '1': i32 193 73..74 '1': i32
194 "### 194 "#]],
195 ); 195 );
196} 196}
197 197
198#[test] 198#[test]
199fn infer_pattern_match_ergonomics_ref() { 199fn infer_pattern_match_ergonomics_ref() {
200 mark::check!(match_ergonomics_ref); 200 mark::check!(match_ergonomics_ref);
201 assert_snapshot!( 201 check_infer(
202 infer(r#" 202 r#"
203fn test() { 203 fn test() {
204 let v = &(1, &2); 204 let v = &(1, &2);
205 let (_, &w) = v; 205 let (_, &w) = v;
206} 206 }
207"#), 207 "#,
208 @r###" 208 expect![[r#"
209 10..56 '{ ...= v; }': () 209 10..56 '{ ...= v; }': ()
210 20..21 'v': &(i32, &i32) 210 20..21 'v': &(i32, &i32)
211 24..32 '&(1, &2)': &(i32, &i32) 211 24..32 '&(1, &2)': &(i32, &i32)
212 25..32 '(1, &2)': (i32, &i32) 212 25..32 '(1, &2)': (i32, &i32)
213 26..27 '1': i32 213 26..27 '1': i32
214 29..31 '&2': &i32 214 29..31 '&2': &i32
215 30..31 '2': i32 215 30..31 '2': i32
216 42..49 '(_, &w)': (i32, &i32) 216 42..49 '(_, &w)': (i32, &i32)
217 43..44 '_': i32 217 43..44 '_': i32
218 46..48 '&w': &i32 218 46..48 '&w': &i32
219 47..48 'w': i32 219 47..48 'w': i32
220 52..53 'v': &(i32, &i32) 220 52..53 'v': &(i32, &i32)
221 "### 221 "#]],
222 ); 222 );
223} 223}
224 224
225#[test] 225#[test]
226fn infer_pattern_match_slice() { 226fn infer_pattern_match_slice() {
227 assert_snapshot!( 227 check_infer(
228 infer(r#" 228 r#"
229fn test() { 229 fn test() {
230 let slice: &[f64] = &[0.0]; 230 let slice: &[f64] = &[0.0];
231 match slice { 231 match slice {
232 &[] => {}, 232 &[] => {},
233 &[a] => { 233 &[a] => {
234 a; 234 a;
235 }, 235 },
236 &[b, c] => { 236 &[b, c] => {
237 b; 237 b;
238 c; 238 c;
239 }
240 _ => {}
241 }
239 } 242 }
240 _ => {} 243 "#,
241 } 244 expect![[r#"
242} 245 10..209 '{ ... } }': ()
243"#), 246 20..25 'slice': &[f64]
244 @r###" 247 36..42 '&[0.0]': &[f64; _]
245 10..209 '{ ... } }': () 248 37..42 '[0.0]': [f64; _]
246 20..25 'slice': &[f64] 249 38..41 '0.0': f64
247 36..42 '&[0.0]': &[f64; _] 250 48..207 'match ... }': ()
248 37..42 '[0.0]': [f64; _] 251 54..59 'slice': &[f64]
249 38..41 '0.0': f64 252 70..73 '&[]': &[f64]
250 48..207 'match ... }': () 253 71..73 '[]': [f64]
251 54..59 'slice': &[f64] 254 77..79 '{}': ()
252 70..73 '&[]': &[f64] 255 89..93 '&[a]': &[f64]
253 71..73 '[]': [f64] 256 90..93 '[a]': [f64]
254 77..79 '{}': () 257 91..92 'a': f64
255 89..93 '&[a]': &[f64] 258 97..123 '{ ... }': ()
256 90..93 '[a]': [f64] 259 111..112 'a': f64
257 91..92 'a': f64 260 133..140 '&[b, c]': &[f64]
258 97..123 '{ ... }': () 261 134..140 '[b, c]': [f64]
259 111..112 'a': f64 262 135..136 'b': f64
260 133..140 '&[b, c]': &[f64] 263 138..139 'c': f64
261 134..140 '[b, c]': [f64] 264 144..185 '{ ... }': ()
262 135..136 'b': f64 265 158..159 'b': f64
263 138..139 'c': f64 266 173..174 'c': f64
264 144..185 '{ ... }': () 267 194..195 '_': &[f64]
265 158..159 'b': f64 268 199..201 '{}': ()
266 173..174 'c': f64 269 "#]],
267 194..195 '_': &[f64]
268 199..201 '{}': ()
269 "###
270 ); 270 );
271} 271}
272 272
273#[test] 273#[test]
274fn infer_pattern_match_string_literal() { 274fn infer_pattern_match_string_literal() {
275 assert_snapshot!( 275 check_infer_with_mismatches(
276 infer_with_mismatches(r#" 276 r#"
277fn test() { 277 fn test() {
278 let s: &str = "hello"; 278 let s: &str = "hello";
279 match s { 279 match s {
280 "hello" => {} 280 "hello" => {}
281 _ => {} 281 _ => {}
282 } 282 }
283} 283 }
284"#, true), 284 "#,
285 @r###" 285 expect![[r#"
286 10..98 '{ ... } }': () 286 10..98 '{ ... } }': ()
287 20..21 's': &str 287 20..21 's': &str
288 30..37 '"hello"': &str 288 30..37 '"hello"': &str
289 43..96 'match ... }': () 289 43..96 'match ... }': ()
290 49..50 's': &str 290 49..50 's': &str
291 61..68 '"hello"': &str 291 61..68 '"hello"': &str
292 61..68 '"hello"': &str 292 61..68 '"hello"': &str
293 72..74 '{}': () 293 72..74 '{}': ()
294 83..84 '_': &str 294 83..84 '_': &str
295 88..90 '{}': () 295 88..90 '{}': ()
296 "### 296 "#]],
297 ); 297 );
298} 298}
299 299
300#[test] 300#[test]
301fn infer_pattern_match_or() { 301fn infer_pattern_match_or() {
302 assert_snapshot!( 302 check_infer_with_mismatches(
303 infer_with_mismatches(r#" 303 r#"
304fn test() { 304 fn test() {
305 let s: &str = "hello"; 305 let s: &str = "hello";
306 match s { 306 match s {
307 "hello" | "world" => {} 307 "hello" | "world" => {}
308 _ => {} 308 _ => {}
309 } 309 }
310} 310 }
311"#, true), 311 "#,
312 @r###" 312 expect![[r#"
313 10..108 '{ ... } }': () 313 10..108 '{ ... } }': ()
314 20..21 's': &str 314 20..21 's': &str
315 30..37 '"hello"': &str 315 30..37 '"hello"': &str
316 43..106 'match ... }': () 316 43..106 'match ... }': ()
317 49..50 's': &str 317 49..50 's': &str
318 61..68 '"hello"': &str 318 61..68 '"hello"': &str
319 61..68 '"hello"': &str 319 61..68 '"hello"': &str
320 61..78 '"hello...world"': &str 320 61..78 '"hello...world"': &str
321 71..78 '"world"': &str 321 71..78 '"world"': &str
322 71..78 '"world"': &str 322 71..78 '"world"': &str
323 82..84 '{}': () 323 82..84 '{}': ()
324 93..94 '_': &str 324 93..94 '_': &str
325 98..100 '{}': () 325 98..100 '{}': ()
326 "### 326 "#]],
327 ); 327 );
328} 328}
329 329
330#[test] 330#[test]
331fn infer_pattern_match_arr() { 331fn infer_pattern_match_arr() {
332 assert_snapshot!( 332 check_infer(
333 infer(r#" 333 r#"
334fn test() { 334 fn test() {
335 let arr: [f64; 2] = [0.0, 1.0]; 335 let arr: [f64; 2] = [0.0, 1.0];
336 match arr { 336 match arr {
337 [1.0, a] => { 337 [1.0, a] => {
338 a; 338 a;
339 }, 339 },
340 [b, c] => { 340 [b, c] => {
341 b; 341 b;
342 c; 342 c;
343 }
344 }
343 } 345 }
344 } 346 "#,
345} 347 expect![[r#"
346"#), 348 10..179 '{ ... } }': ()
347 @r###" 349 20..23 'arr': [f64; _]
348 10..179 '{ ... } }': () 350 36..46 '[0.0, 1.0]': [f64; _]
349 20..23 'arr': [f64; _] 351 37..40 '0.0': f64
350 36..46 '[0.0, 1.0]': [f64; _] 352 42..45 '1.0': f64
351 37..40 '0.0': f64 353 52..177 'match ... }': ()
352 42..45 '1.0': f64 354 58..61 'arr': [f64; _]
353 52..177 'match ... }': () 355 72..80 '[1.0, a]': [f64; _]
354 58..61 'arr': [f64; _] 356 73..76 '1.0': f64
355 72..80 '[1.0, a]': [f64; _] 357 73..76 '1.0': f64
356 73..76 '1.0': f64 358 78..79 'a': f64
357 73..76 '1.0': f64 359 84..110 '{ ... }': ()
358 78..79 'a': f64 360 98..99 'a': f64
359 84..110 '{ ... }': () 361 120..126 '[b, c]': [f64; _]
360 98..99 'a': f64 362 121..122 'b': f64
361 120..126 '[b, c]': [f64; _] 363 124..125 'c': f64
362 121..122 'b': f64 364 130..171 '{ ... }': ()
363 124..125 'c': f64 365 144..145 'b': f64
364 130..171 '{ ... }': () 366 159..160 'c': f64
365 144..145 'b': f64 367 "#]],
366 159..160 'c': f64
367 "###
368 ); 368 );
369} 369}
370 370
371#[test] 371#[test]
372fn infer_adt_pattern() { 372fn infer_adt_pattern() {
373 assert_snapshot!( 373 check_infer(
374 infer(r#" 374 r#"
375enum E { 375 enum E {
376 A { x: usize }, 376 A { x: usize },
377 B 377 B
378} 378 }
379 379
380struct S(u32, E); 380 struct S(u32, E);
381 381
382fn test() { 382 fn test() {
383 let e = E::A { x: 3 }; 383 let e = E::A { x: 3 };
384 384
385 let S(y, z) = foo; 385 let S(y, z) = foo;
386 let E::A { x: new_var } = e; 386 let E::A { x: new_var } = e;
387 387
388 match e { 388 match e {
389 E::A { x } => x, 389 E::A { x } => x,
390 E::B if foo => 1, 390 E::B if foo => 1,
391 E::B => 10, 391 E::B => 10,
392 }; 392 };
393 393
394 let ref d @ E::A { .. } = e; 394 let ref d @ E::A { .. } = e;
395 d; 395 d;
396} 396 }
397"#), 397 "#,
398 @r###" 398 expect![[r#"
399 67..288 '{ ... d; }': () 399 67..288 '{ ... d; }': ()
400 77..78 'e': E 400 77..78 'e': E
401 81..94 'E::A { x: 3 }': E 401 81..94 'E::A { x: 3 }': E
402 91..92 '3': usize 402 91..92 '3': usize
403 105..112 'S(y, z)': S 403 105..112 'S(y, z)': S
404 107..108 'y': u32 404 107..108 'y': u32
405 110..111 'z': E 405 110..111 'z': E
406 115..118 'foo': S 406 115..118 'foo': S
407 128..147 'E::A {..._var }': E 407 128..147 'E::A {..._var }': E
408 138..145 'new_var': usize 408 138..145 'new_var': usize
409 150..151 'e': E 409 150..151 'e': E
410 158..244 'match ... }': usize 410 158..244 'match ... }': usize
411 164..165 'e': E 411 164..165 'e': E
412 176..186 'E::A { x }': E 412 176..186 'E::A { x }': E
413 183..184 'x': usize 413 183..184 'x': usize
414 190..191 'x': usize 414 190..191 'x': usize
415 201..205 'E::B': E 415 201..205 'E::B': E
416 209..212 'foo': bool 416 209..212 'foo': bool
417 216..217 '1': usize 417 216..217 '1': usize
418 227..231 'E::B': E 418 227..231 'E::B': E
419 235..237 '10': usize 419 235..237 '10': usize
420 255..274 'ref d ...{ .. }': &E 420 255..274 'ref d ...{ .. }': &E
421 263..274 'E::A { .. }': E 421 263..274 'E::A { .. }': E
422 277..278 'e': E 422 277..278 'e': E
423 284..285 'd': &E 423 284..285 'd': &E
424 "### 424 "#]],
425 ); 425 );
426} 426}
427 427
428#[test] 428#[test]
429fn enum_variant_through_self_in_pattern() { 429fn enum_variant_through_self_in_pattern() {
430 assert_snapshot!( 430 check_infer(
431 infer(r#" 431 r#"
432enum E { 432 enum E {
433 A { x: usize }, 433 A { x: usize },
434 B(usize), 434 B(usize),
435 C 435 C
436} 436 }
437 437
438impl E { 438 impl E {
439 fn test() { 439 fn test() {
440 match (loop {}) { 440 match (loop {}) {
441 Self::A { x } => { x; }, 441 Self::A { x } => { x; },
442 Self::B(x) => { x; }, 442 Self::B(x) => { x; },
443 Self::C => {}, 443 Self::C => {},
444 }; 444 };
445 } 445 }
446} 446 }
447"#), 447 "#,
448 @r###" 448 expect![[r#"
449 75..217 '{ ... }': () 449 75..217 '{ ... }': ()
450 85..210 'match ... }': () 450 85..210 'match ... }': ()
451 92..99 'loop {}': ! 451 92..99 'loop {}': !
452 97..99 '{}': () 452 97..99 '{}': ()
453 115..128 'Self::A { x }': E 453 115..128 'Self::A { x }': E
454 125..126 'x': usize 454 125..126 'x': usize
455 132..138 '{ x; }': () 455 132..138 '{ x; }': ()
456 134..135 'x': usize 456 134..135 'x': usize
457 152..162 'Self::B(x)': E 457 152..162 'Self::B(x)': E
458 160..161 'x': usize 458 160..161 'x': usize
459 166..172 '{ x; }': () 459 166..172 '{ x; }': ()
460 168..169 'x': usize 460 168..169 'x': usize
461 186..193 'Self::C': E 461 186..193 'Self::C': E
462 197..199 '{}': () 462 197..199 '{}': ()
463 "### 463 "#]],
464 ); 464 );
465} 465}
466 466
467#[test] 467#[test]
468fn infer_generics_in_patterns() { 468fn infer_generics_in_patterns() {
469 assert_snapshot!( 469 check_infer(
470 infer(r#" 470 r#"
471struct A<T> { 471 struct A<T> {
472 x: T, 472 x: T,
473} 473 }
474 474
475enum Option<T> { 475 enum Option<T> {
476 Some(T), 476 Some(T),
477 None, 477 None,
478} 478 }
479 479
480fn test(a1: A<u32>, o: Option<u64>) { 480 fn test(a1: A<u32>, o: Option<u64>) {
481 let A { x: x2 } = a1; 481 let A { x: x2 } = a1;
482 let A::<i64> { x: x3 } = A { x: 1 }; 482 let A::<i64> { x: x3 } = A { x: 1 };
483 match o { 483 match o {
484 Option::Some(t) => t, 484 Option::Some(t) => t,
485 _ => 1, 485 _ => 1,
486 }; 486 };
487} 487 }
488"#), 488 "#,
489 @r###" 489 expect![[r#"
490 78..80 'a1': A<u32> 490 78..80 'a1': A<u32>
491 90..91 'o': Option<u64> 491 90..91 'o': Option<u64>
492 106..243 '{ ... }; }': () 492 106..243 '{ ... }; }': ()
493 116..127 'A { x: x2 }': A<u32> 493 116..127 'A { x: x2 }': A<u32>
494 123..125 'x2': u32 494 123..125 'x2': u32
495 130..132 'a1': A<u32> 495 130..132 'a1': A<u32>
496 142..160 'A::<i6...: x3 }': A<i64> 496 142..160 'A::<i6...: x3 }': A<i64>
497 156..158 'x3': i64 497 156..158 'x3': i64
498 163..173 'A { x: 1 }': A<i64> 498 163..173 'A { x: 1 }': A<i64>
499 170..171 '1': i64 499 170..171 '1': i64
500 179..240 'match ... }': u64 500 179..240 'match ... }': u64
501 185..186 'o': Option<u64> 501 185..186 'o': Option<u64>
502 197..212 'Option::Some(t)': Option<u64> 502 197..212 'Option::Some(t)': Option<u64>
503 210..211 't': u64 503 210..211 't': u64
504 216..217 't': u64 504 216..217 't': u64
505 227..228 '_': Option<u64> 505 227..228 '_': Option<u64>
506 232..233 '1': u64 506 232..233 '1': u64
507 "### 507 "#]],
508 ); 508 );
509} 509}
510 510
511#[test] 511#[test]
512fn infer_const_pattern() { 512fn infer_const_pattern() {
513 assert_snapshot!( 513 check_infer_with_mismatches(
514 infer_with_mismatches(r#" 514 r#"
515enum Option<T> { None } 515 enum Option<T> { None }
516use Option::None; 516 use Option::None;
517struct Foo; 517 struct Foo;
518const Bar: usize = 1; 518 const Bar: usize = 1;
519 519
520fn test() { 520 fn test() {
521 let a: Option<u32> = None; 521 let a: Option<u32> = None;
522 let b: Option<i64> = match a { 522 let b: Option<i64> = match a {
523 None => None, 523 None => None,
524 }; 524 };
525 let _: () = match () { Foo => Foo }; // Expected mismatch 525 let _: () = match () { Foo => Foo }; // Expected mismatch
526 let _: () = match () { Bar => Bar }; // Expected mismatch 526 let _: () = match () { Bar => Bar }; // Expected mismatch
527} 527 }
528"#, true), 528 "#,
529 @r###" 529 expect![[r#"
530 73..74 '1': usize 530 73..74 '1': usize
531 87..309 '{ ...atch }': () 531 87..309 '{ ...atch }': ()
532 97..98 'a': Option<u32> 532 97..98 'a': Option<u32>
533 114..118 'None': Option<u32> 533 114..118 'None': Option<u32>
534 128..129 'b': Option<i64> 534 128..129 'b': Option<i64>
535 145..182 'match ... }': Option<i64> 535 145..182 'match ... }': Option<i64>
536 151..152 'a': Option<u32> 536 151..152 'a': Option<u32>
537 163..167 'None': Option<u32> 537 163..167 'None': Option<u32>
538 171..175 'None': Option<i64> 538 171..175 'None': Option<i64>
539 192..193 '_': () 539 192..193 '_': ()
540 200..223 'match ... Foo }': Foo 540 200..223 'match ... Foo }': Foo
541 206..208 '()': () 541 206..208 '()': ()
542 211..214 'Foo': Foo 542 211..214 'Foo': Foo
543 218..221 'Foo': Foo 543 218..221 'Foo': Foo
544 254..255 '_': () 544 254..255 '_': ()
545 262..285 'match ... Bar }': usize 545 262..285 'match ... Bar }': usize
546 268..270 '()': () 546 268..270 '()': ()
547 273..276 'Bar': usize 547 273..276 'Bar': usize
548 280..283 'Bar': usize 548 280..283 'Bar': usize
549 200..223: expected (), got Foo 549 200..223: expected (), got Foo
550 262..285: expected (), got usize 550 262..285: expected (), got usize
551 "### 551 "#]],
552 ); 552 );
553} 553}
554 554
555#[test] 555#[test]
556fn infer_guard() { 556fn infer_guard() {
557 assert_snapshot!( 557 check_infer(
558 infer(r#" 558 r#"
559struct S; 559struct S;
560impl S { fn foo(&self) -> bool { false } } 560impl S { fn foo(&self) -> bool { false } }
561 561
@@ -564,91 +564,93 @@ fn main() {
564 s if s.foo() => (), 564 s if s.foo() => (),
565 } 565 }
566} 566}
567 "#), @r###" 567 "#,
568 27..31 'self': &S 568 expect![[r#"
569 41..50 '{ false }': bool 569 27..31 'self': &S
570 43..48 'false': bool 570 41..50 '{ false }': bool
571 64..115 '{ ... } }': () 571 43..48 'false': bool
572 70..113 'match ... }': () 572 64..115 '{ ... } }': ()
573 76..77 'S': S 573 70..113 'match ... }': ()
574 88..89 's': S 574 76..77 'S': S
575 93..94 's': S 575 88..89 's': S
576 93..100 's.foo()': bool 576 93..94 's': S
577 104..106 '()': () 577 93..100 's.foo()': bool
578 "###) 578 104..106 '()': ()
579 "#]],
580 )
579} 581}
580 582
581#[test] 583#[test]
582fn match_ergonomics_in_closure_params() { 584fn match_ergonomics_in_closure_params() {
583 assert_snapshot!( 585 check_infer(
584 infer(r#" 586 r#"
585#[lang = "fn_once"] 587 #[lang = "fn_once"]
586trait FnOnce<Args> { 588 trait FnOnce<Args> {
587 type Output; 589 type Output;
588} 590 }
589 591
590fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} } 592 fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
591 593
592fn test() { 594 fn test() {
593 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics 595 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
594 foo(&(1, "a"), |(x, y)| x); 596 foo(&(1, "a"), |(x, y)| x);
595} 597 }
596"#), 598 "#,
597 @r###" 599 expect![[r#"
598 93..94 't': T 600 93..94 't': T
599 99..100 'f': F 601 99..100 'f': F
600 110..121 '{ loop {} }': U 602 110..121 '{ loop {} }': U
601 112..119 'loop {}': ! 603 112..119 'loop {}': !
602 117..119 '{}': () 604 117..119 '{}': ()
603 133..232 '{ ... x); }': () 605 133..232 '{ ... x); }': ()
604 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 606 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
605 139..166 'foo(&(...y)| x)': i32 607 139..166 'foo(&(...y)| x)': i32
606 143..152 '&(1, "a")': &(i32, &str) 608 143..152 '&(1, "a")': &(i32, &str)
607 144..152 '(1, "a")': (i32, &str) 609 144..152 '(1, "a")': (i32, &str)
608 145..146 '1': i32 610 145..146 '1': i32
609 148..151 '"a"': &str 611 148..151 '"a"': &str
610 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32 612 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32
611 155..162 '&(x, y)': &(i32, &str) 613 155..162 '&(x, y)': &(i32, &str)
612 156..162 '(x, y)': (i32, &str) 614 156..162 '(x, y)': (i32, &str)
613 157..158 'x': i32 615 157..158 'x': i32
614 160..161 'y': &str 616 160..161 'y': &str
615 164..165 'x': i32 617 164..165 'x': i32
616 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 618 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
617 203..229 'foo(&(...y)| x)': &i32 619 203..229 'foo(&(...y)| x)': &i32
618 207..216 '&(1, "a")': &(i32, &str) 620 207..216 '&(1, "a")': &(i32, &str)
619 208..216 '(1, "a")': (i32, &str) 621 208..216 '(1, "a")': (i32, &str)
620 209..210 '1': i32 622 209..210 '1': i32
621 212..215 '"a"': &str 623 212..215 '"a"': &str
622 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32 624 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32
623 219..225 '(x, y)': (i32, &str) 625 219..225 '(x, y)': (i32, &str)
624 220..221 'x': &i32 626 220..221 'x': &i32
625 223..224 'y': &&str 627 223..224 'y': &&str
626 227..228 'x': &i32 628 227..228 'x': &i32
627 "### 629 "#]],
628 ); 630 );
629} 631}
630 632
631#[test] 633#[test]
632fn slice_tail_pattern() { 634fn slice_tail_pattern() {
633 assert_snapshot!( 635 check_infer(
634 infer(r#" 636 r#"
635fn foo(params: &[i32]) { 637 fn foo(params: &[i32]) {
636 match params { 638 match params {
637 [head, tail @ ..] => { 639 [head, tail @ ..] => {
640 }
641 }
638 } 642 }
639 } 643 "#,
640} 644 expect![[r#"
641"#), 645 7..13 'params': &[i32]
642 @r###" 646 23..92 '{ ... } }': ()
643 7..13 'params': &[i32] 647 29..90 'match ... }': ()
644 23..92 '{ ... } }': () 648 35..41 'params': &[i32]
645 29..90 'match ... }': () 649 52..69 '[head,... @ ..]': [i32]
646 35..41 'params': &[i32] 650 53..57 'head': &i32
647 52..69 '[head,... @ ..]': [i32] 651 59..68 'tail @ ..': &[i32]
648 53..57 'head': &i32 652 66..68 '..': [i32]
649 59..68 'tail @ ..': &[i32] 653 73..84 '{ }': ()
650 66..68 '..': [i32] 654 "#]],
651 73..84 '{ }': ()
652 "###
653 ); 655 );
654} 656}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index d806e0ffb..b9ab0f357 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -1,87 +1,87 @@
1use insta::assert_snapshot; 1use expect::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_types, infer}; 4use super::{check_infer, check_types};
5 5
6#[test] 6#[test]
7fn bug_484() { 7fn bug_484() {
8 assert_snapshot!( 8 check_infer(
9 infer(r#" 9 r#"
10fn test() { 10 fn test() {
11 let x = if true {}; 11 let x = if true {};
12} 12 }
13"#), 13 "#,
14 @r###" 14 expect![[r#"
15 10..36 '{ l... {}; }': () 15 10..37 '{ ... {}; }': ()
16 19..20 'x': () 16 20..21 'x': ()
17 23..33 'if true {}': () 17 24..34 'if true {}': ()
18 26..30 'true': bool 18 27..31 'true': bool
19 31..33 '{}': () 19 32..34 '{}': ()
20 "### 20 "#]],
21 ); 21 );
22} 22}
23 23
24#[test] 24#[test]
25fn no_panic_on_field_of_enum() { 25fn no_panic_on_field_of_enum() {
26 assert_snapshot!( 26 check_infer(
27 infer(r#" 27 r#"
28enum X {} 28 enum X {}
29 29
30fn test(x: X) { 30 fn test(x: X) {
31 x.some_field; 31 x.some_field;
32} 32 }
33"#), 33 "#,
34 @r###" 34 expect![[r#"
35 19..20 'x': X 35 19..20 'x': X
36 25..46 '{ ...eld; }': () 36 25..46 '{ ...eld; }': ()
37 31..32 'x': X 37 31..32 'x': X
38 31..43 'x.some_field': {unknown} 38 31..43 'x.some_field': {unknown}
39 "### 39 "#]],
40 ); 40 );
41} 41}
42 42
43#[test] 43#[test]
44fn bug_585() { 44fn bug_585() {
45 assert_snapshot!( 45 check_infer(
46 infer(r#" 46 r#"
47fn test() { 47 fn test() {
48 X {}; 48 X {};
49 match x { 49 match x {
50 A::B {} => (), 50 A::B {} => (),
51 A::Y() => (), 51 A::Y() => (),
52 } 52 }
53} 53 }
54"#), 54 "#,
55 @r###" 55 expect![[r#"
56 10..88 '{ ... } }': () 56 10..88 '{ ... } }': ()
57 16..20 'X {}': {unknown} 57 16..20 'X {}': {unknown}
58 26..86 'match ... }': () 58 26..86 'match ... }': ()
59 32..33 'x': {unknown} 59 32..33 'x': {unknown}
60 44..51 'A::B {}': {unknown} 60 44..51 'A::B {}': {unknown}
61 55..57 '()': () 61 55..57 '()': ()
62 67..73 'A::Y()': {unknown} 62 67..73 'A::Y()': {unknown}
63 77..79 '()': () 63 77..79 '()': ()
64 "### 64 "#]],
65 ); 65 );
66} 66}
67 67
68#[test] 68#[test]
69fn bug_651() { 69fn bug_651() {
70 assert_snapshot!( 70 check_infer(
71 infer(r#" 71 r#"
72fn quux() { 72 fn quux() {
73 let y = 92; 73 let y = 92;
74 1 + y; 74 1 + y;
75} 75 }
76"#), 76 "#,
77 @r###" 77 expect![[r#"
78 10..40 '{ ...+ y; }': () 78 10..40 '{ ...+ y; }': ()
79 20..21 'y': i32 79 20..21 'y': i32
80 24..26 '92': i32 80 24..26 '92': i32
81 32..33 '1': i32 81 32..33 '1': i32
82 32..37 '1 + y': i32 82 32..37 '1 + y': i32
83 36..37 'y': i32 83 36..37 'y': i32
84 "### 84 "#]],
85 ); 85 );
86} 86}
87 87
@@ -89,78 +89,78 @@ fn quux() {
89fn recursive_vars() { 89fn recursive_vars() {
90 mark::check!(type_var_cycles_resolve_completely); 90 mark::check!(type_var_cycles_resolve_completely);
91 mark::check!(type_var_cycles_resolve_as_possible); 91 mark::check!(type_var_cycles_resolve_as_possible);
92 assert_snapshot!( 92 check_infer(
93 infer(r#" 93 r#"
94fn test() { 94 fn test() {
95 let y = unknown; 95 let y = unknown;
96 [y, &y]; 96 [y, &y];
97} 97 }
98"#), 98 "#,
99 @r###" 99 expect![[r#"
100 10..47 '{ ...&y]; }': () 100 10..47 '{ ...&y]; }': ()
101 20..21 'y': &{unknown} 101 20..21 'y': &{unknown}
102 24..31 'unknown': &{unknown} 102 24..31 'unknown': &{unknown}
103 37..44 '[y, &y]': [&&{unknown}; _] 103 37..44 '[y, &y]': [&&{unknown}; _]
104 38..39 'y': &{unknown} 104 38..39 'y': &{unknown}
105 41..43 '&y': &&{unknown} 105 41..43 '&y': &&{unknown}
106 42..43 'y': &{unknown} 106 42..43 'y': &{unknown}
107 "### 107 "#]],
108 ); 108 );
109} 109}
110 110
111#[test] 111#[test]
112fn recursive_vars_2() { 112fn recursive_vars_2() {
113 assert_snapshot!( 113 check_infer(
114 infer(r#" 114 r#"
115fn test() { 115 fn test() {
116 let x = unknown; 116 let x = unknown;
117 let y = unknown; 117 let y = unknown;
118 [(x, y), (&y, &x)]; 118 [(x, y), (&y, &x)];
119} 119 }
120"#), 120 "#,
121 @r###" 121 expect![[r#"
122 10..79 '{ ...x)]; }': () 122 10..79 '{ ...x)]; }': ()
123 20..21 'x': &&{unknown} 123 20..21 'x': &&{unknown}
124 24..31 'unknown': &&{unknown} 124 24..31 'unknown': &&{unknown}
125 41..42 'y': &&{unknown} 125 41..42 'y': &&{unknown}
126 45..52 'unknown': &&{unknown} 126 45..52 'unknown': &&{unknown}
127 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _] 127 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _]
128 59..65 '(x, y)': (&&&{unknown}, &&&{unknown}) 128 59..65 '(x, y)': (&&&{unknown}, &&&{unknown})
129 60..61 'x': &&{unknown} 129 60..61 'x': &&{unknown}
130 63..64 'y': &&{unknown} 130 63..64 'y': &&{unknown}
131 67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown}) 131 67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown})
132 68..70 '&y': &&&{unknown} 132 68..70 '&y': &&&{unknown}
133 69..70 'y': &&{unknown} 133 69..70 'y': &&{unknown}
134 72..74 '&x': &&&{unknown} 134 72..74 '&x': &&&{unknown}
135 73..74 'x': &&{unknown} 135 73..74 'x': &&{unknown}
136 "### 136 "#]],
137 ); 137 );
138} 138}
139 139
140#[test] 140#[test]
141fn infer_std_crash_1() { 141fn infer_std_crash_1() {
142 // caused stack overflow, taken from std 142 // caused stack overflow, taken from std
143 assert_snapshot!( 143 check_infer(
144 infer(r#" 144 r#"
145enum Maybe<T> { 145 enum Maybe<T> {
146 Real(T), 146 Real(T),
147 Fake, 147 Fake,
148} 148 }
149 149
150fn write() { 150 fn write() {
151 match something_unknown { 151 match something_unknown {
152 Maybe::Real(ref mut something) => (), 152 Maybe::Real(ref mut something) => (),
153 } 153 }
154} 154 }
155"#), 155 "#,
156 @r###" 156 expect![[r#"
157 53..138 '{ ... } }': () 157 53..138 '{ ... } }': ()
158 59..136 'match ... }': () 158 59..136 'match ... }': ()
159 65..82 'someth...nknown': Maybe<{unknown}> 159 65..82 'someth...nknown': Maybe<{unknown}>
160 93..123 'Maybe:...thing)': Maybe<{unknown}> 160 93..123 'Maybe:...thing)': Maybe<{unknown}>
161 105..122 'ref mu...ething': &mut {unknown} 161 105..122 'ref mu...ething': &mut {unknown}
162 127..129 '()': () 162 127..129 '()': ()
163 "### 163 "#]],
164 ); 164 );
165} 165}
166 166
@@ -168,234 +168,235 @@ fn write() {
168fn infer_std_crash_2() { 168fn infer_std_crash_2() {
169 mark::check!(type_var_resolves_to_int_var); 169 mark::check!(type_var_resolves_to_int_var);
170 // caused "equating two type variables, ...", taken from std 170 // caused "equating two type variables, ...", taken from std
171 assert_snapshot!( 171 check_infer(
172 infer(r#" 172 r#"
173fn test_line_buffer() { 173 fn test_line_buffer() {
174 &[0, b'\n', 1, b'\n']; 174 &[0, b'\n', 1, b'\n'];
175} 175 }
176"#), 176 "#,
177 @r###" 177 expect![[r#"
178 22..52 '{ ...n']; }': () 178 22..52 '{ ...n']; }': ()
179 28..49 '&[0, b...b'\n']': &[u8; _] 179 28..49 '&[0, b...b'\n']': &[u8; _]
180 29..49 '[0, b'...b'\n']': [u8; _] 180 29..49 '[0, b'...b'\n']': [u8; _]
181 30..31 '0': u8 181 30..31 '0': u8
182 33..38 'b'\n'': u8 182 33..38 'b'\n'': u8
183 40..41 '1': u8 183 40..41 '1': u8
184 43..48 'b'\n'': u8 184 43..48 'b'\n'': u8
185 "### 185 "#]],
186 ); 186 );
187} 187}
188 188
189#[test] 189#[test]
190fn infer_std_crash_3() { 190fn infer_std_crash_3() {
191 // taken from rustc 191 // taken from rustc
192 assert_snapshot!( 192 check_infer(
193 infer(r#" 193 r#"
194pub fn compute() { 194 pub fn compute() {
195 match nope!() { 195 match nope!() {
196 SizeSkeleton::Pointer { non_zero: true, tail } => {} 196 SizeSkeleton::Pointer { non_zero: true, tail } => {}
197 } 197 }
198} 198 }
199"#), 199 "#,
200 @r###" 200 expect![[r#"
201 17..107 '{ ... } }': () 201 17..107 '{ ... } }': ()
202 23..105 'match ... }': () 202 23..105 'match ... }': ()
203 29..36 'nope!()': {unknown} 203 29..36 'nope!()': {unknown}
204 47..93 'SizeSk...tail }': {unknown} 204 47..93 'SizeSk...tail }': {unknown}
205 81..85 'true': bool 205 81..85 'true': bool
206 81..85 'true': bool 206 81..85 'true': bool
207 87..91 'tail': {unknown} 207 87..91 'tail': {unknown}
208 97..99 '{}': () 208 97..99 '{}': ()
209 "### 209 "#]],
210 ); 210 );
211} 211}
212 212
213#[test] 213#[test]
214fn infer_std_crash_4() { 214fn infer_std_crash_4() {
215 // taken from rustc 215 // taken from rustc
216 assert_snapshot!( 216 check_infer(
217 infer(r#" 217 r#"
218pub fn primitive_type() { 218 pub fn primitive_type() {
219 match *self { 219 match *self {
220 BorrowedRef { type_: Primitive(p), ..} => {}, 220 BorrowedRef { type_: Primitive(p), ..} => {},
221 } 221 }
222} 222 }
223"#), 223 "#,
224 @r###" 224 expect![[r#"
225 24..105 '{ ... } }': () 225 24..105 '{ ... } }': ()
226 30..103 'match ... }': () 226 30..103 'match ... }': ()
227 36..41 '*self': {unknown} 227 36..41 '*self': {unknown}
228 37..41 'self': {unknown} 228 37..41 'self': {unknown}
229 52..90 'Borrow...), ..}': {unknown} 229 52..90 'Borrow...), ..}': {unknown}
230 73..85 'Primitive(p)': {unknown} 230 73..85 'Primitive(p)': {unknown}
231 83..84 'p': {unknown} 231 83..84 'p': {unknown}
232 94..96 '{}': () 232 94..96 '{}': ()
233 "### 233 "#]],
234 ); 234 );
235} 235}
236 236
237#[test] 237#[test]
238fn infer_std_crash_5() { 238fn infer_std_crash_5() {
239 // taken from rustc 239 // taken from rustc
240 assert_snapshot!( 240 check_infer(
241 infer(r#" 241 r#"
242fn extra_compiler_flags() { 242 fn extra_compiler_flags() {
243 for content in doesnt_matter { 243 for content in doesnt_matter {
244 let name = if doesnt_matter { 244 let name = if doesnt_matter {
245 first 245 first
246 } else { 246 } else {
247 &content 247 &content
248 }; 248 };
249 249
250 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { 250 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
251 name 251 name
252 } else { 252 } else {
253 content 253 content
254 }; 254 };
255 } 255 }
256} 256 }
257"#), 257 "#,
258 @r###" 258 expect![[r#"
259 26..322 '{ ... } }': () 259 26..322 '{ ... } }': ()
260 32..320 'for co... }': () 260 32..320 'for co... }': ()
261 36..43 'content': &{unknown} 261 36..43 'content': &{unknown}
262 47..60 'doesnt_matter': {unknown} 262 47..60 'doesnt_matter': {unknown}
263 61..320 '{ ... }': () 263 61..320 '{ ... }': ()
264 75..79 'name': &&{unknown} 264 75..79 'name': &&{unknown}
265 82..166 'if doe... }': &&{unknown} 265 82..166 'if doe... }': &&{unknown}
266 85..98 'doesnt_matter': bool 266 85..98 'doesnt_matter': bool
267 99..128 '{ ... }': &&{unknown} 267 99..128 '{ ... }': &&{unknown}
268 113..118 'first': &&{unknown} 268 113..118 'first': &&{unknown}
269 134..166 '{ ... }': &&{unknown} 269 134..166 '{ ... }': &&{unknown}
270 148..156 '&content': &&{unknown} 270 148..156 '&content': &&{unknown}
271 149..156 'content': &{unknown} 271 149..156 'content': &{unknown}
272 181..188 'content': &{unknown} 272 181..188 'content': &{unknown}
273 191..313 'if ICE... }': &{unknown} 273 191..313 'if ICE... }': &{unknown}
274 194..231 'ICE_RE..._VALUE': {unknown} 274 194..231 'ICE_RE..._VALUE': {unknown}
275 194..247 'ICE_RE...&name)': bool 275 194..247 'ICE_RE...&name)': bool
276 241..246 '&name': &&&{unknown} 276 241..246 '&name': &&&{unknown}
277 242..246 'name': &&{unknown} 277 242..246 'name': &&{unknown}
278 248..276 '{ ... }': &&{unknown} 278 248..276 '{ ... }': &&{unknown}
279 262..266 'name': &&{unknown} 279 262..266 'name': &&{unknown}
280 282..313 '{ ... }': &{unknown} 280 282..313 '{ ... }': &{unknown}
281 296..303 'content': &{unknown} 281 296..303 'content': &{unknown}
282 "### 282 "#]],
283 ); 283 );
284} 284}
285 285
286#[test] 286#[test]
287fn infer_nested_generics_crash() { 287fn infer_nested_generics_crash() {
288 // another crash found typechecking rustc 288 // another crash found typechecking rustc
289 assert_snapshot!( 289 check_infer(
290 infer(r#" 290 r#"
291struct Canonical<V> { 291 struct Canonical<V> {
292 value: V, 292 value: V,
293} 293 }
294struct QueryResponse<V> { 294 struct QueryResponse<V> {
295 value: V, 295 value: V,
296} 296 }
297fn test<R>(query_response: Canonical<QueryResponse<R>>) { 297 fn test<R>(query_response: Canonical<QueryResponse<R>>) {
298 &query_response.value; 298 &query_response.value;
299} 299 }
300"#), 300 "#,
301 @r###" 301 expect![[r#"
302 91..105 'query_response': Canonical<QueryResponse<R>> 302 91..105 'query_response': Canonical<QueryResponse<R>>
303 136..166 '{ ...lue; }': () 303 136..166 '{ ...lue; }': ()
304 142..163 '&query....value': &QueryResponse<R> 304 142..163 '&query....value': &QueryResponse<R>
305 143..157 'query_response': Canonical<QueryResponse<R>> 305 143..157 'query_response': Canonical<QueryResponse<R>>
306 143..163 'query_....value': QueryResponse<R> 306 143..163 'query_....value': QueryResponse<R>
307 "### 307 "#]],
308 ); 308 );
309} 309}
310 310
311#[test] 311#[test]
312fn infer_paren_macro_call() { 312fn infer_paren_macro_call() {
313 assert_snapshot!( 313 check_infer(
314 infer(r#" 314 r#"
315macro_rules! bar { () => {0u32} } 315 macro_rules! bar { () => {0u32} }
316fn test() { 316 fn test() {
317 let a = (bar!()); 317 let a = (bar!());
318} 318 }
319"#), 319 "#,
320 @r###" 320 expect![[r#"
321 !0..4 '0u32': u32 321 !0..4 '0u32': u32
322 44..69 '{ ...()); }': () 322 44..69 '{ ...()); }': ()
323 54..55 'a': u32 323 54..55 'a': u32
324 "### 324 "#]],
325 ); 325 );
326} 326}
327 327
328#[test] 328#[test]
329fn bug_1030() { 329fn bug_1030() {
330 assert_snapshot!(infer(r#" 330 check_infer(
331struct HashSet<T, H>; 331 r#"
332struct FxHasher; 332 struct HashSet<T, H>;
333type FxHashSet<T> = HashSet<T, FxHasher>; 333 struct FxHasher;
334 type FxHashSet<T> = HashSet<T, FxHasher>;
334 335
335impl<T, H> HashSet<T, H> { 336 impl<T, H> HashSet<T, H> {
336 fn default() -> HashSet<T, H> {} 337 fn default() -> HashSet<T, H> {}
337} 338 }
338 339
339pub fn main_loop() { 340 pub fn main_loop() {
340 FxHashSet::default(); 341 FxHashSet::default();
341} 342 }
342"#), 343 "#,
343 @r###" 344 expect![[r#"
344 143..145 '{}': () 345 143..145 '{}': ()
345 168..197 '{ ...t(); }': () 346 168..197 '{ ...t(); }': ()
346 174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher> 347 174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher>
347 174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher> 348 174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher>
348 "### 349 "#]],
349 ); 350 );
350} 351}
351 352
352#[test] 353#[test]
353fn issue_2669() { 354fn issue_2669() {
354 assert_snapshot!( 355 check_infer(
355 infer( 356 r#"
356 r#"trait A {} 357 trait A {}
357 trait Write {} 358 trait Write {}
358 struct Response<T> {} 359 struct Response<T> {}
359
360 trait D {
361 fn foo();
362 }
363 360
364 impl<T:A> D for Response<T> { 361 trait D {
365 fn foo() { 362 fn foo();
366 end(); 363 }
367 fn end<W: Write>() { 364
368 let _x: T = loop {}; 365 impl<T:A> D for Response<T> {
366 fn foo() {
367 end();
368 fn end<W: Write>() {
369 let _x: T = loop {};
370 }
369 } 371 }
370 } 372 }
371 }"# 373 "#,
372 ), 374 expect![[r#"
373 @r###" 375 119..214 '{ ... }': ()
374 147..262 '{ ... }': () 376 129..132 'end': fn end<{unknown}>()
375 161..164 'end': fn end<{unknown}>() 377 129..134 'end()': ()
376 161..166 'end()': () 378 163..208 '{ ... }': ()
377 199..252 '{ ... }': () 379 181..183 '_x': !
378 221..223 '_x': ! 380 190..197 'loop {}': !
379 230..237 'loop {}': ! 381 195..197 '{}': ()
380 235..237 '{}': () 382 "#]],
381 "###
382 ) 383 )
383} 384}
384 385
385#[test] 386#[test]
386fn issue_2705() { 387fn issue_2705() {
387 assert_snapshot!( 388 check_infer(
388 infer(r#" 389 r#"
389trait Trait {} 390 trait Trait {}
390fn test() { 391 fn test() {
391 <Trait<u32>>::foo() 392 <Trait<u32>>::foo()
392} 393 }
393"#), 394 "#,
394 @r###" 395 expect![[r#"
395 25..52 '{ ...oo() }': () 396 25..52 '{ ...oo() }': ()
396 31..48 '<Trait...>::foo': {unknown} 397 31..48 '<Trait...>::foo': {unknown}
397 31..50 '<Trait...:foo()': () 398 31..50 '<Trait...:foo()': ()
398 "### 399 "#]],
399 ); 400 );
400} 401}
401 402
@@ -479,25 +480,25 @@ fn main() {
479 480
480#[test] 481#[test]
481fn issue_3999_slice() { 482fn issue_3999_slice() {
482 assert_snapshot!( 483 check_infer(
483 infer(r#" 484 r#"
484fn foo(params: &[usize]) { 485 fn foo(params: &[usize]) {
485 match params { 486 match params {
486 [ps @ .., _] => {} 487 [ps @ .., _] => {}
487 } 488 }
488} 489 }
489"#), 490 "#,
490 @r###" 491 expect![[r#"
491 7..13 'params': &[usize] 492 7..13 'params': &[usize]
492 25..80 '{ ... } }': () 493 25..80 '{ ... } }': ()
493 31..78 'match ... }': () 494 31..78 'match ... }': ()
494 37..43 'params': &[usize] 495 37..43 'params': &[usize]
495 54..66 '[ps @ .., _]': [usize] 496 54..66 '[ps @ .., _]': [usize]
496 55..62 'ps @ ..': &[usize] 497 55..62 'ps @ ..': &[usize]
497 60..62 '..': [usize] 498 60..62 '..': [usize]
498 64..65 '_': usize 499 64..65 '_': usize
499 70..72 '{}': () 500 70..72 '{}': ()
500 "### 501 "#]],
501 ); 502 );
502} 503}
503 504
@@ -505,277 +506,337 @@ fn foo(params: &[usize]) {
505fn issue_3999_struct() { 506fn issue_3999_struct() {
506 // rust-analyzer should not panic on seeing this malformed 507 // rust-analyzer should not panic on seeing this malformed
507 // record pattern. 508 // record pattern.
508 assert_snapshot!( 509 check_infer(
509 infer(r#" 510 r#"
510struct Bar { 511 struct Bar {
511 a: bool, 512 a: bool,
512} 513 }
513fn foo(b: Bar) { 514 fn foo(b: Bar) {
514 match b { 515 match b {
515 Bar { a: .. } => {}, 516 Bar { a: .. } => {},
516 } 517 }
517} 518 }
518"#), 519 "#,
519 @r###" 520 expect![[r#"
520 35..36 'b': Bar 521 35..36 'b': Bar
521 43..95 '{ ... } }': () 522 43..95 '{ ... } }': ()
522 49..93 'match ... }': () 523 49..93 'match ... }': ()
523 55..56 'b': Bar 524 55..56 'b': Bar
524 67..80 'Bar { a: .. }': Bar 525 67..80 'Bar { a: .. }': Bar
525 76..78 '..': bool 526 76..78 '..': bool
526 84..86 '{}': () 527 84..86 '{}': ()
527 "### 528 "#]],
528 ); 529 );
529} 530}
530 531
531#[test] 532#[test]
532fn issue_4235_name_conflicts() { 533fn issue_4235_name_conflicts() {
533 assert_snapshot!( 534 check_infer(
534 infer(r#" 535 r#"
535struct FOO {} 536 struct FOO {}
536static FOO:FOO = FOO {}; 537 static FOO:FOO = FOO {};
537 538
538impl FOO { 539 impl FOO {
539 fn foo(&self) {} 540 fn foo(&self) {}
540} 541 }
541 542
542fn main() { 543 fn main() {
543 let a = &FOO; 544 let a = &FOO;
544 a.foo(); 545 a.foo();
545} 546 }
546"#), @r###" 547 "#,
547 31..37 'FOO {}': FOO 548 expect![[r#"
548 63..67 'self': &FOO 549 31..37 'FOO {}': FOO
549 69..71 '{}': () 550 63..67 'self': &FOO
550 85..119 '{ ...o(); }': () 551 69..71 '{}': ()
551 95..96 'a': &FOO 552 85..119 '{ ...o(); }': ()
552 99..103 '&FOO': &FOO 553 95..96 'a': &FOO
553 100..103 'FOO': FOO 554 99..103 '&FOO': &FOO
554 109..110 'a': &FOO 555 100..103 'FOO': FOO
555 109..116 'a.foo()': () 556 109..110 'a': &FOO
556 "### 557 109..116 'a.foo()': ()
558 "#]],
557 ); 559 );
558} 560}
559 561
560#[test] 562#[test]
561fn issue_4465_dollar_crate_at_type() { 563fn issue_4465_dollar_crate_at_type() {
562 assert_snapshot!( 564 check_infer(
563 infer(r#" 565 r#"
564pub struct Foo {} 566 pub struct Foo {}
565pub fn anything<T>() -> T { 567 pub fn anything<T>() -> T {
566 loop {} 568 loop {}
567} 569 }
568macro_rules! foo { 570 macro_rules! foo {
569 () => {{ 571 () => {{
570 let r: $crate::Foo = anything(); 572 let r: $crate::Foo = anything();
571 r 573 r
572 }}; 574 }};
573} 575 }
574fn main() { 576 fn main() {
575 let _a = foo!(); 577 let _a = foo!();
576} 578 }
577"#), @r###" 579 "#,
578 44..59 '{ loop {} }': T 580 expect![[r#"
579 50..57 'loop {}': ! 581 44..59 '{ loop {} }': T
580 55..57 '{}': () 582 50..57 'loop {}': !
581 !0..31 '{letr:...g();r}': Foo 583 55..57 '{}': ()
582 !4..5 'r': Foo 584 !0..31 '{letr:...g();r}': Foo
583 !18..26 'anything': fn anything<Foo>() -> Foo 585 !4..5 'r': Foo
584 !18..28 'anything()': Foo 586 !18..26 'anything': fn anything<Foo>() -> Foo
585 !29..30 'r': Foo 587 !18..28 'anything()': Foo
586 163..187 '{ ...!(); }': () 588 !29..30 'r': Foo
587 173..175 '_a': Foo 589 163..187 '{ ...!(); }': ()
588 "###); 590 173..175 '_a': Foo
591 "#]],
592 );
589} 593}
590 594
591#[test] 595#[test]
592fn issue_4053_diesel_where_clauses() { 596fn issue_4053_diesel_where_clauses() {
593 assert_snapshot!( 597 check_infer(
594 infer(r#" 598 r#"
595trait BoxedDsl<DB> { 599 trait BoxedDsl<DB> {
596 type Output; 600 type Output;
597 fn internal_into_boxed(self) -> Self::Output; 601 fn internal_into_boxed(self) -> Self::Output;
598} 602 }
599 603
600struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> { 604 struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
601 order: Order, 605 order: Order,
602} 606 }
603 607
604trait QueryFragment<DB: Backend> {} 608 trait QueryFragment<DB: Backend> {}
605 609
606trait Into<T> { fn into(self) -> T; } 610 trait Into<T> { fn into(self) -> T; }
607 611
608impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB> 612 impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
609 for SelectStatement<F, S, D, W, O, LOf, G> 613 for SelectStatement<F, S, D, W, O, LOf, G>
610where 614 where
611 O: Into<dyn QueryFragment<DB>>, 615 O: Into<dyn QueryFragment<DB>>,
612{ 616 {
613 type Output = XXX; 617 type Output = XXX;
614 618
615 fn internal_into_boxed(self) -> Self::Output { 619 fn internal_into_boxed(self) -> Self::Output {
616 self.order.into(); 620 self.order.into();
617 } 621 }
618} 622 }
619"#), 623 "#,
620 @r###" 624 expect![[r#"
621 65..69 'self': Self 625 65..69 'self': Self
622 267..271 'self': Self 626 267..271 'self': Self
623 466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> 627 466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
624 488..522 '{ ... }': () 628 488..522 '{ ... }': ()
625 498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> 629 498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
626 498..508 'self.order': O 630 498..508 'self.order': O
627 498..515 'self.o...into()': dyn QueryFragment<DB> 631 498..515 'self.o...into()': dyn QueryFragment<DB>
628 "### 632 "#]],
629 ); 633 );
630} 634}
631 635
632#[test] 636#[test]
633fn issue_4953() { 637fn issue_4953() {
634 assert_snapshot!( 638 check_infer(
635 infer(r#" 639 r#"
636pub struct Foo(pub i64); 640 pub struct Foo(pub i64);
637impl Foo { 641 impl Foo {
638 fn test() -> Self { Self(0i64) } 642 fn test() -> Self { Self(0i64) }
639} 643 }
640"#), 644 "#,
641 @r###" 645 expect![[r#"
642 58..72 '{ Self(0i64) }': Foo 646 58..72 '{ Self(0i64) }': Foo
643 60..64 'Self': Foo(i64) -> Foo 647 60..64 'Self': Foo(i64) -> Foo
644 60..70 'Self(0i64)': Foo 648 60..70 'Self(0i64)': Foo
645 65..69 '0i64': i64 649 65..69 '0i64': i64
646 "### 650 "#]],
647 ); 651 );
648 assert_snapshot!( 652 check_infer(
649 infer(r#" 653 r#"
650pub struct Foo<T>(pub T); 654 pub struct Foo<T>(pub T);
651impl Foo<i64> { 655 impl Foo<i64> {
652 fn test() -> Self { Self(0i64) } 656 fn test() -> Self { Self(0i64) }
653} 657 }
654"#), 658 "#,
655 @r###" 659 expect![[r#"
656 64..78 '{ Self(0i64) }': Foo<i64> 660 64..78 '{ Self(0i64) }': Foo<i64>
657 66..70 'Self': Foo<i64>(i64) -> Foo<i64> 661 66..70 'Self': Foo<i64>(i64) -> Foo<i64>
658 66..76 'Self(0i64)': Foo<i64> 662 66..76 'Self(0i64)': Foo<i64>
659 71..75 '0i64': i64 663 71..75 '0i64': i64
660 "### 664 "#]],
661 ); 665 );
662} 666}
663 667
664#[test] 668#[test]
665fn issue_4931() { 669fn issue_4931() {
666 assert_snapshot!( 670 check_infer(
667 infer(r#" 671 r#"
668trait Div<T> { 672 trait Div<T> {
669 type Output; 673 type Output;
670} 674 }
671 675
672trait CheckedDiv: Div<()> {} 676 trait CheckedDiv: Div<()> {}
673 677
674trait PrimInt: CheckedDiv<Output = ()> { 678 trait PrimInt: CheckedDiv<Output = ()> {
675 fn pow(self); 679 fn pow(self);
676} 680 }
677 681
678fn check<T: PrimInt>(i: T) { 682 fn check<T: PrimInt>(i: T) {
679 i.pow(); 683 i.pow();
680} 684 }
681"#), 685 "#,
682 @r###" 686 expect![[r#"
683 117..121 'self': Self 687 117..121 'self': Self
684 148..149 'i': T 688 148..149 'i': T
685 154..170 '{ ...w(); }': () 689 154..170 '{ ...w(); }': ()
686 160..161 'i': T 690 160..161 'i': T
687 160..167 'i.pow()': () 691 160..167 'i.pow()': ()
688 "### 692 "#]],
689 ); 693 );
690} 694}
691 695
692#[test] 696#[test]
693fn issue_4885() { 697fn issue_4885() {
694 assert_snapshot!( 698 check_infer(
695 infer(r#" 699 r#"
696#[lang = "coerce_unsized"] 700 #[lang = "coerce_unsized"]
697pub trait CoerceUnsized<T> {} 701 pub trait CoerceUnsized<T> {}
698 702
699trait Future { 703 trait Future {
700 type Output; 704 type Output;
701} 705 }
702trait Foo<R> { 706 trait Foo<R> {
703 type Bar; 707 type Bar;
704} 708 }
705fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar> 709 fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar>
706where 710 where
707 K: Foo<R>, 711 K: Foo<R>,
708{ 712 {
709 bar(key) 713 bar(key)
710} 714 }
711fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar> 715 fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar>
712where 716 where
713 K: Foo<R>, 717 K: Foo<R>,
714{ 718 {
715} 719 }
716"#), 720 "#,
717 @r###" 721 expect![[r#"
718 136..139 'key': &K 722 136..139 'key': &K
719 198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> 723 198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
720 204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> 724 204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
721 204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> 725 204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
722 208..211 'key': &K 726 208..211 'key': &K
723 228..231 'key': &K 727 228..231 'key': &K
724 290..293 '{ }': () 728 290..293 '{ }': ()
725 "### 729 "#]],
726 ); 730 );
727} 731}
728 732
729#[test] 733#[test]
730fn issue_4800() { 734fn issue_4800() {
731 assert_snapshot!( 735 check_infer(
732 infer(r#" 736 r#"
733trait Debug {} 737 trait Debug {}
734 738
735struct Foo<T>; 739 struct Foo<T>;
736 740
737type E1<T> = (T, T, T); 741 type E1<T> = (T, T, T);
738type E2<T> = E1<E1<E1<(T, T, T)>>>; 742 type E2<T> = E1<E1<E1<(T, T, T)>>>;
739 743
740impl Debug for Foo<E2<()>> {} 744 impl Debug for Foo<E2<()>> {}
741 745
742struct Request; 746 struct Request;
743 747
744pub trait Future { 748 pub trait Future {
745 type Output; 749 type Output;
746} 750 }
747 751
748pub struct PeerSet<D>; 752 pub struct PeerSet<D>;
749 753
750impl<D> Service<Request> for PeerSet<D> 754 impl<D> Service<Request> for PeerSet<D>
751where 755 where
752 D: Discover, 756 D: Discover,
753 D::Key: Debug, 757 D::Key: Debug,
754{ 758 {
755 type Error = (); 759 type Error = ();
756 type Future = dyn Future<Output = Self::Error>; 760 type Future = dyn Future<Output = Self::Error>;
757 761
758 fn call(&mut self) -> Self::Future { 762 fn call(&mut self) -> Self::Future {
759 loop {} 763 loop {}
760 } 764 }
761} 765 }
762 766
763pub trait Discover { 767 pub trait Discover {
764 type Key; 768 type Key;
765} 769 }
766 770
767pub trait Service<Request> { 771 pub trait Service<Request> {
768 type Error; 772 type Error;
769 type Future: Future<Output = Self::Error>; 773 type Future: Future<Output = Self::Error>;
770 fn call(&mut self) -> Self::Future; 774 fn call(&mut self) -> Self::Future;
775 }
776 "#,
777 expect![[r#"
778 379..383 'self': &mut PeerSet<D>
779 401..424 '{ ... }': dyn Future<Output = ()>
780 411..418 'loop {}': !
781 416..418 '{}': ()
782 575..579 'self': &mut Self
783 "#]],
784 );
771} 785}
772"#), 786
773 @r###" 787#[test]
774 379..383 'self': &mut PeerSet<D> 788fn issue_4966() {
775 401..424 '{ ... }': dyn Future<Output = ()> 789 check_infer(
776 411..418 'loop {}': ! 790 r#"
777 416..418 '{}': () 791 pub trait IntoIterator {
778 575..579 'self': &mut Self 792 type Item;
779 "### 793 }
794
795 struct Repeat<A> { element: A }
796
797 struct Map<F> { f: F }
798
799 struct Vec<T> {}
800
801 #[lang = "deref"]
802 pub trait Deref {
803 type Target;
804 }
805
806 impl<T> Deref for Vec<T> {
807 type Target = [T];
808 }
809
810 fn from_iter<A, T: IntoIterator<Item = A>>(iter: T) -> Vec<A> {}
811
812 fn main() {
813 let inner = Map { f: |_: &f64| 0.0 };
814
815 let repeat = Repeat { element: inner };
816
817 let vec = from_iter(repeat);
818
819 vec.foo_bar();
820 }
821 "#,
822 expect![[r#"
823 270..274 'iter': T
824 289..291 '{}': ()
825 303..447 '{ ...r(); }': ()
826 313..318 'inner': Map<|&f64| -> f64>
827 321..345 'Map { ... 0.0 }': Map<|&f64| -> f64>
828 330..343 '|_: &f64| 0.0': |&f64| -> f64
829 331..332 '_': &f64
830 340..343 '0.0': f64
831 356..362 'repeat': Repeat<Map<|&f64| -> f64>>
832 365..390 'Repeat...nner }': Repeat<Map<|&f64| -> f64>>
833 383..388 'inner': Map<|&f64| -> f64>
834 401..404 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
835 407..416 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
836 407..424 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
837 417..423 'repeat': Repeat<Map<|&f64| -> f64>>
838 431..434 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
839 431..444 'vec.foo_bar()': {unknown}
840 "#]],
780 ); 841 );
781} 842}
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index de63f4cce..3fd7d5cd4 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -1,6 +1,6 @@
1use insta::assert_snapshot; 1use expect::expect;
2 2
3use super::{check_types, infer}; 3use super::{check_infer, check_types};
4 4
5#[test] 5#[test]
6fn infer_box() { 6fn infer_box() {
@@ -45,43 +45,44 @@ fn test() {
45 45
46#[test] 46#[test]
47fn self_in_struct_lit() { 47fn self_in_struct_lit() {
48 assert_snapshot!(infer( 48 check_infer(
49 r#" 49 r#"
50//- /main.rs 50 //- /main.rs
51struct S<T> { x: T } 51 struct S<T> { x: T }
52 52
53impl S<u32> { 53 impl S<u32> {
54 fn foo() { 54 fn foo() {
55 Self { x: 1 }; 55 Self { x: 1 };
56 } 56 }
57} 57 }
58"#, 58 "#,
59 ), @r###" 59 expect![[r#"
60 49..79 '{ ... }': () 60 49..79 '{ ... }': ()
61 59..72 'Self { x: 1 }': S<u32> 61 59..72 'Self { x: 1 }': S<u32>
62 69..70 '1': u32 62 69..70 '1': u32
63 "###); 63 "#]],
64 );
64} 65}
65 66
66#[test] 67#[test]
67fn type_alias_in_struct_lit() { 68fn type_alias_in_struct_lit() {
68 assert_snapshot!(infer( 69 check_infer(
69 r#" 70 r#"
70//- /main.rs 71 //- /main.rs
71struct S<T> { x: T } 72 struct S<T> { x: T }
72 73
73type SS = S<u32>; 74 type SS = S<u32>;
74 75
75fn foo() { 76 fn foo() {
76 SS { x: 1 }; 77 SS { x: 1 };
77} 78 }
78 79 "#,
79"#, 80 expect![[r#"
80 ), @r###" 81 50..70 '{ ...1 }; }': ()
81 50..70 '{ ...1 }; }': () 82 56..67 'SS { x: 1 }': S<u32>
82 56..67 'SS { x: 1 }': S<u32> 83 64..65 '1': u32
83 64..65 '1': u32 84 "#]],
84 "###); 85 );
85} 86}
86 87
87#[test] 88#[test]
@@ -148,1526 +149,1549 @@ fn test() {
148 149
149#[test] 150#[test]
150fn infer_basics() { 151fn infer_basics() {
151 assert_snapshot!( 152 check_infer(
152 infer(r#" 153 r#"
153fn test(a: u32, b: isize, c: !, d: &str) { 154 fn test(a: u32, b: isize, c: !, d: &str) {
154 a; 155 a;
155 b; 156 b;
156 c; 157 c;
157 d; 158 d;
158 1usize; 159 1usize;
159 1isize; 160 1isize;
160 "test"; 161 "test";
161 1.0f32; 162 1.0f32;
162}"#), 163 }"#,
163 @r###" 164 expect![[r#"
164 8..9 'a': u32 165 8..9 'a': u32
165 16..17 'b': isize 166 16..17 'b': isize
166 26..27 'c': ! 167 26..27 'c': !
167 32..33 'd': &str 168 32..33 'd': &str
168 41..120 '{ ...f32; }': () 169 41..120 '{ ...f32; }': ()
169 47..48 'a': u32 170 47..48 'a': u32
170 54..55 'b': isize 171 54..55 'b': isize
171 61..62 'c': ! 172 61..62 'c': !
172 68..69 'd': &str 173 68..69 'd': &str
173 75..81 '1usize': usize 174 75..81 '1usize': usize
174 87..93 '1isize': isize 175 87..93 '1isize': isize
175 99..105 '"test"': &str 176 99..105 '"test"': &str
176 111..117 '1.0f32': f32 177 111..117 '1.0f32': f32
177 "### 178 "#]],
178 ); 179 );
179} 180}
180 181
181#[test] 182#[test]
182fn infer_let() { 183fn infer_let() {
183 assert_snapshot!( 184 check_infer(
184 infer(r#" 185 r#"
185fn test() { 186 fn test() {
186 let a = 1isize; 187 let a = 1isize;
187 let b: usize = 1; 188 let b: usize = 1;
188 let c = b; 189 let c = b;
189 let d: u32; 190 let d: u32;
190 let e; 191 let e;
191 let f: i32 = e; 192 let f: i32 = e;
192} 193 }
193"#), 194 "#,
194 @r###" 195 expect![[r#"
195 10..117 '{ ...= e; }': () 196 10..117 '{ ...= e; }': ()
196 20..21 'a': isize 197 20..21 'a': isize
197 24..30 '1isize': isize 198 24..30 '1isize': isize
198 40..41 'b': usize 199 40..41 'b': usize
199 51..52 '1': usize 200 51..52 '1': usize
200 62..63 'c': usize 201 62..63 'c': usize
201 66..67 'b': usize 202 66..67 'b': usize
202 77..78 'd': u32 203 77..78 'd': u32
203 93..94 'e': i32 204 93..94 'e': i32
204 104..105 'f': i32 205 104..105 'f': i32
205 113..114 'e': i32 206 113..114 'e': i32
206 "### 207 "#]],
207 ); 208 );
208} 209}
209 210
210#[test] 211#[test]
211fn infer_paths() { 212fn infer_paths() {
212 assert_snapshot!( 213 check_infer(
213 infer(r#" 214 r#"
214fn a() -> u32 { 1 } 215 fn a() -> u32 { 1 }
215 216
216mod b { 217 mod b {
217 fn c() -> u32 { 1 } 218 fn c() -> u32 { 1 }
218} 219 }
219 220
220fn test() { 221 fn test() {
221 a(); 222 a();
222 b::c(); 223 b::c();
223} 224 }
224"#), 225 "#,
225 @r###" 226 expect![[r#"
226 14..19 '{ 1 }': u32 227 14..19 '{ 1 }': u32
227 16..17 '1': u32 228 16..17 '1': u32
228 47..52 '{ 1 }': u32 229 47..52 '{ 1 }': u32
229 49..50 '1': u32 230 49..50 '1': u32
230 66..90 '{ ...c(); }': () 231 66..90 '{ ...c(); }': ()
231 72..73 'a': fn a() -> u32 232 72..73 'a': fn a() -> u32
232 72..75 'a()': u32 233 72..75 'a()': u32
233 81..85 'b::c': fn c() -> u32 234 81..85 'b::c': fn c() -> u32
234 81..87 'b::c()': u32 235 81..87 'b::c()': u32
235 "### 236 "#]],
236 ); 237 );
237} 238}
238 239
239#[test] 240#[test]
240fn infer_path_type() { 241fn infer_path_type() {
241 assert_snapshot!( 242 check_infer(
242 infer(r#" 243 r#"
243struct S; 244 struct S;
244 245
245impl S { 246 impl S {
246 fn foo() -> i32 { 1 } 247 fn foo() -> i32 { 1 }
247} 248 }
248 249
249fn test() { 250 fn test() {
250 S::foo(); 251 S::foo();
251 <S>::foo(); 252 <S>::foo();
252} 253 }
253"#), 254 "#,
254 @r###" 255 expect![[r#"
255 40..45 '{ 1 }': i32 256 40..45 '{ 1 }': i32
256 42..43 '1': i32 257 42..43 '1': i32
257 59..92 '{ ...o(); }': () 258 59..92 '{ ...o(); }': ()
258 65..71 'S::foo': fn foo() -> i32 259 65..71 'S::foo': fn foo() -> i32
259 65..73 'S::foo()': i32 260 65..73 'S::foo()': i32
260 79..87 '<S>::foo': fn foo() -> i32 261 79..87 '<S>::foo': fn foo() -> i32
261 79..89 '<S>::foo()': i32 262 79..89 '<S>::foo()': i32
262 "### 263 "#]],
263 ); 264 );
264} 265}
265 266
266#[test] 267#[test]
267fn infer_struct() { 268fn infer_struct() {
268 assert_snapshot!( 269 check_infer(
269 infer(r#" 270 r#"
270struct A { 271 struct A {
271 b: B, 272 b: B,
272 c: C, 273 c: C,
273} 274 }
274struct B; 275 struct B;
275struct C(usize); 276 struct C(usize);
276 277
277fn test() { 278 fn test() {
278 let c = C(1); 279 let c = C(1);
279 B; 280 B;
280 let a: A = A { b: B, c: C(1) }; 281 let a: A = A { b: B, c: C(1) };
281 a.b; 282 a.b;
282 a.c; 283 a.c;
283} 284 }
284"#), 285 "#,
285 @r###" 286 expect![[r#"
286 71..153 '{ ...a.c; }': () 287 71..153 '{ ...a.c; }': ()
287 81..82 'c': C 288 81..82 'c': C
288 85..86 'C': C(usize) -> C 289 85..86 'C': C(usize) -> C
289 85..89 'C(1)': C 290 85..89 'C(1)': C
290 87..88 '1': usize 291 87..88 '1': usize
291 95..96 'B': B 292 95..96 'B': B
292 106..107 'a': A 293 106..107 'a': A
293 113..132 'A { b:...C(1) }': A 294 113..132 'A { b:...C(1) }': A
294 120..121 'B': B 295 120..121 'B': B
295 126..127 'C': C(usize) -> C 296 126..127 'C': C(usize) -> C
296 126..130 'C(1)': C 297 126..130 'C(1)': C
297 128..129 '1': usize 298 128..129 '1': usize
298 138..139 'a': A 299 138..139 'a': A
299 138..141 'a.b': B 300 138..141 'a.b': B
300 147..148 'a': A 301 147..148 'a': A
301 147..150 'a.c': C 302 147..150 'a.c': C
302 "### 303 "#]],
303 ); 304 );
304} 305}
305 306
306#[test] 307#[test]
307fn infer_enum() { 308fn infer_enum() {
308 assert_snapshot!( 309 check_infer(
309 infer(r#" 310 r#"
310enum E { 311 enum E {
311 V1 { field: u32 }, 312 V1 { field: u32 },
312 V2 313 V2
314 }
315 fn test() {
316 E::V1 { field: 1 };
317 E::V2;
318 }"#,
319 expect![[r#"
320 51..89 '{ ...:V2; }': ()
321 57..75 'E::V1 ...d: 1 }': E
322 72..73 '1': u32
323 81..86 'E::V2': E
324 "#]],
325 );
313} 326}
314fn test() { 327
315 E::V1 { field: 1 }; 328#[test]
316 E::V2; 329fn infer_union() {
317}"#), 330 check_infer(
318 @r###" 331 r#"
319 47..81 '{ E:...:V2; }': () 332 union MyUnion {
320 51..69 'E::V1 ...d: 1 }': E 333 foo: u32,
321 66..67 '1': u32 334 bar: f32,
322 73..78 'E::V2': E 335 }
323 "### 336
337 unsafe fn baz(u: MyUnion) {
338 let inner = u.foo;
339 }
340 "#,
341 expect![[r#"
342 61..62 'u': MyUnion
343 73..99 '{ ...foo; }': ()
344 83..88 'inner': u32
345 91..92 'u': MyUnion
346 91..96 'u.foo': u32
347 "#]],
324 ); 348 );
325} 349}
326 350
327#[test] 351#[test]
328fn infer_refs() { 352fn infer_refs() {
329 assert_snapshot!( 353 check_infer(
330 infer(r#" 354 r#"
331fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { 355 fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
332 a; 356 a;
333 *a; 357 *a;
334 &a; 358 &a;
335 &mut a; 359 &mut a;
336 b; 360 b;
337 *b; 361 *b;
338 &b; 362 &b;
339 c; 363 c;
340 *c; 364 *c;
341 d; 365 d;
342 *d; 366 *d;
343} 367 }
344"#), 368 "#,
345 @r###" 369 expect![[r#"
346 8..9 'a': &u32 370 8..9 'a': &u32
347 17..18 'b': &mut u32 371 17..18 'b': &mut u32
348 30..31 'c': *const u32 372 30..31 'c': *const u32
349 45..46 'd': *mut u32 373 45..46 'd': *mut u32
350 58..149 '{ ... *d; }': () 374 58..149 '{ ... *d; }': ()
351 64..65 'a': &u32 375 64..65 'a': &u32
352 71..73 '*a': u32 376 71..73 '*a': u32
353 72..73 'a': &u32 377 72..73 'a': &u32
354 79..81 '&a': &&u32 378 79..81 '&a': &&u32
355 80..81 'a': &u32 379 80..81 'a': &u32
356 87..93 '&mut a': &mut &u32 380 87..93 '&mut a': &mut &u32
357 92..93 'a': &u32 381 92..93 'a': &u32
358 99..100 'b': &mut u32 382 99..100 'b': &mut u32
359 106..108 '*b': u32 383 106..108 '*b': u32
360 107..108 'b': &mut u32 384 107..108 'b': &mut u32
361 114..116 '&b': &&mut u32 385 114..116 '&b': &&mut u32
362 115..116 'b': &mut u32 386 115..116 'b': &mut u32
363 122..123 'c': *const u32 387 122..123 'c': *const u32
364 129..131 '*c': u32 388 129..131 '*c': u32
365 130..131 'c': *const u32 389 130..131 'c': *const u32
366 137..138 'd': *mut u32 390 137..138 'd': *mut u32
367 144..146 '*d': u32 391 144..146 '*d': u32
368 145..146 'd': *mut u32 392 145..146 'd': *mut u32
369 "### 393 "#]],
370 ); 394 );
371} 395}
372 396
373#[test] 397#[test]
374fn infer_raw_ref() { 398fn infer_raw_ref() {
375 assert_snapshot!( 399 check_infer(
376 infer(r#" 400 r#"
377fn test(a: i32) { 401 fn test(a: i32) {
378 &raw mut a; 402 &raw mut a;
379 &raw const a; 403 &raw const a;
380} 404 }
381"#), 405 "#,
382 @r###" 406 expect![[r#"
383 8..9 'a': i32 407 8..9 'a': i32
384 16..53 '{ ...t a; }': () 408 16..53 '{ ...t a; }': ()
385 22..32 '&raw mut a': *mut i32 409 22..32 '&raw mut a': *mut i32
386 31..32 'a': i32 410 31..32 'a': i32
387 38..50 '&raw const a': *const i32 411 38..50 '&raw const a': *const i32
388 49..50 'a': i32 412 49..50 'a': i32
389 "### 413 "#]],
390 ); 414 );
391} 415}
392 416
393#[test] 417#[test]
394fn infer_literals() { 418fn infer_literals() {
395 assert_snapshot!( 419 check_infer(
396 infer(r##" 420 r##"
397fn test() { 421 fn test() {
398 5i32; 422 5i32;
399 5f32; 423 5f32;
400 5f64; 424 5f64;
401 "hello"; 425 "hello";
402 b"bytes"; 426 b"bytes";
403 'c'; 427 'c';
404 b'b'; 428 b'b';
405 3.14; 429 3.14;
406 5000; 430 5000;
407 false; 431 false;
408 true; 432 true;
409 r#" 433 r#"
410 //! doc 434 //! doc
411 // non-doc 435 // non-doc
412 mod foo {} 436 mod foo {}
413 "#; 437 "#;
414 br#"yolo"#; 438 br#"yolo"#;
415} 439 }
416"##), 440 "##,
417 @r###" 441 expect![[r##"
418 10..220 '{ ...o"#; }': () 442 10..216 '{ ...o"#; }': ()
419 16..20 '5i32': i32 443 16..20 '5i32': i32
420 26..30 '5f32': f32 444 26..30 '5f32': f32
421 36..40 '5f64': f64 445 36..40 '5f64': f64
422 46..53 '"hello"': &str 446 46..53 '"hello"': &str
423 59..67 'b"bytes"': &[u8; _] 447 59..67 'b"bytes"': &[u8; _]
424 73..76 ''c'': char 448 73..76 ''c'': char
425 82..86 'b'b'': u8 449 82..86 'b'b'': u8
426 92..96 '3.14': f64 450 92..96 '3.14': f64
427 102..106 '5000': i32 451 102..106 '5000': i32
428 112..117 'false': bool 452 112..117 'false': bool
429 123..127 'true': bool 453 123..127 'true': bool
430 133..201 'r#" ... "#': &str 454 133..197 'r#" ... "#': &str
431 207..217 'br#"yolo"#': &[u8; _] 455 203..213 'br#"yolo"#': &[u8; _]
432 "### 456 "##]],
433 ); 457 );
434} 458}
435 459
436#[test] 460#[test]
437fn infer_unary_op() { 461fn infer_unary_op() {
438 assert_snapshot!( 462 check_infer(
439 infer(r#" 463 r#"
440enum SomeType {} 464 enum SomeType {}
441 465
442fn test(x: SomeType) { 466 fn test(x: SomeType) {
443 let b = false; 467 let b = false;
444 let c = !b; 468 let c = !b;
445 let a = 100; 469 let a = 100;
446 let d: i128 = -a; 470 let d: i128 = -a;
447 let e = -100; 471 let e = -100;
448 let f = !!!true; 472 let f = !!!true;
449 let g = !42; 473 let g = !42;
450 let h = !10u32; 474 let h = !10u32;
451 let j = !a; 475 let j = !a;
452 -3.14; 476 -3.14;
453 !3; 477 !3;
454 -x; 478 -x;
455 !x; 479 !x;
456 -"hello"; 480 -"hello";
457 !"hello"; 481 !"hello";
458} 482 }
459"#), 483 "#,
460 @r###" 484 expect![[r#"
461 26..27 'x': SomeType 485 26..27 'x': SomeType
462 39..271 '{ ...lo"; }': () 486 39..271 '{ ...lo"; }': ()
463 49..50 'b': bool 487 49..50 'b': bool
464 53..58 'false': bool 488 53..58 'false': bool
465 68..69 'c': bool 489 68..69 'c': bool
466 72..74 '!b': bool 490 72..74 '!b': bool
467 73..74 'b': bool 491 73..74 'b': bool
468 84..85 'a': i128 492 84..85 'a': i128
469 88..91 '100': i128 493 88..91 '100': i128
470 101..102 'd': i128 494 101..102 'd': i128
471 111..113 '-a': i128 495 111..113 '-a': i128
472 112..113 'a': i128 496 112..113 'a': i128
473 123..124 'e': i32 497 123..124 'e': i32
474 127..131 '-100': i32 498 127..131 '-100': i32
475 128..131 '100': i32 499 128..131 '100': i32
476 141..142 'f': bool 500 141..142 'f': bool
477 145..152 '!!!true': bool 501 145..152 '!!!true': bool
478 146..152 '!!true': bool 502 146..152 '!!true': bool
479 147..152 '!true': bool 503 147..152 '!true': bool
480 148..152 'true': bool 504 148..152 'true': bool
481 162..163 'g': i32 505 162..163 'g': i32
482 166..169 '!42': i32 506 166..169 '!42': i32
483 167..169 '42': i32 507 167..169 '42': i32
484 179..180 'h': u32 508 179..180 'h': u32
485 183..189 '!10u32': u32 509 183..189 '!10u32': u32
486 184..189 '10u32': u32 510 184..189 '10u32': u32
487 199..200 'j': i128 511 199..200 'j': i128
488 203..205 '!a': i128 512 203..205 '!a': i128
489 204..205 'a': i128 513 204..205 'a': i128
490 211..216 '-3.14': f64 514 211..216 '-3.14': f64
491 212..216 '3.14': f64 515 212..216 '3.14': f64
492 222..224 '!3': i32 516 222..224 '!3': i32
493 223..224 '3': i32 517 223..224 '3': i32
494 230..232 '-x': {unknown} 518 230..232 '-x': {unknown}
495 231..232 'x': SomeType 519 231..232 'x': SomeType
496 238..240 '!x': {unknown} 520 238..240 '!x': {unknown}
497 239..240 'x': SomeType 521 239..240 'x': SomeType
498 246..254 '-"hello"': {unknown} 522 246..254 '-"hello"': {unknown}
499 247..254 '"hello"': &str 523 247..254 '"hello"': &str
500 260..268 '!"hello"': {unknown} 524 260..268 '!"hello"': {unknown}
501 261..268 '"hello"': &str 525 261..268 '"hello"': &str
502 "### 526 "#]],
503 ); 527 );
504} 528}
505 529
506#[test] 530#[test]
507fn infer_backwards() { 531fn infer_backwards() {
508 assert_snapshot!( 532 check_infer(
509 infer(r#" 533 r#"
510fn takes_u32(x: u32) {} 534 fn takes_u32(x: u32) {}
511 535
512struct S { i32_field: i32 } 536 struct S { i32_field: i32 }
513 537
514fn test() -> &mut &f64 { 538 fn test() -> &mut &f64 {
515 let a = unknown_function(); 539 let a = unknown_function();
516 takes_u32(a); 540 takes_u32(a);
517 let b = unknown_function(); 541 let b = unknown_function();
518 S { i32_field: b }; 542 S { i32_field: b };
519 let c = unknown_function(); 543 let c = unknown_function();
520 &mut &c 544 &mut &c
521} 545 }
522"#), 546 "#,
523 @r###" 547 expect![[r#"
524 13..14 'x': u32 548 13..14 'x': u32
525 21..23 '{}': () 549 21..23 '{}': ()
526 77..230 '{ ...t &c }': &mut &f64 550 77..230 '{ ...t &c }': &mut &f64
527 87..88 'a': u32 551 87..88 'a': u32
528 91..107 'unknow...nction': {unknown} 552 91..107 'unknow...nction': {unknown}
529 91..109 'unknow...tion()': u32 553 91..109 'unknow...tion()': u32
530 115..124 'takes_u32': fn takes_u32(u32) 554 115..124 'takes_u32': fn takes_u32(u32)
531 115..127 'takes_u32(a)': () 555 115..127 'takes_u32(a)': ()
532 125..126 'a': u32 556 125..126 'a': u32
533 137..138 'b': i32 557 137..138 'b': i32
534 141..157 'unknow...nction': {unknown} 558 141..157 'unknow...nction': {unknown}
535 141..159 'unknow...tion()': i32 559 141..159 'unknow...tion()': i32
536 165..183 'S { i3...d: b }': S 560 165..183 'S { i3...d: b }': S
537 180..181 'b': i32 561 180..181 'b': i32
538 193..194 'c': f64 562 193..194 'c': f64
539 197..213 'unknow...nction': {unknown} 563 197..213 'unknow...nction': {unknown}
540 197..215 'unknow...tion()': f64 564 197..215 'unknow...tion()': f64
541 221..228 '&mut &c': &mut &f64 565 221..228 '&mut &c': &mut &f64
542 226..228 '&c': &f64 566 226..228 '&c': &f64
543 227..228 'c': f64 567 227..228 'c': f64
544 "### 568 "#]],
545 ); 569 );
546} 570}
547 571
548#[test] 572#[test]
549fn infer_self() { 573fn infer_self() {
550 assert_snapshot!( 574 check_infer(
551 infer(r#" 575 r#"
552struct S; 576 struct S;
553 577
554impl S { 578 impl S {
555 fn test(&self) { 579 fn test(&self) {
556 self; 580 self;
557 } 581 }
558 fn test2(self: &Self) { 582 fn test2(self: &Self) {
559 self; 583 self;
560 } 584 }
561 fn test3() -> Self { 585 fn test3() -> Self {
562 S {} 586 S {}
563 } 587 }
564 fn test4() -> Self { 588 fn test4() -> Self {
565 Self {} 589 Self {}
566 } 590 }
567} 591 }
568"#), 592 "#,
569 @r###" 593 expect![[r#"
570 33..37 'self': &S 594 33..37 'self': &S
571 39..60 '{ ... }': () 595 39..60 '{ ... }': ()
572 49..53 'self': &S 596 49..53 'self': &S
573 74..78 'self': &S 597 74..78 'self': &S
574 87..108 '{ ... }': () 598 87..108 '{ ... }': ()
575 97..101 'self': &S 599 97..101 'self': &S
576 132..152 '{ ... }': S 600 132..152 '{ ... }': S
577 142..146 'S {}': S 601 142..146 'S {}': S
578 176..199 '{ ... }': S 602 176..199 '{ ... }': S
579 186..193 'Self {}': S 603 186..193 'Self {}': S
580 "### 604 "#]],
581 ); 605 );
582} 606}
583 607
584#[test] 608#[test]
585fn infer_self_as_path() { 609fn infer_self_as_path() {
586 assert_snapshot!( 610 check_infer(
587 infer(r#" 611 r#"
588struct S1; 612 struct S1;
589struct S2(isize); 613 struct S2(isize);
590enum E { 614 enum E {
591 V1, 615 V1,
592 V2(u32), 616 V2(u32),
593} 617 }
594 618
595impl S1 { 619 impl S1 {
596 fn test() { 620 fn test() {
597 Self; 621 Self;
598 } 622 }
599} 623 }
600impl S2 { 624 impl S2 {
601 fn test() { 625 fn test() {
602 Self(1); 626 Self(1);
603 } 627 }
604} 628 }
605impl E { 629 impl E {
606 fn test() { 630 fn test() {
607 Self::V1; 631 Self::V1;
608 Self::V2(1); 632 Self::V2(1);
609 } 633 }
610} 634 }
611"#), 635 "#,
612 @r###" 636 expect![[r#"
613 86..107 '{ ... }': () 637 86..107 '{ ... }': ()
614 96..100 'Self': S1 638 96..100 'Self': S1
615 134..158 '{ ... }': () 639 134..158 '{ ... }': ()
616 144..148 'Self': S2(isize) -> S2 640 144..148 'Self': S2(isize) -> S2
617 144..151 'Self(1)': S2 641 144..151 'Self(1)': S2
618 149..150 '1': isize 642 149..150 '1': isize
619 184..230 '{ ... }': () 643 184..230 '{ ... }': ()
620 194..202 'Self::V1': E 644 194..202 'Self::V1': E
621 212..220 'Self::V2': V2(u32) -> E 645 212..220 'Self::V2': V2(u32) -> E
622 212..223 'Self::V2(1)': E 646 212..223 'Self::V2(1)': E
623 221..222 '1': u32 647 221..222 '1': u32
624 "### 648 "#]],
625 ); 649 );
626} 650}
627 651
628#[test] 652#[test]
629fn infer_binary_op() { 653fn infer_binary_op() {
630 assert_snapshot!( 654 check_infer(
631 infer(r#" 655 r#"
632fn f(x: bool) -> i32 { 656 fn f(x: bool) -> i32 {
633 0i32 657 0i32
634} 658 }
635 659
636fn test() -> bool { 660 fn test() -> bool {
637 let x = a && b; 661 let x = a && b;
638 let y = true || false; 662 let y = true || false;
639 let z = x == y; 663 let z = x == y;
640 let t = x != y; 664 let t = x != y;
641 let minus_forty: isize = -40isize; 665 let minus_forty: isize = -40isize;
642 let h = minus_forty <= CONST_2; 666 let h = minus_forty <= CONST_2;
643 let c = f(z || y) + 5; 667 let c = f(z || y) + 5;
644 let d = b; 668 let d = b;
645 let g = minus_forty ^= i; 669 let g = minus_forty ^= i;
646 let ten: usize = 10; 670 let ten: usize = 10;
647 let ten_is_eleven = ten == some_num; 671 let ten_is_eleven = ten == some_num;
648 672
649 ten < 3 673 ten < 3
650} 674 }
651"#), 675 "#,
652 @r###" 676 expect![[r#"
653 5..6 'x': bool 677 5..6 'x': bool
654 21..33 '{ 0i32 }': i32 678 21..33 '{ 0i32 }': i32
655 27..31 '0i32': i32 679 27..31 '0i32': i32
656 53..369 '{ ... < 3 }': bool 680 53..369 '{ ... < 3 }': bool
657 63..64 'x': bool 681 63..64 'x': bool
658 67..68 'a': bool 682 67..68 'a': bool
659 67..73 'a && b': bool 683 67..73 'a && b': bool
660 72..73 'b': bool 684 72..73 'b': bool
661 83..84 'y': bool 685 83..84 'y': bool
662 87..91 'true': bool 686 87..91 'true': bool
663 87..100 'true || false': bool 687 87..100 'true || false': bool
664 95..100 'false': bool 688 95..100 'false': bool
665 110..111 'z': bool 689 110..111 'z': bool
666 114..115 'x': bool 690 114..115 'x': bool
667 114..120 'x == y': bool 691 114..120 'x == y': bool
668 119..120 'y': bool 692 119..120 'y': bool
669 130..131 't': bool 693 130..131 't': bool
670 134..135 'x': bool 694 134..135 'x': bool
671 134..140 'x != y': bool 695 134..140 'x != y': bool
672 139..140 'y': bool 696 139..140 'y': bool
673 150..161 'minus_forty': isize 697 150..161 'minus_forty': isize
674 171..179 '-40isize': isize 698 171..179 '-40isize': isize
675 172..179 '40isize': isize 699 172..179 '40isize': isize
676 189..190 'h': bool 700 189..190 'h': bool
677 193..204 'minus_forty': isize 701 193..204 'minus_forty': isize
678 193..215 'minus_...ONST_2': bool 702 193..215 'minus_...ONST_2': bool
679 208..215 'CONST_2': isize 703 208..215 'CONST_2': isize
680 225..226 'c': i32 704 225..226 'c': i32
681 229..230 'f': fn f(bool) -> i32 705 229..230 'f': fn f(bool) -> i32
682 229..238 'f(z || y)': i32 706 229..238 'f(z || y)': i32
683 229..242 'f(z || y) + 5': i32 707 229..242 'f(z || y) + 5': i32
684 231..232 'z': bool 708 231..232 'z': bool
685 231..237 'z || y': bool 709 231..237 'z || y': bool
686 236..237 'y': bool 710 236..237 'y': bool
687 241..242 '5': i32 711 241..242 '5': i32
688 252..253 'd': {unknown} 712 252..253 'd': {unknown}
689 256..257 'b': {unknown} 713 256..257 'b': {unknown}
690 267..268 'g': () 714 267..268 'g': ()
691 271..282 'minus_forty': isize 715 271..282 'minus_forty': isize
692 271..287 'minus_...y ^= i': () 716 271..287 'minus_...y ^= i': ()
693 286..287 'i': isize 717 286..287 'i': isize
694 297..300 'ten': usize 718 297..300 'ten': usize
695 310..312 '10': usize 719 310..312 '10': usize
696 322..335 'ten_is_eleven': bool 720 322..335 'ten_is_eleven': bool
697 338..341 'ten': usize 721 338..341 'ten': usize
698 338..353 'ten == some_num': bool 722 338..353 'ten == some_num': bool
699 345..353 'some_num': usize 723 345..353 'some_num': usize
700 360..363 'ten': usize 724 360..363 'ten': usize
701 360..367 'ten < 3': bool 725 360..367 'ten < 3': bool
702 366..367 '3': usize 726 366..367 '3': usize
703 "### 727 "#]],
704 ); 728 );
705} 729}
706 730
707#[test] 731#[test]
708fn infer_shift_op() { 732fn infer_shift_op() {
709 assert_snapshot!( 733 check_infer(
710 infer(r#" 734 r#"
711fn test() { 735 fn test() {
712 1u32 << 5u8; 736 1u32 << 5u8;
713 1u32 >> 5u8; 737 1u32 >> 5u8;
714} 738 }
715"#), 739 "#,
716 @r###" 740 expect![[r#"
717 10..47 '{ ...5u8; }': () 741 10..47 '{ ...5u8; }': ()
718 16..20 '1u32': u32 742 16..20 '1u32': u32
719 16..27 '1u32 << 5u8': u32 743 16..27 '1u32 << 5u8': u32
720 24..27 '5u8': u8 744 24..27 '5u8': u8
721 33..37 '1u32': u32 745 33..37 '1u32': u32
722 33..44 '1u32 >> 5u8': u32 746 33..44 '1u32 >> 5u8': u32
723 41..44 '5u8': u8 747 41..44 '5u8': u8
724 "### 748 "#]],
725 ); 749 );
726} 750}
727 751
728#[test] 752#[test]
729fn infer_field_autoderef() { 753fn infer_field_autoderef() {
730 assert_snapshot!( 754 check_infer(
731 infer(r#" 755 r#"
732struct A { 756 struct A {
733 b: B, 757 b: B,
734} 758 }
735struct B; 759 struct B;
736 760
737fn test1(a: A) { 761 fn test1(a: A) {
738 let a1 = a; 762 let a1 = a;
739 a1.b; 763 a1.b;
740 let a2 = &a; 764 let a2 = &a;
741 a2.b; 765 a2.b;
742 let a3 = &mut a; 766 let a3 = &mut a;
743 a3.b; 767 a3.b;
744 let a4 = &&&&&&&a; 768 let a4 = &&&&&&&a;
745 a4.b; 769 a4.b;
746 let a5 = &mut &&mut &&mut a; 770 let a5 = &mut &&mut &&mut a;
747 a5.b; 771 a5.b;
748} 772 }
749 773
750fn test2(a1: *const A, a2: *mut A) { 774 fn test2(a1: *const A, a2: *mut A) {
751 a1.b; 775 a1.b;
752 a2.b; 776 a2.b;
753} 777 }
754"#), 778 "#,
755 @r###" 779 expect![[r#"
756 43..44 'a': A 780 43..44 'a': A
757 49..212 '{ ...5.b; }': () 781 49..212 '{ ...5.b; }': ()
758 59..61 'a1': A 782 59..61 'a1': A
759 64..65 'a': A 783 64..65 'a': A
760 71..73 'a1': A 784 71..73 'a1': A
761 71..75 'a1.b': B 785 71..75 'a1.b': B
762 85..87 'a2': &A 786 85..87 'a2': &A
763 90..92 '&a': &A 787 90..92 '&a': &A
764 91..92 'a': A 788 91..92 'a': A
765 98..100 'a2': &A 789 98..100 'a2': &A
766 98..102 'a2.b': B 790 98..102 'a2.b': B
767 112..114 'a3': &mut A 791 112..114 'a3': &mut A
768 117..123 '&mut a': &mut A 792 117..123 '&mut a': &mut A
769 122..123 'a': A 793 122..123 'a': A
770 129..131 'a3': &mut A 794 129..131 'a3': &mut A
771 129..133 'a3.b': B 795 129..133 'a3.b': B
772 143..145 'a4': &&&&&&&A 796 143..145 'a4': &&&&&&&A
773 148..156 '&&&&&&&a': &&&&&&&A 797 148..156 '&&&&&&&a': &&&&&&&A
774 149..156 '&&&&&&a': &&&&&&A 798 149..156 '&&&&&&a': &&&&&&A
775 150..156 '&&&&&a': &&&&&A 799 150..156 '&&&&&a': &&&&&A
776 151..156 '&&&&a': &&&&A 800 151..156 '&&&&a': &&&&A
777 152..156 '&&&a': &&&A 801 152..156 '&&&a': &&&A
778 153..156 '&&a': &&A 802 153..156 '&&a': &&A
779 154..156 '&a': &A 803 154..156 '&a': &A
780 155..156 'a': A 804 155..156 'a': A
781 162..164 'a4': &&&&&&&A 805 162..164 'a4': &&&&&&&A
782 162..166 'a4.b': B 806 162..166 'a4.b': B
783 176..178 'a5': &mut &&mut &&mut A 807 176..178 'a5': &mut &&mut &&mut A
784 181..199 '&mut &...&mut a': &mut &&mut &&mut A 808 181..199 '&mut &...&mut a': &mut &&mut &&mut A
785 186..199 '&&mut &&mut a': &&mut &&mut A 809 186..199 '&&mut &&mut a': &&mut &&mut A
786 187..199 '&mut &&mut a': &mut &&mut A 810 187..199 '&mut &&mut a': &mut &&mut A
787 192..199 '&&mut a': &&mut A 811 192..199 '&&mut a': &&mut A
788 193..199 '&mut a': &mut A 812 193..199 '&mut a': &mut A
789 198..199 'a': A 813 198..199 'a': A
790 205..207 'a5': &mut &&mut &&mut A 814 205..207 'a5': &mut &&mut &&mut A
791 205..209 'a5.b': B 815 205..209 'a5.b': B
792 223..225 'a1': *const A 816 223..225 'a1': *const A
793 237..239 'a2': *mut A 817 237..239 'a2': *mut A
794 249..272 '{ ...2.b; }': () 818 249..272 '{ ...2.b; }': ()
795 255..257 'a1': *const A 819 255..257 'a1': *const A
796 255..259 'a1.b': B 820 255..259 'a1.b': B
797 265..267 'a2': *mut A 821 265..267 'a2': *mut A
798 265..269 'a2.b': B 822 265..269 'a2.b': B
799 "### 823 "#]],
800 ); 824 );
801} 825}
802 826
803#[test] 827#[test]
804fn infer_argument_autoderef() { 828fn infer_argument_autoderef() {
805 assert_snapshot!( 829 check_infer(
806 infer(r#" 830 r#"
807#[lang = "deref"] 831 #[lang = "deref"]
808pub trait Deref { 832 pub trait Deref {
809 type Target; 833 type Target;
810 fn deref(&self) -> &Self::Target; 834 fn deref(&self) -> &Self::Target;
811} 835 }
812 836
813struct A<T>(T); 837 struct A<T>(T);
814 838
815impl<T> A<T> { 839 impl<T> A<T> {
816 fn foo(&self) -> &T { 840 fn foo(&self) -> &T {
817 &self.0 841 &self.0
818 } 842 }
819} 843 }
820 844
821struct B<T>(T); 845 struct B<T>(T);
822 846
823impl<T> Deref for B<T> { 847 impl<T> Deref for B<T> {
824 type Target = T; 848 type Target = T;
825 fn deref(&self) -> &Self::Target { 849 fn deref(&self) -> &Self::Target {
826 &self.0 850 &self.0
827 } 851 }
828} 852 }
829 853
830fn test() { 854 fn test() {
831 let t = A::foo(&&B(B(A(42)))); 855 let t = A::foo(&&B(B(A(42))));
832} 856 }
833"#), 857 "#,
834 @r###" 858 expect![[r#"
835 67..71 'self': &Self 859 67..71 'self': &Self
836 138..142 'self': &A<T> 860 138..142 'self': &A<T>
837 150..173 '{ ... }': &T 861 150..173 '{ ... }': &T
838 160..167 '&self.0': &T 862 160..167 '&self.0': &T
839 161..165 'self': &A<T> 863 161..165 'self': &A<T>
840 161..167 'self.0': T 864 161..167 'self.0': T
841 254..258 'self': &B<T> 865 254..258 'self': &B<T>
842 277..300 '{ ... }': &T 866 277..300 '{ ... }': &T
843 287..294 '&self.0': &T 867 287..294 '&self.0': &T
844 288..292 'self': &B<T> 868 288..292 'self': &B<T>
845 288..294 'self.0': T 869 288..294 'self.0': T
846 314..352 '{ ...))); }': () 870 314..352 '{ ...))); }': ()
847 324..325 't': &i32 871 324..325 't': &i32
848 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 872 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32
849 328..349 'A::foo...42))))': &i32 873 328..349 'A::foo...42))))': &i32
850 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> 874 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>>
851 336..348 '&B(B(A(42)))': &B<B<A<i32>>> 875 336..348 '&B(B(A(42)))': &B<B<A<i32>>>
852 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 876 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
853 337..348 'B(B(A(42)))': B<B<A<i32>>> 877 337..348 'B(B(A(42)))': B<B<A<i32>>>
854 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 878 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
855 339..347 'B(A(42))': B<A<i32>> 879 339..347 'B(A(42))': B<A<i32>>
856 341..342 'A': A<i32>(i32) -> A<i32> 880 341..342 'A': A<i32>(i32) -> A<i32>
857 341..346 'A(42)': A<i32> 881 341..346 'A(42)': A<i32>
858 343..345 '42': i32 882 343..345 '42': i32
859 "### 883 "#]],
860 ); 884 );
861} 885}
862 886
863#[test] 887#[test]
864fn infer_method_argument_autoderef() { 888fn infer_method_argument_autoderef() {
865 assert_snapshot!( 889 check_infer(
866 infer(r#" 890 r#"
867#[lang = "deref"] 891 #[lang = "deref"]
868pub trait Deref { 892 pub trait Deref {
869 type Target; 893 type Target;
870 fn deref(&self) -> &Self::Target; 894 fn deref(&self) -> &Self::Target;
871} 895 }
872 896
873struct A<T>(*mut T); 897 struct A<T>(*mut T);
874 898
875impl<T> A<T> { 899 impl<T> A<T> {
876 fn foo(&self, x: &A<T>) -> &T { 900 fn foo(&self, x: &A<T>) -> &T {
877 &*x.0 901 &*x.0
878 } 902 }
879} 903 }
880 904
881struct B<T>(T); 905 struct B<T>(T);
882 906
883impl<T> Deref for B<T> { 907 impl<T> Deref for B<T> {
884 type Target = T; 908 type Target = T;
885 fn deref(&self) -> &Self::Target { 909 fn deref(&self) -> &Self::Target {
886 &self.0 910 &self.0
887 } 911 }
888} 912 }
889 913
890fn test(a: A<i32>) { 914 fn test(a: A<i32>) {
891 let t = A(0 as *mut _).foo(&&B(B(a))); 915 let t = A(0 as *mut _).foo(&&B(B(a)));
892} 916 }
893"#), 917 "#,
894 @r###" 918 expect![[r#"
895 67..71 'self': &Self 919 67..71 'self': &Self
896 143..147 'self': &A<T> 920 143..147 'self': &A<T>
897 149..150 'x': &A<T> 921 149..150 'x': &A<T>
898 165..186 '{ ... }': &T 922 165..186 '{ ... }': &T
899 175..180 '&*x.0': &T 923 175..180 '&*x.0': &T
900 176..180 '*x.0': T 924 176..180 '*x.0': T
901 177..178 'x': &A<T> 925 177..178 'x': &A<T>
902 177..180 'x.0': *mut T 926 177..180 'x.0': *mut T
903 267..271 'self': &B<T> 927 267..271 'self': &B<T>
904 290..313 '{ ... }': &T 928 290..313 '{ ... }': &T
905 300..307 '&self.0': &T 929 300..307 '&self.0': &T
906 301..305 'self': &B<T> 930 301..305 'self': &B<T>
907 301..307 'self.0': T 931 301..307 'self.0': T
908 325..326 'a': A<i32> 932 325..326 'a': A<i32>
909 336..382 '{ ...))); }': () 933 336..382 '{ ...))); }': ()
910 346..347 't': &i32 934 346..347 't': &i32
911 350..351 'A': A<i32>(*mut i32) -> A<i32> 935 350..351 'A': A<i32>(*mut i32) -> A<i32>
912 350..364 'A(0 as *mut _)': A<i32> 936 350..364 'A(0 as *mut _)': A<i32>
913 350..379 'A(0 as...B(a)))': &i32 937 350..379 'A(0 as...B(a)))': &i32
914 352..353 '0': i32 938 352..353 '0': i32
915 352..363 '0 as *mut _': *mut i32 939 352..363 '0 as *mut _': *mut i32
916 369..378 '&&B(B(a))': &&B<B<A<i32>>> 940 369..378 '&&B(B(a))': &&B<B<A<i32>>>
917 370..378 '&B(B(a))': &B<B<A<i32>>> 941 370..378 '&B(B(a))': &B<B<A<i32>>>
918 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 942 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
919 371..378 'B(B(a))': B<B<A<i32>>> 943 371..378 'B(B(a))': B<B<A<i32>>>
920 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 944 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
921 373..377 'B(a)': B<A<i32>> 945 373..377 'B(a)': B<A<i32>>
922 375..376 'a': A<i32> 946 375..376 'a': A<i32>
923 "### 947 "#]],
924 ); 948 );
925} 949}
926 950
927#[test] 951#[test]
928fn infer_in_elseif() { 952fn infer_in_elseif() {
929 assert_snapshot!( 953 check_infer(
930 infer(r#" 954 r#"
931struct Foo { field: i32 } 955 struct Foo { field: i32 }
932fn main(foo: Foo) { 956 fn main(foo: Foo) {
933 if true { 957 if true {
934 958
935 } else if false { 959 } else if false {
936 foo.field 960 foo.field
937 } 961 }
938} 962 }
939"#), 963 "#,
940 @r###" 964 expect![[r#"
941 34..37 'foo': Foo 965 34..37 'foo': Foo
942 44..108 '{ ... } }': () 966 44..108 '{ ... } }': ()
943 50..106 'if tru... }': () 967 50..106 'if tru... }': ()
944 53..57 'true': bool 968 53..57 'true': bool
945 58..66 '{ }': () 969 58..66 '{ }': ()
946 72..106 'if fal... }': i32 970 72..106 'if fal... }': i32
947 75..80 'false': bool 971 75..80 'false': bool
948 81..106 '{ ... }': i32 972 81..106 '{ ... }': i32
949 91..94 'foo': Foo 973 91..94 'foo': Foo
950 91..100 'foo.field': i32 974 91..100 'foo.field': i32
951 "### 975 "#]],
952 ) 976 )
953} 977}
954 978
955#[test] 979#[test]
956fn infer_if_match_with_return() { 980fn infer_if_match_with_return() {
957 assert_snapshot!( 981 check_infer(
958 infer(r#" 982 r#"
959fn foo() { 983 fn foo() {
960 let _x1 = if true { 984 let _x1 = if true {
961 1 985 1
962 } else { 986 } else {
963 return; 987 return;
964 }; 988 };
965 let _x2 = if true { 989 let _x2 = if true {
966 2 990 2
967 } else { 991 } else {
968 return 992 return
969 }; 993 };
970 let _x3 = match true { 994 let _x3 = match true {
971 true => 3, 995 true => 3,
972 _ => { 996 _ => {
973 return; 997 return;
974 } 998 }
975 }; 999 };
976 let _x4 = match true { 1000 let _x4 = match true {
977 true => 4, 1001 true => 4,
978 _ => return 1002 _ => return
979 }; 1003 };
980}"#), 1004 }"#,
981 @r###" 1005 expect![[r#"
982 9..322 '{ ... }; }': () 1006 9..322 '{ ... }; }': ()
983 19..22 '_x1': i32 1007 19..22 '_x1': i32
984 25..79 'if tru... }': i32 1008 25..79 'if tru... }': i32
985 28..32 'true': bool 1009 28..32 'true': bool
986 33..50 '{ ... }': i32 1010 33..50 '{ ... }': i32
987 43..44 '1': i32 1011 43..44 '1': i32
988 56..79 '{ ... }': i32 1012 56..79 '{ ... }': i32
989 66..72 'return': ! 1013 66..72 'return': !
990 89..92 '_x2': i32 1014 89..92 '_x2': i32
991 95..148 'if tru... }': i32 1015 95..148 'if tru... }': i32
992 98..102 'true': bool 1016 98..102 'true': bool
993 103..120 '{ ... }': i32 1017 103..120 '{ ... }': i32
994 113..114 '2': i32 1018 113..114 '2': i32
995 126..148 '{ ... }': ! 1019 126..148 '{ ... }': !
996 136..142 'return': ! 1020 136..142 'return': !
997 158..161 '_x3': i32 1021 158..161 '_x3': i32
998 164..246 'match ... }': i32 1022 164..246 'match ... }': i32
999 170..174 'true': bool 1023 170..174 'true': bool
1000 185..189 'true': bool 1024 185..189 'true': bool
1001 185..189 'true': bool 1025 185..189 'true': bool
1002 193..194 '3': i32 1026 193..194 '3': i32
1003 204..205 '_': bool 1027 204..205 '_': bool
1004 209..240 '{ ... }': i32 1028 209..240 '{ ... }': i32
1005 223..229 'return': ! 1029 223..229 'return': !
1006 256..259 '_x4': i32 1030 256..259 '_x4': i32
1007 262..319 'match ... }': i32 1031 262..319 'match ... }': i32
1008 268..272 'true': bool 1032 268..272 'true': bool
1009 283..287 'true': bool 1033 283..287 'true': bool
1010 283..287 'true': bool 1034 283..287 'true': bool
1011 291..292 '4': i32 1035 291..292 '4': i32
1012 302..303 '_': bool 1036 302..303 '_': bool
1013 307..313 'return': ! 1037 307..313 'return': !
1014 "### 1038 "#]],
1015 ) 1039 )
1016} 1040}
1017 1041
1018#[test] 1042#[test]
1019fn infer_inherent_method() { 1043fn infer_inherent_method() {
1020 assert_snapshot!( 1044 check_infer(
1021 infer(r#" 1045 r#"
1022struct A; 1046 struct A;
1023 1047
1024impl A { 1048 impl A {
1025 fn foo(self, x: u32) -> i32 {} 1049 fn foo(self, x: u32) -> i32 {}
1026} 1050 }
1027 1051
1028mod b { 1052 mod b {
1029 impl super::A { 1053 impl super::A {
1030 fn bar(&self, x: u64) -> i64 {} 1054 fn bar(&self, x: u64) -> i64 {}
1031 } 1055 }
1032} 1056 }
1033 1057
1034fn test(a: A) { 1058 fn test(a: A) {
1035 a.foo(1); 1059 a.foo(1);
1036 (&a).bar(1); 1060 (&a).bar(1);
1037 a.bar(1); 1061 a.bar(1);
1038} 1062 }
1039"#), 1063 "#,
1040 @r###" 1064 expect![[r#"
1041 31..35 'self': A 1065 31..35 'self': A
1042 37..38 'x': u32 1066 37..38 'x': u32
1043 52..54 '{}': () 1067 52..54 '{}': ()
1044 102..106 'self': &A 1068 102..106 'self': &A
1045 108..109 'x': u64 1069 108..109 'x': u64
1046 123..125 '{}': () 1070 123..125 '{}': ()
1047 143..144 'a': A 1071 143..144 'a': A
1048 149..197 '{ ...(1); }': () 1072 149..197 '{ ...(1); }': ()
1049 155..156 'a': A 1073 155..156 'a': A
1050 155..163 'a.foo(1)': i32 1074 155..163 'a.foo(1)': i32
1051 161..162 '1': u32 1075 161..162 '1': u32
1052 169..180 '(&a).bar(1)': i64 1076 169..180 '(&a).bar(1)': i64
1053 170..172 '&a': &A 1077 170..172 '&a': &A
1054 171..172 'a': A 1078 171..172 'a': A
1055 178..179 '1': u64 1079 178..179 '1': u64
1056 186..187 'a': A 1080 186..187 'a': A
1057 186..194 'a.bar(1)': i64 1081 186..194 'a.bar(1)': i64
1058 192..193 '1': u64 1082 192..193 '1': u64
1059 "### 1083 "#]],
1060 ); 1084 );
1061} 1085}
1062 1086
1063#[test] 1087#[test]
1064fn infer_inherent_method_str() { 1088fn infer_inherent_method_str() {
1065 assert_snapshot!( 1089 check_infer(
1066 infer(r#" 1090 r#"
1067#[lang = "str"] 1091 #[lang = "str"]
1068impl str { 1092 impl str {
1069 fn foo(&self) -> i32 {} 1093 fn foo(&self) -> i32 {}
1070} 1094 }
1071 1095
1072fn test() { 1096 fn test() {
1073 "foo".foo(); 1097 "foo".foo();
1074} 1098 }
1075"#), 1099 "#,
1076 @r###" 1100 expect![[r#"
1077 39..43 'self': &str 1101 39..43 'self': &str
1078 52..54 '{}': () 1102 52..54 '{}': ()
1079 68..88 '{ ...o(); }': () 1103 68..88 '{ ...o(); }': ()
1080 74..79 '"foo"': &str 1104 74..79 '"foo"': &str
1081 74..85 '"foo".foo()': i32 1105 74..85 '"foo".foo()': i32
1082 "### 1106 "#]],
1083 ); 1107 );
1084} 1108}
1085 1109
1086#[test] 1110#[test]
1087fn infer_tuple() { 1111fn infer_tuple() {
1088 assert_snapshot!( 1112 check_infer(
1089 infer(r#" 1113 r#"
1090fn test(x: &str, y: isize) { 1114 fn test(x: &str, y: isize) {
1091 let a: (u32, &str) = (1, "a"); 1115 let a: (u32, &str) = (1, "a");
1092 let b = (a, x); 1116 let b = (a, x);
1093 let c = (y, x); 1117 let c = (y, x);
1094 let d = (c, x); 1118 let d = (c, x);
1095 let e = (1, "e"); 1119 let e = (1, "e");
1096 let f = (e, "d"); 1120 let f = (e, "d");
1097} 1121 }
1098"#), 1122 "#,
1099 @r###" 1123 expect![[r#"
1100 8..9 'x': &str 1124 8..9 'x': &str
1101 17..18 'y': isize 1125 17..18 'y': isize
1102 27..169 '{ ...d"); }': () 1126 27..169 '{ ...d"); }': ()
1103 37..38 'a': (u32, &str) 1127 37..38 'a': (u32, &str)
1104 54..62 '(1, "a")': (u32, &str) 1128 54..62 '(1, "a")': (u32, &str)
1105 55..56 '1': u32 1129 55..56 '1': u32
1106 58..61 '"a"': &str 1130 58..61 '"a"': &str
1107 72..73 'b': ((u32, &str), &str) 1131 72..73 'b': ((u32, &str), &str)
1108 76..82 '(a, x)': ((u32, &str), &str) 1132 76..82 '(a, x)': ((u32, &str), &str)
1109 77..78 'a': (u32, &str) 1133 77..78 'a': (u32, &str)
1110 80..81 'x': &str 1134 80..81 'x': &str
1111 92..93 'c': (isize, &str) 1135 92..93 'c': (isize, &str)
1112 96..102 '(y, x)': (isize, &str) 1136 96..102 '(y, x)': (isize, &str)
1113 97..98 'y': isize 1137 97..98 'y': isize
1114 100..101 'x': &str 1138 100..101 'x': &str
1115 112..113 'd': ((isize, &str), &str) 1139 112..113 'd': ((isize, &str), &str)
1116 116..122 '(c, x)': ((isize, &str), &str) 1140 116..122 '(c, x)': ((isize, &str), &str)
1117 117..118 'c': (isize, &str) 1141 117..118 'c': (isize, &str)
1118 120..121 'x': &str 1142 120..121 'x': &str
1119 132..133 'e': (i32, &str) 1143 132..133 'e': (i32, &str)
1120 136..144 '(1, "e")': (i32, &str) 1144 136..144 '(1, "e")': (i32, &str)
1121 137..138 '1': i32 1145 137..138 '1': i32
1122 140..143 '"e"': &str 1146 140..143 '"e"': &str
1123 154..155 'f': ((i32, &str), &str) 1147 154..155 'f': ((i32, &str), &str)
1124 158..166 '(e, "d")': ((i32, &str), &str) 1148 158..166 '(e, "d")': ((i32, &str), &str)
1125 159..160 'e': (i32, &str) 1149 159..160 'e': (i32, &str)
1126 162..165 '"d"': &str 1150 162..165 '"d"': &str
1127 "### 1151 "#]],
1128 ); 1152 );
1129} 1153}
1130 1154
1131#[test] 1155#[test]
1132fn infer_array() { 1156fn infer_array() {
1133 assert_snapshot!( 1157 check_infer(
1134 infer(r#" 1158 r#"
1135fn test(x: &str, y: isize) { 1159 fn test(x: &str, y: isize) {
1136 let a = [x]; 1160 let a = [x];
1137 let b = [a, a]; 1161 let b = [a, a];
1138 let c = [b, b]; 1162 let c = [b, b];
1139 1163
1140 let d = [y, 1, 2, 3]; 1164 let d = [y, 1, 2, 3];
1141 let d = [1, y, 2, 3]; 1165 let d = [1, y, 2, 3];
1142 let e = [y]; 1166 let e = [y];
1143 let f = [d, d]; 1167 let f = [d, d];
1144 let g = [e, e]; 1168 let g = [e, e];
1145 1169
1146 let h = [1, 2]; 1170 let h = [1, 2];
1147 let i = ["a", "b"]; 1171 let i = ["a", "b"];
1148 1172
1149 let b = [a, ["b"]]; 1173 let b = [a, ["b"]];
1150 let x: [u8; 0] = []; 1174 let x: [u8; 0] = [];
1151} 1175 }
1152"#), 1176 "#,
1153 @r###" 1177 expect![[r#"
1154 8..9 'x': &str 1178 8..9 'x': &str
1155 17..18 'y': isize 1179 17..18 'y': isize
1156 27..292 '{ ... []; }': () 1180 27..292 '{ ... []; }': ()
1157 37..38 'a': [&str; _] 1181 37..38 'a': [&str; _]
1158 41..44 '[x]': [&str; _] 1182 41..44 '[x]': [&str; _]
1159 42..43 'x': &str 1183 42..43 'x': &str
1160 54..55 'b': [[&str; _]; _] 1184 54..55 'b': [[&str; _]; _]
1161 58..64 '[a, a]': [[&str; _]; _] 1185 58..64 '[a, a]': [[&str; _]; _]
1162 59..60 'a': [&str; _] 1186 59..60 'a': [&str; _]
1163 62..63 'a': [&str; _] 1187 62..63 'a': [&str; _]
1164 74..75 'c': [[[&str; _]; _]; _] 1188 74..75 'c': [[[&str; _]; _]; _]
1165 78..84 '[b, b]': [[[&str; _]; _]; _] 1189 78..84 '[b, b]': [[[&str; _]; _]; _]
1166 79..80 'b': [[&str; _]; _] 1190 79..80 'b': [[&str; _]; _]
1167 82..83 'b': [[&str; _]; _] 1191 82..83 'b': [[&str; _]; _]
1168 95..96 'd': [isize; _] 1192 95..96 'd': [isize; _]
1169 99..111 '[y, 1, 2, 3]': [isize; _] 1193 99..111 '[y, 1, 2, 3]': [isize; _]
1170 100..101 'y': isize 1194 100..101 'y': isize
1171 103..104 '1': isize 1195 103..104 '1': isize
1172 106..107 '2': isize 1196 106..107 '2': isize
1173 109..110 '3': isize 1197 109..110 '3': isize
1174 121..122 'd': [isize; _] 1198 121..122 'd': [isize; _]
1175 125..137 '[1, y, 2, 3]': [isize; _] 1199 125..137 '[1, y, 2, 3]': [isize; _]
1176 126..127 '1': isize 1200 126..127 '1': isize
1177 129..130 'y': isize 1201 129..130 'y': isize
1178 132..133 '2': isize 1202 132..133 '2': isize
1179 135..136 '3': isize 1203 135..136 '3': isize
1180 147..148 'e': [isize; _] 1204 147..148 'e': [isize; _]
1181 151..154 '[y]': [isize; _] 1205 151..154 '[y]': [isize; _]
1182 152..153 'y': isize 1206 152..153 'y': isize
1183 164..165 'f': [[isize; _]; _] 1207 164..165 'f': [[isize; _]; _]
1184 168..174 '[d, d]': [[isize; _]; _] 1208 168..174 '[d, d]': [[isize; _]; _]
1185 169..170 'd': [isize; _] 1209 169..170 'd': [isize; _]
1186 172..173 'd': [isize; _] 1210 172..173 'd': [isize; _]
1187 184..185 'g': [[isize; _]; _] 1211 184..185 'g': [[isize; _]; _]
1188 188..194 '[e, e]': [[isize; _]; _] 1212 188..194 '[e, e]': [[isize; _]; _]
1189 189..190 'e': [isize; _] 1213 189..190 'e': [isize; _]
1190 192..193 'e': [isize; _] 1214 192..193 'e': [isize; _]
1191 205..206 'h': [i32; _] 1215 205..206 'h': [i32; _]
1192 209..215 '[1, 2]': [i32; _] 1216 209..215 '[1, 2]': [i32; _]
1193 210..211 '1': i32 1217 210..211 '1': i32
1194 213..214 '2': i32 1218 213..214 '2': i32
1195 225..226 'i': [&str; _] 1219 225..226 'i': [&str; _]
1196 229..239 '["a", "b"]': [&str; _] 1220 229..239 '["a", "b"]': [&str; _]
1197 230..233 '"a"': &str 1221 230..233 '"a"': &str
1198 235..238 '"b"': &str 1222 235..238 '"b"': &str
1199 250..251 'b': [[&str; _]; _] 1223 250..251 'b': [[&str; _]; _]
1200 254..264 '[a, ["b"]]': [[&str; _]; _] 1224 254..264 '[a, ["b"]]': [[&str; _]; _]
1201 255..256 'a': [&str; _] 1225 255..256 'a': [&str; _]
1202 258..263 '["b"]': [&str; _] 1226 258..263 '["b"]': [&str; _]
1203 259..262 '"b"': &str 1227 259..262 '"b"': &str
1204 274..275 'x': [u8; _] 1228 274..275 'x': [u8; _]
1205 287..289 '[]': [u8; _] 1229 287..289 '[]': [u8; _]
1206 "### 1230 "#]],
1207 ); 1231 );
1208} 1232}
1209 1233
1210#[test] 1234#[test]
1211fn infer_struct_generics() { 1235fn infer_struct_generics() {
1212 assert_snapshot!( 1236 check_infer(
1213 infer(r#" 1237 r#"
1214struct A<T> { 1238 struct A<T> {
1215 x: T, 1239 x: T,
1216} 1240 }
1217 1241
1218fn test(a1: A<u32>, i: i32) { 1242 fn test(a1: A<u32>, i: i32) {
1219 a1.x; 1243 a1.x;
1220 let a2 = A { x: i }; 1244 let a2 = A { x: i };
1221 a2.x; 1245 a2.x;
1222 let a3 = A::<i128> { x: 1 }; 1246 let a3 = A::<i128> { x: 1 };
1223 a3.x; 1247 a3.x;
1224} 1248 }
1225"#), 1249 "#,
1226 @r###" 1250 expect![[r#"
1227 35..37 'a1': A<u32> 1251 35..37 'a1': A<u32>
1228 47..48 'i': i32 1252 47..48 'i': i32
1229 55..146 '{ ...3.x; }': () 1253 55..146 '{ ...3.x; }': ()
1230 61..63 'a1': A<u32> 1254 61..63 'a1': A<u32>
1231 61..65 'a1.x': u32 1255 61..65 'a1.x': u32
1232 75..77 'a2': A<i32> 1256 75..77 'a2': A<i32>
1233 80..90 'A { x: i }': A<i32> 1257 80..90 'A { x: i }': A<i32>
1234 87..88 'i': i32 1258 87..88 'i': i32
1235 96..98 'a2': A<i32> 1259 96..98 'a2': A<i32>
1236 96..100 'a2.x': i32 1260 96..100 'a2.x': i32
1237 110..112 'a3': A<i128> 1261 110..112 'a3': A<i128>
1238 115..133 'A::<i1...x: 1 }': A<i128> 1262 115..133 'A::<i1...x: 1 }': A<i128>
1239 130..131 '1': i128 1263 130..131 '1': i128
1240 139..141 'a3': A<i128> 1264 139..141 'a3': A<i128>
1241 139..143 'a3.x': i128 1265 139..143 'a3.x': i128
1242 "### 1266 "#]],
1243 ); 1267 );
1244} 1268}
1245 1269
1246#[test] 1270#[test]
1247fn infer_tuple_struct_generics() { 1271fn infer_tuple_struct_generics() {
1248 assert_snapshot!( 1272 check_infer(
1249 infer(r#" 1273 r#"
1250struct A<T>(T); 1274 struct A<T>(T);
1251enum Option<T> { Some(T), None } 1275 enum Option<T> { Some(T), None }
1252use Option::*; 1276 use Option::*;
1253 1277
1254fn test() { 1278 fn test() {
1255 A(42); 1279 A(42);
1256 A(42u128); 1280 A(42u128);
1257 Some("x"); 1281 Some("x");
1258 Option::Some("x"); 1282 Option::Some("x");
1259 None; 1283 None;
1260 let x: Option<i64> = None; 1284 let x: Option<i64> = None;
1261} 1285 }
1262"#), 1286 "#,
1263 @r###" 1287 expect![[r#"
1264 75..183 '{ ...one; }': () 1288 75..183 '{ ...one; }': ()
1265 81..82 'A': A<i32>(i32) -> A<i32> 1289 81..82 'A': A<i32>(i32) -> A<i32>
1266 81..86 'A(42)': A<i32> 1290 81..86 'A(42)': A<i32>
1267 83..85 '42': i32 1291 83..85 '42': i32
1268 92..93 'A': A<u128>(u128) -> A<u128> 1292 92..93 'A': A<u128>(u128) -> A<u128>
1269 92..101 'A(42u128)': A<u128> 1293 92..101 'A(42u128)': A<u128>
1270 94..100 '42u128': u128 1294 94..100 '42u128': u128
1271 107..111 'Some': Some<&str>(&str) -> Option<&str> 1295 107..111 'Some': Some<&str>(&str) -> Option<&str>
1272 107..116 'Some("x")': Option<&str> 1296 107..116 'Some("x")': Option<&str>
1273 112..115 '"x"': &str 1297 112..115 '"x"': &str
1274 122..134 'Option::Some': Some<&str>(&str) -> Option<&str> 1298 122..134 'Option::Some': Some<&str>(&str) -> Option<&str>
1275 122..139 'Option...e("x")': Option<&str> 1299 122..139 'Option...e("x")': Option<&str>
1276 135..138 '"x"': &str 1300 135..138 '"x"': &str
1277 145..149 'None': Option<{unknown}> 1301 145..149 'None': Option<{unknown}>
1278 159..160 'x': Option<i64> 1302 159..160 'x': Option<i64>
1279 176..180 'None': Option<i64> 1303 176..180 'None': Option<i64>
1280 "### 1304 "#]],
1281 ); 1305 );
1282} 1306}
1283 1307
1284#[test] 1308#[test]
1285fn infer_function_generics() { 1309fn infer_function_generics() {
1286 assert_snapshot!( 1310 check_infer(
1287 infer(r#" 1311 r#"
1288fn id<T>(t: T) -> T { t } 1312 fn id<T>(t: T) -> T { t }
1289 1313
1290fn test() { 1314 fn test() {
1291 id(1u32); 1315 id(1u32);
1292 id::<i128>(1); 1316 id::<i128>(1);
1293 let x: u64 = id(1); 1317 let x: u64 = id(1);
1294} 1318 }
1295"#), 1319 "#,
1296 @r###" 1320 expect![[r#"
1297 9..10 't': T 1321 9..10 't': T
1298 20..25 '{ t }': T 1322 20..25 '{ t }': T
1299 22..23 't': T 1323 22..23 't': T
1300 37..97 '{ ...(1); }': () 1324 37..97 '{ ...(1); }': ()
1301 43..45 'id': fn id<u32>(u32) -> u32 1325 43..45 'id': fn id<u32>(u32) -> u32
1302 43..51 'id(1u32)': u32 1326 43..51 'id(1u32)': u32
1303 46..50 '1u32': u32 1327 46..50 '1u32': u32
1304 57..67 'id::<i128>': fn id<i128>(i128) -> i128 1328 57..67 'id::<i128>': fn id<i128>(i128) -> i128
1305 57..70 'id::<i128>(1)': i128 1329 57..70 'id::<i128>(1)': i128
1306 68..69 '1': i128 1330 68..69 '1': i128
1307 80..81 'x': u64 1331 80..81 'x': u64
1308 89..91 'id': fn id<u64>(u64) -> u64 1332 89..91 'id': fn id<u64>(u64) -> u64
1309 89..94 'id(1)': u64 1333 89..94 'id(1)': u64
1310 92..93 '1': u64 1334 92..93 '1': u64
1311 "### 1335 "#]],
1312 ); 1336 );
1313} 1337}
1314 1338
1315#[test] 1339#[test]
1316fn infer_impl_generics_basic() { 1340fn infer_impl_generics_basic() {
1317 assert_snapshot!( 1341 check_infer(
1318 infer(r#" 1342 r#"
1319struct A<T1, T2> { 1343 struct A<T1, T2> {
1320 x: T1, 1344 x: T1,
1321 y: T2, 1345 y: T2,
1322} 1346 }
1323impl<Y, X> A<X, Y> { 1347 impl<Y, X> A<X, Y> {
1324 fn x(self) -> X { 1348 fn x(self) -> X {
1325 self.x 1349 self.x
1326 } 1350 }
1327 fn y(self) -> Y { 1351 fn y(self) -> Y {
1328 self.y 1352 self.y
1329 } 1353 }
1330 fn z<T>(self, t: T) -> (X, Y, T) { 1354 fn z<T>(self, t: T) -> (X, Y, T) {
1331 (self.x, self.y, t) 1355 (self.x, self.y, t)
1332 } 1356 }
1333} 1357 }
1334 1358
1335fn test() -> i128 { 1359 fn test() -> i128 {
1336 let a = A { x: 1u64, y: 1i64 }; 1360 let a = A { x: 1u64, y: 1i64 };
1337 a.x(); 1361 a.x();
1338 a.y(); 1362 a.y();
1339 a.z(1i128); 1363 a.z(1i128);
1340 a.z::<u128>(1); 1364 a.z::<u128>(1);
1341} 1365 }
1342"#), 1366 "#,
1343 @r###" 1367 expect![[r#"
1344 73..77 'self': A<X, Y> 1368 73..77 'self': A<X, Y>
1345 84..106 '{ ... }': X 1369 84..106 '{ ... }': X
1346 94..98 'self': A<X, Y> 1370 94..98 'self': A<X, Y>
1347 94..100 'self.x': X 1371 94..100 'self.x': X
1348 116..120 'self': A<X, Y> 1372 116..120 'self': A<X, Y>
1349 127..149 '{ ... }': Y 1373 127..149 '{ ... }': Y
1350 137..141 'self': A<X, Y> 1374 137..141 'self': A<X, Y>
1351 137..143 'self.y': Y 1375 137..143 'self.y': Y
1352 162..166 'self': A<X, Y> 1376 162..166 'self': A<X, Y>
1353 168..169 't': T 1377 168..169 't': T
1354 187..222 '{ ... }': (X, Y, T) 1378 187..222 '{ ... }': (X, Y, T)
1355 197..216 '(self.....y, t)': (X, Y, T) 1379 197..216 '(self.....y, t)': (X, Y, T)
1356 198..202 'self': A<X, Y> 1380 198..202 'self': A<X, Y>
1357 198..204 'self.x': X 1381 198..204 'self.x': X
1358 206..210 'self': A<X, Y> 1382 206..210 'self': A<X, Y>
1359 206..212 'self.y': Y 1383 206..212 'self.y': Y
1360 214..215 't': T 1384 214..215 't': T
1361 244..341 '{ ...(1); }': () 1385 244..341 '{ ...(1); }': ()
1362 254..255 'a': A<u64, i64> 1386 254..255 'a': A<u64, i64>
1363 258..280 'A { x:...1i64 }': A<u64, i64> 1387 258..280 'A { x:...1i64 }': A<u64, i64>
1364 265..269 '1u64': u64 1388 265..269 '1u64': u64
1365 274..278 '1i64': i64 1389 274..278 '1i64': i64
1366 286..287 'a': A<u64, i64> 1390 286..287 'a': A<u64, i64>
1367 286..291 'a.x()': u64 1391 286..291 'a.x()': u64
1368 297..298 'a': A<u64, i64> 1392 297..298 'a': A<u64, i64>
1369 297..302 'a.y()': i64 1393 297..302 'a.y()': i64
1370 308..309 'a': A<u64, i64> 1394 308..309 'a': A<u64, i64>
1371 308..318 'a.z(1i128)': (u64, i64, i128) 1395 308..318 'a.z(1i128)': (u64, i64, i128)
1372 312..317 '1i128': i128 1396 312..317 '1i128': i128
1373 324..325 'a': A<u64, i64> 1397 324..325 'a': A<u64, i64>
1374 324..338 'a.z::<u128>(1)': (u64, i64, u128) 1398 324..338 'a.z::<u128>(1)': (u64, i64, u128)
1375 336..337 '1': u128 1399 336..337 '1': u128
1376 "### 1400 "#]],
1377 ); 1401 );
1378} 1402}
1379 1403
1380#[test] 1404#[test]
1381fn infer_impl_generics_with_autoderef() { 1405fn infer_impl_generics_with_autoderef() {
1382 assert_snapshot!( 1406 check_infer(
1383 infer(r#" 1407 r#"
1384enum Option<T> { 1408 enum Option<T> {
1385 Some(T), 1409 Some(T),
1386 None, 1410 None,
1387} 1411 }
1388impl<T> Option<T> { 1412 impl<T> Option<T> {
1389 fn as_ref(&self) -> Option<&T> {} 1413 fn as_ref(&self) -> Option<&T> {}
1390} 1414 }
1391fn test(o: Option<u32>) { 1415 fn test(o: Option<u32>) {
1392 (&o).as_ref(); 1416 (&o).as_ref();
1393 o.as_ref(); 1417 o.as_ref();
1394} 1418 }
1395"#), 1419 "#,
1396 @r###" 1420 expect![[r#"
1397 77..81 'self': &Option<T> 1421 77..81 'self': &Option<T>
1398 97..99 '{}': () 1422 97..99 '{}': ()
1399 110..111 'o': Option<u32> 1423 110..111 'o': Option<u32>
1400 126..164 '{ ...f(); }': () 1424 126..164 '{ ...f(); }': ()
1401 132..145 '(&o).as_ref()': Option<&u32> 1425 132..145 '(&o).as_ref()': Option<&u32>
1402 133..135 '&o': &Option<u32> 1426 133..135 '&o': &Option<u32>
1403 134..135 'o': Option<u32> 1427 134..135 'o': Option<u32>
1404 151..152 'o': Option<u32> 1428 151..152 'o': Option<u32>
1405 151..161 'o.as_ref()': Option<&u32> 1429 151..161 'o.as_ref()': Option<&u32>
1406 "### 1430 "#]],
1407 ); 1431 );
1408} 1432}
1409 1433
1410#[test] 1434#[test]
1411fn infer_generic_chain() { 1435fn infer_generic_chain() {
1412 assert_snapshot!( 1436 check_infer(
1413 infer(r#" 1437 r#"
1414struct A<T> { 1438 struct A<T> {
1415 x: T, 1439 x: T,
1416} 1440 }
1417impl<T2> A<T2> { 1441 impl<T2> A<T2> {
1418 fn x(self) -> T2 { 1442 fn x(self) -> T2 {
1419 self.x 1443 self.x
1420 } 1444 }
1421} 1445 }
1422fn id<T>(t: T) -> T { t } 1446 fn id<T>(t: T) -> T { t }
1423 1447
1424fn test() -> i128 { 1448 fn test() -> i128 {
1425 let x = 1; 1449 let x = 1;
1426 let y = id(x); 1450 let y = id(x);
1427 let a = A { x: id(y) }; 1451 let a = A { x: id(y) };
1428 let z = id(a.x); 1452 let z = id(a.x);
1429 let b = A { x: z }; 1453 let b = A { x: z };
1430 b.x() 1454 b.x()
1431} 1455 }
1432"#), 1456 "#,
1433 @r###" 1457 expect![[r#"
1434 52..56 'self': A<T2> 1458 52..56 'self': A<T2>
1435 64..86 '{ ... }': T2 1459 64..86 '{ ... }': T2
1436 74..78 'self': A<T2> 1460 74..78 'self': A<T2>
1437 74..80 'self.x': T2 1461 74..80 'self.x': T2
1438 98..99 't': T 1462 98..99 't': T
1439 109..114 '{ t }': T 1463 109..114 '{ t }': T
1440 111..112 't': T 1464 111..112 't': T
1441 134..260 '{ ....x() }': i128 1465 134..254 '{ ....x() }': i128
1442 145..146 'x': i128 1466 144..145 'x': i128
1443 149..150 '1': i128 1467 148..149 '1': i128
1444 161..162 'y': i128 1468 159..160 'y': i128
1445 165..167 'id': fn id<i128>(i128) -> i128 1469 163..165 'id': fn id<i128>(i128) -> i128
1446 165..170 'id(x)': i128 1470 163..168 'id(x)': i128
1447 168..169 'x': i128 1471 166..167 'x': i128
1448 181..182 'a': A<i128> 1472 178..179 'a': A<i128>
1449 185..199 'A { x: id(y) }': A<i128> 1473 182..196 'A { x: id(y) }': A<i128>
1450 192..194 'id': fn id<i128>(i128) -> i128 1474 189..191 'id': fn id<i128>(i128) -> i128
1451 192..197 'id(y)': i128 1475 189..194 'id(y)': i128
1452 195..196 'y': i128 1476 192..193 'y': i128
1453 210..211 'z': i128 1477 206..207 'z': i128
1454 214..216 'id': fn id<i128>(i128) -> i128 1478 210..212 'id': fn id<i128>(i128) -> i128
1455 214..221 'id(a.x)': i128 1479 210..217 'id(a.x)': i128
1456 217..218 'a': A<i128> 1480 213..214 'a': A<i128>
1457 217..220 'a.x': i128 1481 213..216 'a.x': i128
1458 232..233 'b': A<i128> 1482 227..228 'b': A<i128>
1459 236..246 'A { x: z }': A<i128> 1483 231..241 'A { x: z }': A<i128>
1460 243..244 'z': i128 1484 238..239 'z': i128
1461 253..254 'b': A<i128> 1485 247..248 'b': A<i128>
1462 253..258 'b.x()': i128 1486 247..252 'b.x()': i128
1463 "### 1487 "#]],
1464 ); 1488 );
1465} 1489}
1466 1490
1467#[test] 1491#[test]
1468fn infer_associated_const() { 1492fn infer_associated_const() {
1469 assert_snapshot!( 1493 check_infer(
1470 infer(r#" 1494 r#"
1471struct Struct; 1495 struct Struct;
1472 1496
1473impl Struct { 1497 impl Struct {
1474 const FOO: u32 = 1; 1498 const FOO: u32 = 1;
1475} 1499 }
1476 1500
1477enum Enum {} 1501 enum Enum {}
1478 1502
1479impl Enum { 1503 impl Enum {
1480 const BAR: u32 = 2; 1504 const BAR: u32 = 2;
1481} 1505 }
1482 1506
1483trait Trait { 1507 trait Trait {
1484 const ID: u32; 1508 const ID: u32;
1485} 1509 }
1486 1510
1487struct TraitTest; 1511 struct TraitTest;
1488 1512
1489impl Trait for TraitTest { 1513 impl Trait for TraitTest {
1490 const ID: u32 = 5; 1514 const ID: u32 = 5;
1491} 1515 }
1492 1516
1493fn test() { 1517 fn test() {
1494 let x = Struct::FOO; 1518 let x = Struct::FOO;
1495 let y = Enum::BAR; 1519 let y = Enum::BAR;
1496 let z = TraitTest::ID; 1520 let z = TraitTest::ID;
1497} 1521 }
1498"#), 1522 "#,
1499 @r###" 1523 expect![[r#"
1500 51..52 '1': u32 1524 51..52 '1': u32
1501 104..105 '2': u32 1525 104..105 '2': u32
1502 212..213 '5': u32 1526 212..213 '5': u32
1503 228..306 '{ ...:ID; }': () 1527 228..306 '{ ...:ID; }': ()
1504 238..239 'x': u32 1528 238..239 'x': u32
1505 242..253 'Struct::FOO': u32 1529 242..253 'Struct::FOO': u32
1506 263..264 'y': u32 1530 263..264 'y': u32
1507 267..276 'Enum::BAR': u32 1531 267..276 'Enum::BAR': u32
1508 286..287 'z': u32 1532 286..287 'z': u32
1509 290..303 'TraitTest::ID': u32 1533 290..303 'TraitTest::ID': u32
1510 "### 1534 "#]],
1511 ); 1535 );
1512} 1536}
1513 1537
1514#[test] 1538#[test]
1515fn infer_type_alias() { 1539fn infer_type_alias() {
1516 assert_snapshot!( 1540 check_infer(
1517 infer(r#" 1541 r#"
1518struct A<X, Y> { x: X, y: Y } 1542 struct A<X, Y> { x: X, y: Y }
1519type Foo = A<u32, i128>; 1543 type Foo = A<u32, i128>;
1520type Bar<T> = A<T, u128>; 1544 type Bar<T> = A<T, u128>;
1521type Baz<U, V> = A<V, U>; 1545 type Baz<U, V> = A<V, U>;
1522fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) { 1546 fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
1523 x.x; 1547 x.x;
1524 x.y; 1548 x.y;
1525 y.x; 1549 y.x;
1526 y.y; 1550 y.y;
1527 z.x; 1551 z.x;
1528 z.y; 1552 z.y;
1529} 1553 }
1530"#), 1554 "#,
1531 @r###" 1555 expect![[r#"
1532 115..116 'x': A<u32, i128> 1556 115..116 'x': A<u32, i128>
1533 123..124 'y': A<&str, u128> 1557 123..124 'y': A<&str, u128>
1534 137..138 'z': A<u8, i8> 1558 137..138 'z': A<u8, i8>
1535 153..210 '{ ...z.y; }': () 1559 153..210 '{ ...z.y; }': ()
1536 159..160 'x': A<u32, i128> 1560 159..160 'x': A<u32, i128>
1537 159..162 'x.x': u32 1561 159..162 'x.x': u32
1538 168..169 'x': A<u32, i128> 1562 168..169 'x': A<u32, i128>
1539 168..171 'x.y': i128 1563 168..171 'x.y': i128
1540 177..178 'y': A<&str, u128> 1564 177..178 'y': A<&str, u128>
1541 177..180 'y.x': &str 1565 177..180 'y.x': &str
1542 186..187 'y': A<&str, u128> 1566 186..187 'y': A<&str, u128>
1543 186..189 'y.y': u128 1567 186..189 'y.y': u128
1544 195..196 'z': A<u8, i8> 1568 195..196 'z': A<u8, i8>
1545 195..198 'z.x': u8 1569 195..198 'z.x': u8
1546 204..205 'z': A<u8, i8> 1570 204..205 'z': A<u8, i8>
1547 204..207 'z.y': i8 1571 204..207 'z.y': i8
1548 "### 1572 "#]],
1549 ) 1573 )
1550} 1574}
1551 1575
1552#[test] 1576#[test]
1553fn recursive_type_alias() { 1577fn recursive_type_alias() {
1554 assert_snapshot!( 1578 check_infer(
1555 infer(r#" 1579 r#"
1556struct A<X> {} 1580 struct A<X> {}
1557type Foo = Foo; 1581 type Foo = Foo;
1558type Bar = A<Bar>; 1582 type Bar = A<Bar>;
1559fn test(x: Foo) {} 1583 fn test(x: Foo) {}
1560"#), 1584 "#,
1561 @r###" 1585 expect![[r#"
1562 58..59 'x': {unknown} 1586 58..59 'x': {unknown}
1563 66..68 '{}': () 1587 66..68 '{}': ()
1564 "### 1588 "#]],
1565 ) 1589 )
1566} 1590}
1567 1591
1568#[test] 1592#[test]
1569fn infer_type_param() { 1593fn infer_type_param() {
1570 assert_snapshot!( 1594 check_infer(
1571 infer(r#" 1595 r#"
1572fn id<T>(x: T) -> T { 1596 fn id<T>(x: T) -> T {
1573 x 1597 x
1574} 1598 }
1575 1599
1576fn clone<T>(x: &T) -> T { 1600 fn clone<T>(x: &T) -> T {
1577 *x 1601 *x
1578} 1602 }
1579 1603
1580fn test() { 1604 fn test() {
1581 let y = 10u32; 1605 let y = 10u32;
1582 id(y); 1606 id(y);
1583 let x: bool = clone(z); 1607 let x: bool = clone(z);
1584 id::<i128>(1); 1608 id::<i128>(1);
1585} 1609 }
1586"#), 1610 "#,
1587 @r###" 1611 expect![[r#"
1588 9..10 'x': T 1612 9..10 'x': T
1589 20..29 '{ x }': T 1613 20..29 '{ x }': T
1590 26..27 'x': T 1614 26..27 'x': T
1591 43..44 'x': &T 1615 43..44 'x': &T
1592 55..65 '{ *x }': T 1616 55..65 '{ *x }': T
1593 61..63 '*x': T 1617 61..63 '*x': T
1594 62..63 'x': &T 1618 62..63 'x': &T
1595 77..157 '{ ...(1); }': () 1619 77..157 '{ ...(1); }': ()
1596 87..88 'y': u32 1620 87..88 'y': u32
1597 91..96 '10u32': u32 1621 91..96 '10u32': u32
1598 102..104 'id': fn id<u32>(u32) -> u32 1622 102..104 'id': fn id<u32>(u32) -> u32
1599 102..107 'id(y)': u32 1623 102..107 'id(y)': u32
1600 105..106 'y': u32 1624 105..106 'y': u32
1601 117..118 'x': bool 1625 117..118 'x': bool
1602 127..132 'clone': fn clone<bool>(&bool) -> bool 1626 127..132 'clone': fn clone<bool>(&bool) -> bool
1603 127..135 'clone(z)': bool 1627 127..135 'clone(z)': bool
1604 133..134 'z': &bool 1628 133..134 'z': &bool
1605 141..151 'id::<i128>': fn id<i128>(i128) -> i128 1629 141..151 'id::<i128>': fn id<i128>(i128) -> i128
1606 141..154 'id::<i128>(1)': i128 1630 141..154 'id::<i128>(1)': i128
1607 152..153 '1': i128 1631 152..153 '1': i128
1608 "### 1632 "#]],
1609 ); 1633 );
1610} 1634}
1611 1635
1612#[test] 1636#[test]
1613fn infer_const() { 1637fn infer_const() {
1614 assert_snapshot!( 1638 check_infer(
1615 infer(r#" 1639 r#"
1616struct Foo; 1640 struct Foo;
1617impl Foo { const ASSOC_CONST: u32 = 0; } 1641 impl Foo { const ASSOC_CONST: u32 = 0; }
1618const GLOBAL_CONST: u32 = 101; 1642 const GLOBAL_CONST: u32 = 101;
1619fn test() { 1643 fn test() {
1620 const LOCAL_CONST: u32 = 99; 1644 const LOCAL_CONST: u32 = 99;
1621 let x = LOCAL_CONST; 1645 let x = LOCAL_CONST;
1622 let z = GLOBAL_CONST; 1646 let z = GLOBAL_CONST;
1623 let id = Foo::ASSOC_CONST; 1647 let id = Foo::ASSOC_CONST;
1624} 1648 }
1625"#), 1649 "#,
1626 @r###" 1650 expect![[r#"
1627 48..49 '0': u32 1651 48..49 '0': u32
1628 79..82 '101': u32 1652 79..82 '101': u32
1629 94..212 '{ ...NST; }': () 1653 94..212 '{ ...NST; }': ()
1630 137..138 'x': u32 1654 137..138 'x': u32
1631 141..152 'LOCAL_CONST': u32 1655 141..152 'LOCAL_CONST': u32
1632 162..163 'z': u32 1656 162..163 'z': u32
1633 166..178 'GLOBAL_CONST': u32 1657 166..178 'GLOBAL_CONST': u32
1634 188..190 'id': u32 1658 188..190 'id': u32
1635 193..209 'Foo::A..._CONST': u32 1659 193..209 'Foo::A..._CONST': u32
1636 125..127 '99': u32 1660 125..127 '99': u32
1637 "### 1661 "#]],
1638 ); 1662 );
1639} 1663}
1640 1664
1641#[test] 1665#[test]
1642fn infer_static() { 1666fn infer_static() {
1643 assert_snapshot!( 1667 check_infer(
1644 infer(r#" 1668 r#"
1645static GLOBAL_STATIC: u32 = 101; 1669 static GLOBAL_STATIC: u32 = 101;
1646static mut GLOBAL_STATIC_MUT: u32 = 101; 1670 static mut GLOBAL_STATIC_MUT: u32 = 101;
1647fn test() { 1671 fn test() {
1648 static LOCAL_STATIC: u32 = 99; 1672 static LOCAL_STATIC: u32 = 99;
1649 static mut LOCAL_STATIC_MUT: u32 = 99; 1673 static mut LOCAL_STATIC_MUT: u32 = 99;
1650 let x = LOCAL_STATIC; 1674 let x = LOCAL_STATIC;
1651 let y = LOCAL_STATIC_MUT; 1675 let y = LOCAL_STATIC_MUT;
1652 let z = GLOBAL_STATIC; 1676 let z = GLOBAL_STATIC;
1653 let w = GLOBAL_STATIC_MUT; 1677 let w = GLOBAL_STATIC_MUT;
1654} 1678 }
1655"#), 1679 "#,
1656 @r###" 1680 expect![[r#"
1657 28..31 '101': u32 1681 28..31 '101': u32
1658 69..72 '101': u32 1682 69..72 '101': u32
1659 84..279 '{ ...MUT; }': () 1683 84..279 '{ ...MUT; }': ()
1660 172..173 'x': u32 1684 172..173 'x': u32
1661 176..188 'LOCAL_STATIC': u32 1685 176..188 'LOCAL_STATIC': u32
1662 198..199 'y': u32 1686 198..199 'y': u32
1663 202..218 'LOCAL_...IC_MUT': u32 1687 202..218 'LOCAL_...IC_MUT': u32
1664 228..229 'z': u32 1688 228..229 'z': u32
1665 232..245 'GLOBAL_STATIC': u32 1689 232..245 'GLOBAL_STATIC': u32
1666 255..256 'w': u32 1690 255..256 'w': u32
1667 259..276 'GLOBAL...IC_MUT': u32 1691 259..276 'GLOBAL...IC_MUT': u32
1668 117..119 '99': u32 1692 117..119 '99': u32
1669 160..162 '99': u32 1693 160..162 '99': u32
1670 "### 1694 "#]],
1671 ); 1695 );
1672} 1696}
1673 1697
@@ -1754,413 +1778,413 @@ fn main() {
1754 1778
1755#[test] 1779#[test]
1756fn closure_return() { 1780fn closure_return() {
1757 assert_snapshot!( 1781 check_infer(
1758 infer(r#" 1782 r#"
1759fn foo() -> u32 { 1783 fn foo() -> u32 {
1760 let x = || -> usize { return 1; }; 1784 let x = || -> usize { return 1; };
1761} 1785 }
1762"#), 1786 "#,
1763 @r###" 1787 expect![[r#"
1764 16..58 '{ ...; }; }': () 1788 16..58 '{ ...; }; }': ()
1765 26..27 'x': || -> usize 1789 26..27 'x': || -> usize
1766 30..55 '|| -> ...n 1; }': || -> usize 1790 30..55 '|| -> ...n 1; }': || -> usize
1767 42..55 '{ return 1; }': usize 1791 42..55 '{ return 1; }': usize
1768 44..52 'return 1': ! 1792 44..52 'return 1': !
1769 51..52 '1': usize 1793 51..52 '1': usize
1770 "### 1794 "#]],
1771 ); 1795 );
1772} 1796}
1773 1797
1774#[test] 1798#[test]
1775fn closure_return_unit() { 1799fn closure_return_unit() {
1776 assert_snapshot!( 1800 check_infer(
1777 infer(r#" 1801 r#"
1778fn foo() -> u32 { 1802 fn foo() -> u32 {
1779 let x = || { return; }; 1803 let x = || { return; };
1780} 1804 }
1781"#), 1805 "#,
1782 @r###" 1806 expect![[r#"
1783 16..47 '{ ...; }; }': () 1807 16..47 '{ ...; }; }': ()
1784 26..27 'x': || -> () 1808 26..27 'x': || -> ()
1785 30..44 '|| { return; }': || -> () 1809 30..44 '|| { return; }': || -> ()
1786 33..44 '{ return; }': () 1810 33..44 '{ return; }': ()
1787 35..41 'return': ! 1811 35..41 'return': !
1788 "### 1812 "#]],
1789 ); 1813 );
1790} 1814}
1791 1815
1792#[test] 1816#[test]
1793fn closure_return_inferred() { 1817fn closure_return_inferred() {
1794 assert_snapshot!( 1818 check_infer(
1795 infer(r#" 1819 r#"
1796fn foo() -> u32 { 1820 fn foo() -> u32 {
1797 let x = || { "test" }; 1821 let x = || { "test" };
1798} 1822 }
1799"#), 1823 "#,
1800 @r###" 1824 expect![[r#"
1801 16..46 '{ ..." }; }': () 1825 16..46 '{ ..." }; }': ()
1802 26..27 'x': || -> &str 1826 26..27 'x': || -> &str
1803 30..43 '|| { "test" }': || -> &str 1827 30..43 '|| { "test" }': || -> &str
1804 33..43 '{ "test" }': &str 1828 33..43 '{ "test" }': &str
1805 35..41 '"test"': &str 1829 35..41 '"test"': &str
1806 "### 1830 "#]],
1807 ); 1831 );
1808} 1832}
1809 1833
1810#[test] 1834#[test]
1811fn fn_pointer_return() { 1835fn fn_pointer_return() {
1812 assert_snapshot!( 1836 check_infer(
1813 infer(r#" 1837 r#"
1814struct Vtable { 1838 struct Vtable {
1815 method: fn(), 1839 method: fn(),
1816} 1840 }
1817 1841
1818fn main() { 1842 fn main() {
1819 let vtable = Vtable { method: || {} }; 1843 let vtable = Vtable { method: || {} };
1820 let m = vtable.method; 1844 let m = vtable.method;
1821} 1845 }
1822"#), 1846 "#,
1823 @r###" 1847 expect![[r#"
1824 47..120 '{ ...hod; }': () 1848 47..120 '{ ...hod; }': ()
1825 57..63 'vtable': Vtable 1849 57..63 'vtable': Vtable
1826 66..90 'Vtable...| {} }': Vtable 1850 66..90 'Vtable...| {} }': Vtable
1827 83..88 '|| {}': || -> () 1851 83..88 '|| {}': || -> ()
1828 86..88 '{}': () 1852 86..88 '{}': ()
1829 100..101 'm': fn() 1853 100..101 'm': fn()
1830 104..110 'vtable': Vtable 1854 104..110 'vtable': Vtable
1831 104..117 'vtable.method': fn() 1855 104..117 'vtable.method': fn()
1832 "### 1856 "#]],
1833 ); 1857 );
1834} 1858}
1835 1859
1836#[test] 1860#[test]
1837fn effects_smoke_test() { 1861fn effects_smoke_test() {
1838 assert_snapshot!( 1862 check_infer(
1839 infer(r#" 1863 r#"
1840fn main() { 1864 fn main() {
1841 let x = unsafe { 92 }; 1865 let x = unsafe { 92 };
1842 let y = async { async { () }.await }; 1866 let y = async { async { () }.await };
1843 let z = try { () }; 1867 let z = try { () };
1844 let t = 'a: { 92 }; 1868 let t = 'a: { 92 };
1845} 1869 }
1846"#), 1870 "#,
1847 @r###" 1871 expect![[r#"
1848 10..130 '{ ...2 }; }': () 1872 10..130 '{ ...2 }; }': ()
1849 20..21 'x': i32 1873 20..21 'x': i32
1850 24..37 'unsafe { 92 }': i32 1874 24..37 'unsafe { 92 }': i32
1851 31..37 '{ 92 }': i32 1875 31..37 '{ 92 }': i32
1852 33..35 '92': i32 1876 33..35 '92': i32
1853 47..48 'y': {unknown} 1877 47..48 'y': {unknown}
1854 57..79 '{ asyn...wait }': {unknown} 1878 57..79 '{ asyn...wait }': {unknown}
1855 59..77 'async ....await': {unknown} 1879 59..77 'async ....await': {unknown}
1856 65..71 '{ () }': () 1880 65..71 '{ () }': ()
1857 67..69 '()': () 1881 67..69 '()': ()
1858 89..90 'z': {unknown} 1882 89..90 'z': {unknown}
1859 93..103 'try { () }': {unknown} 1883 93..103 'try { () }': {unknown}
1860 97..103 '{ () }': () 1884 97..103 '{ () }': ()
1861 99..101 '()': () 1885 99..101 '()': ()
1862 113..114 't': i32 1886 113..114 't': i32
1863 121..127 '{ 92 }': i32 1887 121..127 '{ 92 }': i32
1864 123..125 '92': i32 1888 123..125 '92': i32
1865 "### 1889 "#]],
1866 ) 1890 )
1867} 1891}
1868 1892
1869#[test] 1893#[test]
1870fn infer_generic_from_later_assignment() { 1894fn infer_generic_from_later_assignment() {
1871 assert_snapshot!( 1895 check_infer(
1872 infer(r#" 1896 r#"
1873enum Option<T> { Some(T), None } 1897 enum Option<T> { Some(T), None }
1874use Option::*; 1898 use Option::*;
1875 1899
1876fn test() { 1900 fn test() {
1877 let mut end = None; 1901 let mut end = None;
1878 loop { 1902 loop {
1879 end = Some(true); 1903 end = Some(true);
1880 } 1904 }
1881} 1905 }
1882"#), 1906 "#,
1883 @r###" 1907 expect![[r#"
1884 59..129 '{ ... } }': () 1908 59..129 '{ ... } }': ()
1885 69..76 'mut end': Option<bool> 1909 69..76 'mut end': Option<bool>
1886 79..83 'None': Option<bool> 1910 79..83 'None': Option<bool>
1887 89..127 'loop {... }': ! 1911 89..127 'loop {... }': !
1888 94..127 '{ ... }': () 1912 94..127 '{ ... }': ()
1889 104..107 'end': Option<bool> 1913 104..107 'end': Option<bool>
1890 104..120 'end = ...(true)': () 1914 104..120 'end = ...(true)': ()
1891 110..114 'Some': Some<bool>(bool) -> Option<bool> 1915 110..114 'Some': Some<bool>(bool) -> Option<bool>
1892 110..120 'Some(true)': Option<bool> 1916 110..120 'Some(true)': Option<bool>
1893 115..119 'true': bool 1917 115..119 'true': bool
1894 "### 1918 "#]],
1895 ); 1919 );
1896} 1920}
1897 1921
1898#[test] 1922#[test]
1899fn infer_loop_break_with_val() { 1923fn infer_loop_break_with_val() {
1900 assert_snapshot!( 1924 check_infer(
1901 infer(r#" 1925 r#"
1902enum Option<T> { Some(T), None } 1926 enum Option<T> { Some(T), None }
1903use Option::*; 1927 use Option::*;
1904 1928
1905fn test() { 1929 fn test() {
1906 let x = loop { 1930 let x = loop {
1907 if false { 1931 if false {
1908 break None; 1932 break None;
1909 } 1933 }
1910 1934
1911 break Some(true); 1935 break Some(true);
1912 }; 1936 };
1913} 1937 }
1914"#), 1938 "#,
1915 @r###" 1939 expect![[r#"
1916 59..168 '{ ... }; }': () 1940 59..168 '{ ... }; }': ()
1917 69..70 'x': Option<bool> 1941 69..70 'x': Option<bool>
1918 73..165 'loop {... }': Option<bool> 1942 73..165 'loop {... }': Option<bool>
1919 78..165 '{ ... }': () 1943 78..165 '{ ... }': ()
1920 88..132 'if fal... }': () 1944 88..132 'if fal... }': ()
1921 91..96 'false': bool 1945 91..96 'false': bool
1922 97..132 '{ ... }': () 1946 97..132 '{ ... }': ()
1923 111..121 'break None': ! 1947 111..121 'break None': !
1924 117..121 'None': Option<bool> 1948 117..121 'None': Option<bool>
1925 142..158 'break ...(true)': ! 1949 142..158 'break ...(true)': !
1926 148..152 'Some': Some<bool>(bool) -> Option<bool> 1950 148..152 'Some': Some<bool>(bool) -> Option<bool>
1927 148..158 'Some(true)': Option<bool> 1951 148..158 'Some(true)': Option<bool>
1928 153..157 'true': bool 1952 153..157 'true': bool
1929 "### 1953 "#]],
1930 ); 1954 );
1931} 1955}
1932 1956
1933#[test] 1957#[test]
1934fn infer_loop_break_without_val() { 1958fn infer_loop_break_without_val() {
1935 assert_snapshot!( 1959 check_infer(
1936 infer(r#" 1960 r#"
1937enum Option<T> { Some(T), None } 1961 enum Option<T> { Some(T), None }
1938use Option::*; 1962 use Option::*;
1939 1963
1940fn test() { 1964 fn test() {
1941 let x = loop { 1965 let x = loop {
1942 if false { 1966 if false {
1943 break; 1967 break;
1944 } 1968 }
1945 }; 1969 };
1946} 1970 }
1947"#), 1971 "#,
1948 @r###" 1972 expect![[r#"
1949 59..136 '{ ... }; }': () 1973 59..136 '{ ... }; }': ()
1950 69..70 'x': () 1974 69..70 'x': ()
1951 73..133 'loop {... }': () 1975 73..133 'loop {... }': ()
1952 78..133 '{ ... }': () 1976 78..133 '{ ... }': ()
1953 88..127 'if fal... }': () 1977 88..127 'if fal... }': ()
1954 91..96 'false': bool 1978 91..96 'false': bool
1955 97..127 '{ ... }': () 1979 97..127 '{ ... }': ()
1956 111..116 'break': ! 1980 111..116 'break': !
1957 "### 1981 "#]],
1958 ); 1982 );
1959} 1983}
1960 1984
1961#[test] 1985#[test]
1962fn infer_labelled_break_with_val() { 1986fn infer_labelled_break_with_val() {
1963 assert_snapshot!( 1987 check_infer(
1964 infer(r#" 1988 r#"
1965fn foo() { 1989 fn foo() {
1966 let _x = || 'outer: loop { 1990 let _x = || 'outer: loop {
1967 let inner = 'inner: loop { 1991 let inner = 'inner: loop {
1968 let i = Default::default(); 1992 let i = Default::default();
1969 if (break 'outer i) { 1993 if (break 'outer i) {
1970 loop { break 'inner 5i8; }; 1994 loop { break 'inner 5i8; };
1971 } else if true { 1995 } else if true {
1972 break 'inner 6; 1996 break 'inner 6;
1973 } 1997 }
1974 break 7; 1998 break 7;
1975 }; 1999 };
1976 break inner < 8; 2000 break inner < 8;
1977 }; 2001 };
1978} 2002 }
1979"#), 2003 "#,
1980 @r###" 2004 expect![[r#"
1981 9..335 '{ ... }; }': () 2005 9..335 '{ ... }; }': ()
1982 19..21 '_x': || -> bool 2006 19..21 '_x': || -> bool
1983 24..332 '|| 'ou... }': || -> bool 2007 24..332 '|| 'ou... }': || -> bool
1984 27..332 ''outer... }': bool 2008 27..332 ''outer... }': bool
1985 40..332 '{ ... }': () 2009 40..332 '{ ... }': ()
1986 54..59 'inner': i8 2010 54..59 'inner': i8
1987 62..300 ''inner... }': i8 2011 62..300 ''inner... }': i8
1988 75..300 '{ ... }': () 2012 75..300 '{ ... }': ()
1989 93..94 'i': bool 2013 93..94 'i': bool
1990 97..113 'Defaul...efault': {unknown} 2014 97..113 'Defaul...efault': {unknown}
1991 97..115 'Defaul...ault()': bool 2015 97..115 'Defaul...ault()': bool
1992 129..269 'if (br... }': () 2016 129..269 'if (br... }': ()
1993 133..147 'break 'outer i': ! 2017 133..147 'break 'outer i': !
1994 146..147 'i': bool 2018 146..147 'i': bool
1995 149..208 '{ ... }': () 2019 149..208 '{ ... }': ()
1996 167..193 'loop {...5i8; }': ! 2020 167..193 'loop {...5i8; }': !
1997 172..193 '{ brea...5i8; }': () 2021 172..193 '{ brea...5i8; }': ()
1998 174..190 'break ...er 5i8': ! 2022 174..190 'break ...er 5i8': !
1999 187..190 '5i8': i8 2023 187..190 '5i8': i8
2000 214..269 'if tru... }': () 2024 214..269 'if tru... }': ()
2001 217..221 'true': bool 2025 217..221 'true': bool
2002 222..269 '{ ... }': () 2026 222..269 '{ ... }': ()
2003 240..254 'break 'inner 6': ! 2027 240..254 'break 'inner 6': !
2004 253..254 '6': i8 2028 253..254 '6': i8
2005 282..289 'break 7': ! 2029 282..289 'break 7': !
2006 288..289 '7': i8 2030 288..289 '7': i8
2007 310..325 'break inner < 8': ! 2031 310..325 'break inner < 8': !
2008 316..321 'inner': i8 2032 316..321 'inner': i8
2009 316..325 'inner < 8': bool 2033 316..325 'inner < 8': bool
2010 324..325 '8': i8 2034 324..325 '8': i8
2011 "### 2035 "#]],
2012 ); 2036 );
2013} 2037}
2014 2038
2015#[test] 2039#[test]
2016fn generic_default() { 2040fn generic_default() {
2017 assert_snapshot!( 2041 check_infer(
2018 infer(r#" 2042 r#"
2019struct Thing<T = ()> { t: T } 2043 struct Thing<T = ()> { t: T }
2020enum OtherThing<T = ()> { 2044 enum OtherThing<T = ()> {
2021 One { t: T }, 2045 One { t: T },
2022 Two(T), 2046 Two(T),
2023} 2047 }
2024 2048
2025fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) { 2049 fn test(t1: Thing, t2: OtherThing, t3: Thing<i32>, t4: OtherThing<i32>) {
2026 t1.t; 2050 t1.t;
2027 t3.t; 2051 t3.t;
2028 match t2 { 2052 match t2 {
2029 OtherThing::One { t } => { t; }, 2053 OtherThing::One { t } => { t; },
2030 OtherThing::Two(t) => { t; }, 2054 OtherThing::Two(t) => { t; },
2031 } 2055 }
2032 match t4 { 2056 match t4 {
2033 OtherThing::One { t } => { t; }, 2057 OtherThing::One { t } => { t; },
2034 OtherThing::Two(t) => { t; }, 2058 OtherThing::Two(t) => { t; },
2035 } 2059 }
2036} 2060 }
2037"#), 2061 "#,
2038 @r###" 2062 expect![[r#"
2039 97..99 't1': Thing<()> 2063 97..99 't1': Thing<()>
2040 108..110 't2': OtherThing<()> 2064 108..110 't2': OtherThing<()>
2041 124..126 't3': Thing<i32> 2065 124..126 't3': Thing<i32>
2042 140..142 't4': OtherThing<i32> 2066 140..142 't4': OtherThing<i32>
2043 161..384 '{ ... } }': () 2067 161..384 '{ ... } }': ()
2044 167..169 't1': Thing<()> 2068 167..169 't1': Thing<()>
2045 167..171 't1.t': () 2069 167..171 't1.t': ()
2046 177..179 't3': Thing<i32> 2070 177..179 't3': Thing<i32>
2047 177..181 't3.t': i32 2071 177..181 't3.t': i32
2048 187..282 'match ... }': () 2072 187..282 'match ... }': ()
2049 193..195 't2': OtherThing<()> 2073 193..195 't2': OtherThing<()>
2050 206..227 'OtherT... { t }': OtherThing<()> 2074 206..227 'OtherT... { t }': OtherThing<()>
2051 224..225 't': () 2075 224..225 't': ()
2052 231..237 '{ t; }': () 2076 231..237 '{ t; }': ()
2053 233..234 't': () 2077 233..234 't': ()
2054 247..265 'OtherT...Two(t)': OtherThing<()> 2078 247..265 'OtherT...Two(t)': OtherThing<()>
2055 263..264 't': () 2079 263..264 't': ()
2056 269..275 '{ t; }': () 2080 269..275 '{ t; }': ()
2057 271..272 't': () 2081 271..272 't': ()
2058 287..382 'match ... }': () 2082 287..382 'match ... }': ()
2059 293..295 't4': OtherThing<i32> 2083 293..295 't4': OtherThing<i32>
2060 306..327 'OtherT... { t }': OtherThing<i32> 2084 306..327 'OtherT... { t }': OtherThing<i32>
2061 324..325 't': i32 2085 324..325 't': i32
2062 331..337 '{ t; }': () 2086 331..337 '{ t; }': ()
2063 333..334 't': i32 2087 333..334 't': i32
2064 347..365 'OtherT...Two(t)': OtherThing<i32> 2088 347..365 'OtherT...Two(t)': OtherThing<i32>
2065 363..364 't': i32 2089 363..364 't': i32
2066 369..375 '{ t; }': () 2090 369..375 '{ t; }': ()
2067 371..372 't': i32 2091 371..372 't': i32
2068 "### 2092 "#]],
2069 ); 2093 );
2070} 2094}
2071 2095
2072#[test] 2096#[test]
2073fn generic_default_in_struct_literal() { 2097fn generic_default_in_struct_literal() {
2074 assert_snapshot!( 2098 check_infer(
2075 infer(r#" 2099 r#"
2076struct Thing<T = ()> { t: T } 2100 struct Thing<T = ()> { t: T }
2077enum OtherThing<T = ()> { 2101 enum OtherThing<T = ()> {
2078 One { t: T }, 2102 One { t: T },
2079 Two(T), 2103 Two(T),
2080} 2104 }
2081 2105
2082fn test() { 2106 fn test() {
2083 let x = Thing { t: loop {} }; 2107 let x = Thing { t: loop {} };
2084 let y = Thing { t: () }; 2108 let y = Thing { t: () };
2085 let z = Thing { t: 1i32 }; 2109 let z = Thing { t: 1i32 };
2086 if let Thing { t } = z { 2110 if let Thing { t } = z {
2087 t; 2111 t;
2088 } 2112 }
2089 2113
2090 let a = OtherThing::One { t: 1i32 }; 2114 let a = OtherThing::One { t: 1i32 };
2091 let b = OtherThing::Two(1i32); 2115 let b = OtherThing::Two(1i32);
2092} 2116 }
2093"#), 2117 "#,
2094 @r###" 2118 expect![[r#"
2095 99..319 '{ ...32); }': () 2119 99..319 '{ ...32); }': ()
2096 109..110 'x': Thing<!> 2120 109..110 'x': Thing<!>
2097 113..133 'Thing ...p {} }': Thing<!> 2121 113..133 'Thing ...p {} }': Thing<!>
2098 124..131 'loop {}': ! 2122 124..131 'loop {}': !
2099 129..131 '{}': () 2123 129..131 '{}': ()
2100 143..144 'y': Thing<()> 2124 143..144 'y': Thing<()>
2101 147..162 'Thing { t: () }': Thing<()> 2125 147..162 'Thing { t: () }': Thing<()>
2102 158..160 '()': () 2126 158..160 '()': ()
2103 172..173 'z': Thing<i32> 2127 172..173 'z': Thing<i32>
2104 176..193 'Thing ...1i32 }': Thing<i32> 2128 176..193 'Thing ...1i32 }': Thing<i32>
2105 187..191 '1i32': i32 2129 187..191 '1i32': i32
2106 199..240 'if let... }': () 2130 199..240 'if let... }': ()
2107 206..217 'Thing { t }': Thing<i32> 2131 206..217 'Thing { t }': Thing<i32>
2108 214..215 't': i32 2132 214..215 't': i32
2109 220..221 'z': Thing<i32> 2133 220..221 'z': Thing<i32>
2110 222..240 '{ ... }': () 2134 222..240 '{ ... }': ()
2111 232..233 't': i32 2135 232..233 't': i32
2112 250..251 'a': OtherThing<i32> 2136 250..251 'a': OtherThing<i32>
2113 254..281 'OtherT...1i32 }': OtherThing<i32> 2137 254..281 'OtherT...1i32 }': OtherThing<i32>
2114 275..279 '1i32': i32 2138 275..279 '1i32': i32
2115 291..292 'b': OtherThing<i32> 2139 291..292 'b': OtherThing<i32>
2116 295..310 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32> 2140 295..310 'OtherThing::Two': Two<i32>(i32) -> OtherThing<i32>
2117 295..316 'OtherT...(1i32)': OtherThing<i32> 2141 295..316 'OtherT...(1i32)': OtherThing<i32>
2118 311..315 '1i32': i32 2142 311..315 '1i32': i32
2119 "### 2143 "#]],
2120 ); 2144 );
2121} 2145}
2122 2146
2123#[test] 2147#[test]
2124fn generic_default_depending_on_other_type_arg() { 2148fn generic_default_depending_on_other_type_arg() {
2125 assert_snapshot!( 2149 // FIXME: the {unknown} is a bug
2126 infer(r#" 2150 check_infer(
2127struct Thing<T = u128, F = fn() -> T> { t: T } 2151 r#"
2128 2152 struct Thing<T = u128, F = fn() -> T> { t: T }
2129fn test(t1: Thing<u32>, t2: Thing) { 2153
2130 t1; 2154 fn test(t1: Thing<u32>, t2: Thing) {
2131 t2; 2155 t1;
2132 Thing::<_> { t: 1u32 }; 2156 t2;
2133} 2157 Thing::<_> { t: 1u32 };
2134"#), 2158 }
2135 // FIXME: the {unknown} is a bug 2159 "#,
2136 @r###" 2160 expect![[r#"
2137 56..58 't1': Thing<u32, fn() -> u32> 2161 56..58 't1': Thing<u32, fn() -> u32>
2138 72..74 't2': Thing<u128, fn() -> u128> 2162 72..74 't2': Thing<u128, fn() -> u128>
2139 83..130 '{ ...2 }; }': () 2163 83..130 '{ ...2 }; }': ()
2140 89..91 't1': Thing<u32, fn() -> u32> 2164 89..91 't1': Thing<u32, fn() -> u32>
2141 97..99 't2': Thing<u128, fn() -> u128> 2165 97..99 't2': Thing<u128, fn() -> u128>
2142 105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}> 2166 105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}>
2143 121..125 '1u32': u32 2167 121..125 '1u32': u32
2144 "### 2168 "#]],
2145 ); 2169 );
2146} 2170}
2147 2171
2148#[test] 2172#[test]
2149fn generic_default_depending_on_other_type_arg_forward() { 2173fn generic_default_depending_on_other_type_arg_forward() {
2150 assert_snapshot!( 2174 // the {unknown} here is intentional, as defaults are not allowed to
2151 infer(r#" 2175 // refer to type parameters coming later
2152struct Thing<F = fn() -> T, T = u128> { t: T } 2176 check_infer(
2153 2177 r#"
2154fn test(t1: Thing) { 2178 struct Thing<F = fn() -> T, T = u128> { t: T }
2155 t1; 2179
2156} 2180 fn test(t1: Thing) {
2157"#), 2181 t1;
2158 // the {unknown} here is intentional, as defaults are not allowed to 2182 }
2159 // refer to type parameters coming later 2183 "#,
2160 @r###" 2184 expect![[r#"
2161 56..58 't1': Thing<fn() -> {unknown}, u128> 2185 56..58 't1': Thing<fn() -> {unknown}, u128>
2162 67..78 '{ t1; }': () 2186 67..78 '{ t1; }': ()
2163 73..75 't1': Thing<fn() -> {unknown}, u128> 2187 73..75 't1': Thing<fn() -> {unknown}, u128>
2164 "### 2188 "#]],
2165 ); 2189 );
2166} 2190}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 01c919a7e..526e61caf 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,7 +1,7 @@
1use insta::assert_snapshot; 1use expect::expect;
2use test_utils::mark; 2use test_utils::mark;
3 3
4use super::{check_types, infer, infer_with_mismatches}; 4use super::{check_infer, check_infer_with_mismatches, check_types};
5 5
6#[test] 6#[test]
7fn infer_await() { 7fn infer_await() {
@@ -38,7 +38,7 @@ fn infer_async() {
38 r#" 38 r#"
39//- /main.rs crate:main deps:core 39//- /main.rs crate:main deps:core
40async fn foo() -> u64 { 40async fn foo() -> u64 {
41 128 41 128
42} 42}
43 43
44fn test() { 44fn test() {
@@ -65,7 +65,7 @@ fn infer_desugar_async() {
65 r#" 65 r#"
66//- /main.rs crate:main deps:core 66//- /main.rs crate:main deps:core
67async fn foo() -> u64 { 67async fn foo() -> u64 {
68 128 68 128
69} 69}
70 70
71fn test() { 71fn test() {
@@ -222,291 +222,291 @@ mod ops {
222 222
223#[test] 223#[test]
224fn infer_from_bound_1() { 224fn infer_from_bound_1() {
225 assert_snapshot!( 225 check_infer(
226 infer(r#" 226 r#"
227trait Trait<T> {} 227 trait Trait<T> {}
228struct S<T>(T); 228 struct S<T>(T);
229impl<U> Trait<U> for S<U> {} 229 impl<U> Trait<U> for S<U> {}
230fn foo<T: Trait<u32>>(t: T) {} 230 fn foo<T: Trait<u32>>(t: T) {}
231fn test() { 231 fn test() {
232 let s = S(unknown); 232 let s = S(unknown);
233 foo(s); 233 foo(s);
234} 234 }
235"#), 235 "#,
236 @r###" 236 expect![[r#"
237 85..86 't': T 237 85..86 't': T
238 91..93 '{}': () 238 91..93 '{}': ()
239 104..143 '{ ...(s); }': () 239 104..143 '{ ...(s); }': ()
240 114..115 's': S<u32> 240 114..115 's': S<u32>
241 118..119 'S': S<u32>(u32) -> S<u32> 241 118..119 'S': S<u32>(u32) -> S<u32>
242 118..128 'S(unknown)': S<u32> 242 118..128 'S(unknown)': S<u32>
243 120..127 'unknown': u32 243 120..127 'unknown': u32
244 134..137 'foo': fn foo<S<u32>>(S<u32>) 244 134..137 'foo': fn foo<S<u32>>(S<u32>)
245 134..140 'foo(s)': () 245 134..140 'foo(s)': ()
246 138..139 's': S<u32> 246 138..139 's': S<u32>
247 "### 247 "#]],
248 ); 248 );
249} 249}
250 250
251#[test] 251#[test]
252fn infer_from_bound_2() { 252fn infer_from_bound_2() {
253 assert_snapshot!( 253 check_infer(
254 infer(r#" 254 r#"
255trait Trait<T> {} 255 trait Trait<T> {}
256struct S<T>(T); 256 struct S<T>(T);
257impl<U> Trait<U> for S<U> {} 257 impl<U> Trait<U> for S<U> {}
258fn foo<U, T: Trait<U>>(t: T) -> U {} 258 fn foo<U, T: Trait<U>>(t: T) -> U {}
259fn test() { 259 fn test() {
260 let s = S(unknown); 260 let s = S(unknown);
261 let x: u32 = foo(s); 261 let x: u32 = foo(s);
262} 262 }
263"#), 263 "#,
264 @r###" 264 expect![[r#"
265 86..87 't': T 265 86..87 't': T
266 97..99 '{}': () 266 97..99 '{}': ()
267 110..162 '{ ...(s); }': () 267 110..162 '{ ...(s); }': ()
268 120..121 's': S<u32> 268 120..121 's': S<u32>
269 124..125 'S': S<u32>(u32) -> S<u32> 269 124..125 'S': S<u32>(u32) -> S<u32>
270 124..134 'S(unknown)': S<u32> 270 124..134 'S(unknown)': S<u32>
271 126..133 'unknown': u32 271 126..133 'unknown': u32
272 144..145 'x': u32 272 144..145 'x': u32
273 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32 273 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32
274 153..159 'foo(s)': u32 274 153..159 'foo(s)': u32
275 157..158 's': S<u32> 275 157..158 's': S<u32>
276 "### 276 "#]],
277 ); 277 );
278} 278}
279 279
280#[test] 280#[test]
281fn trait_default_method_self_bound_implements_trait() { 281fn trait_default_method_self_bound_implements_trait() {
282 mark::check!(trait_self_implements_self); 282 mark::check!(trait_self_implements_self);
283 assert_snapshot!( 283 check_infer(
284 infer(r#" 284 r#"
285trait Trait { 285 trait Trait {
286 fn foo(&self) -> i64; 286 fn foo(&self) -> i64;
287 fn bar(&self) -> { 287 fn bar(&self) -> {
288 let x = self.foo(); 288 let x = self.foo();
289 } 289 }
290} 290 }
291"#), 291 "#,
292 @r###" 292 expect![[r#"
293 26..30 'self': &Self 293 26..30 'self': &Self
294 52..56 'self': &Self 294 52..56 'self': &Self
295 61..96 '{ ... }': () 295 61..96 '{ ... }': ()
296 75..76 'x': i64 296 75..76 'x': i64
297 79..83 'self': &Self 297 79..83 'self': &Self
298 79..89 'self.foo()': i64 298 79..89 'self.foo()': i64
299 "### 299 "#]],
300 ); 300 );
301} 301}
302 302
303#[test] 303#[test]
304fn trait_default_method_self_bound_implements_super_trait() { 304fn trait_default_method_self_bound_implements_super_trait() {
305 assert_snapshot!( 305 check_infer(
306 infer(r#" 306 r#"
307trait SuperTrait { 307 trait SuperTrait {
308 fn foo(&self) -> i64; 308 fn foo(&self) -> i64;
309} 309 }
310trait Trait: SuperTrait { 310 trait Trait: SuperTrait {
311 fn bar(&self) -> { 311 fn bar(&self) -> {
312 let x = self.foo(); 312 let x = self.foo();
313 } 313 }
314} 314 }
315"#), 315 "#,
316 @r###" 316 expect![[r#"
317 31..35 'self': &Self 317 31..35 'self': &Self
318 85..89 'self': &Self 318 85..89 'self': &Self
319 94..129 '{ ... }': () 319 94..129 '{ ... }': ()
320 108..109 'x': i64 320 108..109 'x': i64
321 112..116 'self': &Self 321 112..116 'self': &Self
322 112..122 'self.foo()': i64 322 112..122 'self.foo()': i64
323 "### 323 "#]],
324 ); 324 );
325} 325}
326 326
327#[test] 327#[test]
328fn infer_project_associated_type() { 328fn infer_project_associated_type() {
329 assert_snapshot!( 329 check_infer(
330 infer(r#" 330 r#"
331trait Iterable { 331 trait Iterable {
332 type Item; 332 type Item;
333} 333 }
334struct S; 334 struct S;
335impl Iterable for S { type Item = u32; } 335 impl Iterable for S { type Item = u32; }
336fn test<T: Iterable>() { 336 fn test<T: Iterable>() {
337 let x: <S as Iterable>::Item = 1; 337 let x: <S as Iterable>::Item = 1;
338 let y: <T as Iterable>::Item = no_matter; 338 let y: <T as Iterable>::Item = no_matter;
339 let z: T::Item = no_matter; 339 let z: T::Item = no_matter;
340 let a: <T>::Item = no_matter; 340 let a: <T>::Item = no_matter;
341} 341 }
342"#), 342 "#,
343 @r###" 343 expect![[r#"
344 107..260 '{ ...ter; }': () 344 108..261 '{ ...ter; }': ()
345 117..118 'x': u32 345 118..119 'x': u32
346 144..145 '1': u32 346 145..146 '1': u32
347 155..156 'y': Iterable::Item<T> 347 156..157 'y': Iterable::Item<T>
348 182..191 'no_matter': Iterable::Item<T> 348 183..192 'no_matter': Iterable::Item<T>
349 201..202 'z': Iterable::Item<T> 349 202..203 'z': Iterable::Item<T>
350 214..223 'no_matter': Iterable::Item<T> 350 215..224 'no_matter': Iterable::Item<T>
351 233..234 'a': Iterable::Item<T> 351 234..235 'a': Iterable::Item<T>
352 248..257 'no_matter': Iterable::Item<T> 352 249..258 'no_matter': Iterable::Item<T>
353 "### 353 "#]],
354 ); 354 );
355} 355}
356 356
357#[test] 357#[test]
358fn infer_return_associated_type() { 358fn infer_return_associated_type() {
359 assert_snapshot!( 359 check_infer(
360 infer(r#" 360 r#"
361trait Iterable { 361 trait Iterable {
362 type Item; 362 type Item;
363} 363 }
364struct S; 364 struct S;
365impl Iterable for S { type Item = u32; } 365 impl Iterable for S { type Item = u32; }
366fn foo1<T: Iterable>(t: T) -> T::Item {} 366 fn foo1<T: Iterable>(t: T) -> T::Item {}
367fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} 367 fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
368fn foo3<T: Iterable>(t: T) -> <T>::Item {} 368 fn foo3<T: Iterable>(t: T) -> <T>::Item {}
369fn test() { 369 fn test() {
370 let x = foo1(S); 370 let x = foo1(S);
371 let y = foo2(S); 371 let y = foo2(S);
372 let z = foo3(S); 372 let z = foo3(S);
373} 373 }
374"#), 374 "#,
375 @r###" 375 expect![[r#"
376 105..106 't': T 376 106..107 't': T
377 122..124 '{}': () 377 123..125 '{}': ()
378 146..147 't': T 378 147..148 't': T
379 177..179 '{}': () 379 178..180 '{}': ()
380 201..202 't': T 380 202..203 't': T
381 220..222 '{}': () 381 221..223 '{}': ()
382 233..299 '{ ...(S); }': () 382 234..300 '{ ...(S); }': ()
383 243..244 'x': u32 383 244..245 'x': u32
384 247..251 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item 384 248..252 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item
385 247..254 'foo1(S)': u32 385 248..255 'foo1(S)': u32
386 252..253 'S': S 386 253..254 'S': S
387 264..265 'y': u32 387 265..266 'y': u32
388 268..272 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item 388 269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item
389 268..275 'foo2(S)': u32 389 269..276 'foo2(S)': u32
390 273..274 'S': S 390 274..275 'S': S
391 285..286 'z': u32 391 286..287 'z': u32
392 289..293 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item 392 290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item
393 289..296 'foo3(S)': u32 393 290..297 'foo3(S)': u32
394 294..295 'S': S 394 295..296 'S': S
395 "### 395 "#]],
396 ); 396 );
397} 397}
398 398
399#[test] 399#[test]
400fn infer_associated_type_bound() { 400fn infer_associated_type_bound() {
401 assert_snapshot!( 401 check_infer(
402 infer(r#" 402 r#"
403trait Iterable { 403 trait Iterable {
404 type Item; 404 type Item;
405} 405 }
406fn test<T: Iterable<Item=u32>>() { 406 fn test<T: Iterable<Item=u32>>() {
407 let y: T::Item = unknown; 407 let y: T::Item = unknown;
408} 408 }
409"#), 409 "#,
410 @r###" 410 expect![[r#"
411 66..99 '{ ...own; }': () 411 67..100 '{ ...own; }': ()
412 76..77 'y': u32 412 77..78 'y': u32
413 89..96 'unknown': u32 413 90..97 'unknown': u32
414 "### 414 "#]],
415 ); 415 );
416} 416}
417 417
418#[test] 418#[test]
419fn infer_const_body() { 419fn infer_const_body() {
420 assert_snapshot!( 420 check_infer(
421 infer(r#" 421 r#"
422const A: u32 = 1 + 1; 422 const A: u32 = 1 + 1;
423static B: u64 = { let x = 1; x }; 423 static B: u64 = { let x = 1; x };
424"#), 424 "#,
425 @r###" 425 expect![[r#"
426 15..16 '1': u32 426 15..16 '1': u32
427 15..20 '1 + 1': u32 427 15..20 '1 + 1': u32
428 19..20 '1': u32 428 19..20 '1': u32
429 38..54 '{ let ...1; x }': u64 429 38..54 '{ let ...1; x }': u64
430 44..45 'x': u64 430 44..45 'x': u64
431 48..49 '1': u64 431 48..49 '1': u64
432 51..52 'x': u64 432 51..52 'x': u64
433 "### 433 "#]],
434 ); 434 );
435} 435}
436 436
437#[test] 437#[test]
438fn tuple_struct_fields() { 438fn tuple_struct_fields() {
439 assert_snapshot!( 439 check_infer(
440 infer(r#" 440 r#"
441struct S(i32, u64); 441 struct S(i32, u64);
442fn test() -> u64 { 442 fn test() -> u64 {
443 let a = S(4, 6); 443 let a = S(4, 6);
444 let b = a.0; 444 let b = a.0;
445 a.1 445 a.1
446} 446 }
447"#), 447 "#,
448 @r###" 448 expect![[r#"
449 37..86 '{ ... a.1 }': u64 449 37..86 '{ ... a.1 }': u64
450 47..48 'a': S 450 47..48 'a': S
451 51..52 'S': S(i32, u64) -> S 451 51..52 'S': S(i32, u64) -> S
452 51..58 'S(4, 6)': S 452 51..58 'S(4, 6)': S
453 53..54 '4': i32 453 53..54 '4': i32
454 56..57 '6': u64 454 56..57 '6': u64
455 68..69 'b': i32 455 68..69 'b': i32
456 72..73 'a': S 456 72..73 'a': S
457 72..75 'a.0': i32 457 72..75 'a.0': i32
458 81..82 'a': S 458 81..82 'a': S
459 81..84 'a.1': u64 459 81..84 'a.1': u64
460 "### 460 "#]],
461 ); 461 );
462} 462}
463 463
464#[test] 464#[test]
465fn tuple_struct_with_fn() { 465fn tuple_struct_with_fn() {
466 assert_snapshot!( 466 check_infer(
467 infer(r#" 467 r#"
468struct S(fn(u32) -> u64); 468 struct S(fn(u32) -> u64);
469fn test() -> u64 { 469 fn test() -> u64 {
470 let a = S(|i| 2*i); 470 let a = S(|i| 2*i);
471 let b = a.0(4); 471 let b = a.0(4);
472 a.0(2) 472 a.0(2)
473} 473 }
474"#), 474 "#,
475 @r###" 475 expect![[r#"
476 43..101 '{ ...0(2) }': u64 476 43..101 '{ ...0(2) }': u64
477 53..54 'a': S 477 53..54 'a': S
478 57..58 'S': S(fn(u32) -> u64) -> S 478 57..58 'S': S(fn(u32) -> u64) -> S
479 57..67 'S(|i| 2*i)': S 479 57..67 'S(|i| 2*i)': S
480 59..66 '|i| 2*i': |u32| -> u64 480 59..66 '|i| 2*i': |u32| -> u64
481 60..61 'i': u32 481 60..61 'i': u32
482 63..64 '2': u32 482 63..64 '2': u32
483 63..66 '2*i': u32 483 63..66 '2*i': u32
484 65..66 'i': u32 484 65..66 'i': u32
485 77..78 'b': u64 485 77..78 'b': u64
486 81..82 'a': S 486 81..82 'a': S
487 81..84 'a.0': fn(u32) -> u64 487 81..84 'a.0': fn(u32) -> u64
488 81..87 'a.0(4)': u64 488 81..87 'a.0(4)': u64
489 85..86 '4': u32 489 85..86 '4': u32
490 93..94 'a': S 490 93..94 'a': S
491 93..96 'a.0': fn(u32) -> u64 491 93..96 'a.0': fn(u32) -> u64
492 93..99 'a.0(2)': u64 492 93..99 'a.0(2)': u64
493 97..98 '2': u32 493 97..98 '2': u32
494 "### 494 "#]],
495 ); 495 );
496} 496}
497 497
498#[test] 498#[test]
499fn indexing_arrays() { 499fn indexing_arrays() {
500 assert_snapshot!( 500 check_infer(
501 infer("fn main() { &mut [9][2]; }"), 501 "fn main() { &mut [9][2]; }",
502 @r###" 502 expect![[r#"
503 10..26 '{ &mut...[2]; }': () 503 10..26 '{ &mut...[2]; }': ()
504 12..23 '&mut [9][2]': &mut {unknown} 504 12..23 '&mut [9][2]': &mut {unknown}
505 17..20 '[9]': [i32; _] 505 17..20 '[9]': [i32; _]
506 17..23 '[9][2]': {unknown} 506 17..23 '[9][2]': {unknown}
507 18..19 '9': i32 507 18..19 '9': i32
508 21..22 '2': i32 508 21..22 '2': i32
509 "### 509 "#]],
510 ) 510 )
511} 511}
512 512
@@ -541,6 +541,42 @@ mod ops {
541} 541}
542 542
543#[test] 543#[test]
544fn infer_ops_index_int() {
545 check_types(
546 r#"
547//- /main.rs crate:main deps:std
548struct Bar;
549struct Foo;
550
551impl std::ops::Index<u32> for Bar {
552 type Output = Foo;
553}
554
555struct Range;
556impl std::ops::Index<Range> for Bar {
557 type Output = Bar;
558}
559
560fn test() {
561 let a = Bar;
562 let b = a[1];
563 b;
564 //^ Foo
565}
566
567//- /std.rs crate:std
568#[prelude_import] use ops::*;
569mod ops {
570 #[lang = "index"]
571 pub trait Index<Idx> {
572 type Output;
573 }
574}
575"#,
576 );
577}
578
579#[test]
544fn infer_ops_index_autoderef() { 580fn infer_ops_index_autoderef() {
545 check_types( 581 check_types(
546 r#" 582 r#"
@@ -872,476 +908,475 @@ fn test<T: ApplyL>(t: T) {
872 908
873#[test] 909#[test]
874fn argument_impl_trait() { 910fn argument_impl_trait() {
875 assert_snapshot!( 911 check_infer_with_mismatches(
876 infer_with_mismatches(r#" 912 r#"
877trait Trait<T> { 913 trait Trait<T> {
878 fn foo(&self) -> T; 914 fn foo(&self) -> T;
879 fn foo2(&self) -> i64; 915 fn foo2(&self) -> i64;
880} 916 }
881fn bar(x: impl Trait<u16>) {} 917 fn bar(x: impl Trait<u16>) {}
882struct S<T>(T); 918 struct S<T>(T);
883impl<T> Trait<T> for S<T> {} 919 impl<T> Trait<T> for S<T> {}
884 920
885fn test(x: impl Trait<u64>, y: &impl Trait<u32>) { 921 fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
886 x; 922 x;
887 y; 923 y;
888 let z = S(1); 924 let z = S(1);
889 bar(z); 925 bar(z);
890 x.foo(); 926 x.foo();
891 y.foo(); 927 y.foo();
892 z.foo(); 928 z.foo();
893 x.foo2(); 929 x.foo2();
894 y.foo2(); 930 y.foo2();
895 z.foo2(); 931 z.foo2();
896} 932 }
897"#, true), 933 "#,
898 @r###" 934 expect![[r#"
899 29..33 'self': &Self 935 29..33 'self': &Self
900 54..58 'self': &Self 936 54..58 'self': &Self
901 77..78 'x': impl Trait<u16> 937 77..78 'x': impl Trait<u16>
902 97..99 '{}': () 938 97..99 '{}': ()
903 154..155 'x': impl Trait<u64> 939 154..155 'x': impl Trait<u64>
904 174..175 'y': &impl Trait<u32> 940 174..175 'y': &impl Trait<u32>
905 195..323 '{ ...2(); }': () 941 195..323 '{ ...2(); }': ()
906 201..202 'x': impl Trait<u64> 942 201..202 'x': impl Trait<u64>
907 208..209 'y': &impl Trait<u32> 943 208..209 'y': &impl Trait<u32>
908 219..220 'z': S<u16> 944 219..220 'z': S<u16>
909 223..224 'S': S<u16>(u16) -> S<u16> 945 223..224 'S': S<u16>(u16) -> S<u16>
910 223..227 'S(1)': S<u16> 946 223..227 'S(1)': S<u16>
911 225..226 '1': u16 947 225..226 '1': u16
912 233..236 'bar': fn bar(S<u16>) 948 233..236 'bar': fn bar(S<u16>)
913 233..239 'bar(z)': () 949 233..239 'bar(z)': ()
914 237..238 'z': S<u16> 950 237..238 'z': S<u16>
915 245..246 'x': impl Trait<u64> 951 245..246 'x': impl Trait<u64>
916 245..252 'x.foo()': u64 952 245..252 'x.foo()': u64
917 258..259 'y': &impl Trait<u32> 953 258..259 'y': &impl Trait<u32>
918 258..265 'y.foo()': u32 954 258..265 'y.foo()': u32
919 271..272 'z': S<u16> 955 271..272 'z': S<u16>
920 271..278 'z.foo()': u16 956 271..278 'z.foo()': u16
921 284..285 'x': impl Trait<u64> 957 284..285 'x': impl Trait<u64>
922 284..292 'x.foo2()': i64 958 284..292 'x.foo2()': i64
923 298..299 'y': &impl Trait<u32> 959 298..299 'y': &impl Trait<u32>
924 298..306 'y.foo2()': i64 960 298..306 'y.foo2()': i64
925 312..313 'z': S<u16> 961 312..313 'z': S<u16>
926 312..320 'z.foo2()': i64 962 312..320 'z.foo2()': i64
927 "### 963 "#]],
928 ); 964 );
929} 965}
930 966
931#[test] 967#[test]
932fn argument_impl_trait_type_args_1() { 968fn argument_impl_trait_type_args_1() {
933 assert_snapshot!( 969 check_infer_with_mismatches(
934 infer_with_mismatches(r#" 970 r#"
935trait Trait {} 971 trait Trait {}
936trait Foo { 972 trait Foo {
937 // this function has an implicit Self param, an explicit type param, 973 // this function has an implicit Self param, an explicit type param,
938 // and an implicit impl Trait param! 974 // and an implicit impl Trait param!
939 fn bar<T>(x: impl Trait) -> T { loop {} } 975 fn bar<T>(x: impl Trait) -> T { loop {} }
940} 976 }
941fn foo<T>(x: impl Trait) -> T { loop {} } 977 fn foo<T>(x: impl Trait) -> T { loop {} }
942struct S; 978 struct S;
943impl Trait for S {} 979 impl Trait for S {}
944struct F; 980 struct F;
945impl Foo for F {} 981 impl Foo for F {}
946 982
947fn test() { 983 fn test() {
948 Foo::bar(S); 984 Foo::bar(S);
949 <F as Foo>::bar(S); 985 <F as Foo>::bar(S);
950 F::bar(S); 986 F::bar(S);
951 Foo::bar::<u32>(S); 987 Foo::bar::<u32>(S);
952 <F as Foo>::bar::<u32>(S); 988 <F as Foo>::bar::<u32>(S);
953 989
954 foo(S); 990 foo(S);
955 foo::<u32>(S); 991 foo::<u32>(S);
956 foo::<u32, i32>(S); // we should ignore the extraneous i32 992 foo::<u32, i32>(S); // we should ignore the extraneous i32
957} 993 }
958"#, true), 994 "#,
959 @r###" 995 expect![[r#"
960 155..156 'x': impl Trait 996 155..156 'x': impl Trait
961 175..186 '{ loop {} }': T 997 175..186 '{ loop {} }': T
962 177..184 'loop {}': ! 998 177..184 'loop {}': !
963 182..184 '{}': () 999 182..184 '{}': ()
964 199..200 'x': impl Trait 1000 199..200 'x': impl Trait
965 219..230 '{ loop {} }': T 1001 219..230 '{ loop {} }': T
966 221..228 'loop {}': ! 1002 221..228 'loop {}': !
967 226..228 '{}': () 1003 226..228 '{}': ()
968 300..509 '{ ... i32 }': () 1004 300..509 '{ ... i32 }': ()
969 306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown} 1005 306..314 'Foo::bar': fn bar<{unknown}, {unknown}>(S) -> {unknown}
970 306..317 'Foo::bar(S)': {unknown} 1006 306..317 'Foo::bar(S)': {unknown}
971 315..316 'S': S 1007 315..316 'S': S
972 323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown} 1008 323..338 '<F as Foo>::bar': fn bar<F, {unknown}>(S) -> {unknown}
973 323..341 '<F as ...bar(S)': {unknown} 1009 323..341 '<F as ...bar(S)': {unknown}
974 339..340 'S': S 1010 339..340 'S': S
975 347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown} 1011 347..353 'F::bar': fn bar<F, {unknown}>(S) -> {unknown}
976 347..356 'F::bar(S)': {unknown} 1012 347..356 'F::bar(S)': {unknown}
977 354..355 'S': S 1013 354..355 'S': S
978 362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32 1014 362..377 'Foo::bar::<u32>': fn bar<{unknown}, u32>(S) -> u32
979 362..380 'Foo::b...32>(S)': u32 1015 362..380 'Foo::b...32>(S)': u32
980 378..379 'S': S 1016 378..379 'S': S
981 386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32 1017 386..408 '<F as ...:<u32>': fn bar<F, u32>(S) -> u32
982 386..411 '<F as ...32>(S)': u32 1018 386..411 '<F as ...32>(S)': u32
983 409..410 'S': S 1019 409..410 'S': S
984 418..421 'foo': fn foo<{unknown}>(S) -> {unknown} 1020 418..421 'foo': fn foo<{unknown}>(S) -> {unknown}
985 418..424 'foo(S)': {unknown} 1021 418..424 'foo(S)': {unknown}
986 422..423 'S': S 1022 422..423 'S': S
987 430..440 'foo::<u32>': fn foo<u32>(S) -> u32 1023 430..440 'foo::<u32>': fn foo<u32>(S) -> u32
988 430..443 'foo::<u32>(S)': u32 1024 430..443 'foo::<u32>(S)': u32
989 441..442 'S': S 1025 441..442 'S': S
990 449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32 1026 449..464 'foo::<u32, i32>': fn foo<u32>(S) -> u32
991 449..467 'foo::<...32>(S)': u32 1027 449..467 'foo::<...32>(S)': u32
992 465..466 'S': S 1028 465..466 'S': S
993 "### 1029 "#]],
994 ); 1030 );
995} 1031}
996 1032
997#[test] 1033#[test]
998fn argument_impl_trait_type_args_2() { 1034fn argument_impl_trait_type_args_2() {
999 assert_snapshot!( 1035 check_infer_with_mismatches(
1000 infer_with_mismatches(r#" 1036 r#"
1001trait Trait {} 1037 trait Trait {}
1002struct S; 1038 struct S;
1003impl Trait for S {} 1039 impl Trait for S {}
1004struct F<T>; 1040 struct F<T>;
1005impl<T> F<T> { 1041 impl<T> F<T> {
1006 fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} } 1042 fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
1007} 1043 }
1008 1044
1009fn test() { 1045 fn test() {
1010 F.foo(S); 1046 F.foo(S);
1011 F::<u32>.foo(S); 1047 F::<u32>.foo(S);
1012 F::<u32>.foo::<i32>(S); 1048 F::<u32>.foo::<i32>(S);
1013 F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored 1049 F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
1014} 1050 }
1015"#, true), 1051 "#,
1016 @r###" 1052 expect![[r#"
1017 87..91 'self': F<T> 1053 87..91 'self': F<T>
1018 93..94 'x': impl Trait 1054 93..94 'x': impl Trait
1019 118..129 '{ loop {} }': (T, U) 1055 118..129 '{ loop {} }': (T, U)
1020 120..127 'loop {}': ! 1056 120..127 'loop {}': !
1021 125..127 '{}': () 1057 125..127 '{}': ()
1022 143..283 '{ ...ored }': () 1058 143..283 '{ ...ored }': ()
1023 149..150 'F': F<{unknown}> 1059 149..150 'F': F<{unknown}>
1024 149..157 'F.foo(S)': ({unknown}, {unknown}) 1060 149..157 'F.foo(S)': ({unknown}, {unknown})
1025 155..156 'S': S 1061 155..156 'S': S
1026 163..171 'F::<u32>': F<u32> 1062 163..171 'F::<u32>': F<u32>
1027 163..178 'F::<u32>.foo(S)': (u32, {unknown}) 1063 163..178 'F::<u32>.foo(S)': (u32, {unknown})
1028 176..177 'S': S 1064 176..177 'S': S
1029 184..192 'F::<u32>': F<u32> 1065 184..192 'F::<u32>': F<u32>
1030 184..206 'F::<u3...32>(S)': (u32, i32) 1066 184..206 'F::<u3...32>(S)': (u32, i32)
1031 204..205 'S': S 1067 204..205 'S': S
1032 212..220 'F::<u32>': F<u32> 1068 212..220 'F::<u32>': F<u32>
1033 212..239 'F::<u3...32>(S)': (u32, i32) 1069 212..239 'F::<u3...32>(S)': (u32, i32)
1034 237..238 'S': S 1070 237..238 'S': S
1035 "### 1071 "#]],
1036 ); 1072 );
1037} 1073}
1038 1074
1039#[test] 1075#[test]
1040fn argument_impl_trait_to_fn_pointer() { 1076fn argument_impl_trait_to_fn_pointer() {
1041 assert_snapshot!( 1077 check_infer_with_mismatches(
1042 infer_with_mismatches(r#" 1078 r#"
1043trait Trait {} 1079 trait Trait {}
1044fn foo(x: impl Trait) { loop {} } 1080 fn foo(x: impl Trait) { loop {} }
1045struct S; 1081 struct S;
1046impl Trait for S {} 1082 impl Trait for S {}
1047 1083
1048fn test() { 1084 fn test() {
1049 let f: fn(S) -> () = foo; 1085 let f: fn(S) -> () = foo;
1050} 1086 }
1051"#, true), 1087 "#,
1052 @r###" 1088 expect![[r#"
1053 22..23 'x': impl Trait 1089 22..23 'x': impl Trait
1054 37..48 '{ loop {} }': () 1090 37..48 '{ loop {} }': ()
1055 39..46 'loop {}': ! 1091 39..46 'loop {}': !
1056 44..46 '{}': () 1092 44..46 '{}': ()
1057 90..123 '{ ...foo; }': () 1093 90..123 '{ ...foo; }': ()
1058 100..101 'f': fn(S) 1094 100..101 'f': fn(S)
1059 117..120 'foo': fn foo(S) 1095 117..120 'foo': fn foo(S)
1060 "### 1096 "#]],
1061 ); 1097 );
1062} 1098}
1063 1099
1064#[test] 1100#[test]
1065fn impl_trait() { 1101fn impl_trait() {
1066 assert_snapshot!( 1102 check_infer(
1067 infer(r#" 1103 r#"
1068trait Trait<T> { 1104 trait Trait<T> {
1069 fn foo(&self) -> T; 1105 fn foo(&self) -> T;
1070 fn foo2(&self) -> i64; 1106 fn foo2(&self) -> i64;
1071} 1107 }
1072fn bar() -> impl Trait<u64> {} 1108 fn bar() -> impl Trait<u64> {}
1073 1109
1074fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { 1110 fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
1075 x; 1111 x;
1076 y; 1112 y;
1077 let z = bar(); 1113 let z = bar();
1078 x.foo(); 1114 x.foo();
1079 y.foo(); 1115 y.foo();
1080 z.foo(); 1116 z.foo();
1081 x.foo2(); 1117 x.foo2();
1082 y.foo2(); 1118 y.foo2();
1083 z.foo2(); 1119 z.foo2();
1084} 1120 }
1085"#), 1121 "#,
1086 @r###" 1122 expect![[r#"
1087 29..33 'self': &Self 1123 29..33 'self': &Self
1088 54..58 'self': &Self 1124 54..58 'self': &Self
1089 98..100 '{}': () 1125 98..100 '{}': ()
1090 110..111 'x': impl Trait<u64> 1126 110..111 'x': impl Trait<u64>
1091 130..131 'y': &impl Trait<u64> 1127 130..131 'y': &impl Trait<u64>
1092 151..268 '{ ...2(); }': () 1128 151..268 '{ ...2(); }': ()
1093 157..158 'x': impl Trait<u64> 1129 157..158 'x': impl Trait<u64>
1094 164..165 'y': &impl Trait<u64> 1130 164..165 'y': &impl Trait<u64>
1095 175..176 'z': impl Trait<u64> 1131 175..176 'z': impl Trait<u64>
1096 179..182 'bar': fn bar() -> impl Trait<u64> 1132 179..182 'bar': fn bar() -> impl Trait<u64>
1097 179..184 'bar()': impl Trait<u64> 1133 179..184 'bar()': impl Trait<u64>
1098 190..191 'x': impl Trait<u64> 1134 190..191 'x': impl Trait<u64>
1099 190..197 'x.foo()': u64 1135 190..197 'x.foo()': u64
1100 203..204 'y': &impl Trait<u64> 1136 203..204 'y': &impl Trait<u64>
1101 203..210 'y.foo()': u64 1137 203..210 'y.foo()': u64
1102 216..217 'z': impl Trait<u64> 1138 216..217 'z': impl Trait<u64>
1103 216..223 'z.foo()': u64 1139 216..223 'z.foo()': u64
1104 229..230 'x': impl Trait<u64> 1140 229..230 'x': impl Trait<u64>
1105 229..237 'x.foo2()': i64 1141 229..237 'x.foo2()': i64
1106 243..244 'y': &impl Trait<u64> 1142 243..244 'y': &impl Trait<u64>
1107 243..251 'y.foo2()': i64 1143 243..251 'y.foo2()': i64
1108 257..258 'z': impl Trait<u64> 1144 257..258 'z': impl Trait<u64>
1109 257..265 'z.foo2()': i64 1145 257..265 'z.foo2()': i64
1110 "### 1146 "#]],
1111 ); 1147 );
1112} 1148}
1113 1149
1114#[test] 1150#[test]
1115fn simple_return_pos_impl_trait() { 1151fn simple_return_pos_impl_trait() {
1116 mark::check!(lower_rpit); 1152 mark::check!(lower_rpit);
1117 assert_snapshot!( 1153 check_infer(
1118 infer(r#" 1154 r#"
1119trait Trait<T> { 1155 trait Trait<T> {
1120 fn foo(&self) -> T; 1156 fn foo(&self) -> T;
1121} 1157 }
1122fn bar() -> impl Trait<u64> { loop {} } 1158 fn bar() -> impl Trait<u64> { loop {} }
1123 1159
1124fn test() { 1160 fn test() {
1125 let a = bar(); 1161 let a = bar();
1126 a.foo(); 1162 a.foo();
1127} 1163 }
1128"#), 1164 "#,
1129 @r###" 1165 expect![[r#"
1130 29..33 'self': &Self 1166 29..33 'self': &Self
1131 71..82 '{ loop {} }': ! 1167 71..82 '{ loop {} }': !
1132 73..80 'loop {}': ! 1168 73..80 'loop {}': !
1133 78..80 '{}': () 1169 78..80 '{}': ()
1134 94..129 '{ ...o(); }': () 1170 94..129 '{ ...o(); }': ()
1135 104..105 'a': impl Trait<u64> 1171 104..105 'a': impl Trait<u64>
1136 108..111 'bar': fn bar() -> impl Trait<u64> 1172 108..111 'bar': fn bar() -> impl Trait<u64>
1137 108..113 'bar()': impl Trait<u64> 1173 108..113 'bar()': impl Trait<u64>
1138 119..120 'a': impl Trait<u64> 1174 119..120 'a': impl Trait<u64>
1139 119..126 'a.foo()': u64 1175 119..126 'a.foo()': u64
1140 "### 1176 "#]],
1141 ); 1177 );
1142} 1178}
1143 1179
1144#[test] 1180#[test]
1145fn more_return_pos_impl_trait() { 1181fn more_return_pos_impl_trait() {
1146 assert_snapshot!( 1182 check_infer(
1147 infer(r#" 1183 r#"
1148trait Iterator { 1184 trait Iterator {
1149 type Item; 1185 type Item;
1150 fn next(&mut self) -> Self::Item; 1186 fn next(&mut self) -> Self::Item;
1151} 1187 }
1152trait Trait<T> { 1188 trait Trait<T> {
1153 fn foo(&self) -> T; 1189 fn foo(&self) -> T;
1154} 1190 }
1155fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} } 1191 fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
1156fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} } 1192 fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
1157 1193
1158fn test() { 1194 fn test() {
1159 let (a, b) = bar(); 1195 let (a, b) = bar();
1160 a.next().foo(); 1196 a.next().foo();
1161 b.foo(); 1197 b.foo();
1162 let (c, d) = baz(1u128); 1198 let (c, d) = baz(1u128);
1163 c.next().foo(); 1199 c.next().foo();
1164 d.foo(); 1200 d.foo();
1165} 1201 }
1166"#), 1202 "#,
1167 @r###" 1203 expect![[r#"
1168 49..53 'self': &mut Self 1204 49..53 'self': &mut Self
1169 101..105 'self': &Self 1205 101..105 'self': &Self
1170 184..195 '{ loop {} }': ({unknown}, {unknown}) 1206 184..195 '{ loop {} }': ({unknown}, {unknown})
1171 186..193 'loop {}': ! 1207 186..193 'loop {}': !
1172 191..193 '{}': () 1208 191..193 '{}': ()
1173 206..207 't': T 1209 206..207 't': T
1174 268..279 '{ loop {} }': ({unknown}, {unknown}) 1210 268..279 '{ loop {} }': ({unknown}, {unknown})
1175 270..277 'loop {}': ! 1211 270..277 'loop {}': !
1176 275..277 '{}': () 1212 275..277 '{}': ()
1177 291..413 '{ ...o(); }': () 1213 291..413 '{ ...o(); }': ()
1178 301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) 1214 301..307 '(a, b)': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1179 302..303 'a': impl Iterator<Item = impl Trait<u32>> 1215 302..303 'a': impl Iterator<Item = impl Trait<u32>>
1180 305..306 'b': impl Trait<u64> 1216 305..306 'b': impl Trait<u64>
1181 310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) 1217 310..313 'bar': fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1182 310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) 1218 310..315 'bar()': (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>)
1183 321..322 'a': impl Iterator<Item = impl Trait<u32>> 1219 321..322 'a': impl Iterator<Item = impl Trait<u32>>
1184 321..329 'a.next()': impl Trait<u32> 1220 321..329 'a.next()': impl Trait<u32>
1185 321..335 'a.next().foo()': u32 1221 321..335 'a.next().foo()': u32
1186 341..342 'b': impl Trait<u64> 1222 341..342 'b': impl Trait<u64>
1187 341..348 'b.foo()': u64 1223 341..348 'b.foo()': u64
1188 358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) 1224 358..364 '(c, d)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1189 359..360 'c': impl Iterator<Item = impl Trait<u128>> 1225 359..360 'c': impl Iterator<Item = impl Trait<u128>>
1190 362..363 'd': impl Trait<u128> 1226 362..363 'd': impl Trait<u128>
1191 367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) 1227 367..370 'baz': fn baz<u128>(u128) -> (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1192 367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>) 1228 367..377 'baz(1u128)': (impl Iterator<Item = impl Trait<u128>>, impl Trait<u128>)
1193 371..376 '1u128': u128 1229 371..376 '1u128': u128
1194 383..384 'c': impl Iterator<Item = impl Trait<u128>> 1230 383..384 'c': impl Iterator<Item = impl Trait<u128>>
1195 383..391 'c.next()': impl Trait<u128> 1231 383..391 'c.next()': impl Trait<u128>
1196 383..397 'c.next().foo()': u128 1232 383..397 'c.next().foo()': u128
1197 403..404 'd': impl Trait<u128> 1233 403..404 'd': impl Trait<u128>
1198 403..410 'd.foo()': u128 1234 403..410 'd.foo()': u128
1199 "### 1235 "#]],
1200 ); 1236 );
1201} 1237}
1202 1238
1203#[test] 1239#[test]
1204fn dyn_trait() { 1240fn dyn_trait() {
1205 assert_snapshot!( 1241 check_infer(
1206 infer(r#" 1242 r#"
1207trait Trait<T> { 1243 trait Trait<T> {
1208 fn foo(&self) -> T; 1244 fn foo(&self) -> T;
1209 fn foo2(&self) -> i64; 1245 fn foo2(&self) -> i64;
1210} 1246 }
1211fn bar() -> dyn Trait<u64> {} 1247 fn bar() -> dyn Trait<u64> {}
1212 1248
1213fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { 1249 fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
1214 x; 1250 x;
1215 y; 1251 y;
1216 let z = bar(); 1252 let z = bar();
1217 x.foo(); 1253 x.foo();
1218 y.foo(); 1254 y.foo();
1219 z.foo(); 1255 z.foo();
1220 x.foo2(); 1256 x.foo2();
1221 y.foo2(); 1257 y.foo2();
1222 z.foo2(); 1258 z.foo2();
1223} 1259 }
1224"#), 1260 "#,
1225 @r###" 1261 expect![[r#"
1226 29..33 'self': &Self 1262 29..33 'self': &Self
1227 54..58 'self': &Self 1263 54..58 'self': &Self
1228 97..99 '{}': () 1264 97..99 '{}': ()
1229 109..110 'x': dyn Trait<u64> 1265 109..110 'x': dyn Trait<u64>
1230 128..129 'y': &dyn Trait<u64> 1266 128..129 'y': &dyn Trait<u64>
1231 148..265 '{ ...2(); }': () 1267 148..265 '{ ...2(); }': ()
1232 154..155 'x': dyn Trait<u64> 1268 154..155 'x': dyn Trait<u64>
1233 161..162 'y': &dyn Trait<u64> 1269 161..162 'y': &dyn Trait<u64>
1234 172..173 'z': dyn Trait<u64> 1270 172..173 'z': dyn Trait<u64>
1235 176..179 'bar': fn bar() -> dyn Trait<u64> 1271 176..179 'bar': fn bar() -> dyn Trait<u64>
1236 176..181 'bar()': dyn Trait<u64> 1272 176..181 'bar()': dyn Trait<u64>
1237 187..188 'x': dyn Trait<u64> 1273 187..188 'x': dyn Trait<u64>
1238 187..194 'x.foo()': u64 1274 187..194 'x.foo()': u64
1239 200..201 'y': &dyn Trait<u64> 1275 200..201 'y': &dyn Trait<u64>
1240 200..207 'y.foo()': u64 1276 200..207 'y.foo()': u64
1241 213..214 'z': dyn Trait<u64> 1277 213..214 'z': dyn Trait<u64>
1242 213..220 'z.foo()': u64 1278 213..220 'z.foo()': u64
1243 226..227 'x': dyn Trait<u64> 1279 226..227 'x': dyn Trait<u64>
1244 226..234 'x.foo2()': i64 1280 226..234 'x.foo2()': i64
1245 240..241 'y': &dyn Trait<u64> 1281 240..241 'y': &dyn Trait<u64>
1246 240..248 'y.foo2()': i64 1282 240..248 'y.foo2()': i64
1247 254..255 'z': dyn Trait<u64> 1283 254..255 'z': dyn Trait<u64>
1248 254..262 'z.foo2()': i64 1284 254..262 'z.foo2()': i64
1249 "### 1285 "#]],
1250 ); 1286 );
1251} 1287}
1252 1288
1253#[test] 1289#[test]
1254fn dyn_trait_in_impl() { 1290fn dyn_trait_in_impl() {
1255 assert_snapshot!( 1291 check_infer(
1256 infer(r#" 1292 r#"
1257trait Trait<T, U> { 1293 trait Trait<T, U> {
1258 fn foo(&self) -> (T, U); 1294 fn foo(&self) -> (T, U);
1259} 1295 }
1260struct S<T, U> {} 1296 struct S<T, U> {}
1261impl<T, U> S<T, U> { 1297 impl<T, U> S<T, U> {
1262 fn bar(&self) -> &dyn Trait<T, U> { loop {} } 1298 fn bar(&self) -> &dyn Trait<T, U> { loop {} }
1263} 1299 }
1264trait Trait2<T, U> { 1300 trait Trait2<T, U> {
1265 fn baz(&self) -> (T, U); 1301 fn baz(&self) -> (T, U);
1266} 1302 }
1267impl<T, U> Trait2<T, U> for dyn Trait<T, U> { } 1303 impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
1268 1304
1269fn test(s: S<u32, i32>) { 1305 fn test(s: S<u32, i32>) {
1270 s.bar().baz(); 1306 s.bar().baz();
1271} 1307 }
1272"#), 1308 "#,
1273 @r###" 1309 expect![[r#"
1274 32..36 'self': &Self 1310 32..36 'self': &Self
1275 102..106 'self': &S<T, U> 1311 102..106 'self': &S<T, U>
1276 128..139 '{ loop {} }': &dyn Trait<T, U> 1312 128..139 '{ loop {} }': &dyn Trait<T, U>
1277 130..137 'loop {}': ! 1313 130..137 'loop {}': !
1278 135..137 '{}': () 1314 135..137 '{}': ()
1279 175..179 'self': &Self 1315 175..179 'self': &Self
1280 251..252 's': S<u32, i32> 1316 251..252 's': S<u32, i32>
1281 267..289 '{ ...z(); }': () 1317 267..289 '{ ...z(); }': ()
1282 273..274 's': S<u32, i32> 1318 273..274 's': S<u32, i32>
1283 273..280 's.bar()': &dyn Trait<u32, i32> 1319 273..280 's.bar()': &dyn Trait<u32, i32>
1284 273..286 's.bar().baz()': (u32, i32) 1320 273..286 's.bar().baz()': (u32, i32)
1285 "### 1321 "#]],
1286 ); 1322 );
1287} 1323}
1288 1324
1289#[test] 1325#[test]
1290fn dyn_trait_bare() { 1326fn dyn_trait_bare() {
1291 assert_snapshot!( 1327 check_infer(
1292 infer(r#" 1328 r#"
1293trait Trait { 1329 trait Trait {
1294 fn foo(&self) -> u64; 1330 fn foo(&self) -> u64;
1295} 1331 }
1296fn bar() -> Trait {} 1332 fn bar() -> Trait {}
1297 1333
1298fn test(x: Trait, y: &Trait) -> u64 { 1334 fn test(x: Trait, y: &Trait) -> u64 {
1299 x; 1335 x;
1300 y; 1336 y;
1301 let z = bar(); 1337 let z = bar();
1302 x.foo(); 1338 x.foo();
1303 y.foo(); 1339 y.foo();
1304 z.foo(); 1340 z.foo();
1305} 1341 }
1306"#), 1342 "#,
1307 @r###" 1343 expect![[r#"
1308 26..30 'self': &Self 1344 26..30 'self': &Self
1309 60..62 '{}': () 1345 60..62 '{}': ()
1310 72..73 'x': dyn Trait 1346 72..73 'x': dyn Trait
1311 82..83 'y': &dyn Trait 1347 82..83 'y': &dyn Trait
1312 100..175 '{ ...o(); }': () 1348 100..175 '{ ...o(); }': ()
1313 106..107 'x': dyn Trait 1349 106..107 'x': dyn Trait
1314 113..114 'y': &dyn Trait 1350 113..114 'y': &dyn Trait
1315 124..125 'z': dyn Trait 1351 124..125 'z': dyn Trait
1316 128..131 'bar': fn bar() -> dyn Trait 1352 128..131 'bar': fn bar() -> dyn Trait
1317 128..133 'bar()': dyn Trait 1353 128..133 'bar()': dyn Trait
1318 139..140 'x': dyn Trait 1354 139..140 'x': dyn Trait
1319 139..146 'x.foo()': u64 1355 139..146 'x.foo()': u64
1320 152..153 'y': &dyn Trait 1356 152..153 'y': &dyn Trait
1321 152..159 'y.foo()': u64 1357 152..159 'y.foo()': u64
1322 165..166 'z': dyn Trait 1358 165..166 'z': dyn Trait
1323 165..172 'z.foo()': u64 1359 165..172 'z.foo()': u64
1324 "### 1360 "#]],
1325 ); 1361 );
1326} 1362}
1327 1363
1328#[test] 1364#[test]
1329fn weird_bounds() { 1365fn weird_bounds() {
1330 assert_snapshot!( 1366 check_infer(
1331 infer(r#" 1367 r#"
1332trait Trait {} 1368 trait Trait {}
1333fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) { 1369 fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) {}
1334} 1370 "#,
1335"#), 1371 expect![[r#"
1336 @r###" 1372 23..24 'a': impl Trait + {error}
1337 23..24 'a': impl Trait + {error} 1373 50..51 'b': impl {error}
1338 50..51 'b': impl {error} 1374 69..70 'c': impl Trait
1339 69..70 'c': impl Trait 1375 86..87 'd': impl {error}
1340 86..87 'd': impl {error} 1376 107..108 'e': impl {error}
1341 107..108 'e': impl {error} 1377 123..124 'f': impl Trait + {error}
1342 123..124 'f': impl Trait + {error} 1378 147..149 '{}': ()
1343 147..150 '{ }': () 1379 "#]],
1344 "###
1345 ); 1380 );
1346} 1381}
1347 1382
@@ -1363,66 +1398,66 @@ fn test(x: (impl Trait + UnknownTrait)) {
1363 1398
1364#[test] 1399#[test]
1365fn assoc_type_bindings() { 1400fn assoc_type_bindings() {
1366 assert_snapshot!( 1401 check_infer(
1367 infer(r#" 1402 r#"
1368trait Trait { 1403 trait Trait {
1369 type Type; 1404 type Type;
1370} 1405 }
1371
1372fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
1373fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1374fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1375 1406
1376struct S<T>; 1407 fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
1377impl<T> Trait for S<T> { type Type = T; } 1408 fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1378 1409 fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1379fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { 1410
1380 get(x); 1411 struct S<T>;
1381 get2(x); 1412 impl<T> Trait for S<T> { type Type = T; }
1382 get(y); 1413
1383 get2(y); 1414 fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
1384 get(set(S)); 1415 get(x);
1385 get2(set(S)); 1416 get2(x);
1386 get2(S::<str>); 1417 get(y);
1387} 1418 get2(y);
1388"#), 1419 get(set(S));
1389 @r###" 1420 get2(set(S));
1390 49..50 't': T 1421 get2(S::<str>);
1391 77..79 '{}': () 1422 }
1392 111..112 't': T 1423 "#,
1393 122..124 '{}': () 1424 expect![[r#"
1394 154..155 't': T 1425 49..50 't': T
1395 165..168 '{t}': T 1426 77..79 '{}': ()
1396 166..167 't': T 1427 111..112 't': T
1397 256..257 'x': T 1428 122..124 '{}': ()
1398 262..263 'y': impl Trait<Type = i64> 1429 154..155 't': T
1399 289..397 '{ ...r>); }': () 1430 165..168 '{t}': T
1400 295..298 'get': fn get<T>(T) -> <T as Trait>::Type 1431 166..167 't': T
1401 295..301 'get(x)': u32 1432 256..257 'x': T
1402 299..300 'x': T 1433 262..263 'y': impl Trait<Type = i64>
1403 307..311 'get2': fn get2<u32, T>(T) -> u32 1434 289..397 '{ ...r>); }': ()
1404 307..314 'get2(x)': u32 1435 295..298 'get': fn get<T>(T) -> <T as Trait>::Type
1405 312..313 'x': T 1436 295..301 'get(x)': u32
1406 320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type 1437 299..300 'x': T
1407 320..326 'get(y)': i64 1438 307..311 'get2': fn get2<u32, T>(T) -> u32
1408 324..325 'y': impl Trait<Type = i64> 1439 307..314 'get2(x)': u32
1409 332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64 1440 312..313 'x': T
1410 332..339 'get2(y)': i64 1441 320..323 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type
1411 337..338 'y': impl Trait<Type = i64> 1442 320..326 'get(y)': i64
1412 345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type 1443 324..325 'y': impl Trait<Type = i64>
1413 345..356 'get(set(S))': u64 1444 332..336 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64
1414 349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64> 1445 332..339 'get2(y)': i64
1415 349..355 'set(S)': S<u64> 1446 337..338 'y': impl Trait<Type = i64>
1416 353..354 'S': S<u64> 1447 345..348 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type
1417 362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 1448 345..356 'get(set(S))': u64
1418 362..374 'get2(set(S))': u64 1449 349..352 'set': fn set<S<u64>>(S<u64>) -> S<u64>
1419 367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64> 1450 349..355 'set(S)': S<u64>
1420 367..373 'set(S)': S<u64> 1451 353..354 'S': S<u64>
1421 371..372 'S': S<u64> 1452 362..366 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
1422 380..384 'get2': fn get2<str, S<str>>(S<str>) -> str 1453 362..374 'get2(set(S))': u64
1423 380..394 'get2(S::<str>)': str 1454 367..370 'set': fn set<S<u64>>(S<u64>) -> S<u64>
1424 385..393 'S::<str>': S<str> 1455 367..373 'set(S)': S<u64>
1425 "### 1456 371..372 'S': S<u64>
1457 380..384 'get2': fn get2<str, S<str>>(S<str>) -> str
1458 380..394 'get2(S::<str>)': str
1459 385..393 'S::<str>': S<str>
1460 "#]],
1426 ); 1461 );
1427} 1462}
1428 1463
@@ -1470,27 +1505,27 @@ mod iter {
1470 1505
1471#[test] 1506#[test]
1472fn projection_eq_within_chalk() { 1507fn projection_eq_within_chalk() {
1473 assert_snapshot!( 1508 check_infer(
1474 infer(r#" 1509 r#"
1475trait Trait1 { 1510 trait Trait1 {
1476 type Type; 1511 type Type;
1477} 1512 }
1478trait Trait2<T> { 1513 trait Trait2<T> {
1479 fn foo(self) -> T; 1514 fn foo(self) -> T;
1480} 1515 }
1481impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} 1516 impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
1482 1517
1483fn test<T: Trait1<Type = u32>>(x: T) { 1518 fn test<T: Trait1<Type = u32>>(x: T) {
1484 x.foo(); 1519 x.foo();
1485} 1520 }
1486"#), 1521 "#,
1487 @r###" 1522 expect![[r#"
1488 61..65 'self': Self 1523 61..65 'self': Self
1489 163..164 'x': T 1524 163..164 'x': T
1490 169..185 '{ ...o(); }': () 1525 169..185 '{ ...o(); }': ()
1491 175..176 'x': T 1526 175..176 'x': T
1492 175..182 'x.foo()': u32 1527 175..182 'x.foo()': u32
1493 "### 1528 "#]],
1494 ); 1529 );
1495} 1530}
1496 1531
@@ -1513,445 +1548,467 @@ fn test<T: foo::Trait>(x: T) {
1513 1548
1514#[test] 1549#[test]
1515fn super_trait_method_resolution() { 1550fn super_trait_method_resolution() {
1516 assert_snapshot!( 1551 check_infer(
1517 infer(r#" 1552 r#"
1518mod foo { 1553 mod foo {
1519 trait SuperTrait { 1554 trait SuperTrait {
1520 fn foo(&self) -> u32 {} 1555 fn foo(&self) -> u32 {}
1521 } 1556 }
1522} 1557 }
1523trait Trait1: foo::SuperTrait {} 1558 trait Trait1: foo::SuperTrait {}
1524trait Trait2 where Self: foo::SuperTrait {} 1559 trait Trait2 where Self: foo::SuperTrait {}
1525 1560
1526fn test<T: Trait1, U: Trait2>(x: T, y: U) { 1561 fn test<T: Trait1, U: Trait2>(x: T, y: U) {
1527 x.foo(); 1562 x.foo();
1528 y.foo(); 1563 y.foo();
1529} 1564 }
1530"#), 1565 "#,
1531 @r###" 1566 expect![[r#"
1532 49..53 'self': &Self 1567 49..53 'self': &Self
1533 62..64 '{}': () 1568 62..64 '{}': ()
1534 181..182 'x': T 1569 181..182 'x': T
1535 187..188 'y': U 1570 187..188 'y': U
1536 193..222 '{ ...o(); }': () 1571 193..222 '{ ...o(); }': ()
1537 199..200 'x': T 1572 199..200 'x': T
1538 199..206 'x.foo()': u32 1573 199..206 'x.foo()': u32
1539 212..213 'y': U 1574 212..213 'y': U
1540 212..219 'y.foo()': u32 1575 212..219 'y.foo()': u32
1541 "### 1576 "#]],
1542 ); 1577 );
1543} 1578}
1544 1579
1545#[test] 1580#[test]
1546fn super_trait_impl_trait_method_resolution() { 1581fn super_trait_impl_trait_method_resolution() {
1547 assert_snapshot!( 1582 check_infer(
1548 infer(r#" 1583 r#"
1549mod foo { 1584 mod foo {
1550 trait SuperTrait { 1585 trait SuperTrait {
1551 fn foo(&self) -> u32 {} 1586 fn foo(&self) -> u32 {}
1552 } 1587 }
1553} 1588 }
1554trait Trait1: foo::SuperTrait {} 1589 trait Trait1: foo::SuperTrait {}
1555 1590
1556fn test(x: &impl Trait1) { 1591 fn test(x: &impl Trait1) {
1557 x.foo(); 1592 x.foo();
1558} 1593 }
1559"#), 1594 "#,
1560 @r###" 1595 expect![[r#"
1561 49..53 'self': &Self 1596 49..53 'self': &Self
1562 62..64 '{}': () 1597 62..64 '{}': ()
1563 115..116 'x': &impl Trait1 1598 115..116 'x': &impl Trait1
1564 132..148 '{ ...o(); }': () 1599 132..148 '{ ...o(); }': ()
1565 138..139 'x': &impl Trait1 1600 138..139 'x': &impl Trait1
1566 138..145 'x.foo()': u32 1601 138..145 'x.foo()': u32
1567 "### 1602 "#]],
1568 ); 1603 );
1569} 1604}
1570 1605
1571#[test] 1606#[test]
1572fn super_trait_cycle() { 1607fn super_trait_cycle() {
1573 // This just needs to not crash 1608 // This just needs to not crash
1574 assert_snapshot!( 1609 check_infer(
1575 infer(r#" 1610 r#"
1576trait A: B {} 1611 trait A: B {}
1577trait B: A {} 1612 trait B: A {}
1578 1613
1579fn test<T: A>(x: T) { 1614 fn test<T: A>(x: T) {
1580 x.foo(); 1615 x.foo();
1581} 1616 }
1582"#), 1617 "#,
1583 @r###" 1618 expect![[r#"
1584 43..44 'x': T 1619 43..44 'x': T
1585 49..65 '{ ...o(); }': () 1620 49..65 '{ ...o(); }': ()
1586 55..56 'x': T 1621 55..56 'x': T
1587 55..62 'x.foo()': {unknown} 1622 55..62 'x.foo()': {unknown}
1588 "### 1623 "#]],
1589 ); 1624 );
1590} 1625}
1591 1626
1592#[test] 1627#[test]
1593fn super_trait_assoc_type_bounds() { 1628fn super_trait_assoc_type_bounds() {
1594 assert_snapshot!( 1629 check_infer(
1595 infer(r#" 1630 r#"
1596trait SuperTrait { type Type; } 1631 trait SuperTrait { type Type; }
1597trait Trait where Self: SuperTrait {} 1632 trait Trait where Self: SuperTrait {}
1598 1633
1599fn get2<U, T: Trait<Type = U>>(t: T) -> U {} 1634 fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1600fn set<T: Trait<Type = u64>>(t: T) -> T {t} 1635 fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1601 1636
1602struct S<T>; 1637 struct S<T>;
1603impl<T> SuperTrait for S<T> { type Type = T; } 1638 impl<T> SuperTrait for S<T> { type Type = T; }
1604impl<T> Trait for S<T> {} 1639 impl<T> Trait for S<T> {}
1605 1640
1606fn test() { 1641 fn test() {
1607 get2(set(S)); 1642 get2(set(S));
1608} 1643 }
1609"#), 1644 "#,
1610 @r###" 1645 expect![[r#"
1611 102..103 't': T 1646 102..103 't': T
1612 113..115 '{}': () 1647 113..115 '{}': ()
1613 145..146 't': T 1648 145..146 't': T
1614 156..159 '{t}': T 1649 156..159 '{t}': T
1615 157..158 't': T 1650 157..158 't': T
1616 258..279 '{ ...S)); }': () 1651 258..279 '{ ...S)); }': ()
1617 264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64 1652 264..268 'get2': fn get2<u64, S<u64>>(S<u64>) -> u64
1618 264..276 'get2(set(S))': u64 1653 264..276 'get2(set(S))': u64
1619 269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64> 1654 269..272 'set': fn set<S<u64>>(S<u64>) -> S<u64>
1620 269..275 'set(S)': S<u64> 1655 269..275 'set(S)': S<u64>
1621 273..274 'S': S<u64> 1656 273..274 'S': S<u64>
1622 "### 1657 "#]],
1623 ); 1658 );
1624} 1659}
1625 1660
1626#[test] 1661#[test]
1627fn fn_trait() { 1662fn fn_trait() {
1628 assert_snapshot!( 1663 check_infer(
1629 infer(r#" 1664 r#"
1630trait FnOnce<Args> { 1665 trait FnOnce<Args> {
1631 type Output; 1666 type Output;
1632 1667
1633 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output; 1668 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
1634} 1669 }
1635 1670
1636fn test<F: FnOnce(u32, u64) -> u128>(f: F) { 1671 fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1637 f.call_once((1, 2)); 1672 f.call_once((1, 2));
1638} 1673 }
1639"#), 1674 "#,
1640 @r###" 1675 expect![[r#"
1641 56..60 'self': Self 1676 56..60 'self': Self
1642 62..66 'args': Args 1677 62..66 'args': Args
1643 149..150 'f': F 1678 149..150 'f': F
1644 155..183 '{ ...2)); }': () 1679 155..183 '{ ...2)); }': ()
1645 161..162 'f': F 1680 161..162 'f': F
1646 161..180 'f.call...1, 2))': u128 1681 161..180 'f.call...1, 2))': u128
1647 173..179 '(1, 2)': (u32, u64) 1682 173..179 '(1, 2)': (u32, u64)
1648 174..175 '1': u32 1683 174..175 '1': u32
1649 177..178 '2': u64 1684 177..178 '2': u64
1650 "### 1685 "#]],
1651 ); 1686 );
1652} 1687}
1653 1688
1654#[test] 1689#[test]
1655fn fn_ptr_and_item() { 1690fn fn_ptr_and_item() {
1656 assert_snapshot!( 1691 check_infer(
1657 infer(r#" 1692 r#"
1658#[lang="fn_once"] 1693 #[lang="fn_once"]
1659trait FnOnce<Args> { 1694 trait FnOnce<Args> {
1660 type Output; 1695 type Output;
1661 1696
1662 fn call_once(self, args: Args) -> Self::Output; 1697 fn call_once(self, args: Args) -> Self::Output;
1663} 1698 }
1664 1699
1665trait Foo<T> { 1700 trait Foo<T> {
1666 fn foo(&self) -> T; 1701 fn foo(&self) -> T;
1667} 1702 }
1668 1703
1669struct Bar<T>(T); 1704 struct Bar<T>(T);
1670 1705
1671impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> { 1706 impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
1672 fn foo(&self) -> (A1, R) {} 1707 fn foo(&self) -> (A1, R) {}
1673} 1708 }
1674 1709
1675enum Opt<T> { None, Some(T) } 1710 enum Opt<T> { None, Some(T) }
1676impl<T> Opt<T> { 1711 impl<T> Opt<T> {
1677 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {} 1712 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
1678} 1713 }
1679 1714
1680fn test() { 1715 fn test() {
1681 let bar: Bar<fn(u8) -> u32>; 1716 let bar: Bar<fn(u8) -> u32>;
1682 bar.foo(); 1717 bar.foo();
1683 1718
1684 let opt: Opt<u8>; 1719 let opt: Opt<u8>;
1685 let f: fn(u8) -> u32; 1720 let f: fn(u8) -> u32;
1686 opt.map(f); 1721 opt.map(f);
1687} 1722 }
1688"#), 1723 "#,
1689 @r###" 1724 expect![[r#"
1690 74..78 'self': Self 1725 74..78 'self': Self
1691 80..84 'args': Args 1726 80..84 'args': Args
1692 139..143 'self': &Self 1727 139..143 'self': &Self
1693 243..247 'self': &Bar<F> 1728 243..247 'self': &Bar<F>
1694 260..262 '{}': () 1729 260..262 '{}': ()
1695 346..350 'self': Opt<T> 1730 346..350 'self': Opt<T>
1696 352..353 'f': F 1731 352..353 'f': F
1697 368..370 '{}': () 1732 368..370 '{}': ()
1698 384..500 '{ ...(f); }': () 1733 384..500 '{ ...(f); }': ()
1699 394..397 'bar': Bar<fn(u8) -> u32> 1734 394..397 'bar': Bar<fn(u8) -> u32>
1700 423..426 'bar': Bar<fn(u8) -> u32> 1735 423..426 'bar': Bar<fn(u8) -> u32>
1701 423..432 'bar.foo()': (u8, u32) 1736 423..432 'bar.foo()': (u8, u32)
1702 443..446 'opt': Opt<u8> 1737 443..446 'opt': Opt<u8>
1703 465..466 'f': fn(u8) -> u32 1738 465..466 'f': fn(u8) -> u32
1704 487..490 'opt': Opt<u8> 1739 487..490 'opt': Opt<u8>
1705 487..497 'opt.map(f)': Opt<u32> 1740 487..497 'opt.map(f)': Opt<u32>
1706 495..496 'f': fn(u8) -> u32 1741 495..496 'f': fn(u8) -> u32
1707 "### 1742 "#]],
1708 ); 1743 );
1709} 1744}
1710 1745
1711#[test] 1746#[test]
1712fn fn_trait_deref_with_ty_default() { 1747fn fn_trait_deref_with_ty_default() {
1713 assert_snapshot!( 1748 check_infer(
1714 infer(r#" 1749 r#"
1715#[lang = "deref"] 1750 #[lang = "deref"]
1716trait Deref { 1751 trait Deref {
1717 type Target; 1752 type Target;
1718 1753
1719 fn deref(&self) -> &Self::Target; 1754 fn deref(&self) -> &Self::Target;
1720} 1755 }
1721 1756
1722#[lang="fn_once"] 1757 #[lang="fn_once"]
1723trait FnOnce<Args> { 1758 trait FnOnce<Args> {
1724 type Output; 1759 type Output;
1725 1760
1726 fn call_once(self, args: Args) -> Self::Output; 1761 fn call_once(self, args: Args) -> Self::Output;
1727} 1762 }
1728 1763
1729struct Foo; 1764 struct Foo;
1730 1765
1731impl Foo { 1766 impl Foo {
1732 fn foo(&self) -> usize {} 1767 fn foo(&self) -> usize {}
1733} 1768 }
1734 1769
1735struct Lazy<T, F = fn() -> T>(F); 1770 struct Lazy<T, F = fn() -> T>(F);
1736 1771
1737impl<T, F> Lazy<T, F> { 1772 impl<T, F> Lazy<T, F> {
1738 pub fn new(f: F) -> Lazy<T, F> {} 1773 pub fn new(f: F) -> Lazy<T, F> {}
1739} 1774 }
1740 1775
1741impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { 1776 impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
1742 type Target = T; 1777 type Target = T;
1743} 1778 }
1744 1779
1745fn test() { 1780 fn test() {
1746 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo); 1781 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
1747 let r1 = lazy1.foo(); 1782 let r1 = lazy1.foo();
1748 1783
1749 fn make_foo_fn() -> Foo {} 1784 fn make_foo_fn() -> Foo {}
1750 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; 1785 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
1751 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr); 1786 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
1752 let r2 = lazy2.foo(); 1787 let r2 = lazy2.foo();
1753} 1788 }
1754"#), 1789 "#,
1755 @r###" 1790 expect![[r#"
1756 64..68 'self': &Self 1791 64..68 'self': &Self
1757 165..169 'self': Self 1792 165..169 'self': Self
1758 171..175 'args': Args 1793 171..175 'args': Args
1759 239..243 'self': &Foo 1794 239..243 'self': &Foo
1760 254..256 '{}': () 1795 254..256 '{}': ()
1761 334..335 'f': F 1796 334..335 'f': F
1762 354..356 '{}': () 1797 354..356 '{}': ()
1763 443..689 '{ ...o(); }': () 1798 443..689 '{ ...o(); }': ()
1764 453..458 'lazy1': Lazy<Foo, || -> Foo> 1799 453..458 'lazy1': Lazy<Foo, || -> Foo>
1765 475..484 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> 1800 475..484 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
1766 475..492 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> 1801 475..492 'Lazy::...| Foo)': Lazy<Foo, || -> Foo>
1767 485..491 '|| Foo': || -> Foo 1802 485..491 '|| Foo': || -> Foo
1768 488..491 'Foo': Foo 1803 488..491 'Foo': Foo
1769 502..504 'r1': usize 1804 502..504 'r1': usize
1770 507..512 'lazy1': Lazy<Foo, || -> Foo> 1805 507..512 'lazy1': Lazy<Foo, || -> Foo>
1771 507..518 'lazy1.foo()': usize 1806 507..518 'lazy1.foo()': usize
1772 560..575 'make_foo_fn_ptr': fn() -> Foo 1807 560..575 'make_foo_fn_ptr': fn() -> Foo
1773 591..602 'make_foo_fn': fn make_foo_fn() -> Foo 1808 591..602 'make_foo_fn': fn make_foo_fn() -> Foo
1774 612..617 'lazy2': Lazy<Foo, fn() -> Foo> 1809 612..617 'lazy2': Lazy<Foo, fn() -> Foo>
1775 634..643 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> 1810 634..643 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo>
1776 634..660 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> 1811 634..660 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo>
1777 644..659 'make_foo_fn_ptr': fn() -> Foo 1812 644..659 'make_foo_fn_ptr': fn() -> Foo
1778 670..672 'r2': usize 1813 670..672 'r2': usize
1779 675..680 'lazy2': Lazy<Foo, fn() -> Foo> 1814 675..680 'lazy2': Lazy<Foo, fn() -> Foo>
1780 675..686 'lazy2.foo()': usize 1815 675..686 'lazy2.foo()': usize
1781 549..551 '{}': () 1816 549..551 '{}': ()
1782 "### 1817 "#]],
1783 ); 1818 );
1784} 1819}
1785 1820
1786#[test] 1821#[test]
1787fn closure_1() { 1822fn closure_1() {
1788 assert_snapshot!( 1823 check_infer(
1789 infer(r#" 1824 r#"
1790#[lang = "fn_once"] 1825 #[lang = "fn_once"]
1791trait FnOnce<Args> { 1826 trait FnOnce<Args> {
1792 type Output; 1827 type Output;
1793} 1828 }
1794 1829
1795enum Option<T> { Some(T), None } 1830 enum Option<T> { Some(T), None }
1796impl<T> Option<T> { 1831 impl<T> Option<T> {
1797 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {} 1832 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
1798} 1833 }
1799 1834
1800fn test() { 1835 fn test() {
1801 let x = Option::Some(1u32); 1836 let x = Option::Some(1u32);
1802 x.map(|v| v + 1); 1837 x.map(|v| v + 1);
1803 x.map(|_v| 1u64); 1838 x.map(|_v| 1u64);
1804 let y: Option<i64> = x.map(|_v| 1); 1839 let y: Option<i64> = x.map(|_v| 1);
1805} 1840 }
1806"#), 1841 "#,
1807 @r###" 1842 expect![[r#"
1808 147..151 'self': Option<T> 1843 147..151 'self': Option<T>
1809 153..154 'f': F 1844 153..154 'f': F
1810 172..174 '{}': () 1845 172..174 '{}': ()
1811 188..307 '{ ... 1); }': () 1846 188..307 '{ ... 1); }': ()
1812 198..199 'x': Option<u32> 1847 198..199 'x': Option<u32>
1813 202..214 'Option::Some': Some<u32>(u32) -> Option<u32> 1848 202..214 'Option::Some': Some<u32>(u32) -> Option<u32>
1814 202..220 'Option...(1u32)': Option<u32> 1849 202..220 'Option...(1u32)': Option<u32>
1815 215..219 '1u32': u32 1850 215..219 '1u32': u32
1816 226..227 'x': Option<u32> 1851 226..227 'x': Option<u32>
1817 226..242 'x.map(...v + 1)': Option<u32> 1852 226..242 'x.map(...v + 1)': Option<u32>
1818 232..241 '|v| v + 1': |u32| -> u32 1853 232..241 '|v| v + 1': |u32| -> u32
1819 233..234 'v': u32 1854 233..234 'v': u32
1820 236..237 'v': u32 1855 236..237 'v': u32
1821 236..241 'v + 1': u32 1856 236..241 'v + 1': u32
1822 240..241 '1': u32 1857 240..241 '1': u32
1823 248..249 'x': Option<u32> 1858 248..249 'x': Option<u32>
1824 248..264 'x.map(... 1u64)': Option<u64> 1859 248..264 'x.map(... 1u64)': Option<u64>
1825 254..263 '|_v| 1u64': |u32| -> u64 1860 254..263 '|_v| 1u64': |u32| -> u64
1826 255..257 '_v': u32 1861 255..257 '_v': u32
1827 259..263 '1u64': u64 1862 259..263 '1u64': u64
1828 274..275 'y': Option<i64> 1863 274..275 'y': Option<i64>
1829 291..292 'x': Option<u32> 1864 291..292 'x': Option<u32>
1830 291..304 'x.map(|_v| 1)': Option<i64> 1865 291..304 'x.map(|_v| 1)': Option<i64>
1831 297..303 '|_v| 1': |u32| -> i64 1866 297..303 '|_v| 1': |u32| -> i64
1832 298..300 '_v': u32 1867 298..300 '_v': u32
1833 302..303 '1': i64 1868 302..303 '1': i64
1834 "### 1869 "#]],
1835 ); 1870 );
1836} 1871}
1837 1872
1838#[test] 1873#[test]
1839fn closure_2() { 1874fn closure_2() {
1840 assert_snapshot!( 1875 check_infer(
1841 infer(r#" 1876 r#"
1842trait FnOnce<Args> { 1877 trait FnOnce<Args> {
1843 type Output; 1878 type Output;
1844} 1879 }
1845 1880
1846fn test<F: FnOnce(u32) -> u64>(f: F) { 1881 fn test<F: FnOnce(u32) -> u64>(f: F) {
1847 f(1); 1882 f(1);
1848 let g = |v| v + 1; 1883 let g = |v| v + 1;
1849 g(1u64); 1884 g(1u64);
1850 let h = |v| 1u128 + v; 1885 let h = |v| 1u128 + v;
1851} 1886 }
1852"#), 1887 "#,
1853 @r###" 1888 expect![[r#"
1854 72..73 'f': F 1889 72..73 'f': F
1855 78..154 '{ ...+ v; }': () 1890 78..154 '{ ...+ v; }': ()
1856 84..85 'f': F 1891 84..85 'f': F
1857 84..88 'f(1)': {unknown} 1892 84..88 'f(1)': {unknown}
1858 86..87 '1': i32 1893 86..87 '1': i32
1859 98..99 'g': |u64| -> i32 1894 98..99 'g': |u64| -> i32
1860 102..111 '|v| v + 1': |u64| -> i32 1895 102..111 '|v| v + 1': |u64| -> i32
1861 103..104 'v': u64 1896 103..104 'v': u64
1862 106..107 'v': u64 1897 106..107 'v': u64
1863 106..111 'v + 1': i32 1898 106..111 'v + 1': i32
1864 110..111 '1': i32 1899 110..111 '1': i32
1865 117..118 'g': |u64| -> i32 1900 117..118 'g': |u64| -> i32
1866 117..124 'g(1u64)': i32 1901 117..124 'g(1u64)': i32
1867 119..123 '1u64': u64 1902 119..123 '1u64': u64
1868 134..135 'h': |u128| -> u128 1903 134..135 'h': |u128| -> u128
1869 138..151 '|v| 1u128 + v': |u128| -> u128 1904 138..151 '|v| 1u128 + v': |u128| -> u128
1870 139..140 'v': u128 1905 139..140 'v': u128
1871 142..147 '1u128': u128 1906 142..147 '1u128': u128
1872 142..151 '1u128 + v': u128 1907 142..151 '1u128 + v': u128
1873 150..151 'v': u128 1908 150..151 'v': u128
1874 "### 1909 "#]],
1875 ); 1910 );
1876} 1911}
1877 1912
1878#[test] 1913#[test]
1879fn closure_as_argument_inference_order() { 1914fn closure_as_argument_inference_order() {
1880 assert_snapshot!( 1915 check_infer(
1881 infer(r#" 1916 r#"
1917 #[lang = "fn_once"]
1918 trait FnOnce<Args> {
1919 type Output;
1920 }
1921
1922 fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
1923 fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
1924
1925 struct S;
1926 impl S {
1927 fn method(self) -> u64;
1928
1929 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
1930 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
1931 }
1932
1933 fn test() {
1934 let x1 = foo1(S, |s| s.method());
1935 let x2 = foo2(|s| s.method(), S);
1936 let x3 = S.foo1(S, |s| s.method());
1937 let x4 = S.foo2(|s| s.method(), S);
1938 }
1939 "#,
1940 expect![[r#"
1941 94..95 'x': T
1942 100..101 'f': F
1943 111..113 '{}': ()
1944 147..148 'f': F
1945 153..154 'x': T
1946 164..166 '{}': ()
1947 201..205 'self': S
1948 253..257 'self': S
1949 259..260 'x': T
1950 265..266 'f': F
1951 276..278 '{}': ()
1952 316..320 'self': S
1953 322..323 'f': F
1954 328..329 'x': T
1955 339..341 '{}': ()
1956 355..514 '{ ... S); }': ()
1957 365..367 'x1': u64
1958 370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
1959 370..393 'foo1(S...hod())': u64
1960 375..376 'S': S
1961 378..392 '|s| s.method()': |S| -> u64
1962 379..380 's': S
1963 382..383 's': S
1964 382..392 's.method()': u64
1965 403..405 'x2': u64
1966 408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
1967 408..431 'foo2(|...(), S)': u64
1968 413..427 '|s| s.method()': |S| -> u64
1969 414..415 's': S
1970 417..418 's': S
1971 417..427 's.method()': u64
1972 429..430 'S': S
1973 441..443 'x3': u64
1974 446..447 'S': S
1975 446..471 'S.foo1...hod())': u64
1976 453..454 'S': S
1977 456..470 '|s| s.method()': |S| -> u64
1978 457..458 's': S
1979 460..461 's': S
1980 460..470 's.method()': u64
1981 481..483 'x4': u64
1982 486..487 'S': S
1983 486..511 'S.foo2...(), S)': u64
1984 493..507 '|s| s.method()': |S| -> u64
1985 494..495 's': S
1986 497..498 's': S
1987 497..507 's.method()': u64
1988 509..510 'S': S
1989 "#]],
1990 );
1991}
1992
1993#[test]
1994fn fn_item_fn_trait() {
1995 check_types(
1996 r#"
1882#[lang = "fn_once"] 1997#[lang = "fn_once"]
1883trait FnOnce<Args> { 1998trait FnOnce<Args> {
1884 type Output; 1999 type Output;
1885} 2000}
1886 2001
1887fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
1888fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
1889
1890struct S; 2002struct S;
1891impl S {
1892 fn method(self) -> u64;
1893 2003
1894 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {} 2004fn foo() -> S {}
1895 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {} 2005
1896} 2006fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
1897 2007
1898fn test() { 2008fn test() {
1899 let x1 = foo1(S, |s| s.method()); 2009 takes_closure(foo);
1900 let x2 = foo2(|s| s.method(), S); 2010} //^^^^^^^^^^^^^^^^^^ S
1901 let x3 = S.foo1(S, |s| s.method()); 2011"#,
1902 let x4 = S.foo2(|s| s.method(), S);
1903}
1904"#),
1905 @r###"
1906 94..95 'x': T
1907 100..101 'f': F
1908 111..113 '{}': ()
1909 147..148 'f': F
1910 153..154 'x': T
1911 164..166 '{}': ()
1912 201..205 'self': S
1913 253..257 'self': S
1914 259..260 'x': T
1915 265..266 'f': F
1916 276..278 '{}': ()
1917 316..320 'self': S
1918 322..323 'f': F
1919 328..329 'x': T
1920 339..341 '{}': ()
1921 355..514 '{ ... S); }': ()
1922 365..367 'x1': u64
1923 370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
1924 370..393 'foo1(S...hod())': u64
1925 375..376 'S': S
1926 378..392 '|s| s.method()': |S| -> u64
1927 379..380 's': S
1928 382..383 's': S
1929 382..392 's.method()': u64
1930 403..405 'x2': u64
1931 408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
1932 408..431 'foo2(|...(), S)': u64
1933 413..427 '|s| s.method()': |S| -> u64
1934 414..415 's': S
1935 417..418 's': S
1936 417..427 's.method()': u64
1937 429..430 'S': S
1938 441..443 'x3': u64
1939 446..447 'S': S
1940 446..471 'S.foo1...hod())': u64
1941 453..454 'S': S
1942 456..470 '|s| s.method()': |S| -> u64
1943 457..458 's': S
1944 460..461 's': S
1945 460..470 's.method()': u64
1946 481..483 'x4': u64
1947 486..487 'S': S
1948 486..511 'S.foo2...(), S)': u64
1949 493..507 '|s| s.method()': |S| -> u64
1950 494..495 's': S
1951 497..498 's': S
1952 497..507 's.method()': u64
1953 509..510 'S': S
1954 "###
1955 ); 2012 );
1956} 2013}
1957 2014
@@ -1998,43 +2055,44 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1998 2055
1999#[test] 2056#[test]
2000fn unselected_projection_on_impl_self() { 2057fn unselected_projection_on_impl_self() {
2001 assert_snapshot!(infer( 2058 check_infer(
2002 r#" 2059 r#"
2003//- /main.rs 2060 //- /main.rs
2004trait Trait { 2061 trait Trait {
2005 type Item; 2062 type Item;
2006 2063
2007 fn f(&self, x: Self::Item); 2064 fn f(&self, x: Self::Item);
2008} 2065 }
2009 2066
2010struct S; 2067 struct S;
2011 2068
2012impl Trait for S { 2069 impl Trait for S {
2013 type Item = u32; 2070 type Item = u32;
2014 fn f(&self, x: Self::Item) { let y = x; } 2071 fn f(&self, x: Self::Item) { let y = x; }
2015} 2072 }
2016 2073
2017struct S2; 2074 struct S2;
2018 2075
2019impl Trait for S2 { 2076 impl Trait for S2 {
2020 type Item = i32; 2077 type Item = i32;
2021 fn f(&self, x: <Self>::Item) { let y = x; } 2078 fn f(&self, x: <Self>::Item) { let y = x; }
2022} 2079 }
2023"#, 2080 "#,
2024 ), @r###" 2081 expect![[r#"
2025 40..44 'self': &Self 2082 40..44 'self': &Self
2026 46..47 'x': Trait::Item<Self> 2083 46..47 'x': Trait::Item<Self>
2027 126..130 'self': &S 2084 126..130 'self': &S
2028 132..133 'x': u32 2085 132..133 'x': u32
2029 147..161 '{ let y = x; }': () 2086 147..161 '{ let y = x; }': ()
2030 153..154 'y': u32 2087 153..154 'y': u32
2031 157..158 'x': u32 2088 157..158 'x': u32
2032 228..232 'self': &S2 2089 228..232 'self': &S2
2033 234..235 'x': i32 2090 234..235 'x': i32
2034 251..265 '{ let y = x; }': () 2091 251..265 '{ let y = x; }': ()
2035 257..258 'y': i32 2092 257..258 'y': i32
2036 261..262 'x': i32 2093 261..262 'x': i32
2037 "###); 2094 "#]],
2095 );
2038} 2096}
2039 2097
2040#[test] 2098#[test]
@@ -2203,170 +2261,170 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2203 2261
2204#[test] 2262#[test]
2205fn proc_macro_server_types() { 2263fn proc_macro_server_types() {
2206 assert_snapshot!( 2264 check_infer(
2207 infer(r#" 2265 r#"
2208macro_rules! with_api { 2266 macro_rules! with_api {
2209 ($S:ident, $self:ident, $m:ident) => { 2267 ($S:ident, $self:ident, $m:ident) => {
2210 $m! { 2268 $m! {
2211 TokenStream { 2269 TokenStream {
2212 fn new() -> $S::TokenStream; 2270 fn new() -> $S::TokenStream;
2213 }, 2271 },
2214 Group { 2272 Group {
2215 }, 2273 },
2216 } 2274 }
2217 }; 2275 };
2218} 2276 }
2219macro_rules! associated_item { 2277 macro_rules! associated_item {
2220 (type TokenStream) => 2278 (type TokenStream) =>
2221 (type TokenStream: 'static;); 2279 (type TokenStream: 'static;);
2222 (type Group) => 2280 (type Group) =>
2223 (type Group: 'static;); 2281 (type Group: 'static;);
2224 ($($item:tt)*) => ($($item)*;) 2282 ($($item:tt)*) => ($($item)*;)
2225} 2283 }
2226macro_rules! declare_server_traits { 2284 macro_rules! declare_server_traits {
2227 ($($name:ident { 2285 ($($name:ident {
2228 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* 2286 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
2229 }),* $(,)?) => { 2287 }),* $(,)?) => {
2230 pub trait Types { 2288 pub trait Types {
2231 $(associated_item!(type $name);)* 2289 $(associated_item!(type $name);)*
2232 } 2290 }
2233
2234 $(pub trait $name: Types {
2235 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2236 })*
2237
2238 pub trait Server: Types $(+ $name)* {}
2239 impl<S: Types $(+ $name)*> Server for S {}
2240 }
2241}
2242 2291
2243with_api!(Self, self_, declare_server_traits); 2292 $(pub trait $name: Types {
2244struct G {} 2293 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2245struct T {} 2294 })*
2246struct Rustc;
2247impl Types for Rustc {
2248 type TokenStream = T;
2249 type Group = G;
2250}
2251 2295
2252fn make<T>() -> T { loop {} } 2296 pub trait Server: Types $(+ $name)* {}
2253impl TokenStream for Rustc { 2297 impl<S: Types $(+ $name)*> Server for S {}
2254 fn new() -> Self::TokenStream { 2298 }
2255 let group: Self::Group = make(); 2299 }
2256 make() 2300
2257 } 2301 with_api!(Self, self_, declare_server_traits);
2258} 2302 struct G {}
2259"#), 2303 struct T {}
2260 @r###" 2304 struct Rustc;
2261 1061..1072 '{ loop {} }': T 2305 impl Types for Rustc {
2262 1063..1070 'loop {}': ! 2306 type TokenStream = T;
2263 1068..1070 '{}': () 2307 type Group = G;
2264 1136..1199 '{ ... }': T 2308 }
2265 1150..1155 'group': G 2309
2266 1171..1175 'make': fn make<G>() -> G 2310 fn make<T>() -> T { loop {} }
2267 1171..1177 'make()': G 2311 impl TokenStream for Rustc {
2268 1187..1191 'make': fn make<T>() -> T 2312 fn new() -> Self::TokenStream {
2269 1187..1193 'make()': T 2313 let group: Self::Group = make();
2270 "### 2314 make()
2315 }
2316 }
2317 "#,
2318 expect![[r#"
2319 1061..1072 '{ loop {} }': T
2320 1063..1070 'loop {}': !
2321 1068..1070 '{}': ()
2322 1136..1199 '{ ... }': T
2323 1150..1155 'group': G
2324 1171..1175 'make': fn make<G>() -> G
2325 1171..1177 'make()': G
2326 1187..1191 'make': fn make<T>() -> T
2327 1187..1193 'make()': T
2328 "#]],
2271 ); 2329 );
2272} 2330}
2273 2331
2274#[test] 2332#[test]
2275fn unify_impl_trait() { 2333fn unify_impl_trait() {
2276 assert_snapshot!( 2334 check_infer_with_mismatches(
2277 infer_with_mismatches(r#" 2335 r#"
2278trait Trait<T> {} 2336 trait Trait<T> {}
2279 2337
2280fn foo(x: impl Trait<u32>) { loop {} } 2338 fn foo(x: impl Trait<u32>) { loop {} }
2281fn bar<T>(x: impl Trait<T>) -> T { loop {} } 2339 fn bar<T>(x: impl Trait<T>) -> T { loop {} }
2282 2340
2283struct S<T>(T); 2341 struct S<T>(T);
2284impl<T> Trait<T> for S<T> {} 2342 impl<T> Trait<T> for S<T> {}
2285 2343
2286fn default<T>() -> T { loop {} } 2344 fn default<T>() -> T { loop {} }
2287 2345
2288fn test() -> impl Trait<i32> { 2346 fn test() -> impl Trait<i32> {
2289 let s1 = S(default()); 2347 let s1 = S(default());
2290 foo(s1); 2348 foo(s1);
2291 let x: i32 = bar(S(default())); 2349 let x: i32 = bar(S(default()));
2292 S(default()) 2350 S(default())
2293} 2351 }
2294"#, true), 2352 "#,
2295 @r###" 2353 expect![[r#"
2296 26..27 'x': impl Trait<u32> 2354 26..27 'x': impl Trait<u32>
2297 46..57 '{ loop {} }': () 2355 46..57 '{ loop {} }': ()
2298 48..55 'loop {}': ! 2356 48..55 'loop {}': !
2299 53..55 '{}': () 2357 53..55 '{}': ()
2300 68..69 'x': impl Trait<T> 2358 68..69 'x': impl Trait<T>
2301 91..102 '{ loop {} }': T 2359 91..102 '{ loop {} }': T
2302 93..100 'loop {}': ! 2360 93..100 'loop {}': !
2303 98..100 '{}': () 2361 98..100 '{}': ()
2304 171..182 '{ loop {} }': T 2362 171..182 '{ loop {} }': T
2305 173..180 'loop {}': ! 2363 173..180 'loop {}': !
2306 178..180 '{}': () 2364 178..180 '{}': ()
2307 213..309 '{ ...t()) }': S<{unknown}> 2365 213..309 '{ ...t()) }': S<{unknown}>
2308 223..225 's1': S<u32> 2366 223..225 's1': S<u32>
2309 228..229 'S': S<u32>(u32) -> S<u32> 2367 228..229 'S': S<u32>(u32) -> S<u32>
2310 228..240 'S(default())': S<u32> 2368 228..240 'S(default())': S<u32>
2311 230..237 'default': fn default<u32>() -> u32 2369 230..237 'default': fn default<u32>() -> u32
2312 230..239 'default()': u32 2370 230..239 'default()': u32
2313 246..249 'foo': fn foo(S<u32>) 2371 246..249 'foo': fn foo(S<u32>)
2314 246..253 'foo(s1)': () 2372 246..253 'foo(s1)': ()
2315 250..252 's1': S<u32> 2373 250..252 's1': S<u32>
2316 263..264 'x': i32 2374 263..264 'x': i32
2317 272..275 'bar': fn bar<i32>(S<i32>) -> i32 2375 272..275 'bar': fn bar<i32>(S<i32>) -> i32
2318 272..289 'bar(S(...lt()))': i32 2376 272..289 'bar(S(...lt()))': i32
2319 276..277 'S': S<i32>(i32) -> S<i32> 2377 276..277 'S': S<i32>(i32) -> S<i32>
2320 276..288 'S(default())': S<i32> 2378 276..288 'S(default())': S<i32>
2321 278..285 'default': fn default<i32>() -> i32 2379 278..285 'default': fn default<i32>() -> i32
2322 278..287 'default()': i32 2380 278..287 'default()': i32
2323 295..296 'S': S<{unknown}>({unknown}) -> S<{unknown}> 2381 295..296 'S': S<{unknown}>({unknown}) -> S<{unknown}>
2324 295..307 'S(default())': S<{unknown}> 2382 295..307 'S(default())': S<{unknown}>
2325 297..304 'default': fn default<{unknown}>() -> {unknown} 2383 297..304 'default': fn default<{unknown}>() -> {unknown}
2326 297..306 'default()': {unknown} 2384 297..306 'default()': {unknown}
2327 "### 2385 "#]],
2328 ); 2386 );
2329} 2387}
2330 2388
2331#[test] 2389#[test]
2332fn assoc_types_from_bounds() { 2390fn assoc_types_from_bounds() {
2333 assert_snapshot!( 2391 check_infer(
2334 infer(r#" 2392 r#"
2335//- /main.rs 2393 //- /main.rs
2336#[lang = "fn_once"] 2394 #[lang = "fn_once"]
2337trait FnOnce<Args> { 2395 trait FnOnce<Args> {
2338 type Output; 2396 type Output;
2339} 2397 }
2340 2398
2341trait T { 2399 trait T {
2342 type O; 2400 type O;
2343} 2401 }
2344 2402
2345impl T for () { 2403 impl T for () {
2346 type O = (); 2404 type O = ();
2347} 2405 }
2348 2406
2349fn f<X, F>(_v: F) 2407 fn f<X, F>(_v: F)
2350where 2408 where
2351 X: T, 2409 X: T,
2352 F: FnOnce(&X::O), 2410 F: FnOnce(&X::O),
2353{ } 2411 { }
2354 2412
2355fn main() { 2413 fn main() {
2356 f::<(), _>(|z| { z; }); 2414 f::<(), _>(|z| { z; });
2357} 2415 }
2358"#), 2416 "#,
2359 @r###" 2417 expect![[r#"
2360 133..135 '_v': F 2418 133..135 '_v': F
2361 178..181 '{ }': () 2419 178..181 '{ }': ()
2362 193..224 '{ ... }); }': () 2420 193..224 '{ ... }); }': ()
2363 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) 2421 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
2364 199..221 'f::<()... z; })': () 2422 199..221 'f::<()... z; })': ()
2365 210..220 '|z| { z; }': |&()| -> () 2423 210..220 '|z| { z; }': |&()| -> ()
2366 211..212 'z': &() 2424 211..212 'z': &()
2367 214..220 '{ z; }': () 2425 214..220 '{ z; }': ()
2368 216..217 'z': &() 2426 216..217 'z': &()
2369 "### 2427 "#]],
2370 ); 2428 );
2371} 2429}
2372 2430
@@ -2439,120 +2497,120 @@ fn test() {
2439 2497
2440#[test] 2498#[test]
2441fn iterator_chain() { 2499fn iterator_chain() {
2442 assert_snapshot!( 2500 check_infer(
2443 infer(r#" 2501 r#"
2444//- /main.rs 2502 //- /main.rs
2445#[lang = "fn_once"] 2503 #[lang = "fn_once"]
2446trait FnOnce<Args> { 2504 trait FnOnce<Args> {
2447 type Output; 2505 type Output;
2448} 2506 }
2449#[lang = "fn_mut"] 2507 #[lang = "fn_mut"]
2450trait FnMut<Args>: FnOnce<Args> { } 2508 trait FnMut<Args>: FnOnce<Args> { }
2451 2509
2452enum Option<T> { Some(T), None } 2510 enum Option<T> { Some(T), None }
2453use Option::*; 2511 use Option::*;
2454 2512
2455pub trait Iterator { 2513 pub trait Iterator {
2456 type Item; 2514 type Item;
2457 2515
2458 fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> 2516 fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
2459 where 2517 where
2460 F: FnMut(Self::Item) -> Option<B>, 2518 F: FnMut(Self::Item) -> Option<B>,
2461 { loop {} } 2519 { loop {} }
2462 2520
2463 fn for_each<F>(self, f: F) 2521 fn for_each<F>(self, f: F)
2464 where 2522 where
2465 F: FnMut(Self::Item), 2523 F: FnMut(Self::Item),
2466 { loop {} } 2524 { loop {} }
2467} 2525 }
2468 2526
2469pub trait IntoIterator { 2527 pub trait IntoIterator {
2470 type Item; 2528 type Item;
2471 type IntoIter: Iterator<Item = Self::Item>; 2529 type IntoIter: Iterator<Item = Self::Item>;
2472 fn into_iter(self) -> Self::IntoIter; 2530 fn into_iter(self) -> Self::IntoIter;
2473} 2531 }
2474 2532
2475pub struct FilterMap<I, F> { } 2533 pub struct FilterMap<I, F> { }
2476impl<B, I: Iterator, F> Iterator for FilterMap<I, F> 2534 impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
2477where 2535 where
2478 F: FnMut(I::Item) -> Option<B>, 2536 F: FnMut(I::Item) -> Option<B>,
2479{ 2537 {
2480 type Item = B; 2538 type Item = B;
2481} 2539 }
2482 2540
2483#[stable(feature = "rust1", since = "1.0.0")] 2541 #[stable(feature = "rust1", since = "1.0.0")]
2484impl<I: Iterator> IntoIterator for I { 2542 impl<I: Iterator> IntoIterator for I {
2485 type Item = I::Item; 2543 type Item = I::Item;
2486 type IntoIter = I; 2544 type IntoIter = I;
2487 2545
2488 fn into_iter(self) -> I { 2546 fn into_iter(self) -> I {
2489 self 2547 self
2490 } 2548 }
2491} 2549 }
2492 2550
2493struct Vec<T> {} 2551 struct Vec<T> {}
2494impl<T> Vec<T> { 2552 impl<T> Vec<T> {
2495 fn new() -> Self { loop {} } 2553 fn new() -> Self { loop {} }
2496} 2554 }
2497 2555
2498impl<T> IntoIterator for Vec<T> { 2556 impl<T> IntoIterator for Vec<T> {
2499 type Item = T; 2557 type Item = T;
2500 type IntoIter = IntoIter<T>; 2558 type IntoIter = IntoIter<T>;
2501} 2559 }
2502 2560
2503pub struct IntoIter<T> { } 2561 pub struct IntoIter<T> { }
2504impl<T> Iterator for IntoIter<T> { 2562 impl<T> Iterator for IntoIter<T> {
2505 type Item = T; 2563 type Item = T;
2506} 2564 }
2507 2565
2508fn main() { 2566 fn main() {
2509 Vec::<i32>::new().into_iter() 2567 Vec::<i32>::new().into_iter()
2510 .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) 2568 .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
2511 .for_each(|y| { y; }); 2569 .for_each(|y| { y; });
2512} 2570 }
2513"#), 2571 "#,
2514 @r###" 2572 expect![[r#"
2515 226..230 'self': Self 2573 226..230 'self': Self
2516 232..233 'f': F 2574 232..233 'f': F
2517 317..328 '{ loop {} }': FilterMap<Self, F> 2575 317..328 '{ loop {} }': FilterMap<Self, F>
2518 319..326 'loop {}': ! 2576 319..326 'loop {}': !
2519 324..326 '{}': () 2577 324..326 '{}': ()
2520 349..353 'self': Self 2578 349..353 'self': Self
2521 355..356 'f': F 2579 355..356 'f': F
2522 405..416 '{ loop {} }': () 2580 405..416 '{ loop {} }': ()
2523 407..414 'loop {}': ! 2581 407..414 'loop {}': !
2524 412..414 '{}': () 2582 412..414 '{}': ()
2525 525..529 'self': Self 2583 525..529 'self': Self
2526 854..858 'self': I 2584 854..858 'self': I
2527 865..885 '{ ... }': I 2585 865..885 '{ ... }': I
2528 875..879 'self': I 2586 875..879 'self': I
2529 944..955 '{ loop {} }': Vec<T> 2587 944..955 '{ loop {} }': Vec<T>
2530 946..953 'loop {}': ! 2588 946..953 'loop {}': !
2531 951..953 '{}': () 2589 951..953 '{}': ()
2532 1142..1273 '{ ... }); }': () 2590 1142..1269 '{ ... }); }': ()
2533 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> 2591 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
2534 1148..1165 'Vec::<...:new()': Vec<i32> 2592 1148..1165 'Vec::<...:new()': Vec<i32>
2535 1148..1177 'Vec::<...iter()': IntoIter<i32> 2593 1148..1177 'Vec::<...iter()': IntoIter<i32>
2536 1148..1242 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> 2594 1148..1240 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
2537 1148..1270 'Vec::<... y; })': () 2595 1148..1266 'Vec::<... y; })': ()
2538 1196..1241 '|x| if...None }': |i32| -> Option<u32> 2596 1194..1239 '|x| if...None }': |i32| -> Option<u32>
2539 1197..1198 'x': i32 2597 1195..1196 'x': i32
2540 1200..1241 'if x >...None }': Option<u32> 2598 1198..1239 'if x >...None }': Option<u32>
2541 1203..1204 'x': i32 2599 1201..1202 'x': i32
2542 1203..1208 'x > 0': bool 2600 1201..1206 'x > 0': bool
2543 1207..1208 '0': i32 2601 1205..1206 '0': i32
2544 1209..1227 '{ Some...u32) }': Option<u32> 2602 1207..1225 '{ Some...u32) }': Option<u32>
2545 1211..1215 'Some': Some<u32>(u32) -> Option<u32> 2603 1209..1213 'Some': Some<u32>(u32) -> Option<u32>
2546 1211..1225 'Some(x as u32)': Option<u32> 2604 1209..1223 'Some(x as u32)': Option<u32>
2547 1216..1217 'x': i32 2605 1214..1215 'x': i32
2548 1216..1224 'x as u32': u32 2606 1214..1222 'x as u32': u32
2549 1233..1241 '{ None }': Option<u32> 2607 1231..1239 '{ None }': Option<u32>
2550 1235..1239 'None': Option<u32> 2608 1233..1237 'None': Option<u32>
2551 1259..1269 '|y| { y; }': |u32| -> () 2609 1255..1265 '|y| { y; }': |u32| -> ()
2552 1260..1261 'y': u32 2610 1256..1257 'y': u32
2553 1263..1269 '{ y; }': () 2611 1259..1265 '{ y; }': ()
2554 1265..1266 'y': u32 2612 1261..1262 'y': u32
2555 "### 2613 "#]],
2556 ); 2614 );
2557} 2615}
2558 2616
@@ -2590,176 +2648,176 @@ fn main() {
2590 2648
2591#[test] 2649#[test]
2592fn trait_object_no_coercion() { 2650fn trait_object_no_coercion() {
2593 assert_snapshot!( 2651 check_infer_with_mismatches(
2594 infer_with_mismatches(r#" 2652 r#"
2595trait Foo {} 2653 trait Foo {}
2596 2654
2597fn foo(x: &dyn Foo) {} 2655 fn foo(x: &dyn Foo) {}
2598 2656
2599fn test(x: &dyn Foo) { 2657 fn test(x: &dyn Foo) {
2600 foo(x); 2658 foo(x);
2601} 2659 }
2602"#, true), 2660 "#,
2603 @r###" 2661 expect![[r#"
2604 21..22 'x': &dyn Foo 2662 21..22 'x': &dyn Foo
2605 34..36 '{}': () 2663 34..36 '{}': ()
2606 46..47 'x': &dyn Foo 2664 46..47 'x': &dyn Foo
2607 59..74 '{ foo(x); }': () 2665 59..74 '{ foo(x); }': ()
2608 65..68 'foo': fn foo(&dyn Foo) 2666 65..68 'foo': fn foo(&dyn Foo)
2609 65..71 'foo(x)': () 2667 65..71 'foo(x)': ()
2610 69..70 'x': &dyn Foo 2668 69..70 'x': &dyn Foo
2611 "### 2669 "#]],
2612 ); 2670 );
2613} 2671}
2614 2672
2615#[test] 2673#[test]
2616fn builtin_copy() { 2674fn builtin_copy() {
2617 assert_snapshot!( 2675 check_infer_with_mismatches(
2618 infer_with_mismatches(r#" 2676 r#"
2619#[lang = "copy"] 2677 #[lang = "copy"]
2620trait Copy {} 2678 trait Copy {}
2621 2679
2622struct IsCopy; 2680 struct IsCopy;
2623impl Copy for IsCopy {} 2681 impl Copy for IsCopy {}
2624struct NotCopy; 2682 struct NotCopy;
2625 2683
2626trait Test { fn test(&self) -> bool; } 2684 trait Test { fn test(&self) -> bool; }
2627impl<T: Copy> Test for T {} 2685 impl<T: Copy> Test for T {}
2628 2686
2629fn test() { 2687 fn test() {
2630 IsCopy.test(); 2688 IsCopy.test();
2631 NotCopy.test(); 2689 NotCopy.test();
2632 (IsCopy, IsCopy).test(); 2690 (IsCopy, IsCopy).test();
2633 (IsCopy, NotCopy).test(); 2691 (IsCopy, NotCopy).test();
2634} 2692 }
2635"#, true), 2693 "#,
2636 @r###" 2694 expect![[r#"
2637 110..114 'self': &Self 2695 110..114 'self': &Self
2638 166..267 '{ ...t(); }': () 2696 166..267 '{ ...t(); }': ()
2639 172..178 'IsCopy': IsCopy 2697 172..178 'IsCopy': IsCopy
2640 172..185 'IsCopy.test()': bool 2698 172..185 'IsCopy.test()': bool
2641 191..198 'NotCopy': NotCopy 2699 191..198 'NotCopy': NotCopy
2642 191..205 'NotCopy.test()': {unknown} 2700 191..205 'NotCopy.test()': {unknown}
2643 211..227 '(IsCop...sCopy)': (IsCopy, IsCopy) 2701 211..227 '(IsCop...sCopy)': (IsCopy, IsCopy)
2644 211..234 '(IsCop...test()': bool 2702 211..234 '(IsCop...test()': bool
2645 212..218 'IsCopy': IsCopy 2703 212..218 'IsCopy': IsCopy
2646 220..226 'IsCopy': IsCopy 2704 220..226 'IsCopy': IsCopy
2647 240..257 '(IsCop...tCopy)': (IsCopy, NotCopy) 2705 240..257 '(IsCop...tCopy)': (IsCopy, NotCopy)
2648 240..264 '(IsCop...test()': {unknown} 2706 240..264 '(IsCop...test()': {unknown}
2649 241..247 'IsCopy': IsCopy 2707 241..247 'IsCopy': IsCopy
2650 249..256 'NotCopy': NotCopy 2708 249..256 'NotCopy': NotCopy
2651 "### 2709 "#]],
2652 ); 2710 );
2653} 2711}
2654 2712
2655#[test] 2713#[test]
2656fn builtin_fn_def_copy() { 2714fn builtin_fn_def_copy() {
2657 assert_snapshot!( 2715 check_infer_with_mismatches(
2658 infer_with_mismatches(r#" 2716 r#"
2659#[lang = "copy"] 2717 #[lang = "copy"]
2660trait Copy {} 2718 trait Copy {}
2661 2719
2662fn foo() {} 2720 fn foo() {}
2663fn bar<T: Copy>(T) -> T {} 2721 fn bar<T: Copy>(T) -> T {}
2664struct Struct(usize); 2722 struct Struct(usize);
2665enum Enum { Variant(usize) } 2723 enum Enum { Variant(usize) }
2666 2724
2667trait Test { fn test(&self) -> bool; } 2725 trait Test { fn test(&self) -> bool; }
2668impl<T: Copy> Test for T {} 2726 impl<T: Copy> Test for T {}
2669 2727
2670fn test() { 2728 fn test() {
2671 foo.test(); 2729 foo.test();
2672 bar.test(); 2730 bar.test();
2673 Struct.test(); 2731 Struct.test();
2674 Enum::Variant.test(); 2732 Enum::Variant.test();
2675} 2733 }
2676"#, true), 2734 "#,
2677 @r###" 2735 expect![[r#"
2678 41..43 '{}': () 2736 41..43 '{}': ()
2679 60..61 'T': {unknown} 2737 60..61 'T': {unknown}
2680 68..70 '{}': () 2738 68..70 '{}': ()
2681 68..70: expected T, got () 2739 68..70: expected T, got ()
2682 145..149 'self': &Self 2740 145..149 'self': &Self
2683 201..281 '{ ...t(); }': () 2741 201..281 '{ ...t(); }': ()
2684 207..210 'foo': fn foo() 2742 207..210 'foo': fn foo()
2685 207..217 'foo.test()': bool 2743 207..217 'foo.test()': bool
2686 223..226 'bar': fn bar<{unknown}>({unknown}) -> {unknown} 2744 223..226 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
2687 223..233 'bar.test()': bool 2745 223..233 'bar.test()': bool
2688 239..245 'Struct': Struct(usize) -> Struct 2746 239..245 'Struct': Struct(usize) -> Struct
2689 239..252 'Struct.test()': bool 2747 239..252 'Struct.test()': bool
2690 258..271 'Enum::Variant': Variant(usize) -> Enum 2748 258..271 'Enum::Variant': Variant(usize) -> Enum
2691 258..278 'Enum::...test()': bool 2749 258..278 'Enum::...test()': bool
2692 "### 2750 "#]],
2693 ); 2751 );
2694} 2752}
2695 2753
2696#[test] 2754#[test]
2697fn builtin_fn_ptr_copy() { 2755fn builtin_fn_ptr_copy() {
2698 assert_snapshot!( 2756 check_infer_with_mismatches(
2699 infer_with_mismatches(r#" 2757 r#"
2700#[lang = "copy"] 2758 #[lang = "copy"]
2701trait Copy {} 2759 trait Copy {}
2702 2760
2703trait Test { fn test(&self) -> bool; } 2761 trait Test { fn test(&self) -> bool; }
2704impl<T: Copy> Test for T {} 2762 impl<T: Copy> Test for T {}
2705 2763
2706fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { 2764 fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2707 f1.test(); 2765 f1.test();
2708 f2.test(); 2766 f2.test();
2709 f3.test(); 2767 f3.test();
2710} 2768 }
2711"#, true), 2769 "#,
2712 @r###" 2770 expect![[r#"
2713 54..58 'self': &Self 2771 54..58 'self': &Self
2714 108..110 'f1': fn() 2772 108..110 'f1': fn()
2715 118..120 'f2': fn(usize) -> u8 2773 118..120 'f2': fn(usize) -> u8
2716 139..141 'f3': fn(u8, u8) -> &u8 2774 139..141 'f3': fn(u8, u8) -> &u8
2717 162..210 '{ ...t(); }': () 2775 162..210 '{ ...t(); }': ()
2718 168..170 'f1': fn() 2776 168..170 'f1': fn()
2719 168..177 'f1.test()': bool 2777 168..177 'f1.test()': bool
2720 183..185 'f2': fn(usize) -> u8 2778 183..185 'f2': fn(usize) -> u8
2721 183..192 'f2.test()': bool 2779 183..192 'f2.test()': bool
2722 198..200 'f3': fn(u8, u8) -> &u8 2780 198..200 'f3': fn(u8, u8) -> &u8
2723 198..207 'f3.test()': bool 2781 198..207 'f3.test()': bool
2724 "### 2782 "#]],
2725 ); 2783 );
2726} 2784}
2727 2785
2728#[test] 2786#[test]
2729fn builtin_sized() { 2787fn builtin_sized() {
2730 assert_snapshot!( 2788 check_infer_with_mismatches(
2731 infer_with_mismatches(r#" 2789 r#"
2732#[lang = "sized"] 2790 #[lang = "sized"]
2733trait Sized {} 2791 trait Sized {}
2734 2792
2735trait Test { fn test(&self) -> bool; } 2793 trait Test { fn test(&self) -> bool; }
2736impl<T: Sized> Test for T {} 2794 impl<T: Sized> Test for T {}
2737 2795
2738fn test() { 2796 fn test() {
2739 1u8.test(); 2797 1u8.test();
2740 (*"foo").test(); // not Sized 2798 (*"foo").test(); // not Sized
2741 (1u8, 1u8).test(); 2799 (1u8, 1u8).test();
2742 (1u8, *"foo").test(); // not Sized 2800 (1u8, *"foo").test(); // not Sized
2743} 2801 }
2744"#, true), 2802 "#,
2745 @r###" 2803 expect![[r#"
2746 56..60 'self': &Self 2804 56..60 'self': &Self
2747 113..228 '{ ...ized }': () 2805 113..228 '{ ...ized }': ()
2748 119..122 '1u8': u8 2806 119..122 '1u8': u8
2749 119..129 '1u8.test()': bool 2807 119..129 '1u8.test()': bool
2750 135..150 '(*"foo").test()': {unknown} 2808 135..150 '(*"foo").test()': {unknown}
2751 136..142 '*"foo"': str 2809 136..142 '*"foo"': str
2752 137..142 '"foo"': &str 2810 137..142 '"foo"': &str
2753 169..179 '(1u8, 1u8)': (u8, u8) 2811 169..179 '(1u8, 1u8)': (u8, u8)
2754 169..186 '(1u8, ...test()': bool 2812 169..186 '(1u8, ...test()': bool
2755 170..173 '1u8': u8 2813 170..173 '1u8': u8
2756 175..178 '1u8': u8 2814 175..178 '1u8': u8
2757 192..205 '(1u8, *"foo")': (u8, str) 2815 192..205 '(1u8, *"foo")': (u8, str)
2758 192..212 '(1u8, ...test()': {unknown} 2816 192..212 '(1u8, ...test()': {unknown}
2759 193..196 '1u8': u8 2817 193..196 '1u8': u8
2760 198..204 '*"foo"': str 2818 198..204 '*"foo"': str
2761 199..204 '"foo"': &str 2819 199..204 '"foo"': &str
2762 "### 2820 "#]],
2763 ); 2821 );
2764} 2822}
2765 2823
@@ -2809,223 +2867,247 @@ impl<A: Step> iter::Iterator for ops::Range<A> {
2809 2867
2810#[test] 2868#[test]
2811fn infer_closure_arg() { 2869fn infer_closure_arg() {
2812 assert_snapshot!( 2870 check_infer(
2813 infer( 2871 r#"
2814 r#" 2872 //- /lib.rs
2815 //- /lib.rs
2816
2817 enum Option<T> {
2818 None,
2819 Some(T)
2820 }
2821 2873
2822 fn foo() { 2874 enum Option<T> {
2823 let s = Option::None; 2875 None,
2824 let f = |x: Option<i32>| {}; 2876 Some(T)
2825 (&f)(s) 2877 }
2826 } 2878
2827 "# 2879 fn foo() {
2828 ), 2880 let s = Option::None;
2829 @r###" 2881 let f = |x: Option<i32>| {};
2830 52..126 '{ ...)(s) }': () 2882 (&f)(s)
2831 62..63 's': Option<i32> 2883 }
2832 66..78 'Option::None': Option<i32> 2884 "#,
2833 88..89 'f': |Option<i32>| -> () 2885 expect![[r#"
2834 92..111 '|x: Op...2>| {}': |Option<i32>| -> () 2886 52..126 '{ ...)(s) }': ()
2835 93..94 'x': Option<i32> 2887 62..63 's': Option<i32>
2836 109..111 '{}': () 2888 66..78 'Option::None': Option<i32>
2837 117..124 '(&f)(s)': () 2889 88..89 'f': |Option<i32>| -> ()
2838 118..120 '&f': &|Option<i32>| -> () 2890 92..111 '|x: Op...2>| {}': |Option<i32>| -> ()
2839 119..120 'f': |Option<i32>| -> () 2891 93..94 'x': Option<i32>
2840 122..123 's': Option<i32> 2892 109..111 '{}': ()
2841 "### 2893 117..124 '(&f)(s)': ()
2894 118..120 '&f': &|Option<i32>| -> ()
2895 119..120 'f': |Option<i32>| -> ()
2896 122..123 's': Option<i32>
2897 "#]],
2842 ); 2898 );
2843} 2899}
2844 2900
2845#[test] 2901#[test]
2846fn infer_fn_trait_arg() { 2902fn infer_fn_trait_arg() {
2847 assert_snapshot!( 2903 check_infer(
2848 infer( 2904 r#"
2849 r#" 2905 //- /lib.rs deps:std
2850 //- /lib.rs deps:std
2851 2906
2852 #[lang = "fn_once"] 2907 #[lang = "fn_once"]
2853 pub trait FnOnce<Args> { 2908 pub trait FnOnce<Args> {
2854 type Output; 2909 type Output;
2855 2910
2856 extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; 2911 extern "rust-call" fn call_once(&self, args: Args) -> Self::Output;
2857 } 2912 }
2858 2913
2859 #[lang = "fn"] 2914 #[lang = "fn"]
2860 pub trait Fn<Args>:FnOnce<Args> { 2915 pub trait Fn<Args>:FnOnce<Args> {
2861 extern "rust-call" fn call(&self, args: Args) -> Self::Output; 2916 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
2862 } 2917 }
2863 2918
2864 enum Option<T> { 2919 enum Option<T> {
2865 None, 2920 None,
2866 Some(T) 2921 Some(T)
2867 } 2922 }
2868 2923
2869 fn foo<F, T>(f: F) -> T 2924 fn foo<F, T>(f: F) -> T
2870 where 2925 where
2871 F: Fn(Option<i32>) -> T, 2926 F: Fn(Option<i32>) -> T,
2872 { 2927 {
2873 let s = None; 2928 let s = None;
2874 f(s) 2929 f(s)
2875 } 2930 }
2876 "# 2931 "#,
2877 ), 2932 expect![[r#"
2878 @r###" 2933 101..105 'self': &Self
2879 101..105 'self': &Self 2934 107..111 'args': Args
2880 107..111 'args': Args 2935 220..224 'self': &Self
2881 220..224 'self': &Self 2936 226..230 'args': Args
2882 226..230 'args': Args 2937 313..314 'f': F
2883 313..314 'f': F 2938 359..389 '{ ...f(s) }': T
2884 359..389 '{ ...f(s) }': T 2939 369..370 's': Option<i32>
2885 369..370 's': Option<i32> 2940 373..377 'None': Option<i32>
2886 373..377 'None': Option<i32> 2941 383..384 'f': F
2887 383..384 'f': F 2942 383..387 'f(s)': T
2888 383..387 'f(s)': T 2943 385..386 's': Option<i32>
2889 385..386 's': Option<i32> 2944 "#]],
2890 "###
2891 ); 2945 );
2892} 2946}
2893 2947
2894#[test] 2948#[test]
2895fn infer_box_fn_arg() { 2949fn infer_box_fn_arg() {
2896 assert_snapshot!( 2950 check_infer(
2897 infer( 2951 r#"
2898 r#" 2952 //- /lib.rs deps:std
2899 //- /lib.rs deps:std
2900 2953
2901 #[lang = "fn_once"] 2954 #[lang = "fn_once"]
2902 pub trait FnOnce<Args> { 2955 pub trait FnOnce<Args> {
2903 type Output; 2956 type Output;
2904 2957
2905 extern "rust-call" fn call_once(self, args: Args) -> Self::Output; 2958 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
2906 } 2959 }
2907 2960
2908 #[lang = "deref"] 2961 #[lang = "deref"]
2909 pub trait Deref { 2962 pub trait Deref {
2910 type Target: ?Sized; 2963 type Target: ?Sized;
2911 2964
2912 fn deref(&self) -> &Self::Target; 2965 fn deref(&self) -> &Self::Target;
2913 } 2966 }
2914 2967
2915 #[lang = "owned_box"] 2968 #[lang = "owned_box"]
2916 pub struct Box<T: ?Sized> { 2969 pub struct Box<T: ?Sized> {
2917 inner: *mut T, 2970 inner: *mut T,
2918 } 2971 }
2919 2972
2920 impl<T: ?Sized> Deref for Box<T> { 2973 impl<T: ?Sized> Deref for Box<T> {
2921 type Target = T; 2974 type Target = T;
2922 2975
2923 fn deref(&self) -> &T { 2976 fn deref(&self) -> &T {
2924 &self.inner 2977 &self.inner
2925 }
2926 } 2978 }
2979 }
2927 2980
2928 enum Option<T> { 2981 enum Option<T> {
2929 None, 2982 None,
2930 Some(T) 2983 Some(T)
2931 } 2984 }
2932 2985
2933 fn foo() { 2986 fn foo() {
2934 let s = Option::None; 2987 let s = Option::None;
2935 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); 2988 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
2936 f(&s) 2989 f(&s)
2937 } 2990 }
2938 "# 2991 "#,
2939 ), 2992 expect![[r#"
2940 @r###" 2993 100..104 'self': Self
2941 100..104 'self': Self 2994 106..110 'args': Args
2942 106..110 'args': Args 2995 214..218 'self': &Self
2943 214..218 'self': &Self 2996 384..388 'self': &Box<T>
2944 384..388 'self': &Box<T> 2997 396..423 '{ ... }': &T
2945 396..423 '{ ... }': &T 2998 406..417 '&self.inner': &*mut T
2946 406..417 '&self.inner': &*mut T 2999 407..411 'self': &Box<T>
2947 407..411 'self': &Box<T> 3000 407..417 'self.inner': *mut T
2948 407..417 'self.inner': *mut T 3001 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)>
2949 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> 3002 488..489 's': Option<i32>
2950 488..489 's': Option<i32> 3003 492..504 'Option::None': Option<i32>
2951 492..504 'Option::None': Option<i32> 3004 514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>>
2952 514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>> 3005 549..562 'box (|ps| {})': Box<|{unknown}| -> ()>
2953 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> 3006 554..561 '|ps| {}': |{unknown}| -> ()
2954 554..561 '|ps| {}': |{unknown}| -> () 3007 555..557 'ps': {unknown}
2955 555..557 'ps': {unknown} 3008 559..561 '{}': ()
2956 559..561 '{}': () 3009 568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>>
2957 568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>> 3010 568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)>
2958 568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> 3011 570..572 '&s': &Option<i32>
2959 570..572 '&s': &Option<i32> 3012 571..572 's': Option<i32>
2960 571..572 's': Option<i32> 3013 "#]],
2961 "###
2962 ); 3014 );
2963} 3015}
2964 3016
2965#[test] 3017#[test]
2966fn infer_dyn_fn_output() { 3018fn infer_dyn_fn_output() {
2967 assert_snapshot!( 3019 check_types(
2968 infer( 3020 r#"
2969 r#" 3021#[lang = "fn_once"]
2970 //- /lib.rs deps:std 3022pub trait FnOnce<Args> {
3023 type Output;
3024 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3025}
2971 3026
2972 #[lang = "fn_once"] 3027#[lang = "fn"]
2973 pub trait FnOnce<Args> { 3028pub trait Fn<Args>: FnOnce<Args> {
2974 type Output; 3029 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
3030}
2975 3031
2976 extern "rust-call" fn call_once(self, args: Args) -> Self::Output; 3032fn foo() {
2977 } 3033 let f: &dyn Fn() -> i32;
3034 f();
3035 //^^^ i32
3036}"#,
3037 );
3038}
2978 3039
2979 #[lang = "fn"] 3040#[test]
2980 pub trait Fn<Args>:FnOnce<Args> { 3041fn infer_dyn_fn_once_output() {
2981 extern "rust-call" fn call(&self, args: Args) -> Self::Output; 3042 check_types(
2982 } 3043 r#"
3044#[lang = "fn_once"]
3045pub trait FnOnce<Args> {
3046 type Output;
3047 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3048}
2983 3049
2984 #[lang = "deref"] 3050fn foo() {
2985 pub trait Deref { 3051 let f: dyn FnOnce() -> i32;
2986 type Target: ?Sized; 3052 f();
3053 //^^^ i32
3054}"#,
3055 );
3056}
2987 3057
2988 fn deref(&self) -> &Self::Target; 3058#[test]
2989 } 3059fn variable_kinds_1() {
3060 check_types(
3061 r#"
3062trait Trait<T> { fn get(self, t: T) -> T; }
3063struct S;
3064impl Trait<u128> for S {}
3065impl Trait<f32> for S {}
3066fn test() {
3067 S.get(1);
3068 //^^^^^^^^ u128
3069 S.get(1.);
3070 //^^^^^^^^ f32
3071}
3072 "#,
3073 );
3074}
2990 3075
2991 #[lang = "owned_box"] 3076#[test]
2992 pub struct Box<T: ?Sized> { 3077fn variable_kinds_2() {
2993 inner: *mut T, 3078 check_types(
2994 } 3079 r#"
3080trait Trait { fn get(self) -> Self; }
3081impl Trait for u128 {}
3082impl Trait for f32 {}
3083fn test() {
3084 1.get();
3085 //^^^^^^^ u128
3086 (1.).get();
3087 //^^^^^^^^^^ f32
3088}
3089 "#,
3090 );
3091}
2995 3092
2996 impl<T: ?Sized> Deref for Box<T> { 3093#[test]
2997 type Target = T; 3094fn underscore_import() {
3095 check_types(
3096 r#"
3097mod tr {
3098 pub trait Tr {
3099 fn method(&self) -> u8 { 0 }
3100 }
3101}
2998 3102
2999 fn deref(&self) -> &T { 3103struct Tr;
3000 &self.inner 3104impl crate::tr::Tr for Tr {}
3001 }
3002 }
3003 3105
3004 fn foo() { 3106use crate::tr::Tr as _;
3005 let f: Box<dyn Fn() -> i32> = box(|| 5); 3107fn test() {
3006 let x = f(); 3108 Tr.method();
3007 } 3109 //^^^^^^^^^^^ u8
3008 "# 3110}
3009 ), 3111 "#,
3010 @r###"
3011 100..104 'self': Self
3012 106..110 'args': Args
3013 219..223 'self': &Self
3014 225..229 'args': Args
3015 333..337 'self': &Self
3016 503..507 'self': &Box<T>
3017 515..542 '{ ... }': &T
3018 525..536 '&self.inner': &*mut T
3019 526..530 'self': &Box<T>
3020 526..536 'self.inner': *mut T
3021 555..620 '{ ...f(); }': ()
3022 565..566 'f': Box<dyn Fn<(), Output = i32>>
3023 591..600 'box(|| 5)': Box<|| -> i32>
3024 595..599 '|| 5': || -> i32
3025 598..599 '5': i32
3026 610..611 'x': FnOnce::Output<dyn Fn<(), Output = i32>, ()>
3027 614..615 'f': Box<dyn Fn<(), Output = i32>>
3028 614..617 'f()': FnOnce::Output<dyn Fn<(), Output = i32>, ()>
3029 "###
3030 ); 3112 );
3031} 3113}
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 6f43c3a22..3f6d2cf35 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,21 +1,19 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::{panic, sync::Arc}; 2use std::sync::Arc;
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
5use hir_def::{ 5use chalk_solve::Solver;
6 expr::ExprId, lang_item::LangItemTarget, DefWithBodyId, ImplId, TraitId, TypeAliasId, 6use hir_def::{lang_item::LangItemTarget, TraitId};
7}; 7use ra_db::CrateId;
8use ra_db::{impl_intern_key, salsa, CrateId};
9use ra_prof::profile; 8use ra_prof::profile;
10 9
11use crate::{db::HirDatabase, DebruijnIndex}; 10use crate::{db::HirDatabase, DebruijnIndex, Substs};
12 11
13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
14 13
15use self::chalk::{from_chalk, Interner, ToChalk}; 14use self::chalk::{from_chalk, Interner, ToChalk};
16 15
17pub(crate) mod chalk; 16pub(crate) mod chalk;
18mod builtin;
19 17
20// This controls the maximum size of types Chalk considers. If we set this too 18// This controls the maximum size of types Chalk considers. If we set this too
21// high, we can run into slow edge cases; if we set it too low, Chalk won't 19// high, we can run into slow edge cases; if we set it too low, Chalk won't
@@ -32,9 +30,10 @@ struct ChalkContext<'a> {
32 krate: CrateId, 30 krate: CrateId,
33} 31}
34 32
35fn create_chalk_solver() -> chalk_solve::Solver<Interner> { 33fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
36 let solver_choice = chalk_solve::SolverChoice::recursive(); 34 let overflow_depth = 100;
37 solver_choice.into_solver() 35 let caching_enabled = true;
36 chalk_recursive::RecursiveSolver::new(overflow_depth, caching_enabled)
38} 37}
39 38
40/// A set of clauses that we assume to be true. E.g. if we are inside this function: 39/// A set of clauses that we assume to be true. E.g. if we are inside this function:
@@ -190,15 +189,7 @@ fn solution_from_chalk(
190 solution: chalk_solve::Solution<Interner>, 189 solution: chalk_solve::Solution<Interner>,
191) -> Solution { 190) -> Solution {
192 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { 191 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
193 let value = subst 192 let result = from_chalk(db, subst);
194 .value
195 .iter(&Interner)
196 .map(|p| match p.ty(&Interner) {
197 Some(ty) => from_chalk(db, ty.clone()),
198 None => unimplemented!(),
199 })
200 .collect();
201 let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
202 SolutionVariables(result) 193 SolutionVariables(result)
203 }; 194 };
204 match solution { 195 match solution {
@@ -222,7 +213,7 @@ fn solution_from_chalk(
222} 213}
223 214
224#[derive(Clone, Debug, PartialEq, Eq)] 215#[derive(Clone, Debug, PartialEq, Eq)]
225pub struct SolutionVariables(pub Canonical<Vec<Ty>>); 216pub struct SolutionVariables(pub Canonical<Substs>);
226 217
227#[derive(Clone, Debug, PartialEq, Eq)] 218#[derive(Clone, Debug, PartialEq, Eq)]
228/// A (possible) solution for a proposed goal. 219/// A (possible) solution for a proposed goal.
@@ -280,52 +271,3 @@ impl FnTrait {
280 } 271 }
281 } 272 }
282} 273}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
285pub struct ClosureFnTraitImplData {
286 def: DefWithBodyId,
287 expr: ExprId,
288 fn_trait: FnTrait,
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
292pub struct UnsizeToSuperTraitObjectData {
293 trait_: TraitId,
294 super_trait: TraitId,
295}
296
297/// An impl. Usually this comes from an impl block, but some built-in types get
298/// synthetic impls.
299#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
300pub enum Impl {
301 /// A normal impl from an impl block.
302 ImplDef(ImplId),
303 /// Closure types implement the Fn traits synthetically.
304 ClosureFnTraitImpl(ClosureFnTraitImplData),
305 /// [T; n]: Unsize<[T]>
306 UnsizeArray,
307 /// T: Unsize<dyn Trait> where T: Trait
308 UnsizeToTraitObject(TraitId),
309 /// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait
310 UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData),
311}
312/// This exists just for Chalk, because our ImplIds are only unique per module.
313#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
314pub struct GlobalImplId(salsa::InternId);
315impl_intern_key!(GlobalImplId);
316
317/// An associated type value. Usually this comes from a `type` declaration
318/// inside an impl block, but for built-in impls we have to synthesize it.
319/// (We only need this because Chalk wants a unique ID for each of these.)
320#[derive(Debug, Clone, PartialEq, Eq, Hash)]
321pub enum AssocTyValue {
322 /// A normal assoc type value from an impl block.
323 TypeAlias(TypeAliasId),
324 /// The output type of the Fn trait implementation.
325 ClosureFnTraitImplOutput(ClosureFnTraitImplData),
326}
327/// This exists just for Chalk, because it needs a unique ID for each associated
328/// type value in an impl (even synthetic ones).
329#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
330pub struct AssocTyValueId(salsa::InternId);
331impl_intern_key!(AssocTyValueId);
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
deleted file mode 100644
index 6d5f2d46a..000000000
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ /dev/null
@@ -1,371 +0,0 @@
1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name::name;
5use ra_db::CrateId;
6
7use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
8use crate::{
9 db::HirDatabase,
10 utils::{all_super_traits, generics},
11 ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
12 TypeCtor, TypeWalk,
13};
14
15pub(super) struct BuiltinImplData {
16 pub num_vars: usize,
17 pub trait_ref: TraitRef,
18 pub where_clauses: Vec<super::GenericPredicate>,
19 pub assoc_ty_values: Vec<AssocTyValue>,
20}
21
22pub(super) struct BuiltinImplAssocTyValueData {
23 pub impl_: Impl,
24 pub assoc_ty_id: TypeAliasId,
25 pub num_vars: usize,
26 pub value: Ty,
27}
28
29pub(super) fn get_builtin_impls(
30 db: &dyn HirDatabase,
31 krate: CrateId,
32 ty: &Ty,
33 // The first argument for the trait, if present
34 arg: &Option<Ty>,
35 trait_: TraitId,
36 mut callback: impl FnMut(Impl),
37) {
38 // Note: since impl_datum needs to be infallible, we need to make sure here
39 // that we have all prerequisites to build the respective impls.
40 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
41 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
42 {
43 if let Some(actual_trait) = fn_trait.get_id(db, krate) {
44 if trait_ == actual_trait {
45 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait };
46 if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) {
47 callback(Impl::ClosureFnTraitImpl(impl_));
48 }
49 }
50 }
51 }
52 }
53
54 let unsize_trait = get_unsize_trait(db, krate);
55 if let Some(actual_trait) = unsize_trait {
56 if trait_ == actual_trait {
57 get_builtin_unsize_impls(db, krate, ty, arg, callback);
58 }
59 }
60}
61
62fn get_builtin_unsize_impls(
63 db: &dyn HirDatabase,
64 krate: CrateId,
65 ty: &Ty,
66 // The first argument for the trait, if present
67 arg: &Option<Ty>,
68 mut callback: impl FnMut(Impl),
69) {
70 if !check_unsize_impl_prerequisites(db, krate) {
71 return;
72 }
73
74 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty {
75 callback(Impl::UnsizeArray);
76 return; // array is unsized, the rest of the impls shouldn't apply
77 }
78
79 if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) {
80 // FIXME what about more complicated dyn tys with marker traits?
81 if let Some(trait_ref) = ty.dyn_trait_ref() {
82 if trait_ref.trait_ != target_trait.trait_ {
83 let super_traits = all_super_traits(db.upcast(), trait_ref.trait_);
84 if super_traits.contains(&target_trait.trait_) {
85 callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData {
86 trait_: trait_ref.trait_,
87 super_trait: target_trait.trait_,
88 }));
89 }
90 }
91 } else {
92 // FIXME only for sized types
93 callback(Impl::UnsizeToTraitObject(target_trait.trait_));
94 }
95 }
96}
97
98pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
99 match impl_ {
100 Impl::ImplDef(_) => unreachable!(),
101 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
102 Impl::UnsizeArray => array_unsize_impl_datum(db, krate),
103 Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_),
104 Impl::UnsizeToSuperTraitObject(data) => {
105 super_trait_object_unsize_impl_datum(db, krate, data)
106 }
107 }
108}
109
110pub(super) fn associated_ty_value(
111 db: &dyn HirDatabase,
112 krate: CrateId,
113 data: AssocTyValue,
114) -> BuiltinImplAssocTyValueData {
115 match data {
116 AssocTyValue::TypeAlias(_) => unreachable!(),
117 AssocTyValue::ClosureFnTraitImplOutput(data) => {
118 closure_fn_trait_output_assoc_ty_value(db, krate, data)
119 }
120 }
121}
122
123// Closure Fn trait impls
124
125fn check_closure_fn_trait_impl_prerequisites(
126 db: &dyn HirDatabase,
127 krate: CrateId,
128 data: super::ClosureFnTraitImplData,
129) -> bool {
130 // the respective Fn/FnOnce/FnMut trait needs to exist
131 if data.fn_trait.get_id(db, krate).is_none() {
132 return false;
133 }
134
135 // FIXME: there are more assumptions that we should probably check here:
136 // the traits having no type params, FnOnce being a supertrait
137
138 // the FnOnce trait needs to exist and have an assoc type named Output
139 let fn_once_trait = match (super::FnTrait::FnOnce).get_id(db, krate) {
140 Some(t) => t,
141 None => return false,
142 };
143 db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some()
144}
145
146fn closure_fn_trait_impl_datum(
147 db: &dyn HirDatabase,
148 krate: CrateId,
149 data: super::ClosureFnTraitImplData,
150) -> BuiltinImplData {
151 // for some closure |X, Y| -> Z:
152 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
153
154 let trait_ = data
155 .fn_trait
156 .get_id(db, krate) // get corresponding fn trait
157 // the existence of the Fn trait has been checked before
158 .expect("fn trait for closure impl missing");
159
160 let num_args: u16 = match &db.body(data.def)[data.expr] {
161 Expr::Lambda { args, .. } => args.len() as u16,
162 _ => {
163 log::warn!("closure for closure type {:?} not found", data);
164 0
165 }
166 };
167
168 let arg_ty = Ty::apply(
169 TypeCtor::Tuple { cardinality: num_args },
170 Substs::builder(num_args as usize)
171 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
172 .build(),
173 );
174 let sig_ty = Ty::apply(
175 TypeCtor::FnPtr { num_args },
176 Substs::builder(num_args as usize + 1)
177 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
178 .build(),
179 );
180
181 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
182
183 let trait_ref = TraitRef {
184 trait_,
185 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
186 };
187
188 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data);
189
190 BuiltinImplData {
191 num_vars: num_args as usize + 1,
192 trait_ref,
193 where_clauses: Vec::new(),
194 assoc_ty_values: vec![output_ty_id],
195 }
196}
197
198fn closure_fn_trait_output_assoc_ty_value(
199 db: &dyn HirDatabase,
200 krate: CrateId,
201 data: super::ClosureFnTraitImplData,
202) -> BuiltinImplAssocTyValueData {
203 let impl_ = Impl::ClosureFnTraitImpl(data);
204
205 let num_args: u16 = match &db.body(data.def)[data.expr] {
206 Expr::Lambda { args, .. } => args.len() as u16,
207 _ => {
208 log::warn!("closure for closure type {:?} not found", data);
209 0
210 }
211 };
212
213 let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into()));
214
215 let fn_once_trait =
216 (super::FnTrait::FnOnce).get_id(db, krate).expect("assoc ty value should not exist");
217
218 let output_ty_id = db
219 .trait_data(fn_once_trait)
220 .associated_type_by_name(&name![Output])
221 .expect("assoc ty value should not exist");
222
223 BuiltinImplAssocTyValueData {
224 impl_,
225 assoc_ty_id: output_ty_id,
226 num_vars: num_args as usize + 1,
227 value: output_ty,
228 }
229}
230
231// Array unsizing
232
233fn check_unsize_impl_prerequisites(db: &dyn HirDatabase, krate: CrateId) -> bool {
234 // the Unsize trait needs to exist and have two type parameters (Self and T)
235 let unsize_trait = match get_unsize_trait(db, krate) {
236 Some(t) => t,
237 None => return false,
238 };
239 let generic_params = generics(db.upcast(), unsize_trait.into());
240 generic_params.len() == 2
241}
242
243fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplData {
244 // impl<T> Unsize<[T]> for [T; _]
245 // (this can be a single impl because we don't distinguish array sizes currently)
246
247 let trait_ = get_unsize_trait(db, krate) // get unsize trait
248 // the existence of the Unsize trait has been checked before
249 .expect("Unsize trait missing");
250
251 let var = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
252 let substs = Substs::builder(2)
253 .push(Ty::apply_one(TypeCtor::Array, var.clone()))
254 .push(Ty::apply_one(TypeCtor::Slice, var))
255 .build();
256
257 let trait_ref = TraitRef { trait_, substs };
258
259 BuiltinImplData {
260 num_vars: 1,
261 trait_ref,
262 where_clauses: Vec::new(),
263 assoc_ty_values: Vec::new(),
264 }
265}
266
267// Trait object unsizing
268
269fn trait_object_unsize_impl_datum(
270 db: &dyn HirDatabase,
271 krate: CrateId,
272 trait_: TraitId,
273) -> BuiltinImplData {
274 // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
275
276 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
277 // the existence of the Unsize trait has been checked before
278 .expect("Unsize trait missing");
279
280 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
281
282 let target_substs = Substs::build_for_def(db, trait_)
283 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
284 .fill_with_bound_vars(DebruijnIndex::ONE, 1)
285 .build();
286 let num_vars = target_substs.len();
287 let target_trait_ref = TraitRef { trait_, substs: target_substs };
288 let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
289
290 let self_substs =
291 Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
292 let self_trait_ref = TraitRef { trait_, substs: self_substs };
293 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
294
295 let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
296
297 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
298
299 BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
300}
301
302fn super_trait_object_unsize_impl_datum(
303 db: &dyn HirDatabase,
304 krate: CrateId,
305 data: UnsizeToSuperTraitObjectData,
306) -> BuiltinImplData {
307 // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
308
309 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
310 // the existence of the Unsize trait has been checked before
311 .expect("Unsize trait missing");
312
313 let self_substs = Substs::build_for_def(db, data.trait_)
314 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
315 .build();
316 let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
317
318 let num_vars = self_substs.len() - 1;
319
320 // we need to go from our trait to the super trait, substituting type parameters
321 let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
322
323 let mut current_trait_ref = self_trait_ref.clone();
324 for t in path.into_iter().skip(1) {
325 let bounds = db.generic_predicates(current_trait_ref.trait_.into());
326 let super_trait_ref = bounds
327 .iter()
328 .find_map(|b| match &b.value {
329 GenericPredicate::Implemented(tr)
330 if tr.trait_ == t
331 && tr.substs[0]
332 == Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)) =>
333 {
334 Some(Binders { value: tr, num_binders: b.num_binders })
335 }
336 _ => None,
337 })
338 .expect("trait bound for known super trait not found");
339 current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs);
340 }
341
342 // We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
343 // to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
344 // from the dyn Trait binder, while the other variables come from the impl.
345 let new_substs = Substs::builder(num_vars + 1)
346 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
347 .fill_with_bound_vars(DebruijnIndex::ONE, 0)
348 .build();
349
350 let self_bounds =
351 vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
352 let super_bounds =
353 vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
354
355 let substs = Substs::builder(2)
356 .push(Ty::Dyn(self_bounds.into()))
357 .push(Ty::Dyn(super_bounds.into()))
358 .build();
359
360 let trait_ref = TraitRef { trait_: unsize_trait, substs };
361
362 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
363}
364
365fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
366 let target = db.lang_item(krate, "unsize".into())?;
367 match target {
368 LangItemTarget::TraitId(t) => Some(t),
369 _ => None,
370 }
371}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 8ef4941c0..1c7065364 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3 3
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; 6use chalk_ir::{fold::shift::Shift, CanonicalVarKinds, GenericArg, TypeName};
7use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; 7use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
8 8
9use hir_def::{ 9use hir_def::{
@@ -12,12 +12,17 @@ use hir_def::{
12}; 12};
13use ra_db::{salsa::InternKey, CrateId}; 13use ra_db::{salsa::InternKey, CrateId};
14 14
15use super::{builtin, AssocTyValue, ChalkContext, Impl}; 15use super::ChalkContext;
16use crate::{ 16use crate::{
17 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, 17 db::HirDatabase,
18 CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, 18 display::HirDisplay,
19 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
20 utils::generics,
21 CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor,
22};
23use mapping::{
24 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
19}; 25};
20use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
21 26
22pub use self::interner::*; 27pub use self::interner::*;
23 28
@@ -49,7 +54,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
49 self.db.struct_datum(self.krate, struct_id) 54 self.db.struct_datum(self.krate, struct_id)
50 } 55 }
51 fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr { 56 fn adt_repr(&self, _struct_id: AdtId) -> rust_ir::AdtRepr {
52 unreachable!() 57 rust_ir::AdtRepr { repr_c: false, repr_packed: false }
53 } 58 }
54 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { 59 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
55 self.db.impl_datum(self.krate, impl_id) 60 self.db.impl_datum(self.krate, impl_id)
@@ -66,45 +71,58 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
66 &self, 71 &self,
67 trait_id: TraitId, 72 trait_id: TraitId,
68 parameters: &[GenericArg<Interner>], 73 parameters: &[GenericArg<Interner>],
74 binders: &CanonicalVarKinds<Interner>,
69 ) -> Vec<ImplId> { 75 ) -> Vec<ImplId> {
70 debug!("impls_for_trait {:?}", trait_id); 76 debug!("impls_for_trait {:?}", trait_id);
71 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 77 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
72 78
73 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); 79 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
74 80
81 fn binder_kind(ty: &Ty, binders: &CanonicalVarKinds<Interner>) -> Option<chalk_ir::TyKind> {
82 if let Ty::Bound(bv) = ty {
83 let binders = binders.as_slice(&Interner);
84 if bv.debruijn == DebruijnIndex::INNERMOST {
85 if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
86 return Some(tk);
87 }
88 }
89 }
90 None
91 }
92
75 let self_ty_fp = TyFingerprint::for_impl(&ty); 93 let self_ty_fp = TyFingerprint::for_impl(&ty);
94 let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
95 Some(chalk_ir::TyKind::Integer) => &ALL_INT_FPS,
96 Some(chalk_ir::TyKind::Float) => &ALL_FLOAT_FPS,
97 _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
98 };
76 99
77 // Note: Since we're using impls_for_trait, only impls where the trait 100 // Note: Since we're using impls_for_trait, only impls where the trait
78 // can be resolved should ever reach Chalk. `impl_datum` relies on that 101 // can be resolved should ever reach Chalk. `impl_datum` relies on that
79 // and will panic if the trait can't be resolved. 102 // and will panic if the trait can't be resolved.
80 let in_deps = self.db.impls_from_deps(self.krate); 103 let in_deps = self.db.trait_impls_in_deps(self.krate);
81 let in_self = self.db.impls_in_crate(self.krate); 104 let in_self = self.db.trait_impls_in_crate(self.krate);
82 let impl_maps = [in_deps, in_self]; 105 let impl_maps = [in_deps, in_self];
83 106
84 let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db); 107 let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
85 108
86 let mut result: Vec<_> = match self_ty_fp { 109 let result: Vec<_> = if fps.is_empty() {
87 Some(fp) => impl_maps 110 debug!("Unrestricted search for {:?} impls...", trait_);
111 impl_maps
88 .iter() 112 .iter()
89 .flat_map(|crate_impl_defs| { 113 .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
90 crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk) 114 .collect()
91 }) 115 } else {
92 .collect(), 116 impl_maps
93 None => impl_maps
94 .iter() 117 .iter()
95 .flat_map(|crate_impl_defs| { 118 .flat_map(|crate_impl_defs| {
96 crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk) 119 fps.iter().flat_map(move |fp| {
120 crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
121 })
97 }) 122 })
98 .collect(), 123 .collect()
99 }; 124 };
100 125
101 let arg: Option<Ty> =
102 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone()));
103
104 builtin::get_builtin_impls(self.db, self.krate, &ty, &arg, trait_, |i| {
105 result.push(i.to_chalk(self.db))
106 });
107
108 debug!("impls_for_trait returned {} impls", result.len()); 126 debug!("impls_for_trait returned {} impls", result.len());
109 result 127 result
110 } 128 }
@@ -165,6 +183,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
165 .collect(), 183 .collect(),
166 1, 184 1,
167 ), 185 ),
186 where_clauses: make_binders(vec![], 0),
168 }; 187 };
169 let num_vars = datas.num_binders; 188 let num_vars = datas.num_binders;
170 Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) 189 Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) })
@@ -175,15 +194,6 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
175 Ty::Unknown.to_chalk(self.db) 194 Ty::Unknown.to_chalk(self.db)
176 } 195 }
177 196
178 fn force_impl_for(
179 &self,
180 _well_known: rust_ir::WellKnownTrait,
181 _ty: &chalk_ir::TyData<Interner>,
182 ) -> Option<bool> {
183 // this method is mostly for rustc
184 None
185 }
186
187 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { 197 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
188 // FIXME: implement actual object safety 198 // FIXME: implement actual object safety
189 true 199 true
@@ -194,31 +204,55 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
194 _closure_id: chalk_ir::ClosureId<Interner>, 204 _closure_id: chalk_ir::ClosureId<Interner>,
195 _substs: &chalk_ir::Substitution<Interner>, 205 _substs: &chalk_ir::Substitution<Interner>,
196 ) -> rust_ir::ClosureKind { 206 ) -> rust_ir::ClosureKind {
197 // FIXME: implement closure support 207 // Fn is the closure kind that implements all three traits
198 unimplemented!() 208 rust_ir::ClosureKind::Fn
199 } 209 }
200 fn closure_inputs_and_output( 210 fn closure_inputs_and_output(
201 &self, 211 &self,
202 _closure_id: chalk_ir::ClosureId<Interner>, 212 _closure_id: chalk_ir::ClosureId<Interner>,
203 _substs: &chalk_ir::Substitution<Interner>, 213 substs: &chalk_ir::Substitution<Interner>,
204 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { 214 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
205 // FIXME: implement closure support 215 let sig_ty: Ty =
206 unimplemented!() 216 from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
217 let sig = FnSig::from_fn_ptr_substs(
218 &sig_ty.substs().expect("first closure param should be fn ptr"),
219 false,
220 );
221 let io = rust_ir::FnDefInputsAndOutputDatum {
222 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(),
223 return_type: sig.ret().clone().to_chalk(self.db),
224 };
225 make_binders(io.shifted_in(&Interner), 0)
207 } 226 }
208 fn closure_upvars( 227 fn closure_upvars(
209 &self, 228 &self,
210 _closure_id: chalk_ir::ClosureId<Interner>, 229 _closure_id: chalk_ir::ClosureId<Interner>,
211 _substs: &chalk_ir::Substitution<Interner>, 230 _substs: &chalk_ir::Substitution<Interner>,
212 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { 231 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
213 // FIXME: implement closure support 232 let ty = Ty::unit().to_chalk(self.db);
214 unimplemented!() 233 make_binders(ty, 0)
215 } 234 }
216 fn closure_fn_substitution( 235 fn closure_fn_substitution(
217 &self, 236 &self,
218 _closure_id: chalk_ir::ClosureId<Interner>, 237 _closure_id: chalk_ir::ClosureId<Interner>,
219 _substs: &chalk_ir::Substitution<Interner>, 238 _substs: &chalk_ir::Substitution<Interner>,
220 ) -> chalk_ir::Substitution<Interner> { 239 ) -> chalk_ir::Substitution<Interner> {
221 // FIXME: implement closure support 240 Substs::empty().to_chalk(self.db)
241 }
242
243 fn trait_name(&self, _trait_id: chalk_ir::TraitId<Interner>) -> String {
244 unimplemented!()
245 }
246 fn adt_name(&self, _struct_id: chalk_ir::AdtId<Interner>) -> String {
247 unimplemented!()
248 }
249 fn assoc_type_name(&self, _assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
250 unimplemented!()
251 }
252 fn opaque_type_name(&self, _opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
253 unimplemented!()
254 }
255 fn fn_def_name(&self, _fn_def_id: chalk_ir::FnDefId<Interner>) -> String {
222 unimplemented!() 256 unimplemented!()
223 } 257 }
224} 258}
@@ -356,12 +390,18 @@ pub(crate) fn struct_datum_query(
356 fundamental: false, 390 fundamental: false,
357 phantom_data: false, 391 phantom_data: false,
358 }; 392 };
359 let struct_datum_bound = rust_ir::AdtDatumBound { 393 // FIXME provide enum variants properly (for auto traits)
360 fields: Vec::new(), // FIXME add fields (only relevant for auto traits) 394 let variant = rust_ir::AdtVariantDatum {
361 where_clauses, 395 fields: Vec::new(), // FIXME add fields (only relevant for auto traits),
396 };
397 let struct_datum_bound = rust_ir::AdtDatumBound { variants: vec![variant], where_clauses };
398 let struct_datum = StructDatum {
399 // FIXME set ADT kind
400 kind: rust_ir::AdtKind::Struct,
401 id: struct_id,
402 binders: make_binders(struct_datum_bound, num_params),
403 flags,
362 }; 404 };
363 let struct_datum =
364 StructDatum { id: struct_id, binders: make_binders(struct_datum_bound, num_params), flags };
365 Arc::new(struct_datum) 405 Arc::new(struct_datum)
366} 406}
367 407
@@ -372,11 +412,8 @@ pub(crate) fn impl_datum_query(
372) -> Arc<ImplDatum> { 412) -> Arc<ImplDatum> {
373 let _p = ra_prof::profile("impl_datum"); 413 let _p = ra_prof::profile("impl_datum");
374 debug!("impl_datum {:?}", impl_id); 414 debug!("impl_datum {:?}", impl_id);
375 let impl_: Impl = from_chalk(db, impl_id); 415 let impl_: hir_def::ImplId = from_chalk(db, impl_id);
376 match impl_ { 416 impl_def_datum(db, krate, impl_id, impl_)
377 Impl::ImplDef(impl_def) => impl_def_datum(db, krate, impl_id, impl_def),
378 _ => Arc::new(builtin::impl_datum(db, krate, impl_).to_chalk(db)),
379 }
380} 417}
381 418
382fn impl_def_datum( 419fn impl_def_datum(
@@ -427,7 +464,7 @@ fn impl_def_datum(
427 let name = &db.type_alias_data(type_alias).name; 464 let name = &db.type_alias_data(type_alias).name;
428 trait_data.associated_type_by_name(name).is_some() 465 trait_data.associated_type_by_name(name).is_some()
429 }) 466 })
430 .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db)) 467 .map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db))
431 .collect(); 468 .collect();
432 debug!("impl_datum: {:?}", impl_datum_bound); 469 debug!("impl_datum: {:?}", impl_datum_bound);
433 let impl_datum = ImplDatum { 470 let impl_datum = ImplDatum {
@@ -444,13 +481,8 @@ pub(crate) fn associated_ty_value_query(
444 krate: CrateId, 481 krate: CrateId,
445 id: AssociatedTyValueId, 482 id: AssociatedTyValueId,
446) -> Arc<AssociatedTyValue> { 483) -> Arc<AssociatedTyValue> {
447 let data: AssocTyValue = from_chalk(db, id); 484 let type_alias: TypeAliasAsValue = from_chalk(db, id);
448 match data { 485 type_alias_associated_ty_value(db, krate, type_alias.0)
449 AssocTyValue::TypeAlias(type_alias) => {
450 type_alias_associated_ty_value(db, krate, type_alias)
451 }
452 _ => Arc::new(builtin::associated_ty_value(db, krate, data).to_chalk(db)),
453 }
454} 486}
455 487
456fn type_alias_associated_ty_value( 488fn type_alias_associated_ty_value(
@@ -473,7 +505,7 @@ fn type_alias_associated_ty_value(
473 let ty = db.ty(type_alias.into()); 505 let ty = db.ty(type_alias.into());
474 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; 506 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) };
475 let value = rust_ir::AssociatedTyValue { 507 let value = rust_ir::AssociatedTyValue {
476 impl_id: Impl::ImplDef(impl_id).to_chalk(db), 508 impl_id: impl_id.to_chalk(db),
477 associated_ty_id: assoc_ty.to_chalk(db), 509 associated_ty_id: assoc_ty.to_chalk(db),
478 value: make_binders(value_bound, ty.num_binders), 510 value: make_binders(value_bound, ty.num_binders),
479 }; 511 };
@@ -485,7 +517,7 @@ pub(crate) fn fn_def_datum_query(
485 _krate: CrateId, 517 _krate: CrateId,
486 fn_def_id: FnDefId, 518 fn_def_id: FnDefId,
487) -> Arc<FnDefDatum> { 519) -> Arc<FnDefDatum> {
488 let callable_def: CallableDef = from_chalk(db, fn_def_id); 520 let callable_def: CallableDefId = from_chalk(db, fn_def_id);
489 let generic_params = generics(db.upcast(), callable_def.into()); 521 let generic_params = generics(db.upcast(), callable_def.into());
490 let sig = db.callable_item_signature(callable_def); 522 let sig = db.callable_item_signature(callable_def);
491 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 523 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
@@ -507,47 +539,28 @@ pub(crate) fn fn_def_datum_query(
507 ), 539 ),
508 where_clauses, 540 where_clauses,
509 }; 541 };
510 let datum = 542 let datum = FnDefDatum {
511 FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders), abi: () }; 543 id: fn_def_id,
544 abi: (),
545 safety: chalk_ir::Safety::Safe,
546 variadic: sig.value.is_varargs,
547 binders: make_binders(bound, sig.num_binders),
548 };
512 Arc::new(datum) 549 Arc::new(datum)
513} 550}
514 551
515impl From<AdtId> for crate::TypeCtorId { 552impl From<FnDefId> for crate::db::InternedCallableDefId {
516 fn from(struct_id: AdtId) -> Self {
517 struct_id.0
518 }
519}
520
521impl From<crate::TypeCtorId> for AdtId {
522 fn from(type_ctor_id: crate::TypeCtorId) -> Self {
523 chalk_ir::AdtId(type_ctor_id)
524 }
525}
526
527impl From<FnDefId> for crate::CallableDefId {
528 fn from(fn_def_id: FnDefId) -> Self { 553 fn from(fn_def_id: FnDefId) -> Self {
529 InternKey::from_intern_id(fn_def_id.0) 554 InternKey::from_intern_id(fn_def_id.0)
530 } 555 }
531} 556}
532 557
533impl From<crate::CallableDefId> for FnDefId { 558impl From<crate::db::InternedCallableDefId> for FnDefId {
534 fn from(callable_def_id: crate::CallableDefId) -> Self { 559 fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self {
535 chalk_ir::FnDefId(callable_def_id.as_intern_id()) 560 chalk_ir::FnDefId(callable_def_id.as_intern_id())
536 } 561 }
537} 562}
538 563
539impl From<ImplId> for crate::traits::GlobalImplId {
540 fn from(impl_id: ImplId) -> Self {
541 InternKey::from_intern_id(impl_id.0)
542 }
543}
544
545impl From<crate::traits::GlobalImplId> for ImplId {
546 fn from(impl_id: crate::traits::GlobalImplId) -> Self {
547 chalk_ir::ImplId(impl_id.as_intern_id())
548 }
549}
550
551impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId { 564impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
552 fn from(id: OpaqueTyId) -> Self { 565 fn from(id: OpaqueTyId) -> Self {
553 InternKey::from_intern_id(id.0) 566 InternKey::from_intern_id(id.0)
@@ -560,14 +573,14 @@ impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
560 } 573 }
561} 574}
562 575
563impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { 576impl From<chalk_ir::ClosureId<Interner>> for crate::db::ClosureId {
564 fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self { 577 fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
565 Self::from_intern_id(id.0) 578 Self::from_intern_id(id.0)
566 } 579 }
567} 580}
568 581
569impl From<crate::traits::AssocTyValueId> for rust_ir::AssociatedTyValueId<Interner> { 582impl From<crate::db::ClosureId> for chalk_ir::ClosureId<Interner> {
570 fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { 583 fn from(id: crate::db::ClosureId) -> Self {
571 rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) 584 chalk_ir::ClosureId(id.as_intern_id())
572 } 585 }
573} 586}
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs
index 15426b022..8d4c51a8f 100644
--- a/crates/ra_hir_ty/src/traits/chalk/interner.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs
@@ -39,8 +39,9 @@ impl chalk_ir::interner::Interner for Interner {
39 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; 39 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
40 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; 40 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
41 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; 41 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
42 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
42 type DefId = InternId; 43 type DefId = InternId;
43 type InternedAdtId = crate::TypeCtorId; 44 type InternedAdtId = hir_def::AdtId;
44 type Identifier = TypeAliasId; 45 type Identifier = TypeAliasId;
45 type FnAbi = (); 46 type FnAbi = ();
46 47
@@ -349,6 +350,32 @@ impl chalk_ir::interner::Interner for Interner {
349 ) -> &'a [chalk_ir::CanonicalVarKind<Self>] { 350 ) -> &'a [chalk_ir::CanonicalVarKind<Self>] {
350 &canonical_var_kinds 351 &canonical_var_kinds
351 } 352 }
353
354 fn intern_constraints<E>(
355 &self,
356 data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>,
357 ) -> Result<Self::InternedConstraints, E> {
358 data.into_iter().collect()
359 }
360
361 fn constraints_data<'a>(
362 &self,
363 constraints: &'a Self::InternedConstraints,
364 ) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
365 constraints
366 }
367 fn debug_closure_id(
368 _fn_def_id: chalk_ir::ClosureId<Self>,
369 _fmt: &mut fmt::Formatter<'_>,
370 ) -> Option<fmt::Result> {
371 None
372 }
373 fn debug_constraints(
374 _clauses: &chalk_ir::Constraints<Self>,
375 _fmt: &mut fmt::Formatter<'_>,
376 ) -> Option<fmt::Result> {
377 None
378 }
352} 379}
353 380
354impl chalk_ir::interner::HasInterner for Interner { 381impl chalk_ir::interner::HasInterner for Interner {
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index ac82ea831..b3e92993d 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -15,9 +15,9 @@ use ra_db::salsa::InternKey;
15use crate::{ 15use crate::{
16 db::HirDatabase, 16 db::HirDatabase,
17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, 17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, 18 traits::{Canonical, Obligation},
19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, 19 ApplicationTy, CallableDefId, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
21}; 21};
22 22
23use super::interner::*; 23use super::interner::*;
@@ -29,10 +29,17 @@ impl ToChalk for Ty {
29 match self { 29 match self {
30 Ty::Apply(apply_ty) => match apply_ty.ctor { 30 Ty::Apply(apply_ty) => match apply_ty.ctor {
31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), 31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
32 TypeCtor::FnPtr { num_args: _ } => { 32 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
33 TypeCtor::FnPtr { num_args: _, is_varargs } => {
33 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); 34 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
34 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) 35 chalk_ir::TyData::Function(chalk_ir::FnPointer {
35 .intern(&Interner) 36 num_binders: 0,
37 abi: (),
38 safety: chalk_ir::Safety::Safe,
39 variadic: is_varargs,
40 substitution,
41 })
42 .intern(&Interner)
36 } 43 }
37 _ => { 44 _ => {
38 let name = apply_ty.ctor.to_chalk(db); 45 let name = apply_ty.ctor.to_chalk(db);
@@ -61,13 +68,13 @@ impl ToChalk for Ty {
61 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), 68 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
62 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 69 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
63 Ty::Dyn(predicates) => { 70 Ty::Dyn(predicates) => {
64 let where_clauses = chalk_ir::QuantifiedWhereClauses::from( 71 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
65 &Interner, 72 &Interner,
66 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), 73 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)),
67 ); 74 );
68 let bounded_ty = chalk_ir::DynTy { 75 let bounded_ty = chalk_ir::DynTy {
69 bounds: make_binders(where_clauses, 1), 76 bounds: make_binders(where_clauses, 1),
70 lifetime: LIFETIME_PLACEHOLDER.to_lifetime(&Interner), 77 lifetime: FAKE_PLACEHOLDER.to_lifetime(&Interner),
71 }; 78 };
72 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) 79 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
73 } 80 }
@@ -92,6 +99,7 @@ impl ToChalk for Ty {
92 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { 99 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
93 TypeName::Error => Ty::Unknown, 100 TypeName::Error => Ty::Unknown,
94 TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), 101 TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution),
102 TypeName::Array => array_from_chalk(db, apply_ty.substitution),
95 _ => { 103 _ => {
96 let ctor = from_chalk(db, apply_ty.name); 104 let ctor = from_chalk(db, apply_ty.name);
97 let parameters = from_chalk(db, apply_ty.substitution); 105 let parameters = from_chalk(db, apply_ty.substitution);
@@ -115,10 +123,22 @@ impl ToChalk for Ty {
115 let parameters = from_chalk(db, opaque_ty.substitution); 123 let parameters = from_chalk(db, opaque_ty.substitution);
116 Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters }) 124 Ty::Opaque(OpaqueTy { opaque_ty_id: impl_trait_id, parameters })
117 } 125 }
118 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { 126 chalk_ir::TyData::Function(chalk_ir::FnPointer {
119 let parameters: Substs = from_chalk(db, substitution); 127 num_binders,
128 variadic,
129 substitution,
130 ..
131 }) => {
132 assert_eq!(num_binders, 0);
133 let parameters: Substs = from_chalk(
134 db,
135 substitution.shifted_out(&Interner).expect("fn ptr should have no binders"),
136 );
120 Ty::Apply(ApplicationTy { 137 Ty::Apply(ApplicationTy {
121 ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, 138 ctor: TypeCtor::FnPtr {
139 num_args: (parameters.len() - 1) as u16,
140 is_varargs: variadic,
141 },
122 parameters, 142 parameters,
123 }) 143 })
124 } 144 }
@@ -138,7 +158,7 @@ impl ToChalk for Ty {
138 } 158 }
139} 159}
140 160
141const LIFETIME_PLACEHOLDER: PlaceholderIndex = 161const FAKE_PLACEHOLDER: PlaceholderIndex =
142 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; 162 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX };
143 163
144/// We currently don't model lifetimes, but Chalk does. So, we have to insert a 164/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
@@ -149,10 +169,10 @@ fn ref_to_chalk(
149 subst: Substs, 169 subst: Substs,
150) -> chalk_ir::Ty<Interner> { 170) -> chalk_ir::Ty<Interner> {
151 let arg = subst[0].clone().to_chalk(db); 171 let arg = subst[0].clone().to_chalk(db);
152 let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner); 172 let lifetime = FAKE_PLACEHOLDER.to_lifetime(&Interner);
153 chalk_ir::ApplicationTy { 173 chalk_ir::ApplicationTy {
154 name: TypeName::Ref(mutability.to_chalk(db)), 174 name: TypeName::Ref(mutability.to_chalk(db)),
155 substitution: chalk_ir::Substitution::from( 175 substitution: chalk_ir::Substitution::from_iter(
156 &Interner, 176 &Interner,
157 vec![lifetime.cast(&Interner), arg.cast(&Interner)], 177 vec![lifetime.cast(&Interner), arg.cast(&Interner)],
158 ), 178 ),
@@ -173,11 +193,40 @@ fn ref_from_chalk(
173 Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) 193 Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys))
174} 194}
175 195
196/// We currently don't model constants, but Chalk does. So, we have to insert a
197/// fake constant here, because Chalks built-in logic may expect it to be there.
198fn array_to_chalk(db: &dyn HirDatabase, subst: Substs) -> chalk_ir::Ty<Interner> {
199 let arg = subst[0].clone().to_chalk(db);
200 let usize_ty = chalk_ir::ApplicationTy {
201 name: TypeName::Scalar(Scalar::Uint(chalk_ir::UintTy::Usize)),
202 substitution: chalk_ir::Substitution::empty(&Interner),
203 }
204 .intern(&Interner);
205 let const_ = FAKE_PLACEHOLDER.to_const(&Interner, usize_ty);
206 chalk_ir::ApplicationTy {
207 name: TypeName::Array,
208 substitution: chalk_ir::Substitution::from_iter(
209 &Interner,
210 vec![arg.cast(&Interner), const_.cast(&Interner)],
211 ),
212 }
213 .intern(&Interner)
214}
215
216/// Here we remove the const from the type we got from Chalk.
217fn array_from_chalk(db: &dyn HirDatabase, subst: chalk_ir::Substitution<Interner>) -> Ty {
218 let tys = subst
219 .iter(&Interner)
220 .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone())))
221 .collect();
222 Ty::apply(TypeCtor::Array, Substs(tys))
223}
224
176impl ToChalk for Substs { 225impl ToChalk for Substs {
177 type Chalk = chalk_ir::Substitution<Interner>; 226 type Chalk = chalk_ir::Substitution<Interner>;
178 227
179 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> { 228 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
180 chalk_ir::Substitution::from(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db))) 229 chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
181 } 230 }
182 231
183 fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs { 232 fn from_chalk(db: &dyn HirDatabase, parameters: chalk_ir::Substitution<Interner>) -> Substs {
@@ -263,6 +312,7 @@ impl ToChalk for TypeCtor {
263 TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), 312 TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()),
264 TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), 313 TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)),
265 TypeCtor::Slice => TypeName::Slice, 314 TypeCtor::Slice => TypeName::Slice,
315 TypeCtor::Array => TypeName::Array,
266 TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), 316 TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
267 TypeCtor::Str => TypeName::Str, 317 TypeCtor::Str => TypeName::Str,
268 TypeCtor::FnDef(callable_def) => { 318 TypeCtor::FnDef(callable_def) => {
@@ -271,20 +321,24 @@ impl ToChalk for TypeCtor {
271 } 321 }
272 TypeCtor::Never => TypeName::Never, 322 TypeCtor::Never => TypeName::Never,
273 323
274 TypeCtor::Adt(_) 324 TypeCtor::Closure { def, expr } => {
275 | TypeCtor::Array 325 let closure_id = db.intern_closure((def, expr));
276 | TypeCtor::FnPtr { .. } 326 TypeName::Closure(closure_id.into())
277 | TypeCtor::Closure { .. } => { 327 }
278 // other TypeCtors get interned and turned into a chalk StructId 328
279 let struct_id = db.intern_type_ctor(self).into(); 329 TypeCtor::Adt(adt_id) => TypeName::Adt(chalk_ir::AdtId(adt_id)),
280 TypeName::Adt(struct_id) 330
331 TypeCtor::FnPtr { .. } => {
332 // This should not be reached, since Chalk doesn't represent
333 // function pointers with TypeName
334 unreachable!()
281 } 335 }
282 } 336 }
283 } 337 }
284 338
285 fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor { 339 fn from_chalk(db: &dyn HirDatabase, type_name: TypeName<Interner>) -> TypeCtor {
286 match type_name { 340 match type_name {
287 TypeName::Adt(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), 341 TypeName::Adt(struct_id) => TypeCtor::Adt(struct_id.0),
288 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 342 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
289 TypeName::OpaqueType(opaque_type_id) => { 343 TypeName::OpaqueType(opaque_type_id) => {
290 TypeCtor::OpaqueType(from_chalk(db, opaque_type_id)) 344 TypeCtor::OpaqueType(from_chalk(db, opaque_type_id))
@@ -317,13 +371,16 @@ impl ToChalk for TypeCtor {
317 let callable_def = from_chalk(db, fn_def_id); 371 let callable_def = from_chalk(db, fn_def_id);
318 TypeCtor::FnDef(callable_def) 372 TypeCtor::FnDef(callable_def)
319 } 373 }
374 TypeName::Array => TypeCtor::Array,
320 375
321 TypeName::Array | TypeName::Error => { 376 TypeName::Closure(id) => {
322 // this should not be reached, since we don't represent TypeName::Error with TypeCtor 377 let id: crate::db::ClosureId = id.into();
323 unreachable!() 378 let (def, expr) = db.lookup_intern_closure(id);
379 TypeCtor::Closure { def, expr }
324 } 380 }
325 TypeName::Closure(_) => { 381
326 // FIXME: implement closure support 382 TypeName::Error => {
383 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
327 unreachable!() 384 unreachable!()
328 } 385 }
329 } 386 }
@@ -395,26 +452,26 @@ impl ToChalk for Mutability {
395 } 452 }
396} 453}
397 454
398impl ToChalk for Impl { 455impl ToChalk for hir_def::ImplId {
399 type Chalk = ImplId; 456 type Chalk = ImplId;
400 457
401 fn to_chalk(self, db: &dyn HirDatabase) -> ImplId { 458 fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId {
402 db.intern_chalk_impl(self).into() 459 chalk_ir::ImplId(self.as_intern_id())
403 } 460 }
404 461
405 fn from_chalk(db: &dyn HirDatabase, impl_id: ImplId) -> Impl { 462 fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId {
406 db.lookup_intern_chalk_impl(impl_id.into()) 463 InternKey::from_intern_id(impl_id.0)
407 } 464 }
408} 465}
409 466
410impl ToChalk for CallableDef { 467impl ToChalk for CallableDefId {
411 type Chalk = FnDefId; 468 type Chalk = FnDefId;
412 469
413 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { 470 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
414 db.intern_callable_def(self).into() 471 db.intern_callable_def(self).into()
415 } 472 }
416 473
417 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef { 474 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
418 db.lookup_intern_callable_def(fn_def_id.into()) 475 db.lookup_intern_callable_def(fn_def_id.into())
419 } 476 }
420} 477}
@@ -431,15 +488,20 @@ impl ToChalk for TypeAliasId {
431 } 488 }
432} 489}
433 490
434impl ToChalk for AssocTyValue { 491pub struct TypeAliasAsValue(pub TypeAliasId);
492
493impl ToChalk for TypeAliasAsValue {
435 type Chalk = AssociatedTyValueId; 494 type Chalk = AssociatedTyValueId;
436 495
437 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValueId { 496 fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId {
438 db.intern_assoc_ty_value(self).into() 497 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
439 } 498 }
440 499
441 fn from_chalk(db: &dyn HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue { 500 fn from_chalk(
442 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) 501 _db: &dyn HirDatabase,
502 assoc_ty_value_id: AssociatedTyValueId,
503 ) -> TypeAliasAsValue {
504 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
443 } 505 }
444} 506}
445 507
@@ -492,6 +554,11 @@ impl ToChalk for GenericPredicate {
492 // we shouldn't get these from Chalk 554 // we shouldn't get these from Chalk
493 panic!("encountered LifetimeOutlives from Chalk") 555 panic!("encountered LifetimeOutlives from Chalk")
494 } 556 }
557
558 chalk_ir::WhereClause::TypeOutlives(_) => {
559 // we shouldn't get these from Chalk
560 panic!("encountered TypeOutlives from Chalk")
561 }
495 } 562 }
496 } 563 }
497} 564}
@@ -555,22 +622,42 @@ where
555 type Chalk = chalk_ir::Canonical<T::Chalk>; 622 type Chalk = chalk_ir::Canonical<T::Chalk>;
556 623
557 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { 624 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
558 let parameter = chalk_ir::CanonicalVarKind::new( 625 let kinds = self
559 chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), 626 .kinds
560 chalk_ir::UniverseIndex::ROOT, 627 .iter()
561 ); 628 .map(|k| match k {
629 TyKind::General => chalk_ir::TyKind::General,
630 TyKind::Integer => chalk_ir::TyKind::Integer,
631 TyKind::Float => chalk_ir::TyKind::Float,
632 })
633 .map(|tk| {
634 chalk_ir::CanonicalVarKind::new(
635 chalk_ir::VariableKind::Ty(tk),
636 chalk_ir::UniverseIndex::ROOT,
637 )
638 });
562 let value = self.value.to_chalk(db); 639 let value = self.value.to_chalk(db);
563 chalk_ir::Canonical { 640 chalk_ir::Canonical {
564 value, 641 value,
565 binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]), 642 binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds),
566 } 643 }
567 } 644 }
568 645
569 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { 646 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
570 Canonical { 647 let kinds = canonical
571 num_vars: canonical.binders.len(&Interner), 648 .binders
572 value: from_chalk(db, canonical.value), 649 .iter(&Interner)
573 } 650 .map(|k| match k.kind {
651 chalk_ir::VariableKind::Ty(tk) => match tk {
652 chalk_ir::TyKind::General => TyKind::General,
653 chalk_ir::TyKind::Integer => TyKind::Integer,
654 chalk_ir::TyKind::Float => TyKind::Float,
655 },
656 chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
657 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
658 })
659 .collect();
660 Canonical { kinds, value: from_chalk(db, canonical.value) }
574 } 661 }
575} 662}
576 663
@@ -623,58 +710,12 @@ where
623 } 710 }
624} 711}
625 712
626impl ToChalk for builtin::BuiltinImplData {
627 type Chalk = ImplDatum;
628
629 fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum {
630 let impl_type = rust_ir::ImplType::External;
631 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
632
633 let impl_datum_bound =
634 rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
635 let associated_ty_value_ids =
636 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
637 rust_ir::ImplDatum {
638 binders: make_binders(impl_datum_bound, self.num_vars),
639 impl_type,
640 polarity: rust_ir::Polarity::Positive,
641 associated_ty_value_ids,
642 }
643 }
644
645 fn from_chalk(_db: &dyn HirDatabase, _data: ImplDatum) -> Self {
646 unimplemented!()
647 }
648}
649
650impl ToChalk for builtin::BuiltinImplAssocTyValueData {
651 type Chalk = AssociatedTyValue;
652
653 fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue {
654 let ty = self.value.to_chalk(db);
655 let value_bound = rust_ir::AssociatedTyValueBound { ty };
656
657 rust_ir::AssociatedTyValue {
658 associated_ty_id: self.assoc_ty_id.to_chalk(db),
659 impl_id: self.impl_.to_chalk(db),
660 value: make_binders(value_bound, self.num_vars),
661 }
662 }
663
664 fn from_chalk(
665 _db: &dyn HirDatabase,
666 _data: AssociatedTyValue,
667 ) -> builtin::BuiltinImplAssocTyValueData {
668 unimplemented!()
669 }
670}
671
672pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> 713pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
673where 714where
674 T: HasInterner<Interner = Interner>, 715 T: HasInterner<Interner = Interner>,
675{ 716{
676 chalk_ir::Binders::new( 717 chalk_ir::Binders::new(
677 chalk_ir::VariableKinds::from( 718 chalk_ir::VariableKinds::from_iter(
678 &Interner, 719 &Interner,
679 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars), 720 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars),
680 ), 721 ),
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index 556af7098..db915625c 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -5,12 +5,12 @@ use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplicat
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use super::{from_chalk, Interner}; 7use super::{from_chalk, Interner};
8use crate::{db::HirDatabase, CallableDef, TypeCtor}; 8use crate::{db::HirDatabase, CallableDefId, TypeCtor};
9use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; 9use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
10 10
11pub use unsafe_tls::{set_current_program, with_current_program}; 11pub use unsafe_tls::{set_current_program, with_current_program};
12 12
13pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a)); 13pub struct DebugContext<'a>(&'a dyn HirDatabase);
14 14
15impl DebugContext<'_> { 15impl DebugContext<'_> {
16 pub fn debug_struct_id( 16 pub fn debug_struct_id(
@@ -38,16 +38,16 @@ impl DebugContext<'_> {
38 } 38 }
39 TypeCtor::FnDef(def) => { 39 TypeCtor::FnDef(def) => {
40 let name = match def { 40 let name = match def {
41 CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), 41 CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
42 CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), 42 CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
43 CallableDef::EnumVariantId(e) => { 43 CallableDefId::EnumVariantId(e) => {
44 let enum_data = self.0.enum_data(e.parent); 44 let enum_data = self.0.enum_data(e.parent);
45 enum_data.variants[e.local_id].name.clone() 45 enum_data.variants[e.local_id].name.clone()
46 } 46 }
47 }; 47 };
48 match def { 48 match def {
49 CallableDef::FunctionId(_) => write!(f, "{{fn {}}}", name)?, 49 CallableDefId::FunctionId(_) => write!(f, "{{fn {}}}", name)?,
50 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { 50 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
51 write!(f, "{{ctor {}}}", name)? 51 write!(f, "{{ctor {}}}", name)?
52 } 52 }
53 } 53 }
@@ -157,7 +157,7 @@ impl DebugContext<'_> {
157 _ => panic!("associated type not in trait"), 157 _ => panic!("associated type not in trait"),
158 }; 158 };
159 let trait_data = self.0.trait_data(trait_); 159 let trait_data = self.0.trait_data(trait_);
160 let params = projection_ty.substitution.parameters(&Interner); 160 let params = projection_ty.substitution.as_slice(&Interner);
161 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?; 161 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
162 if params.len() > 1 { 162 if params.len() > 1 {
163 write!( 163 write!(
@@ -255,18 +255,18 @@ impl DebugContext<'_> {
255 fn_def_id: chalk_ir::FnDefId<Interner>, 255 fn_def_id: chalk_ir::FnDefId<Interner>,
256 fmt: &mut fmt::Formatter<'_>, 256 fmt: &mut fmt::Formatter<'_>,
257 ) -> Result<(), fmt::Error> { 257 ) -> Result<(), fmt::Error> {
258 let def: CallableDef = from_chalk(self.0, fn_def_id); 258 let def: CallableDefId = from_chalk(self.0, fn_def_id);
259 let name = match def { 259 let name = match def {
260 CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), 260 CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
261 CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), 261 CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
262 CallableDef::EnumVariantId(e) => { 262 CallableDefId::EnumVariantId(e) => {
263 let enum_data = self.0.enum_data(e.parent); 263 let enum_data = self.0.enum_data(e.parent);
264 enum_data.variants[e.local_id].name.clone() 264 enum_data.variants[e.local_id].name.clone()
265 } 265 }
266 }; 266 };
267 match def { 267 match def {
268 CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name), 268 CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
269 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { 269 CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
270 write!(fmt, "{{ctor {}}}", name) 270 write!(fmt, "{{ctor {}}}", name)
271 } 271 }
272 } 272 }
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index c45820ff0..e3e244268 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -110,38 +110,6 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
110 result 110 result
111} 111}
112 112
113/// Finds a path from a trait to one of its super traits. Returns an empty
114/// vector if there is no path.
115pub(super) fn find_super_trait_path(
116 db: &dyn DefDatabase,
117 trait_: TraitId,
118 super_trait: TraitId,
119) -> Vec<TraitId> {
120 let mut result = Vec::with_capacity(2);
121 result.push(trait_);
122 return if go(db, super_trait, &mut result) { result } else { Vec::new() };
123
124 fn go(db: &dyn DefDatabase, super_trait: TraitId, path: &mut Vec<TraitId>) -> bool {
125 let trait_ = *path.last().unwrap();
126 if trait_ == super_trait {
127 return true;
128 }
129
130 for tt in direct_super_traits(db, trait_) {
131 if path.contains(&tt) {
132 continue;
133 }
134 path.push(tt);
135 if go(db, super_trait, path) {
136 return true;
137 } else {
138 path.pop();
139 }
140 }
141 false
142 }
143}
144
145pub(super) fn associated_type_by_name_including_super_traits( 113pub(super) fn associated_type_by_name_including_super_traits(
146 db: &dyn HirDatabase, 114 db: &dyn HirDatabase,
147 trait_ref: TraitRef, 115 trait_ref: TraitRef,
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index d0eb018d5..4e2ba6d61 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_ide" 3name = "ra_ide"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -22,6 +23,7 @@ maplit = "*"
22lazy_static = "*" 23lazy_static = "*"
23pulldown-cmark-to-cmark = "4.0.2" 24pulldown-cmark-to-cmark = "4.0.2"
24pulldown-cmark = "0.7.0" 25pulldown-cmark = "0.7.0"
26oorandom = "11.1.2"
25 27
26stdx = { path = "../stdx" } 28stdx = { path = "../stdx" }
27 29
@@ -44,4 +46,4 @@ ra_parser = { path = "../ra_parser" }
44hir = { path = "../ra_hir", package = "ra_hir" } 46hir = { path = "../ra_hir", package = "ra_hir" }
45 47
46[dev-dependencies] 48[dev-dependencies]
47insta = "0.16.0" 49expect = { path = "../expect" }
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index 1e3a31602..1fcaf4a32 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -39,10 +39,11 @@ pub(crate) fn call_hierarchy(
39 39
40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> { 40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
41 let sema = Semantics::new(db); 41 let sema = Semantics::new(db);
42
42 // 1. Find all refs 43 // 1. Find all refs
43 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply. 44 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
44 // 3. Add ranges relative to the start of the fndef. 45 // 3. Add ranges relative to the start of the fndef.
45 let refs = references::find_all_refs(db, position, None)?; 46 let refs = references::find_all_refs(&sema, position, None)?;
46 47
47 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
48 49
@@ -58,7 +59,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
58 if let Some(nav) = syntax.ancestors().find_map(|node| { 59 if let Some(nav) = syntax.ancestors().find_map(|node| {
59 match_ast! { 60 match_ast! {
60 match node { 61 match node {
61 ast::FnDef(it) => { 62 ast::Fn(it) => {
62 let def = sema.to_def(&it)?; 63 let def = sema.to_def(&it)?;
63 Some(def.to_nav(sema.db)) 64 Some(def.to_nav(sema.db))
64 }, 65 },
@@ -94,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
94 if let Some(func_target) = match &call_node { 95 if let Some(func_target) = match &call_node {
95 FnCallNode::CallExpr(expr) => { 96 FnCallNode::CallExpr(expr) => {
96 //FIXME: Type::as_callable is broken 97 //FIXME: Type::as_callable is broken
97 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
98 match callable_def { 99 match callable.kind() {
99 hir::CallableDef::FunctionId(it) => { 100 hir::CallableKind::Function(it) => {
100 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
101 let nav = fn_def.to_nav(db); 102 let nav = fn_def.to_nav(db);
102 Some(nav) 103 Some(nav)
@@ -108,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
108 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
109 Some(function.to_nav(db)) 110 Some(function.to_nav(db))
110 } 111 }
111 FnCallNode::MacroCallExpr(macro_call) => {
112 let macro_def = sema.resolve_macro_call(&macro_call)?;
113 Some(macro_def.to_nav(db))
114 }
115 } { 112 } {
116 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
117 } else { 114 } else {
@@ -157,7 +154,8 @@ mod tests {
157 let nav = navs.pop().unwrap(); 154 let nav = navs.pop().unwrap();
158 nav.assert_match(expected); 155 nav.assert_match(expected);
159 156
160 let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() }; 157 let item_pos =
158 FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
161 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); 159 let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
162 assert_eq!(incoming_calls.len(), expected_incoming.len()); 160 assert_eq!(incoming_calls.len(), expected_incoming.len());
163 161
@@ -183,8 +181,8 @@ fn caller() {
183 call<|>ee(); 181 call<|>ee();
184} 182}
185"#, 183"#,
186 "callee FN_DEF FileId(1) 0..14 3..9", 184 "callee FN FileId(1) 0..14 3..9",
187 &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], 185 &["caller FN FileId(1) 15..44 18..24 : [33..39]"],
188 &[], 186 &[],
189 ); 187 );
190 } 188 }
@@ -199,8 +197,8 @@ fn caller() {
199 callee(); 197 callee();
200} 198}
201"#, 199"#,
202 "callee FN_DEF FileId(1) 0..14 3..9", 200 "callee FN FileId(1) 0..14 3..9",
203 &["caller FN_DEF FileId(1) 15..44 18..24 : [33..39]"], 201 &["caller FN FileId(1) 15..44 18..24 : [33..39]"],
204 &[], 202 &[],
205 ); 203 );
206 } 204 }
@@ -216,8 +214,8 @@ fn caller() {
216 callee(); 214 callee();
217} 215}
218"#, 216"#,
219 "callee FN_DEF FileId(1) 0..14 3..9", 217 "callee FN FileId(1) 0..14 3..9",
220 &["caller FN_DEF FileId(1) 15..58 18..24 : [33..39, 47..53]"], 218 &["caller FN FileId(1) 15..58 18..24 : [33..39, 47..53]"],
221 &[], 219 &[],
222 ); 220 );
223 } 221 }
@@ -236,10 +234,10 @@ fn caller2() {
236 callee(); 234 callee();
237} 235}
238"#, 236"#,
239 "callee FN_DEF FileId(1) 0..14 3..9", 237 "callee FN FileId(1) 0..14 3..9",
240 &[ 238 &[
241 "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", 239 "caller1 FN FileId(1) 15..45 18..25 : [34..40]",
242 "caller2 FN_DEF FileId(1) 47..77 50..57 : [66..72]", 240 "caller2 FN FileId(1) 47..77 50..57 : [66..72]",
243 ], 241 ],
244 &[], 242 &[],
245 ); 243 );
@@ -265,10 +263,10 @@ mod tests {
265 } 263 }
266} 264}
267"#, 265"#,
268 "callee FN_DEF FileId(1) 0..14 3..9", 266 "callee FN FileId(1) 0..14 3..9",
269 &[ 267 &[
270 "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", 268 "caller1 FN FileId(1) 15..45 18..25 : [34..40]",
271 "test_caller FN_DEF FileId(1) 95..149 110..121 : [134..140]", 269 "test_caller FN FileId(1) 95..149 110..121 : [134..140]",
272 ], 270 ],
273 &[], 271 &[],
274 ); 272 );
@@ -289,8 +287,8 @@ fn caller() {
289//- /foo/mod.rs 287//- /foo/mod.rs
290pub fn callee() {} 288pub fn callee() {}
291"#, 289"#,
292 "callee FN_DEF FileId(2) 0..18 7..13", 290 "callee FN FileId(2) 0..18 7..13",
293 &["caller FN_DEF FileId(1) 27..56 30..36 : [45..51]"], 291 &["caller FN FileId(1) 27..56 30..36 : [45..51]"],
294 &[], 292 &[],
295 ); 293 );
296 } 294 }
@@ -306,9 +304,9 @@ fn call<|>er() {
306 callee(); 304 callee();
307} 305}
308"#, 306"#,
309 "caller FN_DEF FileId(1) 15..58 18..24", 307 "caller FN FileId(1) 15..58 18..24",
310 &[], 308 &[],
311 &["callee FN_DEF FileId(1) 0..14 3..9 : [33..39, 47..53]"], 309 &["callee FN FileId(1) 0..14 3..9 : [33..39, 47..53]"],
312 ); 310 );
313 } 311 }
314 312
@@ -327,9 +325,9 @@ fn call<|>er() {
327//- /foo/mod.rs 325//- /foo/mod.rs
328pub fn callee() {} 326pub fn callee() {}
329"#, 327"#,
330 "caller FN_DEF FileId(1) 27..56 30..36", 328 "caller FN FileId(1) 27..56 30..36",
331 &[], 329 &[],
332 &["callee FN_DEF FileId(2) 0..18 7..13 : [45..51]"], 330 &["callee FN FileId(2) 0..18 7..13 : [45..51]"],
333 ); 331 );
334 } 332 }
335 333
@@ -350,9 +348,46 @@ fn caller3() {
350 348
351} 349}
352"#, 350"#,
353 "caller2 FN_DEF FileId(1) 33..64 36..43", 351 "caller2 FN FileId(1) 33..64 36..43",
354 &["caller1 FN_DEF FileId(1) 0..31 3..10 : [19..26]"], 352 &["caller1 FN FileId(1) 0..31 3..10 : [19..26]"],
355 &["caller3 FN_DEF FileId(1) 66..83 69..76 : [52..59]"], 353 &["caller3 FN FileId(1) 66..83 69..76 : [52..59]"],
354 );
355 }
356
357 #[test]
358 fn test_call_hierarchy_issue_5103() {
359 check_hierarchy(
360 r#"
361fn a() {
362 b()
363}
364
365fn b() {}
366
367fn main() {
368 a<|>()
369}
370"#,
371 "a FN FileId(1) 0..18 3..4",
372 &["main FN FileId(1) 31..52 34..38 : [47..48]"],
373 &["b FN FileId(1) 20..29 23..24 : [13..14]"],
374 );
375
376 check_hierarchy(
377 r#"
378fn a() {
379 b<|>()
380}
381
382fn b() {}
383
384fn main() {
385 a()
386}
387"#,
388 "b FN FileId(1) 20..29 23..24",
389 &["a FN FileId(1) 0..18 3..4 : [13..14]"],
390 &[],
356 ); 391 );
357 } 392 }
358} 393}
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index a6bdf1c9d..ff602202f 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,13 +1,43 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use hir::Semantics; 2use either::Either;
3use hir::{Docs, HirDisplay, Semantics, Type};
3use ra_ide_db::RootDatabase; 4use ra_ide_db::RootDatabase;
4use ra_syntax::{ 5use ra_syntax::{
5 ast::{self, ArgListOwner}, 6 ast::{self, ArgListOwner},
6 match_ast, AstNode, SyntaxNode, SyntaxToken, 7 match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize,
7}; 8};
9use stdx::format_to;
8use test_utils::mark; 10use test_utils::mark;
9 11
10use crate::{CallInfo, FilePosition, FunctionSignature}; 12use crate::FilePosition;
13
14/// Contains information about a call site. Specifically the
15/// `FunctionSignature`and current parameter.
16#[derive(Debug)]
17pub struct CallInfo {
18 pub doc: Option<String>,
19 pub signature: String,
20 pub active_parameter: Option<usize>,
21 parameters: Vec<TextRange>,
22}
23
24impl CallInfo {
25 pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
26 self.parameters.iter().map(move |&it| &self.signature[it])
27 }
28 pub fn parameter_ranges(&self) -> &[TextRange] {
29 &self.parameters
30 }
31 fn push_param(&mut self, param: &str) {
32 if !self.signature.ends_with('(') {
33 self.signature.push_str(", ");
34 }
35 let start = TextSize::of(&self.signature);
36 self.signature.push_str(param);
37 let end = TextSize::of(&self.signature);
38 self.parameters.push(TextRange::new(start, end))
39 }
40}
11 41
12/// Computes parameter information for the given call expression. 42/// Computes parameter information for the given call expression.
13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 43pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
@@ -16,106 +46,135 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
16 let file = file.syntax(); 46 let file = file.syntax();
17 let token = file.token_at_offset(position.offset).next()?; 47 let token = file.token_at_offset(position.offset).next()?;
18 let token = sema.descend_into_macros(token); 48 let token = sema.descend_into_macros(token);
19 call_info_for_token(&sema, token)
20}
21 49
22#[derive(Debug)] 50 let (callable, active_parameter) = call_info_impl(&sema, token)?;
23pub(crate) struct ActiveParameter {
24 /// FIXME: should be `Type` and `Name
25 pub(crate) ty: String,
26 pub(crate) name: String,
27}
28 51
29impl ActiveParameter { 52 let mut res =
30 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 53 CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
31 call_info(db, position)?.into_active_parameter() 54
55 match callable.kind() {
56 hir::CallableKind::Function(func) => {
57 res.doc = func.docs(db).map(|it| it.as_str().to_string());
58 format_to!(res.signature, "fn {}", func.name(db));
59 }
60 hir::CallableKind::TupleStruct(strukt) => {
61 res.doc = strukt.docs(db).map(|it| it.as_str().to_string());
62 format_to!(res.signature, "struct {}", strukt.name(db));
63 }
64 hir::CallableKind::TupleEnumVariant(variant) => {
65 res.doc = variant.docs(db).map(|it| it.as_str().to_string());
66 format_to!(
67 res.signature,
68 "enum {}::{}",
69 variant.parent_enum(db).name(db),
70 variant.name(db)
71 );
72 }
73 hir::CallableKind::Closure => (),
32 } 74 }
33 75
34 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 76 res.signature.push('(');
35 call_info_for_token(sema, token)?.into_active_parameter() 77 {
78 if let Some(self_param) = callable.receiver_param(db) {
79 format_to!(res.signature, "{}", self_param)
80 }
81 let mut buf = String::new();
82 for (pat, ty) in callable.params(db) {
83 buf.clear();
84 if let Some(pat) = pat {
85 match pat {
86 Either::Left(_self) => format_to!(buf, "self: "),
87 Either::Right(pat) => format_to!(buf, "{}: ", pat),
88 }
89 }
90 format_to!(buf, "{}", ty.display(db));
91 res.push_param(&buf);
92 }
36 } 93 }
94 res.signature.push(')');
95
96 match callable.kind() {
97 hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
98 let ret_type = callable.return_type();
99 if !ret_type.is_unit() {
100 format_to!(res.signature, " -> {}", ret_type.display(db));
101 }
102 }
103 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
104 }
105 Some(res)
37} 106}
38 107
39fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 108fn call_info_impl(
109 sema: &Semantics<RootDatabase>,
110 token: SyntaxToken,
111) -> Option<(hir::Callable, Option<usize>)> {
40 // Find the calling expression and it's NameRef 112 // Find the calling expression and it's NameRef
41 let calling_node = FnCallNode::with_node(&token.parent())?; 113 let calling_node = FnCallNode::with_node(&token.parent())?;
42 114
43 let (mut call_info, has_self) = match &calling_node { 115 let callable = match &calling_node {
44 FnCallNode::CallExpr(call) => { 116 FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?,
45 //FIXME: Type::as_callable is broken 117 FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?,
46 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; 118 };
47 match callable_def { 119 let active_param = if let Some(arg_list) = calling_node.arg_list() {
48 hir::CallableDef::FunctionId(it) => { 120 // Number of arguments specified at the call site
49 let fn_def = it.into(); 121 let num_args_at_callsite = arg_list.args().count();
50 (CallInfo::with_fn(sema.db, fn_def), fn_def.has_self_param(sema.db)) 122
51 } 123 let arg_list_range = arg_list.syntax().text_range();
52 hir::CallableDef::StructId(it) => { 124 if !arg_list_range.contains_inclusive(token.text_range().start()) {
53 (CallInfo::with_struct(sema.db, it.into())?, false) 125 mark::hit!(call_info_bad_offset);
54 } 126 return None;
55 hir::CallableDef::EnumVariantId(it) => {
56 (CallInfo::with_enum_variant(sema.db, it.into())?, false)
57 }
58 }
59 }
60 FnCallNode::MethodCallExpr(method_call) => {
61 let function = sema.resolve_method_call(&method_call)?;
62 (CallInfo::with_fn(sema.db, function), function.has_self_param(sema.db))
63 }
64 FnCallNode::MacroCallExpr(macro_call) => {
65 let macro_def = sema.resolve_macro_call(&macro_call)?;
66 (CallInfo::with_macro(sema.db, macro_def)?, false)
67 } 127 }
128 let param = std::cmp::min(
129 num_args_at_callsite,
130 arg_list
131 .args()
132 .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
133 .count(),
134 );
135
136 Some(param)
137 } else {
138 None
68 }; 139 };
140 Some((callable, active_param))
141}
69 142
70 // If we have a calling expression let's find which argument we are on 143#[derive(Debug)]
71 let num_params = call_info.parameters().len(); 144pub(crate) struct ActiveParameter {
145 pub(crate) ty: Type,
146 pub(crate) name: String,
147}
72 148
73 match num_params { 149impl ActiveParameter {
74 0 => (), 150 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
75 1 => { 151 let sema = Semantics::new(db);
76 if !has_self { 152 let file = sema.parse(position.file_id);
77 call_info.active_parameter = Some(0); 153 let file = file.syntax();
78 } 154 let token = file.token_at_offset(position.offset).next()?;
79 } 155 let token = sema.descend_into_macros(token);
80 _ => { 156 Self::at_token(&sema, token)
81 if let Some(arg_list) = calling_node.arg_list() { 157 }
82 // Number of arguments specified at the call site
83 let num_args_at_callsite = arg_list.args().count();
84
85 let arg_list_range = arg_list.syntax().text_range();
86 if !arg_list_range.contains_inclusive(token.text_range().start()) {
87 mark::hit!(call_info_bad_offset);
88 return None;
89 }
90 158
91 let mut param = std::cmp::min( 159 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
92 num_args_at_callsite, 160 let (signature, active_parameter) = call_info_impl(&sema, token)?;
93 arg_list
94 .args()
95 .take_while(|arg| {
96 arg.syntax().text_range().end() < token.text_range().start()
97 })
98 .count(),
99 );
100
101 // If we are in a method account for `self`
102 if has_self {
103 param += 1;
104 }
105 161
106 call_info.active_parameter = Some(param); 162 let idx = active_parameter?;
107 } 163 let mut params = signature.params(sema.db);
164 if !(idx < params.len()) {
165 mark::hit!(too_many_arguments);
166 return None;
108 } 167 }
168 let (pat, ty) = params.swap_remove(idx);
169 let name = pat?.to_string();
170 Some(ActiveParameter { ty, name })
109 } 171 }
110
111 Some(call_info)
112} 172}
113 173
114#[derive(Debug)] 174#[derive(Debug)]
115pub(crate) enum FnCallNode { 175pub(crate) enum FnCallNode {
116 CallExpr(ast::CallExpr), 176 CallExpr(ast::CallExpr),
117 MethodCallExpr(ast::MethodCallExpr), 177 MethodCallExpr(ast::MethodCallExpr),
118 MacroCallExpr(ast::MacroCall),
119} 178}
120 179
121impl FnCallNode { 180impl FnCallNode {
@@ -131,7 +190,6 @@ impl FnCallNode {
131 } 190 }
132 Some(FnCallNode::MethodCallExpr(it)) 191 Some(FnCallNode::MethodCallExpr(it))
133 }, 192 },
134 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
135 _ => None, 193 _ => None,
136 } 194 }
137 } 195 }
@@ -143,7 +201,6 @@ impl FnCallNode {
143 match node { 201 match node {
144 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 202 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
145 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), 203 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)),
146 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
147 _ => None, 204 _ => None,
148 } 205 }
149 } 206 }
@@ -159,8 +216,6 @@ impl FnCallNode {
159 FnCallNode::MethodCallExpr(call_expr) => { 216 FnCallNode::MethodCallExpr(call_expr) => {
160 call_expr.syntax().children().filter_map(ast::NameRef::cast).next() 217 call_expr.syntax().children().filter_map(ast::NameRef::cast).next()
161 } 218 }
162
163 FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(),
164 } 219 }
165 } 220 }
166 221
@@ -168,214 +223,209 @@ impl FnCallNode {
168 match self { 223 match self {
169 FnCallNode::CallExpr(expr) => expr.arg_list(), 224 FnCallNode::CallExpr(expr) => expr.arg_list(),
170 FnCallNode::MethodCallExpr(expr) => expr.arg_list(), 225 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
171 FnCallNode::MacroCallExpr(_) => None,
172 } 226 }
173 } 227 }
174} 228}
175 229
176impl CallInfo {
177 fn into_active_parameter(self) -> Option<ActiveParameter> {
178 let idx = self.active_parameter?;
179 let ty = self.signature.parameter_types.get(idx)?.clone();
180 let name = self.signature.parameter_names.get(idx)?.clone();
181 let res = ActiveParameter { ty, name };
182 Some(res)
183 }
184
185 fn with_fn(db: &RootDatabase, function: hir::Function) -> Self {
186 let signature = FunctionSignature::from_hir(db, function);
187
188 CallInfo { signature, active_parameter: None }
189 }
190
191 fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
192 let signature = FunctionSignature::from_struct(db, st)?;
193
194 Some(CallInfo { signature, active_parameter: None })
195 }
196
197 fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
198 let signature = FunctionSignature::from_enum_variant(db, variant)?;
199
200 Some(CallInfo { signature, active_parameter: None })
201 }
202
203 fn with_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
204 let signature = FunctionSignature::from_macro(db, macro_def)?;
205
206 Some(CallInfo { signature, active_parameter: None })
207 }
208
209 fn parameters(&self) -> &[String] {
210 &self.signature.parameters
211 }
212}
213
214#[cfg(test)] 230#[cfg(test)]
215mod tests { 231mod tests {
232 use expect::{expect, Expect};
216 use test_utils::mark; 233 use test_utils::mark;
217 234
218 use crate::mock_analysis::analysis_and_position; 235 use crate::mock_analysis::analysis_and_position;
219 236
220 use super::*; 237 fn check(ra_fixture: &str, expect: Expect) {
221 238 let (analysis, position) = analysis_and_position(ra_fixture);
222 // These are only used when testing 239 let call_info = analysis.call_info(position).unwrap();
223 impl CallInfo { 240 let actual = match call_info {
224 fn doc(&self) -> Option<hir::Documentation> { 241 Some(call_info) => {
225 self.signature.doc.clone() 242 let docs = match &call_info.doc {
226 } 243 None => "".to_string(),
227 244 Some(docs) => format!("{}\n------\n", docs.as_str()),
228 fn label(&self) -> String { 245 };
229 self.signature.to_string() 246 let params = call_info
230 } 247 .parameter_labels()
231 } 248 .enumerate()
232 249 .map(|(i, param)| {
233 fn call_info_helper(text: &str) -> Option<CallInfo> { 250 if Some(i) == call_info.active_parameter {
234 let (analysis, position) = analysis_and_position(text); 251 format!("<{}>", param)
235 analysis.call_info(position).unwrap() 252 } else {
236 } 253 param.to_string()
237 254 }
238 fn call_info(text: &str) -> CallInfo { 255 })
239 let info = call_info_helper(text); 256 .collect::<Vec<_>>()
240 assert!(info.is_some()); 257 .join(", ");
241 info.unwrap() 258 format!("{}{}\n({})\n", docs, call_info.signature, params)
242 } 259 }
243 260 None => String::new(),
244 fn no_call_info(text: &str) { 261 };
245 let info = call_info_helper(text); 262 expect.assert_eq(&actual);
246 assert!(info.is_none());
247 } 263 }
248 264
249 #[test] 265 #[test]
250 fn test_fn_signature_two_args_firstx() { 266 fn test_fn_signature_two_args() {
251 let info = call_info( 267 check(
252 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 268 r#"
253fn bar() { foo(<|>3, ); }"#, 269fn foo(x: u32, y: u32) -> u32 {x + y}
270fn bar() { foo(<|>3, ); }
271"#,
272 expect![[r#"
273 fn foo(x: u32, y: u32) -> u32
274 (<x: u32>, y: u32)
275 "#]],
254 ); 276 );
255 277 check(
256 assert_eq!(info.parameters(), ["x: u32", "y: u32"]); 278 r#"
257 assert_eq!(info.active_parameter, Some(0)); 279fn foo(x: u32, y: u32) -> u32 {x + y}
258 } 280fn bar() { foo(3<|>, ); }
259 281"#,
260 #[test] 282 expect![[r#"
261 fn test_fn_signature_two_args_second() { 283 fn foo(x: u32, y: u32) -> u32
262 let info = call_info( 284 (<x: u32>, y: u32)
263 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 285 "#]],
264fn bar() { foo(3, <|>); }"#, 286 );
287 check(
288 r#"
289fn foo(x: u32, y: u32) -> u32 {x + y}
290fn bar() { foo(3,<|> ); }
291"#,
292 expect![[r#"
293 fn foo(x: u32, y: u32) -> u32
294 (x: u32, <y: u32>)
295 "#]],
296 );
297 check(
298 r#"
299fn foo(x: u32, y: u32) -> u32 {x + y}
300fn bar() { foo(3, <|>); }
301"#,
302 expect![[r#"
303 fn foo(x: u32, y: u32) -> u32
304 (x: u32, <y: u32>)
305 "#]],
265 ); 306 );
266
267 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
268 assert_eq!(info.active_parameter, Some(1));
269 } 307 }
270 308
271 #[test] 309 #[test]
272 fn test_fn_signature_two_args_empty() { 310 fn test_fn_signature_two_args_empty() {
273 let info = call_info( 311 check(
274 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 312 r#"
275fn bar() { foo(<|>); }"#, 313fn foo(x: u32, y: u32) -> u32 {x + y}
314fn bar() { foo(<|>); }
315"#,
316 expect![[r#"
317 fn foo(x: u32, y: u32) -> u32
318 (<x: u32>, y: u32)
319 "#]],
276 ); 320 );
277
278 assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
279 assert_eq!(info.active_parameter, Some(0));
280 } 321 }
281 322
282 #[test] 323 #[test]
283 fn test_fn_signature_two_args_first_generics() { 324 fn test_fn_signature_two_args_first_generics() {
284 let info = call_info( 325 check(
285 r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
286fn bar() { foo(<|>3, ); }"#,
287 );
288
289 assert_eq!(info.parameters(), ["x: T", "y: U"]);
290 assert_eq!(
291 info.label(),
292 r#" 326 r#"
293fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 327fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
294where T: Copy + Display, 328 where T: Copy + Display, U: Debug
295 U: Debug 329{ x + y }
296 "# 330
297 .trim() 331fn bar() { foo(<|>3, ); }
332"#,
333 expect![[r#"
334 fn foo(x: i32, y: {unknown}) -> u32
335 (<x: i32>, y: {unknown})
336 "#]],
298 ); 337 );
299 assert_eq!(info.active_parameter, Some(0));
300 } 338 }
301 339
302 #[test] 340 #[test]
303 fn test_fn_signature_no_params() { 341 fn test_fn_signature_no_params() {
304 let info = call_info( 342 check(
305 r#"fn foo<T>() -> T where T: Copy + Display {}
306fn bar() { foo(<|>); }"#,
307 );
308
309 assert!(info.parameters().is_empty());
310 assert_eq!(
311 info.label(),
312 r#" 343 r#"
313fn foo<T>() -> T 344fn foo<T>() -> T where T: Copy + Display {}
314where T: Copy + Display 345fn bar() { foo(<|>); }
315 "# 346"#,
316 .trim() 347 expect![[r#"
348 fn foo() -> {unknown}
349 ()
350 "#]],
317 ); 351 );
318 assert!(info.active_parameter.is_none());
319 } 352 }
320 353
321 #[test] 354 #[test]
322 fn test_fn_signature_for_impl() { 355 fn test_fn_signature_for_impl() {
323 let info = call_info( 356 check(
324 r#"struct F; impl F { pub fn new() { F{}} } 357 r#"
325fn bar() {let _ : F = F::new(<|>);}"#, 358struct F;
359impl F { pub fn new() { } }
360fn bar() {
361 let _ : F = F::new(<|>);
362}
363"#,
364 expect![[r#"
365 fn new()
366 ()
367 "#]],
326 ); 368 );
327
328 assert!(info.parameters().is_empty());
329 assert_eq!(info.active_parameter, None);
330 } 369 }
331 370
332 #[test] 371 #[test]
333 fn test_fn_signature_for_method_self() { 372 fn test_fn_signature_for_method_self() {
334 let info = call_info( 373 check(
335 r#"struct F; 374 r#"
336impl F { 375struct S;
337 pub fn new() -> F{ 376impl S { pub fn do_it(&self) {} }
338 F{}
339 }
340
341 pub fn do_it(&self) {}
342}
343 377
344fn bar() { 378fn bar() {
345 let f : F = F::new(); 379 let s: S = S;
346 f.do_it(<|>); 380 s.do_it(<|>);
347}"#, 381}
382"#,
383 expect![[r#"
384 fn do_it(&self)
385 ()
386 "#]],
348 ); 387 );
349
350 assert_eq!(info.parameters(), ["&self"]);
351 assert_eq!(info.active_parameter, None);
352 } 388 }
353 389
354 #[test] 390 #[test]
355 fn test_fn_signature_for_method_with_arg() { 391 fn test_fn_signature_for_method_with_arg() {
356 let info = call_info( 392 check(
357 r#"struct F; 393 r#"
358impl F { 394struct S;
359 pub fn new() -> F{ 395impl S {
360 F{} 396 fn foo(&self, x: i32) {}
397}
398
399fn main() { S.foo(<|>); }
400"#,
401 expect![[r#"
402 fn foo(&self, x: i32)
403 (<x: i32>)
404 "#]],
405 );
361 } 406 }
362 407
363 pub fn do_it(&self, x: i32) {} 408 #[test]
409 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
410 check(
411 r#"
412struct S;
413impl S {
414 fn foo(&self, x: i32) {}
364} 415}
365 416
366fn bar() { 417fn main() { S::foo(<|>); }
367 let f : F = F::new(); 418"#,
368 f.do_it(<|>); 419 expect![[r#"
369}"#, 420 fn foo(self: &S, x: i32)
421 (<self: &S>, x: i32)
422 "#]],
370 ); 423 );
371
372 assert_eq!(info.parameters(), ["&self", "x: i32"]);
373 assert_eq!(info.active_parameter, Some(1));
374 } 424 }
375 425
376 #[test] 426 #[test]
377 fn test_fn_signature_with_docs_simple() { 427 fn test_fn_signature_with_docs_simple() {
378 let info = call_info( 428 check(
379 r#" 429 r#"
380/// test 430/// test
381// non-doc-comment 431// non-doc-comment
@@ -387,17 +437,18 @@ fn bar() {
387 let _ = foo(<|>); 437 let _ = foo(<|>);
388} 438}
389"#, 439"#,
440 expect![[r#"
441 test
442 ------
443 fn foo(j: u32) -> u32
444 (<j: u32>)
445 "#]],
390 ); 446 );
391
392 assert_eq!(info.parameters(), ["j: u32"]);
393 assert_eq!(info.active_parameter, Some(0));
394 assert_eq!(info.label(), "fn foo(j: u32) -> u32");
395 assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
396 } 447 }
397 448
398 #[test] 449 #[test]
399 fn test_fn_signature_with_docs() { 450 fn test_fn_signature_with_docs() {
400 let info = call_info( 451 check(
401 r#" 452 r#"
402/// Adds one to the number given. 453/// Adds one to the number given.
403/// 454///
@@ -415,31 +466,26 @@ pub fn add_one(x: i32) -> i32 {
415pub fn do() { 466pub fn do() {
416 add_one(<|> 467 add_one(<|>
417}"#, 468}"#,
418 ); 469 expect![[r##"
419 470 Adds one to the number given.
420 assert_eq!(info.parameters(), ["x: i32"]);
421 assert_eq!(info.active_parameter, Some(0));
422 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
423 assert_eq!(
424 info.doc().map(|it| it.into()),
425 Some(
426 r#"Adds one to the number given.
427 471
428# Examples 472 # Examples
429 473
430``` 474 ```
431let five = 5; 475 let five = 5;
432 476
433assert_eq!(6, my_crate::add_one(5)); 477 assert_eq!(6, my_crate::add_one(5));
434```"# 478 ```
435 .to_string() 479 ------
436 ) 480 fn add_one(x: i32) -> i32
481 (<x: i32>)
482 "##]],
437 ); 483 );
438 } 484 }
439 485
440 #[test] 486 #[test]
441 fn test_fn_signature_with_docs_impl() { 487 fn test_fn_signature_with_docs_impl() {
442 let info = call_info( 488 check(
443 r#" 489 r#"
444struct addr; 490struct addr;
445impl addr { 491impl addr {
@@ -460,32 +506,28 @@ impl addr {
460pub fn do_it() { 506pub fn do_it() {
461 addr {}; 507 addr {};
462 addr::add_one(<|>); 508 addr::add_one(<|>);
463}"#, 509}
464 ); 510"#,
465 511 expect![[r##"
466 assert_eq!(info.parameters(), ["x: i32"]); 512 Adds one to the number given.
467 assert_eq!(info.active_parameter, Some(0));
468 assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
469 assert_eq!(
470 info.doc().map(|it| it.into()),
471 Some(
472 r#"Adds one to the number given.
473 513
474# Examples 514 # Examples
475 515
476``` 516 ```
477let five = 5; 517 let five = 5;
478 518
479assert_eq!(6, my_crate::add_one(5)); 519 assert_eq!(6, my_crate::add_one(5));
480```"# 520 ```
481 .to_string() 521 ------
482 ) 522 fn add_one(x: i32) -> i32
523 (<x: i32>)
524 "##]],
483 ); 525 );
484 } 526 }
485 527
486 #[test] 528 #[test]
487 fn test_fn_signature_with_docs_from_actix() { 529 fn test_fn_signature_with_docs_from_actix() {
488 let info = call_info( 530 check(
489 r#" 531 r#"
490struct WriteHandler<E>; 532struct WriteHandler<E>;
491 533
@@ -509,101 +551,89 @@ impl<E> WriteHandler<E> {
509pub fn foo(mut r: WriteHandler<()>) { 551pub fn foo(mut r: WriteHandler<()>) {
510 r.finished(<|>); 552 r.finished(<|>);
511} 553}
512
513"#, 554"#,
514 ); 555 expect![[r#"
515 556 Method is called when writer finishes.
516 assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); 557
517 assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); 558 By default this method stops actor's `Context`.
518 assert_eq!(info.active_parameter, Some(1)); 559 ------
519 assert_eq!( 560 fn finished(&mut self, ctx: &mut {unknown})
520 info.doc().map(|it| it.into()), 561 (<ctx: &mut {unknown}>)
521 Some( 562 "#]],
522 r#"Method is called when writer finishes.
523
524By default this method stops actor's `Context`."#
525 .to_string()
526 )
527 ); 563 );
528 } 564 }
529 565
530 #[test] 566 #[test]
531 fn call_info_bad_offset() { 567 fn call_info_bad_offset() {
532 mark::check!(call_info_bad_offset); 568 mark::check!(call_info_bad_offset);
533 let (analysis, position) = analysis_and_position( 569 check(
534 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 570 r#"
535 fn bar() { foo <|> (3, ); }"#, 571fn foo(x: u32, y: u32) -> u32 {x + y}
572fn bar() { foo <|> (3, ); }
573"#,
574 expect![[""]],
536 ); 575 );
537 let call_info = analysis.call_info(position).unwrap();
538 assert!(call_info.is_none());
539 } 576 }
540 577
541 #[test] 578 #[test]
542 fn test_nested_method_in_lamba() { 579 fn test_nested_method_in_lambda() {
543 let info = call_info( 580 check(
544 r#"struct Foo; 581 r#"
545 582struct Foo;
546impl Foo { 583impl Foo { fn bar(&self, _: u32) { } }
547 fn bar(&self, _: u32) { }
548}
549 584
550fn bar(_: u32) { } 585fn bar(_: u32) { }
551 586
552fn main() { 587fn main() {
553 let foo = Foo; 588 let foo = Foo;
554 std::thread::spawn(move || foo.bar(<|>)); 589 std::thread::spawn(move || foo.bar(<|>));
555}"#, 590}
591"#,
592 expect![[r#"
593 fn bar(&self, _: u32)
594 (<_: u32>)
595 "#]],
556 ); 596 );
557
558 assert_eq!(info.parameters(), ["&self", "_: u32"]);
559 assert_eq!(info.active_parameter, Some(1));
560 assert_eq!(info.label(), "fn bar(&self, _: u32)");
561 } 597 }
562 598
563 #[test] 599 #[test]
564 fn works_for_tuple_structs() { 600 fn works_for_tuple_structs() {
565 let info = call_info( 601 check(
566 r#" 602 r#"
567/// A cool tuple struct 603/// A cool tuple struct
568struct TS(u32, i32); 604struct S(u32, i32);
569fn main() { 605fn main() {
570 let s = TS(0, <|>); 606 let s = S(0, <|>);
571}"#, 607}
608"#,
609 expect![[r#"
610 A cool tuple struct
611 ------
612 struct S(u32, i32)
613 (u32, <i32>)
614 "#]],
572 ); 615 );
573
574 assert_eq!(info.label(), "struct TS(u32, i32) -> TS");
575 assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string()));
576 assert_eq!(info.active_parameter, Some(1));
577 } 616 }
578 617
579 #[test] 618 #[test]
580 fn generic_struct() { 619 fn generic_struct() {
581 let info = call_info( 620 check(
582 r#" 621 r#"
583struct TS<T>(T); 622struct S<T>(T);
584fn main() { 623fn main() {
585 let s = TS(<|>); 624 let s = S(<|>);
586}"#, 625}
587 ); 626"#,
588 627 expect![[r#"
589 assert_eq!(info.label(), "struct TS<T>(T) -> TS"); 628 struct S({unknown})
590 assert_eq!(info.active_parameter, Some(0)); 629 (<{unknown}>)
591 } 630 "#]],
592
593 #[test]
594 fn cant_call_named_structs() {
595 no_call_info(
596 r#"
597struct TS { x: u32, y: i32 }
598fn main() {
599 let s = TS(<|>);
600}"#,
601 ); 631 );
602 } 632 }
603 633
604 #[test] 634 #[test]
605 fn works_for_enum_variants() { 635 fn works_for_enum_variants() {
606 let info = call_info( 636 check(
607 r#" 637 r#"
608enum E { 638enum E {
609 /// A Variant 639 /// A Variant
@@ -617,17 +647,32 @@ enum E {
617fn main() { 647fn main() {
618 let a = E::A(<|>); 648 let a = E::A(<|>);
619} 649}
620 "#, 650"#,
651 expect![[r#"
652 A Variant
653 ------
654 enum E::A(i32)
655 (<i32>)
656 "#]],
621 ); 657 );
658 }
622 659
623 assert_eq!(info.label(), "E::A(0: i32)"); 660 #[test]
624 assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); 661 fn cant_call_struct_record() {
625 assert_eq!(info.active_parameter, Some(0)); 662 check(
663 r#"
664struct S { x: u32, y: i32 }
665fn main() {
666 let s = S(<|>);
667}
668"#,
669 expect![[""]],
670 );
626 } 671 }
627 672
628 #[test] 673 #[test]
629 fn cant_call_enum_records() { 674 fn cant_call_enum_record() {
630 no_call_info( 675 check(
631 r#" 676 r#"
632enum E { 677enum E {
633 /// A Variant 678 /// A Variant
@@ -641,47 +686,57 @@ enum E {
641fn main() { 686fn main() {
642 let a = E::C(<|>); 687 let a = E::C(<|>);
643} 688}
644 "#, 689"#,
690 expect![[""]],
645 ); 691 );
646 } 692 }
647 693
648 #[test] 694 #[test]
649 fn fn_signature_for_macro() { 695 fn fn_signature_for_call_in_macro() {
650 let info = call_info( 696 check(
651 r#" 697 r#"
652/// empty macro 698macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
653macro_rules! foo { 699fn foo() { }
654 () => {} 700id! {
701 fn bar() { foo(<|>); }
655} 702}
703"#,
704 expect![[r#"
705 fn foo()
706 ()
707 "#]],
708 );
709 }
656 710
657fn f() { 711 #[test]
658 foo!(<|>); 712 fn call_info_for_lambdas() {
713 check(
714 r#"
715struct S;
716fn foo(s: S) -> i32 { 92 }
717fn main() {
718 (|s| foo(s))(<|>)
659} 719}
660 "#, 720 "#,
661 ); 721 expect![[r#"
662 722 (S) -> i32
663 assert_eq!(info.label(), "foo!()"); 723 (<S>)
664 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 724 "#]],
725 )
665 } 726 }
666 727
667 #[test] 728 #[test]
668 fn fn_signature_for_call_in_macro() { 729 fn call_info_for_fn_ptr() {
669 let info = call_info( 730 check(
670 r#" 731 r#"
671 macro_rules! id { 732fn main(f: fn(i32, f64) -> char) {
672 ($($tt:tt)*) => { $($tt)* } 733 f(0, <|>)
673 } 734}
674 fn foo() { 735 "#,
675 736 expect![[r#"
676 } 737 (i32, f64) -> char
677 id! { 738 (i32, <f64>)
678 fn bar() { 739 "#]],
679 foo(<|>); 740 )
680 }
681 }
682 "#,
683 );
684
685 assert_eq!(info.label(), "fn foo()");
686 } 741 }
687} 742}
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index e1fcf379d..68ac05e4c 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -2,6 +2,9 @@ mod completion_config;
2mod completion_item; 2mod completion_item;
3mod completion_context; 3mod completion_context;
4mod presentation; 4mod presentation;
5mod patterns;
6#[cfg(test)]
7mod test_utils;
5 8
6mod complete_attribute; 9mod complete_attribute;
7mod complete_dot; 10mod complete_dot;
@@ -15,9 +18,6 @@ mod complete_unqualified_path;
15mod complete_postfix; 18mod complete_postfix;
16mod complete_macro_in_item_position; 19mod complete_macro_in_item_position;
17mod complete_trait_impl; 20mod complete_trait_impl;
18mod patterns;
19#[cfg(test)]
20mod test_utils;
21 21
22use ra_ide_db::RootDatabase; 22use ra_ide_db::RootDatabase;
23 23
@@ -63,11 +63,11 @@ pub use crate::completion::{
63// There also snippet completions: 63// There also snippet completions:
64// 64//
65// .Expressions 65// .Expressions
66// - `pd` -> `println!("{:?}")` 66// - `pd` -> `eprintln!(" = {:?}", );`
67// - `ppd` -> `println!("{:#?}")` 67// - `ppd` -> `eprintln!(" = {:#?}", );`
68// 68//
69// .Items 69// .Items
70// - `tfn` -> `#[test] fn f(){}` 70// - `tfn` -> `#[test] fn feature(){}`
71// - `tmod` -> 71// - `tmod` ->
72// ```rust 72// ```rust
73// #[cfg(test)] 73// #[cfg(test)]
@@ -75,7 +75,7 @@ pub use crate::completion::{
75// use super::*; 75// use super::*;
76// 76//
77// #[test] 77// #[test]
78// fn test_fn() {} 78// fn test_name() {}
79// } 79// }
80// ``` 80// ```
81 81
@@ -137,8 +137,8 @@ mod tests {
137 documentation: &'a str, 137 documentation: &'a str,
138 } 138 }
139 139
140 fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { 140 fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
141 let (analysis, position) = analysis_and_position(fixture); 141 let (analysis, position) = analysis_and_position(ra_fixture);
142 let config = CompletionConfig::default(); 142 let config = CompletionConfig::default();
143 let completions = analysis.completions(&config, position).unwrap().unwrap(); 143 let completions = analysis.completions(&config, position).unwrap().unwrap();
144 for item in completions { 144 for item in completions {
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs
index 6beeca457..2faaae974 100644
--- a/crates/ra_ide/src/completion/complete_attribute.rs
+++ b/crates/ra_ide/src/completion/complete_attribute.rs
@@ -13,14 +13,18 @@ use crate::completion::{
13 13
14pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 14pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
15 let attribute = ctx.attribute_under_caret.as_ref()?; 15 let attribute = ctx.attribute_under_caret.as_ref()?;
16 16 match (attribute.path(), attribute.token_tree()) {
17 match (attribute.path(), attribute.input()) { 17 (Some(path), Some(token_tree)) if path.to_string() == "derive" => {
18 (Some(path), Some(ast::AttrInput::TokenTree(token_tree)))
19 if path.to_string() == "derive" =>
20 {
21 complete_derive(acc, ctx, token_tree) 18 complete_derive(acc, ctx, token_tree)
22 } 19 }
23 (_, Some(ast::AttrInput::TokenTree(_token_tree))) => {} 20 (Some(path), Some(token_tree))
21 if ["allow", "warn", "deny", "forbid"]
22 .iter()
23 .any(|lint_level| lint_level == &path.to_string()) =>
24 {
25 complete_lint(acc, ctx, token_tree)
26 }
27 (_, Some(_token_tree)) => {}
24 _ => complete_attribute_start(acc, ctx, attribute), 28 _ => complete_attribute_start(acc, ctx, attribute),
25 } 29 }
26 Some(()) 30 Some(())
@@ -46,7 +50,7 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
46 _ => {} 50 _ => {}
47 } 51 }
48 52
49 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.should_be_inner { 53 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
50 acc.add(item); 54 acc.add(item);
51 } 55 }
52 } 56 }
@@ -56,163 +60,76 @@ struct AttrCompletion {
56 label: &'static str, 60 label: &'static str,
57 lookup: Option<&'static str>, 61 lookup: Option<&'static str>,
58 snippet: Option<&'static str>, 62 snippet: Option<&'static str>,
59 should_be_inner: bool, 63 prefer_inner: bool,
64}
65
66impl AttrCompletion {
67 const fn prefer_inner(self) -> AttrCompletion {
68 AttrCompletion { prefer_inner: true, ..self }
69 }
70}
71
72const fn attr(
73 label: &'static str,
74 lookup: Option<&'static str>,
75 snippet: Option<&'static str>,
76) -> AttrCompletion {
77 AttrCompletion { label, lookup, snippet, prefer_inner: false }
60} 78}
61 79
62const ATTRIBUTES: &[AttrCompletion] = &[ 80const ATTRIBUTES: &[AttrCompletion] = &[
63 AttrCompletion { 81 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
64 label: "allow(…)", 82 attr("cfg_attr(…)", Some("cfg_attr"), Some("cfg_attr(${1:predicate}, ${0:attr})")),
65 snippet: Some("allow(${0:lint})"), 83 attr("cfg(…)", Some("cfg"), Some("cfg(${0:predicate})")),
66 should_be_inner: false, 84 attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
67 lookup: Some("allow"), 85 attr(r#"deprecated = "…""#, Some("deprecated"), Some(r#"deprecated = "${0:reason}""#)),
68 }, 86 attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
69 AttrCompletion { 87 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
70 label: "cfg_attr(…)", 88 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
71 snippet: Some("cfg_attr(${1:predicate}, ${0:attr})"), 89 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
72 should_be_inner: false,
73 lookup: Some("cfg_attr"),
74 },
75 AttrCompletion {
76 label: "cfg(…)",
77 snippet: Some("cfg(${0:predicate})"),
78 should_be_inner: false,
79 lookup: Some("cfg"),
80 },
81 AttrCompletion {
82 label: "deny(…)",
83 snippet: Some("deny(${0:lint})"),
84 should_be_inner: false,
85 lookup: Some("deny"),
86 },
87 AttrCompletion {
88 label: r#"deprecated = "…""#,
89 snippet: Some(r#"deprecated = "${0:reason}""#),
90 should_be_inner: false,
91 lookup: Some("deprecated"),
92 },
93 AttrCompletion {
94 label: "derive(…)",
95 snippet: Some(r#"derive(${0:Debug})"#),
96 should_be_inner: false,
97 lookup: Some("derive"),
98 },
99 AttrCompletion {
100 label: r#"doc = "…""#,
101 snippet: Some(r#"doc = "${0:docs}""#),
102 should_be_inner: false,
103 lookup: Some("doc"),
104 },
105 AttrCompletion {
106 label: "feature(…)",
107 snippet: Some("feature(${0:flag})"),
108 should_be_inner: true,
109 lookup: Some("feature"),
110 },
111 AttrCompletion {
112 label: "forbid(…)",
113 snippet: Some("forbid(${0:lint})"),
114 should_be_inner: false,
115 lookup: Some("forbid"),
116 },
117 // FIXME: resolve through macro resolution? 90 // FIXME: resolve through macro resolution?
118 AttrCompletion { 91 attr("global_allocator", None, None).prefer_inner(),
119 label: "global_allocator", 92 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
120 snippet: None, 93 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")),
121 should_be_inner: true, 94 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
122 lookup: None, 95 attr("link", None, None),
123 }, 96 attr("macro_export", None, None),
124 AttrCompletion { 97 attr("macro_use", None, None),
125 label: "ignore(…)", 98 attr(r#"must_use = "…""#, Some("must_use"), Some(r#"must_use = "${0:reason}""#)),
126 snippet: Some("ignore(${0:lint})"), 99 attr("no_mangle", None, None),
127 should_be_inner: false, 100 attr("no_std", None, None).prefer_inner(),
128 lookup: Some("ignore"), 101 attr("non_exhaustive", None, None),
129 }, 102 attr("panic_handler", None, None).prefer_inner(),
130 AttrCompletion { 103 attr("path = \"…\"", Some("path"), Some("path =\"${0:path}\"")),
131 label: "inline(…)", 104 attr("proc_macro", None, None),
132 snippet: Some("inline(${0:lint})"), 105 attr("proc_macro_attribute", None, None),
133 should_be_inner: false, 106 attr("proc_macro_derive(…)", Some("proc_macro_derive"), Some("proc_macro_derive(${0:Trait})")),
134 lookup: Some("inline"), 107 attr("recursion_limit = …", Some("recursion_limit"), Some("recursion_limit = ${0:128}"))
135 }, 108 .prefer_inner(),
136 AttrCompletion { 109 attr("repr(…)", Some("repr"), Some("repr(${0:C})")),
137 label: r#"link_name = "…""#, 110 attr(
138 snippet: Some(r#"link_name = "${0:symbol_name}""#), 111 "should_panic(…)",
139 should_be_inner: false, 112 Some("should_panic"),
140 lookup: Some("link_name"), 113 Some(r#"should_panic(expected = "${0:reason}")"#),
141 }, 114 ),
142 AttrCompletion { label: "link", snippet: None, should_be_inner: false, lookup: None }, 115 attr(
143 AttrCompletion { label: "macro_export", snippet: None, should_be_inner: false, lookup: None }, 116 r#"target_feature = "…""#,
144 AttrCompletion { label: "macro_use", snippet: None, should_be_inner: false, lookup: None }, 117 Some("target_feature"),
145 AttrCompletion { 118 Some("target_feature = \"${0:feature}\""),
146 label: r#"must_use = "…""#, 119 ),
147 snippet: Some(r#"must_use = "${0:reason}""#), 120 attr("test", None, None),
148 should_be_inner: false, 121 attr("used", None, None),
149 lookup: Some("must_use"), 122 attr("warn(…)", Some("warn"), Some("warn(${0:lint})")),
150 }, 123 attr(
151 AttrCompletion { label: "no_mangle", snippet: None, should_be_inner: false, lookup: None }, 124 r#"windows_subsystem = "…""#,
152 AttrCompletion { label: "no_std", snippet: None, should_be_inner: true, lookup: None }, 125 Some("windows_subsystem"),
153 AttrCompletion { label: "non_exhaustive", snippet: None, should_be_inner: false, lookup: None }, 126 Some(r#"windows_subsystem = "${0:subsystem}""#),
154 AttrCompletion { label: "panic_handler", snippet: None, should_be_inner: true, lookup: None }, 127 )
155 AttrCompletion { 128 .prefer_inner(),
156 label: "path = \"…\"",
157 snippet: Some("path =\"${0:path}\""),
158 should_be_inner: false,
159 lookup: Some("path"),
160 },
161 AttrCompletion { label: "proc_macro", snippet: None, should_be_inner: false, lookup: None },
162 AttrCompletion {
163 label: "proc_macro_attribute",
164 snippet: None,
165 should_be_inner: false,
166 lookup: None,
167 },
168 AttrCompletion {
169 label: "proc_macro_derive(…)",
170 snippet: Some("proc_macro_derive(${0:Trait})"),
171 should_be_inner: false,
172 lookup: Some("proc_macro_derive"),
173 },
174 AttrCompletion {
175 label: "recursion_limit = …",
176 snippet: Some("recursion_limit = ${0:128}"),
177 should_be_inner: true,
178 lookup: Some("recursion_limit"),
179 },
180 AttrCompletion {
181 label: "repr(…)",
182 snippet: Some("repr(${0:C})"),
183 should_be_inner: false,
184 lookup: Some("repr"),
185 },
186 AttrCompletion {
187 label: "should_panic(…)",
188 snippet: Some(r#"should_panic(expected = "${0:reason}")"#),
189 should_be_inner: false,
190 lookup: Some("should_panic"),
191 },
192 AttrCompletion {
193 label: r#"target_feature = "…""#,
194 snippet: Some("target_feature = \"${0:feature}\""),
195 should_be_inner: false,
196 lookup: Some("target_feature"),
197 },
198 AttrCompletion { label: "test", snippet: None, should_be_inner: false, lookup: None },
199 AttrCompletion { label: "used", snippet: None, should_be_inner: false, lookup: None },
200 AttrCompletion {
201 label: "warn(…)",
202 snippet: Some("warn(${0:lint})"),
203 should_be_inner: false,
204 lookup: Some("warn"),
205 },
206 AttrCompletion {
207 label: r#"windows_subsystem = "…""#,
208 snippet: Some(r#"windows_subsystem = "${0:subsystem}""#),
209 should_be_inner: true,
210 lookup: Some("windows_subsystem"),
211 },
212]; 129];
213 130
214fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) { 131fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
215 if let Ok(existing_derives) = parse_derive_input(derive_input) { 132 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) {
216 for derive_completion in DEFAULT_DERIVE_COMPLETIONS 133 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
217 .into_iter() 134 .into_iter()
218 .filter(|completion| !existing_derives.contains(completion.label)) 135 .filter(|completion| !existing_derives.contains(completion.label))
@@ -245,7 +162,26 @@ fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input:
245 } 162 }
246} 163}
247 164
248fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { 165fn complete_lint(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
166 if let Ok(existing_lints) = parse_comma_sep_input(derive_input) {
167 for lint_completion in DEFAULT_LINT_COMPLETIONS
168 .into_iter()
169 .filter(|completion| !existing_lints.contains(completion.label))
170 {
171 acc.add(
172 CompletionItem::new(
173 CompletionKind::Attribute,
174 ctx.source_range(),
175 lint_completion.label,
176 )
177 .kind(CompletionItemKind::Attribute)
178 .detail(lint_completion.description),
179 );
180 }
181 }
182}
183
184fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
249 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { 185 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
250 (Some(left_paren), Some(right_paren)) 186 (Some(left_paren), Some(right_paren))
251 if left_paren.kind() == SyntaxKind::L_PAREN 187 if left_paren.kind() == SyntaxKind::L_PAREN
@@ -282,7 +218,7 @@ fn parse_derive_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>,
282 218
283fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 219fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
284 let mut result = FxHashSet::default(); 220 let mut result = FxHashSet::default();
285 ctx.scope().process_all_names(&mut |name, scope_def| { 221 ctx.scope.process_all_names(&mut |name, scope_def| {
286 if let hir::ScopeDef::MacroDef(mac) = scope_def { 222 if let hir::ScopeDef::MacroDef(mac) = scope_def {
287 if mac.is_derive_macro() { 223 if mac.is_derive_macro() {
288 result.insert(name.to_string()); 224 result.insert(name.to_string());
@@ -299,6 +235,7 @@ struct DeriveCompletion {
299 235
300/// Standard Rust derives and the information about their dependencies 236/// Standard Rust derives and the information about their dependencies
301/// (the dependencies are needed so that the main derive don't break the compilation when added) 237/// (the dependencies are needed so that the main derive don't break the compilation when added)
238#[rustfmt::skip]
302const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ 239const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
303 DeriveCompletion { label: "Clone", dependencies: &[] }, 240 DeriveCompletion { label: "Clone", dependencies: &[] },
304 DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, 241 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
@@ -311,679 +248,397 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
311 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, 248 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
312]; 249];
313 250
251struct LintCompletion {
252 label: &'static str,
253 description: &'static str,
254}
255
256#[rustfmt::skip]
257const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
258 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
259 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
260 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
261 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
262 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
263 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
264 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
265 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
266 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
267 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
268 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
269 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
270 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
271 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
272 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
273 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
274 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
275 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
276 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
277 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
278 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
279 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
280 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
281 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
282 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
283 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
284 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
285 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
286 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
287 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
288 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
289 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
290 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
291 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
292 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
293 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
294 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
295 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
296 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
297 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
298 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
299 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
300 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
301 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
302 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
303 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
304 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
305 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
306 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
307 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
308 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
309 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
310 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
311 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
312 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
313 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
314 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
315 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
316 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
317 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
318 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
319 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
320 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
321 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
322 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
323 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
324 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
325 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
326 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
327 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
328 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
329 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
330 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
331 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
332 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
333 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
334 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
335 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
336 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
337 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
338 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
339 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
340 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
341 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
342 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
343 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
344 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
345 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
346 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
347 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
348 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
349 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
350 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
351 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
352 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
353 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
354 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
355 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
356 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
357 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
358 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
359 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
360 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
361 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
362 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
363 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
364 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
365 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
366 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
367 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
368 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
369 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
370 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
371 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
372 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
373];
374
314#[cfg(test)] 375#[cfg(test)]
315mod tests { 376mod tests {
316 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 377 use expect::{expect, Expect};
317 use insta::assert_debug_snapshot;
318 378
319 fn do_attr_completion(code: &str) -> Vec<CompletionItem> { 379 use crate::completion::{test_utils::completion_list, CompletionKind};
320 do_completion(code, CompletionKind::Attribute) 380
381 fn check(ra_fixture: &str, expect: Expect) {
382 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
383 expect.assert_eq(&actual);
321 } 384 }
322 385
323 #[test] 386 #[test]
324 fn empty_derive_completion() { 387 fn empty_derive_completion() {
325 assert_debug_snapshot!( 388 check(
326 do_attr_completion( 389 r#"
327 r" 390#[derive(<|>)]
328 #[derive(<|>)] 391struct Test {}
329 struct Test {} 392 "#,
330 ", 393 expect![[r#"
331 ), 394 at Clone
332 @r###" 395 at Copy, Clone
333 [ 396 at Debug
334 CompletionItem { 397 at Default
335 label: "Clone", 398 at Eq, PartialEq
336 source_range: 9..9, 399 at Hash
337 delete: 9..9, 400 at Ord, PartialOrd, Eq, PartialEq
338 insert: "Clone", 401 at PartialEq
339 kind: Attribute, 402 at PartialOrd, PartialEq
340 }, 403 "#]],
341 CompletionItem {
342 label: "Copy, Clone",
343 source_range: 9..9,
344 delete: 9..9,
345 insert: "Copy, Clone",
346 kind: Attribute,
347 },
348 CompletionItem {
349 label: "Debug",
350 source_range: 9..9,
351 delete: 9..9,
352 insert: "Debug",
353 kind: Attribute,
354 },
355 CompletionItem {
356 label: "Default",
357 source_range: 9..9,
358 delete: 9..9,
359 insert: "Default",
360 kind: Attribute,
361 },
362 CompletionItem {
363 label: "Eq, PartialEq",
364 source_range: 9..9,
365 delete: 9..9,
366 insert: "Eq, PartialEq",
367 kind: Attribute,
368 },
369 CompletionItem {
370 label: "Hash",
371 source_range: 9..9,
372 delete: 9..9,
373 insert: "Hash",
374 kind: Attribute,
375 },
376 CompletionItem {
377 label: "Ord, PartialOrd, Eq, PartialEq",
378 source_range: 9..9,
379 delete: 9..9,
380 insert: "Ord, PartialOrd, Eq, PartialEq",
381 kind: Attribute,
382 },
383 CompletionItem {
384 label: "PartialEq",
385 source_range: 9..9,
386 delete: 9..9,
387 insert: "PartialEq",
388 kind: Attribute,
389 },
390 CompletionItem {
391 label: "PartialOrd, PartialEq",
392 source_range: 9..9,
393 delete: 9..9,
394 insert: "PartialOrd, PartialEq",
395 kind: Attribute,
396 },
397 ]
398 "###
399 ); 404 );
400 } 405 }
401 406
402 #[test] 407 #[test]
408 fn empty_lint_completion() {
409 check(
410 r#"#[allow(<|>)]"#,
411 expect![[r#"
412 at absolute_paths_not_starting_with_crate fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
413 at ambiguous_associated_items ambiguous associated items
414 at anonymous_parameters detects anonymous parameters
415 at arithmetic_overflow arithmetic operation overflows
416 at array_into_iter detects calling `into_iter` on arrays
417 at asm_sub_register using only a subset of a register for inline asm inputs
418 at bare_trait_objects suggest using `dyn Trait` for trait objects
419 at bindings_with_variant_name detects pattern bindings with the same name as one of the matched variants
420 at box_pointers use of owned (Box type) heap memory
421 at cenum_impl_drop_cast a C-like enum implementing Drop is cast
422 at clashing_extern_declarations detects when an extern fn has been declared with the same name but different types
423 at coherence_leak_check distinct impls distinguished only by the leak-check code
424 at conflicting_repr_hints conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
425 at confusable_idents detects visually confusable pairs between identifiers
426 at const_err constant evaluation detected erroneous expression
427 at dead_code detect unused, unexported items
428 at deprecated detects use of deprecated items
429 at deprecated_in_future detects use of items that will be deprecated in a future version
430 at elided_lifetimes_in_paths hidden lifetime parameters in types are deprecated
431 at ellipsis_inclusive_range_patterns `...` range patterns are deprecated
432 at explicit_outlives_requirements outlives requirements can be inferred
433 at exported_private_dependencies public interface leaks type from a private dependency
434 at ill_formed_attribute_input ill-formed attribute inputs that were previously accepted and used in practice
435 at illegal_floating_point_literal_pattern floating-point literals cannot be used in patterns
436 at improper_ctypes proper use of libc types in foreign modules
437 at improper_ctypes_definitions proper use of libc types in foreign item definitions
438 at incomplete_features incomplete features that may function improperly in some or all cases
439 at incomplete_include trailing content in included file
440 at indirect_structural_match pattern with const indirectly referencing non-structural-match type
441 at inline_no_sanitize detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
442 at intra_doc_link_resolution_failure failures in resolving intra-doc link targets
443 at invalid_codeblock_attributes codeblock attribute looks a lot like a known one
444 at invalid_type_param_default type parameter default erroneously allowed in invalid location
445 at invalid_value an invalid value is being created (such as a NULL reference)
446 at irrefutable_let_patterns detects irrefutable patterns in if-let and while-let statements
447 at keyword_idents detects edition keywords being used as an identifier
448 at late_bound_lifetime_arguments detects generic lifetime arguments in path segments with late bound lifetime parameters
449 at macro_expanded_macro_exports_accessed_by_absolute_paths macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
450 at macro_use_extern_crate the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
451 at meta_variable_misuse possible meta-variable misuse at macro definition
452 at missing_copy_implementations detects potentially-forgotten implementations of `Copy`
453 at missing_crate_level_docs detects crates with no crate-level documentation
454 at missing_debug_implementations detects missing implementations of Debug
455 at missing_doc_code_examples detects publicly-exported items without code samples in their documentation
456 at missing_docs detects missing documentation for public members
457 at missing_fragment_specifier detects missing fragment specifiers in unused `macro_rules!` patterns
458 at mixed_script_confusables detects Unicode scripts whose mixed script confusables codepoints are solely used
459 at mutable_borrow_reservation_conflict reservation of a two-phased borrow conflicts with other shared borrows
460 at mutable_transmutes mutating transmuted &mut T from &T may cause undefined behavior
461 at no_mangle_const_items const items will not have their symbols exported
462 at no_mangle_generic_items generic items must be mangled
463 at non_ascii_idents detects non-ASCII identifiers
464 at non_camel_case_types types, variants, traits and type parameters should have camel case names
465 at non_shorthand_field_patterns using `Struct { x: x }` instead of `Struct { x }` in a pattern
466 at non_snake_case variables, methods, functions, lifetime parameters and modules should have snake case names
467 at non_upper_case_globals static constants should have uppercase identifiers
468 at order_dependent_trait_objects trait-object types were treated as different depending on marker-trait order
469 at overflowing_literals literal out of range for its type
470 at overlapping_patterns detects overlapping patterns
471 at path_statements path statements with no effect
472 at patterns_in_fns_without_body patterns in functions without body were erroneously allowed
473 at private_doc_tests detects code samples in docs of private items not documented by rustdoc
474 at private_in_public detect private items in public interfaces not caught by the old implementation
475 at proc_macro_derive_resolution_fallback detects proc macro derives using inaccessible names from parent modules
476 at pub_use_of_private_extern_crate detect public re-exports of private extern crates
477 at redundant_semicolons detects unnecessary trailing semicolons
478 at renamed_and_removed_lints lints that have been renamed or removed
479 at safe_packed_borrows safe borrows of fields of packed structs were erroneously allowed
480 at single_use_lifetimes detects lifetime parameters that are only used once
481 at soft_unstable a feature gate that doesn't break dependent crates
482 at stable_features stable features found in `#[feature]` directive
483 at trivial_bounds these bounds don't depend on an type parameters
484 at trivial_casts detects trivial casts which could be removed
485 at trivial_numeric_casts detects trivial casts of numeric types which could be removed
486 at type_alias_bounds bounds in type aliases are not enforced
487 at tyvar_behind_raw_pointer raw pointer to an inference variable
488 at unaligned_references detects unaligned references to fields of packed structs
489 at uncommon_codepoints detects uncommon Unicode codepoints in identifiers
490 at unconditional_panic operation will cause a panic at runtime
491 at unconditional_recursion functions that cannot return without calling themselves
492 at unknown_crate_types unknown crate type found in `#[crate_type]` directive
493 at unknown_lints unrecognized lint attribute
494 at unnameable_test_items detects an item that cannot be named being marked as `#[test_case]`
495 at unreachable_code detects unreachable code paths
496 at unreachable_patterns detects unreachable patterns
497 at unreachable_pub `pub` items not reachable from crate root
498 at unsafe_code usage of `unsafe` code
499 at unsafe_op_in_unsafe_fn unsafe operations in unsafe functions without an explicit unsafe block are deprecated
500 at unstable_features enabling unstable features (deprecated. do not use)
501 at unstable_name_collisions detects name collision with an existing but unstable method
502 at unused_allocation detects unnecessary allocations that can be eliminated
503 at unused_assignments detect assignments that will never be read
504 at unused_attributes detects attributes that were not used by the compiler
505 at unused_braces unnecessary braces around an expression
506 at unused_comparisons comparisons made useless by limits of the types involved
507 at unused_crate_dependencies crate dependencies that are never used
508 at unused_doc_comments detects doc comments that aren't used by rustdoc
509 at unused_extern_crates extern crates that are never used
510 at unused_features unused features found in crate-level `#[feature]` directives
511 at unused_import_braces unnecessary braces around an imported item
512 at unused_imports imports that are never used
513 at unused_labels detects labels that are never used
514 at unused_lifetimes detects lifetime parameters that are never used
515 at unused_macros detects macros that were not used
516 at unused_must_use unused result of a type flagged as `#[must_use]`
517 at unused_mut detect mut variables which don't need to be mutable
518 at unused_parens `if`, `match`, `while` and `return` do not need parentheses
519 at unused_qualifications detects unnecessarily qualified names
520 at unused_results unused result of an expression in a statement
521 at unused_unsafe unnecessary use of an `unsafe` block
522 at unused_variables detect variables which are not used in any way
523 at variant_size_differences detects enums with widely varying variant sizes
524 at warnings mass-change the level for lints which produce warnings
525 at where_clauses_object_safety checks the object safety of where clauses
526 at while_true suggest using `loop { }` instead of `while true { }`
527 "#]],
528 )
529 }
530
531 #[test]
403 fn no_completion_for_incorrect_derive() { 532 fn no_completion_for_incorrect_derive() {
404 assert_debug_snapshot!( 533 check(
405 do_attr_completion( 534 r#"
406 r" 535#[derive{<|>)]
407 #[derive{<|>)] 536struct Test {}
408 struct Test {} 537"#,
409 ", 538 expect![[r#""#]],
410 ), 539 )
411 @"[]"
412 );
413 } 540 }
414 541
415 #[test] 542 #[test]
416 fn derive_with_input_completion() { 543 fn derive_with_input_completion() {
417 assert_debug_snapshot!( 544 check(
418 do_attr_completion( 545 r#"
419 r" 546#[derive(serde::Serialize, PartialEq, <|>)]
420 #[derive(serde::Serialize, PartialEq, <|>)] 547struct Test {}
421 struct Test {} 548"#,
422 ", 549 expect![[r#"
423 ), 550 at Clone
424 @r###" 551 at Copy, Clone
425 [ 552 at Debug
426 CompletionItem { 553 at Default
427 label: "Clone", 554 at Eq
428 source_range: 38..38, 555 at Hash
429 delete: 38..38, 556 at Ord, PartialOrd, Eq
430 insert: "Clone", 557 at PartialOrd
431 kind: Attribute, 558 "#]],
432 }, 559 )
433 CompletionItem {
434 label: "Copy, Clone",
435 source_range: 38..38,
436 delete: 38..38,
437 insert: "Copy, Clone",
438 kind: Attribute,
439 },
440 CompletionItem {
441 label: "Debug",
442 source_range: 38..38,
443 delete: 38..38,
444 insert: "Debug",
445 kind: Attribute,
446 },
447 CompletionItem {
448 label: "Default",
449 source_range: 38..38,
450 delete: 38..38,
451 insert: "Default",
452 kind: Attribute,
453 },
454 CompletionItem {
455 label: "Eq",
456 source_range: 38..38,
457 delete: 38..38,
458 insert: "Eq",
459 kind: Attribute,
460 },
461 CompletionItem {
462 label: "Hash",
463 source_range: 38..38,
464 delete: 38..38,
465 insert: "Hash",
466 kind: Attribute,
467 },
468 CompletionItem {
469 label: "Ord, PartialOrd, Eq",
470 source_range: 38..38,
471 delete: 38..38,
472 insert: "Ord, PartialOrd, Eq",
473 kind: Attribute,
474 },
475 CompletionItem {
476 label: "PartialOrd",
477 source_range: 38..38,
478 delete: 38..38,
479 insert: "PartialOrd",
480 kind: Attribute,
481 },
482 ]
483 "###
484 );
485 } 560 }
486 561
487 #[test] 562 #[test]
488 fn test_attribute_completion() { 563 fn test_attribute_completion() {
489 assert_debug_snapshot!( 564 check(
490 do_attr_completion( 565 r#"#[<|>]"#,
491 r" 566 expect![[r#"
492 #[<|>] 567 at allow(…)
493 ", 568 at cfg(…)
494 ), 569 at cfg_attr(…)
495 @r###" 570 at deny(…)
496 [ 571 at deprecated = "…"
497 CompletionItem { 572 at derive(…)
498 label: "allow(…)", 573 at doc = "…"
499 source_range: 2..2, 574 at forbid(…)
500 delete: 2..2, 575 at ignore = "…"
501 insert: "allow(${0:lint})", 576 at inline(…)
502 kind: Attribute, 577 at link
503 lookup: "allow", 578 at link_name = "…"
504 }, 579 at macro_export
505 CompletionItem { 580 at macro_use
506 label: "cfg(…)", 581 at must_use = "…"
507 source_range: 2..2, 582 at no_mangle
508 delete: 2..2, 583 at non_exhaustive
509 insert: "cfg(${0:predicate})", 584 at path = "…"
510 kind: Attribute, 585 at proc_macro
511 lookup: "cfg", 586 at proc_macro_attribute
512 }, 587 at proc_macro_derive(…)
513 CompletionItem { 588 at repr(…)
514 label: "cfg_attr(…)", 589 at should_panic(…)
515 source_range: 2..2, 590 at target_feature = "…"
516 delete: 2..2, 591 at test
517 insert: "cfg_attr(${1:predicate}, ${0:attr})", 592 at used
518 kind: Attribute, 593 at warn(…)
519 lookup: "cfg_attr", 594 "#]],
520 }, 595 )
521 CompletionItem {
522 label: "deny(…)",
523 source_range: 2..2,
524 delete: 2..2,
525 insert: "deny(${0:lint})",
526 kind: Attribute,
527 lookup: "deny",
528 },
529 CompletionItem {
530 label: "deprecated = \"…\"",
531 source_range: 2..2,
532 delete: 2..2,
533 insert: "deprecated = \"${0:reason}\"",
534 kind: Attribute,
535 lookup: "deprecated",
536 },
537 CompletionItem {
538 label: "derive(…)",
539 source_range: 2..2,
540 delete: 2..2,
541 insert: "derive(${0:Debug})",
542 kind: Attribute,
543 lookup: "derive",
544 },
545 CompletionItem {
546 label: "doc = \"…\"",
547 source_range: 2..2,
548 delete: 2..2,
549 insert: "doc = \"${0:docs}\"",
550 kind: Attribute,
551 lookup: "doc",
552 },
553 CompletionItem {
554 label: "forbid(…)",
555 source_range: 2..2,
556 delete: 2..2,
557 insert: "forbid(${0:lint})",
558 kind: Attribute,
559 lookup: "forbid",
560 },
561 CompletionItem {
562 label: "ignore(…)",
563 source_range: 2..2,
564 delete: 2..2,
565 insert: "ignore(${0:lint})",
566 kind: Attribute,
567 lookup: "ignore",
568 },
569 CompletionItem {
570 label: "inline(…)",
571 source_range: 2..2,
572 delete: 2..2,
573 insert: "inline(${0:lint})",
574 kind: Attribute,
575 lookup: "inline",
576 },
577 CompletionItem {
578 label: "link",
579 source_range: 2..2,
580 delete: 2..2,
581 insert: "link",
582 kind: Attribute,
583 },
584 CompletionItem {
585 label: "link_name = \"…\"",
586 source_range: 2..2,
587 delete: 2..2,
588 insert: "link_name = \"${0:symbol_name}\"",
589 kind: Attribute,
590 lookup: "link_name",
591 },
592 CompletionItem {
593 label: "macro_export",
594 source_range: 2..2,
595 delete: 2..2,
596 insert: "macro_export",
597 kind: Attribute,
598 },
599 CompletionItem {
600 label: "macro_use",
601 source_range: 2..2,
602 delete: 2..2,
603 insert: "macro_use",
604 kind: Attribute,
605 },
606 CompletionItem {
607 label: "must_use = \"…\"",
608 source_range: 2..2,
609 delete: 2..2,
610 insert: "must_use = \"${0:reason}\"",
611 kind: Attribute,
612 lookup: "must_use",
613 },
614 CompletionItem {
615 label: "no_mangle",
616 source_range: 2..2,
617 delete: 2..2,
618 insert: "no_mangle",
619 kind: Attribute,
620 },
621 CompletionItem {
622 label: "non_exhaustive",
623 source_range: 2..2,
624 delete: 2..2,
625 insert: "non_exhaustive",
626 kind: Attribute,
627 },
628 CompletionItem {
629 label: "path = \"…\"",
630 source_range: 2..2,
631 delete: 2..2,
632 insert: "path =\"${0:path}\"",
633 kind: Attribute,
634 lookup: "path",
635 },
636 CompletionItem {
637 label: "proc_macro",
638 source_range: 2..2,
639 delete: 2..2,
640 insert: "proc_macro",
641 kind: Attribute,
642 },
643 CompletionItem {
644 label: "proc_macro_attribute",
645 source_range: 2..2,
646 delete: 2..2,
647 insert: "proc_macro_attribute",
648 kind: Attribute,
649 },
650 CompletionItem {
651 label: "proc_macro_derive(…)",
652 source_range: 2..2,
653 delete: 2..2,
654 insert: "proc_macro_derive(${0:Trait})",
655 kind: Attribute,
656 lookup: "proc_macro_derive",
657 },
658 CompletionItem {
659 label: "repr(…)",
660 source_range: 2..2,
661 delete: 2..2,
662 insert: "repr(${0:C})",
663 kind: Attribute,
664 lookup: "repr",
665 },
666 CompletionItem {
667 label: "should_panic(…)",
668 source_range: 2..2,
669 delete: 2..2,
670 insert: "should_panic(expected = \"${0:reason}\")",
671 kind: Attribute,
672 lookup: "should_panic",
673 },
674 CompletionItem {
675 label: "target_feature = \"…\"",
676 source_range: 2..2,
677 delete: 2..2,
678 insert: "target_feature = \"${0:feature}\"",
679 kind: Attribute,
680 lookup: "target_feature",
681 },
682 CompletionItem {
683 label: "test",
684 source_range: 2..2,
685 delete: 2..2,
686 insert: "test",
687 kind: Attribute,
688 },
689 CompletionItem {
690 label: "used",
691 source_range: 2..2,
692 delete: 2..2,
693 insert: "used",
694 kind: Attribute,
695 },
696 CompletionItem {
697 label: "warn(…)",
698 source_range: 2..2,
699 delete: 2..2,
700 insert: "warn(${0:lint})",
701 kind: Attribute,
702 lookup: "warn",
703 },
704 ]
705 "###
706 );
707 } 596 }
708 597
709 #[test] 598 #[test]
710 fn test_attribute_completion_inside_nested_attr() { 599 fn test_attribute_completion_inside_nested_attr() {
711 assert_debug_snapshot!( 600 check(r#"#[cfg(<|>)]"#, expect![[]])
712 do_attr_completion(
713 r"
714 #[allow(<|>)]
715 ",
716 ),
717 @r###"
718 []
719 "###
720 );
721 } 601 }
722 602
723 #[test] 603 #[test]
724 fn test_inner_attribute_completion() { 604 fn test_inner_attribute_completion() {
725 assert_debug_snapshot!( 605 check(
726 do_attr_completion( 606 r"#![<|>]",
727 r" 607 expect![[r#"
728 #![<|>] 608 at allow(…)
729 ", 609 at cfg(…)
730 ), 610 at cfg_attr(…)
731 @r###" 611 at deny(…)
732 [ 612 at deprecated = "…"
733 CompletionItem { 613 at derive(…)
734 label: "allow(…)", 614 at doc = "…"
735 source_range: 3..3, 615 at feature(…)
736 delete: 3..3, 616 at forbid(…)
737 insert: "allow(${0:lint})", 617 at global_allocator
738 kind: Attribute, 618 at ignore = "…"
739 lookup: "allow", 619 at inline(…)
740 }, 620 at link
741 CompletionItem { 621 at link_name = "…"
742 label: "cfg(…)", 622 at macro_export
743 source_range: 3..3, 623 at macro_use
744 delete: 3..3, 624 at must_use = "…"
745 insert: "cfg(${0:predicate})", 625 at no_mangle
746 kind: Attribute, 626 at no_std
747 lookup: "cfg", 627 at non_exhaustive
748 }, 628 at panic_handler
749 CompletionItem { 629 at path = "…"
750 label: "cfg_attr(…)", 630 at proc_macro
751 source_range: 3..3, 631 at proc_macro_attribute
752 delete: 3..3, 632 at proc_macro_derive(…)
753 insert: "cfg_attr(${1:predicate}, ${0:attr})", 633 at recursion_limit = …
754 kind: Attribute, 634 at repr(…)
755 lookup: "cfg_attr", 635 at should_panic(…)
756 }, 636 at target_feature = "…"
757 CompletionItem { 637 at test
758 label: "deny(…)", 638 at used
759 source_range: 3..3, 639 at warn(…)
760 delete: 3..3, 640 at windows_subsystem = "…"
761 insert: "deny(${0:lint})", 641 "#]],
762 kind: Attribute,
763 lookup: "deny",
764 },
765 CompletionItem {
766 label: "deprecated = \"…\"",
767 source_range: 3..3,
768 delete: 3..3,
769 insert: "deprecated = \"${0:reason}\"",
770 kind: Attribute,
771 lookup: "deprecated",
772 },
773 CompletionItem {
774 label: "derive(…)",
775 source_range: 3..3,
776 delete: 3..3,
777 insert: "derive(${0:Debug})",
778 kind: Attribute,
779 lookup: "derive",
780 },
781 CompletionItem {
782 label: "doc = \"…\"",
783 source_range: 3..3,
784 delete: 3..3,
785 insert: "doc = \"${0:docs}\"",
786 kind: Attribute,
787 lookup: "doc",
788 },
789 CompletionItem {
790 label: "feature(…)",
791 source_range: 3..3,
792 delete: 3..3,
793 insert: "feature(${0:flag})",
794 kind: Attribute,
795 lookup: "feature",
796 },
797 CompletionItem {
798 label: "forbid(…)",
799 source_range: 3..3,
800 delete: 3..3,
801 insert: "forbid(${0:lint})",
802 kind: Attribute,
803 lookup: "forbid",
804 },
805 CompletionItem {
806 label: "global_allocator",
807 source_range: 3..3,
808 delete: 3..3,
809 insert: "global_allocator",
810 kind: Attribute,
811 },
812 CompletionItem {
813 label: "ignore(…)",
814 source_range: 3..3,
815 delete: 3..3,
816 insert: "ignore(${0:lint})",
817 kind: Attribute,
818 lookup: "ignore",
819 },
820 CompletionItem {
821 label: "inline(…)",
822 source_range: 3..3,
823 delete: 3..3,
824 insert: "inline(${0:lint})",
825 kind: Attribute,
826 lookup: "inline",
827 },
828 CompletionItem {
829 label: "link",
830 source_range: 3..3,
831 delete: 3..3,
832 insert: "link",
833 kind: Attribute,
834 },
835 CompletionItem {
836 label: "link_name = \"…\"",
837 source_range: 3..3,
838 delete: 3..3,
839 insert: "link_name = \"${0:symbol_name}\"",
840 kind: Attribute,
841 lookup: "link_name",
842 },
843 CompletionItem {
844 label: "macro_export",
845 source_range: 3..3,
846 delete: 3..3,
847 insert: "macro_export",
848 kind: Attribute,
849 },
850 CompletionItem {
851 label: "macro_use",
852 source_range: 3..3,
853 delete: 3..3,
854 insert: "macro_use",
855 kind: Attribute,
856 },
857 CompletionItem {
858 label: "must_use = \"…\"",
859 source_range: 3..3,
860 delete: 3..3,
861 insert: "must_use = \"${0:reason}\"",
862 kind: Attribute,
863 lookup: "must_use",
864 },
865 CompletionItem {
866 label: "no_mangle",
867 source_range: 3..3,
868 delete: 3..3,
869 insert: "no_mangle",
870 kind: Attribute,
871 },
872 CompletionItem {
873 label: "no_std",
874 source_range: 3..3,
875 delete: 3..3,
876 insert: "no_std",
877 kind: Attribute,
878 },
879 CompletionItem {
880 label: "non_exhaustive",
881 source_range: 3..3,
882 delete: 3..3,
883 insert: "non_exhaustive",
884 kind: Attribute,
885 },
886 CompletionItem {
887 label: "panic_handler",
888 source_range: 3..3,
889 delete: 3..3,
890 insert: "panic_handler",
891 kind: Attribute,
892 },
893 CompletionItem {
894 label: "path = \"…\"",
895 source_range: 3..3,
896 delete: 3..3,
897 insert: "path =\"${0:path}\"",
898 kind: Attribute,
899 lookup: "path",
900 },
901 CompletionItem {
902 label: "proc_macro",
903 source_range: 3..3,
904 delete: 3..3,
905 insert: "proc_macro",
906 kind: Attribute,
907 },
908 CompletionItem {
909 label: "proc_macro_attribute",
910 source_range: 3..3,
911 delete: 3..3,
912 insert: "proc_macro_attribute",
913 kind: Attribute,
914 },
915 CompletionItem {
916 label: "proc_macro_derive(…)",
917 source_range: 3..3,
918 delete: 3..3,
919 insert: "proc_macro_derive(${0:Trait})",
920 kind: Attribute,
921 lookup: "proc_macro_derive",
922 },
923 CompletionItem {
924 label: "recursion_limit = …",
925 source_range: 3..3,
926 delete: 3..3,
927 insert: "recursion_limit = ${0:128}",
928 kind: Attribute,
929 lookup: "recursion_limit",
930 },
931 CompletionItem {
932 label: "repr(…)",
933 source_range: 3..3,
934 delete: 3..3,
935 insert: "repr(${0:C})",
936 kind: Attribute,
937 lookup: "repr",
938 },
939 CompletionItem {
940 label: "should_panic(…)",
941 source_range: 3..3,
942 delete: 3..3,
943 insert: "should_panic(expected = \"${0:reason}\")",
944 kind: Attribute,
945 lookup: "should_panic",
946 },
947 CompletionItem {
948 label: "target_feature = \"…\"",
949 source_range: 3..3,
950 delete: 3..3,
951 insert: "target_feature = \"${0:feature}\"",
952 kind: Attribute,
953 lookup: "target_feature",
954 },
955 CompletionItem {
956 label: "test",
957 source_range: 3..3,
958 delete: 3..3,
959 insert: "test",
960 kind: Attribute,
961 },
962 CompletionItem {
963 label: "used",
964 source_range: 3..3,
965 delete: 3..3,
966 insert: "used",
967 kind: Attribute,
968 },
969 CompletionItem {
970 label: "warn(…)",
971 source_range: 3..3,
972 delete: 3..3,
973 insert: "warn(${0:lint})",
974 kind: Attribute,
975 lookup: "warn",
976 },
977 CompletionItem {
978 label: "windows_subsystem = \"…\"",
979 source_range: 3..3,
980 delete: 3..3,
981 insert: "windows_subsystem = \"${0:subsystem}\"",
982 kind: Attribute,
983 lookup: "windows_subsystem",
984 },
985 ]
986 "###
987 ); 642 );
988 } 643 }
989} 644}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index ee4e24fca..532665285 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -1,17 +1,12 @@
1//! FIXME: write short doc here 1//! Completes references after dot (fields and method calls).
2 2
3use hir::{HasVisibility, Type}; 3use hir::{HasVisibility, Type};
4
5use crate::{
6 completion::{
7 completion_context::CompletionContext,
8 completion_item::{CompletionKind, Completions},
9 },
10 CompletionItem,
11};
12use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark;
13 6
14/// Complete dot accesses, i.e. fields or methods (and .await syntax). 7use crate::completion::{completion_context::CompletionContext, completion_item::Completions};
8
9/// Complete dot accesses, i.e. fields or methods.
15pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
16 let dot_receiver = match &ctx.dot_receiver { 11 let dot_receiver = match &ctx.dot_receiver {
17 Some(expr) => expr, 12 Some(expr) => expr,
@@ -23,24 +18,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
23 _ => return, 18 _ => return,
24 }; 19 };
25 20
26 if !ctx.is_call { 21 if ctx.is_call {
22 mark::hit!(test_no_struct_field_completion_for_method_call);
23 } else {
27 complete_fields(acc, ctx, &receiver_ty); 24 complete_fields(acc, ctx, &receiver_ty);
28 } 25 }
29 complete_methods(acc, ctx, &receiver_ty); 26 complete_methods(acc, ctx, &receiver_ty);
30
31 // Suggest .await syntax for types that implement Future trait
32 if receiver_ty.impls_future(ctx.db) {
33 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
34 .detail("expr.await")
35 .insert_text("await")
36 .add_to(acc);
37 }
38} 27}
39 28
40fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 29fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
41 for receiver in receiver.autoderef(ctx.db) { 30 for receiver in receiver.autoderef(ctx.db) {
42 for (field, ty) in receiver.fields(ctx.db) { 31 for (field, ty) in receiver.fields(ctx.db) {
43 if ctx.scope().module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { 32 if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
44 // Skip private field. FIXME: If the definition location of the 33 // Skip private field. FIXME: If the definition location of the
45 // field is editable, we should show the completion 34 // field is editable, we should show the completion
46 continue; 35 continue;
@@ -57,10 +46,10 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
57fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 46fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
58 if let Some(krate) = ctx.krate { 47 if let Some(krate) = ctx.krate {
59 let mut seen_methods = FxHashSet::default(); 48 let mut seen_methods = FxHashSet::default();
60 let traits_in_scope = ctx.scope().traits_in_scope(); 49 let traits_in_scope = ctx.scope.traits_in_scope();
61 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { 50 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
62 if func.has_self_param(ctx.db) 51 if func.has_self_param(ctx.db)
63 && ctx.scope().module().map_or(true, |m| func.is_visible_from(ctx.db, m)) 52 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
64 && seen_methods.insert(func.name(ctx.db)) 53 && seen_methods.insert(func.name(ctx.db))
65 { 54 {
66 acc.add_function(ctx, func, None); 55 acc.add_function(ctx, func, None);
@@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
72 61
73#[cfg(test)] 62#[cfg(test)]
74mod tests { 63mod tests {
75 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 64 use expect::{expect, Expect};
76 use insta::assert_debug_snapshot; 65 use test_utils::mark;
66
67 use crate::completion::{test_utils::completion_list, CompletionKind};
77 68
78 fn do_ref_completion(code: &str) -> Vec<CompletionItem> { 69 fn check(ra_fixture: &str, expect: Expect) {
79 do_completion(code, CompletionKind::Reference) 70 let actual = completion_list(ra_fixture, CompletionKind::Reference);
71 expect.assert_eq(&actual);
80 } 72 }
81 73
82 #[test] 74 #[test]
83 fn test_struct_field_completion() { 75 fn test_struct_field_and_method_completion() {
84 assert_debug_snapshot!( 76 check(
85 do_ref_completion( 77 r#"
86 r" 78struct S { foo: u32 }
87 struct A { the_field: u32 } 79impl S {
88 fn foo(a: A) { 80 fn bar(&self) {}
89 a.<|> 81}
90 } 82fn foo(s: S) { s.<|> }
91 ", 83"#,
92 ), 84 expect![[r#"
93 @r###" 85 me bar() fn bar(&self)
94 [ 86 fd foo u32
95 CompletionItem { 87 "#]],
96 label: "the_field",
97 source_range: 45..45,
98 delete: 45..45,
99 insert: "the_field",
100 kind: Field,
101 detail: "u32",
102 },
103 ]
104 "###
105 ); 88 );
106 } 89 }
107 90
108 #[test] 91 #[test]
109 fn test_struct_field_completion_self() { 92 fn test_struct_field_completion_self() {
110 assert_debug_snapshot!( 93 check(
111 do_ref_completion( 94 r#"
112 r" 95struct S { the_field: (u32,) }
113 struct A { 96impl S {
114 /// This is the_field 97 fn foo(self) { self.<|> }
115 the_field: (u32,) 98}
116 } 99"#,
117 impl A { 100 expect![[r#"
118 fn foo(self) { 101 me foo() fn foo(self)
119 self.<|> 102 fd the_field (u32,)
120 } 103 "#]],
121 } 104 )
122 ",
123 ),
124 @r###"
125 [
126 CompletionItem {
127 label: "foo()",
128 source_range: 102..102,
129 delete: 102..102,
130 insert: "foo()$0",
131 kind: Method,
132 lookup: "foo",
133 detail: "fn foo(self)",
134 },
135 CompletionItem {
136 label: "the_field",
137 source_range: 102..102,
138 delete: 102..102,
139 insert: "the_field",
140 kind: Field,
141 detail: "(u32,)",
142 documentation: Documentation(
143 "This is the_field",
144 ),
145 },
146 ]
147 "###
148 );
149 } 105 }
150 106
151 #[test] 107 #[test]
152 fn test_struct_field_completion_autoderef() { 108 fn test_struct_field_completion_autoderef() {
153 assert_debug_snapshot!( 109 check(
154 do_ref_completion( 110 r#"
155 r" 111struct A { the_field: (u32, i32) }
156 struct A { the_field: (u32, i32) } 112impl A {
157 impl A { 113 fn foo(&self) { self.<|> }
158 fn foo(&self) { 114}
159 self.<|> 115"#,
160 } 116 expect![[r#"
161 } 117 me foo() fn foo(&self)
162 ", 118 fd the_field (u32, i32)
163 ), 119 "#]],
164 @r###" 120 )
165 [
166 CompletionItem {
167 label: "foo()",
168 source_range: 77..77,
169 delete: 77..77,
170 insert: "foo()$0",
171 kind: Method,
172 lookup: "foo",
173 detail: "fn foo(&self)",
174 },
175 CompletionItem {
176 label: "the_field",
177 source_range: 77..77,
178 delete: 77..77,
179 insert: "the_field",
180 kind: Field,
181 detail: "(u32, i32)",
182 },
183 ]
184 "###
185 );
186 } 121 }
187 122
188 #[test] 123 #[test]
189 fn test_no_struct_field_completion_for_method_call() { 124 fn test_no_struct_field_completion_for_method_call() {
190 assert_debug_snapshot!( 125 mark::check!(test_no_struct_field_completion_for_method_call);
191 do_ref_completion( 126 check(
192 r" 127 r#"
193 struct A { the_field: u32 } 128struct A { the_field: u32 }
194 fn foo(a: A) { 129fn foo(a: A) { a.<|>() }
195 a.<|>() 130"#,
196 } 131 expect![[""]],
197 ",
198 ),
199 @"[]"
200 ); 132 );
201 } 133 }
202 134
203 #[test] 135 #[test]
204 fn test_struct_field_visibility_private() { 136 fn test_visibility_filtering() {
205 assert_debug_snapshot!( 137 check(
206 do_ref_completion( 138 r#"
207 r" 139mod inner {
208 mod inner { 140 pub struct A {
209 struct A { 141 private_field: u32,
210 private_field: u32, 142 pub pub_field: u32,
211 pub pub_field: u32, 143 pub(crate) crate_field: u32,
212 pub(crate) crate_field: u32, 144 pub(super) super_field: u32,
213 pub(super) super_field: u32,
214 }
215 }
216 fn foo(a: inner::A) {
217 a.<|>
218 }
219 ",
220 ),
221 @r###"
222 [
223 CompletionItem {
224 label: "crate_field",
225 source_range: 192..192,
226 delete: 192..192,
227 insert: "crate_field",
228 kind: Field,
229 detail: "u32",
230 },
231 CompletionItem {
232 label: "pub_field",
233 source_range: 192..192,
234 delete: 192..192,
235 insert: "pub_field",
236 kind: Field,
237 detail: "u32",
238 },
239 CompletionItem {
240 label: "super_field",
241 source_range: 192..192,
242 delete: 192..192,
243 insert: "super_field",
244 kind: Field,
245 detail: "u32",
246 },
247 ]
248 "###
249 );
250 } 145 }
251 146}
252 #[test] 147fn foo(a: inner::A) { a.<|> }
253 fn test_union_field_completion() { 148"#,
254 assert_debug_snapshot!( 149 expect![[r#"
255 do_ref_completion( 150 fd crate_field u32
256 r" 151 fd pub_field u32
257 union Un { 152 fd super_field u32
258 field: u8, 153 "#]],
259 other: u16,
260 }
261
262 fn foo(u: Un) {
263 u.<|>
264 }
265 ",
266 ),
267 @r###"
268 [
269 CompletionItem {
270 label: "field",
271 source_range: 67..67,
272 delete: 67..67,
273 insert: "field",
274 kind: Field,
275 detail: "u8",
276 },
277 CompletionItem {
278 label: "other",
279 source_range: 67..67,
280 delete: 67..67,
281 insert: "other",
282 kind: Field,
283 detail: "u16",
284 },
285 ]
286 "###
287 ); 154 );
288 }
289 155
290 #[test] 156 check(
291 fn test_method_completion() { 157 r#"
292 assert_debug_snapshot!( 158struct A {}
293 do_ref_completion( 159mod m {
294 r" 160 impl super::A {
295 struct A {} 161 fn private_method(&self) {}
296 impl A { 162 pub(super) fn the_method(&self) {}
297 fn the_method(&self) {} 163 }
298 } 164}
299 fn foo(a: A) { 165fn foo(a: A) { a.<|> }
300 a.<|> 166"#,
301 } 167 expect![[r#"
302 ", 168 me the_method() pub(super) fn the_method(&self)
303 ), 169 "#]],
304 @r###"
305 [
306 CompletionItem {
307 label: "the_method()",
308 source_range: 71..71,
309 delete: 71..71,
310 insert: "the_method()$0",
311 kind: Method,
312 lookup: "the_method",
313 detail: "fn the_method(&self)",
314 },
315 ]
316 "###
317 ); 170 );
318 } 171 }
319 172
320 #[test] 173 #[test]
321 fn test_method_completion_only_fitting_impls() { 174 fn test_union_field_completion() {
322 assert_debug_snapshot!( 175 check(
323 do_ref_completion( 176 r#"
324 r" 177union U { field: u8, other: u16 }
325 struct A<T> {} 178fn foo(u: U) { u.<|> }
326 impl A<u32> { 179"#,
327 fn the_method(&self) {} 180 expect![[r#"
328 } 181 fd field u8
329 impl A<i32> { 182 fd other u16
330 fn the_other_method(&self) {} 183 "#]],
331 }
332 fn foo(a: A<u32>) {
333 a.<|>
334 }
335 ",
336 ),
337 @r###"
338 [
339 CompletionItem {
340 label: "the_method()",
341 source_range: 134..134,
342 delete: 134..134,
343 insert: "the_method()$0",
344 kind: Method,
345 lookup: "the_method",
346 detail: "fn the_method(&self)",
347 },
348 ]
349 "###
350 ); 184 );
351 } 185 }
352 186
353 #[test] 187 #[test]
354 fn test_method_completion_private() { 188 fn test_method_completion_only_fitting_impls() {
355 assert_debug_snapshot!( 189 check(
356 do_ref_completion( 190 r#"
357 r" 191struct A<T> {}
358 struct A {} 192impl A<u32> {
359 mod m { 193 fn the_method(&self) {}
360 impl super::A { 194}
361 fn private_method(&self) {} 195impl A<i32> {
362 pub(super) fn the_method(&self) {} 196 fn the_other_method(&self) {}
363 } 197}
364 } 198fn foo(a: A<u32>) { a.<|> }
365 fn foo(a: A) { 199"#,
366 a.<|> 200 expect![[r#"
367 } 201 me the_method() fn the_method(&self)
368 ", 202 "#]],
369 ), 203 )
370 @r###"
371 [
372 CompletionItem {
373 label: "the_method()",
374 source_range: 147..147,
375 delete: 147..147,
376 insert: "the_method()$0",
377 kind: Method,
378 lookup: "the_method",
379 detail: "pub(super) fn the_method(&self)",
380 },
381 ]
382 "###
383 );
384 } 204 }
385 205
386 #[test] 206 #[test]
387 fn test_trait_method_completion() { 207 fn test_trait_method_completion() {
388 assert_debug_snapshot!( 208 check(
389 do_ref_completion( 209 r#"
390 r" 210struct A {}
391 struct A {} 211trait Trait { fn the_method(&self); }
392 trait Trait { fn the_method(&self); } 212impl Trait for A {}
393 impl Trait for A {} 213fn foo(a: A) { a.<|> }
394 fn foo(a: A) { 214"#,
395 a.<|> 215 expect![[r#"
396 } 216 me the_method() fn the_method(&self)
397 ", 217 "#]],
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "the_method()",
403 source_range: 90..90,
404 delete: 90..90,
405 insert: "the_method()$0",
406 kind: Method,
407 lookup: "the_method",
408 detail: "fn the_method(&self)",
409 },
410 ]
411 "###
412 ); 218 );
413 } 219 }
414 220
415 #[test] 221 #[test]
416 fn test_trait_method_completion_deduplicated() { 222 fn test_trait_method_completion_deduplicated() {
417 assert_debug_snapshot!( 223 check(
418 do_ref_completion( 224 r"
419 r" 225struct A {}
420 struct A {} 226trait Trait { fn the_method(&self); }
421 trait Trait { fn the_method(&self); } 227impl<T> Trait for T {}
422 impl<T> Trait for T {} 228fn foo(a: &A) { a.<|> }
423 fn foo(a: &A) { 229",
424 a.<|> 230 expect![[r#"
425 } 231 me the_method() fn the_method(&self)
426 ", 232 "#]],
427 ),
428 @r###"
429 [
430 CompletionItem {
431 label: "the_method()",
432 source_range: 94..94,
433 delete: 94..94,
434 insert: "the_method()$0",
435 kind: Method,
436 lookup: "the_method",
437 detail: "fn the_method(&self)",
438 },
439 ]
440 "###
441 ); 233 );
442 } 234 }
443 235
444 #[test] 236 #[test]
445 fn completes_trait_method_from_other_module() { 237 fn completes_trait_method_from_other_module() {
446 assert_debug_snapshot!( 238 check(
447 do_ref_completion(
448 r"
449 struct A {}
450 mod m {
451 pub trait Trait { fn the_method(&self); }
452 }
453 use m::Trait;
454 impl Trait for A {}
455 fn foo(a: A) {
456 a.<|>
457 }
458 ",
459 ),
460 @r###"
461 [
462 CompletionItem {
463 label: "the_method()",
464 source_range: 122..122,
465 delete: 122..122,
466 insert: "the_method()$0",
467 kind: Method,
468 lookup: "the_method",
469 detail: "fn the_method(&self)",
470 },
471 ]
472 "###
473 );
474 }
475
476 #[test]
477 fn test_no_non_self_method() {
478 assert_debug_snapshot!(
479 do_ref_completion(
480 r" 239 r"
481 struct A {} 240struct A {}
482 impl A { 241mod m {
483 fn the_method() {} 242 pub trait Trait { fn the_method(&self); }
484 } 243}
485 fn foo(a: A) { 244use m::Trait;
486 a.<|> 245impl Trait for A {}
487 } 246fn foo(a: A) { a.<|> }
488 ", 247",
489 ), 248 expect![[r#"
490 @"[]" 249 me the_method() fn the_method(&self)
250 "#]],
491 ); 251 );
492 } 252 }
493 253
494 #[test] 254 #[test]
495 fn test_method_attr_filtering() { 255 fn test_no_non_self_method() {
496 assert_debug_snapshot!( 256 check(
497 do_ref_completion( 257 r#"
498 r" 258struct A {}
499 struct A {} 259impl A {
500 impl A { 260 fn the_method() {}
501 #[inline] 261}
502 fn the_method(&self) { 262fn foo(a: A) {
503 let x = 1; 263 a.<|>
504 let y = 2; 264}
505 } 265"#,
506 } 266 expect![[""]],
507 fn foo(a: A) {
508 a.<|>
509 }
510 ",
511 ),
512 @r###"
513 [
514 CompletionItem {
515 label: "the_method()",
516 source_range: 128..128,
517 delete: 128..128,
518 insert: "the_method()$0",
519 kind: Method,
520 lookup: "the_method",
521 detail: "fn the_method(&self)",
522 },
523 ]
524 "###
525 ); 267 );
526 } 268 }
527 269
528 #[test] 270 #[test]
529 fn test_tuple_field_completion() { 271 fn test_tuple_field_completion() {
530 assert_debug_snapshot!( 272 check(
531 do_ref_completion( 273 r#"
532 r" 274fn foo() {
533 fn foo() { 275 let b = (0, 3.14);
534 let b = (0, 3.14); 276 b.<|>
535 b.<|> 277}
536 } 278"#,
537 ", 279 expect![[r#"
538 ), 280 fd 0 i32
539 @r###" 281 fd 1 f64
540 [ 282 "#]],
541 CompletionItem { 283 )
542 label: "0",
543 source_range: 38..38,
544 delete: 38..38,
545 insert: "0",
546 kind: Field,
547 detail: "i32",
548 },
549 CompletionItem {
550 label: "1",
551 source_range: 38..38,
552 delete: 38..38,
553 insert: "1",
554 kind: Field,
555 detail: "f64",
556 },
557 ]
558 "###
559 );
560 } 284 }
561 285
562 #[test] 286 #[test]
563 fn test_tuple_field_inference() { 287 fn test_tuple_field_inference() {
564 assert_debug_snapshot!( 288 check(
565 do_ref_completion( 289 r#"
566 r" 290pub struct S;
567 pub struct S; 291impl S { pub fn blah(&self) {} }
568 impl S {
569 pub fn blah(&self) {}
570 }
571 292
572 struct T(S); 293struct T(S);
573 294
574 impl T { 295impl T {
575 fn foo(&self) { 296 fn foo(&self) {
576 // FIXME: This doesn't work without the trailing `a` as `0.` is a float 297 // FIXME: This doesn't work without the trailing `a` as `0.` is a float
577 self.0.a<|> 298 self.0.a<|>
578 }
579 }
580 ",
581 ),
582 @r###"
583 [
584 CompletionItem {
585 label: "blah()",
586 source_range: 190..191,
587 delete: 190..191,
588 insert: "blah()$0",
589 kind: Method,
590 lookup: "blah",
591 detail: "pub fn blah(&self)",
592 },
593 ]
594 "###
595 );
596 } 299 }
597 300}
598 #[test] 301"#,
599 fn test_completion_works_in_consts() { 302 expect![[r#"
600 assert_debug_snapshot!( 303 me blah() pub fn blah(&self)
601 do_ref_completion( 304 "#]],
602 r"
603 struct A { the_field: u32 }
604 const X: u32 = {
605 A { the_field: 92 }.<|>
606 };
607 ",
608 ),
609 @r###"
610 [
611 CompletionItem {
612 label: "the_field",
613 source_range: 69..69,
614 delete: 69..69,
615 insert: "the_field",
616 kind: Field,
617 detail: "u32",
618 },
619 ]
620 "###
621 ); 305 );
622 } 306 }
623 307
624 #[test] 308 #[test]
625 fn test_completion_await_impls_future() { 309 fn test_completion_works_in_consts() {
626 assert_debug_snapshot!( 310 check(
627 do_completion( 311 r#"
628 r###" 312struct A { the_field: u32 }
629 //- /main.rs 313const X: u32 = {
630 use std::future::*; 314 A { the_field: 92 }.<|>
631 struct A {} 315};
632 impl Future for A {} 316"#,
633 fn foo(a: A) { 317 expect![[r#"
634 a.<|> 318 fd the_field u32
635 } 319 "#]],
636
637 //- /std/lib.rs
638 pub mod future {
639 #[lang = "future_trait"]
640 pub trait Future {}
641 }
642 "###, CompletionKind::Keyword),
643 @r###"
644 [
645 CompletionItem {
646 label: "await",
647 source_range: 74..74,
648 delete: 74..74,
649 insert: "await",
650 detail: "expr.await",
651 },
652 ]
653 "###
654 )
655 }
656
657 #[test]
658 fn test_super_super_completion() {
659 assert_debug_snapshot!(
660 do_ref_completion(
661 r"
662 mod a {
663 const A: usize = 0;
664
665 mod b {
666 const B: usize = 0;
667
668 mod c {
669 use super::super::<|>
670 }
671 }
672 }
673 ",
674 ),
675 @r###"
676 [
677 CompletionItem {
678 label: "A",
679 source_range: 120..120,
680 delete: 120..120,
681 insert: "A",
682 kind: Const,
683 },
684 CompletionItem {
685 label: "b",
686 source_range: 120..120,
687 delete: 120..120,
688 insert: "b",
689 kind: Module,
690 },
691 ]
692 "###
693 ); 320 );
694 } 321 }
695 322
696 #[test] 323 #[test]
697 fn works_in_simple_macro_1() { 324 fn works_in_simple_macro_1() {
698 assert_debug_snapshot!( 325 check(
699 do_ref_completion( 326 r#"
700 r" 327macro_rules! m { ($e:expr) => { $e } }
701 macro_rules! m { ($e:expr) => { $e } } 328struct A { the_field: u32 }
702 struct A { the_field: u32 } 329fn foo(a: A) {
703 fn foo(a: A) { 330 m!(a.x<|>)
704 m!(a.x<|>) 331}
705 } 332"#,
706 ", 333 expect![[r#"
707 ), 334 fd the_field u32
708 @r###" 335 "#]],
709 [
710 CompletionItem {
711 label: "the_field",
712 source_range: 91..92,
713 delete: 91..92,
714 insert: "the_field",
715 kind: Field,
716 detail: "u32",
717 },
718 ]
719 "###
720 );
721 }
722
723 #[test]
724 fn works_in_simple_macro_recursive() {
725 assert_debug_snapshot!(
726 do_ref_completion(
727 r"
728 macro_rules! m { ($e:expr) => { $e } }
729 struct A { the_field: u32 }
730 fn foo(a: A) {
731 m!(a.x<|>)
732 }
733 ",
734 ),
735 @r###"
736 [
737 CompletionItem {
738 label: "the_field",
739 source_range: 91..92,
740 delete: 91..92,
741 insert: "the_field",
742 kind: Field,
743 detail: "u32",
744 },
745 ]
746 "###
747 ); 336 );
748 } 337 }
749 338
750 #[test] 339 #[test]
751 fn works_in_simple_macro_2() { 340 fn works_in_simple_macro_2() {
752 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery 341 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
753 assert_debug_snapshot!( 342 check(
754 do_ref_completion( 343 r#"
755 r" 344macro_rules! m { ($e:expr) => { $e } }
756 macro_rules! m { ($e:expr) => { $e } } 345struct A { the_field: u32 }
757 struct A { the_field: u32 } 346fn foo(a: A) {
758 fn foo(a: A) { 347 m!(a.<|>)
759 m!(a.<|>) 348}
760 } 349"#,
761 ", 350 expect![[r#"
762 ), 351 fd the_field u32
763 @r###" 352 "#]],
764 [
765 CompletionItem {
766 label: "the_field",
767 source_range: 91..91,
768 delete: 91..91,
769 insert: "the_field",
770 kind: Field,
771 detail: "u32",
772 },
773 ]
774 "###
775 ); 353 );
776 } 354 }
777 355
778 #[test] 356 #[test]
779 fn works_in_simple_macro_recursive_1() { 357 fn works_in_simple_macro_recursive_1() {
780 assert_debug_snapshot!( 358 check(
781 do_ref_completion( 359 r#"
782 r" 360macro_rules! m { ($e:expr) => { $e } }
783 macro_rules! m { ($e:expr) => { $e } } 361struct A { the_field: u32 }
784 struct A { the_field: u32 } 362fn foo(a: A) {
785 fn foo(a: A) { 363 m!(m!(m!(a.x<|>)))
786 m!(m!(m!(a.x<|>))) 364}
787 } 365"#,
788 ", 366 expect![[r#"
789 ), 367 fd the_field u32
790 @r###" 368 "#]],
791 [
792 CompletionItem {
793 label: "the_field",
794 source_range: 97..98,
795 delete: 97..98,
796 insert: "the_field",
797 kind: Field,
798 detail: "u32",
799 },
800 ]
801 "###
802 ); 369 );
803 } 370 }
804 371
805 #[test] 372 #[test]
806 fn macro_expansion_resilient() { 373 fn macro_expansion_resilient() {
807 assert_debug_snapshot!( 374 check(
808 do_ref_completion( 375 r#"
809 r" 376macro_rules! dbg {
810 macro_rules! dbg { 377 () => {};
811 () => {}; 378 ($val:expr) => {
812 ($val:expr) => { 379 match $val { tmp => { tmp } }
813 match $val { tmp => { tmp } } 380 };
814 }; 381 // Trailing comma with single argument is ignored
815 // Trailing comma with single argument is ignored 382 ($val:expr,) => { $crate::dbg!($val) };
816 ($val:expr,) => { $crate::dbg!($val) }; 383 ($($val:expr),+ $(,)?) => {
817 ($($val:expr),+ $(,)?) => { 384 ($($crate::dbg!($val)),+,)
818 ($($crate::dbg!($val)),+,) 385 };
819 }; 386}
820 } 387struct A { the_field: u32 }
821 struct A { the_field: u32 } 388fn foo(a: A) {
822 fn foo(a: A) { 389 dbg!(a.<|>)
823 dbg!(a.<|>) 390}
824 } 391"#,
825 ", 392 expect![[r#"
826 ), 393 fd the_field u32
827 @r###" 394 "#]],
828 [
829 CompletionItem {
830 label: "the_field",
831 source_range: 327..327,
832 delete: 327..327,
833 insert: "the_field",
834 kind: Field,
835 detail: "u32",
836 },
837 ]
838 "###
839 ); 395 );
840 } 396 }
841 397
842 #[test] 398 #[test]
843 fn test_method_completion_3547() { 399 fn test_method_completion_issue_3547() {
844 assert_debug_snapshot!( 400 check(
845 do_ref_completion( 401 r#"
846 r" 402struct HashSet<T> {}
847 struct HashSet<T> {} 403impl<T> HashSet<T> {
848 impl<T> HashSet<T> { 404 pub fn the_method(&self) {}
849 pub fn the_method(&self) {} 405}
850 } 406fn foo() {
851 fn foo() { 407 let s: HashSet<_>;
852 let s: HashSet<_>; 408 s.<|>
853 s.<|> 409}
854 } 410"#,
855 ", 411 expect![[r#"
856 ), 412 me the_method() pub fn the_method(&self)
857 @r###" 413 "#]],
858 [
859 CompletionItem {
860 label: "the_method()",
861 source_range: 116..116,
862 delete: 116..116,
863 insert: "the_method()$0",
864 kind: Method,
865 lookup: "the_method",
866 detail: "pub fn the_method(&self)",
867 },
868 ]
869 "###
870 ); 414 );
871 } 415 }
872} 416}
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs
index f5573ddf7..406334257 100644
--- a/crates/ra_ide/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide/src/completion/complete_fn_param.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `complete_fn_param`.
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, ModuleItemOwner}, 4 ast::{self, ModuleItemOwner},
@@ -18,35 +18,47 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
18 } 18 }
19 19
20 let mut params = FxHashMap::default(); 20 let mut params = FxHashMap::default();
21
22 let me = ctx.token.ancestors().find_map(ast::Fn::cast);
23 let mut process_fn = |func: ast::Fn| {
24 if Some(&func) == me.as_ref() {
25 return;
26 }
27 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
28 let text = param.syntax().text().to_string();
29 params.entry(text).or_insert(param);
30 })
31 };
32
21 for node in ctx.token.parent().ancestors() { 33 for node in ctx.token.parent().ancestors() {
22 let items = match_ast! { 34 match_ast! {
23 match node { 35 match node {
24 ast::SourceFile(it) => it.items(), 36 ast::SourceFile(it) => it.items().filter_map(|item| match item {
25 ast::ItemList(it) => it.items(), 37 ast::Item::Fn(it) => Some(it),
38 _ => None,
39 }).for_each(&mut process_fn),
40 ast::ItemList(it) => it.items().filter_map(|item| match item {
41 ast::Item::Fn(it) => Some(it),
42 _ => None,
43 }).for_each(&mut process_fn),
44 ast::AssocItemList(it) => it.assoc_items().filter_map(|item| match item {
45 ast::AssocItem::Fn(it) => Some(it),
46 _ => None,
47 }).for_each(&mut process_fn),
26 _ => continue, 48 _ => continue,
27 } 49 }
28 }; 50 };
29 for item in items {
30 if let ast::ModuleItem::FnDef(func) = item {
31 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32 let text = param.syntax().text().to_string();
33 params.entry(text).or_insert((0, param)).0 += 1;
34 })
35 }
36 }
37 } 51 }
52
38 params 53 params
39 .into_iter() 54 .into_iter()
40 .filter_map(|(label, (count, param))| { 55 .filter_map(|(label, param)| {
41 let lookup = param.pat()?.syntax().text().to_string(); 56 let lookup = param.pat()?.syntax().text().to_string();
42 if count < 2 { 57 Some((label, lookup))
43 None
44 } else {
45 Some((label, lookup))
46 }
47 }) 58 })
48 .for_each(|(label, lookup)| { 59 .for_each(|(label, lookup)| {
49 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(crate::CompletionItemKind::Binding)
50 .lookup_by(lookup) 62 .lookup_by(lookup)
51 .add_to(acc) 63 .add_to(acc)
52 }); 64 });
@@ -54,85 +66,70 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
54 66
55#[cfg(test)] 67#[cfg(test)]
56mod tests { 68mod tests {
57 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 69 use expect::{expect, Expect};
58 use insta::assert_debug_snapshot; 70
71 use crate::completion::{test_utils::completion_list, CompletionKind};
59 72
60 fn do_magic_completion(code: &str) -> Vec<CompletionItem> { 73 fn check(ra_fixture: &str, expect: Expect) {
61 do_completion(code, CompletionKind::Magic) 74 let actual = completion_list(ra_fixture, CompletionKind::Magic);
75 expect.assert_eq(&actual);
62 } 76 }
63 77
64 #[test] 78 #[test]
65 fn test_param_completion_last_param() { 79 fn test_param_completion_last_param() {
66 assert_debug_snapshot!( 80 check(
67 do_magic_completion( 81 r#"
68 r" 82fn foo(file_id: FileId) {}
69 fn foo(file_id: FileId) {} 83fn bar(file_id: FileId) {}
70 fn bar(file_id: FileId) {} 84fn baz(file<|>) {}
71 fn baz(file<|>) {} 85"#,
72 ", 86 expect![[r#"
73 ), 87 bn file_id: FileId
74 @r###" 88 "#]],
75 [
76 CompletionItem {
77 label: "file_id: FileId",
78 source_range: 61..65,
79 delete: 61..65,
80 insert: "file_id: FileId",
81 lookup: "file_id",
82 },
83 ]
84 "###
85 ); 89 );
86 } 90 }
87 91
88 #[test] 92 #[test]
89 fn test_param_completion_nth_param() { 93 fn test_param_completion_nth_param() {
90 assert_debug_snapshot!( 94 check(
91 do_magic_completion( 95 r#"
92 r" 96fn foo(file_id: FileId) {}
93 fn foo(file_id: FileId) {} 97fn baz(file<|>, x: i32) {}
94 fn bar(file_id: FileId) {} 98"#,
95 fn baz(file<|>, x: i32) {} 99 expect![[r#"
96 ", 100 bn file_id: FileId
97 ), 101 "#]],
98 @r###"
99 [
100 CompletionItem {
101 label: "file_id: FileId",
102 source_range: 61..65,
103 delete: 61..65,
104 insert: "file_id: FileId",
105 lookup: "file_id",
106 },
107 ]
108 "###
109 ); 102 );
110 } 103 }
111 104
112 #[test] 105 #[test]
113 fn test_param_completion_trait_param() { 106 fn test_param_completion_trait_param() {
114 assert_debug_snapshot!( 107 check(
115 do_magic_completion( 108 r#"
116 r" 109pub(crate) trait SourceRoot {
117 pub(crate) trait SourceRoot { 110 pub fn contains(&self, file_id: FileId) -> bool;
118 pub fn contains(&self, file_id: FileId) -> bool; 111 pub fn module_map(&self) -> &ModuleMap;
119 pub fn module_map(&self) -> &ModuleMap; 112 pub fn lines(&self, file_id: FileId) -> &LineIndex;
120 pub fn lines(&self, file_id: FileId) -> &LineIndex; 113 pub fn syntax(&self, file<|>)
121 pub fn syntax(&self, file<|>) 114}
122 } 115"#,
123 ", 116 expect![[r#"
124 ), 117 bn file_id: FileId
125 @r###" 118 "#]],
126 [
127 CompletionItem {
128 label: "file_id: FileId",
129 source_range: 208..212,
130 delete: 208..212,
131 insert: "file_id: FileId",
132 lookup: "file_id",
133 },
134 ]
135 "###
136 ); 119 );
137 } 120 }
121
122 #[test]
123 fn completes_param_in_inner_function() {
124 check(
125 r#"
126fn outer(text: String) {
127 fn inner(<|>)
128}
129"#,
130 expect![[r#"
131 bn text: String
132 "#]],
133 )
134 }
138} 135}
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 3b174f916..b62064797 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::ast; 3use ra_syntax::{ast, SyntaxKind};
4use test_utils::mark;
4 5
5use crate::completion::{ 6use crate::completion::{
6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -34,9 +35,27 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
34 } 35 }
35 _ => {} 36 _ => {}
36 } 37 }
38
39 // Suggest .await syntax for types that implement Future trait
40 if let Some(receiver) = &ctx.dot_receiver {
41 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
42 if ty.impls_future(ctx.db) {
43 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
44 .kind(CompletionItemKind::Keyword)
45 .detail("expr.await")
46 .insert_text("await")
47 .add_to(acc);
48 }
49 };
50 }
37} 51}
38 52
39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 53pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
54 if ctx.token.kind() == SyntaxKind::COMMENT {
55 mark::hit!(no_keyword_completion_in_comments);
56 return;
57 }
58
40 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; 59 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
41 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { 60 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
42 add_keyword(ctx, acc, "where", "where "); 61 add_keyword(ctx, acc, "where", "where ");
@@ -47,73 +66,67 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
47 add_keyword(ctx, acc, "fn", "fn $0() {}") 66 add_keyword(ctx, acc, "fn", "fn $0() {}")
48 } 67 }
49 68
50 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 69 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
51 || ctx.block_expr_parent
52 {
53 add_keyword(ctx, acc, "trait", "trait $0 {}"); 70 add_keyword(ctx, acc, "trait", "trait $0 {}");
54 add_keyword(ctx, acc, "impl", "impl $0 {}"); 71 add_keyword(ctx, acc, "impl", "impl $0 {}");
55 } 72 }
56 73
57 return; 74 return;
58 } 75 }
59 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { 76 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
77 {
60 add_keyword(ctx, acc, "fn", "fn $0() {}"); 78 add_keyword(ctx, acc, "fn", "fn $0() {}");
61 } 79 }
62 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 80 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
63 || ctx.block_expr_parent
64 {
65 add_keyword(ctx, acc, "use", "use "); 81 add_keyword(ctx, acc, "use", "use ");
66 add_keyword(ctx, acc, "impl", "impl $0 {}"); 82 add_keyword(ctx, acc, "impl", "impl $0 {}");
67 add_keyword(ctx, acc, "trait", "trait $0 {}"); 83 add_keyword(ctx, acc, "trait", "trait $0 {}");
68 } 84 }
69 85
70 if ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent { 86 if ctx.has_item_list_or_source_file_parent {
71 add_keyword(ctx, acc, "enum", "enum $0 {}"); 87 add_keyword(ctx, acc, "enum", "enum $0 {}");
72 add_keyword(ctx, acc, "struct", "struct $0 {}"); 88 add_keyword(ctx, acc, "struct", "struct $0");
73 add_keyword(ctx, acc, "union", "union $0 {}"); 89 add_keyword(ctx, acc, "union", "union $0 {}");
74 } 90 }
75 91
76 if ctx.block_expr_parent || ctx.is_match_arm { 92 if ctx.is_expr {
77 add_keyword(ctx, acc, "match", "match $0 {}"); 93 add_keyword(ctx, acc, "match", "match $0 {}");
78 add_keyword(ctx, acc, "loop", "loop {$0}");
79 }
80 if ctx.block_expr_parent {
81 add_keyword(ctx, acc, "while", "while $0 {}"); 94 add_keyword(ctx, acc, "while", "while $0 {}");
95 add_keyword(ctx, acc, "loop", "loop {$0}");
96 add_keyword(ctx, acc, "if", "if ");
97 add_keyword(ctx, acc, "if let", "if let ");
82 } 98 }
99
83 if ctx.if_is_prev || ctx.block_expr_parent { 100 if ctx.if_is_prev || ctx.block_expr_parent {
84 add_keyword(ctx, acc, "let", "let "); 101 add_keyword(ctx, acc, "let", "let ");
85 } 102 }
86 if ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm { 103
87 add_keyword(ctx, acc, "if", "if ");
88 add_keyword(ctx, acc, "if let", "if let ");
89 }
90 if ctx.after_if { 104 if ctx.after_if {
91 add_keyword(ctx, acc, "else", "else {$0}"); 105 add_keyword(ctx, acc, "else", "else {$0}");
92 add_keyword(ctx, acc, "else if", "else if $0 {}"); 106 add_keyword(ctx, acc, "else if", "else if $0 {}");
93 } 107 }
94 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 108 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
95 || ctx.block_expr_parent
96 {
97 add_keyword(ctx, acc, "mod", "mod $0 {}"); 109 add_keyword(ctx, acc, "mod", "mod $0 {}");
98 } 110 }
99 if ctx.bind_pat_parent || ctx.ref_pat_parent { 111 if ctx.bind_pat_parent || ctx.ref_pat_parent {
100 add_keyword(ctx, acc, "mut", "mut "); 112 add_keyword(ctx, acc, "mut", "mut ");
101 } 113 }
102 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { 114 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
115 {
103 add_keyword(ctx, acc, "const", "const "); 116 add_keyword(ctx, acc, "const", "const ");
104 add_keyword(ctx, acc, "type", "type "); 117 add_keyword(ctx, acc, "type", "type ");
105 } 118 }
106 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 119 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
107 || ctx.block_expr_parent
108 {
109 add_keyword(ctx, acc, "static", "static "); 120 add_keyword(ctx, acc, "static", "static ");
110 }; 121 };
111 if (ctx.has_item_list_or_source_file_parent && !has_trait_or_impl_parent) 122 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
112 || ctx.block_expr_parent
113 {
114 add_keyword(ctx, acc, "extern", "extern "); 123 add_keyword(ctx, acc, "extern", "extern ");
115 } 124 }
116 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent || ctx.is_match_arm { 125 if ctx.has_item_list_or_source_file_parent
126 || has_trait_or_impl_parent
127 || ctx.block_expr_parent
128 || ctx.is_match_arm
129 {
117 add_keyword(ctx, acc, "unsafe", "unsafe "); 130 add_keyword(ctx, acc, "unsafe", "unsafe ");
118 } 131 }
119 if ctx.in_loop_body { 132 if ctx.in_loop_body {
@@ -125,7 +138,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
125 add_keyword(ctx, acc, "break", "break"); 138 add_keyword(ctx, acc, "break", "break");
126 } 139 }
127 } 140 }
128 if ctx.has_item_list_or_source_file_parent && !ctx.has_trait_parent { 141 if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent {
129 add_keyword(ctx, acc, "pub", "pub ") 142 add_keyword(ctx, acc, "pub", "pub ")
130 } 143 }
131 144
@@ -156,7 +169,7 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
156 169
157fn complete_return( 170fn complete_return(
158 ctx: &CompletionContext, 171 ctx: &CompletionContext,
159 fn_def: &ast::FnDef, 172 fn_def: &ast::Fn,
160 can_be_stmt: bool, 173 can_be_stmt: bool,
161) -> Option<CompletionItem> { 174) -> Option<CompletionItem> {
162 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { 175 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
@@ -170,289 +183,354 @@ fn complete_return(
170 183
171#[cfg(test)] 184#[cfg(test)]
172mod tests { 185mod tests {
173 use crate::completion::{test_utils::completion_list, CompletionKind}; 186 use expect::{expect, Expect};
174 use insta::assert_snapshot; 187
188 use crate::completion::{
189 test_utils::{check_edit, completion_list},
190 CompletionKind,
191 };
192 use test_utils::mark;
175 193
176 fn get_keyword_completions(code: &str) -> String { 194 fn check(ra_fixture: &str, expect: Expect) {
177 completion_list(code, CompletionKind::Keyword) 195 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
196 expect.assert_eq(&actual)
178 } 197 }
179 198
180 #[test] 199 #[test]
181 fn test_keywords_in_use_stmt() { 200 fn test_keywords_in_use_stmt() {
182 assert_snapshot!( 201 check(
183 get_keyword_completions(r"use <|>"), 202 r"use <|>",
184 @r###" 203 expect![[r#"
185 kw crate:: 204 kw crate::
186 kw self 205 kw self
187 kw super:: 206 kw super::
188 "### 207 "#]],
189 ); 208 );
190 209
191 assert_snapshot!( 210 check(
192 get_keyword_completions(r"use a::<|>"), 211 r"use a::<|>",
193 @r###" 212 expect![[r#"
194 kw self 213 kw self
195 kw super:: 214 kw super::
196 "### 215 "#]],
197 ); 216 );
198 217
199 assert_snapshot!( 218 check(
200 get_keyword_completions(r"use a::{b, <|>}"), 219 r"use a::{b, <|>}",
201 @r###" 220 expect![[r#"
202 kw self 221 kw self
203 kw super:: 222 kw super::
204 "### 223 "#]],
205 ); 224 );
206 } 225 }
207 226
208 #[test] 227 #[test]
209 fn test_keywords_at_source_file_level() { 228 fn test_keywords_at_source_file_level() {
210 assert_snapshot!( 229 check(
211 get_keyword_completions(r"m<|>"), 230 r"m<|>",
212 @r###" 231 expect![[r#"
213 kw const 232 kw const
214 kw enum 233 kw enum
215 kw extern 234 kw extern
216 kw fn 235 kw fn
217 kw impl 236 kw impl
218 kw mod 237 kw mod
219 kw pub 238 kw pub
220 kw static 239 kw static
221 kw struct 240 kw struct
222 kw trait 241 kw trait
223 kw type 242 kw type
224 kw union 243 kw union
225 kw unsafe 244 kw unsafe
226 kw use 245 kw use
227 "### 246 "#]],
228 ); 247 );
229 } 248 }
230 249
231 #[test] 250 #[test]
232 fn test_keywords_in_function() { 251 fn test_keywords_in_function() {
233 assert_snapshot!( 252 check(
234 get_keyword_completions(r"fn quux() { <|> }"), 253 r"fn quux() { <|> }",
235 @r###" 254 expect![[r#"
236 kw const 255 kw const
237 kw extern 256 kw extern
238 kw fn 257 kw fn
239 kw if 258 kw if
240 kw if let 259 kw if let
241 kw impl 260 kw impl
242 kw let 261 kw let
243 kw loop 262 kw loop
244 kw match 263 kw match
245 kw mod 264 kw mod
246 kw return 265 kw return
247 kw static 266 kw static
248 kw trait 267 kw trait
249 kw type 268 kw type
250 kw unsafe 269 kw unsafe
251 kw use 270 kw use
252 kw while 271 kw while
253 "### 272 "#]],
254 ); 273 );
255 } 274 }
256 275
257 #[test] 276 #[test]
258 fn test_keywords_inside_block() { 277 fn test_keywords_inside_block() {
259 assert_snapshot!( 278 check(
260 get_keyword_completions(r"fn quux() { if true { <|> } }"), 279 r"fn quux() { if true { <|> } }",
261 @r###" 280 expect![[r#"
262 kw const 281 kw const
263 kw extern 282 kw extern
264 kw fn 283 kw fn
265 kw if 284 kw if
266 kw if let 285 kw if let
267 kw impl 286 kw impl
268 kw let 287 kw let
269 kw loop 288 kw loop
270 kw match 289 kw match
271 kw mod 290 kw mod
272 kw return 291 kw return
273 kw static 292 kw static
274 kw trait 293 kw trait
275 kw type 294 kw type
276 kw unsafe 295 kw unsafe
277 kw use 296 kw use
278 kw while 297 kw while
279 "### 298 "#]],
280 ); 299 );
281 } 300 }
282 301
283 #[test] 302 #[test]
284 fn test_keywords_after_if() { 303 fn test_keywords_after_if() {
285 assert_snapshot!( 304 check(
286 get_keyword_completions( 305 r#"fn quux() { if true { () } <|> }"#,
287 r" 306 expect![[r#"
288 fn quux() { 307 kw const
289 if true { 308 kw else
290 () 309 kw else if
291 } <|> 310 kw extern
292 } 311 kw fn
293 ", 312 kw if
294 ), 313 kw if let
295 @r###" 314 kw impl
296 kw const 315 kw let
297 kw else 316 kw loop
298 kw else if 317 kw match
299 kw extern 318 kw mod
300 kw fn 319 kw return
301 kw if 320 kw static
302 kw if let 321 kw trait
303 kw impl 322 kw type
304 kw let 323 kw unsafe
305 kw loop 324 kw use
306 kw match 325 kw while
307 kw mod 326 "#]],
308 kw return 327 );
309 kw static 328 check_edit(
310 kw trait 329 "else",
311 kw type 330 r#"fn quux() { if true { () } <|> }"#,
312 kw unsafe 331 r#"fn quux() { if true { () } else {$0} }"#,
313 kw use
314 kw while
315 "###
316 ); 332 );
317 } 333 }
318 334
319 #[test] 335 #[test]
320 fn test_keywords_in_match_arm() { 336 fn test_keywords_in_match_arm() {
321 assert_snapshot!( 337 check(
322 get_keyword_completions( 338 r#"
323 r" 339fn quux() -> i32 {
324 fn quux() -> i32 { 340 match () { () => <|> }
325 match () { 341}
326 () => <|> 342"#,
327 } 343 expect![[r#"
328 } 344 kw if
329 ", 345 kw if let
330 ), 346 kw loop
331 @r###" 347 kw match
332 kw if 348 kw return
333 kw if let 349 kw unsafe
334 kw loop 350 kw while
335 kw match 351 "#]],
336 kw return
337 kw unsafe
338 "###
339 ); 352 );
340 } 353 }
341 354
342 #[test] 355 #[test]
343 fn test_keywords_in_trait_def() { 356 fn test_keywords_in_trait_def() {
344 assert_snapshot!( 357 check(
345 get_keyword_completions(r"trait My { <|> }"), 358 r"trait My { <|> }",
346 @r###" 359 expect![[r#"
347 kw const 360 kw const
348 kw fn 361 kw fn
349 kw type 362 kw type
350 kw unsafe 363 kw unsafe
351 "### 364 "#]],
352 ); 365 );
353 } 366 }
354 367
355 #[test] 368 #[test]
356 fn test_keywords_in_impl_def() { 369 fn test_keywords_in_impl_def() {
357 assert_snapshot!( 370 check(
358 get_keyword_completions(r"impl My { <|> }"), 371 r"impl My { <|> }",
359 @r###" 372 expect![[r#"
360 kw const 373 kw const
361 kw fn 374 kw fn
362 kw pub 375 kw pub
363 kw type 376 kw type
364 kw unsafe 377 kw unsafe
365 "### 378 "#]],
366 ); 379 );
367 } 380 }
368 381
369 #[test] 382 #[test]
370 fn test_keywords_in_loop() { 383 fn test_keywords_in_loop() {
371 assert_snapshot!( 384 check(
372 get_keyword_completions(r"fn my() { loop { <|> } }"), 385 r"fn my() { loop { <|> } }",
373 @r###" 386 expect![[r#"
374 kw break 387 kw break
375 kw const 388 kw const
376 kw continue 389 kw continue
377 kw extern 390 kw extern
378 kw fn 391 kw fn
379 kw if 392 kw if
380 kw if let 393 kw if let
381 kw impl 394 kw impl
382 kw let 395 kw let
383 kw loop 396 kw loop
384 kw match 397 kw match
385 kw mod 398 kw mod
386 kw return 399 kw return
387 kw static 400 kw static
388 kw trait 401 kw trait
389 kw type 402 kw type
390 kw unsafe 403 kw unsafe
391 kw use 404 kw use
392 kw while 405 kw while
393 "### 406 "#]],
394 ); 407 );
395 } 408 }
396 409
397 #[test] 410 #[test]
398 fn test_keywords_after_unsafe_in_item_list() { 411 fn test_keywords_after_unsafe_in_item_list() {
399 assert_snapshot!( 412 check(
400 get_keyword_completions(r"unsafe <|>"), 413 r"unsafe <|>",
401 @r###" 414 expect![[r#"
402 kw fn 415 kw fn
403 kw impl 416 kw impl
404 kw trait 417 kw trait
405 "### 418 "#]],
406 ); 419 );
407 } 420 }
408 421
409 #[test] 422 #[test]
410 fn test_keywords_after_unsafe_in_block_expr() { 423 fn test_keywords_after_unsafe_in_block_expr() {
411 assert_snapshot!( 424 check(
412 get_keyword_completions(r"fn my_fn() { unsafe <|> }"), 425 r"fn my_fn() { unsafe <|> }",
413 @r###" 426 expect![[r#"
414 kw fn 427 kw fn
415 kw impl 428 kw impl
416 kw trait 429 kw trait
417 "### 430 "#]],
418 ); 431 );
419 } 432 }
420 433
421 #[test] 434 #[test]
422 fn test_mut_in_ref_and_in_fn_parameters_list() { 435 fn test_mut_in_ref_and_in_fn_parameters_list() {
423 assert_snapshot!( 436 check(
424 get_keyword_completions(r"fn my_fn(&<|>) {}"), 437 r"fn my_fn(&<|>) {}",
425 @r###" 438 expect![[r#"
426 kw mut 439 kw mut
427 "### 440 "#]],
428 ); 441 );
429 assert_snapshot!( 442 check(
430 get_keyword_completions(r"fn my_fn(<|>) {}"), 443 r"fn my_fn(<|>) {}",
431 @r###" 444 expect![[r#"
432 kw mut 445 kw mut
433 "### 446 "#]],
434 ); 447 );
435 assert_snapshot!( 448 check(
436 get_keyword_completions(r"fn my_fn() { let &<|> }"), 449 r"fn my_fn() { let &<|> }",
437 @r###" 450 expect![[r#"
438 kw mut 451 kw mut
439 "### 452 "#]],
440 ); 453 );
441 } 454 }
442 455
443 #[test] 456 #[test]
444 fn test_where_keyword() { 457 fn test_where_keyword() {
445 assert_snapshot!( 458 check(
446 get_keyword_completions(r"trait A <|>"), 459 r"trait A <|>",
447 @r###" 460 expect![[r#"
448 kw where 461 kw where
449 "### 462 "#]],
450 ); 463 );
451 assert_snapshot!( 464 check(
452 get_keyword_completions(r"impl A <|>"), 465 r"impl A <|>",
453 @r###" 466 expect![[r#"
454 kw where 467 kw where
455 "### 468 "#]],
456 ); 469 );
457 } 470 }
471
472 #[test]
473 fn no_keyword_completion_in_comments() {
474 mark::check!(no_keyword_completion_in_comments);
475 check(
476 r#"
477fn test() {
478 let x = 2; // A comment<|>
479}
480"#,
481 expect![[""]],
482 );
483 check(
484 r#"
485/*
486Some multi-line comment<|>
487*/
488"#,
489 expect![[""]],
490 );
491 check(
492 r#"
493/// Some doc comment
494/// let test<|> = 1
495"#,
496 expect![[""]],
497 );
498 }
499
500 #[test]
501 fn test_completion_await_impls_future() {
502 check(
503 r#"
504//- /main.rs
505use std::future::*;
506struct A {}
507impl Future for A {}
508fn foo(a: A) { a.<|> }
509
510//- /std/lib.rs
511pub mod future {
512 #[lang = "future_trait"]
513 pub trait Future {}
514}
515"#,
516 expect![[r#"
517 kw await expr.await
518 "#]],
519 )
520 }
521
522 #[test]
523 fn after_let() {
524 check(
525 r#"fn main() { let _ = <|> }"#,
526 expect![[r#"
527 kw if
528 kw if let
529 kw loop
530 kw match
531 kw return
532 kw while
533 "#]],
534 )
535 }
458} 536}
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
index 4c33f41d4..0447f0511 100644
--- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
7 if ctx.is_new_item { 7 if ctx.is_new_item {
8 ctx.scope().process_all_names(&mut |name, res| { 8 ctx.scope.process_all_names(&mut |name, res| {
9 if let hir::ScopeDef::MacroDef(mac) = res { 9 if let hir::ScopeDef::MacroDef(mac) = res {
10 acc.add_macro(ctx, Some(name.to_string()), mac); 10 acc.add_macro(ctx, Some(name.to_string()), mac);
11 } 11 }
@@ -15,130 +15,27 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
15 15
16#[cfg(test)] 16#[cfg(test)]
17mod tests { 17mod tests {
18 use insta::assert_debug_snapshot; 18 use expect::{expect, Expect};
19 19
20 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 20 use crate::completion::{test_utils::completion_list, CompletionKind};
21 21
22 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 22 fn check(ra_fixture: &str, expect: Expect) {
23 do_completion(code, CompletionKind::Reference) 23 let actual = completion_list(ra_fixture, CompletionKind::Reference);
24 expect.assert_eq(&actual)
24 } 25 }
25 26
26 #[test] 27 #[test]
27 fn completes_macros_as_item() { 28 fn completes_macros_as_item() {
28 assert_debug_snapshot!( 29 check(
29 do_reference_completion( 30 r#"
30 " 31macro_rules! foo { () => {} }
31 //- /main.rs 32fn foo() {}
32 macro_rules! foo { 33
33 () => {} 34<|>
34 } 35"#,
35 36 expect![[r#"
36 fn foo() {} 37 ma foo!(…) macro_rules! foo
37 38 "#]],
38 <|> 39 )
39 "
40 ),
41 @r###"
42 [
43 CompletionItem {
44 label: "foo!(…)",
45 source_range: 48..48,
46 delete: 48..48,
47 insert: "foo!($0)",
48 kind: Macro,
49 detail: "macro_rules! foo",
50 },
51 ]
52 "###
53 );
54 }
55
56 #[test]
57 fn completes_vec_macros_with_square_brackets() {
58 assert_debug_snapshot!(
59 do_reference_completion(
60 "
61 //- /main.rs
62 /// Creates a [`Vec`] containing the arguments.
63 ///
64 /// - Create a [`Vec`] containing a given list of elements:
65 ///
66 /// ```
67 /// let v = vec![1, 2, 3];
68 /// assert_eq!(v[0], 1);
69 /// assert_eq!(v[1], 2);
70 /// assert_eq!(v[2], 3);
71 /// ```
72 macro_rules! vec {
73 () => {}
74 }
75
76 fn foo() {}
77
78 <|>
79 "
80 ),
81 @r###"
82 [
83 CompletionItem {
84 label: "vec![…]",
85 source_range: 282..282,
86 delete: 282..282,
87 insert: "vec![$0]",
88 kind: Macro,
89 detail: "macro_rules! vec",
90 documentation: Documentation(
91 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
92 ),
93 },
94 ]
95 "###
96 );
97 }
98
99 #[test]
100 fn completes_macros_braces_guessing() {
101 assert_debug_snapshot!(
102 do_reference_completion(
103 "
104 //- /main.rs
105 /// Foo
106 ///
107 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
108 /// Call as `let _=foo! { hello world };`
109 macro_rules! foo {
110 () => {}
111 }
112
113 fn main() {
114 <|>
115 }
116 "
117 ),
118 @r###"
119 [
120 CompletionItem {
121 label: "foo! {…}",
122 source_range: 164..164,
123 delete: 164..164,
124 insert: "foo! {$0}",
125 kind: Macro,
126 detail: "macro_rules! foo",
127 documentation: Documentation(
128 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
129 ),
130 },
131 CompletionItem {
132 label: "main()",
133 source_range: 164..164,
134 delete: 164..164,
135 insert: "main()$0",
136 kind: Function,
137 lookup: "main",
138 detail: "fn main()",
139 },
140 ]
141 "###
142 );
143 } 40 }
144} 41}
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index 367e2bbce..aceb77cb5 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -13,7 +13,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
13 13
14 // FIXME: ideally, we should look at the type we are matching against and 14 // FIXME: ideally, we should look at the type we are matching against and
15 // suggest variants + auto-imports 15 // suggest variants + auto-imports
16 ctx.scope().process_all_names(&mut |name, res| { 16 ctx.scope.process_all_names(&mut |name, res| {
17 match &res { 17 match &res {
18 hir::ScopeDef::ModuleDef(def) => match def { 18 hir::ScopeDef::ModuleDef(def) => match def {
19 hir::ModuleDef::Adt(hir::Adt::Enum(..)) 19 hir::ModuleDef::Adt(hir::Adt::Enum(..))
@@ -33,106 +33,56 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
33 33
34#[cfg(test)] 34#[cfg(test)]
35mod tests { 35mod tests {
36 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 36 use expect::{expect, Expect};
37 use insta::assert_debug_snapshot;
38 37
39 fn complete(code: &str) -> Vec<CompletionItem> { 38 use crate::completion::{test_utils::completion_list, CompletionKind};
40 do_completion(code, CompletionKind::Reference) 39
40 fn check(ra_fixture: &str, expect: Expect) {
41 let actual = completion_list(ra_fixture, CompletionKind::Reference);
42 expect.assert_eq(&actual)
41 } 43 }
42 44
43 #[test] 45 #[test]
44 fn completes_enum_variants_and_modules() { 46 fn completes_enum_variants_and_modules() {
45 let completions = complete( 47 check(
46 r" 48 r#"
47 enum E { X } 49enum E { X }
48 use self::E::X; 50use self::E::X;
49 const Z: E = E::X; 51const Z: E = E::X;
50 mod m {} 52mod m {}
51 53
52 static FOO: E = E::X; 54static FOO: E = E::X;
53 struct Bar { f: u32 } 55struct Bar { f: u32 }
54 56
55 fn foo() { 57fn foo() {
56 match E::X { 58 match E::X { <|> }
57 <|> 59}
58 } 60"#,
59 } 61 expect![[r#"
60 ", 62 st Bar
63 en E
64 ev X ()
65 ct Z
66 md m
67 "#]],
61 ); 68 );
62 assert_debug_snapshot!(completions, @r###"
63 [
64 CompletionItem {
65 label: "Bar",
66 source_range: 137..137,
67 delete: 137..137,
68 insert: "Bar",
69 kind: Struct,
70 },
71 CompletionItem {
72 label: "E",
73 source_range: 137..137,
74 delete: 137..137,
75 insert: "E",
76 kind: Enum,
77 },
78 CompletionItem {
79 label: "X",
80 source_range: 137..137,
81 delete: 137..137,
82 insert: "X",
83 kind: EnumVariant,
84 detail: "()",
85 },
86 CompletionItem {
87 label: "Z",
88 source_range: 137..137,
89 delete: 137..137,
90 insert: "Z",
91 kind: Const,
92 },
93 CompletionItem {
94 label: "m",
95 source_range: 137..137,
96 delete: 137..137,
97 insert: "m",
98 kind: Module,
99 },
100 ]
101 "###);
102 } 69 }
103 70
104 #[test] 71 #[test]
105 fn completes_in_simple_macro_call() { 72 fn completes_in_simple_macro_call() {
106 let completions = complete( 73 check(
107 r" 74 r#"
108 macro_rules! m { ($e:expr) => { $e } } 75macro_rules! m { ($e:expr) => { $e } }
109 enum E { X } 76enum E { X }
110 77
111 fn foo() { 78fn foo() {
112 m!(match E::X { 79 m!(match E::X { <|> })
113 <|> 80}
114 }) 81"#,
115 } 82 expect![[r#"
116 ", 83 en E
84 ma m!(…) macro_rules! m
85 "#]],
117 ); 86 );
118 assert_debug_snapshot!(completions, @r###"
119 [
120 CompletionItem {
121 label: "E",
122 source_range: 90..90,
123 delete: 90..90,
124 insert: "E",
125 kind: Enum,
126 },
127 CompletionItem {
128 label: "m!(…)",
129 source_range: 90..90,
130 delete: 90..90,
131 insert: "m!($0)",
132 kind: Macro,
133 detail: "macro_rules! m",
134 },
135 ]
136 "###);
137 } 87 }
138} 88}
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 3bd64804f..8735b9010 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -8,14 +8,13 @@ use ra_text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{
10 completion::{ 10 completion::{
11 completion_config::SnippetCap,
11 completion_context::CompletionContext, 12 completion_context::CompletionContext,
12 completion_item::{Builder, CompletionKind, Completions}, 13 completion_item::{Builder, CompletionKind, Completions},
13 }, 14 },
14 CompletionItem, 15 CompletionItem, CompletionItemKind,
15}; 16};
16 17
17use super::completion_config::SnippetCap;
18
19pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 18pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
20 if !ctx.config.enable_postfix_completions { 19 if !ctx.config.enable_postfix_completions {
21 return; 20 return;
@@ -103,10 +102,9 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
103 &format!("while {} {{\n $0\n}}", receiver_text), 102 &format!("while {} {{\n $0\n}}", receiver_text),
104 ) 103 )
105 .add_to(acc); 104 .add_to(acc);
105 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
106 .add_to(acc);
106 } 107 }
107 // !&&&42 is a compiler error, ergo process it before considering the references
108 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
109 .add_to(acc);
110 108
111 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) 109 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text))
112 .add_to(acc); 110 .add_to(acc);
@@ -125,33 +123,35 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
125 let dot_receiver = include_references(dot_receiver); 123 let dot_receiver = include_references(dot_receiver);
126 let receiver_text = 124 let receiver_text =
127 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); 125 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
126
128 match try_enum { 127 match try_enum {
129 Some(try_enum) => { 128 Some(try_enum) => match try_enum {
130 match try_enum { 129 TryEnum::Result => {
131 TryEnum::Result => { 130 postfix_snippet(
132 postfix_snippet(
133 ctx, 131 ctx,
134 cap, 132 cap,
135 &dot_receiver, 133 &dot_receiver,
136 "match", 134 "match",
137 "match expr {}", 135 "match expr {}",
138 &format!("match {} {{\n Ok(${{1:_}}) => {{$2\\}},\n Err(${{3:_}}) => {{$0\\}},\n}}", receiver_text), 136 &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text),
139 ) 137 )
140 .add_to(acc); 138 .add_to(acc);
141 } 139 }
142 TryEnum::Option => { 140 TryEnum::Option => {
143 postfix_snippet( 141 postfix_snippet(
144 ctx, 142 ctx,
145 cap, 143 cap,
146 &dot_receiver, 144 &dot_receiver,
147 "match", 145 "match",
148 "match expr {}", 146 "match expr {}",
149 &format!("match {} {{\n Some(${{1:_}}) => {{$2\\}},\n None => {{$0\\}},\n}}", receiver_text), 147 &format!(
148 "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}",
149 receiver_text
150 ),
150 ) 151 )
151 .add_to(acc); 152 .add_to(acc);
152 }
153 } 153 }
154 } 154 },
155 None => { 155 None => {
156 postfix_snippet( 156 postfix_snippet(
157 ctx, 157 ctx,
@@ -159,7 +159,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
159 &dot_receiver, 159 &dot_receiver,
160 "match", 160 "match",
161 "match expr {}", 161 "match expr {}",
162 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), 162 &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text),
163 ) 163 )
164 .add_to(acc); 164 .add_to(acc);
165 } 165 }
@@ -232,536 +232,147 @@ fn postfix_snippet(
232 }; 232 };
233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
234 .detail(detail) 234 .detail(detail)
235 .kind(CompletionItemKind::Snippet)
235 .snippet_edit(cap, edit) 236 .snippet_edit(cap, edit)
236} 237}
237 238
238#[cfg(test)] 239#[cfg(test)]
239mod tests { 240mod tests {
240 use insta::assert_debug_snapshot; 241 use expect::{expect, Expect};
241 242
242 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 243 use crate::completion::{
244 test_utils::{check_edit, completion_list},
245 CompletionKind,
246 };
243 247
244 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { 248 fn check(ra_fixture: &str, expect: Expect) {
245 do_completion(code, CompletionKind::Postfix) 249 let actual = completion_list(ra_fixture, CompletionKind::Postfix);
250 expect.assert_eq(&actual)
246 } 251 }
247 252
248 #[test] 253 #[test]
249 fn postfix_completion_works_for_trivial_path_expression() { 254 fn postfix_completion_works_for_trivial_path_expression() {
250 assert_debug_snapshot!( 255 check(
251 do_postfix_completion( 256 r#"
252 r#" 257fn main() {
253 fn main() { 258 let bar = true;
254 let bar = true; 259 bar.<|>
255 bar.<|> 260}
256 } 261"#,
257 "#, 262 expect![[r#"
258 ), 263 sn box Box::new(expr)
259 @r###" 264 sn call function(expr)
260 [ 265 sn dbg dbg!(expr)
261 CompletionItem { 266 sn if if expr {}
262 label: "box", 267 sn match match expr {}
263 source_range: 40..40, 268 sn not !expr
264 delete: 36..40, 269 sn ref &expr
265 insert: "Box::new(bar)", 270 sn refm &mut expr
266 detail: "Box::new(expr)", 271 sn while while expr {}
267 }, 272 "#]],
268 CompletionItem {
269 label: "call",
270 source_range: 40..40,
271 delete: 36..40,
272 insert: "${1}(bar)",
273 detail: "function(expr)",
274 },
275 CompletionItem {
276 label: "dbg",
277 source_range: 40..40,
278 delete: 36..40,
279 insert: "dbg!(bar)",
280 detail: "dbg!(expr)",
281 },
282 CompletionItem {
283 label: "if",
284 source_range: 40..40,
285 delete: 36..40,
286 insert: "if bar {\n $0\n}",
287 detail: "if expr {}",
288 },
289 CompletionItem {
290 label: "match",
291 source_range: 40..40,
292 delete: 36..40,
293 insert: "match bar {\n ${1:_} => {$0\\},\n}",
294 detail: "match expr {}",
295 },
296 CompletionItem {
297 label: "not",
298 source_range: 40..40,
299 delete: 36..40,
300 insert: "!bar",
301 detail: "!expr",
302 },
303 CompletionItem {
304 label: "ref",
305 source_range: 40..40,
306 delete: 36..40,
307 insert: "&bar",
308 detail: "&expr",
309 },
310 CompletionItem {
311 label: "refm",
312 source_range: 40..40,
313 delete: 36..40,
314 insert: "&mut bar",
315 detail: "&mut expr",
316 },
317 CompletionItem {
318 label: "while",
319 source_range: 40..40,
320 delete: 36..40,
321 insert: "while bar {\n $0\n}",
322 detail: "while expr {}",
323 },
324 ]
325 "###
326 ); 273 );
327 } 274 }
328 275
329 #[test] 276 #[test]
330 fn postfix_completion_works_for_option() { 277 fn postfix_type_filtering() {
331 assert_debug_snapshot!( 278 check(
332 do_postfix_completion( 279 r#"
333 r#" 280fn main() {
334 enum Option<T> { 281 let bar: u8 = 12;
335 Some(T), 282 bar.<|>
336 None, 283}
337 } 284"#,
338 285 expect![[r#"
339 fn main() { 286 sn box Box::new(expr)
340 let bar = Option::Some(true); 287 sn call function(expr)
341 bar.<|> 288 sn dbg dbg!(expr)
342 } 289 sn match match expr {}
343 "#, 290 sn ref &expr
344 ), 291 sn refm &mut expr
345 @r###" 292 "#]],
346 [ 293 )
347 CompletionItem {
348 label: "box",
349 source_range: 97..97,
350 delete: 93..97,
351 insert: "Box::new(bar)",
352 detail: "Box::new(expr)",
353 },
354 CompletionItem {
355 label: "call",
356 source_range: 97..97,
357 delete: 93..97,
358 insert: "${1}(bar)",
359 detail: "function(expr)",
360 },
361 CompletionItem {
362 label: "dbg",
363 source_range: 97..97,
364 delete: 93..97,
365 insert: "dbg!(bar)",
366 detail: "dbg!(expr)",
367 },
368 CompletionItem {
369 label: "ifl",
370 source_range: 97..97,
371 delete: 93..97,
372 insert: "if let Some($1) = bar {\n $0\n}",
373 detail: "if let Some {}",
374 },
375 CompletionItem {
376 label: "match",
377 source_range: 97..97,
378 delete: 93..97,
379 insert: "match bar {\n Some(${1:_}) => {$2\\},\n None => {$0\\},\n}",
380 detail: "match expr {}",
381 },
382 CompletionItem {
383 label: "not",
384 source_range: 97..97,
385 delete: 93..97,
386 insert: "!bar",
387 detail: "!expr",
388 },
389 CompletionItem {
390 label: "ref",
391 source_range: 97..97,
392 delete: 93..97,
393 insert: "&bar",
394 detail: "&expr",
395 },
396 CompletionItem {
397 label: "refm",
398 source_range: 97..97,
399 delete: 93..97,
400 insert: "&mut bar",
401 detail: "&mut expr",
402 },
403 CompletionItem {
404 label: "while",
405 source_range: 97..97,
406 delete: 93..97,
407 insert: "while let Some($1) = bar {\n $0\n}",
408 detail: "while let Some {}",
409 },
410 ]
411 "###
412 );
413 } 294 }
414 295
415 #[test] 296 #[test]
416 fn postfix_completion_works_for_result() { 297 fn option_iflet() {
417 assert_debug_snapshot!( 298 check_edit(
418 do_postfix_completion( 299 "ifl",
419 r#" 300 r#"
420 enum Result<T, E> { 301enum Option<T> { Some(T), None }
421 Ok(T), 302
422 Err(E), 303fn main() {
423 } 304 let bar = Option::Some(true);
305 bar.<|>
306}
307"#,
308 r#"
309enum Option<T> { Some(T), None }
424 310
425 fn main() { 311fn main() {
426 let bar = Result::Ok(true); 312 let bar = Option::Some(true);
427 bar.<|> 313 if let Some($1) = bar {
428 } 314 $0
429 "#, 315}
430 ), 316}
431 @r###" 317"#,
432 [
433 CompletionItem {
434 label: "box",
435 source_range: 98..98,
436 delete: 94..98,
437 insert: "Box::new(bar)",
438 detail: "Box::new(expr)",
439 },
440 CompletionItem {
441 label: "call",
442 source_range: 98..98,
443 delete: 94..98,
444 insert: "${1}(bar)",
445 detail: "function(expr)",
446 },
447 CompletionItem {
448 label: "dbg",
449 source_range: 98..98,
450 delete: 94..98,
451 insert: "dbg!(bar)",
452 detail: "dbg!(expr)",
453 },
454 CompletionItem {
455 label: "ifl",
456 source_range: 98..98,
457 delete: 94..98,
458 insert: "if let Ok($1) = bar {\n $0\n}",
459 detail: "if let Ok {}",
460 },
461 CompletionItem {
462 label: "match",
463 source_range: 98..98,
464 delete: 94..98,
465 insert: "match bar {\n Ok(${1:_}) => {$2\\},\n Err(${3:_}) => {$0\\},\n}",
466 detail: "match expr {}",
467 },
468 CompletionItem {
469 label: "not",
470 source_range: 98..98,
471 delete: 94..98,
472 insert: "!bar",
473 detail: "!expr",
474 },
475 CompletionItem {
476 label: "ref",
477 source_range: 98..98,
478 delete: 94..98,
479 insert: "&bar",
480 detail: "&expr",
481 },
482 CompletionItem {
483 label: "refm",
484 source_range: 98..98,
485 delete: 94..98,
486 insert: "&mut bar",
487 detail: "&mut expr",
488 },
489 CompletionItem {
490 label: "while",
491 source_range: 98..98,
492 delete: 94..98,
493 insert: "while let Ok($1) = bar {\n $0\n}",
494 detail: "while let Ok {}",
495 },
496 ]
497 "###
498 ); 318 );
499 } 319 }
500 320
501 #[test] 321 #[test]
502 fn some_postfix_completions_ignored() { 322 fn result_match() {
503 assert_debug_snapshot!( 323 check_edit(
504 do_postfix_completion( 324 "match",
505 r#" 325 r#"
506 fn main() { 326enum Result<T, E> { Ok(T), Err(E) }
507 let bar: u8 = 12; 327
508 bar.<|> 328fn main() {
509 } 329 let bar = Result::Ok(true);
510 "#, 330 bar.<|>
511 ), 331}
512 @r###" 332"#,
513 [ 333 r#"
514 CompletionItem { 334enum Result<T, E> { Ok(T), Err(E) }
515 label: "box", 335
516 source_range: 42..42, 336fn main() {
517 delete: 38..42, 337 let bar = Result::Ok(true);
518 insert: "Box::new(bar)", 338 match bar {
519 detail: "Box::new(expr)", 339 Ok(${1:_}) => {$2},
520 }, 340 Err(${3:_}) => {$0},
521 CompletionItem { 341}
522 label: "call", 342}
523 source_range: 42..42, 343"#,
524 delete: 38..42,
525 insert: "${1}(bar)",
526 detail: "function(expr)",
527 },
528 CompletionItem {
529 label: "dbg",
530 source_range: 42..42,
531 delete: 38..42,
532 insert: "dbg!(bar)",
533 detail: "dbg!(expr)",
534 },
535 CompletionItem {
536 label: "match",
537 source_range: 42..42,
538 delete: 38..42,
539 insert: "match bar {\n ${1:_} => {$0\\},\n}",
540 detail: "match expr {}",
541 },
542 CompletionItem {
543 label: "not",
544 source_range: 42..42,
545 delete: 38..42,
546 insert: "!bar",
547 detail: "!expr",
548 },
549 CompletionItem {
550 label: "ref",
551 source_range: 42..42,
552 delete: 38..42,
553 insert: "&bar",
554 detail: "&expr",
555 },
556 CompletionItem {
557 label: "refm",
558 source_range: 42..42,
559 delete: 38..42,
560 insert: "&mut bar",
561 detail: "&mut expr",
562 },
563 ]
564 "###
565 ); 344 );
566 } 345 }
567 346
568 #[test] 347 #[test]
569 fn postfix_completion_works_for_ambiguous_float_literal() { 348 fn postfix_completion_works_for_ambiguous_float_literal() {
570 assert_debug_snapshot!( 349 check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#)
571 do_postfix_completion(
572 r#"
573 fn main() {
574 42.<|>
575 }
576 "#,
577 ),
578 @r###"
579 [
580 CompletionItem {
581 label: "box",
582 source_range: 19..19,
583 delete: 16..19,
584 insert: "Box::new(42)",
585 detail: "Box::new(expr)",
586 },
587 CompletionItem {
588 label: "call",
589 source_range: 19..19,
590 delete: 16..19,
591 insert: "${1}(42)",
592 detail: "function(expr)",
593 },
594 CompletionItem {
595 label: "dbg",
596 source_range: 19..19,
597 delete: 16..19,
598 insert: "dbg!(42)",
599 detail: "dbg!(expr)",
600 },
601 CompletionItem {
602 label: "match",
603 source_range: 19..19,
604 delete: 16..19,
605 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
606 detail: "match expr {}",
607 },
608 CompletionItem {
609 label: "not",
610 source_range: 19..19,
611 delete: 16..19,
612 insert: "!42",
613 detail: "!expr",
614 },
615 CompletionItem {
616 label: "ref",
617 source_range: 19..19,
618 delete: 16..19,
619 insert: "&42",
620 detail: "&expr",
621 },
622 CompletionItem {
623 label: "refm",
624 source_range: 19..19,
625 delete: 16..19,
626 insert: "&mut 42",
627 detail: "&mut expr",
628 },
629 ]
630 "###
631 );
632 } 350 }
633 351
634 #[test] 352 #[test]
635 fn works_in_simple_macro() { 353 fn works_in_simple_macro() {
636 assert_debug_snapshot!( 354 check_edit(
637 do_postfix_completion( 355 "dbg",
638 r#" 356 r#"
639 macro_rules! m { ($e:expr) => { $e } } 357macro_rules! m { ($e:expr) => { $e } }
640 fn main() { 358fn main() {
641 let bar: u8 = 12; 359 let bar: u8 = 12;
642 m!(bar.b<|>) 360 m!(bar.d<|>)
643 } 361}
644 "#, 362"#,
645 ), 363 r#"
646 @r###" 364macro_rules! m { ($e:expr) => { $e } }
647 [ 365fn main() {
648 CompletionItem { 366 let bar: u8 = 12;
649 label: "box", 367 m!(dbg!(bar))
650 source_range: 84..85, 368}
651 delete: 80..85, 369"#,
652 insert: "Box::new(bar)",
653 detail: "Box::new(expr)",
654 },
655 CompletionItem {
656 label: "call",
657 source_range: 84..85,
658 delete: 80..85,
659 insert: "${1}(bar)",
660 detail: "function(expr)",
661 },
662 CompletionItem {
663 label: "dbg",
664 source_range: 84..85,
665 delete: 80..85,
666 insert: "dbg!(bar)",
667 detail: "dbg!(expr)",
668 },
669 CompletionItem {
670 label: "match",
671 source_range: 84..85,
672 delete: 80..85,
673 insert: "match bar {\n ${1:_} => {$0\\},\n}",
674 detail: "match expr {}",
675 },
676 CompletionItem {
677 label: "not",
678 source_range: 84..85,
679 delete: 80..85,
680 insert: "!bar",
681 detail: "!expr",
682 },
683 CompletionItem {
684 label: "ref",
685 source_range: 84..85,
686 delete: 80..85,
687 insert: "&bar",
688 detail: "&expr",
689 },
690 CompletionItem {
691 label: "refm",
692 source_range: 84..85,
693 delete: 80..85,
694 insert: "&mut bar",
695 detail: "&mut expr",
696 },
697 ]
698 "###
699 ); 370 );
700 } 371 }
701 372
702 #[test] 373 #[test]
703 fn postfix_completion_for_references() { 374 fn postfix_completion_for_references() {
704 assert_debug_snapshot!( 375 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#);
705 do_postfix_completion( 376 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#);
706 r#"
707 fn main() {
708 &&&&42.<|>
709 }
710 "#,
711 ),
712 @r###"
713 [
714 CompletionItem {
715 label: "box",
716 source_range: 23..23,
717 delete: 16..23,
718 insert: "Box::new(&&&&42)",
719 detail: "Box::new(expr)",
720 },
721 CompletionItem {
722 label: "call",
723 source_range: 23..23,
724 delete: 16..23,
725 insert: "${1}(&&&&42)",
726 detail: "function(expr)",
727 },
728 CompletionItem {
729 label: "dbg",
730 source_range: 23..23,
731 delete: 16..23,
732 insert: "dbg!(&&&&42)",
733 detail: "dbg!(expr)",
734 },
735 CompletionItem {
736 label: "match",
737 source_range: 23..23,
738 delete: 16..23,
739 insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
740 detail: "match expr {}",
741 },
742 CompletionItem {
743 label: "not",
744 source_range: 23..23,
745 delete: 20..23,
746 insert: "!42",
747 detail: "!expr",
748 },
749 CompletionItem {
750 label: "ref",
751 source_range: 23..23,
752 delete: 20..23,
753 insert: "&42",
754 detail: "&expr",
755 },
756 CompletionItem {
757 label: "refm",
758 source_range: 23..23,
759 delete: 20..23,
760 insert: "&mut 42",
761 detail: "&mut expr",
762 },
763 ]
764 "###
765 );
766 } 377 }
767} 378}
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs
index f133ce3ce..b08f5b9b4 100644
--- a/crates/ra_ide/src/completion/complete_qualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_qualified_path.rs
@@ -17,21 +17,20 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
17 return; 17 return;
18 } 18 }
19 19
20 let scope = ctx.scope(); 20 let context_module = ctx.scope.module();
21 let context_module = scope.module();
22 21
23 let res = match scope.resolve_hir_path_qualifier(&path) { 22 let resolution = match ctx.scope.resolve_hir_path_qualifier(&path) {
24 Some(res) => res, 23 Some(res) => res,
25 None => return, 24 None => return,
26 }; 25 };
27 26
28 // Add associated types on type parameters and `Self`. 27 // Add associated types on type parameters and `Self`.
29 res.assoc_type_shorthand_candidates(ctx.db, |alias| { 28 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
30 acc.add_type_alias(ctx, alias); 29 acc.add_type_alias(ctx, alias);
31 None::<()> 30 None::<()>
32 }); 31 });
33 32
34 match res { 33 match resolution {
35 PathResolution::Def(hir::ModuleDef::Module(module)) => { 34 PathResolution::Def(hir::ModuleDef::Module(module)) => {
36 let module_scope = module.scope(ctx.db, context_module); 35 let module_scope = module.scope(ctx.db, context_module);
37 for (name, def) in module_scope { 36 for (name, def) in module_scope {
@@ -68,7 +67,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
68 67
69 let krate = ctx.krate; 68 let krate = ctx.krate;
70 if let Some(krate) = krate { 69 if let Some(krate) = krate {
71 let traits_in_scope = ctx.scope().traits_in_scope(); 70 let traits_in_scope = ctx.scope.traits_in_scope();
72 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 71 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
73 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 72 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
74 return None; 73 return None;
@@ -113,13 +112,13 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
113 } 112 }
114 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { 113 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
115 if let Some(krate) = ctx.krate { 114 if let Some(krate) = ctx.krate {
116 let ty = match res { 115 let ty = match resolution {
117 PathResolution::TypeParam(param) => param.ty(ctx.db), 116 PathResolution::TypeParam(param) => param.ty(ctx.db),
118 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), 117 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
119 _ => return, 118 _ => return,
120 }; 119 };
121 120
122 let traits_in_scope = ctx.scope().traits_in_scope(); 121 let traits_in_scope = ctx.scope.traits_in_scope();
123 let mut seen = FxHashSet::default(); 122 let mut seen = FxHashSet::default();
124 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 123 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
125 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 124 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
@@ -147,1229 +146,588 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
147 146
148#[cfg(test)] 147#[cfg(test)]
149mod tests { 148mod tests {
149 use expect::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 152 use crate::completion::{
153 use insta::assert_debug_snapshot; 153 test_utils::{check_edit, completion_list},
154 CompletionKind,
155 };
156
157 fn check(ra_fixture: &str, expect: Expect) {
158 let actual = completion_list(ra_fixture, CompletionKind::Reference);
159 expect.assert_eq(&actual);
160 }
154 161
155 fn do_reference_completion(code: &str) -> Vec<CompletionItem> { 162 fn check_builtin(ra_fixture: &str, expect: Expect) {
156 do_completion(code, CompletionKind::Reference) 163 let actual = completion_list(ra_fixture, CompletionKind::BuiltinType);
164 expect.assert_eq(&actual);
157 } 165 }
158 166
159 #[test] 167 #[test]
160 fn dont_complete_current_use() { 168 fn dont_complete_current_use() {
161 mark::check!(dont_complete_current_use); 169 mark::check!(dont_complete_current_use);
162 let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); 170 check(r#"use self::foo<|>;"#, expect![[""]]);
163 assert!(completions.is_empty());
164 } 171 }
165 172
166 #[test] 173 #[test]
167 fn dont_complete_current_use_in_braces_with_glob() { 174 fn dont_complete_current_use_in_braces_with_glob() {
168 let completions = do_completion( 175 check(
169 r" 176 r#"
170 mod foo { pub struct S; } 177mod foo { pub struct S; }
171 use self::{foo::*, bar<|>}; 178use self::{foo::*, bar<|>};
172 ", 179"#,
173 CompletionKind::Reference, 180 expect![[r#"
181 st S
182 md foo
183 "#]],
174 ); 184 );
175 assert_eq!(completions.len(), 2);
176 } 185 }
177 186
178 #[test] 187 #[test]
179 fn dont_complete_primitive_in_use() { 188 fn dont_complete_primitive_in_use() {
180 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); 189 check_builtin(r#"use self::<|>;"#, expect![[""]]);
181 assert!(completions.is_empty());
182 } 190 }
183 191
184 #[test] 192 #[test]
185 fn dont_complete_primitive_in_module_scope() { 193 fn dont_complete_primitive_in_module_scope() {
186 let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); 194 check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]);
187 assert!(completions.is_empty());
188 } 195 }
189 196
190 #[test] 197 #[test]
191 fn completes_primitives() { 198 fn completes_primitives() {
192 let completions = 199 check_builtin(
193 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); 200 r#"fn main() { let _: <|> = 92; }"#,
194 assert_eq!(completions.len(), 17); 201 expect![[r#"
195 } 202 bt bool
196 203 bt char
197 #[test] 204 bt f32
198 fn completes_mod_with_docs() { 205 bt f64
199 assert_debug_snapshot!( 206 bt i128
200 do_reference_completion( 207 bt i16
201 r" 208 bt i32
202 use self::my<|>; 209 bt i64
203 210 bt i8
204 /// Some simple 211 bt isize
205 /// docs describing `mod my`. 212 bt str
206 mod my { 213 bt u128
207 struct Bar; 214 bt u16
208 } 215 bt u32
209 " 216 bt u64
210 ), 217 bt u8
211 @r###" 218 bt usize
212 [ 219 "#]],
213 CompletionItem {
214 label: "my",
215 source_range: 10..12,
216 delete: 10..12,
217 insert: "my",
218 kind: Module,
219 documentation: Documentation(
220 "Some simple\ndocs describing `mod my`.",
221 ),
222 },
223 ]
224 "###
225 ); 220 );
226 } 221 }
227 222
228 #[test] 223 #[test]
229 fn completes_mod_with_same_name_as_function() { 224 fn completes_mod_with_same_name_as_function() {
230 assert_debug_snapshot!( 225 check(
231 do_reference_completion( 226 r#"
232 r" 227use self::my::<|>;
233 use self::my::<|>; 228
234 229mod my { pub struct Bar; }
235 mod my { 230fn my() {}
236 pub struct Bar; 231"#,
237 } 232 expect![[r#"
238 233 st Bar
239 fn my() {} 234 "#]],
240 "
241 ),
242 @r###"
243 [
244 CompletionItem {
245 label: "Bar",
246 source_range: 14..14,
247 delete: 14..14,
248 insert: "Bar",
249 kind: Struct,
250 },
251 ]
252 "###
253 ); 235 );
254 } 236 }
255 237
256 #[test] 238 #[test]
257 fn path_visibility() { 239 fn filters_visibility() {
258 assert_debug_snapshot!( 240 check(
259 do_reference_completion( 241 r#"
260 r" 242use self::my::<|>;
261 use self::my::<|>; 243
262 244mod my {
263 mod my { 245 struct Bar;
264 struct Bar; 246 pub struct Foo;
265 pub struct Foo; 247 pub use Bar as PublicBar;
266 pub use Bar as PublicBar; 248}
267 } 249"#,
268 " 250 expect![[r#"
269 ), 251 st Foo
270 @r###" 252 st PublicBar
271 [ 253 "#]],
272 CompletionItem {
273 label: "Foo",
274 source_range: 14..14,
275 delete: 14..14,
276 insert: "Foo",
277 kind: Struct,
278 },
279 CompletionItem {
280 label: "PublicBar",
281 source_range: 14..14,
282 delete: 14..14,
283 insert: "PublicBar",
284 kind: Struct,
285 },
286 ]
287 "###
288 ); 254 );
289 } 255 }
290 256
291 #[test] 257 #[test]
292 fn completes_use_item_starting_with_self() { 258 fn completes_use_item_starting_with_self() {
293 assert_debug_snapshot!( 259 check(
294 do_reference_completion( 260 r#"
295 r" 261use self::m::<|>;
296 use self::m::<|>;
297 262
298 mod m { 263mod m { pub struct Bar; }
299 pub struct Bar; 264"#,
300 } 265 expect![[r#"
301 " 266 st Bar
302 ), 267 "#]],
303 @r###"
304 [
305 CompletionItem {
306 label: "Bar",
307 source_range: 13..13,
308 delete: 13..13,
309 insert: "Bar",
310 kind: Struct,
311 },
312 ]
313 "###
314 ); 268 );
315 } 269 }
316 270
317 #[test] 271 #[test]
318 fn completes_use_item_starting_with_crate() { 272 fn completes_use_item_starting_with_crate() {
319 assert_debug_snapshot!( 273 check(
320 do_reference_completion( 274 r#"
321 " 275//- /lib.rs
322 //- /lib.rs 276mod foo;
323 mod foo; 277struct Spam;
324 struct Spam; 278//- /foo.rs
325 //- /foo.rs 279use crate::Sp<|>
326 use crate::Sp<|> 280"#,
327 " 281 expect![[r#"
328 ), 282 st Spam
329 @r###" 283 md foo
330 [ 284 "#]],
331 CompletionItem {
332 label: "Spam",
333 source_range: 11..13,
334 delete: 11..13,
335 insert: "Spam",
336 kind: Struct,
337 },
338 CompletionItem {
339 label: "foo",
340 source_range: 11..13,
341 delete: 11..13,
342 insert: "foo",
343 kind: Module,
344 },
345 ]
346 "###
347 ); 285 );
348 } 286 }
349 287
350 #[test] 288 #[test]
351 fn completes_nested_use_tree() { 289 fn completes_nested_use_tree() {
352 assert_debug_snapshot!( 290 check(
353 do_reference_completion( 291 r#"
354 " 292//- /lib.rs
355 //- /lib.rs 293mod foo;
356 mod foo; 294struct Spam;
357 struct Spam; 295//- /foo.rs
358 //- /foo.rs 296use crate::{Sp<|>};
359 use crate::{Sp<|>}; 297"#,
360 " 298 expect![[r#"
361 ), 299 st Spam
362 @r###" 300 md foo
363 [ 301 "#]],
364 CompletionItem {
365 label: "Spam",
366 source_range: 12..14,
367 delete: 12..14,
368 insert: "Spam",
369 kind: Struct,
370 },
371 CompletionItem {
372 label: "foo",
373 source_range: 12..14,
374 delete: 12..14,
375 insert: "foo",
376 kind: Module,
377 },
378 ]
379 "###
380 ); 302 );
381 } 303 }
382 304
383 #[test] 305 #[test]
384 fn completes_deeply_nested_use_tree() { 306 fn completes_deeply_nested_use_tree() {
385 assert_debug_snapshot!( 307 check(
386 do_reference_completion( 308 r#"
387 " 309//- /lib.rs
388 //- /lib.rs 310mod foo;
389 mod foo; 311pub mod bar {
390 pub mod bar { 312 pub mod baz {
391 pub mod baz { 313 pub struct Spam;
392 pub struct Spam;
393 }
394 }
395 //- /foo.rs
396 use crate::{bar::{baz::Sp<|>}};
397 "
398 ),
399 @r###"
400 [
401 CompletionItem {
402 label: "Spam",
403 source_range: 23..25,
404 delete: 23..25,
405 insert: "Spam",
406 kind: Struct,
407 },
408 ]
409 "###
410 );
411 }
412
413 #[test]
414 fn completes_enum_variant() {
415 assert_debug_snapshot!(
416 do_reference_completion(
417 "
418 //- /lib.rs
419 /// An enum
420 enum E {
421 /// Foo Variant
422 Foo,
423 /// Bar Variant with i32
424 Bar(i32)
425 }
426 fn foo() { let _ = E::<|> }
427 "
428 ),
429 @r###"
430 [
431 CompletionItem {
432 label: "Bar(…)",
433 source_range: 116..116,
434 delete: 116..116,
435 insert: "Bar($0)",
436 kind: EnumVariant,
437 lookup: "Bar",
438 detail: "(i32)",
439 documentation: Documentation(
440 "Bar Variant with i32",
441 ),
442 trigger_call_info: true,
443 },
444 CompletionItem {
445 label: "Foo",
446 source_range: 116..116,
447 delete: 116..116,
448 insert: "Foo",
449 kind: EnumVariant,
450 detail: "()",
451 documentation: Documentation(
452 "Foo Variant",
453 ),
454 },
455 ]
456 "###
457 );
458 }
459
460 #[test]
461 fn completes_enum_variant_with_details() {
462 assert_debug_snapshot!(
463 do_reference_completion(
464 "
465 //- /lib.rs
466 struct S { field: u32 }
467 /// An enum
468 enum E {
469 /// Foo Variant (empty)
470 Foo,
471 /// Bar Variant with i32 and u32
472 Bar(i32, u32),
473 ///
474 S(S),
475 }
476 fn foo() { let _ = E::<|> }
477 "
478 ),
479 @r###"
480 [
481 CompletionItem {
482 label: "Bar(…)",
483 source_range: 180..180,
484 delete: 180..180,
485 insert: "Bar($0)",
486 kind: EnumVariant,
487 lookup: "Bar",
488 detail: "(i32, u32)",
489 documentation: Documentation(
490 "Bar Variant with i32 and u32",
491 ),
492 trigger_call_info: true,
493 },
494 CompletionItem {
495 label: "Foo",
496 source_range: 180..180,
497 delete: 180..180,
498 insert: "Foo",
499 kind: EnumVariant,
500 detail: "()",
501 documentation: Documentation(
502 "Foo Variant (empty)",
503 ),
504 },
505 CompletionItem {
506 label: "S(…)",
507 source_range: 180..180,
508 delete: 180..180,
509 insert: "S($0)",
510 kind: EnumVariant,
511 lookup: "S",
512 detail: "(S)",
513 documentation: Documentation(
514 "",
515 ),
516 trigger_call_info: true,
517 },
518 ]
519 "###
520 );
521 } 314 }
522 315}
523 #[test] 316//- /foo.rs
524 fn completes_struct_associated_method() { 317use crate::{bar::{baz::Sp<|>}};
525 assert_debug_snapshot!( 318"#,
526 do_reference_completion( 319 expect![[r#"
527 " 320 st Spam
528 //- /lib.rs 321 "#]],
529 /// A Struct
530 struct S;
531
532 impl S {
533 /// An associated method
534 fn m() { }
535 }
536
537 fn foo() { let _ = S::<|> }
538 "
539 ),
540 @r###"
541 [
542 CompletionItem {
543 label: "m()",
544 source_range: 102..102,
545 delete: 102..102,
546 insert: "m()$0",
547 kind: Function,
548 lookup: "m",
549 detail: "fn m()",
550 documentation: Documentation(
551 "An associated method",
552 ),
553 },
554 ]
555 "###
556 ); 322 );
557 } 323 }
558 324
559 #[test] 325 #[test]
560 fn completes_struct_associated_method_with_self() { 326 fn completes_enum_variant() {
561 assert_debug_snapshot!( 327 check(
562 do_reference_completion( 328 r#"
563 " 329enum E { Foo, Bar(i32) }
564 //- /lib.rs 330fn foo() { let _ = E::<|> }
565 /// A Struct 331"#,
566 struct S; 332 expect![[r#"
567 333 ev Bar(…) (i32)
568 impl S { 334 ev Foo ()
569 /// An associated method 335 "#]],
570 fn m(&self) { }
571 }
572
573 fn foo() { let _ = S::<|> }
574 "
575 ),
576 @r###"
577 [
578 CompletionItem {
579 label: "m()",
580 source_range: 107..107,
581 delete: 107..107,
582 insert: "m()$0",
583 kind: Method,
584 lookup: "m",
585 detail: "fn m(&self)",
586 documentation: Documentation(
587 "An associated method",
588 ),
589 },
590 ]
591 "###
592 ); 336 );
593 } 337 }
594 338
595 #[test] 339 #[test]
596 fn completes_struct_associated_const() { 340 fn completes_struct_associated_items() {
597 assert_debug_snapshot!( 341 check(
598 do_reference_completion( 342 r#"
599 " 343//- /lib.rs
600 //- /lib.rs 344struct S;
601 /// A Struct 345
602 struct S; 346impl S {
603 347 fn a() {}
604 impl S { 348 fn b(&self) {}
605 /// An associated const 349 const C: i32 = 42;
606 const C: i32 = 42; 350 type T = i32;
607 } 351}
608 352
609 fn foo() { let _ = S::<|> } 353fn foo() { let _ = S::<|> }
610 " 354"#,
611 ), 355 expect![[r#"
612 @r###" 356 ct C const C: i32 = 42;
613 [ 357 ta T type T = i32;
614 CompletionItem { 358 fn a() fn a()
615 label: "C", 359 me b() fn b(&self)
616 source_range: 109..109, 360 "#]],
617 delete: 109..109,
618 insert: "C",
619 kind: Const,
620 detail: "const C: i32 = 42;",
621 documentation: Documentation(
622 "An associated const",
623 ),
624 },
625 ]
626 "###
627 ); 361 );
628 } 362 }
629 363
630 #[test] 364 #[test]
631 fn completes_struct_associated_type() { 365 fn associated_item_visibility() {
632 assert_debug_snapshot!( 366 check(
633 do_reference_completion( 367 r#"
634 " 368struct S;
635 //- /lib.rs
636 /// A Struct
637 struct S;
638
639 impl S {
640 /// An associated type
641 type T = i32;
642 }
643 369
644 fn foo() { let _ = S::<|> } 370mod m {
645 " 371 impl super::S {
646 ), 372 pub(super) fn public_method() { }
647 @r###" 373 fn private_method() { }
648 [ 374 pub(super) type PublicType = u32;
649 CompletionItem { 375 type PrivateType = u32;
650 label: "T", 376 pub(super) const PUBLIC_CONST: u32 = 1;
651 source_range: 103..103, 377 const PRIVATE_CONST: u32 = 1;
652 delete: 103..103,
653 insert: "T",
654 kind: TypeAlias,
655 detail: "type T = i32;",
656 documentation: Documentation(
657 "An associated type",
658 ),
659 },
660 ]
661 "###
662 );
663 } 378 }
379}
664 380
665 #[test] 381fn foo() { let _ = S::<|> }
666 fn associated_item_visibility() { 382"#,
667 assert_debug_snapshot!( 383 expect![[r#"
668 do_reference_completion( 384 ct PUBLIC_CONST pub(super) const PUBLIC_CONST: u32 = 1;
669 " 385 ta PublicType pub(super) type PublicType = u32;
670 //- /lib.rs 386 fn public_method() pub(super) fn public_method()
671 struct S; 387 "#]],
672
673 mod m {
674 impl super::S {
675 pub(super) fn public_method() { }
676 fn private_method() { }
677 pub(super) type PublicType = u32;
678 type PrivateType = u32;
679 pub(super) const PUBLIC_CONST: u32 = 1;
680 const PRIVATE_CONST: u32 = 1;
681 }
682 }
683
684 fn foo() { let _ = S::<|> }
685 "
686 ),
687 @r###"
688 [
689 CompletionItem {
690 label: "PUBLIC_CONST",
691 source_range: 304..304,
692 delete: 304..304,
693 insert: "PUBLIC_CONST",
694 kind: Const,
695 detail: "pub(super) const PUBLIC_CONST: u32 = 1;",
696 },
697 CompletionItem {
698 label: "PublicType",
699 source_range: 304..304,
700 delete: 304..304,
701 insert: "PublicType",
702 kind: TypeAlias,
703 detail: "pub(super) type PublicType = u32;",
704 },
705 CompletionItem {
706 label: "public_method()",
707 source_range: 304..304,
708 delete: 304..304,
709 insert: "public_method()$0",
710 kind: Function,
711 lookup: "public_method",
712 detail: "pub(super) fn public_method()",
713 },
714 ]
715 "###
716 ); 388 );
717 } 389 }
718 390
719 #[test] 391 #[test]
720 fn completes_enum_associated_method() { 392 fn completes_enum_associated_method() {
721 assert_debug_snapshot!( 393 check(
722 do_reference_completion( 394 r#"
723 " 395enum E {};
724 //- /lib.rs 396impl E { fn m() { } }
725 /// An enum 397
726 enum S {}; 398fn foo() { let _ = E::<|> }
727 399 "#,
728 impl S { 400 expect![[r#"
729 /// An associated method 401 fn m() fn m()
730 fn m() { } 402 "#]],
731 }
732
733 fn foo() { let _ = S::<|> }
734 "
735 ),
736 @r###"
737 [
738 CompletionItem {
739 label: "m()",
740 source_range: 102..102,
741 delete: 102..102,
742 insert: "m()$0",
743 kind: Function,
744 lookup: "m",
745 detail: "fn m()",
746 documentation: Documentation(
747 "An associated method",
748 ),
749 },
750 ]
751 "###
752 ); 403 );
753 } 404 }
754 405
755 #[test] 406 #[test]
756 fn completes_union_associated_method() { 407 fn completes_union_associated_method() {
757 assert_debug_snapshot!( 408 check(
758 do_reference_completion( 409 r#"
759 " 410union U {};
760 //- /lib.rs 411impl U { fn m() { } }
761 /// A union 412
762 union U {}; 413fn foo() { let _ = U::<|> }
763 414"#,
764 impl U { 415 expect![[r#"
765 /// An associated method 416 fn m() fn m()
766 fn m() { } 417 "#]],
767 }
768
769 fn foo() { let _ = U::<|> }
770 "
771 ),
772 @r###"
773 [
774 CompletionItem {
775 label: "m()",
776 source_range: 103..103,
777 delete: 103..103,
778 insert: "m()$0",
779 kind: Function,
780 lookup: "m",
781 detail: "fn m()",
782 documentation: Documentation(
783 "An associated method",
784 ),
785 },
786 ]
787 "###
788 ); 418 );
789 } 419 }
790 420
791 #[test] 421 #[test]
792 fn completes_use_paths_across_crates() { 422 fn completes_use_paths_across_crates() {
793 assert_debug_snapshot!( 423 check(
794 do_reference_completion( 424 r#"
795 " 425//- /main.rs
796 //- /main.rs 426use foo::<|>;
797 use foo::<|>; 427
798 428//- /foo/lib.rs
799 //- /foo/lib.rs 429pub mod bar { pub struct S; }
800 pub mod bar { 430"#,
801 pub struct S; 431 expect![[r#"
802 } 432 md bar
803 " 433 "#]],
804 ),
805 @r###"
806 [
807 CompletionItem {
808 label: "bar",
809 source_range: 9..9,
810 delete: 9..9,
811 insert: "bar",
812 kind: Module,
813 },
814 ]
815 "###
816 ); 434 );
817 } 435 }
818 436
819 #[test] 437 #[test]
820 fn completes_trait_associated_method_1() { 438 fn completes_trait_associated_method_1() {
821 assert_debug_snapshot!( 439 check(
822 do_reference_completion( 440 r#"
823 " 441trait Trait { fn m(); }
824 //- /lib.rs
825 trait Trait {
826 /// A trait method
827 fn m();
828 }
829 442
830 fn foo() { let _ = Trait::<|> } 443fn foo() { let _ = Trait::<|> }
831 " 444"#,
832 ), 445 expect![[r#"
833 @r###" 446 fn m() fn m()
834 [ 447 "#]],
835 CompletionItem {
836 label: "m()",
837 source_range: 74..74,
838 delete: 74..74,
839 insert: "m()$0",
840 kind: Function,
841 lookup: "m",
842 detail: "fn m()",
843 documentation: Documentation(
844 "A trait method",
845 ),
846 },
847 ]
848 "###
849 ); 448 );
850 } 449 }
851 450
852 #[test] 451 #[test]
853 fn completes_trait_associated_method_2() { 452 fn completes_trait_associated_method_2() {
854 assert_debug_snapshot!( 453 check(
855 do_reference_completion( 454 r#"
856 " 455trait Trait { fn m(); }
857 //- /lib.rs 456
858 trait Trait { 457struct S;
859 /// A trait method 458impl Trait for S {}
860 fn m();
861 }
862 459
863 struct S; 460fn foo() { let _ = S::<|> }
864 impl Trait for S {} 461"#,
865 462 expect![[r#"
866 fn foo() { let _ = S::<|> } 463 fn m() fn m()
867 " 464 "#]],
868 ),
869 @r###"
870 [
871 CompletionItem {
872 label: "m()",
873 source_range: 101..101,
874 delete: 101..101,
875 insert: "m()$0",
876 kind: Function,
877 lookup: "m",
878 detail: "fn m()",
879 documentation: Documentation(
880 "A trait method",
881 ),
882 },
883 ]
884 "###
885 ); 465 );
886 } 466 }
887 467
888 #[test] 468 #[test]
889 fn completes_trait_associated_method_3() { 469 fn completes_trait_associated_method_3() {
890 assert_debug_snapshot!( 470 check(
891 do_reference_completion( 471 r#"
892 " 472trait Trait { fn m(); }
893 //- /lib.rs
894 trait Trait {
895 /// A trait method
896 fn m();
897 }
898 473
899 struct S; 474struct S;
900 impl Trait for S {} 475impl Trait for S {}
901 476
902 fn foo() { let _ = <S as Trait>::<|> } 477fn foo() { let _ = <S as Trait>::<|> }
903 " 478"#,
904 ), 479 expect![[r#"
905 @r###" 480 fn m() fn m()
906 [ 481 "#]],
907 CompletionItem {
908 label: "m()",
909 source_range: 112..112,
910 delete: 112..112,
911 insert: "m()$0",
912 kind: Function,
913 lookup: "m",
914 detail: "fn m()",
915 documentation: Documentation(
916 "A trait method",
917 ),
918 },
919 ]
920 "###
921 ); 482 );
922 } 483 }
923 484
924 #[test] 485 #[test]
925 fn completes_ty_param_assoc_ty() { 486 fn completes_ty_param_assoc_ty() {
926 assert_debug_snapshot!( 487 check(
927 do_reference_completion( 488 r#"
928 " 489trait Super {
929 //- /lib.rs 490 type Ty;
930 trait Super { 491 const CONST: u8;
931 type Ty; 492 fn func() {}
932 const CONST: u8; 493 fn method(&self) {}
933 fn func() {} 494}
934 fn method(&self) {}
935 }
936 495
937 trait Sub: Super { 496trait Sub: Super {
938 type SubTy; 497 type SubTy;
939 const C2: (); 498 const C2: ();
940 fn subfunc() {} 499 fn subfunc() {}
941 fn submethod(&self) {} 500 fn submethod(&self) {}
942 } 501}
943 502
944 fn foo<T: Sub>() { 503fn foo<T: Sub>() { T::<|> }
945 T::<|> 504"#,
946 } 505 expect![[r#"
947 " 506 ct C2 const C2: ();
948 ), 507 ct CONST const CONST: u8;
949 @r###" 508 ta SubTy type SubTy;
950 [ 509 ta Ty type Ty;
951 CompletionItem { 510 fn func() fn func()
952 label: "C2", 511 me method() fn method(&self)
953 source_range: 221..221, 512 fn subfunc() fn subfunc()
954 delete: 221..221, 513 me submethod() fn submethod(&self)
955 insert: "C2", 514 "#]],
956 kind: Const,
957 detail: "const C2: ();",
958 },
959 CompletionItem {
960 label: "CONST",
961 source_range: 221..221,
962 delete: 221..221,
963 insert: "CONST",
964 kind: Const,
965 detail: "const CONST: u8;",
966 },
967 CompletionItem {
968 label: "SubTy",
969 source_range: 221..221,
970 delete: 221..221,
971 insert: "SubTy",
972 kind: TypeAlias,
973 detail: "type SubTy;",
974 },
975 CompletionItem {
976 label: "Ty",
977 source_range: 221..221,
978 delete: 221..221,
979 insert: "Ty",
980 kind: TypeAlias,
981 detail: "type Ty;",
982 },
983 CompletionItem {
984 label: "func()",
985 source_range: 221..221,
986 delete: 221..221,
987 insert: "func()$0",
988 kind: Function,
989 lookup: "func",
990 detail: "fn func()",
991 },
992 CompletionItem {
993 label: "method()",
994 source_range: 221..221,
995 delete: 221..221,
996 insert: "method()$0",
997 kind: Method,
998 lookup: "method",
999 detail: "fn method(&self)",
1000 },
1001 CompletionItem {
1002 label: "subfunc()",
1003 source_range: 221..221,
1004 delete: 221..221,
1005 insert: "subfunc()$0",
1006 kind: Function,
1007 lookup: "subfunc",
1008 detail: "fn subfunc()",
1009 },
1010 CompletionItem {
1011 label: "submethod()",
1012 source_range: 221..221,
1013 delete: 221..221,
1014 insert: "submethod()$0",
1015 kind: Method,
1016 lookup: "submethod",
1017 detail: "fn submethod(&self)",
1018 },
1019 ]
1020 "###
1021 ); 515 );
1022 } 516 }
1023 517
1024 #[test] 518 #[test]
1025 fn completes_self_param_assoc_ty() { 519 fn completes_self_param_assoc_ty() {
1026 assert_debug_snapshot!( 520 check(
1027 do_reference_completion( 521 r#"
1028 " 522trait Super {
1029 //- /lib.rs 523 type Ty;
1030 trait Super { 524 const CONST: u8 = 0;
1031 type Ty; 525 fn func() {}
1032 const CONST: u8 = 0; 526 fn method(&self) {}
1033 fn func() {} 527}
1034 fn method(&self) {}
1035 }
1036 528
1037 trait Sub: Super { 529trait Sub: Super {
1038 type SubTy; 530 type SubTy;
1039 const C2: () = (); 531 const C2: () = ();
1040 fn subfunc() {} 532 fn subfunc() {}
1041 fn submethod(&self) {} 533 fn submethod(&self) {}
1042 } 534}
1043 535
1044 struct Wrap<T>(T); 536struct Wrap<T>(T);
1045 impl<T> Super for Wrap<T> {} 537impl<T> Super for Wrap<T> {}
1046 impl<T> Sub for Wrap<T> { 538impl<T> Sub for Wrap<T> {
1047 fn subfunc() { 539 fn subfunc() {
1048 // Should be able to assume `Self: Sub + Super` 540 // Should be able to assume `Self: Sub + Super`
1049 Self::<|> 541 Self::<|>
1050 } 542 }
1051 } 543}
1052 " 544"#,
1053 ), 545 expect![[r#"
1054 @r###" 546 ct C2 const C2: () = ();
1055 [ 547 ct CONST const CONST: u8 = 0;
1056 CompletionItem { 548 ta SubTy type SubTy;
1057 label: "C2", 549 ta Ty type Ty;
1058 source_range: 367..367, 550 fn func() fn func()
1059 delete: 367..367, 551 me method() fn method(&self)
1060 insert: "C2", 552 fn subfunc() fn subfunc()
1061 kind: Const, 553 me submethod() fn submethod(&self)
1062 detail: "const C2: () = ();", 554 "#]],
1063 },
1064 CompletionItem {
1065 label: "CONST",
1066 source_range: 367..367,
1067 delete: 367..367,
1068 insert: "CONST",
1069 kind: Const,
1070 detail: "const CONST: u8 = 0;",
1071 },
1072 CompletionItem {
1073 label: "SubTy",
1074 source_range: 367..367,
1075 delete: 367..367,
1076 insert: "SubTy",
1077 kind: TypeAlias,
1078 detail: "type SubTy;",
1079 },
1080 CompletionItem {
1081 label: "Ty",
1082 source_range: 367..367,
1083 delete: 367..367,
1084 insert: "Ty",
1085 kind: TypeAlias,
1086 detail: "type Ty;",
1087 },
1088 CompletionItem {
1089 label: "func()",
1090 source_range: 367..367,
1091 delete: 367..367,
1092 insert: "func()$0",
1093 kind: Function,
1094 lookup: "func",
1095 detail: "fn func()",
1096 },
1097 CompletionItem {
1098 label: "method()",
1099 source_range: 367..367,
1100 delete: 367..367,
1101 insert: "method()$0",
1102 kind: Method,
1103 lookup: "method",
1104 detail: "fn method(&self)",
1105 },
1106 CompletionItem {
1107 label: "subfunc()",
1108 source_range: 367..367,
1109 delete: 367..367,
1110 insert: "subfunc()$0",
1111 kind: Function,
1112 lookup: "subfunc",
1113 detail: "fn subfunc()",
1114 },
1115 CompletionItem {
1116 label: "submethod()",
1117 source_range: 367..367,
1118 delete: 367..367,
1119 insert: "submethod()$0",
1120 kind: Method,
1121 lookup: "submethod",
1122 detail: "fn submethod(&self)",
1123 },
1124 ]
1125 "###
1126 ); 555 );
1127 } 556 }
1128 557
1129 #[test] 558 #[test]
1130 fn completes_type_alias() { 559 fn completes_type_alias() {
1131 assert_debug_snapshot!( 560 check(
1132 do_reference_completion( 561 r#"
1133 " 562struct S;
1134 struct S; 563impl S { fn foo() {} }
1135 impl S { fn foo() {} } 564type T = S;
1136 type T = S; 565impl T { fn bar() {} }
1137 impl T { fn bar() {} } 566
1138 567fn main() { T::<|>; }
1139 fn main() { 568"#,
1140 T::<|>; 569 expect![[r#"
1141 } 570 fn bar() fn bar()
1142 " 571 fn foo() fn foo()
1143 ), 572 "#]],
1144 @r###"
1145 [
1146 CompletionItem {
1147 label: "bar()",
1148 source_range: 88..88,
1149 delete: 88..88,
1150 insert: "bar()$0",
1151 kind: Function,
1152 lookup: "bar",
1153 detail: "fn bar()",
1154 },
1155 CompletionItem {
1156 label: "foo()",
1157 source_range: 88..88,
1158 delete: 88..88,
1159 insert: "foo()$0",
1160 kind: Function,
1161 lookup: "foo",
1162 detail: "fn foo()",
1163 },
1164 ]
1165 "###
1166 ); 573 );
1167 } 574 }
1168 575
1169 #[test] 576 #[test]
1170 fn completes_qualified_macros() { 577 fn completes_qualified_macros() {
1171 assert_debug_snapshot!( 578 check(
1172 do_reference_completion( 579 r#"
1173 " 580#[macro_export]
1174 #[macro_export] 581macro_rules! foo { () => {} }
1175 macro_rules! foo { 582
1176 () => {} 583fn main() { let _ = crate::<|> }
1177 } 584 "#,
585 expect![[r##"
586 ma foo!(…) #[macro_export]
587 macro_rules! foo
588 fn main() fn main()
589 "##]],
590 );
591 }
1178 592
1179 fn main() { 593 #[test]
1180 let _ = crate::<|> 594 fn test_super_super_completion() {
1181 } 595 check(
1182 " 596 r#"
1183 ), 597mod a {
1184 @r###" 598 const A: usize = 0;
1185 [ 599 mod b {
1186 CompletionItem { 600 const B: usize = 0;
1187 label: "foo!(…)", 601 mod c { use super::super::<|> }
1188 source_range: 82..82, 602 }
1189 delete: 82..82, 603}
1190 insert: "foo!($0)", 604"#,
1191 kind: Macro, 605 expect![[r#"
1192 detail: "#[macro_export]\nmacro_rules! foo", 606 ct A
1193 }, 607 md b
1194 CompletionItem { 608 "#]],
1195 label: "main()",
1196 source_range: 82..82,
1197 delete: 82..82,
1198 insert: "main()$0",
1199 kind: Function,
1200 lookup: "main",
1201 detail: "fn main()",
1202 },
1203 ]
1204 "###
1205 ); 609 );
1206 } 610 }
1207 611
1208 #[test] 612 #[test]
1209 fn completes_reexported_items_under_correct_name() { 613 fn completes_reexported_items_under_correct_name() {
1210 assert_debug_snapshot!( 614 check(
1211 do_reference_completion( 615 r#"
1212 r" 616fn foo() { self::m::<|> }
1213 fn foo() {
1214 self::m::<|>
1215 }
1216 617
1217 mod m { 618mod m {
1218 pub use super::p::wrong_fn as right_fn; 619 pub use super::p::wrong_fn as right_fn;
1219 pub use super::p::WRONG_CONST as RIGHT_CONST; 620 pub use super::p::WRONG_CONST as RIGHT_CONST;
1220 pub use super::p::WrongType as RightType; 621 pub use super::p::WrongType as RightType;
1221 } 622}
1222 mod p { 623mod p {
1223 fn wrong_fn() {} 624 fn wrong_fn() {}
1224 const WRONG_CONST: u32 = 1; 625 const WRONG_CONST: u32 = 1;
1225 struct WrongType {}; 626 struct WrongType {};
1226 } 627}
1227 " 628"#,
1228 ), 629 expect![[r#"
1229 @r###" 630 ct RIGHT_CONST
1230 [ 631 st RightType
1231 CompletionItem { 632 fn right_fn() fn wrong_fn()
1232 label: "RIGHT_CONST", 633 "#]],
1233 source_range: 24..24, 634 );
1234 delete: 24..24, 635
1235 insert: "RIGHT_CONST", 636 check_edit(
1236 kind: Const, 637 "RightType",
1237 }, 638 r#"
1238 CompletionItem { 639fn foo() { self::m::<|> }
1239 label: "RightType", 640
1240 source_range: 24..24, 641mod m {
1241 delete: 24..24, 642 pub use super::p::wrong_fn as right_fn;
1242 insert: "RightType", 643 pub use super::p::WRONG_CONST as RIGHT_CONST;
1243 kind: Struct, 644 pub use super::p::WrongType as RightType;
1244 }, 645}
1245 CompletionItem { 646mod p {
1246 label: "right_fn()", 647 fn wrong_fn() {}
1247 source_range: 24..24, 648 const WRONG_CONST: u32 = 1;
1248 delete: 24..24, 649 struct WrongType {};
1249 insert: "right_fn()$0", 650}
1250 kind: Function, 651"#,
1251 lookup: "right_fn", 652 r#"
1252 detail: "fn wrong_fn()", 653fn foo() { self::m::RightType }
1253 }, 654
1254 ] 655mod m {
1255 "### 656 pub use super::p::wrong_fn as right_fn;
657 pub use super::p::WRONG_CONST as RIGHT_CONST;
658 pub use super::p::WrongType as RightType;
659}
660mod p {
661 fn wrong_fn() {}
662 const WRONG_CONST: u32 = 1;
663 struct WrongType {};
664}
665"#,
1256 ); 666 );
1257 } 667 }
1258 668
1259 #[test] 669 #[test]
1260 fn completes_in_simple_macro_call() { 670 fn completes_in_simple_macro_call() {
1261 let completions = do_reference_completion( 671 check(
1262 r#" 672 r#"
1263 macro_rules! m { ($e:expr) => { $e } } 673macro_rules! m { ($e:expr) => { $e } }
1264 fn main() { m!(self::f<|>); } 674fn main() { m!(self::f<|>); }
1265 fn foo() {} 675fn foo() {}
1266 "#, 676"#,
677 expect![[r#"
678 fn foo() fn foo()
679 fn main() fn main()
680 "#]],
1267 ); 681 );
1268 assert_debug_snapshot!(completions, @r###"
1269 [
1270 CompletionItem {
1271 label: "foo()",
1272 source_range: 60..61,
1273 delete: 60..61,
1274 insert: "foo()$0",
1275 kind: Function,
1276 lookup: "foo",
1277 detail: "fn foo()",
1278 },
1279 CompletionItem {
1280 label: "main()",
1281 source_range: 60..61,
1282 delete: 60..61,
1283 insert: "main()$0",
1284 kind: Function,
1285 lookup: "main",
1286 detail: "fn main()",
1287 },
1288 ]
1289 "###);
1290 } 682 }
1291 683
1292 #[test] 684 #[test]
1293 fn function_mod_share_name() { 685 fn function_mod_share_name() {
1294 assert_debug_snapshot!( 686 check(
1295 do_reference_completion( 687 r#"
1296 r" 688fn foo() { self::m::<|> }
1297 fn foo() {
1298 self::m::<|>
1299 }
1300 689
1301 mod m { 690mod m {
1302 pub mod z {} 691 pub mod z {}
1303 pub fn z() {} 692 pub fn z() {}
1304 } 693}
1305 ", 694"#,
1306 ), 695 expect![[r#"
1307 @r###" 696 md z
1308 [ 697 fn z() pub fn z()
1309 CompletionItem { 698 "#]],
1310 label: "z",
1311 source_range: 24..24,
1312 delete: 24..24,
1313 insert: "z",
1314 kind: Module,
1315 },
1316 CompletionItem {
1317 label: "z()",
1318 source_range: 24..24,
1319 delete: 24..24,
1320 insert: "z()$0",
1321 kind: Function,
1322 lookup: "z",
1323 detail: "pub fn z()",
1324 },
1325 ]
1326 "###
1327 ); 699 );
1328 } 700 }
1329 701
1330 #[test] 702 #[test]
1331 fn completes_hashmap_new() { 703 fn completes_hashmap_new() {
1332 assert_debug_snapshot!( 704 check(
1333 do_reference_completion( 705 r#"
1334 r" 706struct RandomState;
1335 struct RandomState; 707struct HashMap<K, V, S = RandomState> {}
1336 struct HashMap<K, V, S = RandomState> {} 708
1337 709impl<K, V> HashMap<K, V, RandomState> {
1338 impl<K, V> HashMap<K, V, RandomState> { 710 pub fn new() -> HashMap<K, V, RandomState> { }
1339 pub fn new() -> HashMap<K, V, RandomState> { } 711}
1340 } 712fn foo() {
1341 fn foo() { 713 HashMap::<|>
1342 HashMap::<|> 714}
1343 } 715"#,
1344 " 716 expect![[r#"
1345 ), 717 fn new() pub fn new() -> HashMap<K, V, RandomState>
1346 @r###" 718 "#]],
1347 [
1348 CompletionItem {
1349 label: "new()",
1350 source_range: 179..179,
1351 delete: 179..179,
1352 insert: "new()$0",
1353 kind: Function,
1354 lookup: "new",
1355 detail: "pub fn new() -> HashMap<K, V, RandomState>",
1356 },
1357 ]
1358 "###
1359 ); 719 );
1360 } 720 }
1361 721
1362 #[test] 722 #[test]
1363 fn dont_complete_attr() { 723 fn dont_complete_attr() {
1364 assert_debug_snapshot!( 724 check(
1365 do_reference_completion( 725 r#"
1366 r" 726mod foo { pub struct Foo; }
1367 mod foo { pub struct Foo; } 727#[foo::<|>]
1368 #[foo::<|>] 728fn f() {}
1369 fn f() {} 729"#,
1370 " 730 expect![[""]],
1371 ), 731 );
1372 @r###"[]"###
1373 )
1374 } 732 }
1375} 733}
diff --git a/crates/ra_ide/src/completion/complete_record.rs b/crates/ra_ide/src/completion/complete_record.rs
index 13eb2f79f..74b94594d 100644
--- a/crates/ra_ide/src/completion/complete_record.rs
+++ b/crates/ra_ide/src/completion/complete_record.rs
@@ -18,389 +18,209 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 mod record_pat_tests { 21 use expect::{expect, Expect};
22 use insta::assert_debug_snapshot;
23 22
24 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 23 use crate::completion::{test_utils::completion_list, CompletionKind};
25 24
26 fn complete(code: &str) -> Vec<CompletionItem> { 25 fn check(ra_fixture: &str, expect: Expect) {
27 do_completion(code, CompletionKind::Reference) 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
28 } 27 expect.assert_eq(&actual);
29 28 }
30 #[test]
31 fn test_record_pattern_field() {
32 let completions = complete(
33 r"
34 struct S { foo: u32 }
35
36 fn process(f: S) {
37 match f {
38 S { f<|>: 92 } => (),
39 }
40 }
41 ",
42 );
43 assert_debug_snapshot!(completions, @r###"
44 [
45 CompletionItem {
46 label: "foo",
47 source_range: 68..69,
48 delete: 68..69,
49 insert: "foo",
50 kind: Field,
51 detail: "u32",
52 },
53 ]
54 "###);
55 }
56
57 #[test]
58 fn test_record_pattern_enum_variant() {
59 let completions = complete(
60 r"
61 enum E {
62 S { foo: u32, bar: () }
63 }
64
65 fn process(e: E) {
66 match e {
67 E::S { <|> } => (),
68 }
69 }
70 ",
71 );
72 assert_debug_snapshot!(completions, @r###"
73 [
74 CompletionItem {
75 label: "bar",
76 source_range: 88..88,
77 delete: 88..88,
78 insert: "bar",
79 kind: Field,
80 detail: "()",
81 },
82 CompletionItem {
83 label: "foo",
84 source_range: 88..88,
85 delete: 88..88,
86 insert: "foo",
87 kind: Field,
88 detail: "u32",
89 },
90 ]
91 "###);
92 }
93 29
94 #[test] 30 #[test]
95 fn test_record_pattern_field_in_simple_macro() { 31 fn test_record_pattern_field() {
96 let completions = complete( 32 check(
97 r" 33 r#"
98 macro_rules! m { ($e:expr) => { $e } } 34struct S { foo: u32 }
99 struct S { foo: u32 }
100 35
101 fn process(f: S) { 36fn process(f: S) {
102 m!(match f { 37 match f {
103 S { f<|>: 92 } => (), 38 S { f<|>: 92 } => (),
104 }) 39 }
105 } 40}
106 ", 41"#,
107 ); 42 expect![[r#"
108 assert_debug_snapshot!(completions, @r###" 43 fd foo u32
109 [ 44 "#]],
110 CompletionItem { 45 );
111 label: "foo", 46 }
112 source_range: 110..111,
113 delete: 110..111,
114 insert: "foo",
115 kind: Field,
116 detail: "u32",
117 },
118 ]
119 "###);
120 }
121 47
122 #[test] 48 #[test]
123 fn only_missing_fields_are_completed_in_destruct_pats() { 49 fn test_record_pattern_enum_variant() {
124 let completions = complete( 50 check(
125 r" 51 r#"
126 struct S { 52enum E { S { foo: u32, bar: () } }
127 foo1: u32,
128 foo2: u32,
129 bar: u32,
130 baz: u32,
131 }
132 53
133 fn main() { 54fn process(e: E) {
134 let s = S { 55 match e {
135 foo1: 1, 56 E::S { <|> } => (),
136 foo2: 2, 57 }
137 bar: 3, 58}
138 baz: 4, 59"#,
139 }; 60 expect![[r#"
140 if let S { foo1, foo2: a, <|> } = s {} 61 fd bar ()
141 } 62 fd foo u32
142 ", 63 "#]],
143 ); 64 );
144 assert_debug_snapshot!(completions, @r###"
145 [
146 CompletionItem {
147 label: "bar",
148 source_range: 203..203,
149 delete: 203..203,
150 insert: "bar",
151 kind: Field,
152 detail: "u32",
153 },
154 CompletionItem {
155 label: "baz",
156 source_range: 203..203,
157 delete: 203..203,
158 insert: "baz",
159 kind: Field,
160 detail: "u32",
161 },
162 ]
163 "###);
164 }
165 } 65 }
166 66
167 mod record_lit_tests { 67 #[test]
168 use insta::assert_debug_snapshot; 68 fn test_record_pattern_field_in_simple_macro() {
169 69 check(
170 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 r"
71macro_rules! m { ($e:expr) => { $e } }
72struct S { foo: u32 }
73
74fn process(f: S) {
75 m!(match f {
76 S { f<|>: 92 } => (),
77 })
78}
79",
80 expect![[r#"
81 fd foo u32
82 "#]],
83 );
84 }
171 85
172 fn complete(code: &str) -> Vec<CompletionItem> { 86 #[test]
173 do_completion(code, CompletionKind::Reference) 87 fn only_missing_fields_are_completed_in_destruct_pats() {
174 } 88 check(
89 r#"
90struct S {
91 foo1: u32, foo2: u32,
92 bar: u32, baz: u32,
93}
175 94
176 #[test] 95fn main() {
177 fn test_record_literal_deprecated_field() { 96 let s = S {
178 let completions = complete( 97 foo1: 1, foo2: 2,
179 r" 98 bar: 3, baz: 4,
180 struct A { 99 };
181 #[deprecated] 100 if let S { foo1, foo2: a, <|> } = s {}
182 the_field: u32, 101}
183 } 102"#,
184 fn foo() { 103 expect![[r#"
185 A { the<|> } 104 fd bar u32
186 } 105 fd baz u32
187 ", 106 "#]],
188 ); 107 );
189 assert_debug_snapshot!(completions, @r###" 108 }
190 [
191 CompletionItem {
192 label: "the_field",
193 source_range: 69..72,
194 delete: 69..72,
195 insert: "the_field",
196 kind: Field,
197 detail: "u32",
198 deprecated: true,
199 },
200 ]
201 "###);
202 }
203 109
204 #[test] 110 #[test]
205 fn test_record_literal_field() { 111 fn test_record_literal_field() {
206 let completions = complete( 112 check(
207 r" 113 r#"
208 struct A { the_field: u32 } 114struct A { the_field: u32 }
209 fn foo() { 115fn foo() {
210 A { the<|> } 116 A { the<|> }
211 } 117}
212 ", 118"#,
213 ); 119 expect![[r#"
214 assert_debug_snapshot!(completions, @r###" 120 fd the_field u32
215 [ 121 "#]],
216 CompletionItem { 122 );
217 label: "the_field", 123 }
218 source_range: 46..49,
219 delete: 46..49,
220 insert: "the_field",
221 kind: Field,
222 detail: "u32",
223 },
224 ]
225 "###);
226 }
227 124
228 #[test] 125 #[test]
229 fn test_record_literal_enum_variant() { 126 fn test_record_literal_enum_variant() {
230 let completions = complete( 127 check(
231 r" 128 r#"
232 enum E { 129enum E { A { a: u32 } }
233 A { a: u32 } 130fn foo() {
234 } 131 let _ = E::A { <|> }
235 fn foo() { 132}
236 let _ = E::A { <|> } 133"#,
237 } 134 expect![[r#"
238 ", 135 fd a u32
239 ); 136 "#]],
240 assert_debug_snapshot!(completions, @r###" 137 );
241 [ 138 }
242 CompletionItem {
243 label: "a",
244 source_range: 58..58,
245 delete: 58..58,
246 insert: "a",
247 kind: Field,
248 detail: "u32",
249 },
250 ]
251 "###);
252 }
253 139
254 #[test] 140 #[test]
255 fn test_record_literal_two_structs() { 141 fn test_record_literal_two_structs() {
256 let completions = complete( 142 check(
257 r" 143 r#"
258 struct A { a: u32 } 144struct A { a: u32 }
259 struct B { b: u32 } 145struct B { b: u32 }
260 146
261 fn foo() { 147fn foo() {
262 let _: A = B { <|> } 148 let _: A = B { <|> }
263 } 149}
264 ", 150"#,
265 ); 151 expect![[r#"
266 assert_debug_snapshot!(completions, @r###" 152 fd b u32
267 [ 153 "#]],
268 CompletionItem { 154 );
269 label: "b", 155 }
270 source_range: 70..70,
271 delete: 70..70,
272 insert: "b",
273 kind: Field,
274 detail: "u32",
275 },
276 ]
277 "###);
278 }
279 156
280 #[test] 157 #[test]
281 fn test_record_literal_generic_struct() { 158 fn test_record_literal_generic_struct() {
282 let completions = complete( 159 check(
283 r" 160 r#"
284 struct A<T> { a: T } 161struct A<T> { a: T }
285 162
286 fn foo() { 163fn foo() {
287 let _: A<u32> = A { <|> } 164 let _: A<u32> = A { <|> }
288 } 165}
289 ", 166"#,
290 ); 167 expect![[r#"
291 assert_debug_snapshot!(completions, @r###" 168 fd a u32
292 [ 169 "#]],
293 CompletionItem { 170 );
294 label: "a", 171 }
295 source_range: 56..56,
296 delete: 56..56,
297 insert: "a",
298 kind: Field,
299 detail: "u32",
300 },
301 ]
302 "###);
303 }
304 172
305 #[test] 173 #[test]
306 fn test_record_literal_field_in_simple_macro() { 174 fn test_record_literal_field_in_simple_macro() {
307 let completions = complete( 175 check(
308 r" 176 r#"
309 macro_rules! m { ($e:expr) => { $e } } 177macro_rules! m { ($e:expr) => { $e } }
310 struct A { the_field: u32 } 178struct A { the_field: u32 }
311 fn foo() { 179fn foo() {
312 m!(A { the<|> }) 180 m!(A { the<|> })
313 } 181}
314 ", 182"#,
315 ); 183 expect![[r#"
316 assert_debug_snapshot!(completions, @r###" 184 fd the_field u32
317 [ 185 "#]],
318 CompletionItem { 186 );
319 label: "the_field", 187 }
320 source_range: 88..91,
321 delete: 88..91,
322 insert: "the_field",
323 kind: Field,
324 detail: "u32",
325 },
326 ]
327 "###);
328 }
329 188
330 #[test] 189 #[test]
331 fn only_missing_fields_are_completed() { 190 fn only_missing_fields_are_completed() {
332 let completions = complete( 191 check(
333 r" 192 r#"
334 struct S { 193struct S {
335 foo1: u32, 194 foo1: u32, foo2: u32,
336 foo2: u32, 195 bar: u32, baz: u32,
337 bar: u32, 196}
338 baz: u32,
339 }
340 197
341 fn main() { 198fn main() {
342 let foo1 = 1; 199 let foo1 = 1;
343 let s = S { 200 let s = S { foo1, foo2: 5, <|> }
344 foo1, 201}
345 foo2: 5, 202"#,
346 <|> 203 expect![[r#"
347 } 204 fd bar u32
348 } 205 fd baz u32
349 ", 206 "#]],
350 ); 207 );
351 assert_debug_snapshot!(completions, @r###" 208 }
352 [
353 CompletionItem {
354 label: "bar",
355 source_range: 157..157,
356 delete: 157..157,
357 insert: "bar",
358 kind: Field,
359 detail: "u32",
360 },
361 CompletionItem {
362 label: "baz",
363 source_range: 157..157,
364 delete: 157..157,
365 insert: "baz",
366 kind: Field,
367 detail: "u32",
368 },
369 ]
370 "###);
371 }
372 209
373 #[test] 210 #[test]
374 fn completes_functional_update() { 211 fn completes_functional_update() {
375 let completions = complete( 212 check(
376 r" 213 r#"
377 struct S { 214struct S { foo1: u32, foo2: u32 }
378 foo1: u32,
379 foo2: u32,
380 }
381 215
382 fn main() { 216fn main() {
383 let foo1 = 1; 217 let foo1 = 1;
384 let s = S { 218 let s = S { foo1, <|> .. loop {} }
385 foo1, 219}
386 <|> 220"#,
387 .. loop {} 221 expect![[r#"
388 } 222 fd foo2 u32
389 } 223 "#]],
390 ", 224 );
391 );
392 assert_debug_snapshot!(completions, @r###"
393 [
394 CompletionItem {
395 label: "foo2",
396 source_range: 112..112,
397 delete: 112..112,
398 insert: "foo2",
399 kind: Field,
400 detail: "u32",
401 },
402 ]
403 "###);
404 }
405 } 225 }
406} 226}
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs
index 52aaa70f0..28d8f7876 100644
--- a/crates/ra_ide/src/completion/complete_snippet.rs
+++ b/crates/ra_ide/src/completion/complete_snippet.rs
@@ -70,95 +70,47 @@ fn ${1:feature}() {
70 70
71#[cfg(test)] 71#[cfg(test)]
72mod tests { 72mod tests {
73 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 73 use expect::{expect, Expect};
74 use insta::assert_debug_snapshot;
75 74
76 fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { 75 use crate::completion::{test_utils::completion_list, CompletionKind};
77 do_completion(code, CompletionKind::Snippet) 76
77 fn check(ra_fixture: &str, expect: Expect) {
78 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
79 expect.assert_eq(&actual)
78 } 80 }
79 81
80 #[test] 82 #[test]
81 fn completes_snippets_in_expressions() { 83 fn completes_snippets_in_expressions() {
82 assert_debug_snapshot!( 84 check(
83 do_snippet_completion(r"fn foo(x: i32) { <|> }"), 85 r#"fn foo(x: i32) { <|> }"#,
84 @r###" 86 expect![[r#"
85 [ 87 sn pd
86 CompletionItem { 88 sn ppd
87 label: "pd", 89 "#]],
88 source_range: 17..17, 90 );
89 delete: 17..17,
90 insert: "eprintln!(\"$0 = {:?}\", $0);",
91 kind: Snippet,
92 },
93 CompletionItem {
94 label: "ppd",
95 source_range: 17..17,
96 delete: 17..17,
97 insert: "eprintln!(\"$0 = {:#?}\", $0);",
98 kind: Snippet,
99 },
100 ]
101 "###
102 );
103 } 91 }
104 92
105 #[test] 93 #[test]
106 fn should_not_complete_snippets_in_path() { 94 fn should_not_complete_snippets_in_path() {
107 assert_debug_snapshot!( 95 check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]);
108 do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"), 96 check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]);
109 @"[]"
110 );
111 assert_debug_snapshot!(
112 do_snippet_completion(r"fn foo(x: i32) { ::<|> }"),
113 @"[]"
114 );
115 } 97 }
116 98
117 #[test] 99 #[test]
118 fn completes_snippets_in_items() { 100 fn completes_snippets_in_items() {
119 assert_debug_snapshot!( 101 check(
120 do_snippet_completion( 102 r#"
121 r" 103#[cfg(test)]
122 #[cfg(test)] 104mod tests {
123 mod tests { 105 <|>
124 <|> 106}
125 } 107"#,
126 " 108 expect![[r#"
127 ), 109 sn Test function
128 @r###" 110 sn Test module
129 [ 111 sn macro_rules
130 CompletionItem { 112 sn pub(crate)
131 label: "Test function", 113 "#]],
132 source_range: 29..29, 114 )
133 delete: 29..29,
134 insert: "#[test]\nfn ${1:feature}() {\n $0\n}",
135 kind: Snippet,
136 lookup: "tfn",
137 },
138 CompletionItem {
139 label: "Test module",
140 source_range: 29..29,
141 delete: 29..29,
142 insert: "#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn ${1:test_name}() {\n $0\n }\n}",
143 kind: Snippet,
144 lookup: "tmod",
145 },
146 CompletionItem {
147 label: "macro_rules",
148 source_range: 29..29,
149 delete: 29..29,
150 insert: "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}",
151 kind: Snippet,
152 },
153 CompletionItem {
154 label: "pub(crate)",
155 source_range: 29..29,
156 delete: 29..29,
157 insert: "pub(crate) $0",
158 kind: Snippet,
159 },
160 ]
161 "###
162 );
163 } 115 }
164} 116}
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 23e42928d..d9a0ef167 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -2,8 +2,8 @@
2//! 2//!
3//! This module adds the completion items related to implementing associated 3//! This module adds the completion items related to implementing associated
4//! items within a `impl Trait for Struct` block. The current context node 4//! items within a `impl Trait for Struct` block. The current context node
5//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node 5//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node
6//! and an direct child of an `IMPL_DEF`. 6//! and an direct child of an `IMPL`.
7//! 7//!
8//! # Examples 8//! # Examples
9//! 9//!
@@ -34,7 +34,7 @@
34use hir::{self, Docs, HasSource}; 34use hir::{self, Docs, HasSource};
35use ra_assists::utils::get_missing_assoc_items; 35use ra_assists::utils::get_missing_assoc_items;
36use ra_syntax::{ 36use ra_syntax::{
37 ast::{self, edit, ImplDef}, 37 ast::{self, edit, Impl},
38 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 38 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39}; 39};
40use ra_text_edit::TextEdit; 40use ra_text_edit::TextEdit;
@@ -43,7 +43,7 @@ use crate::{
43 completion::{ 43 completion::{
44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
45 }, 45 },
46 display::FunctionSignature, 46 display::function_declaration,
47}; 47};
48 48
49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
@@ -63,7 +63,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
63 } 63 }
64 }), 64 }),
65 65
66 SyntaxKind::FN_DEF => { 66 SyntaxKind::FN => {
67 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 67 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
68 .into_iter() 68 .into_iter()
69 .filter_map(|item| match item { 69 .filter_map(|item| match item {
@@ -75,7 +75,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
75 } 75 }
76 } 76 }
77 77
78 SyntaxKind::TYPE_ALIAS_DEF => { 78 SyntaxKind::TYPE_ALIAS => {
79 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 79 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
80 .into_iter() 80 .into_iter()
81 .filter_map(|item| match item { 81 .filter_map(|item| match item {
@@ -87,7 +87,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
87 } 87 }
88 } 88 }
89 89
90 SyntaxKind::CONST_DEF => { 90 SyntaxKind::CONST => {
91 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) 91 for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
92 .into_iter() 92 .into_iter()
93 .filter_map(|item| match item { 93 .filter_map(|item| match item {
@@ -104,18 +104,17 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
104 } 104 }
105} 105}
106 106
107fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> { 107fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> {
108 let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { 108 let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
109 SyntaxKind::FN_DEF 109 SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => {
110 | SyntaxKind::TYPE_ALIAS_DEF 110 Some((p, 2))
111 | SyntaxKind::CONST_DEF 111 }
112 | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
113 SyntaxKind::NAME_REF => Some((p, 5)), 112 SyntaxKind::NAME_REF => Some((p, 5)),
114 _ => None, 113 _ => None,
115 })?; 114 })?;
116 let impl_def = (0..impl_def_offset - 1) 115 let impl_def = (0..impl_def_offset - 1)
117 .try_fold(trigger.parent()?, |t, _| t.parent()) 116 .try_fold(trigger.parent()?, |t, _| t.parent())
118 .and_then(ast::ImplDef::cast)?; 117 .and_then(ast::Impl::cast)?;
119 Some((trigger, impl_def)) 118 Some((trigger, impl_def))
120} 119}
121 120
@@ -125,8 +124,6 @@ fn add_function_impl(
125 ctx: &CompletionContext, 124 ctx: &CompletionContext,
126 func: hir::Function, 125 func: hir::Function,
127) { 126) {
128 let signature = FunctionSignature::from_hir(ctx.db, func);
129
130 let fn_name = func.name(ctx.db).to_string(); 127 let fn_name = func.name(ctx.db).to_string();
131 128
132 let label = if !func.params(ctx.db).is_empty() { 129 let label = if !func.params(ctx.db).is_empty() {
@@ -146,13 +143,14 @@ fn add_function_impl(
146 }; 143 };
147 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 144 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
148 145
146 let function_decl = function_declaration(&func.source(ctx.db).value);
149 match ctx.config.snippet_cap { 147 match ctx.config.snippet_cap {
150 Some(cap) => { 148 Some(cap) => {
151 let snippet = format!("{} {{\n $0\n}}", signature); 149 let snippet = format!("{} {{\n $0\n}}", function_decl);
152 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 150 builder.snippet_edit(cap, TextEdit::replace(range, snippet))
153 } 151 }
154 None => { 152 None => {
155 let header = format!("{} {{", signature); 153 let header = format!("{} {{", function_decl);
156 builder.text_edit(TextEdit::replace(range, header)) 154 builder.text_edit(TextEdit::replace(range, header))
157 } 155 }
158 } 156 }
@@ -202,7 +200,7 @@ fn add_const_impl(
202 } 200 }
203} 201}
204 202
205fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { 203fn make_const_compl_syntax(const_: &ast::Const) -> String {
206 let const_ = edit::remove_attrs_and_docs(const_); 204 let const_ = edit::remove_attrs_and_docs(const_);
207 205
208 let const_start = const_.syntax().text_range().start(); 206 let const_start = const_.syntax().text_range().start();
@@ -227,330 +225,264 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
227 225
228#[cfg(test)] 226#[cfg(test)]
229mod tests { 227mod tests {
230 use insta::assert_debug_snapshot; 228 use expect::{expect, Expect};
231 229
232 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 230 use crate::completion::{
231 test_utils::{check_edit, completion_list},
232 CompletionKind,
233 };
233 234
234 fn complete(code: &str) -> Vec<CompletionItem> { 235 fn check(ra_fixture: &str, expect: Expect) {
235 do_completion(code, CompletionKind::Magic) 236 let actual = completion_list(ra_fixture, CompletionKind::Magic);
237 expect.assert_eq(&actual)
236 } 238 }
237 239
238 #[test] 240 #[test]
239 fn name_ref_function_type_const() { 241 fn name_ref_function_type_const() {
240 let completions = complete( 242 check(
241 r" 243 r#"
242 trait Test { 244trait Test {
243 type TestType; 245 type TestType;
244 const TEST_CONST: u16; 246 const TEST_CONST: u16;
245 fn test(); 247 fn test();
246 } 248}
247 249struct T;
248 struct T1;
249 250
250 impl Test for T1 { 251impl Test for T {
251 t<|> 252 t<|>
252 } 253}
253 ", 254"#,
255 expect![["
256ct const TEST_CONST: u16 = \n\
257fn fn test()
258ta type TestType = \n\
259 "]],
254 ); 260 );
255 assert_debug_snapshot!(completions, @r###"
256 [
257 CompletionItem {
258 label: "const TEST_CONST: u16 = ",
259 source_range: 112..113,
260 delete: 112..113,
261 insert: "const TEST_CONST: u16 = ",
262 kind: Const,
263 lookup: "TEST_CONST",
264 },
265 CompletionItem {
266 label: "fn test()",
267 source_range: 112..113,
268 delete: 112..113,
269 insert: "fn test() {\n $0\n}",
270 kind: Function,
271 lookup: "test",
272 },
273 CompletionItem {
274 label: "type TestType = ",
275 source_range: 112..113,
276 delete: 112..113,
277 insert: "type TestType = ",
278 kind: TypeAlias,
279 lookup: "TestType",
280 },
281 ]
282 "###);
283 } 261 }
284 262
285 #[test] 263 #[test]
286 fn no_nested_fn_completions() { 264 fn no_nested_fn_completions() {
287 let completions = complete( 265 check(
288 r" 266 r"
289 trait Test { 267trait Test {
290 fn test(); 268 fn test();
291 fn test2(); 269 fn test2();
292 } 270}
293 271struct T;
294 struct T1;
295 272
296 impl Test for T1 { 273impl Test for T {
297 fn test() { 274 fn test() {
298 t<|> 275 t<|>
299 } 276 }
300 } 277}
301 ", 278",
279 expect![[""]],
302 ); 280 );
303 assert_debug_snapshot!(completions, @r###"[]"###);
304 } 281 }
305 282
306 #[test] 283 #[test]
307 fn name_ref_single_function() { 284 fn name_ref_single_function() {
308 let completions = complete( 285 check_edit(
309 r" 286 "test",
310 trait Test { 287 r#"
311 fn test(); 288trait Test {
312 } 289 fn test();
290}
291struct T;
313 292
314 struct T1; 293impl Test for T {
294 t<|>
295}
296"#,
297 r#"
298trait Test {
299 fn test();
300}
301struct T;
315 302
316 impl Test for T1 { 303impl Test for T {
317 t<|> 304 fn test() {
318 } 305 $0
319 ", 306}
307}
308"#,
320 ); 309 );
321 assert_debug_snapshot!(completions, @r###"
322 [
323 CompletionItem {
324 label: "fn test()",
325 source_range: 66..67,
326 delete: 66..67,
327 insert: "fn test() {\n $0\n}",
328 kind: Function,
329 lookup: "test",
330 },
331 ]
332 "###);
333 } 310 }
334 311
335 #[test] 312 #[test]
336 fn single_function() { 313 fn single_function() {
337 let completions = complete( 314 check_edit(
338 r" 315 "test",
339 trait Test { 316 r#"
340 fn foo(); 317trait Test {
341 } 318 fn test();
319}
320struct T;
342 321
343 struct T1; 322impl Test for T {
323 fn t<|>
324}
325"#,
326 r#"
327trait Test {
328 fn test();
329}
330struct T;
344 331
345 impl Test for T1 { 332impl Test for T {
346 fn f<|> 333 fn test() {
347 } 334 $0
348 ", 335}
336}
337"#,
349 ); 338 );
350 assert_debug_snapshot!(completions, @r###"
351 [
352 CompletionItem {
353 label: "fn foo()",
354 source_range: 68..69,
355 delete: 65..69,
356 insert: "fn foo() {\n $0\n}",
357 kind: Function,
358 lookup: "foo",
359 },
360 ]
361 "###);
362 } 339 }
363 340
364 #[test] 341 #[test]
365 fn hide_implemented_fn() { 342 fn hide_implemented_fn() {
366 let completions = complete( 343 check(
367 r" 344 r#"
368 trait Test { 345trait Test {
369 fn foo(); 346 fn foo();
370 fn foo_bar(); 347 fn foo_bar();
371 } 348}
372 349struct T;
373 struct T1;
374
375 impl Test for T1 {
376 fn foo() {}
377
378 fn f<|>
379 }
380 ",
381 );
382 assert_debug_snapshot!(completions, @r###"
383 [
384 CompletionItem {
385 label: "fn foo_bar()",
386 source_range: 103..104,
387 delete: 100..104,
388 insert: "fn foo_bar() {\n $0\n}",
389 kind: Function,
390 lookup: "foo_bar",
391 },
392 ]
393 "###);
394 }
395
396 #[test]
397 fn completes_only_on_top_level() {
398 let completions = complete(
399 r"
400 trait Test {
401 fn foo();
402
403 fn foo_bar();
404 }
405
406 struct T1;
407 350
408 impl Test for T1 { 351impl Test for T {
409 fn foo() { 352 fn foo() {}
410 <|> 353 fn f<|>
411 } 354}
412 } 355"#,
413 ", 356 expect![[r#"
357 fn fn foo_bar()
358 "#]],
414 ); 359 );
415 assert_debug_snapshot!(completions, @r###"[]"###);
416 } 360 }
417 361
418 #[test] 362 #[test]
419 fn generic_fn() { 363 fn generic_fn() {
420 let completions = complete( 364 check_edit(
421 r" 365 "foo",
422 trait Test { 366 r#"
423 fn foo<T>(); 367trait Test {
424 } 368 fn foo<T>();
369}
370struct T;
425 371
426 struct T1; 372impl Test for T {
373 fn f<|>
374}
375"#,
376 r#"
377trait Test {
378 fn foo<T>();
379}
380struct T;
427 381
428 impl Test for T1 { 382impl Test for T {
429 fn f<|> 383 fn foo<T>() {
430 } 384 $0
431 ", 385}
386}
387"#,
432 ); 388 );
433 assert_debug_snapshot!(completions, @r###" 389 check_edit(
434 [ 390 "foo",
435 CompletionItem { 391 r#"
436 label: "fn foo()", 392trait Test {
437 source_range: 71..72, 393 fn foo<T>() where T: Into<String>;
438 delete: 68..72, 394}
439 insert: "fn foo<T>() {\n $0\n}", 395struct T;
440 kind: Function,
441 lookup: "foo",
442 },
443 ]
444 "###);
445 }
446
447 #[test]
448 fn generic_constrait_fn() {
449 let completions = complete(
450 r"
451 trait Test {
452 fn foo<T>() where T: Into<String>;
453 }
454 396
455 struct T1; 397impl Test for T {
398 fn f<|>
399}
400"#,
401 r#"
402trait Test {
403 fn foo<T>() where T: Into<String>;
404}
405struct T;
456 406
457 impl Test for T1 { 407impl Test for T {
458 fn f<|> 408 fn foo<T>()
459 } 409where T: Into<String> {
460 ", 410 $0
411}
412}
413"#,
461 ); 414 );
462 assert_debug_snapshot!(completions, @r###"
463 [
464 CompletionItem {
465 label: "fn foo()",
466 source_range: 93..94,
467 delete: 90..94,
468 insert: "fn foo<T>()\nwhere T: Into<String> {\n $0\n}",
469 kind: Function,
470 lookup: "foo",
471 },
472 ]
473 "###);
474 } 415 }
475 416
476 #[test] 417 #[test]
477 fn associated_type() { 418 fn associated_type() {
478 let completions = complete( 419 check_edit(
479 r" 420 "SomeType",
480 trait Test { 421 r#"
481 type SomeType; 422trait Test {
482 } 423 type SomeType;
424}
483 425
484 impl Test for () { 426impl Test for () {
485 type S<|> 427 type S<|>
486 } 428}
487 ", 429"#,
430 "
431trait Test {
432 type SomeType;
433}
434
435impl Test for () {
436 type SomeType = \n\
437}
438",
488 ); 439 );
489 assert_debug_snapshot!(completions, @r###"
490 [
491 CompletionItem {
492 label: "type SomeType = ",
493 source_range: 63..64,
494 delete: 58..64,
495 insert: "type SomeType = ",
496 kind: TypeAlias,
497 lookup: "SomeType",
498 },
499 ]
500 "###);
501 } 440 }
502 441
503 #[test] 442 #[test]
504 fn associated_const() { 443 fn associated_const() {
505 let completions = complete( 444 check_edit(
506 r" 445 "SOME_CONST",
507 trait Test { 446 r#"
508 const SOME_CONST: u16; 447trait Test {
509 } 448 const SOME_CONST: u16;
449}
510 450
511 impl Test for () { 451impl Test for () {
512 const S<|> 452 const S<|>
513 } 453}
514 ", 454"#,
455 "
456trait Test {
457 const SOME_CONST: u16;
458}
459
460impl Test for () {
461 const SOME_CONST: u16 = \n\
462}
463",
515 ); 464 );
516 assert_debug_snapshot!(completions, @r###"
517 [
518 CompletionItem {
519 label: "const SOME_CONST: u16 = ",
520 source_range: 72..73,
521 delete: 66..73,
522 insert: "const SOME_CONST: u16 = ",
523 kind: Const,
524 lookup: "SOME_CONST",
525 },
526 ]
527 "###);
528 }
529 465
530 #[test] 466 check_edit(
531 fn associated_const_with_default() { 467 "SOME_CONST",
532 let completions = complete( 468 r#"
533 r" 469trait Test {
534 trait Test { 470 const SOME_CONST: u16 = 92;
535 const SOME_CONST: u16 = 42; 471}
536 }
537 472
538 impl Test for () { 473impl Test for () {
539 const S<|> 474 const S<|>
540 } 475}
541 ", 476"#,
477 "
478trait Test {
479 const SOME_CONST: u16 = 92;
480}
481
482impl Test for () {
483 const SOME_CONST: u16 = \n\
484}
485",
542 ); 486 );
543 assert_debug_snapshot!(completions, @r###"
544 [
545 CompletionItem {
546 label: "const SOME_CONST: u16 = ",
547 source_range: 77..78,
548 delete: 71..78,
549 insert: "const SOME_CONST: u16 = ",
550 kind: Const,
551 lookup: "SOME_CONST",
552 },
553 ]
554 "###);
555 } 487 }
556} 488}
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index a0a04bb58..bd9551f35 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -1,11 +1,10 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::{Adt, ModuleDef, ScopeDef, Type};
4use ra_syntax::AstNode;
4use test_utils::mark; 5use test_utils::mark;
5 6
6use crate::completion::{CompletionContext, Completions}; 7use crate::completion::{CompletionContext, Completions};
7use hir::{Adt, ModuleDef, Type};
8use ra_syntax::AstNode;
9 8
10pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -26,7 +25,7 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
26 return; 25 return;
27 } 26 }
28 27
29 ctx.scope().process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
30 if ctx.use_item_syntax.is_some() { 29 if ctx.use_item_syntax.is_some() {
31 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 30 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
32 if name_ref.syntax().text() == name.to_string().as_str() { 31 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -43,7 +42,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
43 if let Some(Adt::Enum(enum_data)) = ty.as_adt() { 42 if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
44 let variants = enum_data.variants(ctx.db); 43 let variants = enum_data.variants(ctx.db);
45 44
46 let module = if let Some(module) = ctx.scope().module() { 45 let module = if let Some(module) = ctx.scope.module() {
47 // Compute path from the completion site if available. 46 // Compute path from the completion site if available.
48 module 47 module
49 } else { 48 } else {
@@ -65,1361 +64,595 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
65 64
66#[cfg(test)] 65#[cfg(test)]
67mod tests { 66mod tests {
68 use insta::assert_debug_snapshot; 67 use expect::{expect, Expect};
69 use test_utils::mark; 68 use test_utils::mark;
70 69
71 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 70 use crate::completion::{
71 test_utils::{check_edit, completion_list},
72 CompletionKind,
73 };
72 74
73 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 75 fn check(ra_fixture: &str, expect: Expect) {
74 do_completion(ra_fixture, CompletionKind::Reference) 76 let actual = completion_list(ra_fixture, CompletionKind::Reference);
77 expect.assert_eq(&actual)
75 } 78 }
76 79
77 #[test] 80 #[test]
78 fn self_fulfilling_completion() { 81 fn self_fulfilling_completion() {
79 mark::check!(self_fulfilling_completion); 82 mark::check!(self_fulfilling_completion);
80 assert_debug_snapshot!( 83 check(
81 do_reference_completion( 84 r#"
82 r#" 85use foo<|>
83 use foo<|> 86use std::collections;
84 use std::collections; 87"#,
85 "#, 88 expect![[r#"
86 ), 89 ?? collections
87 @r###" 90 "#]],
88 [
89 CompletionItem {
90 label: "collections",
91 source_range: 4..7,
92 delete: 4..7,
93 insert: "collections",
94 },
95 ]
96 "###
97 ); 91 );
98 } 92 }
99 93
100 #[test] 94 #[test]
101 fn bind_pat_and_path_ignore_at() { 95 fn bind_pat_and_path_ignore_at() {
102 assert_debug_snapshot!( 96 check(
103 do_reference_completion( 97 r#"
104 r" 98enum Enum { A, B }
105 enum Enum { 99fn quux(x: Option<Enum>) {
106 A, 100 match x {
107 B, 101 None => (),
108 } 102 Some(en<|> @ Enum::A) => (),
109 fn quux(x: Option<Enum>) { 103 }
110 match x { 104}
111 None => (), 105"#,
112 Some(en<|> @ Enum::A) => (), 106 expect![[""]],
113 }
114 }
115 "
116 ),
117 @"[]"
118 ); 107 );
119 } 108 }
120 109
121 #[test] 110 #[test]
122 fn bind_pat_and_path_ignore_ref() { 111 fn bind_pat_and_path_ignore_ref() {
123 assert_debug_snapshot!( 112 check(
124 do_reference_completion( 113 r#"
125 r" 114enum Enum { A, B }
126 enum Enum { 115fn quux(x: Option<Enum>) {
127 A, 116 match x {
128 B, 117 None => (),
129 } 118 Some(ref en<|>) => (),
130 fn quux(x: Option<Enum>) { 119 }
131 match x { 120}
132 None => (), 121"#,
133 Some(ref en<|>) => (), 122 expect![[""]],
134 }
135 }
136 "
137 ),
138 @r###"[]"###
139 ); 123 );
140 } 124 }
141 125
142 #[test] 126 #[test]
143 fn bind_pat_and_path() { 127 fn bind_pat_and_path() {
144 assert_debug_snapshot!( 128 check(
145 do_reference_completion( 129 r#"
146 r" 130enum Enum { A, B }
147 enum Enum { 131fn quux(x: Option<Enum>) {
148 A, 132 match x {
149 B, 133 None => (),
150 } 134 Some(En<|>) => (),
151 fn quux(x: Option<Enum>) { 135 }
152 match x { 136}
153 None => (), 137"#,
154 Some(En<|>) => (), 138 expect![[r#"
155 } 139 en Enum
156 } 140 "#]],
157 "
158 ),
159 @r###"
160 [
161 CompletionItem {
162 label: "Enum",
163 source_range: 102..104,
164 delete: 102..104,
165 insert: "Enum",
166 kind: Enum,
167 },
168 ]
169 "###
170 ); 141 );
171 } 142 }
172 143
173 #[test] 144 #[test]
174 fn completes_bindings_from_let() { 145 fn completes_bindings_from_let() {
175 assert_debug_snapshot!( 146 check(
176 do_reference_completion( 147 r#"
177 r" 148fn quux(x: i32) {
178 fn quux(x: i32) { 149 let y = 92;
179 let y = 92; 150 1 + <|>;
180 1 + <|>; 151 let z = ();
181 let z = (); 152}
182 } 153"#,
183 " 154 expect![[r#"
184 ), 155 fn quux(…) fn quux(x: i32)
185 @r###" 156 bn x i32
186 [ 157 bn y i32
187 CompletionItem { 158 "#]],
188 label: "quux(…)",
189 source_range: 42..42,
190 delete: 42..42,
191 insert: "quux(${1:x})$0",
192 kind: Function,
193 lookup: "quux",
194 detail: "fn quux(x: i32)",
195 trigger_call_info: true,
196 },
197 CompletionItem {
198 label: "x",
199 source_range: 42..42,
200 delete: 42..42,
201 insert: "x",
202 kind: Binding,
203 detail: "i32",
204 },
205 CompletionItem {
206 label: "y",
207 source_range: 42..42,
208 delete: 42..42,
209 insert: "y",
210 kind: Binding,
211 detail: "i32",
212 },
213 ]
214 "###
215 ); 159 );
216 } 160 }
217 161
218 #[test] 162 #[test]
219 fn completes_bindings_from_if_let() { 163 fn completes_bindings_from_if_let() {
220 assert_debug_snapshot!( 164 check(
221 do_reference_completion( 165 r#"
222 r" 166fn quux() {
223 fn quux() { 167 if let Some(x) = foo() {
224 if let Some(x) = foo() { 168 let y = 92;
225 let y = 92; 169 };
226 }; 170 if let Some(a) = bar() {
227 if let Some(a) = bar() { 171 let b = 62;
228 let b = 62; 172 1 + <|>
229 1 + <|> 173 }
230 } 174}
231 } 175"#,
232 " 176 expect![[r#"
233 ), 177 bn a
234 @r###" 178 bn b i32
235 [ 179 fn quux() fn quux()
236 CompletionItem { 180 "#]],
237 label: "a",
238 source_range: 129..129,
239 delete: 129..129,
240 insert: "a",
241 kind: Binding,
242 },
243 CompletionItem {
244 label: "b",
245 source_range: 129..129,
246 delete: 129..129,
247 insert: "b",
248 kind: Binding,
249 detail: "i32",
250 },
251 CompletionItem {
252 label: "quux()",
253 source_range: 129..129,
254 delete: 129..129,
255 insert: "quux()$0",
256 kind: Function,
257 lookup: "quux",
258 detail: "fn quux()",
259 },
260 ]
261 "###
262 ); 181 );
263 } 182 }
264 183
265 #[test] 184 #[test]
266 fn completes_bindings_from_for() { 185 fn completes_bindings_from_for() {
267 assert_debug_snapshot!( 186 check(
268 do_reference_completion( 187 r#"
269 r" 188fn quux() {
270 fn quux() { 189 for x in &[1, 2, 3] { <|> }
271 for x in &[1, 2, 3] { 190}
272 <|> 191"#,
273 } 192 expect![[r#"
274 } 193 fn quux() fn quux()
275 " 194 bn x
276 ), 195 "#]],
277 @r###"
278 [
279 CompletionItem {
280 label: "quux()",
281 source_range: 46..46,
282 delete: 46..46,
283 insert: "quux()$0",
284 kind: Function,
285 lookup: "quux",
286 detail: "fn quux()",
287 },
288 CompletionItem {
289 label: "x",
290 source_range: 46..46,
291 delete: 46..46,
292 insert: "x",
293 kind: Binding,
294 },
295 ]
296 "###
297 ); 196 );
298 } 197 }
299 198
300 #[test] 199 #[test]
301 fn completes_bindings_from_for_with_in_prefix() { 200 fn completes_if_prefix_is_keyword() {
302 mark::check!(completes_bindings_from_for_with_in_prefix); 201 mark::check!(completes_if_prefix_is_keyword);
303 assert_debug_snapshot!( 202 check_edit(
304 do_reference_completion( 203 "wherewolf",
305 r" 204 r#"
306 fn test() { 205fn main() {
307 for index in &[1, 2, 3] { 206 let wherewolf = 92;
308 let t = in<|> 207 drop(where<|>)
309 } 208}
310 } 209"#,
311 " 210 r#"
312 ), 211fn main() {
313 @r###" 212 let wherewolf = 92;
314 [ 213 drop(wherewolf)
315 CompletionItem { 214}
316 label: "index", 215"#,
317 source_range: 58..58, 216 )
318 delete: 58..58,
319 insert: "index",
320 kind: Binding,
321 },
322 CompletionItem {
323 label: "test()",
324 source_range: 58..58,
325 delete: 58..58,
326 insert: "test()$0",
327 kind: Function,
328 lookup: "test",
329 detail: "fn test()",
330 },
331 ]
332 "###
333 );
334 } 217 }
335 218
336 #[test] 219 #[test]
337 fn completes_generic_params() { 220 fn completes_generic_params() {
338 assert_debug_snapshot!( 221 check(
339 do_reference_completion( 222 r#"fn quux<T>() { <|> }"#,
340 r" 223 expect![[r#"
341 fn quux<T>() { 224 tp T
342 <|> 225 fn quux() fn quux<T>()
343 } 226 "#]],
344 "
345 ),
346 @r###"
347 [
348 CompletionItem {
349 label: "T",
350 source_range: 19..19,
351 delete: 19..19,
352 insert: "T",
353 kind: TypeParam,
354 },
355 CompletionItem {
356 label: "quux()",
357 source_range: 19..19,
358 delete: 19..19,
359 insert: "quux()$0",
360 kind: Function,
361 lookup: "quux",
362 detail: "fn quux<T>()",
363 },
364 ]
365 "###
366 ); 227 );
367 } 228 }
368 229
369 #[test] 230 #[test]
370 fn completes_generic_params_in_struct() { 231 fn completes_generic_params_in_struct() {
371 assert_debug_snapshot!( 232 check(
372 do_reference_completion( 233 r#"struct S<T> { x: <|>}"#,
373 r" 234 expect![[r#"
374 struct X<T> { 235 st S<…>
375 x: <|> 236 tp Self
376 } 237 tp T
377 " 238 "#]],
378 ),
379 @r###"
380 [
381 CompletionItem {
382 label: "Self",
383 source_range: 21..21,
384 delete: 21..21,
385 insert: "Self",
386 kind: TypeParam,
387 },
388 CompletionItem {
389 label: "T",
390 source_range: 21..21,
391 delete: 21..21,
392 insert: "T",
393 kind: TypeParam,
394 },
395 CompletionItem {
396 label: "X<…>",
397 source_range: 21..21,
398 delete: 21..21,
399 insert: "X<$0>",
400 kind: Struct,
401 lookup: "X",
402 },
403 ]
404 "###
405 ); 239 );
406 } 240 }
407 241
408 #[test] 242 #[test]
409 fn completes_self_in_enum() { 243 fn completes_self_in_enum() {
410 assert_debug_snapshot!( 244 check(
411 do_reference_completion( 245 r#"enum X { Y(<|>) }"#,
412 r" 246 expect![[r#"
413 enum X { 247 tp Self
414 Y(<|>) 248 en X
415 } 249 "#]],
416 "
417 ),
418 @r###"
419 [
420 CompletionItem {
421 label: "Self",
422 source_range: 15..15,
423 delete: 15..15,
424 insert: "Self",
425 kind: TypeParam,
426 },
427 CompletionItem {
428 label: "X",
429 source_range: 15..15,
430 delete: 15..15,
431 insert: "X",
432 kind: Enum,
433 },
434 ]
435 "###
436 ); 250 );
437 } 251 }
438 252
439 #[test] 253 #[test]
440 fn completes_module_items() { 254 fn completes_module_items() {
441 assert_debug_snapshot!( 255 check(
442 do_reference_completion( 256 r#"
443 r" 257struct S;
444 struct Foo; 258enum E {}
445 enum Baz {} 259fn quux() { <|> }
446 fn quux() { 260"#,
447 <|> 261 expect![[r#"
448 } 262 en E
449 " 263 st S
450 ), 264 fn quux() fn quux()
451 @r###" 265 "#]],
452 [ 266 );
453 CompletionItem {
454 label: "Baz",
455 source_range: 40..40,
456 delete: 40..40,
457 insert: "Baz",
458 kind: Enum,
459 },
460 CompletionItem {
461 label: "Foo",
462 source_range: 40..40,
463 delete: 40..40,
464 insert: "Foo",
465 kind: Struct,
466 },
467 CompletionItem {
468 label: "quux()",
469 source_range: 40..40,
470 delete: 40..40,
471 insert: "quux()$0",
472 kind: Function,
473 lookup: "quux",
474 detail: "fn quux()",
475 },
476 ]
477 "###
478 );
479 } 267 }
480 268
481 #[test] 269 #[test]
482 fn completes_extern_prelude() { 270 fn completes_extern_prelude() {
483 assert_debug_snapshot!( 271 check(
484 do_reference_completion( 272 r#"
485 r" 273//- /lib.rs
486 //- /lib.rs 274use <|>;
487 use <|>; 275
488 276//- /other_crate/lib.rs
489 //- /other_crate/lib.rs 277// nothing here
490 // nothing here 278"#,
491 " 279 expect![[r#"
492 ), 280 md other_crate
493 @r###" 281 "#]],
494 [
495 CompletionItem {
496 label: "other_crate",
497 source_range: 4..4,
498 delete: 4..4,
499 insert: "other_crate",
500 kind: Module,
501 },
502 ]
503 "###
504 ); 282 );
505 } 283 }
506 284
507 #[test] 285 #[test]
508 fn completes_module_items_in_nested_modules() { 286 fn completes_module_items_in_nested_modules() {
509 assert_debug_snapshot!( 287 check(
510 do_reference_completion( 288 r#"
511 r" 289struct Foo;
512 struct Foo; 290mod m {
513 mod m { 291 struct Bar;
514 struct Bar; 292 fn quux() { <|> }
515 fn quux() { <|> } 293}
516 } 294"#,
517 " 295 expect![[r#"
518 ), 296 st Bar
519 @r###" 297 fn quux() fn quux()
520 [ 298 "#]],
521 CompletionItem {
522 label: "Bar",
523 source_range: 52..52,
524 delete: 52..52,
525 insert: "Bar",
526 kind: Struct,
527 },
528 CompletionItem {
529 label: "quux()",
530 source_range: 52..52,
531 delete: 52..52,
532 insert: "quux()$0",
533 kind: Function,
534 lookup: "quux",
535 detail: "fn quux()",
536 },
537 ]
538 "###
539 ); 299 );
540 } 300 }
541 301
542 #[test] 302 #[test]
543 fn completes_return_type() { 303 fn completes_return_type() {
544 assert_debug_snapshot!( 304 check(
545 do_reference_completion( 305 r#"
546 r" 306struct Foo;
547 struct Foo; 307fn x() -> <|>
548 fn x() -> <|> 308"#,
549 " 309 expect![[r#"
550 ), 310 st Foo
551 @r###" 311 fn x() fn x()
552 [ 312 "#]],
553 CompletionItem {
554 label: "Foo",
555 source_range: 22..22,
556 delete: 22..22,
557 insert: "Foo",
558 kind: Struct,
559 },
560 CompletionItem {
561 label: "x()",
562 source_range: 22..22,
563 delete: 22..22,
564 insert: "x()$0",
565 kind: Function,
566 lookup: "x",
567 detail: "fn x()",
568 },
569 ]
570 "###
571 ); 313 );
572 } 314 }
573 315
574 #[test] 316 #[test]
575 fn dont_show_both_completions_for_shadowing() { 317 fn dont_show_both_completions_for_shadowing() {
576 assert_debug_snapshot!( 318 check(
577 do_reference_completion( 319 r#"
578 r" 320fn foo() {
579 fn foo() { 321 let bar = 92;
580 let bar = 92; 322 {
581 { 323 let bar = 62;
582 let bar = 62; 324 drop(<|>)
583 <|> 325 }
584 } 326}
585 } 327"#,
586 " 328 // FIXME: should be only one bar here
587 ), 329 expect![[r#"
588 @r###" 330 bn bar i32
589 [ 331 bn bar i32
590 CompletionItem { 332 fn foo() fn foo()
591 label: "bar", 333 "#]],
592 source_range: 65..65,
593 delete: 65..65,
594 insert: "bar",
595 kind: Binding,
596 detail: "i32",
597 },
598 CompletionItem {
599 label: "foo()",
600 source_range: 65..65,
601 delete: 65..65,
602 insert: "foo()$0",
603 kind: Function,
604 lookup: "foo",
605 detail: "fn foo()",
606 },
607 ]
608 "###
609 ); 334 );
610 } 335 }
611 336
612 #[test] 337 #[test]
613 fn completes_self_in_methods() { 338 fn completes_self_in_methods() {
614 assert_debug_snapshot!( 339 check(
615 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), 340 r#"impl S { fn foo(&self) { <|> } }"#,
616 @r###" 341 expect![[r#"
617 [ 342 tp Self
618 CompletionItem { 343 bn self &{unknown}
619 label: "Self", 344 "#]],
620 source_range: 25..25,
621 delete: 25..25,
622 insert: "Self",
623 kind: TypeParam,
624 },
625 CompletionItem {
626 label: "self",
627 source_range: 25..25,
628 delete: 25..25,
629 insert: "self",
630 kind: Binding,
631 detail: "&{unknown}",
632 },
633 ]
634 "###
635 ); 345 );
636 } 346 }
637 347
638 #[test] 348 #[test]
639 fn completes_prelude() { 349 fn completes_prelude() {
640 assert_debug_snapshot!( 350 check(
641 do_reference_completion( 351 r#"
642 " 352//- /main.rs
643 //- /main.rs 353fn foo() { let x: <|> }
644 fn foo() { let x: <|> } 354
645 355//- /std/lib.rs
646 //- /std/lib.rs 356#[prelude_import]
647 #[prelude_import] 357use prelude::*;
648 use prelude::*; 358
649 359mod prelude { struct Option; }
650 mod prelude { 360"#,
651 struct Option; 361 expect![[r#"
652 } 362 st Option
653 " 363 fn foo() fn foo()
654 ), 364 md std
655 @r###" 365 "#]],
656 [
657 CompletionItem {
658 label: "Option",
659 source_range: 18..18,
660 delete: 18..18,
661 insert: "Option",
662 kind: Struct,
663 },
664 CompletionItem {
665 label: "foo()",
666 source_range: 18..18,
667 delete: 18..18,
668 insert: "foo()$0",
669 kind: Function,
670 lookup: "foo",
671 detail: "fn foo()",
672 },
673 CompletionItem {
674 label: "std",
675 source_range: 18..18,
676 delete: 18..18,
677 insert: "std",
678 kind: Module,
679 },
680 ]
681 "###
682 ); 366 );
683 } 367 }
684 368
685 #[test] 369 #[test]
686 fn completes_std_prelude_if_core_is_defined() { 370 fn completes_std_prelude_if_core_is_defined() {
687 assert_debug_snapshot!( 371 check(
688 do_reference_completion( 372 r#"
689 " 373//- /main.rs
690 //- /main.rs 374fn foo() { let x: <|> }
691 fn foo() { let x: <|> } 375
692 376//- /core/lib.rs
693 //- /core/lib.rs 377#[prelude_import]
694 #[prelude_import] 378use prelude::*;
695 use prelude::*; 379
696 380mod prelude { struct Option; }
697 mod prelude { 381
698 struct Option; 382//- /std/lib.rs
699 } 383#[prelude_import]
700 384use prelude::*;
701 //- /std/lib.rs 385
702 #[prelude_import] 386mod prelude { struct String; }
703 use prelude::*; 387"#,
704 388 expect![[r#"
705 mod prelude { 389 st String
706 struct String; 390 md core
707 } 391 fn foo() fn foo()
708 " 392 md std
709 ), 393 "#]],
710 @r###"
711 [
712 CompletionItem {
713 label: "String",
714 source_range: 18..18,
715 delete: 18..18,
716 insert: "String",
717 kind: Struct,
718 },
719 CompletionItem {
720 label: "core",
721 source_range: 18..18,
722 delete: 18..18,
723 insert: "core",
724 kind: Module,
725 },
726 CompletionItem {
727 label: "foo()",
728 source_range: 18..18,
729 delete: 18..18,
730 insert: "foo()$0",
731 kind: Function,
732 lookup: "foo",
733 detail: "fn foo()",
734 },
735 CompletionItem {
736 label: "std",
737 source_range: 18..18,
738 delete: 18..18,
739 insert: "std",
740 kind: Module,
741 },
742 ]
743 "###
744 ); 394 );
745 } 395 }
746 396
747 #[test] 397 #[test]
748 fn completes_macros_as_value() { 398 fn completes_macros_as_value() {
749 assert_debug_snapshot!( 399 check(
750 do_reference_completion( 400 r#"
751 " 401macro_rules! foo { () => {} }
752 //- /main.rs
753 macro_rules! foo {
754 () => {}
755 }
756 402
757 #[macro_use] 403#[macro_use]
758 mod m1 { 404mod m1 {
759 macro_rules! bar { 405 macro_rules! bar { () => {} }
760 () => {} 406}
761 }
762 }
763 407
764 mod m2 { 408mod m2 {
765 macro_rules! nope { 409 macro_rules! nope { () => {} }
766 () => {}
767 }
768 410
769 #[macro_export] 411 #[macro_export]
770 macro_rules! baz { 412 macro_rules! baz { () => {} }
771 () => {} 413}
772 }
773 }
774 414
775 fn main() { 415fn main() { let v = <|> }
776 let v = <|> 416"#,
777 } 417 expect![[r##"
778 " 418 ma bar!(…) macro_rules! bar
779 ), 419 ma baz!(…) #[macro_export]
780 @r###" 420 macro_rules! baz
781 [ 421 ma foo!(…) macro_rules! foo
782 CompletionItem { 422 md m1
783 label: "bar!(…)", 423 md m2
784 source_range: 256..256, 424 fn main() fn main()
785 delete: 256..256, 425 "##]],
786 insert: "bar!($0)",
787 kind: Macro,
788 detail: "macro_rules! bar",
789 },
790 CompletionItem {
791 label: "baz!(…)",
792 source_range: 256..256,
793 delete: 256..256,
794 insert: "baz!($0)",
795 kind: Macro,
796 detail: "#[macro_export]\nmacro_rules! baz",
797 },
798 CompletionItem {
799 label: "foo!(…)",
800 source_range: 256..256,
801 delete: 256..256,
802 insert: "foo!($0)",
803 kind: Macro,
804 detail: "macro_rules! foo",
805 },
806 CompletionItem {
807 label: "m1",
808 source_range: 256..256,
809 delete: 256..256,
810 insert: "m1",
811 kind: Module,
812 },
813 CompletionItem {
814 label: "m2",
815 source_range: 256..256,
816 delete: 256..256,
817 insert: "m2",
818 kind: Module,
819 },
820 CompletionItem {
821 label: "main()",
822 source_range: 256..256,
823 delete: 256..256,
824 insert: "main()$0",
825 kind: Function,
826 lookup: "main",
827 detail: "fn main()",
828 },
829 ]
830 "###
831 ); 426 );
832 } 427 }
833 428
834 #[test] 429 #[test]
835 fn completes_both_macro_and_value() { 430 fn completes_both_macro_and_value() {
836 assert_debug_snapshot!( 431 check(
837 do_reference_completion( 432 r#"
838 " 433macro_rules! foo { () => {} }
839 //- /main.rs 434fn foo() { <|> }
840 macro_rules! foo { 435"#,
841 () => {} 436 expect![[r#"
842 } 437 ma foo!(…) macro_rules! foo
843 438 fn foo() fn foo()
844 fn foo() { 439 "#]],
845 <|>
846 }
847 "
848 ),
849 @r###"
850 [
851 CompletionItem {
852 label: "foo!(…)",
853 source_range: 50..50,
854 delete: 50..50,
855 insert: "foo!($0)",
856 kind: Macro,
857 detail: "macro_rules! foo",
858 },
859 CompletionItem {
860 label: "foo()",
861 source_range: 50..50,
862 delete: 50..50,
863 insert: "foo()$0",
864 kind: Function,
865 lookup: "foo",
866 detail: "fn foo()",
867 },
868 ]
869 "###
870 ); 440 );
871 } 441 }
872 442
873 #[test] 443 #[test]
874 fn completes_macros_as_type() { 444 fn completes_macros_as_type() {
875 assert_debug_snapshot!( 445 check(
876 do_reference_completion( 446 r#"
877 " 447macro_rules! foo { () => {} }
878 //- /main.rs 448fn main() { let x: <|> }
879 macro_rules! foo { 449"#,
880 () => {} 450 expect![[r#"
881 } 451 ma foo!(…) macro_rules! foo
882 452 fn main() fn main()
883 fn main() { 453 "#]],
884 let x: <|>
885 }
886 "
887 ),
888 @r###"
889 [
890 CompletionItem {
891 label: "foo!(…)",
892 source_range: 58..58,
893 delete: 58..58,
894 insert: "foo!($0)",
895 kind: Macro,
896 detail: "macro_rules! foo",
897 },
898 CompletionItem {
899 label: "main()",
900 source_range: 58..58,
901 delete: 58..58,
902 insert: "main()$0",
903 kind: Function,
904 lookup: "main",
905 detail: "fn main()",
906 },
907 ]
908 "###
909 ); 454 );
910 } 455 }
911 456
912 #[test] 457 #[test]
913 fn completes_macros_as_stmt() { 458 fn completes_macros_as_stmt() {
914 assert_debug_snapshot!( 459 check(
915 do_reference_completion( 460 r#"
916 " 461macro_rules! foo { () => {} }
917 //- /main.rs 462fn main() { <|> }
918 macro_rules! foo { 463"#,
919 () => {} 464 expect![[r#"
920 } 465 ma foo!(…) macro_rules! foo
921 466 fn main() fn main()
922 fn main() { 467 "#]],
923 <|>
924 }
925 "
926 ),
927 @r###"
928 [
929 CompletionItem {
930 label: "foo!(…)",
931 source_range: 51..51,
932 delete: 51..51,
933 insert: "foo!($0)",
934 kind: Macro,
935 detail: "macro_rules! foo",
936 },
937 CompletionItem {
938 label: "main()",
939 source_range: 51..51,
940 delete: 51..51,
941 insert: "main()$0",
942 kind: Function,
943 lookup: "main",
944 detail: "fn main()",
945 },
946 ]
947 "###
948 ); 468 );
949 } 469 }
950 470
951 #[test] 471 #[test]
952 fn completes_local_item() { 472 fn completes_local_item() {
953 assert_debug_snapshot!( 473 check(
954 do_reference_completion( 474 r#"
955 " 475fn main() {
956 //- /main.rs 476 return f<|>;
957 fn main() { 477 fn frobnicate() {}
958 return f<|>; 478}
959 fn frobnicate() {} 479"#,
960 } 480 expect![[r#"
961 " 481 fn frobnicate() fn frobnicate()
962 ), 482 fn main() fn main()
963 @r###" 483 "#]],
964 [ 484 );
965 CompletionItem {
966 label: "frobnicate()",
967 source_range: 23..24,
968 delete: 23..24,
969 insert: "frobnicate()$0",
970 kind: Function,
971 lookup: "frobnicate",
972 detail: "fn frobnicate()",
973 },
974 CompletionItem {
975 label: "main()",
976 source_range: 23..24,
977 delete: 23..24,
978 insert: "main()$0",
979 kind: Function,
980 lookup: "main",
981 detail: "fn main()",
982 },
983 ]
984 "###
985 )
986 } 485 }
987 486
988 #[test] 487 #[test]
989 fn completes_in_simple_macro_1() { 488 fn completes_in_simple_macro_1() {
990 assert_debug_snapshot!( 489 check(
991 do_reference_completion( 490 r#"
992 r" 491macro_rules! m { ($e:expr) => { $e } }
993 macro_rules! m { ($e:expr) => { $e } } 492fn quux(x: i32) {
994 fn quux(x: i32) { 493 let y = 92;
995 let y = 92; 494 m!(<|>);
996 m!(<|>); 495}
997 } 496"#,
998 " 497 expect![[r#"
999 ), 498 ma m!(…) macro_rules! m
1000 @r###" 499 fn quux(…) fn quux(x: i32)
1001 [ 500 bn x i32
1002 CompletionItem { 501 bn y i32
1003 label: "m!(…)", 502 "#]],
1004 source_range: 80..80,
1005 delete: 80..80,
1006 insert: "m!($0)",
1007 kind: Macro,
1008 detail: "macro_rules! m",
1009 },
1010 CompletionItem {
1011 label: "quux(…)",
1012 source_range: 80..80,
1013 delete: 80..80,
1014 insert: "quux(${1:x})$0",
1015 kind: Function,
1016 lookup: "quux",
1017 detail: "fn quux(x: i32)",
1018 trigger_call_info: true,
1019 },
1020 CompletionItem {
1021 label: "x",
1022 source_range: 80..80,
1023 delete: 80..80,
1024 insert: "x",
1025 kind: Binding,
1026 detail: "i32",
1027 },
1028 CompletionItem {
1029 label: "y",
1030 source_range: 80..80,
1031 delete: 80..80,
1032 insert: "y",
1033 kind: Binding,
1034 detail: "i32",
1035 },
1036 ]
1037 "###
1038 ); 503 );
1039 } 504 }
1040 505
1041 #[test] 506 #[test]
1042 fn completes_in_simple_macro_2() { 507 fn completes_in_simple_macro_2() {
1043 assert_debug_snapshot!( 508 check(
1044 do_reference_completion( 509 r"
1045 r" 510macro_rules! m { ($e:expr) => { $e } }
1046 macro_rules! m { ($e:expr) => { $e } } 511fn quux(x: i32) {
1047 fn quux(x: i32) { 512 let y = 92;
1048 let y = 92; 513 m!(x<|>);
1049 m!(x<|>); 514}
1050 } 515",
1051 " 516 expect![[r#"
1052 ), 517 ma m!(…) macro_rules! m
1053 @r###" 518 fn quux(…) fn quux(x: i32)
1054 [ 519 bn x i32
1055 CompletionItem { 520 bn y i32
1056 label: "m!(…)", 521 "#]],
1057 source_range: 80..81,
1058 delete: 80..81,
1059 insert: "m!($0)",
1060 kind: Macro,
1061 detail: "macro_rules! m",
1062 },
1063 CompletionItem {
1064 label: "quux(…)",
1065 source_range: 80..81,
1066 delete: 80..81,
1067 insert: "quux(${1:x})$0",
1068 kind: Function,
1069 lookup: "quux",
1070 detail: "fn quux(x: i32)",
1071 trigger_call_info: true,
1072 },
1073 CompletionItem {
1074 label: "x",
1075 source_range: 80..81,
1076 delete: 80..81,
1077 insert: "x",
1078 kind: Binding,
1079 detail: "i32",
1080 },
1081 CompletionItem {
1082 label: "y",
1083 source_range: 80..81,
1084 delete: 80..81,
1085 insert: "y",
1086 kind: Binding,
1087 detail: "i32",
1088 },
1089 ]
1090 "###
1091 ); 522 );
1092 } 523 }
1093 524
1094 #[test] 525 #[test]
1095 fn completes_in_simple_macro_without_closing_parens() { 526 fn completes_in_simple_macro_without_closing_parens() {
1096 assert_debug_snapshot!( 527 check(
1097 do_reference_completion( 528 r#"
1098 r" 529macro_rules! m { ($e:expr) => { $e } }
1099 macro_rules! m { ($e:expr) => { $e } } 530fn quux(x: i32) {
1100 fn quux(x: i32) { 531 let y = 92;
1101 let y = 92; 532 m!(x<|>
1102 m!(x<|> 533}
1103 } 534"#,
1104 " 535 expect![[r#"
1105 ), 536 ma m!(…) macro_rules! m
1106 @r###" 537 fn quux(…) fn quux(x: i32)
1107 [ 538 bn x i32
1108 CompletionItem { 539 bn y i32
1109 label: "m!(…)", 540 "#]],
1110 source_range: 80..81,
1111 delete: 80..81,
1112 insert: "m!($0)",
1113 kind: Macro,
1114 detail: "macro_rules! m",
1115 },
1116 CompletionItem {
1117 label: "quux(…)",
1118 source_range: 80..81,
1119 delete: 80..81,
1120 insert: "quux(${1:x})$0",
1121 kind: Function,
1122 lookup: "quux",
1123 detail: "fn quux(x: i32)",
1124 trigger_call_info: true,
1125 },
1126 CompletionItem {
1127 label: "x",
1128 source_range: 80..81,
1129 delete: 80..81,
1130 insert: "x",
1131 kind: Binding,
1132 detail: "i32",
1133 },
1134 CompletionItem {
1135 label: "y",
1136 source_range: 80..81,
1137 delete: 80..81,
1138 insert: "y",
1139 kind: Binding,
1140 detail: "i32",
1141 },
1142 ]
1143 "###
1144 ); 541 );
1145 } 542 }
1146 543
1147 #[test] 544 #[test]
1148 fn completes_unresolved_uses() { 545 fn completes_unresolved_uses() {
1149 assert_debug_snapshot!( 546 check(
1150 do_reference_completion( 547 r#"
1151 r" 548use spam::Quux;
1152 use spam::Quux; 549
1153 550fn main() { <|> }
1154 fn main() { 551"#,
1155 <|> 552 expect![[r#"
1156 } 553 ?? Quux
1157 " 554 fn main() fn main()
1158 ), 555 "#]],
1159 @r###"
1160 [
1161 CompletionItem {
1162 label: "Quux",
1163 source_range: 33..33,
1164 delete: 33..33,
1165 insert: "Quux",
1166 },
1167 CompletionItem {
1168 label: "main()",
1169 source_range: 33..33,
1170 delete: 33..33,
1171 insert: "main()$0",
1172 kind: Function,
1173 lookup: "main",
1174 detail: "fn main()",
1175 },
1176 ]
1177 "###
1178 ); 556 );
1179 } 557 }
1180 #[test] 558 #[test]
1181 fn completes_enum_variant_matcharm() { 559 fn completes_enum_variant_matcharm() {
1182 assert_debug_snapshot!( 560 check(
1183 do_reference_completion( 561 r#"
1184 r" 562enum Foo { Bar, Baz, Quux }
1185 enum Foo {
1186 Bar,
1187 Baz,
1188 Quux
1189 }
1190
1191 fn main() {
1192 let foo = Foo::Quux;
1193 563
1194 match foo { 564fn main() {
1195 Qu<|> 565 let foo = Foo::Quux;
1196 } 566 match foo { Qu<|> }
1197 } 567}
1198 " 568"#,
1199 ), 569 expect![[r#"
1200 @r###" 570 en Foo
1201 [ 571 ev Foo::Bar ()
1202 CompletionItem { 572 ev Foo::Baz ()
1203 label: "Foo", 573 ev Foo::Quux ()
1204 source_range: 103..105, 574 "#]],
1205 delete: 103..105,
1206 insert: "Foo",
1207 kind: Enum,
1208 },
1209 CompletionItem {
1210 label: "Foo::Bar",
1211 source_range: 103..105,
1212 delete: 103..105,
1213 insert: "Foo::Bar",
1214 kind: EnumVariant,
1215 lookup: "Bar",
1216 detail: "()",
1217 },
1218 CompletionItem {
1219 label: "Foo::Baz",
1220 source_range: 103..105,
1221 delete: 103..105,
1222 insert: "Foo::Baz",
1223 kind: EnumVariant,
1224 lookup: "Baz",
1225 detail: "()",
1226 },
1227 CompletionItem {
1228 label: "Foo::Quux",
1229 source_range: 103..105,
1230 delete: 103..105,
1231 insert: "Foo::Quux",
1232 kind: EnumVariant,
1233 lookup: "Quux",
1234 detail: "()",
1235 },
1236 ]
1237 "###
1238 ) 575 )
1239 } 576 }
1240 577
1241 #[test] 578 #[test]
1242 fn completes_enum_variant_iflet() { 579 fn completes_enum_variant_iflet() {
1243 assert_debug_snapshot!( 580 check(
1244 do_reference_completion( 581 r#"
1245 r" 582enum Foo { Bar, Baz, Quux }
1246 enum Foo {
1247 Bar,
1248 Baz,
1249 Quux
1250 }
1251 583
1252 fn main() { 584fn main() {
1253 let foo = Foo::Quux; 585 let foo = Foo::Quux;
1254 586 if let Qu<|> = foo { }
1255 if let Qu<|> = foo { 587}
1256 588"#,
1257 } 589 expect![[r#"
1258 } 590 en Foo
1259 " 591 ev Foo::Bar ()
1260 ), 592 ev Foo::Baz ()
1261 @r###" 593 ev Foo::Quux ()
1262 [ 594 "#]],
1263 CompletionItem {
1264 label: "Foo",
1265 source_range: 90..92,
1266 delete: 90..92,
1267 insert: "Foo",
1268 kind: Enum,
1269 },
1270 CompletionItem {
1271 label: "Foo::Bar",
1272 source_range: 90..92,
1273 delete: 90..92,
1274 insert: "Foo::Bar",
1275 kind: EnumVariant,
1276 lookup: "Bar",
1277 detail: "()",
1278 },
1279 CompletionItem {
1280 label: "Foo::Baz",
1281 source_range: 90..92,
1282 delete: 90..92,
1283 insert: "Foo::Baz",
1284 kind: EnumVariant,
1285 lookup: "Baz",
1286 detail: "()",
1287 },
1288 CompletionItem {
1289 label: "Foo::Quux",
1290 source_range: 90..92,
1291 delete: 90..92,
1292 insert: "Foo::Quux",
1293 kind: EnumVariant,
1294 lookup: "Quux",
1295 detail: "()",
1296 },
1297 ]
1298 "###
1299 ) 595 )
1300 } 596 }
1301 597
1302 #[test] 598 #[test]
1303 fn completes_enum_variant_basic_expr() { 599 fn completes_enum_variant_basic_expr() {
1304 assert_debug_snapshot!( 600 check(
1305 do_reference_completion( 601 r#"
1306 r" 602enum Foo { Bar, Baz, Quux }
1307 enum Foo { 603fn main() { let foo: Foo = Q<|> }
1308 Bar, 604"#,
1309 Baz, 605 expect![[r#"
1310 Quux 606 en Foo
1311 } 607 ev Foo::Bar ()
1312 608 ev Foo::Baz ()
1313 fn main() { 609 ev Foo::Quux ()
1314 let foo: Foo = Q<|> 610 fn main() fn main()
1315 } 611 "#]],
1316 "
1317 ),
1318 @r###"
1319 [
1320 CompletionItem {
1321 label: "Foo",
1322 source_range: 72..73,
1323 delete: 72..73,
1324 insert: "Foo",
1325 kind: Enum,
1326 },
1327 CompletionItem {
1328 label: "Foo::Bar",
1329 source_range: 72..73,
1330 delete: 72..73,
1331 insert: "Foo::Bar",
1332 kind: EnumVariant,
1333 lookup: "Bar",
1334 detail: "()",
1335 },
1336 CompletionItem {
1337 label: "Foo::Baz",
1338 source_range: 72..73,
1339 delete: 72..73,
1340 insert: "Foo::Baz",
1341 kind: EnumVariant,
1342 lookup: "Baz",
1343 detail: "()",
1344 },
1345 CompletionItem {
1346 label: "Foo::Quux",
1347 source_range: 72..73,
1348 delete: 72..73,
1349 insert: "Foo::Quux",
1350 kind: EnumVariant,
1351 lookup: "Quux",
1352 detail: "()",
1353 },
1354 CompletionItem {
1355 label: "main()",
1356 source_range: 72..73,
1357 delete: 72..73,
1358 insert: "main()$0",
1359 kind: Function,
1360 lookup: "main",
1361 detail: "fn main()",
1362 },
1363 ]
1364 "###
1365 ) 612 )
1366 } 613 }
1367 614
1368 #[test] 615 #[test]
1369 fn completes_enum_variant_from_module() { 616 fn completes_enum_variant_from_module() {
1370 assert_debug_snapshot!( 617 check(
1371 do_reference_completion( 618 r#"
1372 r" 619mod m { pub enum E { V } }
1373 mod m { pub enum E { V } } 620fn f() -> m::E { V<|> }
1374 621"#,
1375 fn f() -> m::E { 622 expect![[r#"
1376 V<|> 623 fn f() fn f() -> m::E
1377 } 624 md m
1378 " 625 ev m::E::V ()
1379 ), 626 "#]],
1380 @r###"
1381 [
1382 CompletionItem {
1383 label: "f()",
1384 source_range: 49..50,
1385 delete: 49..50,
1386 insert: "f()$0",
1387 kind: Function,
1388 lookup: "f",
1389 detail: "fn f() -> m::E",
1390 },
1391 CompletionItem {
1392 label: "m",
1393 source_range: 49..50,
1394 delete: 49..50,
1395 insert: "m",
1396 kind: Module,
1397 },
1398 CompletionItem {
1399 label: "m::E::V",
1400 source_range: 49..50,
1401 delete: 49..50,
1402 insert: "m::E::V",
1403 kind: EnumVariant,
1404 lookup: "V",
1405 detail: "()",
1406 },
1407 ]
1408 "###
1409 ) 627 )
1410 } 628 }
1411 629
1412 #[test] 630 #[test]
1413 fn dont_complete_attr() { 631 fn dont_complete_attr() {
1414 assert_debug_snapshot!( 632 check(
1415 do_reference_completion( 633 r#"
1416 r" 634struct Foo;
1417 struct Foo; 635#[<|>]
1418 #[<|>] 636fn f() {}
1419 fn f() {} 637"#,
1420 " 638 expect![[""]],
1421 ), 639 )
1422 @r###"[]"### 640 }
641
642 #[test]
643 fn completes_type_or_trait_in_impl_block() {
644 check(
645 r#"
646trait MyTrait {}
647struct MyStruct {}
648
649impl My<|>
650"#,
651 expect![[r#"
652 st MyStruct
653 tt MyTrait
654 tp Self
655 "#]],
1423 ) 656 )
1424 } 657 }
1425} 658}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 560fb19e6..2113abbb2 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -24,6 +24,7 @@ use test_utils::mark;
24#[derive(Debug)] 24#[derive(Debug)]
25pub(crate) struct CompletionContext<'a> { 25pub(crate) struct CompletionContext<'a> {
26 pub(super) sema: Semantics<'a, RootDatabase>, 26 pub(super) sema: Semantics<'a, RootDatabase>,
27 pub(super) scope: SemanticsScope<'a>,
27 pub(super) db: &'a RootDatabase, 28 pub(super) db: &'a RootDatabase,
28 pub(super) config: &'a CompletionConfig, 29 pub(super) config: &'a CompletionConfig,
29 pub(super) offset: TextSize, 30 pub(super) offset: TextSize,
@@ -34,12 +35,12 @@ pub(crate) struct CompletionContext<'a> {
34 pub(super) krate: Option<hir::Crate>, 35 pub(super) krate: Option<hir::Crate>,
35 pub(super) expected_type: Option<Type>, 36 pub(super) expected_type: Option<Type>,
36 pub(super) name_ref_syntax: Option<ast::NameRef>, 37 pub(super) name_ref_syntax: Option<ast::NameRef>,
37 pub(super) function_syntax: Option<ast::FnDef>, 38 pub(super) function_syntax: Option<ast::Fn>,
38 pub(super) use_item_syntax: Option<ast::UseItem>, 39 pub(super) use_item_syntax: Option<ast::Use>,
39 pub(super) record_lit_syntax: Option<ast::RecordLit>, 40 pub(super) record_lit_syntax: Option<ast::RecordExpr>,
40 pub(super) record_pat_syntax: Option<ast::RecordPat>, 41 pub(super) record_pat_syntax: Option<ast::RecordPat>,
41 pub(super) record_field_syntax: Option<ast::RecordField>, 42 pub(super) record_field_syntax: Option<ast::RecordExprField>,
42 pub(super) impl_def: Option<ast::ImplDef>, 43 pub(super) impl_def: Option<ast::Impl>,
43 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 44 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
44 pub(super) active_parameter: Option<ActiveParameter>, 45 pub(super) active_parameter: Option<ActiveParameter>,
45 pub(super) is_param: bool, 46 pub(super) is_param: bool,
@@ -53,6 +54,8 @@ pub(crate) struct CompletionContext<'a> {
53 pub(super) after_if: bool, 54 pub(super) after_if: bool,
54 /// `true` if we are a statement or a last expr in the block. 55 /// `true` if we are a statement or a last expr in the block.
55 pub(super) can_be_stmt: bool, 56 pub(super) can_be_stmt: bool,
57 /// `true` if we expect an expression at the cursor position.
58 pub(super) is_expr: bool,
56 /// Something is typed at the "top" level, in module or impl/trait. 59 /// Something is typed at the "top" level, in module or impl/trait.
57 pub(super) is_new_item: bool, 60 pub(super) is_new_item: bool,
58 /// The receiver if this is a field or method access, i.e. writing something.<|> 61 /// The receiver if this is a field or method access, i.e. writing something.<|>
@@ -60,6 +63,8 @@ pub(crate) struct CompletionContext<'a> {
60 pub(super) dot_receiver_is_ambiguous_float_literal: bool, 63 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
61 /// If this is a call (method or function) in particular, i.e. the () are already there. 64 /// If this is a call (method or function) in particular, i.e. the () are already there.
62 pub(super) is_call: bool, 65 pub(super) is_call: bool,
66 /// Like `is_call`, but for tuple patterns.
67 pub(super) is_pattern_call: bool,
63 /// If this is a macro call, i.e. the () are already there. 68 /// If this is a macro call, i.e. the () are already there.
64 pub(super) is_macro_call: bool, 69 pub(super) is_macro_call: bool,
65 pub(super) is_path_type: bool, 70 pub(super) is_path_type: bool,
@@ -104,8 +109,10 @@ impl<'a> CompletionContext<'a> {
104 let original_token = 109 let original_token =
105 original_file.syntax().token_at_offset(position.offset).left_biased()?; 110 original_file.syntax().token_at_offset(position.offset).left_biased()?;
106 let token = sema.descend_into_macros(original_token.clone()); 111 let token = sema.descend_into_macros(original_token.clone());
112 let scope = sema.scope_at_offset(&token.parent(), position.offset);
107 let mut ctx = CompletionContext { 113 let mut ctx = CompletionContext {
108 sema, 114 sema,
115 scope,
109 db, 116 db,
110 config, 117 config,
111 original_token, 118 original_token,
@@ -127,9 +134,11 @@ impl<'a> CompletionContext<'a> {
127 path_prefix: None, 134 path_prefix: None,
128 after_if: false, 135 after_if: false,
129 can_be_stmt: false, 136 can_be_stmt: false,
137 is_expr: false,
130 is_new_item: false, 138 is_new_item: false,
131 dot_receiver: None, 139 dot_receiver: None,
132 is_call: false, 140 is_call: false,
141 is_pattern_call: false,
133 is_macro_call: false, 142 is_macro_call: false,
134 is_path_type: false, 143 is_path_type: false,
135 has_type_args: false, 144 has_type_args: false,
@@ -196,30 +205,17 @@ impl<'a> CompletionContext<'a> {
196 // The range of the identifier that is being completed. 205 // The range of the identifier that is being completed.
197 pub(crate) fn source_range(&self) -> TextRange { 206 pub(crate) fn source_range(&self) -> TextRange {
198 // check kind of macro-expanded token, but use range of original token 207 // check kind of macro-expanded token, but use range of original token
199 match self.token.kind() { 208 if self.token.kind() == IDENT || self.token.kind().is_keyword() {
200 // workaroud when completion is triggered by trigger characters. 209 mark::hit!(completes_if_prefix_is_keyword);
201 IDENT => self.original_token.text_range(), 210 self.original_token.text_range()
202 _ => { 211 } else {
203 // If we haven't characters between keyword and our cursor we take the keyword start range to edit 212 TextRange::empty(self.offset)
204 if self.token.kind().is_keyword()
205 && self.offset == self.original_token.text_range().end()
206 {
207 mark::hit!(completes_bindings_from_for_with_in_prefix);
208 TextRange::empty(self.original_token.text_range().start())
209 } else {
210 TextRange::empty(self.offset)
211 }
212 }
213 } 213 }
214 } 214 }
215 215
216 pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> {
217 self.sema.scope_at_offset(&self.token.parent(), self.offset)
218 }
219
220 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 216 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
221 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); 217 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
222 let syntax_element = NodeOrToken::Token(fake_ident_token.clone()); 218 let syntax_element = NodeOrToken::Token(fake_ident_token);
223 self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); 219 self.block_expr_parent = has_block_expr_parent(syntax_element.clone());
224 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); 220 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone());
225 self.if_is_prev = if_is_prev(syntax_element.clone()); 221 self.if_is_prev = if_is_prev(syntax_element.clone());
@@ -232,7 +228,7 @@ impl<'a> CompletionContext<'a> {
232 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 228 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
233 self.is_match_arm = is_match_arm(syntax_element.clone()); 229 self.is_match_arm = is_match_arm(syntax_element.clone());
234 self.has_item_list_or_source_file_parent = 230 self.has_item_list_or_source_file_parent =
235 has_item_list_or_source_file_parent(syntax_element.clone()); 231 has_item_list_or_source_file_parent(syntax_element);
236 } 232 }
237 233
238 fn fill( 234 fn fill(
@@ -320,7 +316,7 @@ impl<'a> CompletionContext<'a> {
320 self.name_ref_syntax = 316 self.name_ref_syntax =
321 find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); 317 find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
322 let name_range = name_ref.syntax().text_range(); 318 let name_range = name_ref.syntax().text_range();
323 if ast::RecordField::for_field_name(&name_ref).is_some() { 319 if ast::RecordExprField::for_field_name(&name_ref).is_some() {
324 self.record_lit_syntax = 320 self.record_lit_syntax =
325 self.sema.find_node_at_offset_with_macros(&original_file, offset); 321 self.sema.find_node_at_offset_with_macros(&original_file, offset);
326 } 322 }
@@ -329,7 +325,7 @@ impl<'a> CompletionContext<'a> {
329 .sema 325 .sema
330 .ancestors_with_macros(self.token.parent()) 326 .ancestors_with_macros(self.token.parent())
331 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 327 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
332 .find_map(ast::ImplDef::cast); 328 .find_map(ast::Impl::cast);
333 329
334 let top_node = name_ref 330 let top_node = name_ref
335 .syntax() 331 .syntax()
@@ -347,13 +343,13 @@ impl<'a> CompletionContext<'a> {
347 } 343 }
348 344
349 self.use_item_syntax = 345 self.use_item_syntax =
350 self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast); 346 self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::Use::cast);
351 347
352 self.function_syntax = self 348 self.function_syntax = self
353 .sema 349 .sema
354 .ancestors_with_macros(self.token.parent()) 350 .ancestors_with_macros(self.token.parent())
355 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 351 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
356 .find_map(ast::FnDef::cast); 352 .find_map(ast::Fn::cast);
357 353
358 self.record_field_syntax = self 354 self.record_field_syntax = self
359 .sema 355 .sema
@@ -361,7 +357,7 @@ impl<'a> CompletionContext<'a> {
361 .take_while(|it| { 357 .take_while(|it| {
362 it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR 358 it.kind() != SOURCE_FILE && it.kind() != MODULE && it.kind() != CALL_EXPR
363 }) 359 })
364 .find_map(ast::RecordField::cast); 360 .find_map(ast::RecordExprField::cast);
365 361
366 let parent = match name_ref.syntax().parent() { 362 let parent = match name_ref.syntax().parent() {
367 Some(it) => it, 363 Some(it) => it,
@@ -377,6 +373,8 @@ impl<'a> CompletionContext<'a> {
377 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 373 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
378 .is_some(); 374 .is_some();
379 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some(); 375 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();
376 self.is_pattern_call =
377 path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some();
380 378
381 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 379 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
382 self.has_type_args = segment.type_arg_list().is_some(); 380 self.has_type_args = segment.type_arg_list().is_some();
@@ -412,6 +410,7 @@ impl<'a> CompletionContext<'a> {
412 None 410 None
413 }) 411 })
414 .unwrap_or(false); 412 .unwrap_or(false);
413 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
415 414
416 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { 415 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
417 if let Some(if_expr) = 416 if let Some(if_expr) =
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs
index 98348b349..7bdda316c 100644
--- a/crates/ra_ide/src/completion/completion_item.rs
+++ b/crates/ra_ide/src/completion/completion_item.rs
@@ -58,7 +58,7 @@ pub struct CompletionItem {
58 score: Option<CompletionScore>, 58 score: Option<CompletionScore>,
59} 59}
60 60
61// We use custom debug for CompletionItem to make `insta`'s diffs more readable. 61// We use custom debug for CompletionItem to make snapshot tests more readable.
62impl fmt::Debug for CompletionItem { 62impl fmt::Debug for CompletionItem {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 let mut s = f.debug_struct("CompletionItem"); 64 let mut s = f.debug_struct("CompletionItem");
@@ -95,7 +95,7 @@ impl fmt::Debug for CompletionItem {
95 } 95 }
96} 96}
97 97
98#[derive(Debug, Clone, Copy)] 98#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
99pub enum CompletionScore { 99pub enum CompletionScore {
100 /// If only type match 100 /// If only type match
101 TypeMatch, 101 TypeMatch,
@@ -123,30 +123,32 @@ pub enum CompletionItemKind {
123 TypeParam, 123 TypeParam,
124 Macro, 124 Macro,
125 Attribute, 125 Attribute,
126 UnresolvedReference,
126} 127}
127 128
128impl CompletionItemKind { 129impl CompletionItemKind {
129 #[cfg(test)] 130 #[cfg(test)]
130 pub(crate) fn tag(&self) -> &'static str { 131 pub(crate) fn tag(&self) -> &'static str {
131 match self { 132 match self {
132 CompletionItemKind::Snippet => "sn", 133 CompletionItemKind::Attribute => "at",
133 CompletionItemKind::Keyword => "kw", 134 CompletionItemKind::Binding => "bn",
134 CompletionItemKind::Module => "md",
135 CompletionItemKind::Function => "fn",
136 CompletionItemKind::BuiltinType => "bt", 135 CompletionItemKind::BuiltinType => "bt",
137 CompletionItemKind::Struct => "st", 136 CompletionItemKind::Const => "ct",
138 CompletionItemKind::Enum => "en", 137 CompletionItemKind::Enum => "en",
139 CompletionItemKind::EnumVariant => "ev", 138 CompletionItemKind::EnumVariant => "ev",
140 CompletionItemKind::Binding => "bn",
141 CompletionItemKind::Field => "fd", 139 CompletionItemKind::Field => "fd",
140 CompletionItemKind::Function => "fn",
141 CompletionItemKind::Keyword => "kw",
142 CompletionItemKind::Macro => "ma",
143 CompletionItemKind::Method => "me",
144 CompletionItemKind::Module => "md",
145 CompletionItemKind::Snippet => "sn",
142 CompletionItemKind::Static => "sc", 146 CompletionItemKind::Static => "sc",
143 CompletionItemKind::Const => "ct", 147 CompletionItemKind::Struct => "st",
144 CompletionItemKind::Trait => "tt", 148 CompletionItemKind::Trait => "tt",
145 CompletionItemKind::TypeAlias => "ta", 149 CompletionItemKind::TypeAlias => "ta",
146 CompletionItemKind::Method => "me",
147 CompletionItemKind::TypeParam => "tp", 150 CompletionItemKind::TypeParam => "tp",
148 CompletionItemKind::Macro => "ma", 151 CompletionItemKind::UnresolvedReference => "??",
149 CompletionItemKind::Attribute => "at",
150 } 152 }
151 } 153 }
152} 154}
diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs
index b2fe13280..a68861e1c 100644
--- a/crates/ra_ide/src/completion/patterns.rs
+++ b/crates/ra_ide/src/completion/patterns.rs
@@ -13,9 +13,9 @@ use crate::completion::test_utils::check_pattern_is_applicable;
13 13
14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { 14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
15 not_same_range_ancestor(element) 15 not_same_range_ancestor(element)
16 .filter(|it| it.kind() == ITEM_LIST) 16 .filter(|it| it.kind() == ASSOC_ITEM_LIST)
17 .and_then(|it| it.parent()) 17 .and_then(|it| it.parent())
18 .filter(|it| it.kind() == TRAIT_DEF) 18 .filter(|it| it.kind() == TRAIT)
19 .is_some() 19 .is_some()
20} 20}
21#[test] 21#[test]
@@ -25,9 +25,9 @@ fn test_has_trait_parent() {
25 25
26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { 26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
27 not_same_range_ancestor(element) 27 not_same_range_ancestor(element)
28 .filter(|it| it.kind() == ITEM_LIST) 28 .filter(|it| it.kind() == ASSOC_ITEM_LIST)
29 .and_then(|it| it.parent()) 29 .and_then(|it| it.parent())
30 .filter(|it| it.kind() == IMPL_DEF) 30 .filter(|it| it.kind() == IMPL)
31 .is_some() 31 .is_some()
32} 32}
33#[test] 33#[test]
@@ -73,7 +73,7 @@ pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> boo
73#[test] 73#[test]
74fn test_has_item_list_or_source_file_parent() { 74fn test_has_item_list_or_source_file_parent() {
75 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent); 75 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
76 check_pattern_is_applicable(r"impl { f<|> }", has_item_list_or_source_file_parent); 76 check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent);
77} 77}
78 78
79pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { 79pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
@@ -113,7 +113,7 @@ fn test_if_is_prev() {
113} 113}
114 114
115pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { 115pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
116 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some() 116 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some()
117} 117}
118#[test] 118#[test]
119fn test_has_trait_as_prev_sibling() { 119fn test_has_trait_as_prev_sibling() {
@@ -121,7 +121,7 @@ fn test_has_trait_as_prev_sibling() {
121} 121}
122 122
123pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { 123pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
124 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some() 124 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
125} 125}
126#[test] 126#[test]
127fn test_has_impl_as_prev_sibling() { 127fn test_has_impl_as_prev_sibling() {
@@ -134,7 +134,7 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
134 NodeOrToken::Token(token) => token.parent(), 134 NodeOrToken::Token(token) => token.parent(),
135 }; 135 };
136 for node in leaf.ancestors() { 136 for node in leaf.ancestors() {
137 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { 137 if node.kind() == FN || node.kind() == LAMBDA_EXPR {
138 break; 138 break;
139 } 139 }
140 let loop_body = match_ast! { 140 let loop_body = match_ast! {
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 4fdc2f0bb..9a94ff476 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1,4 +1,5 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2//! It also handles scoring (sorting) completions.
2 3
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; 4use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
4use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
@@ -10,7 +11,7 @@ use crate::{
10 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, 11 completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
11 CompletionKind, Completions, 12 CompletionKind, Completions,
12 }, 13 },
13 display::{const_label, macro_label, type_label, FunctionSignature}, 14 display::{const_label, function_declaration, macro_label, type_label},
14 CompletionScore, RootDatabase, 15 CompletionScore, RootDatabase,
15}; 16};
16 17
@@ -78,11 +79,10 @@ impl Completions {
78 return self.add_macro(ctx, Some(local_name), *mac); 79 return self.add_macro(ctx, Some(local_name), *mac);
79 } 80 }
80 ScopeDef::Unknown => { 81 ScopeDef::Unknown => {
81 return self.add(CompletionItem::new( 82 return self.add(
82 CompletionKind::Reference, 83 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), local_name)
83 ctx.source_range(), 84 .kind(CompletionItemKind::UnresolvedReference),
84 local_name, 85 );
85 ));
86 } 86 }
87 }; 87 };
88 88
@@ -173,6 +173,7 @@ impl Completions {
173 builder 173 builder
174 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket)) 174 .insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
175 .label(format!("{}!{}…{}", name, bra, ket)) 175 .label(format!("{}!{}…{}", name, bra, ket))
176 .lookup_by(format!("{}!", name))
176 } 177 }
177 None if needs_bang => builder.insert_text(format!("{}!", name)), 178 None if needs_bang => builder.insert_text(format!("{}!", name)),
178 _ => { 179 _ => {
@@ -194,7 +195,6 @@ impl Completions {
194 195
195 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); 196 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
196 let ast_node = func.source(ctx.db).value; 197 let ast_node = func.source(ctx.db).value;
197 let function_signature = FunctionSignature::from(&ast_node);
198 198
199 let mut builder = 199 let mut builder =
200 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) 200 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
@@ -205,13 +205,14 @@ impl Completions {
205 }) 205 })
206 .set_documentation(func.docs(ctx.db)) 206 .set_documentation(func.docs(ctx.db))
207 .set_deprecated(is_deprecated(func, ctx.db)) 207 .set_deprecated(is_deprecated(func, ctx.db))
208 .detail(function_signature.to_string()); 208 .detail(function_declaration(&ast_node));
209 209
210 let params = function_signature 210 let params = ast_node
211 .parameter_names 211 .param_list()
212 .iter() 212 .into_iter()
213 .skip(if function_signature.has_self_param { 1 } else { 0 }) 213 .flat_map(|it| it.params())
214 .map(|name| name.trim_start_matches('_').into()) 214 .flat_map(|it| it.pat())
215 .map(|pat| pat.to_string().trim_start_matches('_').into())
215 .collect(); 216 .collect();
216 217
217 builder = builder.add_call_parens(ctx, name, Params::Named(params)); 218 builder = builder.add_call_parens(ctx, name, Params::Named(params));
@@ -314,6 +315,7 @@ impl Completions {
314 } 315 }
315 316
316 if variant_kind == StructKind::Tuple { 317 if variant_kind == StructKind::Tuple {
318 mark::hit!(inserts_parens_for_tuple_enums);
317 let params = Params::Anonymous(variant.fields(ctx.db).len()); 319 let params = Params::Anonymous(variant.fields(ctx.db).len());
318 res = res.add_call_parens(ctx, qualified_name, params) 320 res = res.add_call_parens(ctx, qualified_name, params)
319 } 321 }
@@ -327,17 +329,12 @@ pub(crate) fn compute_score(
327 ty: &Type, 329 ty: &Type,
328 name: &str, 330 name: &str,
329) -> Option<CompletionScore> { 331) -> Option<CompletionScore> {
330 // FIXME: this should not fall back to string equality.
331 let ty = &ty.display(ctx.db).to_string();
332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
333 mark::hit!(test_struct_field_completion_in_record_lit); 333 mark::hit!(record_field_type_match);
334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
335 ( 335 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
336 struct_field.name(ctx.db).to_string(),
337 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
338 )
339 } else if let Some(active_parameter) = &ctx.active_parameter { 336 } else if let Some(active_parameter) = &ctx.active_parameter {
340 mark::hit!(test_struct_field_completion_in_func_call); 337 mark::hit!(active_param_type_match);
341 (active_parameter.name.clone(), active_parameter.ty.clone()) 338 (active_parameter.name.clone(), active_parameter.ty.clone())
342 } else { 339 } else {
343 return None; 340 return None;
@@ -382,13 +379,22 @@ impl Builder {
382 if !ctx.config.add_call_parenthesis { 379 if !ctx.config.add_call_parenthesis {
383 return self; 380 return self;
384 } 381 }
385 if ctx.use_item_syntax.is_some() || ctx.is_call { 382 if ctx.use_item_syntax.is_some() {
383 mark::hit!(no_parens_in_use_item);
384 return self;
385 }
386 if ctx.is_pattern_call {
387 mark::hit!(dont_duplicate_pattern_parens);
388 return self;
389 }
390 if ctx.is_call {
386 return self; 391 return self;
387 } 392 }
388 393
389 // Don't add parentheses if the expected type is some function reference. 394 // Don't add parentheses if the expected type is some function reference.
390 if let Some(ty) = &ctx.expected_type { 395 if let Some(ty) = &ctx.expected_type {
391 if ty.is_fn() { 396 if ty.is_fn() {
397 mark::hit!(no_call_parens_if_fn_ptr_needed);
392 return self; 398 return self;
393 } 399 }
394 } 400 }
@@ -413,7 +419,10 @@ impl Builder {
413 .sep_by(", "); 419 .sep_by(", ");
414 format!("{}({})$0", name, function_params_snippet) 420 format!("{}({})$0", name, function_params_snippet)
415 } 421 }
416 _ => format!("{}($0)", name), 422 _ => {
423 mark::hit!(suppress_arg_snippets);
424 format!("{}($0)", name)
425 }
417 }; 426 };
418 427
419 (snippet, format!("{}(…)", name)) 428 (snippet, format!("{}(…)", name))
@@ -456,1064 +465,766 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
456 465
457#[cfg(test)] 466#[cfg(test)]
458mod tests { 467mod tests {
459 use insta::assert_debug_snapshot; 468 use std::cmp::Reverse;
469
470 use expect::{expect, Expect};
460 use test_utils::mark; 471 use test_utils::mark;
461 472
462 use crate::completion::{ 473 use crate::{
463 test_utils::{do_completion, do_completion_with_options}, 474 completion::{
464 CompletionConfig, CompletionItem, CompletionKind, 475 test_utils::{
476 check_edit, check_edit_with_config, do_completion, get_all_completion_items,
477 },
478 CompletionConfig, CompletionKind,
479 },
480 CompletionScore,
465 }; 481 };
466 482
467 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 483 fn check(ra_fixture: &str, expect: Expect) {
468 do_completion(ra_fixture, CompletionKind::Reference) 484 let actual = do_completion(ra_fixture, CompletionKind::Reference);
485 expect.assert_debug_eq(&actual);
469 } 486 }
470 487
471 fn do_reference_completion_with_options( 488 fn check_scores(ra_fixture: &str, expect: Expect) {
472 ra_fixture: &str, 489 fn display_score(score: Option<CompletionScore>) -> &'static str {
473 options: CompletionConfig, 490 match score {
474 ) -> Vec<CompletionItem> { 491 Some(CompletionScore::TypeMatch) => "[type]",
475 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) 492 Some(CompletionScore::TypeAndNameMatch) => "[type+name]",
493 None => "[]".into(),
494 }
495 }
496
497 let mut completions = get_all_completion_items(CompletionConfig::default(), ra_fixture);
498 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string()));
499 let actual = completions
500 .into_iter()
501 .filter(|it| it.completion_kind == CompletionKind::Reference)
502 .map(|it| {
503 let tag = it.kind().unwrap().tag();
504 let score = display_score(it.score());
505 format!("{} {} {}\n", tag, it.label(), score)
506 })
507 .collect::<String>();
508 expect.assert_eq(&actual);
476 } 509 }
477 510
478 #[test] 511 #[test]
479 fn enum_detail_includes_names_for_record() { 512 fn enum_detail_includes_record_fields() {
480 assert_debug_snapshot!( 513 check(
481 do_reference_completion(
482 r#" 514 r#"
483 enum Foo { 515enum Foo { Foo { x: i32, y: i32 } }
484 Foo {x: i32, y: i32} 516
485 } 517fn main() { Foo::Fo<|> }
486 518"#,
487 fn main() { Foo::Fo<|> } 519 expect![[r#"
488 "#, 520 [
489 ), 521 CompletionItem {
490 @r###" 522 label: "Foo",
491 [ 523 source_range: 54..56,
492 CompletionItem { 524 delete: 54..56,
493 label: "Foo", 525 insert: "Foo",
494 source_range: 56..58, 526 kind: EnumVariant,
495 delete: 56..58, 527 detail: "{ x: i32, y: i32 }",
496 insert: "Foo", 528 },
497 kind: EnumVariant, 529 ]
498 detail: "{ x: i32, y: i32 }", 530 "#]],
499 },
500 ]
501 "###
502 ); 531 );
503 } 532 }
504 533
505 #[test] 534 #[test]
506 fn enum_detail_doesnt_include_names_for_tuple() { 535 fn enum_detail_doesnt_include_tuple_fields() {
507 assert_debug_snapshot!( 536 check(
508 do_reference_completion(
509 r#" 537 r#"
510 enum Foo { 538enum Foo { Foo (i32, i32) }
511 Foo (i32, i32) 539
512 } 540fn main() { Foo::Fo<|> }
513 541"#,
514 fn main() { Foo::Fo<|> } 542 expect![[r#"
515 "#, 543 [
516 ), 544 CompletionItem {
517 @r###" 545 label: "Foo(…)",
518 [ 546 source_range: 46..48,
519 CompletionItem { 547 delete: 46..48,
520 label: "Foo(…)", 548 insert: "Foo($0)",
521 source_range: 50..52, 549 kind: EnumVariant,
522 delete: 50..52, 550 lookup: "Foo",
523 insert: "Foo($0)", 551 detail: "(i32, i32)",
524 kind: EnumVariant, 552 trigger_call_info: true,
525 lookup: "Foo", 553 },
526 detail: "(i32, i32)", 554 ]
527 trigger_call_info: true, 555 "#]],
528 },
529 ]
530 "###
531 ); 556 );
532 } 557 }
533 558
534 #[test] 559 #[test]
535 fn enum_detail_just_parentheses_for_unit() { 560 fn enum_detail_just_parentheses_for_unit() {
536 assert_debug_snapshot!( 561 check(
537 do_reference_completion(
538 r#" 562 r#"
539 enum Foo { 563enum Foo { Foo }
540 Foo 564
541 } 565fn main() { Foo::Fo<|> }
542 566"#,
543 fn main() { Foo::Fo<|> } 567 expect![[r#"
544 "#, 568 [
545 ), 569 CompletionItem {
546 @r###" 570 label: "Foo",
547 [ 571 source_range: 35..37,
548 CompletionItem { 572 delete: 35..37,
549 label: "Foo", 573 insert: "Foo",
550 source_range: 39..41, 574 kind: EnumVariant,
551 delete: 39..41, 575 detail: "()",
552 insert: "Foo", 576 },
553 kind: EnumVariant, 577 ]
554 detail: "()", 578 "#]],
555 },
556 ]
557 "###
558 ); 579 );
559 } 580 }
560 581
561 #[test] 582 #[test]
562 fn sets_deprecated_flag_in_completion_items() { 583 fn sets_deprecated_flag_in_completion_items() {
563 assert_debug_snapshot!( 584 check(
564 do_reference_completion( 585 r#"
565 r#" 586#[deprecated]
566 #[deprecated] 587fn something_deprecated() {}
567 fn something_deprecated() {} 588#[deprecated(since = "1.0.0")]
568 589fn something_else_deprecated() {}
569 #[deprecated(since = "1.0.0")] 590
570 fn something_else_deprecated() {} 591fn main() { som<|> }
571 592"#,
572 fn main() { som<|> } 593 expect![[r#"
573 "#, 594 [
574 ), 595 CompletionItem {
575 @r###" 596 label: "main()",
576 [ 597 source_range: 121..124,
577 CompletionItem { 598 delete: 121..124,
578 label: "main()", 599 insert: "main()$0",
579 source_range: 122..125, 600 kind: Function,
580 delete: 122..125, 601 lookup: "main",
581 insert: "main()$0", 602 detail: "fn main()",
582 kind: Function, 603 },
583 lookup: "main", 604 CompletionItem {
584 detail: "fn main()", 605 label: "something_deprecated()",
585 }, 606 source_range: 121..124,
586 CompletionItem { 607 delete: 121..124,
587 label: "something_deprecated()", 608 insert: "something_deprecated()$0",
588 source_range: 122..125, 609 kind: Function,
589 delete: 122..125, 610 lookup: "something_deprecated",
590 insert: "something_deprecated()$0", 611 detail: "fn something_deprecated()",
591 kind: Function, 612 deprecated: true,
592 lookup: "something_deprecated", 613 },
593 detail: "fn something_deprecated()", 614 CompletionItem {
594 deprecated: true, 615 label: "something_else_deprecated()",
595 }, 616 source_range: 121..124,
596 CompletionItem { 617 delete: 121..124,
597 label: "something_else_deprecated()", 618 insert: "something_else_deprecated()$0",
598 source_range: 122..125, 619 kind: Function,
599 delete: 122..125, 620 lookup: "something_else_deprecated",
600 insert: "something_else_deprecated()$0", 621 detail: "fn something_else_deprecated()",
601 kind: Function, 622 deprecated: true,
602 lookup: "something_else_deprecated", 623 },
603 detail: "fn something_else_deprecated()", 624 ]
604 deprecated: true, 625 "#]],
605 }, 626 );
606 ] 627
607 "### 628 check(
629 r#"
630struct A { #[deprecated] the_field: u32 }
631fn foo() { A { the<|> } }
632"#,
633 expect![[r#"
634 [
635 CompletionItem {
636 label: "the_field",
637 source_range: 57..60,
638 delete: 57..60,
639 insert: "the_field",
640 kind: Field,
641 detail: "u32",
642 deprecated: true,
643 },
644 ]
645 "#]],
646 );
647 }
648
649 #[test]
650 fn renders_docs() {
651 check(
652 r#"
653struct S {
654 /// Field docs
655 foo:
656}
657impl S {
658 /// Method docs
659 fn bar(self) { self.<|> }
660}"#,
661 expect![[r#"
662 [
663 CompletionItem {
664 label: "bar()",
665 source_range: 94..94,
666 delete: 94..94,
667 insert: "bar()$0",
668 kind: Method,
669 lookup: "bar",
670 detail: "fn bar(self)",
671 documentation: Documentation(
672 "Method docs",
673 ),
674 },
675 CompletionItem {
676 label: "foo",
677 source_range: 94..94,
678 delete: 94..94,
679 insert: "foo",
680 kind: Field,
681 detail: "{unknown}",
682 documentation: Documentation(
683 "Field docs",
684 ),
685 },
686 ]
687 "#]],
608 ); 688 );
689
690 check(
691 r#"
692use self::my<|>;
693
694/// mod docs
695mod my { }
696
697/// enum docs
698enum E {
699 /// variant docs
700 V
701}
702use self::E::*;
703"#,
704 expect![[r#"
705 [
706 CompletionItem {
707 label: "E",
708 source_range: 10..12,
709 delete: 10..12,
710 insert: "E",
711 kind: Enum,
712 documentation: Documentation(
713 "enum docs",
714 ),
715 },
716 CompletionItem {
717 label: "V",
718 source_range: 10..12,
719 delete: 10..12,
720 insert: "V",
721 kind: EnumVariant,
722 detail: "()",
723 documentation: Documentation(
724 "variant docs",
725 ),
726 },
727 CompletionItem {
728 label: "my",
729 source_range: 10..12,
730 delete: 10..12,
731 insert: "my",
732 kind: Module,
733 documentation: Documentation(
734 "mod docs",
735 ),
736 },
737 ]
738 "#]],
739 )
740 }
741
742 #[test]
743 fn dont_render_attrs() {
744 check(
745 r#"
746struct S;
747impl S {
748 #[inline]
749 fn the_method(&self) { }
750}
751fn foo(s: S) { s.<|> }
752"#,
753 expect![[r#"
754 [
755 CompletionItem {
756 label: "the_method()",
757 source_range: 81..81,
758 delete: 81..81,
759 insert: "the_method()$0",
760 kind: Method,
761 lookup: "the_method",
762 detail: "fn the_method(&self)",
763 },
764 ]
765 "#]],
766 )
609 } 767 }
610 768
611 #[test] 769 #[test]
612 fn inserts_parens_for_function_calls() { 770 fn inserts_parens_for_function_calls() {
613 mark::check!(inserts_parens_for_function_calls); 771 mark::check!(inserts_parens_for_function_calls);
614 assert_debug_snapshot!( 772 check_edit(
615 do_reference_completion( 773 "no_args",
616 r" 774 r#"
617 fn no_args() {} 775fn no_args() {}
618 fn main() { no_<|> } 776fn main() { no_<|> }
619 " 777"#,
620 ), 778 r#"
621 @r###" 779fn no_args() {}
622 [ 780fn main() { no_args()$0 }
623 CompletionItem { 781"#,
624 label: "main()",
625 source_range: 28..31,
626 delete: 28..31,
627 insert: "main()$0",
628 kind: Function,
629 lookup: "main",
630 detail: "fn main()",
631 },
632 CompletionItem {
633 label: "no_args()",
634 source_range: 28..31,
635 delete: 28..31,
636 insert: "no_args()$0",
637 kind: Function,
638 lookup: "no_args",
639 detail: "fn no_args()",
640 },
641 ]
642 "###
643 );
644 assert_debug_snapshot!(
645 do_reference_completion(
646 r"
647 fn with_args(x: i32, y: String) {}
648 fn main() { with_<|> }
649 "
650 ),
651 @r###"
652 [
653 CompletionItem {
654 label: "main()",
655 source_range: 47..52,
656 delete: 47..52,
657 insert: "main()$0",
658 kind: Function,
659 lookup: "main",
660 detail: "fn main()",
661 },
662 CompletionItem {
663 label: "with_args(…)",
664 source_range: 47..52,
665 delete: 47..52,
666 insert: "with_args(${1:x}, ${2:y})$0",
667 kind: Function,
668 lookup: "with_args",
669 detail: "fn with_args(x: i32, y: String)",
670 trigger_call_info: true,
671 },
672 ]
673 "###
674 ); 782 );
675 assert_debug_snapshot!( 783
676 do_reference_completion( 784 check_edit(
677 r" 785 "with_args",
678 fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String) {} 786 r#"
679 fn main() { with_<|> } 787fn with_args(x: i32, y: String) {}
680 " 788fn main() { with_<|> }
681 ), 789"#,
682 @r###" 790 r#"
683 [ 791fn with_args(x: i32, y: String) {}
684 CompletionItem { 792fn main() { with_args(${1:x}, ${2:y})$0 }
685 label: "main()", 793"#,
686 source_range: 77..82,
687 delete: 77..82,
688 insert: "main()$0",
689 kind: Function,
690 lookup: "main",
691 detail: "fn main()",
692 },
693 CompletionItem {
694 label: "with_ignored_args(…)",
695 source_range: 77..82,
696 delete: 77..82,
697 insert: "with_ignored_args(${1:foo}, ${2:bar}, ${3:ho_ge_})$0",
698 kind: Function,
699 lookup: "with_ignored_args",
700 detail: "fn with_ignored_args(_foo: i32, ___bar: bool, ho_ge_: String)",
701 trigger_call_info: true,
702 },
703 ]
704 "###
705 ); 794 );
706 assert_debug_snapshot!( 795
707 do_reference_completion( 796 check_edit(
708 r" 797 "foo",
709 struct S {} 798 r#"
710 impl S { 799struct S;
711 fn foo(&self) {} 800impl S {
712 } 801 fn foo(&self) {}
713 fn bar(s: &S) { 802}
714 s.f<|> 803fn bar(s: &S) { s.f<|> }
715 } 804"#,
716 " 805 r#"
717 ), 806struct S;
718 @r###" 807impl S {
719 [ 808 fn foo(&self) {}
720 CompletionItem { 809}
721 label: "foo()", 810fn bar(s: &S) { s.foo()$0 }
722 source_range: 66..67, 811"#,
723 delete: 66..67,
724 insert: "foo()$0",
725 kind: Method,
726 lookup: "foo",
727 detail: "fn foo(&self)",
728 },
729 ]
730 "###
731 ); 812 );
732 assert_debug_snapshot!( 813
733 do_reference_completion( 814 check_edit(
734 r" 815 "foo",
735 struct S {} 816 r#"
736 impl S { 817struct S {}
737 fn foo_ignored_args(&self, _a: bool, b: i32) {} 818impl S {
738 } 819 fn foo(&self, x: i32) {}
739 fn bar(s: &S) { 820}
740 s.f<|> 821fn bar(s: &S) {
741 } 822 s.f<|>
742 " 823}
743 ), 824"#,
744 @r###" 825 r#"
745 [ 826struct S {}
746 CompletionItem { 827impl S {
747 label: "foo_ignored_args(…)", 828 fn foo(&self, x: i32) {}
748 source_range: 97..98, 829}
749 delete: 97..98, 830fn bar(s: &S) {
750 insert: "foo_ignored_args(${1:a}, ${2:b})$0", 831 s.foo(${1:x})$0
751 kind: Method, 832}
752 lookup: "foo_ignored_args", 833"#,
753 detail: "fn foo_ignored_args(&self, _a: bool, b: i32)",
754 trigger_call_info: true,
755 },
756 ]
757 "###
758 ); 834 );
759 } 835 }
760 836
761 #[test] 837 #[test]
762 fn inserts_parens_for_tuple_enums() { 838 fn suppress_arg_snippets() {
763 assert_debug_snapshot!( 839 mark::check!(suppress_arg_snippets);
764 do_reference_completion( 840 check_edit_with_config(
765 r" 841 CompletionConfig { add_call_argument_snippets: false, ..CompletionConfig::default() },
766 enum Option<T> { Some(T), None } 842 "with_args",
767 use Option::*; 843 r#"
768 fn main() -> Option<i32> { 844fn with_args(x: i32, y: String) {}
769 Som<|> 845fn main() { with_<|> }
770 } 846"#,
771 " 847 r#"
772 ), 848fn with_args(x: i32, y: String) {}
773 @r###" 849fn main() { with_args($0) }
774 [ 850"#,
775 CompletionItem {
776 label: "None",
777 source_range: 79..82,
778 delete: 79..82,
779 insert: "None",
780 kind: EnumVariant,
781 detail: "()",
782 },
783 CompletionItem {
784 label: "Option",
785 source_range: 79..82,
786 delete: 79..82,
787 insert: "Option",
788 kind: Enum,
789 },
790 CompletionItem {
791 label: "Some(…)",
792 source_range: 79..82,
793 delete: 79..82,
794 insert: "Some($0)",
795 kind: EnumVariant,
796 lookup: "Some",
797 detail: "(T)",
798 trigger_call_info: true,
799 },
800 CompletionItem {
801 label: "main()",
802 source_range: 79..82,
803 delete: 79..82,
804 insert: "main()$0",
805 kind: Function,
806 lookup: "main",
807 detail: "fn main() -> Option<i32>",
808 },
809 ]
810 "###
811 );
812 assert_debug_snapshot!(
813 do_reference_completion(
814 r"
815 enum Option<T> { Some(T), None }
816 use Option::*;
817 fn main(value: Option<i32>) {
818 match value {
819 Som<|>
820 }
821 }
822 "
823 ),
824 @r###"
825 [
826 CompletionItem {
827 label: "None",
828 source_range: 104..107,
829 delete: 104..107,
830 insert: "None",
831 kind: EnumVariant,
832 detail: "()",
833 },
834 CompletionItem {
835 label: "Option",
836 source_range: 104..107,
837 delete: 104..107,
838 insert: "Option",
839 kind: Enum,
840 },
841 CompletionItem {
842 label: "Some(…)",
843 source_range: 104..107,
844 delete: 104..107,
845 insert: "Some($0)",
846 kind: EnumVariant,
847 lookup: "Some",
848 detail: "(T)",
849 trigger_call_info: true,
850 },
851 ]
852 "###
853 ); 851 );
854 } 852 }
855 853
856 #[test] 854 #[test]
857 fn no_call_parens_if_fn_ptr_needed() { 855 fn strips_underscores_from_args() {
858 assert_debug_snapshot!( 856 check_edit(
859 do_reference_completion( 857 "foo",
860 r" 858 r#"
861 fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8) {} 859fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
862 860fn main() { f<|> }
863 struct ManualVtable { 861"#,
864 method: fn(u8, u8, u8, u8, u8), 862 r#"
865 } 863fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
864fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
865"#,
866 );
867 }
866 868
867 fn main() -> ManualVtable { 869 #[test]
868 ManualVtable { 870 fn inserts_parens_for_tuple_enums() {
869 method: some<|> 871 mark::check!(inserts_parens_for_tuple_enums);
870 } 872 check_edit(
871 } 873 "Some",
872 " 874 r#"
873 ), 875enum Option<T> { Some(T), None }
874 @r###" 876use Option::*;
875 [ 877fn main() -> Option<i32> {
876 CompletionItem { 878 Som<|>
877 label: "ManualVtable", 879}
878 source_range: 182..186, 880"#,
879 delete: 182..186, 881 r#"
880 insert: "ManualVtable", 882enum Option<T> { Some(T), None }
881 kind: Struct, 883use Option::*;
882 }, 884fn main() -> Option<i32> {
883 CompletionItem { 885 Some($0)
884 label: "main", 886}
885 source_range: 182..186, 887"#,
886 delete: 182..186, 888 );
887 insert: "main", 889 check_edit(
888 kind: Function, 890 "Some",
889 detail: "fn main() -> ManualVtable", 891 r#"
890 }, 892enum Option<T> { Some(T), None }
891 CompletionItem { 893use Option::*;
892 label: "somefn", 894fn main(value: Option<i32>) {
893 source_range: 182..186, 895 match value {
894 delete: 182..186, 896 Som<|>
895 insert: "somefn", 897 }
896 kind: Function, 898}
897 detail: "fn somefn(with: u8, a: u8, lot: u8, of: u8, args: u8)", 899"#,
898 }, 900 r#"
899 ] 901enum Option<T> { Some(T), None }
900 "### 902use Option::*;
903fn main(value: Option<i32>) {
904 match value {
905 Some($0)
906 }
907}
908"#,
901 ); 909 );
902 } 910 }
903 911
904 #[test] 912 #[test]
905 fn arg_snippets_for_method_call() { 913 fn dont_duplicate_pattern_parens() {
906 assert_debug_snapshot!( 914 mark::check!(dont_duplicate_pattern_parens);
907 do_reference_completion( 915 check_edit(
908 r" 916 "Var",
909 struct S {} 917 r#"
910 impl S { 918enum E { Var(i32) }
911 fn foo(&self, x: i32) {} 919fn main() {
912 } 920 match E::Var(92) {
913 fn bar(s: &S) { 921 E::<|>(92) => (),
914 s.f<|> 922 }
915 } 923}
916 " 924"#,
917 ), 925 r#"
918 @r###" 926enum E { Var(i32) }
919 [ 927fn main() {
920 CompletionItem { 928 match E::Var(92) {
921 label: "foo(…)", 929 E::Var(92) => (),
922 source_range: 74..75, 930 }
923 delete: 74..75, 931}
924 insert: "foo(${1:x})$0", 932"#,
925 kind: Method, 933 );
926 lookup: "foo",
927 detail: "fn foo(&self, x: i32)",
928 trigger_call_info: true,
929 },
930 ]
931 "###
932 )
933 } 934 }
934 935
935 #[test] 936 #[test]
936 fn no_arg_snippets_for_method_call() { 937 fn no_call_parens_if_fn_ptr_needed() {
937 assert_debug_snapshot!( 938 mark::check!(no_call_parens_if_fn_ptr_needed);
938 do_reference_completion_with_options( 939 check_edit(
939 r" 940 "foo",
940 struct S {} 941 r#"
941 impl S { 942fn foo(foo: u8, bar: u8) {}
942 fn foo(&self, x: i32) {} 943struct ManualVtable { f: fn(u8, u8) }
943 } 944
944 fn bar(s: &S) { 945fn main() -> ManualVtable {
945 s.f<|> 946 ManualVtable { f: f<|> }
946 } 947}
947 ", 948"#,
948 CompletionConfig { 949 r#"
949 add_call_argument_snippets: false, 950fn foo(foo: u8, bar: u8) {}
950 .. Default::default() 951struct ManualVtable { f: fn(u8, u8) }
951 } 952
952 ), 953fn main() -> ManualVtable {
953 @r###" 954 ManualVtable { f: foo }
954 [ 955}
955 CompletionItem { 956"#,
956 label: "foo(…)", 957 );
957 source_range: 74..75,
958 delete: 74..75,
959 insert: "foo($0)",
960 kind: Method,
961 lookup: "foo",
962 detail: "fn foo(&self, x: i32)",
963 trigger_call_info: true,
964 },
965 ]
966 "###
967 )
968 } 958 }
969 959
970 #[test] 960 #[test]
971 fn dont_render_function_parens_in_use_item() { 961 fn no_parens_in_use_item() {
972 assert_debug_snapshot!( 962 mark::check!(no_parens_in_use_item);
973 do_reference_completion( 963 check_edit(
974 " 964 "foo",
975 //- /lib.rs 965 r#"
976 mod m { pub fn foo() {} } 966mod m { pub fn foo() {} }
977 use crate::m::f<|>; 967use crate::m::f<|>;
978 " 968"#,
979 ), 969 r#"
980 @r###" 970mod m { pub fn foo() {} }
981 [ 971use crate::m::foo;
982 CompletionItem { 972"#,
983 label: "foo",
984 source_range: 40..41,
985 delete: 40..41,
986 insert: "foo",
987 kind: Function,
988 detail: "pub fn foo()",
989 },
990 ]
991 "###
992 ); 973 );
993 } 974 }
994 975
995 #[test] 976 #[test]
996 fn dont_render_function_parens_if_already_call() { 977 fn no_parens_in_call() {
997 assert_debug_snapshot!( 978 check_edit(
998 do_reference_completion( 979 "foo",
999 " 980 r#"
1000 //- /lib.rs 981fn foo(x: i32) {}
1001 fn frobnicate() {} 982fn main() { f<|>(); }
1002 fn main() { 983"#,
1003 frob<|>(); 984 r#"
1004 } 985fn foo(x: i32) {}
1005 " 986fn main() { foo(); }
1006 ), 987"#,
1007 @r###"
1008 [
1009 CompletionItem {
1010 label: "frobnicate",
1011 source_range: 35..39,
1012 delete: 35..39,
1013 insert: "frobnicate",
1014 kind: Function,
1015 detail: "fn frobnicate()",
1016 },
1017 CompletionItem {
1018 label: "main",
1019 source_range: 35..39,
1020 delete: 35..39,
1021 insert: "main",
1022 kind: Function,
1023 detail: "fn main()",
1024 },
1025 ]
1026 "###
1027 ); 988 );
1028 assert_debug_snapshot!( 989 check_edit(
1029 do_reference_completion( 990 "foo",
1030 " 991 r#"
1031 //- /lib.rs 992struct Foo;
1032 struct Foo {} 993impl Foo { fn foo(&self){} }
1033 impl Foo { fn new() -> Foo {} } 994fn f(foo: &Foo) { foo.f<|>(); }
1034 fn main() { 995"#,
1035 Foo::ne<|>(); 996 r#"
1036 } 997struct Foo;
1037 " 998impl Foo { fn foo(&self){} }
1038 ), 999fn f(foo: &Foo) { foo.foo(); }
1039 @r###" 1000"#,
1040 [
1041 CompletionItem {
1042 label: "new",
1043 source_range: 67..69,
1044 delete: 67..69,
1045 insert: "new",
1046 kind: Function,
1047 detail: "fn new() -> Foo",
1048 },
1049 ]
1050 "###
1051 ); 1001 );
1052 } 1002 }
1053 1003
1054 #[test] 1004 #[test]
1055 fn inserts_angle_brackets_for_generics() { 1005 fn inserts_angle_brackets_for_generics() {
1056 mark::check!(inserts_angle_brackets_for_generics); 1006 mark::check!(inserts_angle_brackets_for_generics);
1057 assert_debug_snapshot!( 1007 check_edit(
1058 do_reference_completion( 1008 "Vec",
1059 r" 1009 r#"
1060 struct Vec<T> {} 1010struct Vec<T> {}
1061 fn foo(xs: Ve<|>) 1011fn foo(xs: Ve<|>)
1062 " 1012"#,
1063 ), 1013 r#"
1064 @r###" 1014struct Vec<T> {}
1065 [ 1015fn foo(xs: Vec<$0>)
1066 CompletionItem { 1016"#,
1067 label: "Vec<…>",
1068 source_range: 28..30,
1069 delete: 28..30,
1070 insert: "Vec<$0>",
1071 kind: Struct,
1072 lookup: "Vec",
1073 },
1074 CompletionItem {
1075 label: "foo(…)",
1076 source_range: 28..30,
1077 delete: 28..30,
1078 insert: "foo(${1:xs})$0",
1079 kind: Function,
1080 lookup: "foo",
1081 detail: "fn foo(xs: Ve)",
1082 trigger_call_info: true,
1083 },
1084 ]
1085 "###
1086 ); 1017 );
1087 assert_debug_snapshot!( 1018 check_edit(
1088 do_reference_completion( 1019 "Vec",
1089 r" 1020 r#"
1090 type Vec<T> = (T,); 1021type Vec<T> = (T,);
1091 fn foo(xs: Ve<|>) 1022fn foo(xs: Ve<|>)
1092 " 1023"#,
1093 ), 1024 r#"
1094 @r###" 1025type Vec<T> = (T,);
1095 [ 1026fn foo(xs: Vec<$0>)
1096 CompletionItem { 1027"#,
1097 label: "Vec<…>",
1098 source_range: 31..33,
1099 delete: 31..33,
1100 insert: "Vec<$0>",
1101 kind: TypeAlias,
1102 lookup: "Vec",
1103 },
1104 CompletionItem {
1105 label: "foo(…)",
1106 source_range: 31..33,
1107 delete: 31..33,
1108 insert: "foo(${1:xs})$0",
1109 kind: Function,
1110 lookup: "foo",
1111 detail: "fn foo(xs: Ve)",
1112 trigger_call_info: true,
1113 },
1114 ]
1115 "###
1116 ); 1028 );
1117 assert_debug_snapshot!( 1029 check_edit(
1118 do_reference_completion( 1030 "Vec",
1119 r" 1031 r#"
1120 struct Vec<T = i128> {} 1032struct Vec<T = i128> {}
1121 fn foo(xs: Ve<|>) 1033fn foo(xs: Ve<|>)
1122 " 1034"#,
1123 ), 1035 r#"
1124 @r###" 1036struct Vec<T = i128> {}
1125 [ 1037fn foo(xs: Vec)
1126 CompletionItem { 1038"#,
1127 label: "Vec",
1128 source_range: 35..37,
1129 delete: 35..37,
1130 insert: "Vec",
1131 kind: Struct,
1132 },
1133 CompletionItem {
1134 label: "foo(…)",
1135 source_range: 35..37,
1136 delete: 35..37,
1137 insert: "foo(${1:xs})$0",
1138 kind: Function,
1139 lookup: "foo",
1140 detail: "fn foo(xs: Ve)",
1141 trigger_call_info: true,
1142 },
1143 ]
1144 "###
1145 ); 1039 );
1146 assert_debug_snapshot!( 1040 check_edit(
1147 do_reference_completion( 1041 "Vec",
1148 r" 1042 r#"
1149 struct Vec<T> {} 1043struct Vec<T> {}
1150 fn foo(xs: Ve<|><i128>) 1044fn foo(xs: Ve<|><i128>)
1151 " 1045"#,
1152 ), 1046 r#"
1153 @r###" 1047struct Vec<T> {}
1154 [ 1048fn foo(xs: Vec<i128>)
1155 CompletionItem { 1049"#,
1156 label: "Vec",
1157 source_range: 28..30,
1158 delete: 28..30,
1159 insert: "Vec",
1160 kind: Struct,
1161 },
1162 CompletionItem {
1163 label: "foo(…)",
1164 source_range: 28..30,
1165 delete: 28..30,
1166 insert: "foo(${1:xs})$0",
1167 kind: Function,
1168 lookup: "foo",
1169 detail: "fn foo(xs: Ve<i128>)",
1170 trigger_call_info: true,
1171 },
1172 ]
1173 "###
1174 ); 1050 );
1175 } 1051 }
1176 1052
1177 #[test] 1053 #[test]
1178 fn dont_insert_macro_call_parens_unncessary() { 1054 fn dont_insert_macro_call_parens_unncessary() {
1179 mark::check!(dont_insert_macro_call_parens_unncessary); 1055 mark::check!(dont_insert_macro_call_parens_unncessary);
1180 assert_debug_snapshot!( 1056 check_edit(
1181 do_reference_completion( 1057 "frobnicate!",
1182 r" 1058 r#"
1183 //- /main.rs 1059//- /main.rs
1184 use foo::<|>; 1060use foo::<|>;
1185 1061//- /foo/lib.rs
1186 //- /foo/lib.rs 1062#[macro_export]
1187 #[macro_export] 1063macro_rules frobnicate { () => () }
1188 macro_rules frobnicate { 1064"#,
1189 () => () 1065 r#"
1190 } 1066use foo::frobnicate;
1191 " 1067"#,
1192 ),
1193 @r###"
1194 [
1195 CompletionItem {
1196 label: "frobnicate!",
1197 source_range: 9..9,
1198 delete: 9..9,
1199 insert: "frobnicate",
1200 kind: Macro,
1201 detail: "#[macro_export]\nmacro_rules! frobnicate",
1202 },
1203 ]
1204 "###
1205 ); 1068 );
1206 1069
1207 assert_debug_snapshot!( 1070 check_edit(
1208 do_reference_completion( 1071 "frobnicate!",
1209 r" 1072 r#"
1210 //- /main.rs 1073macro_rules frobnicate { () => () }
1211 macro_rules frobnicate { 1074fn main() { frob<|>!(); }
1212 () => () 1075"#,
1213 } 1076 r#"
1214 fn main() { 1077macro_rules frobnicate { () => () }
1215 frob<|>!(); 1078fn main() { frobnicate!(); }
1216 } 1079"#,
1217 "
1218 ),
1219 @r###"
1220 [
1221 CompletionItem {
1222 label: "frobnicate!",
1223 source_range: 56..60,
1224 delete: 56..60,
1225 insert: "frobnicate",
1226 kind: Macro,
1227 detail: "macro_rules! frobnicate",
1228 },
1229 CompletionItem {
1230 label: "main()",
1231 source_range: 56..60,
1232 delete: 56..60,
1233 insert: "main()$0",
1234 kind: Function,
1235 lookup: "main",
1236 detail: "fn main()",
1237 },
1238 ]
1239 "###
1240 ); 1080 );
1241 } 1081 }
1242 1082
1243 #[test] 1083 #[test]
1244 fn test_struct_field_completion_in_func_call() { 1084 fn active_param_score() {
1245 mark::check!(test_struct_field_completion_in_func_call); 1085 mark::check!(active_param_type_match);
1246 assert_debug_snapshot!( 1086 check_scores(
1247 do_reference_completion( 1087 r#"
1248 r" 1088struct S { foo: i64, bar: u32, baz: u32 }
1249 struct A { another_field: i64, the_field: u32, my_string: String } 1089fn test(bar: u32) { }
1250 fn test(my_param: u32) -> u32 { my_param } 1090fn foo(s: S) { test(s.<|>) }
1251 fn foo(a: A) { 1091"#,
1252 test(a.<|>) 1092 expect![[r#"
1253 } 1093 fd bar [type+name]
1254 ", 1094 fd baz [type]
1255 ), 1095 fd foo []
1256 @r###" 1096 "#]],
1257 [
1258 CompletionItem {
1259 label: "another_field",
1260 source_range: 136..136,
1261 delete: 136..136,
1262 insert: "another_field",
1263 kind: Field,
1264 detail: "i64",
1265 },
1266 CompletionItem {
1267 label: "my_string",
1268 source_range: 136..136,
1269 delete: 136..136,
1270 insert: "my_string",
1271 kind: Field,
1272 detail: "{unknown}",
1273 },
1274 CompletionItem {
1275 label: "the_field",
1276 source_range: 136..136,
1277 delete: 136..136,
1278 insert: "the_field",
1279 kind: Field,
1280 detail: "u32",
1281 score: TypeMatch,
1282 },
1283 ]
1284 "###
1285 ); 1097 );
1286 } 1098 }
1287 1099
1288 #[test] 1100 #[test]
1289 fn test_struct_field_completion_in_func_call_with_type_and_name() { 1101 fn record_field_scores() {
1290 assert_debug_snapshot!( 1102 mark::check!(record_field_type_match);
1291 do_reference_completion( 1103 check_scores(
1292 r" 1104 r#"
1293 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1105struct A { foo: i64, bar: u32, baz: u32 }
1294 fn test(the_field: u32) -> u32 { the_field } 1106struct B { x: (), y: f32, bar: u32 }
1295 fn foo(a: A) { 1107fn foo(a: A) { B { bar: a.<|> }; }
1296 test(a.<|>) 1108"#,
1297 } 1109 expect![[r#"
1298 ", 1110 fd bar [type+name]
1299 ), 1111 fd baz [type]
1300 @r###" 1112 fd foo []
1301 [ 1113 "#]],
1302 CompletionItem { 1114 )
1303 label: "another_field",
1304 source_range: 143..143,
1305 delete: 143..143,
1306 insert: "another_field",
1307 kind: Field,
1308 detail: "i64",
1309 },
1310 CompletionItem {
1311 label: "another_good_type",
1312 source_range: 143..143,
1313 delete: 143..143,
1314 insert: "another_good_type",
1315 kind: Field,
1316 detail: "u32",
1317 score: TypeMatch,
1318 },
1319 CompletionItem {
1320 label: "the_field",
1321 source_range: 143..143,
1322 delete: 143..143,
1323 insert: "the_field",
1324 kind: Field,
1325 detail: "u32",
1326 score: TypeAndNameMatch,
1327 },
1328 ]
1329 "###
1330 );
1331 } 1115 }
1332 1116
1333 #[test] 1117 #[test]
1334 fn test_struct_field_completion_in_record_lit() { 1118 fn record_field_and_call_scores() {
1335 mark::check!(test_struct_field_completion_in_record_lit); 1119 check_scores(
1336 assert_debug_snapshot!( 1120 r#"
1337 do_reference_completion( 1121struct A { foo: i64, bar: u32, baz: u32 }
1338 r" 1122struct B { x: (), y: f32, bar: u32 }
1339 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1123fn f(foo: i64) { }
1340 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1124fn foo(a: A) { B { bar: f(a.<|>) }; }
1341 fn foo(a: A) { 1125"#,
1342 let b = B { 1126 expect![[r#"
1343 the_field: a.<|> 1127 fd foo [type+name]
1344 }; 1128 fd bar []
1345 } 1129 fd baz []
1346 ", 1130 "#]],
1347 ), 1131 );
1348 @r###" 1132 check_scores(
1349 [ 1133 r#"
1350 CompletionItem { 1134struct A { foo: i64, bar: u32, baz: u32 }
1351 label: "another_field", 1135struct B { x: (), y: f32, bar: u32 }
1352 source_range: 189..189, 1136fn f(foo: i64) { }
1353 delete: 189..189, 1137fn foo(a: A) { f(B { bar: a.<|> }); }
1354 insert: "another_field", 1138"#,
1355 kind: Field, 1139 expect![[r#"
1356 detail: "i64", 1140 fd bar [type+name]
1357 }, 1141 fd baz [type]
1358 CompletionItem { 1142 fd foo []
1359 label: "another_good_type", 1143 "#]],
1360 source_range: 189..189,
1361 delete: 189..189,
1362 insert: "another_good_type",
1363 kind: Field,
1364 detail: "u32",
1365 score: TypeMatch,
1366 },
1367 CompletionItem {
1368 label: "the_field",
1369 source_range: 189..189,
1370 delete: 189..189,
1371 insert: "the_field",
1372 kind: Field,
1373 detail: "u32",
1374 score: TypeAndNameMatch,
1375 },
1376 ]
1377 "###
1378 ); 1144 );
1379 } 1145 }
1380 1146
1381 #[test] 1147 #[test]
1382 fn test_struct_field_completion_in_record_lit_and_fn_call() { 1148 fn prioritize_exact_ref_match() {
1383 assert_debug_snapshot!( 1149 check_scores(
1384 do_reference_completion( 1150 r#"
1385 r" 1151struct WorldSnapshot { _f: () };
1386 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1152fn go(world: &WorldSnapshot) { go(w<|>) }
1387 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1153"#,
1388 fn test(the_field: i64) -> i64 { the_field } 1154 expect![[r#"
1389 fn foo(a: A) { 1155 bn world [type+name]
1390 let b = B { 1156 st WorldSnapshot []
1391 the_field: test(a.<|>) 1157 fn go(…) []
1392 }; 1158 "#]],
1393 }
1394 ",
1395 ),
1396 @r###"
1397 [
1398 CompletionItem {
1399 label: "another_field",
1400 source_range: 239..239,
1401 delete: 239..239,
1402 insert: "another_field",
1403 kind: Field,
1404 detail: "i64",
1405 score: TypeMatch,
1406 },
1407 CompletionItem {
1408 label: "another_good_type",
1409 source_range: 239..239,
1410 delete: 239..239,
1411 insert: "another_good_type",
1412 kind: Field,
1413 detail: "u32",
1414 },
1415 CompletionItem {
1416 label: "the_field",
1417 source_range: 239..239,
1418 delete: 239..239,
1419 insert: "the_field",
1420 kind: Field,
1421 detail: "u32",
1422 },
1423 ]
1424 "###
1425 ); 1159 );
1426 } 1160 }
1427 1161
1428 #[test] 1162 #[test]
1429 fn test_struct_field_completion_in_fn_call_and_record_lit() { 1163 fn too_many_arguments() {
1430 assert_debug_snapshot!( 1164 mark::check!(too_many_arguments);
1431 do_reference_completion( 1165 check_scores(
1432 r" 1166 r#"
1433 struct A { another_field: i64, another_good_type: u32, the_field: u32 } 1167struct Foo;
1434 struct B { my_string: String, my_vec: Vec<u32>, the_field: u32 } 1168fn f(foo: &Foo) { f(foo, w<|>) }
1435 fn test(the_field: i64) -> i64 { the_field } 1169"#,
1436 fn foo(a: A) { 1170 expect![[r#"
1437 test(B { 1171 st Foo []
1438 the_field: a.<|> 1172 fn f(…) []
1439 }); 1173 bn foo []
1440 } 1174 "#]],
1441 ",
1442 ),
1443 @r###"
1444 [
1445 CompletionItem {
1446 label: "another_field",
1447 source_range: 231..231,
1448 delete: 231..231,
1449 insert: "another_field",
1450 kind: Field,
1451 detail: "i64",
1452 },
1453 CompletionItem {
1454 label: "another_good_type",
1455 source_range: 231..231,
1456 delete: 231..231,
1457 insert: "another_good_type",
1458 kind: Field,
1459 detail: "u32",
1460 score: TypeMatch,
1461 },
1462 CompletionItem {
1463 label: "the_field",
1464 source_range: 231..231,
1465 delete: 231..231,
1466 insert: "the_field",
1467 kind: Field,
1468 detail: "u32",
1469 score: TypeAndNameMatch,
1470 },
1471 ]
1472 "###
1473 ); 1175 );
1474 } 1176 }
1475 1177
1476 #[test] 1178 #[test]
1477 fn prioritize_exact_ref_match() { 1179 fn guesses_macro_braces() {
1478 assert_debug_snapshot!( 1180 check_edit(
1479 do_reference_completion( 1181 "vec!",
1480 r" 1182 r#"
1481 struct WorldSnapshot { _f: () }; 1183/// Creates a [`Vec`] containing the arguments.
1482 fn go(world: &WorldSnapshot) { 1184///
1483 go(w<|>) 1185/// ```
1484 } 1186/// let v = vec![1, 2, 3];
1485 ", 1187/// assert_eq!(v[0], 1);
1486 ), 1188/// assert_eq!(v[1], 2);
1487 @r###" 1189/// assert_eq!(v[2], 3);
1488 [ 1190/// ```
1489 CompletionItem { 1191macro_rules! vec { () => {} }
1490 label: "WorldSnapshot", 1192
1491 source_range: 71..72, 1193fn fn main() { v<|> }
1492 delete: 71..72, 1194"#,
1493 insert: "WorldSnapshot", 1195 r#"
1494 kind: Struct, 1196/// Creates a [`Vec`] containing the arguments.
1495 }, 1197///
1496 CompletionItem { 1198/// ```
1497 label: "go(…)", 1199/// let v = vec![1, 2, 3];
1498 source_range: 71..72, 1200/// assert_eq!(v[0], 1);
1499 delete: 71..72, 1201/// assert_eq!(v[1], 2);
1500 insert: "go(${1:world})$0", 1202/// assert_eq!(v[2], 3);
1501 kind: Function, 1203/// ```
1502 lookup: "go", 1204macro_rules! vec { () => {} }
1503 detail: "fn go(world: &WorldSnapshot)", 1205
1504 trigger_call_info: true, 1206fn fn main() { vec![$0] }
1505 }, 1207"#,
1506 CompletionItem {
1507 label: "world",
1508 source_range: 71..72,
1509 delete: 71..72,
1510 insert: "world",
1511 kind: Binding,
1512 detail: "&WorldSnapshot",
1513 score: TypeAndNameMatch,
1514 },
1515 ]
1516 "###
1517 ); 1208 );
1209
1210 check_edit(
1211 "foo!",
1212 r#"
1213/// Foo
1214///
1215/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1216/// call as `let _=foo! { hello world };`
1217macro_rules! foo { () => {} }
1218fn main() { <|> }
1219"#,
1220 r#"
1221/// Foo
1222///
1223/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
1224/// call as `let _=foo! { hello world };`
1225macro_rules! foo { () => {} }
1226fn main() { foo! {$0} }
1227"#,
1228 )
1518 } 1229 }
1519} 1230}
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 5c01654cc..919177745 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -1,7 +1,10 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics; 3use hir::Semantics;
4use itertools::Itertools;
4use ra_syntax::{AstNode, NodeOrToken, SyntaxElement}; 5use ra_syntax::{AstNode, NodeOrToken, SyntaxElement};
6use stdx::{format_to, trim_indent};
7use test_utils::assert_eq_text;
5 8
6use crate::{ 9use crate::{
7 completion::{completion_item::CompletionKind, CompletionConfig}, 10 completion::{completion_item::CompletionKind, CompletionConfig},
@@ -10,15 +13,15 @@ use crate::{
10}; 13};
11 14
12pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 15pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
13 do_completion_with_options(code, kind, &CompletionConfig::default()) 16 do_completion_with_config(CompletionConfig::default(), code, kind)
14} 17}
15 18
16pub(crate) fn do_completion_with_options( 19pub(crate) fn do_completion_with_config(
20 config: CompletionConfig,
17 code: &str, 21 code: &str,
18 kind: CompletionKind, 22 kind: CompletionKind,
19 options: &CompletionConfig,
20) -> Vec<CompletionItem> { 23) -> Vec<CompletionItem> {
21 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, options) 24 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
22 .into_iter() 25 .into_iter()
23 .filter(|c| c.completion_kind == kind) 26 .filter(|c| c.completion_kind == kind)
24 .collect(); 27 .collect();
@@ -27,25 +30,69 @@ pub(crate) fn do_completion_with_options(
27} 30}
28 31
29pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { 32pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String {
30 completion_list_with_options(code, kind, &CompletionConfig::default()) 33 completion_list_with_config(CompletionConfig::default(), code, kind)
31} 34}
32 35
33pub(crate) fn completion_list_with_options( 36pub(crate) fn completion_list_with_config(
37 config: CompletionConfig,
34 code: &str, 38 code: &str,
35 kind: CompletionKind, 39 kind: CompletionKind,
36 options: &CompletionConfig,
37) -> String { 40) -> String {
38 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(code, options) 41 let mut kind_completions: Vec<CompletionItem> = get_all_completion_items(config, code)
39 .into_iter() 42 .into_iter()
40 .filter(|c| c.completion_kind == kind) 43 .filter(|c| c.completion_kind == kind)
41 .collect(); 44 .collect();
42 kind_completions.sort_by_key(|c| c.label().to_owned()); 45 kind_completions.sort_by_key(|c| c.label().to_owned());
46 let label_width = kind_completions
47 .iter()
48 .map(|it| monospace_width(it.label()))
49 .max()
50 .unwrap_or_default()
51 .min(16);
43 kind_completions 52 kind_completions
44 .into_iter() 53 .into_iter()
45 .map(|it| format!("{} {}\n", it.kind().unwrap().tag(), it.label())) 54 .map(|it| {
55 let tag = it.kind().unwrap().tag();
56 let var_name = format!("{} {}", tag, it.label());
57 let mut buf = var_name;
58 if let Some(detail) = it.detail() {
59 let width = label_width.saturating_sub(monospace_width(it.label()));
60 format_to!(buf, "{:width$} {}", "", detail, width = width);
61 }
62 format_to!(buf, "\n");
63 buf
64 })
46 .collect() 65 .collect()
47} 66}
48 67
68fn monospace_width(s: &str) -> usize {
69 s.chars().count()
70}
71
72pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
73 check_edit_with_config(CompletionConfig::default(), what, ra_fixture_before, ra_fixture_after)
74}
75
76pub(crate) fn check_edit_with_config(
77 config: CompletionConfig,
78 what: &str,
79 ra_fixture_before: &str,
80 ra_fixture_after: &str,
81) {
82 let ra_fixture_after = trim_indent(ra_fixture_after);
83 let (analysis, position) = analysis_and_position(ra_fixture_before);
84 let completions: Vec<CompletionItem> =
85 analysis.completions(&config, position).unwrap().unwrap().into();
86 let (completion,) = completions
87 .iter()
88 .filter(|it| it.lookup() == what)
89 .collect_tuple()
90 .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
91 let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
92 completion.text_edit().apply(&mut actual);
93 assert_eq_text!(&ra_fixture_after, &actual)
94}
95
49pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) { 96pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
50 let (analysis, pos) = analysis_and_position(code); 97 let (analysis, pos) = analysis_and_position(code);
51 analysis 98 analysis
@@ -58,7 +105,10 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -
58 .unwrap(); 105 .unwrap();
59} 106}
60 107
61fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec<CompletionItem> { 108pub(crate) fn get_all_completion_items(
109 config: CompletionConfig,
110 code: &str,
111) -> Vec<CompletionItem> {
62 let (analysis, position) = analysis_and_position(code); 112 let (analysis, position) = analysis_and_position(code);
63 analysis.completions(options, position).unwrap().unwrap().into() 113 analysis.completions(&config, position).unwrap().unwrap().into()
64} 114}
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 05fb799d6..dd8a7ffd9 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -7,7 +7,7 @@
7use std::cell::RefCell; 7use std::cell::RefCell;
8 8
9use hir::{ 9use hir::{
10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}, 10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder},
11 HasSource, HirDisplay, Semantics, VariantDef, 11 HasSource, HirDisplay, Semantics, VariantDef,
12}; 12};
13use itertools::Itertools; 13use itertools::Itertools;
@@ -29,13 +29,18 @@ pub enum Severity {
29 WeakWarning, 29 WeakWarning,
30} 30}
31 31
32pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> { 32pub(crate) fn diagnostics(
33 db: &RootDatabase,
34 file_id: FileId,
35 enable_experimental: bool,
36) -> Vec<Diagnostic> {
33 let _p = profile("diagnostics"); 37 let _p = profile("diagnostics");
34 let sema = Semantics::new(db); 38 let sema = Semantics::new(db);
35 let parse = db.parse(file_id); 39 let parse = db.parse(file_id);
36 let mut res = Vec::new(); 40 let mut res = Vec::new();
37 41
38 res.extend(parse.errors().iter().map(|err| Diagnostic { 42 // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
43 res.extend(parse.errors().iter().take(128).map(|err| Diagnostic {
39 range: err.range(), 44 range: err.range(),
40 message: format!("Syntax Error: {}", err), 45 message: format!("Syntax Error: {}", err),
41 severity: Severity::Error, 46 severity: Severity::Error,
@@ -47,87 +52,85 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
47 check_struct_shorthand_initialization(&mut res, file_id, &node); 52 check_struct_shorthand_initialization(&mut res, file_id, &node);
48 } 53 }
49 let res = RefCell::new(res); 54 let res = RefCell::new(res);
50 let mut sink = DiagnosticSink::new(|d| { 55 let mut sink = DiagnosticSinkBuilder::new()
51 res.borrow_mut().push(Diagnostic { 56 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
52 message: d.message(), 57 let original_file = d.source().file_id.original_file(db);
53 range: sema.diagnostics_range(d).range, 58 let fix = Fix::new(
54 severity: Severity::Error, 59 "Create module",
55 fix: None, 60 FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }
56 }) 61 .into(),
57 }) 62 );
58 .on::<hir::diagnostics::UnresolvedModule, _>(|d| { 63 res.borrow_mut().push(Diagnostic {
59 let original_file = d.source().file_id.original_file(db); 64 range: sema.diagnostics_range(d).range,
60 let fix = Fix::new( 65 message: d.message(),
61 "Create module", 66 severity: Severity::Error,
62 FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }.into(), 67 fix: Some(fix),
63 ); 68 })
64 res.borrow_mut().push(Diagnostic {
65 range: sema.diagnostics_range(d).range,
66 message: d.message(),
67 severity: Severity::Error,
68 fix: Some(fix),
69 }) 69 })
70 }) 70 .on::<hir::diagnostics::MissingFields, _>(|d| {
71 .on::<hir::diagnostics::MissingFields, _>(|d| { 71 // Note that although we could add a diagnostics to
72 // Note that although we could add a diagnostics to 72 // fill the missing tuple field, e.g :
73 // fill the missing tuple field, e.g : 73 // `struct A(usize);`
74 // `struct A(usize);` 74 // `let a = A { 0: () }`
75 // `let a = A { 0: () }` 75 // but it is uncommon usage and it should not be encouraged.
76 // but it is uncommon usage and it should not be encouraged. 76 let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
77 let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { 77 None
78 None 78 } else {
79 } else { 79 let mut field_list = d.ast(db);
80 let mut field_list = d.ast(db); 80 for f in d.missed_fields.iter() {
81 for f in d.missed_fields.iter() { 81 let field =
82 let field = 82 make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
83 make::record_field(make::name_ref(&f.to_string()), Some(make::expr_unit())); 83 field_list = field_list.append_field(&field);
84 field_list = field_list.append_field(&field); 84 }
85 }
86 85
87 let edit = { 86 let edit = {
88 let mut builder = TextEditBuilder::default(); 87 let mut builder = TextEditBuilder::default();
89 algo::diff(&d.ast(db).syntax(), &field_list.syntax()).into_text_edit(&mut builder); 88 algo::diff(&d.ast(db).syntax(), &field_list.syntax())
90 builder.finish() 89 .into_text_edit(&mut builder);
90 builder.finish()
91 };
92 Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
91 }; 93 };
92 Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into()))
93 };
94 94
95 res.borrow_mut().push(Diagnostic { 95 res.borrow_mut().push(Diagnostic {
96 range: sema.diagnostics_range(d).range, 96 range: sema.diagnostics_range(d).range,
97 message: d.message(), 97 message: d.message(),
98 severity: Severity::Error, 98 severity: Severity::Error,
99 fix, 99 fix,
100 }) 100 })
101 })
102 .on::<hir::diagnostics::MissingMatchArms, _>(|d| {
103 res.borrow_mut().push(Diagnostic {
104 range: sema.diagnostics_range(d).range,
105 message: d.message(),
106 severity: Severity::Error,
107 fix: None,
108 }) 101 })
109 }) 102 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
110 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { 103 let node = d.ast(db);
111 let node = d.ast(db); 104 let replacement = format!("Ok({})", node.syntax());
112 let replacement = format!("Ok({})", node.syntax()); 105 let edit = TextEdit::replace(node.syntax().text_range(), replacement);
113 let edit = TextEdit::replace(node.syntax().text_range(), replacement); 106 let source_change = SourceFileEdit { file_id, edit }.into();
114 let source_change = SourceFileEdit { file_id, edit }.into(); 107 let fix = Fix::new("Wrap with ok", source_change);
115 let fix = Fix::new("Wrap with ok", source_change); 108 res.borrow_mut().push(Diagnostic {
116 res.borrow_mut().push(Diagnostic { 109 range: sema.diagnostics_range(d).range,
117 range: sema.diagnostics_range(d).range, 110 message: d.message(),
118 message: d.message(), 111 severity: Severity::Error,
119 severity: Severity::Error, 112 fix: Some(fix),
120 fix: Some(fix), 113 })
121 }) 114 })
122 }) 115 .on::<hir::diagnostics::NoSuchField, _>(|d| {
123 .on::<hir::diagnostics::NoSuchField, _>(|d| { 116 res.borrow_mut().push(Diagnostic {
124 res.borrow_mut().push(Diagnostic { 117 range: sema.diagnostics_range(d).range,
125 range: sema.diagnostics_range(d).range, 118 message: d.message(),
126 message: d.message(), 119 severity: Severity::Error,
127 severity: Severity::Error, 120 fix: missing_struct_field_fix(&sema, file_id, d),
128 fix: missing_struct_field_fix(&sema, file_id, d), 121 })
129 }) 122 })
130 }); 123 // Only collect experimental diagnostics when they're enabled.
124 .filter(|diag| !diag.is_experimental() || enable_experimental)
125 // Diagnostics not handled above get no fix and default treatment.
126 .build(|d| {
127 res.borrow_mut().push(Diagnostic {
128 message: d.message(),
129 range: sema.diagnostics_range(d).range,
130 severity: Severity::Error,
131 fix: None,
132 })
133 });
131 134
132 if let Some(m) = sema.to_module_def(file_id) { 135 if let Some(m) = sema.to_module_def(file_id) {
133 m.diagnostics(db, &mut sink); 136 m.diagnostics(db, &mut sink);
@@ -138,33 +141,38 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
138 141
139fn missing_struct_field_fix( 142fn missing_struct_field_fix(
140 sema: &Semantics<RootDatabase>, 143 sema: &Semantics<RootDatabase>,
141 file_id: FileId, 144 usage_file_id: FileId,
142 d: &hir::diagnostics::NoSuchField, 145 d: &hir::diagnostics::NoSuchField,
143) -> Option<Fix> { 146) -> Option<Fix> {
144 let record_expr = sema.ast(d); 147 let record_expr = sema.ast(d);
145 148
146 let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?; 149 let record_lit = ast::RecordExpr::cast(record_expr.syntax().parent()?.parent()?)?;
147 let def_id = sema.resolve_variant(record_lit)?; 150 let def_id = sema.resolve_variant(record_lit)?;
148 let module; 151 let module;
152 let def_file_id;
149 let record_fields = match VariantDef::from(def_id) { 153 let record_fields = match VariantDef::from(def_id) {
150 VariantDef::Struct(s) => { 154 VariantDef::Struct(s) => {
151 module = s.module(sema.db); 155 module = s.module(sema.db);
152 let source = s.source(sema.db); 156 let source = s.source(sema.db);
153 let fields = source.value.field_def_list()?; 157 def_file_id = source.file_id;
154 record_field_def_list(fields)? 158 let fields = source.value.field_list()?;
159 record_field_list(fields)?
155 } 160 }
156 VariantDef::Union(u) => { 161 VariantDef::Union(u) => {
157 module = u.module(sema.db); 162 module = u.module(sema.db);
158 let source = u.source(sema.db); 163 let source = u.source(sema.db);
159 source.value.record_field_def_list()? 164 def_file_id = source.file_id;
165 source.value.record_field_list()?
160 } 166 }
161 VariantDef::EnumVariant(e) => { 167 VariantDef::EnumVariant(e) => {
162 module = e.module(sema.db); 168 module = e.module(sema.db);
163 let source = e.source(sema.db); 169 let source = e.source(sema.db);
164 let fields = source.value.field_def_list()?; 170 def_file_id = source.file_id;
165 record_field_def_list(fields)? 171 let fields = source.value.field_list()?;
172 record_field_list(fields)?
166 } 173 }
167 }; 174 };
175 let def_file_id = def_file_id.original_file(sema.db);
168 176
169 let new_field_type = sema.type_of_expr(&record_expr.expr()?)?; 177 let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
170 if new_field_type.is_unknown() { 178 if new_field_type.is_unknown() {
@@ -179,24 +187,28 @@ fn missing_struct_field_fix(
179 let last_field_syntax = last_field.syntax(); 187 let last_field_syntax = last_field.syntax();
180 let indent = IndentLevel::from_node(last_field_syntax); 188 let indent = IndentLevel::from_node(last_field_syntax);
181 189
182 let mut new_field = format!("\n{}{}", indent, new_field); 190 let mut new_field = new_field.to_string();
191 if usage_file_id != def_file_id {
192 new_field = format!("pub(crate) {}", new_field);
193 }
194 new_field = format!("\n{}{}", indent, new_field);
183 195
184 let needs_comma = !last_field_syntax.to_string().ends_with(","); 196 let needs_comma = !last_field_syntax.to_string().ends_with(',');
185 if needs_comma { 197 if needs_comma {
186 new_field = format!(",{}", new_field); 198 new_field = format!(",{}", new_field);
187 } 199 }
188 200
189 let source_change = SourceFileEdit { 201 let source_change = SourceFileEdit {
190 file_id, 202 file_id: def_file_id,
191 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), 203 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
192 }; 204 };
193 let fix = Fix::new("Create field", source_change.into()); 205 let fix = Fix::new("Create field", source_change.into());
194 return Some(fix); 206 return Some(fix);
195 207
196 fn record_field_def_list(field_def_list: ast::FieldDefList) -> Option<ast::RecordFieldDefList> { 208 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
197 match field_def_list { 209 match field_def_list {
198 ast::FieldDefList::RecordFieldDefList(it) => Some(it), 210 ast::FieldList::RecordFieldList(it) => Some(it),
199 ast::FieldDefList::TupleFieldDefList(_) => None, 211 ast::FieldList::TupleFieldList(_) => None,
200 } 212 }
201 } 213 }
202} 214}
@@ -251,8 +263,8 @@ fn check_struct_shorthand_initialization(
251 file_id: FileId, 263 file_id: FileId,
252 node: &SyntaxNode, 264 node: &SyntaxNode,
253) -> Option<()> { 265) -> Option<()> {
254 let record_lit = ast::RecordLit::cast(node.clone())?; 266 let record_lit = ast::RecordExpr::cast(node.clone())?;
255 let record_field_list = record_lit.record_field_list()?; 267 let record_field_list = record_lit.record_expr_field_list()?;
256 for record_field in record_field_list.fields() { 268 for record_field in record_field_list.fields() {
257 if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { 269 if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) {
258 let field_name = name_ref.syntax().text().to_string(); 270 let field_name = name_ref.syntax().text().to_string();
@@ -281,54 +293,22 @@ fn check_struct_shorthand_initialization(
281 293
282#[cfg(test)] 294#[cfg(test)]
283mod tests { 295mod tests {
284 use insta::assert_debug_snapshot;
285 use ra_syntax::SourceFile;
286 use stdx::trim_indent; 296 use stdx::trim_indent;
287 use test_utils::assert_eq_text; 297 use test_utils::assert_eq_text;
288 298
289 use crate::mock_analysis::{analysis_and_position, single_file}; 299 use crate::mock_analysis::{analysis_and_position, single_file, MockAnalysis};
290 300 use expect::{expect, Expect};
291 use super::*;
292
293 type DiagnosticChecker = fn(&mut Vec<Diagnostic>, FileId, &SyntaxNode) -> Option<()>;
294
295 fn check_not_applicable(code: &str, func: DiagnosticChecker) {
296 let parse = SourceFile::parse(code);
297 let mut diagnostics = Vec::new();
298 for node in parse.tree().syntax().descendants() {
299 func(&mut diagnostics, FileId(0), &node);
300 }
301 assert!(diagnostics.is_empty());
302 }
303
304 fn check_apply(before: &str, after: &str, func: DiagnosticChecker) {
305 let parse = SourceFile::parse(before);
306 let mut diagnostics = Vec::new();
307 for node in parse.tree().syntax().descendants() {
308 func(&mut diagnostics, FileId(0), &node);
309 }
310 let diagnostic =
311 diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
312 let mut fix = diagnostic.fix.unwrap();
313 let edit = fix.source_change.source_file_edits.pop().unwrap().edit;
314 let actual = {
315 let mut actual = before.to_string();
316 edit.apply(&mut actual);
317 actual
318 };
319 assert_eq_text!(after, &actual);
320 }
321 301
322 /// Takes a multi-file input fixture with annotated cursor positions, 302 /// Takes a multi-file input fixture with annotated cursor positions,
323 /// and checks that: 303 /// and checks that:
324 /// * a diagnostic is produced 304 /// * a diagnostic is produced
325 /// * this diagnostic touches the input cursor position 305 /// * this diagnostic touches the input cursor position
326 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied 306 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
327 fn check_apply_diagnostic_fix_from_position(fixture: &str, after: &str) { 307 fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
328 let after = trim_indent(after); 308 let after = trim_indent(ra_fixture_after);
329 309
330 let (analysis, file_position) = analysis_and_position(fixture); 310 let (analysis, file_position) = analysis_and_position(ra_fixture_before);
331 let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); 311 let diagnostic = analysis.diagnostics(file_position.file_id, true).unwrap().pop().unwrap();
332 let mut fix = diagnostic.fix.unwrap(); 312 let mut fix = diagnostic.fix.unwrap();
333 let edit = fix.source_change.source_file_edits.pop().unwrap().edit; 313 let edit = fix.source_change.source_file_edits.pop().unwrap().edit;
334 let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); 314 let target_file_contents = analysis.file_text(file_position.file_id).unwrap();
@@ -348,16 +328,20 @@ mod tests {
348 ); 328 );
349 } 329 }
350 330
351 fn check_apply_diagnostic_fix(ra_fixture_before: &str, ra_fixture_after: &str) { 331 /// Checks that a diagnostic applies to the file containing the `<|>` cursor marker
332 /// which has a fix that can apply to other files.
333 fn check_apply_diagnostic_fix_in_other_file(ra_fixture_before: &str, ra_fixture_after: &str) {
352 let ra_fixture_after = &trim_indent(ra_fixture_after); 334 let ra_fixture_after = &trim_indent(ra_fixture_after);
353 let (analysis, file_id) = single_file(ra_fixture_before); 335 let (analysis, file_pos) = analysis_and_position(ra_fixture_before);
354 let before = analysis.file_text(file_id).unwrap(); 336 let current_file_id = file_pos.file_id;
355 let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); 337 let diagnostic = analysis.diagnostics(current_file_id, true).unwrap().pop().unwrap();
356 let mut fix = diagnostic.fix.unwrap(); 338 let mut fix = diagnostic.fix.unwrap();
357 let edit = fix.source_change.source_file_edits.pop().unwrap().edit; 339 let edit = fix.source_change.source_file_edits.pop().unwrap();
340 let changed_file_id = edit.file_id;
341 let before = analysis.file_text(changed_file_id).unwrap();
358 let actual = { 342 let actual = {
359 let mut actual = before.to_string(); 343 let mut actual = before.to_string();
360 edit.apply(&mut actual); 344 edit.edit.apply(&mut actual);
361 actual 345 actual
362 }; 346 };
363 assert_eq_text!(ra_fixture_after, &actual); 347 assert_eq_text!(ra_fixture_after, &actual);
@@ -365,498 +349,411 @@ mod tests {
365 349
366 /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics 350 /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
367 /// apply to the file containing the cursor. 351 /// apply to the file containing the cursor.
368 fn check_no_diagnostic_for_target_file(fixture: &str) { 352 fn check_no_diagnostics(ra_fixture: &str) {
369 let (analysis, file_position) = analysis_and_position(fixture); 353 let mock = MockAnalysis::with_files(ra_fixture);
370 let diagnostics = analysis.diagnostics(file_position.file_id).unwrap(); 354 let files = mock.files().map(|(it, _)| it).collect::<Vec<_>>();
371 assert_eq!(diagnostics.len(), 0); 355 let analysis = mock.analysis();
356 let diagnostics = files
357 .into_iter()
358 .flat_map(|file_id| analysis.diagnostics(file_id, true).unwrap())
359 .collect::<Vec<_>>();
360 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
372 } 361 }
373 362
374 fn check_no_diagnostic(content: &str) { 363 fn check_expect(ra_fixture: &str, expect: Expect) {
375 let (analysis, file_id) = single_file(content); 364 let (analysis, file_id) = single_file(ra_fixture);
376 let diagnostics = analysis.diagnostics(file_id).unwrap(); 365 let diagnostics = analysis.diagnostics(file_id, true).unwrap();
377 assert_eq!(diagnostics.len(), 0, "expected no diagnostic, found one"); 366 expect.assert_debug_eq(&diagnostics)
378 } 367 }
379 368
380 #[test] 369 #[test]
381 fn test_wrap_return_type() { 370 fn test_wrap_return_type() {
382 let before = r#" 371 check_fix(
383 //- /main.rs 372 r#"
384 use core::result::Result::{self, Ok, Err}; 373//- /main.rs
374use core::result::Result::{self, Ok, Err};
385 375
386 fn div(x: i32, y: i32) -> Result<i32, ()> { 376fn div(x: i32, y: i32) -> Result<i32, ()> {
387 if y == 0 { 377 if y == 0 {
388 return Err(()); 378 return Err(());
389 } 379 }
390 x / y<|> 380 x / y<|>
391 } 381}
392 //- /core/lib.rs 382//- /core/lib.rs
393 pub mod result { 383pub mod result {
394 pub enum Result<T, E> { Ok(T), Err(E) } 384 pub enum Result<T, E> { Ok(T), Err(E) }
395 } 385}
396 "#; 386"#,
397 let after = r#" 387 r#"
398 use core::result::Result::{self, Ok, Err}; 388use core::result::Result::{self, Ok, Err};
399 389
400 fn div(x: i32, y: i32) -> Result<i32, ()> { 390fn div(x: i32, y: i32) -> Result<i32, ()> {
401 if y == 0 { 391 if y == 0 {
402 return Err(()); 392 return Err(());
403 } 393 }
404 Ok(x / y) 394 Ok(x / y)
405 } 395}
406 "#; 396"#,
407 check_apply_diagnostic_fix_from_position(before, after); 397 );
408 } 398 }
409 399
410 #[test] 400 #[test]
411 fn test_wrap_return_type_handles_generic_functions() { 401 fn test_wrap_return_type_handles_generic_functions() {
412 let before = r#" 402 check_fix(
413 //- /main.rs 403 r#"
414 use core::result::Result::{self, Ok, Err}; 404//- /main.rs
405use core::result::Result::{self, Ok, Err};
415 406
416 fn div<T>(x: T) -> Result<T, i32> { 407fn div<T>(x: T) -> Result<T, i32> {
417 if x == 0 { 408 if x == 0 {
418 return Err(7); 409 return Err(7);
419 } 410 }
420 <|>x 411 <|>x
421 } 412}
422 //- /core/lib.rs 413//- /core/lib.rs
423 pub mod result { 414pub mod result {
424 pub enum Result<T, E> { Ok(T), Err(E) } 415 pub enum Result<T, E> { Ok(T), Err(E) }
425 } 416}
426 "#; 417"#,
427 let after = r#" 418 r#"
428 use core::result::Result::{self, Ok, Err}; 419use core::result::Result::{self, Ok, Err};
429 420
430 fn div<T>(x: T) -> Result<T, i32> { 421fn div<T>(x: T) -> Result<T, i32> {
431 if x == 0 { 422 if x == 0 {
432 return Err(7); 423 return Err(7);
433 } 424 }
434 Ok(x) 425 Ok(x)
435 } 426}
436 "#; 427"#,
437 check_apply_diagnostic_fix_from_position(before, after); 428 );
438 } 429 }
439 430
440 #[test] 431 #[test]
441 fn test_wrap_return_type_handles_type_aliases() { 432 fn test_wrap_return_type_handles_type_aliases() {
442 let before = r#" 433 check_fix(
443 //- /main.rs 434 r#"
444 use core::result::Result::{self, Ok, Err}; 435//- /main.rs
436use core::result::Result::{self, Ok, Err};
445 437
446 type MyResult<T> = Result<T, ()>; 438type MyResult<T> = Result<T, ()>;
447 439
448 fn div(x: i32, y: i32) -> MyResult<i32> { 440fn div(x: i32, y: i32) -> MyResult<i32> {
449 if y == 0 { 441 if y == 0 {
450 return Err(()); 442 return Err(());
451 } 443 }
452 x <|>/ y 444 x <|>/ y
453 } 445}
454 //- /core/lib.rs 446//- /core/lib.rs
455 pub mod result { 447pub mod result {
456 pub enum Result<T, E> { Ok(T), Err(E) } 448 pub enum Result<T, E> { Ok(T), Err(E) }
457 } 449}
458 "#; 450"#,
459 let after = r#" 451 r#"
460 use core::result::Result::{self, Ok, Err}; 452use core::result::Result::{self, Ok, Err};
461 453
462 type MyResult<T> = Result<T, ()>; 454type MyResult<T> = Result<T, ()>;
463 455
464 fn div(x: i32, y: i32) -> MyResult<i32> { 456fn div(x: i32, y: i32) -> MyResult<i32> {
465 if y == 0 { 457 if y == 0 {
466 return Err(()); 458 return Err(());
467 } 459 }
468 Ok(x / y) 460 Ok(x / y)
469 } 461}
470 "#; 462"#,
471 check_apply_diagnostic_fix_from_position(before, after); 463 );
472 } 464 }
473 465
474 #[test] 466 #[test]
475 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { 467 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
476 let content = r#" 468 check_no_diagnostics(
477 //- /main.rs 469 r#"
478 use core::result::Result::{self, Ok, Err}; 470//- /main.rs
471use core::result::Result::{self, Ok, Err};
479 472
480 fn foo() -> Result<(), i32> { 473fn foo() -> Result<(), i32> { 0 }
481 0<|>
482 }
483 474
484 //- /core/lib.rs 475//- /core/lib.rs
485 pub mod result { 476pub mod result {
486 pub enum Result<T, E> { Ok(T), Err(E) } 477 pub enum Result<T, E> { Ok(T), Err(E) }
487 } 478}
488 "#; 479"#,
489 check_no_diagnostic_for_target_file(content); 480 );
490 } 481 }
491 482
492 #[test] 483 #[test]
493 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { 484 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
494 let content = r#" 485 check_no_diagnostics(
495 //- /main.rs 486 r#"
496 use core::result::Result::{self, Ok, Err}; 487//- /main.rs
488use core::result::Result::{self, Ok, Err};
497 489
498 enum SomeOtherEnum { 490enum SomeOtherEnum { Ok(i32), Err(String) }
499 Ok(i32),
500 Err(String),
501 }
502 491
503 fn foo() -> SomeOtherEnum { 492fn foo() -> SomeOtherEnum { 0 }
504 0<|>
505 }
506 493
507 //- /core/lib.rs 494//- /core/lib.rs
508 pub mod result { 495pub mod result {
509 pub enum Result<T, E> { Ok(T), Err(E) } 496 pub enum Result<T, E> { Ok(T), Err(E) }
510 } 497}
511 "#; 498"#,
512 check_no_diagnostic_for_target_file(content); 499 );
513 } 500 }
514 501
515 #[test] 502 #[test]
516 fn test_fill_struct_fields_empty() { 503 fn test_fill_struct_fields_empty() {
517 let before = r" 504 check_fix(
518 struct TestStruct { 505 r#"
519 one: i32, 506struct TestStruct { one: i32, two: i64 }
520 two: i64,
521 }
522 507
523 fn test_fn() { 508fn test_fn() {
524 let s = TestStruct{}; 509 let s = TestStruct {<|>};
525 } 510}
526 "; 511"#,
527 let after = r" 512 r#"
528 struct TestStruct { 513struct TestStruct { one: i32, two: i64 }
529 one: i32,
530 two: i64,
531 }
532 514
533 fn test_fn() { 515fn test_fn() {
534 let s = TestStruct{ one: (), two: ()}; 516 let s = TestStruct { one: (), two: ()};
535 } 517}
536 "; 518"#,
537 check_apply_diagnostic_fix(before, after); 519 );
538 } 520 }
539 521
540 #[test] 522 #[test]
541 fn test_fill_struct_fields_self() { 523 fn test_fill_struct_fields_self() {
542 let before = r" 524 check_fix(
543 struct TestStruct { 525 r#"
544 one: i32, 526struct TestStruct { one: i32 }
545 }
546 527
547 impl TestStruct { 528impl TestStruct {
548 fn test_fn() { 529 fn test_fn() { let s = Self {<|>}; }
549 let s = Self {}; 530}
550 } 531"#,
551 } 532 r#"
552 "; 533struct TestStruct { one: i32 }
553 let after = r"
554 struct TestStruct {
555 one: i32,
556 }
557 534
558 impl TestStruct { 535impl TestStruct {
559 fn test_fn() { 536 fn test_fn() { let s = Self { one: ()}; }
560 let s = Self { one: ()}; 537}
561 } 538"#,
562 } 539 );
563 ";
564 check_apply_diagnostic_fix(before, after);
565 } 540 }
566 541
567 #[test] 542 #[test]
568 fn test_fill_struct_fields_enum() { 543 fn test_fill_struct_fields_enum() {
569 let before = r" 544 check_fix(
570 enum Expr { 545 r#"
571 Bin { lhs: Box<Expr>, rhs: Box<Expr> } 546enum Expr {
572 } 547 Bin { lhs: Box<Expr>, rhs: Box<Expr> }
548}
573 549
574 impl Expr { 550impl Expr {
575 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { 551 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
576 Expr::Bin { } 552 Expr::Bin {<|> }
577 } 553 }
578 } 554}
579 "; 555"#,
580 let after = r" 556 r#"
581 enum Expr { 557enum Expr {
582 Bin { lhs: Box<Expr>, rhs: Box<Expr> } 558 Bin { lhs: Box<Expr>, rhs: Box<Expr> }
583 } 559}
584 560
585 impl Expr { 561impl Expr {
586 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr { 562 fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
587 Expr::Bin { lhs: (), rhs: () } 563 Expr::Bin { lhs: (), rhs: () }
588 } 564 }
589 } 565}
590 "; 566"#,
591 check_apply_diagnostic_fix(before, after); 567 );
592 } 568 }
593 569
594 #[test] 570 #[test]
595 fn test_fill_struct_fields_partial() { 571 fn test_fill_struct_fields_partial() {
596 let before = r" 572 check_fix(
597 struct TestStruct { 573 r#"
598 one: i32, 574struct TestStruct { one: i32, two: i64 }
599 two: i64,
600 }
601 575
602 fn test_fn() { 576fn test_fn() {
603 let s = TestStruct{ two: 2 }; 577 let s = TestStruct{ two: 2<|> };
604 } 578}
605 "; 579"#,
606 let after = r" 580 r"
607 struct TestStruct { 581struct TestStruct { one: i32, two: i64 }
608 one: i32,
609 two: i64,
610 }
611 582
612 fn test_fn() { 583fn test_fn() {
613 let s = TestStruct{ two: 2, one: () }; 584 let s = TestStruct{ two: 2, one: () };
614 } 585}
615 "; 586",
616 check_apply_diagnostic_fix(before, after); 587 );
617 } 588 }
618 589
619 #[test] 590 #[test]
620 fn test_fill_struct_fields_no_diagnostic() { 591 fn test_fill_struct_fields_no_diagnostic() {
621 let content = r" 592 check_no_diagnostics(
622 struct TestStruct { 593 r"
623 one: i32, 594 struct TestStruct { one: i32, two: i64 }
624 two: i64,
625 }
626 595
627 fn test_fn() { 596 fn test_fn() {
628 let one = 1; 597 let one = 1;
629 let s = TestStruct{ one, two: 2 }; 598 let s = TestStruct{ one, two: 2 };
630 } 599 }
631 "; 600 ",
632 601 );
633 check_no_diagnostic(content);
634 } 602 }
635 603
636 #[test] 604 #[test]
637 fn test_fill_struct_fields_no_diagnostic_on_spread() { 605 fn test_fill_struct_fields_no_diagnostic_on_spread() {
638 let content = r" 606 check_no_diagnostics(
639 struct TestStruct { 607 r"
640 one: i32, 608 struct TestStruct { one: i32, two: i64 }
641 two: i64,
642 }
643 609
644 fn test_fn() { 610 fn test_fn() {
645 let one = 1; 611 let one = 1;
646 let s = TestStruct{ ..a }; 612 let s = TestStruct{ ..a };
647 } 613 }
648 "; 614 ",
649 615 );
650 check_no_diagnostic(content);
651 } 616 }
652 617
653 #[test] 618 #[test]
654 fn test_unresolved_module_diagnostic() { 619 fn test_unresolved_module_diagnostic() {
655 let (analysis, file_id) = single_file("mod foo;"); 620 check_expect(
656 let diagnostics = analysis.diagnostics(file_id).unwrap(); 621 r#"mod foo;"#,
657 assert_debug_snapshot!(diagnostics, @r###" 622 expect![[r#"
658 [ 623 [
659 Diagnostic { 624 Diagnostic {
660 message: "unresolved module", 625 message: "unresolved module",
661 range: 0..8, 626 range: 0..8,
662 severity: Error, 627 severity: Error,
663 fix: Some( 628 fix: Some(
664 Fix { 629 Fix {
665 label: "Create module", 630 label: "Create module",
666 source_change: SourceChange { 631 source_change: SourceChange {
667 source_file_edits: [], 632 source_file_edits: [],
668 file_system_edits: [ 633 file_system_edits: [
669 CreateFile { 634 CreateFile {
670 anchor: FileId( 635 anchor: FileId(
671 1, 636 1,
672 ), 637 ),
673 dst: "foo.rs", 638 dst: "foo.rs",
639 },
640 ],
641 is_snippet: false,
674 }, 642 },
675 ], 643 },
676 is_snippet: false, 644 ),
677 },
678 }, 645 },
679 ), 646 ]
680 }, 647 "#]],
681 ] 648 );
682 "###);
683 } 649 }
684 650
685 #[test] 651 #[test]
686 fn range_mapping_out_of_macros() { 652 fn range_mapping_out_of_macros() {
687 let (analysis, file_id) = single_file( 653 // FIXME: this is very wrong, but somewhat tricky to fix.
688 r" 654 check_fix(
689 fn some() {} 655 r#"
690 fn items() {} 656fn some() {}
691 fn here() {} 657fn items() {}
658fn here() {}
692 659
693 macro_rules! id { 660macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
694 ($($tt:tt)*) => { $($tt)*};
695 }
696 661
697 fn main() { 662fn main() {
698 let _x = id![Foo { a: 42 }]; 663 let _x = id![Foo { a: <|>42 }];
699 } 664}
700 665
701 pub struct Foo { 666pub struct Foo { pub a: i32, pub b: i32 }
702 pub a: i32, 667"#,
703 pub b: i32, 668 r#"
704 } 669fn {a:42, b: ()} {}
705 ", 670fn items() {}
671fn here() {}
672
673macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
674
675fn main() {
676 let _x = id![Foo { a: 42 }];
677}
678
679pub struct Foo { pub a: i32, pub b: i32 }
680"#,
706 ); 681 );
707 let diagnostics = analysis.diagnostics(file_id).unwrap();
708 assert_debug_snapshot!(diagnostics, @r###"
709 [
710 Diagnostic {
711 message: "Missing structure fields:\n- b\n",
712 range: 127..136,
713 severity: Error,
714 fix: Some(
715 Fix {
716 label: "Fill struct fields",
717 source_change: SourceChange {
718 source_file_edits: [
719 SourceFileEdit {
720 file_id: FileId(
721 1,
722 ),
723 edit: TextEdit {
724 indels: [
725 Indel {
726 insert: "{a:42, b: ()}",
727 delete: 3..9,
728 },
729 ],
730 },
731 },
732 ],
733 file_system_edits: [],
734 is_snippet: false,
735 },
736 },
737 ),
738 },
739 ]
740 "###);
741 } 682 }
742 683
743 #[test] 684 #[test]
744 fn test_check_unnecessary_braces_in_use_statement() { 685 fn test_check_unnecessary_braces_in_use_statement() {
745 check_not_applicable( 686 check_no_diagnostics(
746 " 687 r#"
747 use a; 688use a;
748 use a::{c, d::e}; 689use a::{c, d::e};
749 ", 690"#,
750 check_unnecessary_braces_in_use_statement,
751 );
752 check_apply("use {b};", "use b;", check_unnecessary_braces_in_use_statement);
753 check_apply("use a::{c};", "use a::c;", check_unnecessary_braces_in_use_statement);
754 check_apply("use a::{self};", "use a;", check_unnecessary_braces_in_use_statement);
755 check_apply(
756 "use a::{c, d::{e}};",
757 "use a::{c, d::e};",
758 check_unnecessary_braces_in_use_statement,
759 ); 691 );
692 check_fix(r#"use {<|>b};"#, r#"use b;"#);
693 check_fix(r#"use {b<|>};"#, r#"use b;"#);
694 check_fix(r#"use a::{c<|>};"#, r#"use a::c;"#);
695 check_fix(r#"use a::{self<|>};"#, r#"use a;"#);
696 check_fix(r#"use a::{c, d::{e<|>}};"#, r#"use a::{c, d::e};"#);
760 } 697 }
761 698
762 #[test] 699 #[test]
763 fn test_check_struct_shorthand_initialization() { 700 fn test_check_struct_shorthand_initialization() {
764 check_not_applicable( 701 check_no_diagnostics(
765 r#" 702 r#"
766 struct A { 703struct A { a: &'static str }
767 a: &'static str 704fn main() { A { a: "hello" } }
768 } 705"#,
769
770 fn main() {
771 A {
772 a: "hello"
773 }
774 }
775 "#,
776 check_struct_shorthand_initialization,
777 ); 706 );
778 check_not_applicable( 707 check_no_diagnostics(
779 r#" 708 r#"
780 struct A(usize); 709struct A(usize);
781 710fn main() { A { 0: 0 } }
782 fn main() { 711"#,
783 A {
784 0: 0
785 }
786 }
787 "#,
788 check_struct_shorthand_initialization,
789 ); 712 );
790 713
791 check_apply( 714 check_fix(
792 r#" 715 r#"
793struct A { 716struct A { a: &'static str }
794 a: &'static str
795}
796
797fn main() { 717fn main() {
798 let a = "haha"; 718 let a = "haha";
799 A { 719 A { a<|>: a }
800 a: a
801 }
802} 720}
803 "#, 721"#,
804 r#" 722 r#"
805struct A { 723struct A { a: &'static str }
806 a: &'static str
807}
808
809fn main() { 724fn main() {
810 let a = "haha"; 725 let a = "haha";
811 A { 726 A { a }
812 a
813 }
814} 727}
815 "#, 728"#,
816 check_struct_shorthand_initialization,
817 ); 729 );
818 730
819 check_apply( 731 check_fix(
820 r#" 732 r#"
821struct A { 733struct A { a: &'static str, b: &'static str }
822 a: &'static str,
823 b: &'static str
824}
825
826fn main() { 734fn main() {
827 let a = "haha"; 735 let a = "haha";
828 let b = "bb"; 736 let b = "bb";
829 A { 737 A { a<|>: a, b }
830 a: a,
831 b
832 }
833} 738}
834 "#, 739"#,
835 r#" 740 r#"
836struct A { 741struct A { a: &'static str, b: &'static str }
837 a: &'static str,
838 b: &'static str
839}
840
841fn main() { 742fn main() {
842 let a = "haha"; 743 let a = "haha";
843 let b = "bb"; 744 let b = "bb";
844 A { 745 A { a, b }
845 a,
846 b
847 }
848} 746}
849 "#, 747"#,
850 check_struct_shorthand_initialization,
851 ); 748 );
852 } 749 }
853 750
854 #[test] 751 #[test]
855 fn test_add_field_from_usage() { 752 fn test_add_field_from_usage() {
856 check_apply_diagnostic_fix( 753 check_fix(
857 r" 754 r"
858fn main() { 755fn main() {
859 Foo { bar: 3, baz: false}; 756 Foo { bar: 3, baz<|>: false};
860} 757}
861struct Foo { 758struct Foo {
862 bar: i32 759 bar: i32
@@ -873,4 +770,28 @@ struct Foo {
873", 770",
874 ) 771 )
875 } 772 }
773
774 #[test]
775 fn test_add_field_in_other_file_from_usage() {
776 check_apply_diagnostic_fix_in_other_file(
777 r"
778 //- /main.rs
779 mod foo;
780
781 fn main() {
782 <|>foo::Foo { bar: 3, baz: false};
783 }
784 //- /foo.rs
785 struct Foo {
786 bar: i32
787 }
788 ",
789 r"
790 struct Foo {
791 bar: i32,
792 pub(crate) baz: bool
793 }
794 ",
795 )
796 }
876} 797}
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 827c094e7..fd42aa435 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -1,31 +1,60 @@
1//! This module contains utilities for turning SyntaxNodes and HIR types 1//! This module contains utilities for turning SyntaxNodes and HIR types
2//! into types that may be used to render in a UI. 2//! into types that may be used to render in a UI.
3 3
4mod function_signature;
5mod navigation_target; 4mod navigation_target;
6mod structure;
7mod short_label; 5mod short_label;
8 6
9use std::fmt::Display;
10
11use ra_syntax::{ 7use ra_syntax::{
12 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, 8 ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
13 SyntaxKind::{ATTR, COMMENT}, 9 SyntaxKind::{ATTR, COMMENT},
14}; 10};
11
12use ast::VisibilityOwner;
15use stdx::format_to; 13use stdx::format_to;
16 14
17pub use function_signature::FunctionSignature;
18pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
19pub use structure::{file_structure, StructureNode};
20
21pub(crate) use navigation_target::{ToNav, TryToNav}; 16pub(crate) use navigation_target::{ToNav, TryToNav};
22pub(crate) use short_label::ShortLabel; 17pub(crate) use short_label::ShortLabel;
23 18
24pub(crate) fn function_label(node: &ast::FnDef) -> String { 19pub(crate) fn function_declaration(node: &ast::Fn) -> String {
25 FunctionSignature::from(node).to_string() 20 let mut buf = String::new();
21 if let Some(vis) = node.visibility() {
22 format_to!(buf, "{} ", vis);
23 }
24 if node.async_token().is_some() {
25 format_to!(buf, "async ");
26 }
27 if node.const_token().is_some() {
28 format_to!(buf, "const ");
29 }
30 if node.unsafe_token().is_some() {
31 format_to!(buf, "unsafe ");
32 }
33 if let Some(abi) = node.abi() {
34 // Keyword `extern` is included in the string.
35 format_to!(buf, "{} ", abi);
36 }
37 if let Some(name) = node.name() {
38 format_to!(buf, "fn {}", name)
39 }
40 if let Some(type_params) = node.generic_param_list() {
41 format_to!(buf, "{}", type_params);
42 }
43 if let Some(param_list) = node.param_list() {
44 format_to!(buf, "{}", param_list);
45 }
46 if let Some(ret_type) = node.ret_type() {
47 if ret_type.ty().is_some() {
48 format_to!(buf, " {}", ret_type);
49 }
50 }
51 if let Some(where_clause) = node.where_clause() {
52 format_to!(buf, "\n{}", where_clause);
53 }
54 buf
26} 55}
27 56
28pub(crate) fn const_label(node: &ast::ConstDef) -> String { 57pub(crate) fn const_label(node: &ast::Const) -> String {
29 let label: String = node 58 let label: String = node
30 .syntax() 59 .syntax()
31 .children_with_tokens() 60 .children_with_tokens()
@@ -36,7 +65,7 @@ pub(crate) fn const_label(node: &ast::ConstDef) -> String {
36 label.trim().to_owned() 65 label.trim().to_owned()
37} 66}
38 67
39pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { 68pub(crate) fn type_label(node: &ast::TypeAlias) -> String {
40 let label: String = node 69 let label: String = node
41 .syntax() 70 .syntax()
42 .children_with_tokens() 71 .children_with_tokens()
@@ -47,51 +76,8 @@ pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String {
47 label.trim().to_owned() 76 label.trim().to_owned()
48} 77}
49 78
50pub(crate) fn generic_parameters<N: TypeParamsOwner>(node: &N) -> Vec<String> {
51 let mut res = vec![];
52 if let Some(type_params) = node.type_param_list() {
53 res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string()));
54 res.extend(type_params.type_params().map(|p| p.syntax().text().to_string()));
55 }
56 res
57}
58
59pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> {
60 let mut res = vec![];
61 if let Some(clause) = node.where_clause() {
62 res.extend(clause.predicates().map(|p| p.syntax().text().to_string()));
63 }
64 res
65}
66
67pub(crate) fn macro_label(node: &ast::MacroCall) -> String { 79pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
68 let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); 80 let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
69 let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; 81 let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
70 format!("{}macro_rules! {}", vis, name) 82 format!("{}macro_rules! {}", vis, name)
71} 83}
72
73pub(crate) fn rust_code_markup(code: &impl Display) -> String {
74 rust_code_markup_with_doc(code, None, None)
75}
76
77pub(crate) fn rust_code_markup_with_doc(
78 code: &impl Display,
79 doc: Option<&str>,
80 mod_path: Option<&str>,
81) -> String {
82 let mut buf = String::new();
83
84 if let Some(mod_path) = mod_path {
85 if !mod_path.is_empty() {
86 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
87 }
88 }
89 format_to!(buf, "```rust\n{}\n```", code);
90
91 if let Some(doc) = doc {
92 format_to!(buf, "\n___");
93 format_to!(buf, "\n\n{}", doc);
94 }
95
96 buf
97}
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
deleted file mode 100644
index a98264fb3..000000000
--- a/crates/ra_ide/src/display/function_signature.rs
+++ /dev/null
@@ -1,334 +0,0 @@
1//! FIXME: write short doc here
2
3// FIXME: this modules relies on strings and AST way too much, and it should be
4// rewritten (matklad 2020-05-07)
5use std::{
6 convert::From,
7 fmt::{self, Display},
8};
9
10use hir::{Docs, Documentation, HasSource, HirDisplay};
11use ra_ide_db::RootDatabase;
12use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
13use stdx::{split_delim, SepBy};
14
15use crate::display::{generic_parameters, where_predicates};
16
17#[derive(Debug)]
18pub enum CallableKind {
19 Function,
20 StructConstructor,
21 VariantConstructor,
22 Macro,
23}
24
25/// Contains information about a function signature
26#[derive(Debug)]
27pub struct FunctionSignature {
28 pub kind: CallableKind,
29 /// Optional visibility
30 pub visibility: Option<String>,
31 /// Qualifiers like `async`, `unsafe`, ...
32 pub qualifier: FunctionQualifier,
33 /// Name of the function
34 pub name: Option<String>,
35 /// Documentation for the function
36 pub doc: Option<Documentation>,
37 /// Generic parameters
38 pub generic_parameters: Vec<String>,
39 /// Parameters of the function
40 pub parameters: Vec<String>,
41 /// Parameter names of the function
42 pub parameter_names: Vec<String>,
43 /// Parameter types of the function
44 pub parameter_types: Vec<String>,
45 /// Optional return type
46 pub ret_type: Option<String>,
47 /// Where predicates
48 pub where_predicates: Vec<String>,
49 /// Self param presence
50 pub has_self_param: bool,
51}
52
53#[derive(Debug, Default)]
54pub struct FunctionQualifier {
55 // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
56 pub is_async: bool,
57 pub is_const: bool,
58 pub is_unsafe: bool,
59 /// The string `extern ".."`
60 pub extern_abi: Option<String>,
61}
62
63impl FunctionSignature {
64 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
65 self.doc = doc;
66 self
67 }
68
69 pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self {
70 let doc = function.docs(db);
71 let ast_node = function.source(db).value;
72 FunctionSignature::from(&ast_node).with_doc_opt(doc)
73 }
74
75 pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> {
76 let node: ast::StructDef = st.source(db).value;
77 if let ast::StructKind::Record(_) = node.kind() {
78 return None;
79 };
80
81 let mut params = vec![];
82 let mut parameter_types = vec![];
83 for field in st.fields(db).into_iter() {
84 let ty = field.signature_ty(db);
85 let raw_param = format!("{}", ty.display(db));
86
87 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
88 parameter_types.push(param_type.to_string());
89 } else {
90 // useful when you have tuple struct
91 parameter_types.push(raw_param.clone());
92 }
93 params.push(raw_param);
94 }
95
96 Some(
97 FunctionSignature {
98 kind: CallableKind::StructConstructor,
99 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
100 // Do we need `const`?
101 qualifier: Default::default(),
102 name: node.name().map(|n| n.text().to_string()),
103 ret_type: node.name().map(|n| n.text().to_string()),
104 parameters: params,
105 parameter_names: vec![],
106 parameter_types,
107 generic_parameters: generic_parameters(&node),
108 where_predicates: where_predicates(&node),
109 doc: None,
110 has_self_param: false,
111 }
112 .with_doc_opt(st.docs(db)),
113 )
114 }
115
116 pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> {
117 let node: ast::EnumVariant = variant.source(db).value;
118 match node.kind() {
119 ast::StructKind::Record(_) | ast::StructKind::Unit => return None,
120 _ => (),
121 };
122
123 let parent_name = variant.parent_enum(db).name(db).to_string();
124
125 let name = format!("{}::{}", parent_name, variant.name(db));
126
127 let mut params = vec![];
128 let mut parameter_types = vec![];
129 for field in variant.fields(db).into_iter() {
130 let ty = field.signature_ty(db);
131 let raw_param = format!("{}", ty.display(db));
132 if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) {
133 parameter_types.push(param_type.to_string());
134 } else {
135 // The unwrap_or_else is useful when you have tuple
136 parameter_types.push(raw_param);
137 }
138 let name = field.name(db);
139
140 params.push(format!("{}: {}", name, ty.display(db)));
141 }
142
143 Some(
144 FunctionSignature {
145 kind: CallableKind::VariantConstructor,
146 visibility: None,
147 // Do we need `const`?
148 qualifier: Default::default(),
149 name: Some(name),
150 ret_type: None,
151 parameters: params,
152 parameter_names: vec![],
153 parameter_types,
154 generic_parameters: vec![],
155 where_predicates: vec![],
156 doc: None,
157 has_self_param: false,
158 }
159 .with_doc_opt(variant.docs(db)),
160 )
161 }
162
163 pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
164 let node: ast::MacroCall = macro_def.source(db).value;
165
166 let params = vec![];
167
168 Some(
169 FunctionSignature {
170 kind: CallableKind::Macro,
171 visibility: None,
172 qualifier: Default::default(),
173 name: node.name().map(|n| n.text().to_string()),
174 ret_type: None,
175 parameters: params,
176 parameter_names: vec![],
177 parameter_types: vec![],
178 generic_parameters: vec![],
179 where_predicates: vec![],
180 doc: None,
181 has_self_param: false,
182 }
183 .with_doc_opt(macro_def.docs(db)),
184 )
185 }
186}
187
188impl From<&'_ ast::FnDef> for FunctionSignature {
189 fn from(node: &ast::FnDef) -> FunctionSignature {
190 fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) {
191 let mut res = vec![];
192 let mut res_types = vec![];
193 let mut has_self_param = false;
194 if let Some(param_list) = node.param_list() {
195 if let Some(self_param) = param_list.self_param() {
196 has_self_param = true;
197 let raw_param = self_param.syntax().text().to_string();
198
199 res_types.push(
200 raw_param
201 .split(':')
202 .nth(1)
203 .and_then(|it| it.get(1..))
204 .unwrap_or_else(|| "Self")
205 .to_string(),
206 );
207 res.push(raw_param);
208 }
209
210 // macro-generated functions are missing whitespace
211 fn fmt_param(param: ast::Param) -> String {
212 let text = param.syntax().text().to_string();
213 match split_delim(&text, ':') {
214 Some((left, right)) => format!("{}: {}", left.trim(), right.trim()),
215 _ => text,
216 }
217 }
218
219 res.extend(param_list.params().map(fmt_param));
220 res_types.extend(param_list.params().map(|param| {
221 let param_text = param.syntax().text().to_string();
222 match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
223 Some(it) => it.to_string(),
224 None => param_text,
225 }
226 }));
227 }
228 (has_self_param, res, res_types)
229 }
230
231 fn param_name_list(node: &ast::FnDef) -> Vec<String> {
232 let mut res = vec![];
233 if let Some(param_list) = node.param_list() {
234 if let Some(self_param) = param_list.self_param() {
235 res.push(self_param.syntax().text().to_string())
236 }
237
238 res.extend(
239 param_list
240 .params()
241 .map(|param| {
242 Some(
243 param
244 .pat()?
245 .syntax()
246 .descendants()
247 .find_map(ast::Name::cast)?
248 .text()
249 .to_string(),
250 )
251 })
252 .map(|param| param.unwrap_or_default()),
253 );
254 }
255 res
256 }
257
258 let (has_self_param, parameters, parameter_types) = param_list(node);
259
260 FunctionSignature {
261 kind: CallableKind::Function,
262 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
263 qualifier: FunctionQualifier {
264 is_async: node.async_token().is_some(),
265 is_const: node.const_token().is_some(),
266 is_unsafe: node.unsafe_token().is_some(),
267 extern_abi: node.abi().map(|n| n.to_string()),
268 },
269 name: node.name().map(|n| n.text().to_string()),
270 ret_type: node
271 .ret_type()
272 .and_then(|r| r.type_ref())
273 .map(|n| n.syntax().text().to_string()),
274 parameters,
275 parameter_names: param_name_list(node),
276 parameter_types,
277 generic_parameters: generic_parameters(node),
278 where_predicates: where_predicates(node),
279 // docs are processed separately
280 doc: None,
281 has_self_param,
282 }
283 }
284}
285
286impl Display for FunctionSignature {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 if let Some(t) = &self.visibility {
289 write!(f, "{} ", t)?;
290 }
291
292 if self.qualifier.is_async {
293 write!(f, "async ")?;
294 }
295
296 if self.qualifier.is_const {
297 write!(f, "const ")?;
298 }
299
300 if self.qualifier.is_unsafe {
301 write!(f, "unsafe ")?;
302 }
303
304 if let Some(extern_abi) = &self.qualifier.extern_abi {
305 // Keyword `extern` is included in the string.
306 write!(f, "{} ", extern_abi)?;
307 }
308
309 if let Some(name) = &self.name {
310 match self.kind {
311 CallableKind::Function => write!(f, "fn {}", name)?,
312 CallableKind::StructConstructor => write!(f, "struct {}", name)?,
313 CallableKind::VariantConstructor => write!(f, "{}", name)?,
314 CallableKind::Macro => write!(f, "{}!", name)?,
315 }
316 }
317
318 if !self.generic_parameters.is_empty() {
319 write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?;
320 }
321
322 write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?;
323
324 if let Some(t) = &self.ret_type {
325 write!(f, " -> {}", t)?;
326 }
327
328 if !self.where_predicates.is_empty() {
329 write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?;
330 }
331
332 Ok(())
333 }
334}
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 0b52b01ab..45fbc86ef 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 TextRange, 11 TextRange,
12}; 12};
13 13
14use crate::{FileRange, FileSymbol}; 14use crate::FileSymbol;
15 15
16use super::short_label::ShortLabel; 16use super::short_label::ShortLabel;
17 17
@@ -22,15 +22,28 @@ use super::short_label::ShortLabel;
22/// code, like a function or a struct, but this is not strictly required. 22/// code, like a function or a struct, but this is not strictly required.
23#[derive(Debug, Clone, PartialEq, Eq, Hash)] 23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct NavigationTarget { 24pub struct NavigationTarget {
25 // FIXME: use FileRange? 25 pub file_id: FileId,
26 file_id: FileId, 26 /// Range which encompasses the whole element.
27 full_range: TextRange, 27 ///
28 name: SmolStr, 28 /// Should include body, doc comments, attributes, etc.
29 kind: SyntaxKind, 29 ///
30 focus_range: Option<TextRange>, 30 /// Clients should use this range to answer "is the cursor inside the
31 container_name: Option<SmolStr>, 31 /// element?" question.
32 description: Option<String>, 32 pub full_range: TextRange,
33 docs: Option<String>, 33 /// A "most interesting" range withing the `full_range`.
34 ///
35 /// Typically, `full_range` is the whole syntax node, including doc
36 /// comments, and `focus_range` is the range of the identifier. "Most
37 /// interesting" range within the full range, typically the range of
38 /// identifier.
39 ///
40 /// Clients should place the cursor on this range when navigating to this target.
41 pub focus_range: Option<TextRange>,
42 pub name: SmolStr,
43 pub kind: SyntaxKind,
44 pub container_name: Option<SmolStr>,
45 pub description: Option<String>,
46 pub docs: Option<String>,
34} 47}
35 48
36pub(crate) trait ToNav { 49pub(crate) trait ToNav {
@@ -42,52 +55,10 @@ pub(crate) trait TryToNav {
42} 55}
43 56
44impl NavigationTarget { 57impl NavigationTarget {
45 /// When `focus_range` is specified, returns it. otherwise 58 pub fn focus_or_full_range(&self) -> TextRange {
46 /// returns `full_range`
47 pub fn range(&self) -> TextRange {
48 self.focus_range.unwrap_or(self.full_range) 59 self.focus_range.unwrap_or(self.full_range)
49 } 60 }
50 61
51 pub fn name(&self) -> &SmolStr {
52 &self.name
53 }
54
55 pub fn container_name(&self) -> Option<&SmolStr> {
56 self.container_name.as_ref()
57 }
58
59 pub fn kind(&self) -> SyntaxKind {
60 self.kind
61 }
62
63 pub fn file_id(&self) -> FileId {
64 self.file_id
65 }
66
67 pub fn file_range(&self) -> FileRange {
68 FileRange { file_id: self.file_id, range: self.full_range }
69 }
70
71 pub fn full_range(&self) -> TextRange {
72 self.full_range
73 }
74
75 pub fn docs(&self) -> Option<&str> {
76 self.docs.as_deref()
77 }
78
79 pub fn description(&self) -> Option<&str> {
80 self.description.as_deref()
81 }
82
83 /// A "most interesting" range withing the `full_range`.
84 ///
85 /// Typically, `full_range` is the whole syntax node,
86 /// including doc comments, and `focus_range` is the range of the identifier.
87 pub fn focus_range(&self) -> Option<TextRange> {
88 self.focus_range
89 }
90
91 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 62 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
92 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 63 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
93 if let Some(src) = module.declaration_source(db) { 64 if let Some(src) = module.declaration_source(db) {
@@ -114,17 +85,12 @@ impl NavigationTarget {
114 85
115 #[cfg(test)] 86 #[cfg(test)]
116 pub(crate) fn debug_render(&self) -> String { 87 pub(crate) fn debug_render(&self) -> String {
117 let mut buf = format!( 88 let mut buf =
118 "{} {:?} {:?} {:?}", 89 format!("{} {:?} {:?} {:?}", self.name, self.kind, self.file_id, self.full_range);
119 self.name(), 90 if let Some(focus_range) = self.focus_range {
120 self.kind(),
121 self.file_id(),
122 self.full_range()
123 );
124 if let Some(focus_range) = self.focus_range() {
125 buf.push_str(&format!(" {:?}", focus_range)) 91 buf.push_str(&format!(" {:?}", focus_range))
126 } 92 }
127 if let Some(container_name) = self.container_name() { 93 if let Some(container_name) = &self.container_name {
128 buf.push_str(&format!(" {}", container_name)) 94 buf.push_str(&format!(" {}", container_name))
129 } 95 }
130 buf 96 buf
@@ -278,16 +244,22 @@ impl ToNav for hir::Module {
278impl ToNav for hir::ImplDef { 244impl ToNav for hir::ImplDef {
279 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 245 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
280 let src = self.source(db); 246 let src = self.source(db);
281 let frange = if let Some(item) = self.is_builtin_derive(db) { 247 let derive_attr = self.is_builtin_derive(db);
248 let frange = if let Some(item) = &derive_attr {
282 original_range(db, item.syntax()) 249 original_range(db, item.syntax())
283 } else { 250 } else {
284 original_range(db, src.as_ref().map(|it| it.syntax())) 251 original_range(db, src.as_ref().map(|it| it.syntax()))
285 }; 252 };
253 let focus_range = if derive_attr.is_some() {
254 None
255 } else {
256 src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range)
257 };
286 258
287 NavigationTarget::from_syntax( 259 NavigationTarget::from_syntax(
288 frange.file_id, 260 frange.file_id,
289 "impl".into(), 261 "impl".into(),
290 None, 262 focus_range,
291 frange.range, 263 frange.range,
292 src.value.syntax().kind(), 264 src.value.syntax().kind(),
293 ) 265 )
@@ -407,16 +379,16 @@ pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option
407 379
408 match_ast! { 380 match_ast! {
409 match node { 381 match node {
410 ast::FnDef(it) => it.doc_comment_text(), 382 ast::Fn(it) => it.doc_comment_text(),
411 ast::StructDef(it) => it.doc_comment_text(), 383 ast::Struct(it) => it.doc_comment_text(),
412 ast::EnumDef(it) => it.doc_comment_text(), 384 ast::Enum(it) => it.doc_comment_text(),
413 ast::TraitDef(it) => it.doc_comment_text(), 385 ast::Trait(it) => it.doc_comment_text(),
414 ast::Module(it) => it.doc_comment_text(), 386 ast::Module(it) => it.doc_comment_text(),
415 ast::TypeAliasDef(it) => it.doc_comment_text(), 387 ast::TypeAlias(it) => it.doc_comment_text(),
416 ast::ConstDef(it) => it.doc_comment_text(), 388 ast::Const(it) => it.doc_comment_text(),
417 ast::StaticDef(it) => it.doc_comment_text(), 389 ast::Static(it) => it.doc_comment_text(),
418 ast::RecordFieldDef(it) => it.doc_comment_text(), 390 ast::RecordField(it) => it.doc_comment_text(),
419 ast::EnumVariant(it) => it.doc_comment_text(), 391 ast::Variant(it) => it.doc_comment_text(),
420 ast::MacroCall(it) => it.doc_comment_text(), 392 ast::MacroCall(it) => it.doc_comment_text(),
421 _ => None, 393 _ => None,
422 } 394 }
@@ -432,17 +404,88 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) ->
432 404
433 match_ast! { 405 match_ast! {
434 match node { 406 match node {
435 ast::FnDef(it) => it.short_label(), 407 ast::Fn(it) => it.short_label(),
436 ast::StructDef(it) => it.short_label(), 408 ast::Struct(it) => it.short_label(),
437 ast::EnumDef(it) => it.short_label(), 409 ast::Enum(it) => it.short_label(),
438 ast::TraitDef(it) => it.short_label(), 410 ast::Trait(it) => it.short_label(),
439 ast::Module(it) => it.short_label(), 411 ast::Module(it) => it.short_label(),
440 ast::TypeAliasDef(it) => it.short_label(), 412 ast::TypeAlias(it) => it.short_label(),
441 ast::ConstDef(it) => it.short_label(), 413 ast::Const(it) => it.short_label(),
442 ast::StaticDef(it) => it.short_label(), 414 ast::Static(it) => it.short_label(),
443 ast::RecordFieldDef(it) => it.short_label(), 415 ast::RecordField(it) => it.short_label(),
444 ast::EnumVariant(it) => it.short_label(), 416 ast::Variant(it) => it.short_label(),
445 _ => None, 417 _ => None,
446 } 418 }
447 } 419 }
448} 420}
421
422#[cfg(test)]
423mod tests {
424 use expect::expect;
425
426 use crate::{mock_analysis::single_file, Query};
427
428 #[test]
429 fn test_nav_for_symbol() {
430 let (analysis, _) = single_file(
431 r#"
432enum FooInner { }
433fn foo() { enum FooInner { } }
434"#,
435 );
436
437 let navs = analysis.symbol_search(Query::new("FooInner".to_string())).unwrap();
438 expect![[r#"
439 [
440 NavigationTarget {
441 file_id: FileId(
442 1,
443 ),
444 full_range: 0..17,
445 focus_range: Some(
446 5..13,
447 ),
448 name: "FooInner",
449 kind: ENUM,
450 container_name: None,
451 description: Some(
452 "enum FooInner",
453 ),
454 docs: None,
455 },
456 NavigationTarget {
457 file_id: FileId(
458 1,
459 ),
460 full_range: 29..46,
461 focus_range: Some(
462 34..42,
463 ),
464 name: "FooInner",
465 kind: ENUM,
466 container_name: Some(
467 "foo",
468 ),
469 description: Some(
470 "enum FooInner",
471 ),
472 docs: None,
473 },
474 ]
475 "#]]
476 .assert_debug_eq(&navs);
477 }
478
479 #[test]
480 fn test_world_symbols_are_case_sensitive() {
481 let (analysis, _) = single_file(
482 r#"
483fn foo() {}
484struct Foo;
485"#,
486 );
487
488 let navs = analysis.symbol_search(Query::new("foo".to_string())).unwrap();
489 assert_eq!(navs.len(), 2)
490 }
491}
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs
index d37260e96..bddf1bd47 100644
--- a/crates/ra_ide/src/display/short_label.rs
+++ b/crates/ra_ide/src/display/short_label.rs
@@ -1,37 +1,37 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::ast::{self, AstNode, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 3use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
4use stdx::format_to; 4use stdx::format_to;
5 5
6pub(crate) trait ShortLabel { 6pub(crate) trait ShortLabel {
7 fn short_label(&self) -> Option<String>; 7 fn short_label(&self) -> Option<String>;
8} 8}
9 9
10impl ShortLabel for ast::FnDef { 10impl ShortLabel for ast::Fn {
11 fn short_label(&self) -> Option<String> { 11 fn short_label(&self) -> Option<String> {
12 Some(crate::display::function_label(self)) 12 Some(crate::display::function_declaration(self))
13 } 13 }
14} 14}
15 15
16impl ShortLabel for ast::StructDef { 16impl ShortLabel for ast::Struct {
17 fn short_label(&self) -> Option<String> { 17 fn short_label(&self) -> Option<String> {
18 short_label_from_node(self, "struct ") 18 short_label_from_node(self, "struct ")
19 } 19 }
20} 20}
21 21
22impl ShortLabel for ast::UnionDef { 22impl ShortLabel for ast::Union {
23 fn short_label(&self) -> Option<String> { 23 fn short_label(&self) -> Option<String> {
24 short_label_from_node(self, "union ") 24 short_label_from_node(self, "union ")
25 } 25 }
26} 26}
27 27
28impl ShortLabel for ast::EnumDef { 28impl ShortLabel for ast::Enum {
29 fn short_label(&self) -> Option<String> { 29 fn short_label(&self) -> Option<String> {
30 short_label_from_node(self, "enum ") 30 short_label_from_node(self, "enum ")
31 } 31 }
32} 32}
33 33
34impl ShortLabel for ast::TraitDef { 34impl ShortLabel for ast::Trait {
35 fn short_label(&self) -> Option<String> { 35 fn short_label(&self) -> Option<String> {
36 if self.unsafe_token().is_some() { 36 if self.unsafe_token().is_some() {
37 short_label_from_node(self, "unsafe trait ") 37 short_label_from_node(self, "unsafe trait ")
@@ -47,43 +47,43 @@ impl ShortLabel for ast::Module {
47 } 47 }
48} 48}
49 49
50impl ShortLabel for ast::TypeAliasDef { 50impl ShortLabel for ast::TypeAlias {
51 fn short_label(&self) -> Option<String> { 51 fn short_label(&self) -> Option<String> {
52 short_label_from_node(self, "type ") 52 short_label_from_node(self, "type ")
53 } 53 }
54} 54}
55 55
56impl ShortLabel for ast::ConstDef { 56impl ShortLabel for ast::Const {
57 fn short_label(&self) -> Option<String> { 57 fn short_label(&self) -> Option<String> {
58 short_label_from_ascribed_node(self, "const ") 58 short_label_from_ty(self, self.ty(), "const ")
59 } 59 }
60} 60}
61 61
62impl ShortLabel for ast::StaticDef { 62impl ShortLabel for ast::Static {
63 fn short_label(&self) -> Option<String> { 63 fn short_label(&self) -> Option<String> {
64 short_label_from_ascribed_node(self, "static ") 64 short_label_from_ty(self, self.ty(), "static ")
65 } 65 }
66} 66}
67 67
68impl ShortLabel for ast::RecordFieldDef { 68impl ShortLabel for ast::RecordField {
69 fn short_label(&self) -> Option<String> { 69 fn short_label(&self) -> Option<String> {
70 short_label_from_ascribed_node(self, "") 70 short_label_from_ty(self, self.ty(), "")
71 } 71 }
72} 72}
73 73
74impl ShortLabel for ast::EnumVariant { 74impl ShortLabel for ast::Variant {
75 fn short_label(&self) -> Option<String> { 75 fn short_label(&self) -> Option<String> {
76 Some(self.name()?.text().to_string()) 76 Some(self.name()?.text().to_string())
77 } 77 }
78} 78}
79 79
80fn short_label_from_ascribed_node<T>(node: &T, prefix: &str) -> Option<String> 80fn short_label_from_ty<T>(node: &T, ty: Option<ast::TypeRef>, prefix: &str) -> Option<String>
81where 81where
82 T: NameOwner + VisibilityOwner + TypeAscriptionOwner, 82 T: NameOwner + VisibilityOwner,
83{ 83{
84 let mut buf = short_label_from_node(node, prefix)?; 84 let mut buf = short_label_from_node(node, prefix)?;
85 85
86 if let Some(type_ref) = node.ascribed_type() { 86 if let Some(type_ref) = ty {
87 format_to!(buf, ": {}", type_ref.syntax()); 87 format_to!(buf, ": {}", type_ref.syntax());
88 } 88 }
89 89
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/display/structure.rs
deleted file mode 100644
index aad5a8e4d..000000000
--- a/crates/ra_ide/src/display/structure.rs
+++ /dev/null
@@ -1,438 +0,0 @@
1use ra_syntax::{
2 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
3 match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, WalkEvent,
4};
5
6#[derive(Debug, Clone)]
7pub struct StructureNode {
8 pub parent: Option<usize>,
9 pub label: String,
10 pub navigation_range: TextRange,
11 pub node_range: TextRange,
12 pub kind: SyntaxKind,
13 pub detail: Option<String>,
14 pub deprecated: bool,
15}
16
17// Feature: File Structure
18//
19// Provides a tree of the symbols defined in the file. Can be used to
20//
21// * fuzzy search symbol in a file (super useful)
22// * draw breadcrumbs to describe the context around the cursor
23// * draw outline of the file
24//
25// |===
26// | Editor | Shortcut
27//
28// | VS Code | kbd:[Ctrl+Shift+O]
29// |===
30pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
31 let mut res = Vec::new();
32 let mut stack = Vec::new();
33
34 for event in file.syntax().preorder() {
35 match event {
36 WalkEvent::Enter(node) => {
37 if let Some(mut symbol) = structure_node(&node) {
38 symbol.parent = stack.last().copied();
39 stack.push(res.len());
40 res.push(symbol);
41 }
42 }
43 WalkEvent::Leave(node) => {
44 if structure_node(&node).is_some() {
45 stack.pop().unwrap();
46 }
47 }
48 }
49 }
50 res
51}
52
53fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
54 fn decl<N: NameOwner + AttrsOwner>(node: N) -> Option<StructureNode> {
55 decl_with_detail(node, None)
56 }
57
58 fn decl_with_ascription<N: NameOwner + AttrsOwner + TypeAscriptionOwner>(
59 node: N,
60 ) -> Option<StructureNode> {
61 let ty = node.ascribed_type();
62 decl_with_type_ref(node, ty)
63 }
64
65 fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
66 node: N,
67 type_ref: Option<ast::TypeRef>,
68 ) -> Option<StructureNode> {
69 let detail = type_ref.map(|type_ref| {
70 let mut detail = String::new();
71 collapse_ws(type_ref.syntax(), &mut detail);
72 detail
73 });
74 decl_with_detail(node, detail)
75 }
76
77 fn decl_with_detail<N: NameOwner + AttrsOwner>(
78 node: N,
79 detail: Option<String>,
80 ) -> Option<StructureNode> {
81 let name = node.name()?;
82
83 Some(StructureNode {
84 parent: None,
85 label: name.text().to_string(),
86 navigation_range: name.syntax().text_range(),
87 node_range: node.syntax().text_range(),
88 kind: node.syntax().kind(),
89 detail,
90 deprecated: node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated"),
91 })
92 }
93
94 fn collapse_ws(node: &SyntaxNode, output: &mut String) {
95 let mut can_insert_ws = false;
96 node.text().for_each_chunk(|chunk| {
97 for line in chunk.lines() {
98 let line = line.trim();
99 if line.is_empty() {
100 if can_insert_ws {
101 output.push(' ');
102 can_insert_ws = false;
103 }
104 } else {
105 output.push_str(line);
106 can_insert_ws = true;
107 }
108 }
109 })
110 }
111
112 match_ast! {
113 match node {
114 ast::FnDef(it) => {
115 let mut detail = String::from("fn");
116 if let Some(type_param_list) = it.type_param_list() {
117 collapse_ws(type_param_list.syntax(), &mut detail);
118 }
119 if let Some(param_list) = it.param_list() {
120 collapse_ws(param_list.syntax(), &mut detail);
121 }
122 if let Some(ret_type) = it.ret_type() {
123 detail.push_str(" ");
124 collapse_ws(ret_type.syntax(), &mut detail);
125 }
126
127 decl_with_detail(it, Some(detail))
128 },
129 ast::StructDef(it) => decl(it),
130 ast::EnumDef(it) => decl(it),
131 ast::EnumVariant(it) => decl(it),
132 ast::TraitDef(it) => decl(it),
133 ast::Module(it) => decl(it),
134 ast::TypeAliasDef(it) => {
135 let ty = it.type_ref();
136 decl_with_type_ref(it, ty)
137 },
138 ast::RecordFieldDef(it) => decl_with_ascription(it),
139 ast::ConstDef(it) => decl_with_ascription(it),
140 ast::StaticDef(it) => decl_with_ascription(it),
141 ast::ImplDef(it) => {
142 let target_type = it.target_type()?;
143 let target_trait = it.target_trait();
144 let label = match target_trait {
145 None => format!("impl {}", target_type.syntax().text()),
146 Some(t) => {
147 format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
148 }
149 };
150
151 let node = StructureNode {
152 parent: None,
153 label,
154 navigation_range: target_type.syntax().text_range(),
155 node_range: it.syntax().text_range(),
156 kind: it.syntax().kind(),
157 detail: None,
158 deprecated: false,
159 };
160 Some(node)
161 },
162 ast::MacroCall(it) => {
163 match it.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
164 Some(path_segment) if path_segment.text() == "macro_rules"
165 => decl(it),
166 _ => None,
167 }
168 },
169 _ => None,
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177 use insta::assert_debug_snapshot;
178
179 #[test]
180 fn test_file_structure() {
181 let file = SourceFile::parse(
182 r#"
183struct Foo {
184 x: i32
185}
186
187mod m {
188 fn bar1() {}
189 fn bar2<T>(t: T) -> T {}
190 fn bar3<A,
191 B>(a: A,
192 b: B) -> Vec<
193 u32
194 > {}
195}
196
197enum E { X, Y(i32) }
198type T = ();
199static S: i32 = 92;
200const C: i32 = 92;
201
202impl E {}
203
204impl fmt::Debug for E {}
205
206macro_rules! mc {
207 () => {}
208}
209
210#[macro_export]
211macro_rules! mcexp {
212 () => {}
213}
214
215/// Doc comment
216macro_rules! mcexp {
217 () => {}
218}
219
220#[deprecated]
221fn obsolete() {}
222
223#[deprecated(note = "for awhile")]
224fn very_obsolete() {}
225"#,
226 )
227 .ok()
228 .unwrap();
229 let structure = file_structure(&file);
230 assert_debug_snapshot!(structure,
231 @r###"
232 [
233 StructureNode {
234 parent: None,
235 label: "Foo",
236 navigation_range: 8..11,
237 node_range: 1..26,
238 kind: STRUCT_DEF,
239 detail: None,
240 deprecated: false,
241 },
242 StructureNode {
243 parent: Some(
244 0,
245 ),
246 label: "x",
247 navigation_range: 18..19,
248 node_range: 18..24,
249 kind: RECORD_FIELD_DEF,
250 detail: Some(
251 "i32",
252 ),
253 deprecated: false,
254 },
255 StructureNode {
256 parent: None,
257 label: "m",
258 navigation_range: 32..33,
259 node_range: 28..158,
260 kind: MODULE,
261 detail: None,
262 deprecated: false,
263 },
264 StructureNode {
265 parent: Some(
266 2,
267 ),
268 label: "bar1",
269 navigation_range: 43..47,
270 node_range: 40..52,
271 kind: FN_DEF,
272 detail: Some(
273 "fn()",
274 ),
275 deprecated: false,
276 },
277 StructureNode {
278 parent: Some(
279 2,
280 ),
281 label: "bar2",
282 navigation_range: 60..64,
283 node_range: 57..81,
284 kind: FN_DEF,
285 detail: Some(
286 "fn<T>(t: T) -> T",
287 ),
288 deprecated: false,
289 },
290 StructureNode {
291 parent: Some(
292 2,
293 ),
294 label: "bar3",
295 navigation_range: 89..93,
296 node_range: 86..156,
297 kind: FN_DEF,
298 detail: Some(
299 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
300 ),
301 deprecated: false,
302 },
303 StructureNode {
304 parent: None,
305 label: "E",
306 navigation_range: 165..166,
307 node_range: 160..180,
308 kind: ENUM_DEF,
309 detail: None,
310 deprecated: false,
311 },
312 StructureNode {
313 parent: Some(
314 6,
315 ),
316 label: "X",
317 navigation_range: 169..170,
318 node_range: 169..170,
319 kind: ENUM_VARIANT,
320 detail: None,
321 deprecated: false,
322 },
323 StructureNode {
324 parent: Some(
325 6,
326 ),
327 label: "Y",
328 navigation_range: 172..173,
329 node_range: 172..178,
330 kind: ENUM_VARIANT,
331 detail: None,
332 deprecated: false,
333 },
334 StructureNode {
335 parent: None,
336 label: "T",
337 navigation_range: 186..187,
338 node_range: 181..193,
339 kind: TYPE_ALIAS_DEF,
340 detail: Some(
341 "()",
342 ),
343 deprecated: false,
344 },
345 StructureNode {
346 parent: None,
347 label: "S",
348 navigation_range: 201..202,
349 node_range: 194..213,
350 kind: STATIC_DEF,
351 detail: Some(
352 "i32",
353 ),
354 deprecated: false,
355 },
356 StructureNode {
357 parent: None,
358 label: "C",
359 navigation_range: 220..221,
360 node_range: 214..232,
361 kind: CONST_DEF,
362 detail: Some(
363 "i32",
364 ),
365 deprecated: false,
366 },
367 StructureNode {
368 parent: None,
369 label: "impl E",
370 navigation_range: 239..240,
371 node_range: 234..243,
372 kind: IMPL_DEF,
373 detail: None,
374 deprecated: false,
375 },
376 StructureNode {
377 parent: None,
378 label: "impl fmt::Debug for E",
379 navigation_range: 265..266,
380 node_range: 245..269,
381 kind: IMPL_DEF,
382 detail: None,
383 deprecated: false,
384 },
385 StructureNode {
386 parent: None,
387 label: "mc",
388 navigation_range: 284..286,
389 node_range: 271..303,
390 kind: MACRO_CALL,
391 detail: None,
392 deprecated: false,
393 },
394 StructureNode {
395 parent: None,
396 label: "mcexp",
397 navigation_range: 334..339,
398 node_range: 305..356,
399 kind: MACRO_CALL,
400 detail: None,
401 deprecated: false,
402 },
403 StructureNode {
404 parent: None,
405 label: "mcexp",
406 navigation_range: 387..392,
407 node_range: 358..409,
408 kind: MACRO_CALL,
409 detail: None,
410 deprecated: false,
411 },
412 StructureNode {
413 parent: None,
414 label: "obsolete",
415 navigation_range: 428..436,
416 node_range: 411..441,
417 kind: FN_DEF,
418 detail: Some(
419 "fn()",
420 ),
421 deprecated: true,
422 },
423 StructureNode {
424 parent: None,
425 label: "very_obsolete",
426 navigation_range: 481..494,
427 node_range: 443..499,
428 kind: FN_DEF,
429 detail: Some(
430 "fn()",
431 ),
432 deprecated: true,
433 },
434 ]
435 "###
436 );
437 }
438}
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index 54a47aac0..043515f54 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -2,7 +2,9 @@ use hir::Semantics;
2use ra_ide_db::RootDatabase; 2use ra_ide_db::RootDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::{find_node_at_offset, SyntaxRewriter}, 4 algo::{find_node_at_offset, SyntaxRewriter},
5 ast, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T, 5 ast, AstNode, NodeOrToken, SyntaxKind,
6 SyntaxKind::*,
7 SyntaxNode, WalkEvent, T,
6}; 8};
7 9
8use crate::FilePosition; 10use crate::FilePosition;
@@ -65,8 +67,6 @@ fn expand_macro_recur(
65// FIXME: It would also be cool to share logic here and in the mbe tests, 67// FIXME: It would also be cool to share logic here and in the mbe tests,
66// which are pretty unreadable at the moment. 68// which are pretty unreadable at the moment.
67fn insert_whitespaces(syn: SyntaxNode) -> String { 69fn insert_whitespaces(syn: SyntaxNode) -> String {
68 use SyntaxKind::*;
69
70 let mut res = String::new(); 70 let mut res = String::new();
71 let mut token_iter = syn 71 let mut token_iter = syn
72 .preorder_with_tokens() 72 .preorder_with_tokens()
@@ -120,175 +120,164 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
120 120
121#[cfg(test)] 121#[cfg(test)]
122mod tests { 122mod tests {
123 use insta::assert_snapshot; 123 use expect::{expect, Expect};
124 124
125 use crate::mock_analysis::analysis_and_position; 125 use crate::mock_analysis::analysis_and_position;
126 126
127 use super::*; 127 fn check(ra_fixture: &str, expect: Expect) {
128 128 let (analysis, pos) = analysis_and_position(ra_fixture);
129 fn check_expand_macro(fixture: &str) -> ExpandedMacro { 129 let expansion = analysis.expand_macro(pos).unwrap().unwrap();
130 let (analysis, pos) = analysis_and_position(fixture); 130 let actual = format!("{}\n{}", expansion.name, expansion.expansion);
131 analysis.expand_macro(pos).unwrap().unwrap() 131 expect.assert_eq(&actual);
132 } 132 }
133 133
134 #[test] 134 #[test]
135 fn macro_expand_recursive_expansion() { 135 fn macro_expand_recursive_expansion() {
136 let res = check_expand_macro( 136 check(
137 r#" 137 r#"
138 //- /lib.rs 138macro_rules! bar {
139 macro_rules! bar { 139 () => { fn b() {} }
140 () => { fn b() {} } 140}
141 } 141macro_rules! foo {
142 macro_rules! foo { 142 () => { bar!(); }
143 () => { bar!(); } 143}
144 } 144macro_rules! baz {
145 macro_rules! baz { 145 () => { foo!(); }
146 () => { foo!(); } 146}
147 } 147f<|>oo!();
148 f<|>oo!(); 148"#,
149 "#, 149 expect![[r#"
150 foo
151 fn b(){}
152 "#]],
150 ); 153 );
151
152 assert_eq!(res.name, "foo");
153 assert_snapshot!(res.expansion, @r###"
154fn b(){}
155"###);
156 } 154 }
157 155
158 #[test] 156 #[test]
159 fn macro_expand_multiple_lines() { 157 fn macro_expand_multiple_lines() {
160 let res = check_expand_macro( 158 check(
161 r#" 159 r#"
162 //- /lib.rs 160macro_rules! foo {
163 macro_rules! foo { 161 () => {
164 () => { 162 fn some_thing() -> u32 {
165 fn some_thing() -> u32 { 163 let a = 0;
166 let a = 0; 164 a + 10
167 a + 10
168 }
169 }
170 } 165 }
171 f<|>oo!(); 166 }
167}
168f<|>oo!();
172 "#, 169 "#,
170 expect![[r#"
171 foo
172 fn some_thing() -> u32 {
173 let a = 0;
174 a+10
175 }"#]],
173 ); 176 );
174
175 assert_eq!(res.name, "foo");
176 assert_snapshot!(res.expansion, @r###"
177fn some_thing() -> u32 {
178 let a = 0;
179 a+10
180}
181"###);
182 } 177 }
183 178
184 #[test] 179 #[test]
185 fn macro_expand_match_ast() { 180 fn macro_expand_match_ast() {
186 let res = check_expand_macro( 181 check(
187 r#" 182 r#"
188 //- /lib.rs 183macro_rules! match_ast {
189 macro_rules! match_ast { 184 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
190 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; 185 (match ($node:expr) {
186 $( ast::$ast:ident($it:ident) => $res:block, )*
187 _ => $catch_all:expr $(,)?
188 }) => {{
189 $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
190 { $catch_all }
191 }};
192}
191 193
192 (match ($node:expr) { 194fn main() {
193 $( ast::$ast:ident($it:ident) => $res:block, )* 195 mat<|>ch_ast! {
194 _ => $catch_all:expr $(,)? 196 match container {
195 }) => {{ 197 ast::TraitDef(it) => {},
196 $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* 198 ast::ImplDef(it) => {},
197 { $catch_all } 199 _ => { continue },
198 }};
199 } 200 }
200
201 fn main() {
202 mat<|>ch_ast! {
203 match container {
204 ast::TraitDef(it) => {},
205 ast::ImplDef(it) => {},
206 _ => { continue },
207 }
208 }
209 }
210 "#,
211 );
212
213 assert_eq!(res.name, "match_ast");
214 assert_snapshot!(res.expansion, @r###"
215{
216 if let Some(it) = ast::TraitDef::cast(container.clone()){}
217 else if let Some(it) = ast::ImplDef::cast(container.clone()){}
218 else {
219 {
220 continue
221 } 201 }
222 }
223} 202}
224"###); 203"#,
204 expect![[r#"
205 match_ast
206 {
207 if let Some(it) = ast::TraitDef::cast(container.clone()){}
208 else if let Some(it) = ast::ImplDef::cast(container.clone()){}
209 else {
210 {
211 continue
212 }
213 }
214 }"#]],
215 );
225 } 216 }
226 217
227 #[test] 218 #[test]
228 fn macro_expand_match_ast_inside_let_statement() { 219 fn macro_expand_match_ast_inside_let_statement() {
229 let res = check_expand_macro( 220 check(
230 r#" 221 r#"
231 //- /lib.rs 222macro_rules! match_ast {
232 macro_rules! match_ast { 223 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
233 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; 224 (match ($node:expr) {}) => {{}};
234 (match ($node:expr) {}) => {{}}; 225}
235 }
236 226
237 fn main() { 227fn main() {
238 let p = f(|it| { 228 let p = f(|it| {
239 let res = mat<|>ch_ast! { match c {}}; 229 let res = mat<|>ch_ast! { match c {}};
240 Some(res) 230 Some(res)
241 })?; 231 })?;
242 } 232}
243 "#, 233"#,
234 expect![[r#"
235 match_ast
236 {}
237 "#]],
244 ); 238 );
245
246 assert_eq!(res.name, "match_ast");
247 assert_snapshot!(res.expansion, @r###"{}"###);
248 } 239 }
249 240
250 #[test] 241 #[test]
251 fn macro_expand_inner_macro_fail_to_expand() { 242 fn macro_expand_inner_macro_fail_to_expand() {
252 let res = check_expand_macro( 243 check(
253 r#" 244 r#"
254 //- /lib.rs 245macro_rules! bar {
255 macro_rules! bar { 246 (BAD) => {};
256 (BAD) => {}; 247}
257 } 248macro_rules! foo {
258 macro_rules! foo { 249 () => {bar!()};
259 () => {bar!()}; 250}
260 }
261 251
262 fn main() { 252fn main() {
263 let res = fo<|>o!(); 253 let res = fo<|>o!();
264 } 254}
265 "#, 255"#,
256 expect![[r#"
257 foo
258 "#]],
266 ); 259 );
267
268 assert_eq!(res.name, "foo");
269 assert_snapshot!(res.expansion, @r###""###);
270 } 260 }
271 261
272 #[test] 262 #[test]
273 fn macro_expand_with_dollar_crate() { 263 fn macro_expand_with_dollar_crate() {
274 let res = check_expand_macro( 264 check(
275 r#" 265 r#"
276 //- /lib.rs 266#[macro_export]
277 #[macro_export] 267macro_rules! bar {
278 macro_rules! bar { 268 () => {0};
279 () => {0}; 269}
280 } 270macro_rules! foo {
281 macro_rules! foo { 271 () => {$crate::bar!()};
282 () => {$crate::bar!()}; 272}
283 }
284 273
285 fn main() { 274fn main() {
286 let res = fo<|>o!(); 275 let res = fo<|>o!();
287 } 276}
288 "#, 277"#,
278 expect![[r#"
279 foo
280 0 "#]],
289 ); 281 );
290
291 assert_eq!(res.name, "foo");
292 assert_snapshot!(res.expansion, @r###"0"###);
293 } 282 }
294} 283}
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index 8a6b3ea99..fc81b48cc 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -39,12 +39,12 @@ fn try_extend_selection(
39 let list_kinds = [ 39 let list_kinds = [
40 RECORD_FIELD_PAT_LIST, 40 RECORD_FIELD_PAT_LIST,
41 MATCH_ARM_LIST, 41 MATCH_ARM_LIST,
42 RECORD_FIELD_DEF_LIST,
43 TUPLE_FIELD_DEF_LIST,
44 RECORD_FIELD_LIST, 42 RECORD_FIELD_LIST,
45 ENUM_VARIANT_LIST, 43 TUPLE_FIELD_LIST,
44 RECORD_EXPR_FIELD_LIST,
45 VARIANT_LIST,
46 USE_TREE_LIST, 46 USE_TREE_LIST,
47 TYPE_PARAM_LIST, 47 GENERIC_PARAM_LIST,
48 TYPE_ARG_LIST, 48 TYPE_ARG_LIST,
49 TYPE_BOUND_LIST, 49 TYPE_BOUND_LIST,
50 PARAM_LIST, 50 PARAM_LIST,
diff --git a/crates/ra_ide/src/file_structure.rs b/crates/ra_ide/src/file_structure.rs
new file mode 100644
index 000000000..91765140a
--- /dev/null
+++ b/crates/ra_ide/src/file_structure.rs
@@ -0,0 +1,431 @@
1use ra_syntax::{
2 ast::{self, AttrsOwner, GenericParamsOwner, NameOwner},
3 match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, WalkEvent,
4};
5
6#[derive(Debug, Clone)]
7pub struct StructureNode {
8 pub parent: Option<usize>,
9 pub label: String,
10 pub navigation_range: TextRange,
11 pub node_range: TextRange,
12 pub kind: SyntaxKind,
13 pub detail: Option<String>,
14 pub deprecated: bool,
15}
16
17// Feature: File Structure
18//
19// Provides a tree of the symbols defined in the file. Can be used to
20//
21// * fuzzy search symbol in a file (super useful)
22// * draw breadcrumbs to describe the context around the cursor
23// * draw outline of the file
24//
25// |===
26// | Editor | Shortcut
27//
28// | VS Code | kbd:[Ctrl+Shift+O]
29// |===
30pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
31 let mut res = Vec::new();
32 let mut stack = Vec::new();
33
34 for event in file.syntax().preorder() {
35 match event {
36 WalkEvent::Enter(node) => {
37 if let Some(mut symbol) = structure_node(&node) {
38 symbol.parent = stack.last().copied();
39 stack.push(res.len());
40 res.push(symbol);
41 }
42 }
43 WalkEvent::Leave(node) => {
44 if structure_node(&node).is_some() {
45 stack.pop().unwrap();
46 }
47 }
48 }
49 }
50 res
51}
52
53fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
54 fn decl<N: NameOwner + AttrsOwner>(node: N) -> Option<StructureNode> {
55 decl_with_detail(&node, None)
56 }
57
58 fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
59 node: &N,
60 type_ref: Option<ast::TypeRef>,
61 ) -> Option<StructureNode> {
62 let detail = type_ref.map(|type_ref| {
63 let mut detail = String::new();
64 collapse_ws(type_ref.syntax(), &mut detail);
65 detail
66 });
67 decl_with_detail(node, detail)
68 }
69
70 fn decl_with_detail<N: NameOwner + AttrsOwner>(
71 node: &N,
72 detail: Option<String>,
73 ) -> Option<StructureNode> {
74 let name = node.name()?;
75
76 Some(StructureNode {
77 parent: None,
78 label: name.text().to_string(),
79 navigation_range: name.syntax().text_range(),
80 node_range: node.syntax().text_range(),
81 kind: node.syntax().kind(),
82 detail,
83 deprecated: node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated"),
84 })
85 }
86
87 fn collapse_ws(node: &SyntaxNode, output: &mut String) {
88 let mut can_insert_ws = false;
89 node.text().for_each_chunk(|chunk| {
90 for line in chunk.lines() {
91 let line = line.trim();
92 if line.is_empty() {
93 if can_insert_ws {
94 output.push(' ');
95 can_insert_ws = false;
96 }
97 } else {
98 output.push_str(line);
99 can_insert_ws = true;
100 }
101 }
102 })
103 }
104
105 match_ast! {
106 match node {
107 ast::Fn(it) => {
108 let mut detail = String::from("fn");
109 if let Some(type_param_list) = it.generic_param_list() {
110 collapse_ws(type_param_list.syntax(), &mut detail);
111 }
112 if let Some(param_list) = it.param_list() {
113 collapse_ws(param_list.syntax(), &mut detail);
114 }
115 if let Some(ret_type) = it.ret_type() {
116 detail.push_str(" ");
117 collapse_ws(ret_type.syntax(), &mut detail);
118 }
119
120 decl_with_detail(&it, Some(detail))
121 },
122 ast::Struct(it) => decl(it),
123 ast::Union(it) => decl(it),
124 ast::Enum(it) => decl(it),
125 ast::Variant(it) => decl(it),
126 ast::Trait(it) => decl(it),
127 ast::Module(it) => decl(it),
128 ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty()),
129 ast::RecordField(it) => decl_with_type_ref(&it, it.ty()),
130 ast::Const(it) => decl_with_type_ref(&it, it.ty()),
131 ast::Static(it) => decl_with_type_ref(&it, it.ty()),
132 ast::Impl(it) => {
133 let target_type = it.target_type()?;
134 let target_trait = it.target_trait();
135 let label = match target_trait {
136 None => format!("impl {}", target_type.syntax().text()),
137 Some(t) => {
138 format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
139 }
140 };
141
142 let node = StructureNode {
143 parent: None,
144 label,
145 navigation_range: target_type.syntax().text_range(),
146 node_range: it.syntax().text_range(),
147 kind: it.syntax().kind(),
148 detail: None,
149 deprecated: false,
150 };
151 Some(node)
152 },
153 ast::MacroCall(it) => {
154 match it.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) {
155 Some(path_segment) if path_segment.text() == "macro_rules"
156 => decl(it),
157 _ => None,
158 }
159 },
160 _ => None,
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use expect::{expect, Expect};
168
169 use super::*;
170
171 fn check(ra_fixture: &str, expect: Expect) {
172 let file = SourceFile::parse(ra_fixture).ok().unwrap();
173 let structure = file_structure(&file);
174 expect.assert_debug_eq(&structure)
175 }
176
177 #[test]
178 fn test_file_structure() {
179 check(
180 r#"
181struct Foo {
182 x: i32
183}
184
185mod m {
186 fn bar1() {}
187 fn bar2<T>(t: T) -> T {}
188 fn bar3<A,
189 B>(a: A,
190 b: B) -> Vec<
191 u32
192 > {}
193}
194
195enum E { X, Y(i32) }
196type T = ();
197static S: i32 = 92;
198const C: i32 = 92;
199
200impl E {}
201
202impl fmt::Debug for E {}
203
204macro_rules! mc {
205 () => {}
206}
207
208#[macro_export]
209macro_rules! mcexp {
210 () => {}
211}
212
213/// Doc comment
214macro_rules! mcexp {
215 () => {}
216}
217
218#[deprecated]
219fn obsolete() {}
220
221#[deprecated(note = "for awhile")]
222fn very_obsolete() {}
223"#,
224 expect![[r#"
225 [
226 StructureNode {
227 parent: None,
228 label: "Foo",
229 navigation_range: 8..11,
230 node_range: 1..26,
231 kind: STRUCT,
232 detail: None,
233 deprecated: false,
234 },
235 StructureNode {
236 parent: Some(
237 0,
238 ),
239 label: "x",
240 navigation_range: 18..19,
241 node_range: 18..24,
242 kind: RECORD_FIELD,
243 detail: Some(
244 "i32",
245 ),
246 deprecated: false,
247 },
248 StructureNode {
249 parent: None,
250 label: "m",
251 navigation_range: 32..33,
252 node_range: 28..158,
253 kind: MODULE,
254 detail: None,
255 deprecated: false,
256 },
257 StructureNode {
258 parent: Some(
259 2,
260 ),
261 label: "bar1",
262 navigation_range: 43..47,
263 node_range: 40..52,
264 kind: FN,
265 detail: Some(
266 "fn()",
267 ),
268 deprecated: false,
269 },
270 StructureNode {
271 parent: Some(
272 2,
273 ),
274 label: "bar2",
275 navigation_range: 60..64,
276 node_range: 57..81,
277 kind: FN,
278 detail: Some(
279 "fn<T>(t: T) -> T",
280 ),
281 deprecated: false,
282 },
283 StructureNode {
284 parent: Some(
285 2,
286 ),
287 label: "bar3",
288 navigation_range: 89..93,
289 node_range: 86..156,
290 kind: FN,
291 detail: Some(
292 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
293 ),
294 deprecated: false,
295 },
296 StructureNode {
297 parent: None,
298 label: "E",
299 navigation_range: 165..166,
300 node_range: 160..180,
301 kind: ENUM,
302 detail: None,
303 deprecated: false,
304 },
305 StructureNode {
306 parent: Some(
307 6,
308 ),
309 label: "X",
310 navigation_range: 169..170,
311 node_range: 169..170,
312 kind: VARIANT,
313 detail: None,
314 deprecated: false,
315 },
316 StructureNode {
317 parent: Some(
318 6,
319 ),
320 label: "Y",
321 navigation_range: 172..173,
322 node_range: 172..178,
323 kind: VARIANT,
324 detail: None,
325 deprecated: false,
326 },
327 StructureNode {
328 parent: None,
329 label: "T",
330 navigation_range: 186..187,
331 node_range: 181..193,
332 kind: TYPE_ALIAS,
333 detail: Some(
334 "()",
335 ),
336 deprecated: false,
337 },
338 StructureNode {
339 parent: None,
340 label: "S",
341 navigation_range: 201..202,
342 node_range: 194..213,
343 kind: STATIC,
344 detail: Some(
345 "i32",
346 ),
347 deprecated: false,
348 },
349 StructureNode {
350 parent: None,
351 label: "C",
352 navigation_range: 220..221,
353 node_range: 214..232,
354 kind: CONST,
355 detail: Some(
356 "i32",
357 ),
358 deprecated: false,
359 },
360 StructureNode {
361 parent: None,
362 label: "impl E",
363 navigation_range: 239..240,
364 node_range: 234..243,
365 kind: IMPL,
366 detail: None,
367 deprecated: false,
368 },
369 StructureNode {
370 parent: None,
371 label: "impl fmt::Debug for E",
372 navigation_range: 265..266,
373 node_range: 245..269,
374 kind: IMPL,
375 detail: None,
376 deprecated: false,
377 },
378 StructureNode {
379 parent: None,
380 label: "mc",
381 navigation_range: 284..286,
382 node_range: 271..303,
383 kind: MACRO_CALL,
384 detail: None,
385 deprecated: false,
386 },
387 StructureNode {
388 parent: None,
389 label: "mcexp",
390 navigation_range: 334..339,
391 node_range: 305..356,
392 kind: MACRO_CALL,
393 detail: None,
394 deprecated: false,
395 },
396 StructureNode {
397 parent: None,
398 label: "mcexp",
399 navigation_range: 387..392,
400 node_range: 358..409,
401 kind: MACRO_CALL,
402 detail: None,
403 deprecated: false,
404 },
405 StructureNode {
406 parent: None,
407 label: "obsolete",
408 navigation_range: 428..436,
409 node_range: 411..441,
410 kind: FN,
411 detail: Some(
412 "fn()",
413 ),
414 deprecated: true,
415 },
416 StructureNode {
417 parent: None,
418 label: "very_obsolete",
419 navigation_range: 481..494,
420 node_range: 443..499,
421 kind: FN,
422 detail: Some(
423 "fn()",
424 ),
425 deprecated: true,
426 },
427 ]
428 "#]],
429 );
430 }
431}
diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs
index 8657377de..5a6e17936 100644
--- a/crates/ra_ide/src/folding_ranges.rs
+++ b/crates/ra_ide/src/folding_ranges.rs
@@ -15,6 +15,7 @@ pub enum FoldKind {
15 Imports, 15 Imports,
16 Mods, 16 Mods,
17 Block, 17 Block,
18 ArgList,
18} 19}
19 20
20#[derive(Debug)] 21#[derive(Debug)]
@@ -57,7 +58,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
57 } 58 }
58 NodeOrToken::Node(node) => { 59 NodeOrToken::Node(node) => {
59 // Fold groups of imports 60 // Fold groups of imports
60 if node.kind() == USE_ITEM && !visited_imports.contains(&node) { 61 if node.kind() == USE && !visited_imports.contains(&node) {
61 if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) { 62 if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
62 res.push(Fold { range, kind: FoldKind::Imports }) 63 res.push(Fold { range, kind: FoldKind::Imports })
63 } 64 }
@@ -82,15 +83,17 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
82fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { 83fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
83 match kind { 84 match kind {
84 COMMENT => Some(FoldKind::Comment), 85 COMMENT => Some(FoldKind::Comment),
85 USE_ITEM => Some(FoldKind::Imports), 86 USE => Some(FoldKind::Imports),
86 RECORD_FIELD_DEF_LIST 87 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
88 RECORD_FIELD_LIST
87 | RECORD_FIELD_PAT_LIST 89 | RECORD_FIELD_PAT_LIST
90 | RECORD_EXPR_FIELD_LIST
88 | ITEM_LIST 91 | ITEM_LIST
89 | EXTERN_ITEM_LIST 92 | EXTERN_ITEM_LIST
90 | USE_TREE_LIST 93 | USE_TREE_LIST
91 | BLOCK_EXPR 94 | BLOCK_EXPR
92 | MATCH_ARM_LIST 95 | MATCH_ARM_LIST
93 | ENUM_VARIANT_LIST 96 | VARIANT_LIST
94 | TOKEN_TREE => Some(FoldKind::Block), 97 | TOKEN_TREE => Some(FoldKind::Block),
95 _ => None, 98 _ => None,
96 } 99 }
@@ -196,89 +199,85 @@ fn contiguous_range_for_comment(
196 199
197#[cfg(test)] 200#[cfg(test)]
198mod tests { 201mod tests {
202 use test_utils::extract_tags;
203
199 use super::*; 204 use super::*;
200 use test_utils::extract_ranges;
201 205
202 fn do_check(text: &str, fold_kinds: &[FoldKind]) { 206 fn check(ra_fixture: &str) {
203 let (ranges, text) = extract_ranges(text, "fold"); 207 let (ranges, text) = extract_tags(ra_fixture, "fold");
208
204 let parse = SourceFile::parse(&text); 209 let parse = SourceFile::parse(&text);
205 let folds = folding_ranges(&parse.tree()); 210 let folds = folding_ranges(&parse.tree());
206
207 assert_eq!( 211 assert_eq!(
208 folds.len(), 212 folds.len(),
209 ranges.len(), 213 ranges.len(),
210 "The amount of folds is different than the expected amount" 214 "The amount of folds is different than the expected amount"
211 ); 215 );
212 assert_eq!( 216
213 folds.len(), 217 for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
214 fold_kinds.len(),
215 "The amount of fold kinds is different than the expected amount"
216 );
217 for ((fold, range), fold_kind) in
218 folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
219 {
220 assert_eq!(fold.range.start(), range.start()); 218 assert_eq!(fold.range.start(), range.start());
221 assert_eq!(fold.range.end(), range.end()); 219 assert_eq!(fold.range.end(), range.end());
222 assert_eq!(&fold.kind, fold_kind); 220
221 let kind = match fold.kind {
222 FoldKind::Comment => "comment",
223 FoldKind::Imports => "imports",
224 FoldKind::Mods => "mods",
225 FoldKind::Block => "block",
226 FoldKind::ArgList => "arglist",
227 };
228 assert_eq!(kind, &attr.unwrap());
223 } 229 }
224 } 230 }
225 231
226 #[test] 232 #[test]
227 fn test_fold_comments() { 233 fn test_fold_comments() {
228 let text = r#" 234 check(
229<fold>// Hello 235 r#"
236<fold comment>// Hello
230// this is a multiline 237// this is a multiline
231// comment 238// comment
232//</fold> 239//</fold>
233 240
234// But this is not 241// But this is not
235 242
236fn main() <fold>{ 243fn main() <fold block>{
237 <fold>// We should 244 <fold comment>// We should
238 // also 245 // also
239 // fold 246 // fold
240 // this one.</fold> 247 // this one.</fold>
241 <fold>//! But this one is different 248 <fold comment>//! But this one is different
242 //! because it has another flavor</fold> 249 //! because it has another flavor</fold>
243 <fold>/* As does this 250 <fold comment>/* As does this
244 multiline comment */</fold> 251 multiline comment */</fold>
245}</fold>"#; 252}</fold>"#,
246 253 );
247 let fold_kinds = &[
248 FoldKind::Comment,
249 FoldKind::Block,
250 FoldKind::Comment,
251 FoldKind::Comment,
252 FoldKind::Comment,
253 ];
254 do_check(text, fold_kinds);
255 } 254 }
256 255
257 #[test] 256 #[test]
258 fn test_fold_imports() { 257 fn test_fold_imports() {
259 let text = r#" 258 check(
260<fold>use std::<fold>{ 259 r#"
260<fold imports>use std::<fold block>{
261 str, 261 str,
262 vec, 262 vec,
263 io as iop 263 io as iop
264}</fold>;</fold> 264}</fold>;</fold>
265 265
266fn main() <fold>{ 266fn main() <fold block>{
267}</fold>"#; 267}</fold>"#,
268 268 );
269 let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
270 do_check(text, folds);
271 } 269 }
272 270
273 #[test] 271 #[test]
274 fn test_fold_mods() { 272 fn test_fold_mods() {
275 let text = r#" 273 check(
274 r#"
276 275
277pub mod foo; 276pub mod foo;
278<fold>mod after_pub; 277<fold mods>mod after_pub;
279mod after_pub_next;</fold> 278mod after_pub_next;</fold>
280 279
281<fold>mod before_pub; 280<fold mods>mod before_pub;
282mod before_pub_next;</fold> 281mod before_pub_next;</fold>
283pub mod bar; 282pub mod bar;
284 283
@@ -286,90 +285,117 @@ mod not_folding_single;
286pub mod foobar; 285pub mod foobar;
287pub not_folding_single_next; 286pub not_folding_single_next;
288 287
289<fold>#[cfg(test)] 288<fold mods>#[cfg(test)]
290mod with_attribute; 289mod with_attribute;
291mod with_attribute_next;</fold> 290mod with_attribute_next;</fold>
292 291
293fn main() <fold>{ 292fn main() <fold block>{
294}</fold>"#; 293}</fold>"#,
295 294 );
296 let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
297 do_check(text, folds);
298 } 295 }
299 296
300 #[test] 297 #[test]
301 fn test_fold_import_groups() { 298 fn test_fold_import_groups() {
302 let text = r#" 299 check(
303<fold>use std::str; 300 r#"
301<fold imports>use std::str;
304use std::vec; 302use std::vec;
305use std::io as iop;</fold> 303use std::io as iop;</fold>
306 304
307<fold>use std::mem; 305<fold imports>use std::mem;
308use std::f64;</fold> 306use std::f64;</fold>
309 307
310use std::collections::HashMap; 308use std::collections::HashMap;
311// Some random comment 309// Some random comment
312use std::collections::VecDeque; 310use std::collections::VecDeque;
313 311
314fn main() <fold>{ 312fn main() <fold block>{
315}</fold>"#; 313}</fold>"#,
316 314 );
317 let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
318 do_check(text, folds);
319 } 315 }
320 316
321 #[test] 317 #[test]
322 fn test_fold_import_and_groups() { 318 fn test_fold_import_and_groups() {
323 let text = r#" 319 check(
324<fold>use std::str; 320 r#"
321<fold imports>use std::str;
325use std::vec; 322use std::vec;
326use std::io as iop;</fold> 323use std::io as iop;</fold>
327 324
328<fold>use std::mem; 325<fold imports>use std::mem;
329use std::f64;</fold> 326use std::f64;</fold>
330 327
331<fold>use std::collections::<fold>{ 328<fold imports>use std::collections::<fold block>{
332 HashMap, 329 HashMap,
333 VecDeque, 330 VecDeque,
334}</fold>;</fold> 331}</fold>;</fold>
335// Some random comment 332// Some random comment
336 333
337fn main() <fold>{ 334fn main() <fold block>{
338}</fold>"#; 335}</fold>"#,
339 336 );
340 let folds = &[
341 FoldKind::Imports,
342 FoldKind::Imports,
343 FoldKind::Imports,
344 FoldKind::Block,
345 FoldKind::Block,
346 ];
347 do_check(text, folds);
348 } 337 }
349 338
350 #[test] 339 #[test]
351 fn test_folds_macros() { 340 fn test_folds_macros() {
352 let text = r#" 341 check(
353macro_rules! foo <fold>{ 342 r#"
343macro_rules! foo <fold block>{
354 ($($tt:tt)*) => { $($tt)* } 344 ($($tt:tt)*) => { $($tt)* }
355}</fold> 345}</fold>
356"#; 346"#,
357 347 );
358 let folds = &[FoldKind::Block];
359 do_check(text, folds);
360 } 348 }
361 349
362 #[test] 350 #[test]
363 fn test_fold_match_arms() { 351 fn test_fold_match_arms() {
364 let text = r#" 352 check(
365fn main() <fold>{ 353 r#"
366 match 0 <fold>{ 354fn main() <fold block>{
355 match 0 <fold block>{
367 0 => 0, 356 0 => 0,
368 _ => 1, 357 _ => 1,
369 }</fold> 358 }</fold>
370}</fold>"#; 359}</fold>
360"#,
361 );
362 }
371 363
372 let folds = &[FoldKind::Block, FoldKind::Block]; 364 #[test]
373 do_check(text, folds); 365 fn fold_big_calls() {
366 check(
367 r#"
368fn main() <fold block>{
369 frobnicate<fold arglist>(
370 1,
371 2,
372 3,
373 )</fold>
374}</fold>
375"#,
376 )
377 }
378
379 #[test]
380 fn fold_record_literals() {
381 check(
382 r#"
383const _: S = S <fold block>{
384
385}</fold>;
386"#,
387 )
388 }
389
390 #[test]
391 fn fold_multiline_params() {
392 check(
393 r#"
394fn foo<fold arglist>(
395 x: i32,
396 y: String,
397)</fold> {}
398"#,
399 )
374 } 400 }
375} 401}
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index bea7fbfa7..4e3f428fa 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -7,7 +7,7 @@ use ra_syntax::{
7 ast::{self}, 7 ast::{self},
8 match_ast, AstNode, 8 match_ast, AstNode,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset, 10 SyntaxToken, TokenAtOffset, T,
11}; 11};
12 12
13use crate::{ 13use crate::{
@@ -32,9 +32,10 @@ pub(crate) fn goto_definition(
32 let file = sema.parse(position.file_id).syntax().clone(); 32 let file = sema.parse(position.file_id).syntax().clone();
33 let original_token = pick_best(file.token_at_offset(position.offset))?; 33 let original_token = pick_best(file.token_at_offset(position.offset))?;
34 let token = sema.descend_into_macros(original_token.clone()); 34 let token = sema.descend_into_macros(original_token.clone());
35 let parent = token.parent();
35 36
36 let nav_targets = match_ast! { 37 let nav_targets = match_ast! {
37 match (token.parent()) { 38 match parent {
38 ast::NameRef(name_ref) => { 39 ast::NameRef(name_ref) => {
39 reference_definition(&sema, &name_ref).to_vec() 40 reference_definition(&sema, &name_ref).to_vec()
40 }, 41 },
@@ -57,7 +58,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
57 return tokens.max_by_key(priority); 58 return tokens.max_by_key(priority);
58 fn priority(n: &SyntaxToken) -> usize { 59 fn priority(n: &SyntaxToken) -> usize {
59 match n.kind() { 60 match n.kind() {
60 IDENT | INT_NUMBER => 2, 61 IDENT | INT_NUMBER | T![self] => 2,
61 kind if kind.is_trivia() => 0, 62 kind if kind.is_trivia() => 0,
62 _ => 1, 63 _ => 1,
63 } 64 }
@@ -103,205 +104,150 @@ pub(crate) fn reference_definition(
103 104
104#[cfg(test)] 105#[cfg(test)]
105mod tests { 106mod tests {
106 use test_utils::assert_eq_text; 107 use ra_db::FileRange;
107 108 use ra_syntax::{TextRange, TextSize};
108 use crate::mock_analysis::analysis_and_position; 109
109 110 use crate::mock_analysis::MockAnalysis;
110 fn check_goto(ra_fixture: &str, expected: &str, expected_range: &str) { 111
111 let (analysis, pos) = analysis_and_position(ra_fixture); 112 fn check(ra_fixture: &str) {
113 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
114 let (mut expected, data) = mock.annotation();
115 let analysis = mock.analysis();
116 match data.as_str() {
117 "" => (),
118 "file" => {
119 expected.range =
120 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
121 }
122 data => panic!("bad data: {}", data),
123 }
112 124
113 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 125 let mut navs =
126 analysis.goto_definition(position).unwrap().expect("no definition found").info;
114 if navs.len() == 0 { 127 if navs.len() == 0 {
115 panic!("unresolved reference") 128 panic!("unresolved reference")
116 } 129 }
117 assert_eq!(navs.len(), 1); 130 assert_eq!(navs.len(), 1);
118 131
119 let nav = navs.pop().unwrap(); 132 let nav = navs.pop().unwrap();
120 let file_text = analysis.file_text(nav.file_id()).unwrap(); 133 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
121
122 let mut actual = file_text[nav.full_range()].to_string();
123 if let Some(focus) = nav.focus_range() {
124 actual += "|";
125 actual += &file_text[focus];
126 }
127
128 if !expected_range.contains("...") {
129 test_utils::assert_eq_text!(&actual, expected_range);
130 } else {
131 let mut parts = expected_range.split("...");
132 let prefix = parts.next().unwrap();
133 let suffix = parts.next().unwrap();
134 assert!(
135 actual.starts_with(prefix) && actual.ends_with(suffix),
136 "\nExpected: {}\n Actual: {}\n",
137 expected_range,
138 actual
139 );
140 }
141
142 nav.assert_match(expected);
143 } 134 }
144 135
145 #[test] 136 #[test]
146 fn goto_def_in_items() { 137 fn goto_def_in_items() {
147 check_goto( 138 check(
148 " 139 r#"
149 //- /lib.rs 140struct Foo;
150 struct Foo; 141 //^^^
151 enum E { X(Foo<|>) } 142enum E { X(Foo<|>) }
152 ", 143"#,
153 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
154 "struct Foo;|Foo",
155 ); 144 );
156 } 145 }
157 146
158 #[test] 147 #[test]
159 fn goto_def_at_start_of_item() { 148 fn goto_def_at_start_of_item() {
160 check_goto( 149 check(
161 " 150 r#"
162 //- /lib.rs 151struct Foo;
163 struct Foo; 152 //^^^
164 enum E { X(<|>Foo) } 153enum E { X(<|>Foo) }
165 ", 154"#,
166 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
167 "struct Foo;|Foo",
168 ); 155 );
169 } 156 }
170 157
171 #[test] 158 #[test]
172 fn goto_definition_resolves_correct_name() { 159 fn goto_definition_resolves_correct_name() {
173 check_goto( 160 check(
174 " 161 r#"
175 //- /lib.rs 162//- /lib.rs
176 use a::Foo; 163use a::Foo;
177 mod a; 164mod a;
178 mod b; 165mod b;
179 enum E { X(Foo<|>) } 166enum E { X(Foo<|>) }
180 167
181 //- /a.rs 168//- /a.rs
182 struct Foo; 169struct Foo;
183 170 //^^^
184 //- /b.rs 171//- /b.rs
185 struct Foo; 172struct Foo;
186 ", 173"#,
187 "Foo STRUCT_DEF FileId(2) 0..11 7..10",
188 "struct Foo;|Foo",
189 ); 174 );
190 } 175 }
191 176
192 #[test] 177 #[test]
193 fn goto_def_for_module_declaration() { 178 fn goto_def_for_module_declaration() {
194 check_goto( 179 check(
195 r#" 180 r#"
196//- /lib.rs 181//- /lib.rs
197mod <|>foo; 182mod <|>foo;
198 183
199//- /foo.rs 184//- /foo.rs
200// empty 185// empty
186//^ file
201"#, 187"#,
202 "foo SOURCE_FILE FileId(2) 0..9",
203 "// empty\n",
204 ); 188 );
205 189
206 check_goto( 190 check(
207 r#" 191 r#"
208//- /lib.rs 192//- /lib.rs
209mod <|>foo; 193mod <|>foo;
210 194
211//- /foo/mod.rs 195//- /foo/mod.rs
212// empty 196// empty
197//^ file
213"#, 198"#,
214 "foo SOURCE_FILE FileId(2) 0..9",
215 "// empty\n",
216 ); 199 );
217 } 200 }
218 201
219 #[test] 202 #[test]
220 fn goto_def_for_macros() { 203 fn goto_def_for_macros() {
221 check_goto( 204 check(
222 " 205 r#"
223 //- /lib.rs 206macro_rules! foo { () => { () } }
224 macro_rules! foo { () => { () } } 207 //^^^
225 208fn bar() {
226 fn bar() { 209 <|>foo!();
227 <|>foo!(); 210}
228 } 211"#,
229 ",
230 "foo MACRO_CALL FileId(1) 0..33 13..16",
231 "macro_rules! foo { () => { () } }|foo",
232 ); 212 );
233 } 213 }
234 214
235 #[test] 215 #[test]
236 fn goto_def_for_macros_from_other_crates() { 216 fn goto_def_for_macros_from_other_crates() {
237 check_goto( 217 check(
238 "
239 //- /lib.rs
240 use foo::foo;
241 fn bar() {
242 <|>foo!();
243 }
244
245 //- /foo/lib.rs
246 #[macro_export]
247 macro_rules! foo { () => { () } }
248 ",
249 "foo MACRO_CALL FileId(2) 0..49 29..32",
250 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
251 );
252 }
253
254 #[test]
255 fn goto_def_for_use_alias() {
256 check_goto(
257 r#" 218 r#"
258//- /lib.rs 219//- /lib.rs
259use foo as bar<|>; 220use foo::foo;
221fn bar() {
222 <|>foo!();
223}
260 224
261//- /foo/lib.rs 225//- /foo/lib.rs
262#[macro_export] 226#[macro_export]
263macro_rules! foo { () => { () } } 227macro_rules! foo { () => { () } }
228 //^^^
264"#, 229"#,
265 "SOURCE_FILE FileId(2) 0..50",
266 "#[macro_export]\nmacro_rules! foo { () => { () } }\n",
267 );
268 }
269
270 #[test]
271 fn goto_def_for_use_alias_foo_macro() {
272 check_goto(
273 "
274 //- /lib.rs
275 use foo::foo as bar<|>;
276
277 //- /foo/lib.rs
278 #[macro_export]
279 macro_rules! foo { () => { () } }
280 ",
281 "foo MACRO_CALL FileId(2) 0..49 29..32",
282 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
283 ); 230 );
284 } 231 }
285 232
286 #[test] 233 #[test]
287 fn goto_def_for_macros_in_use_tree() { 234 fn goto_def_for_macros_in_use_tree() {
288 check_goto( 235 check(
289 " 236 r#"
290 //- /lib.rs 237//- /lib.rs
291 use foo::foo<|>; 238use foo::foo<|>;
292 239
293 //- /foo/lib.rs 240//- /foo/lib.rs
294 #[macro_export] 241#[macro_export]
295 macro_rules! foo { () => { () } } 242macro_rules! foo { () => { () } }
296 ", 243 //^^^
297 "foo MACRO_CALL FileId(2) 0..49 29..32", 244"#,
298 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
299 ); 245 );
300 } 246 }
301 247
302 #[test] 248 #[test]
303 fn goto_def_for_macro_defined_fn_with_arg() { 249 fn goto_def_for_macro_defined_fn_with_arg() {
304 check_goto( 250 check(
305 r#" 251 r#"
306//- /lib.rs 252//- /lib.rs
307macro_rules! define_fn { 253macro_rules! define_fn {
@@ -309,522 +255,478 @@ macro_rules! define_fn {
309} 255}
310 256
311define_fn!(foo); 257define_fn!(foo);
258 //^^^
312 259
313fn bar() { 260fn bar() {
314 <|>foo(); 261 <|>foo();
315} 262}
316"#, 263"#,
317 "foo FN_DEF FileId(1) 65..81 76..79",
318 "define_fn!(foo);|foo",
319 ); 264 );
320 } 265 }
321 266
322 #[test] 267 #[test]
323 fn goto_def_for_macro_defined_fn_no_arg() { 268 fn goto_def_for_macro_defined_fn_no_arg() {
324 check_goto( 269 check(
325 r#" 270 r#"
326//- /lib.rs 271//- /lib.rs
327macro_rules! define_fn { 272macro_rules! define_fn {
328 () => (fn foo() {}) 273 () => (fn foo() {})
329} 274}
330 275
331define_fn!(); 276 define_fn!();
277//^^^^^^^^^^^^^
332 278
333fn bar() { 279fn bar() {
334 <|>foo(); 280 <|>foo();
335} 281}
336"#, 282"#,
337 "foo FN_DEF FileId(1) 52..65 52..65",
338 "define_fn!();|define_fn!();",
339 ); 283 );
340 } 284 }
341 285
342 #[test] 286 #[test]
343 fn goto_definition_works_for_macro_inside_pattern() { 287 fn goto_definition_works_for_macro_inside_pattern() {
344 check_goto( 288 check(
345 " 289 r#"
346 //- /lib.rs 290//- /lib.rs
347 macro_rules! foo {() => {0}} 291macro_rules! foo {() => {0}}
348 292 //^^^
349 fn bar() { 293
350 match (0,1) { 294fn bar() {
351 (<|>foo!(), _) => {} 295 match (0,1) {
352 } 296 (<|>foo!(), _) => {}
353 } 297 }
354 ", 298}
355 "foo MACRO_CALL FileId(1) 0..28 13..16", 299"#,
356 "macro_rules! foo {() => {0}}|foo",
357 ); 300 );
358 } 301 }
359 302
360 #[test] 303 #[test]
361 fn goto_definition_works_for_macro_inside_match_arm_lhs() { 304 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
362 check_goto( 305 check(
363 " 306 r#"
364 //- /lib.rs 307//- /lib.rs
365 macro_rules! foo {() => {0}} 308macro_rules! foo {() => {0}}
366 309 //^^^
367 fn bar() { 310fn bar() {
368 match 0 { 311 match 0 {
369 <|>foo!() => {} 312 <|>foo!() => {}
370 } 313 }
371 } 314}
372 ", 315"#,
373 "foo MACRO_CALL FileId(1) 0..28 13..16", 316 );
374 "macro_rules! foo {() => {0}}|foo", 317 }
318
319 #[test]
320 fn goto_def_for_use_alias() {
321 check(
322 r#"
323//- /lib.rs
324use foo as bar<|>;
325
326//- /foo/lib.rs
327// empty
328//^ file
329"#,
330 );
331 }
332
333 #[test]
334 fn goto_def_for_use_alias_foo_macro() {
335 check(
336 r#"
337//- /lib.rs
338use foo::foo as bar<|>;
339
340//- /foo/lib.rs
341#[macro_export]
342macro_rules! foo { () => { () } }
343 //^^^
344"#,
375 ); 345 );
376 } 346 }
377 347
378 #[test] 348 #[test]
379 fn goto_def_for_methods() { 349 fn goto_def_for_methods() {
380 check_goto( 350 check(
381 " 351 r#"
382 //- /lib.rs 352//- /lib.rs
383 struct Foo; 353struct Foo;
384 impl Foo { 354impl Foo {
385 fn frobnicate(&self) { } 355 fn frobnicate(&self) { }
386 } 356 //^^^^^^^^^^
357}
387 358
388 fn bar(foo: &Foo) { 359fn bar(foo: &Foo) {
389 foo.frobnicate<|>(); 360 foo.frobnicate<|>();
390 } 361}
391 ", 362"#,
392 "frobnicate FN_DEF FileId(1) 27..51 30..40",
393 "fn frobnicate(&self) { }|frobnicate",
394 ); 363 );
395 } 364 }
396 365
397 #[test] 366 #[test]
398 fn goto_def_for_fields() { 367 fn goto_def_for_fields() {
399 check_goto( 368 check(
400 r" 369 r#"
401 //- /lib.rs 370struct Foo {
402 struct Foo { 371 spam: u32,
403 spam: u32, 372} //^^^^
404 }
405 373
406 fn bar(foo: &Foo) { 374fn bar(foo: &Foo) {
407 foo.spam<|>; 375 foo.spam<|>;
408 } 376}
409 ", 377"#,
410 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
411 "spam: u32|spam",
412 ); 378 );
413 } 379 }
414 380
415 #[test] 381 #[test]
416 fn goto_def_for_record_fields() { 382 fn goto_def_for_record_fields() {
417 check_goto( 383 check(
418 r" 384 r#"
419 //- /lib.rs 385//- /lib.rs
420 struct Foo { 386struct Foo {
421 spam: u32, 387 spam: u32,
422 } 388} //^^^^
423 389
424 fn bar() -> Foo { 390fn bar() -> Foo {
425 Foo { 391 Foo {
426 spam<|>: 0, 392 spam<|>: 0,
427 } 393 }
428 } 394}
429 ", 395"#,
430 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
431 "spam: u32|spam",
432 ); 396 );
433 } 397 }
434 398
435 #[test] 399 #[test]
436 fn goto_def_for_record_pat_fields() { 400 fn goto_def_for_record_pat_fields() {
437 check_goto( 401 check(
438 r" 402 r#"
439 //- /lib.rs 403//- /lib.rs
440 struct Foo { 404struct Foo {
441 spam: u32, 405 spam: u32,
442 } 406} //^^^^
443 407
444 fn bar(foo: Foo) -> Foo { 408fn bar(foo: Foo) -> Foo {
445 let Foo { spam<|>: _, } = foo 409 let Foo { spam<|>: _, } = foo
446 } 410}
447 ", 411"#,
448 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
449 "spam: u32|spam",
450 ); 412 );
451 } 413 }
452 414
453 #[test] 415 #[test]
454 fn goto_def_for_record_fields_macros() { 416 fn goto_def_for_record_fields_macros() {
455 check_goto( 417 check(
456 r" 418 r"
457 //- /lib.rs 419macro_rules! m { () => { 92 };}
458 macro_rules! m { () => { 92 };} 420struct Foo { spam: u32 }
459 struct Foo { spam: u32 } 421 //^^^^
460 422
461 fn bar() -> Foo { 423fn bar() -> Foo {
462 Foo { spam<|>: m!() } 424 Foo { spam<|>: m!() }
463 } 425}
464 ", 426",
465 "spam RECORD_FIELD_DEF FileId(1) 45..54 45..49",
466 "spam: u32|spam",
467 ); 427 );
468 } 428 }
469 429
470 #[test] 430 #[test]
471 fn goto_for_tuple_fields() { 431 fn goto_for_tuple_fields() {
472 check_goto( 432 check(
473 " 433 r#"
474 //- /lib.rs 434struct Foo(u32);
475 struct Foo(u32); 435 //^^^
476 436
477 fn bar() { 437fn bar() {
478 let foo = Foo(0); 438 let foo = Foo(0);
479 foo.<|>0; 439 foo.<|>0;
480 } 440}
481 ", 441"#,
482 "TUPLE_FIELD_DEF FileId(1) 11..14",
483 "u32",
484 ); 442 );
485 } 443 }
486 444
487 #[test] 445 #[test]
488 fn goto_def_for_ufcs_inherent_methods() { 446 fn goto_def_for_ufcs_inherent_methods() {
489 check_goto( 447 check(
490 " 448 r#"
491 //- /lib.rs 449struct Foo;
492 struct Foo; 450impl Foo {
493 impl Foo { 451 fn frobnicate() { }
494 fn frobnicate() { } 452} //^^^^^^^^^^
495 }
496 453
497 fn bar(foo: &Foo) { 454fn bar(foo: &Foo) {
498 Foo::frobnicate<|>(); 455 Foo::frobnicate<|>();
499 } 456}
500 ", 457"#,
501 "frobnicate FN_DEF FileId(1) 27..46 30..40",
502 "fn frobnicate() { }|frobnicate",
503 ); 458 );
504 } 459 }
505 460
506 #[test] 461 #[test]
507 fn goto_def_for_ufcs_trait_methods_through_traits() { 462 fn goto_def_for_ufcs_trait_methods_through_traits() {
508 check_goto( 463 check(
509 " 464 r#"
510 //- /lib.rs 465trait Foo {
511 trait Foo { 466 fn frobnicate();
512 fn frobnicate(); 467} //^^^^^^^^^^
513 }
514 468
515 fn bar() { 469fn bar() {
516 Foo::frobnicate<|>(); 470 Foo::frobnicate<|>();
517 } 471}
518 ", 472"#,
519 "frobnicate FN_DEF FileId(1) 16..32 19..29",
520 "fn frobnicate();|frobnicate",
521 ); 473 );
522 } 474 }
523 475
524 #[test] 476 #[test]
525 fn goto_def_for_ufcs_trait_methods_through_self() { 477 fn goto_def_for_ufcs_trait_methods_through_self() {
526 check_goto( 478 check(
527 " 479 r#"
528 //- /lib.rs 480struct Foo;
529 struct Foo; 481trait Trait {
530 trait Trait { 482 fn frobnicate();
531 fn frobnicate(); 483} //^^^^^^^^^^
532 } 484impl Trait for Foo {}
533 impl Trait for Foo {}
534 485
535 fn bar() { 486fn bar() {
536 Foo::frobnicate<|>(); 487 Foo::frobnicate<|>();
537 } 488}
538 ", 489"#,
539 "frobnicate FN_DEF FileId(1) 30..46 33..43",
540 "fn frobnicate();|frobnicate",
541 ); 490 );
542 } 491 }
543 492
544 #[test] 493 #[test]
545 fn goto_definition_on_self() { 494 fn goto_definition_on_self() {
546 check_goto( 495 check(
547 " 496 r#"
548 //- /lib.rs 497struct Foo;
549 struct Foo; 498impl Foo {
550 impl Foo { 499 //^^^
551 pub fn new() -> Self { 500 pub fn new() -> Self {
552 Self<|> {} 501 Self<|> {}
553 } 502 }
554 } 503}
555 ", 504"#,
556 "impl IMPL_DEF FileId(1) 12..73", 505 );
557 "impl Foo {...}", 506 check(
558 ); 507 r#"
559 508struct Foo;
560 check_goto( 509impl Foo {
561 " 510 //^^^
562 //- /lib.rs 511 pub fn new() -> Self<|> {
563 struct Foo; 512 Self {}
564 impl Foo { 513 }
565 pub fn new() -> Self<|> { 514}
566 Self {} 515"#,
567 } 516 );
568 } 517
569 ", 518 check(
570 "impl IMPL_DEF FileId(1) 12..73", 519 r#"
571 "impl Foo {...}", 520enum Foo { A }
572 ); 521impl Foo {
573 522 //^^^
574 check_goto( 523 pub fn new() -> Self<|> {
575 " 524 Foo::A
576 //- /lib.rs 525 }
577 enum Foo { A } 526}
578 impl Foo { 527"#,
579 pub fn new() -> Self<|> { 528 );
580 Foo::A 529
581 } 530 check(
582 } 531 r#"
583 ", 532enum Foo { A }
584 "impl IMPL_DEF FileId(1) 15..75", 533impl Foo {
585 "impl Foo {...}", 534 //^^^
586 ); 535 pub fn thing(a: &Self<|>) {
587 536 }
588 check_goto( 537}
589 " 538"#,
590 //- /lib.rs
591 enum Foo { A }
592 impl Foo {
593 pub fn thing(a: &Self<|>) {
594 }
595 }
596 ",
597 "impl IMPL_DEF FileId(1) 15..62",
598 "impl Foo {...}",
599 ); 539 );
600 } 540 }
601 541
602 #[test] 542 #[test]
603 fn goto_definition_on_self_in_trait_impl() { 543 fn goto_definition_on_self_in_trait_impl() {
604 check_goto( 544 check(
605 " 545 r#"
606 //- /lib.rs 546struct Foo;
607 struct Foo; 547trait Make {
608 trait Make { 548 fn new() -> Self;
609 fn new() -> Self; 549}
610 } 550impl Make for Foo {
611 impl Make for Foo { 551 //^^^
612 fn new() -> Self { 552 fn new() -> Self {
613 Self<|> {} 553 Self<|> {}
614 } 554 }
615 } 555}
616 ", 556"#,
617 "impl IMPL_DEF FileId(1) 49..115",
618 "impl Make for Foo {...}",
619 ); 557 );
620 558
621 check_goto( 559 check(
622 " 560 r#"
623 //- /lib.rs 561struct Foo;
624 struct Foo; 562trait Make {
625 trait Make { 563 fn new() -> Self;
626 fn new() -> Self; 564}
627 } 565impl Make for Foo {
628 impl Make for Foo { 566 //^^^
629 fn new() -> Self<|> { 567 fn new() -> Self<|> {
630 Self {} 568 Self {}
631 } 569 }
632 } 570}
633 ", 571"#,
634 "impl IMPL_DEF FileId(1) 49..115",
635 "impl Make for Foo {...}",
636 ); 572 );
637 } 573 }
638 574
639 #[test] 575 #[test]
640 fn goto_def_when_used_on_definition_name_itself() { 576 fn goto_def_when_used_on_definition_name_itself() {
641 check_goto( 577 check(
642 " 578 r#"
643 //- /lib.rs 579struct Foo<|> { value: u32 }
644 struct Foo<|> { value: u32 } 580 //^^^
645 ", 581 "#,
646 "Foo STRUCT_DEF FileId(1) 0..25 7..10",
647 "struct Foo { value: u32 }|Foo",
648 ); 582 );
649 583
650 check_goto( 584 check(
651 r#" 585 r#"
652 //- /lib.rs 586struct Foo {
653 struct Foo { 587 field<|>: string,
654 field<|>: string, 588} //^^^^^
655 } 589"#,
656 "#,
657 "field RECORD_FIELD_DEF FileId(1) 17..30 17..22",
658 "field: string|field",
659 ); 590 );
660 591
661 check_goto( 592 check(
662 " 593 r#"
663 //- /lib.rs 594fn foo_test<|>() { }
664 fn foo_test<|>() { } 595 //^^^^^^^^
665 ", 596"#,
666 "foo_test FN_DEF FileId(1) 0..17 3..11",
667 "fn foo_test() { }|foo_test",
668 ); 597 );
669 598
670 check_goto( 599 check(
671 " 600 r#"
672 //- /lib.rs 601enum Foo<|> { Variant }
673 enum Foo<|> { 602 //^^^
674 Variant, 603"#,
675 }
676 ",
677 "Foo ENUM_DEF FileId(1) 0..25 5..8",
678 "enum Foo {...}|Foo",
679 );
680
681 check_goto(
682 "
683 //- /lib.rs
684 enum Foo {
685 Variant1,
686 Variant2<|>,
687 Variant3,
688 }
689 ",
690 "Variant2 ENUM_VARIANT FileId(1) 29..37 29..37",
691 "Variant2|Variant2",
692 ); 604 );
693 605
694 check_goto( 606 check(
695 r#" 607 r#"
696 //- /lib.rs 608enum Foo {
697 static INNER<|>: &str = ""; 609 Variant1,
698 "#, 610 Variant2<|>,
699 "INNER STATIC_DEF FileId(1) 0..24 7..12", 611 //^^^^^^^^
700 "static INNER: &str = \"\";|INNER", 612 Variant3,
613}
614"#,
701 ); 615 );
702 616
703 check_goto( 617 check(
704 r#" 618 r#"
705 //- /lib.rs 619static INNER<|>: &str = "";
706 const INNER<|>: &str = ""; 620 //^^^^^
707 "#, 621"#,
708 "INNER CONST_DEF FileId(1) 0..23 6..11",
709 "const INNER: &str = \"\";|INNER",
710 ); 622 );
711 623
712 check_goto( 624 check(
713 r#" 625 r#"
714 //- /lib.rs 626const INNER<|>: &str = "";
715 type Thing<|> = Option<()>; 627 //^^^^^
716 "#, 628"#,
717 "Thing TYPE_ALIAS_DEF FileId(1) 0..24 5..10",
718 "type Thing = Option<()>;|Thing",
719 ); 629 );
720 630
721 check_goto( 631 check(
722 r#" 632 r#"
723 //- /lib.rs 633type Thing<|> = Option<()>;
724 trait Foo<|> { } 634 //^^^^^
725 "#, 635"#,
726 "Foo TRAIT_DEF FileId(1) 0..13 6..9",
727 "trait Foo { }|Foo",
728 ); 636 );
729 637
730 check_goto( 638 check(
731 r#" 639 r#"
732 //- /lib.rs 640trait Foo<|> { }
733 mod bar<|> { } 641 //^^^
734 "#, 642"#,
735 "bar MODULE FileId(1) 0..11 4..7", 643 );
736 "mod bar { }|bar", 644
645 check(
646 r#"
647mod bar<|> { }
648 //^^^
649"#,
737 ); 650 );
738 } 651 }
739 652
740 #[test] 653 #[test]
741 fn goto_from_macro() { 654 fn goto_from_macro() {
742 check_goto( 655 check(
743 " 656 r#"
744 //- /lib.rs 657macro_rules! id {
745 macro_rules! id { 658 ($($tt:tt)*) => { $($tt)* }
746 ($($tt:tt)*) => { $($tt)* } 659}
747 } 660fn foo() {}
748 fn foo() {} 661 //^^^
749 id! { 662id! {
750 fn bar() { 663 fn bar() {
751 fo<|>o(); 664 fo<|>o();
752 } 665 }
753 } 666}
754 mod confuse_index { fn foo(); } 667mod confuse_index { fn foo(); }
755 ", 668"#,
756 "foo FN_DEF FileId(1) 52..63 55..58",
757 "fn foo() {}|foo",
758 ); 669 );
759 } 670 }
760 671
761 #[test] 672 #[test]
762 fn goto_through_format() { 673 fn goto_through_format() {
763 check_goto( 674 check(
764 " 675 r#"
765 //- /lib.rs 676#[macro_export]
766 #[macro_export] 677macro_rules! format {
767 macro_rules! format { 678 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
768 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) 679}
769 } 680#[rustc_builtin_macro]
770 #[rustc_builtin_macro] 681#[macro_export]
771 #[macro_export] 682macro_rules! format_args {
772 macro_rules! format_args { 683 ($fmt:expr) => ({ /* compiler built-in */ });
773 ($fmt:expr) => ({ /* compiler built-in */ }); 684 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
774 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) 685}
775 } 686pub mod __export {
776 pub mod __export { 687 pub use crate::format_args;
777 pub use crate::format_args; 688 fn foo() {} // for index confusion
778 fn foo() {} // for index confusion 689}
779 } 690fn foo() -> i8 {}
780 fn foo() -> i8 {} 691 //^^^
781 fn test() { 692fn test() {
782 format!(\"{}\", fo<|>o()) 693 format!("{}", fo<|>o())
783 } 694}
784 ", 695"#,
785 "foo FN_DEF FileId(1) 398..415 401..404",
786 "fn foo() -> i8 {}|foo",
787 ); 696 );
788 } 697 }
789 698
790 #[test] 699 #[test]
791 fn goto_for_type_param() { 700 fn goto_for_type_param() {
792 check_goto( 701 check(
793 r#" 702 r#"
794 //- /lib.rs 703struct Foo<T: Clone> { t: <|>T }
795 struct Foo<T: Clone> { 704 //^
796 t: <|>T, 705"#,
797 }
798 "#,
799 "T TYPE_PARAM FileId(1) 11..19 11..12",
800 "T: Clone|T",
801 ); 706 );
802 } 707 }
803 708
804 #[test] 709 #[test]
805 fn goto_within_macro() { 710 fn goto_within_macro() {
806 check_goto( 711 check(
807 r#" 712 r#"
808//- /lib.rs
809macro_rules! id { 713macro_rules! id {
810 ($($tt:tt)*) => ($($tt)*) 714 ($($tt:tt)*) => ($($tt)*)
811} 715}
812 716
813fn foo() { 717fn foo() {
814 let x = 1; 718 let x = 1;
719 //^
815 id!({ 720 id!({
816 let y = <|>x; 721 let y = <|>x;
817 let z = y; 722 let z = y;
818 }); 723 });
819} 724}
820"#, 725"#,
821 "x BIND_PAT FileId(1) 70..71",
822 "x",
823 ); 726 );
824 727
825 check_goto( 728 check(
826 r#" 729 r#"
827//- /lib.rs
828macro_rules! id { 730macro_rules! id {
829 ($($tt:tt)*) => ($($tt)*) 731 ($($tt:tt)*) => ($($tt)*)
830} 732}
@@ -833,159 +735,233 @@ fn foo() {
833 let x = 1; 735 let x = 1;
834 id!({ 736 id!({
835 let y = x; 737 let y = x;
738 //^
836 let z = <|>y; 739 let z = <|>y;
837 }); 740 });
838} 741}
839"#, 742"#,
840 "y BIND_PAT FileId(1) 99..100",
841 "y",
842 ); 743 );
843 } 744 }
844 745
845 #[test] 746 #[test]
846 fn goto_def_in_local_fn() { 747 fn goto_def_in_local_fn() {
847 check_goto( 748 check(
848 " 749 r#"
849 //- /lib.rs 750fn main() {
850 fn main() { 751 fn foo() {
851 fn foo() { 752 let x = 92;
852 let x = 92; 753 //^
853 <|>x; 754 <|>x;
854 } 755 }
855 } 756}
856 ", 757"#,
857 "x BIND_PAT FileId(1) 39..40",
858 "x",
859 ); 758 );
860 } 759 }
861 760
862 #[test] 761 #[test]
863 fn goto_def_in_local_macro() { 762 fn goto_def_in_local_macro() {
864 check_goto( 763 check(
865 r" 764 r#"
866 //- /lib.rs 765fn bar() {
867 fn bar() { 766 macro_rules! foo { () => { () } }
868 macro_rules! foo { () => { () } } 767 //^^^
869 <|>foo!(); 768 <|>foo!();
870 } 769}
871 ", 770"#,
872 "foo MACRO_CALL FileId(1) 15..48 28..31",
873 "macro_rules! foo { () => { () } }|foo",
874 ); 771 );
875 } 772 }
876 773
877 #[test] 774 #[test]
878 fn goto_def_for_field_init_shorthand() { 775 fn goto_def_for_field_init_shorthand() {
879 check_goto( 776 check(
880 " 777 r#"
881 //- /lib.rs 778struct Foo { x: i32 }
882 struct Foo { x: i32 } 779fn main() {
883 fn main() { 780 let x = 92;
884 let x = 92; 781 //^
885 Foo { x<|> }; 782 Foo { x<|> };
886 } 783}
887 ", 784"#,
888 "x BIND_PAT FileId(1) 42..43",
889 "x",
890 ) 785 )
891 } 786 }
892 787
893 #[test] 788 #[test]
894 fn goto_def_for_enum_variant_field() { 789 fn goto_def_for_enum_variant_field() {
895 check_goto( 790 check(
896 " 791 r#"
897 //- /lib.rs 792enum Foo {
898 enum Foo { 793 Bar { x: i32 }
899 Bar { x: i32 } 794} //^
900 } 795fn baz(foo: Foo) {
901 fn baz(foo: Foo) { 796 match foo {
902 match foo { 797 Foo::Bar { x<|> } => x
903 Foo::Bar { x<|> } => x 798 };
904 }; 799}
905 } 800"#,
906 ",
907 "x RECORD_FIELD_DEF FileId(1) 21..27 21..22",
908 "x: i32|x",
909 ); 801 );
910 } 802 }
911 803
912 #[test] 804 #[test]
913 fn goto_def_for_enum_variant_self_pattern_const() { 805 fn goto_def_for_enum_variant_self_pattern_const() {
914 check_goto( 806 check(
915 " 807 r#"
916 //- /lib.rs 808enum Foo { Bar }
917 enum Foo { 809 //^^^
918 Bar, 810impl Foo {
919 } 811 fn baz(self) {
920 impl Foo { 812 match self { Self::Bar<|> => {} }
921 fn baz(self) { 813 }
922 match self { 814}
923 Self::Bar<|> => {} 815"#,
924 }
925 }
926 }
927 ",
928 "Bar ENUM_VARIANT FileId(1) 15..18 15..18",
929 "Bar|Bar",
930 ); 816 );
931 } 817 }
932 818
933 #[test] 819 #[test]
934 fn goto_def_for_enum_variant_self_pattern_record() { 820 fn goto_def_for_enum_variant_self_pattern_record() {
935 check_goto( 821 check(
936 " 822 r#"
937 //- /lib.rs 823enum Foo { Bar { val: i32 } }
938 enum Foo { 824 //^^^
939 Bar { val: i32 }, 825impl Foo {
940 } 826 fn baz(self) -> i32 {
941 impl Foo { 827 match self { Self::Bar<|> { val } => {} }
942 fn baz(self) -> i32 { 828 }
943 match self { 829}
944 Self::Bar<|> { val } => {} 830"#,
945 }
946 }
947 }
948 ",
949 "Bar ENUM_VARIANT FileId(1) 15..31 15..18",
950 "Bar { val: i32 }|Bar",
951 ); 831 );
952 } 832 }
953 833
954 #[test] 834 #[test]
955 fn goto_def_for_enum_variant_self_expr_const() { 835 fn goto_def_for_enum_variant_self_expr_const() {
956 check_goto( 836 check(
957 " 837 r#"
958 //- /lib.rs 838enum Foo { Bar }
959 enum Foo { 839 //^^^
960 Bar, 840impl Foo {
961 } 841 fn baz(self) { Self::Bar<|>; }
962 impl Foo { 842}
963 fn baz(self) { 843"#,
964 Self::Bar<|>;
965 }
966 }
967 ",
968 "Bar ENUM_VARIANT FileId(1) 15..18 15..18",
969 "Bar|Bar",
970 ); 844 );
971 } 845 }
972 846
973 #[test] 847 #[test]
974 fn goto_def_for_enum_variant_self_expr_record() { 848 fn goto_def_for_enum_variant_self_expr_record() {
975 check_goto( 849 check(
976 " 850 r#"
977 //- /lib.rs 851enum Foo { Bar { val: i32 } }
978 enum Foo { 852 //^^^
979 Bar { val: i32 }, 853impl Foo {
980 } 854 fn baz(self) { Self::Bar<|> {val: 4}; }
981 impl Foo { 855}
982 fn baz(self) { 856"#,
983 Self::Bar<|> {val: 4}; 857 );
984 } 858 }
985 } 859
986 ", 860 #[test]
987 "Bar ENUM_VARIANT FileId(1) 15..31 15..18", 861 fn goto_def_for_type_alias_generic_parameter() {
988 "Bar { val: i32 }|Bar", 862 check(
863 r#"
864type Alias<T> = T<|>;
865 //^
866"#,
867 )
868 }
869
870 #[test]
871 fn goto_def_for_macro_container() {
872 check(
873 r#"
874//- /lib.rs
875foo::module<|>::mac!();
876
877//- /foo/lib.rs
878pub mod module {
879 //^^^^^^
880 #[macro_export]
881 macro_rules! _mac { () => { () } }
882 pub use crate::_mac as mac;
883}
884"#,
885 );
886 }
887
888 #[test]
889 fn goto_def_for_assoc_ty_in_path() {
890 check(
891 r#"
892trait Iterator {
893 type Item;
894 //^^^^
895}
896
897fn f() -> impl Iterator<Item<|> = u8> {}
898"#,
899 );
900 }
901
902 #[test]
903 fn goto_def_for_assoc_ty_in_path_multiple() {
904 check(
905 r#"
906trait Iterator {
907 type A;
908 //^
909 type B;
910}
911
912fn f() -> impl Iterator<A<|> = u8, B = ()> {}
913"#,
914 );
915 check(
916 r#"
917trait Iterator {
918 type A;
919 type B;
920 //^
921}
922
923fn f() -> impl Iterator<A = u8, B<|> = ()> {}
924"#,
925 );
926 }
927
928 #[test]
929 fn goto_def_for_assoc_ty_ufcs() {
930 check(
931 r#"
932trait Iterator {
933 type Item;
934 //^^^^
935}
936
937fn g() -> <() as Iterator<Item<|> = ()>>::Item {}
938"#,
939 );
940 }
941
942 #[test]
943 fn goto_def_for_assoc_ty_ufcs_multiple() {
944 check(
945 r#"
946trait Iterator {
947 type A;
948 //^
949 type B;
950}
951
952fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {}
953"#,
954 );
955 check(
956 r#"
957trait Iterator {
958 type A;
959 type B;
960 //^
961}
962
963fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {}
964"#,
989 ); 965 );
990 } 966 }
991} 967}
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs
index 0cec0657e..9912b7142 100644
--- a/crates/ra_ide/src/goto_implementation.rs
+++ b/crates/ra_ide/src/goto_implementation.rs
@@ -23,12 +23,12 @@ pub(crate) fn goto_implementation(
23 23
24 let krate = sema.to_module_def(position.file_id)?.krate(); 24 let krate = sema.to_module_def(position.file_id)?.krate();
25 25
26 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) { 26 if let Some(nominal_def) = find_node_at_offset::<ast::AdtDef>(&syntax, position.offset) {
27 return Some(RangeInfo::new( 27 return Some(RangeInfo::new(
28 nominal_def.syntax().text_range(), 28 nominal_def.syntax().text_range(),
29 impls_for_def(&sema, &nominal_def, krate)?, 29 impls_for_def(&sema, &nominal_def, krate)?,
30 )); 30 ));
31 } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(&syntax, position.offset) { 31 } else if let Some(trait_def) = find_node_at_offset::<ast::Trait>(&syntax, position.offset) {
32 return Some(RangeInfo::new( 32 return Some(RangeInfo::new(
33 trait_def.syntax().text_range(), 33 trait_def.syntax().text_range(),
34 impls_for_trait(&sema, &trait_def, krate)?, 34 impls_for_trait(&sema, &trait_def, krate)?,
@@ -40,13 +40,13 @@ pub(crate) fn goto_implementation(
40 40
41fn impls_for_def( 41fn impls_for_def(
42 sema: &Semantics<RootDatabase>, 42 sema: &Semantics<RootDatabase>,
43 node: &ast::NominalDef, 43 node: &ast::AdtDef,
44 krate: Crate, 44 krate: Crate,
45) -> Option<Vec<NavigationTarget>> { 45) -> Option<Vec<NavigationTarget>> {
46 let ty = match node { 46 let ty = match node {
47 ast::NominalDef::StructDef(def) => sema.to_def(def)?.ty(sema.db), 47 ast::AdtDef::Struct(def) => sema.to_def(def)?.ty(sema.db),
48 ast::NominalDef::EnumDef(def) => sema.to_def(def)?.ty(sema.db), 48 ast::AdtDef::Enum(def) => sema.to_def(def)?.ty(sema.db),
49 ast::NominalDef::UnionDef(def) => sema.to_def(def)?.ty(sema.db), 49 ast::AdtDef::Union(def) => sema.to_def(def)?.ty(sema.db),
50 }; 50 };
51 51
52 let impls = ImplDef::all_in_crate(sema.db, krate); 52 let impls = ImplDef::all_in_crate(sema.db, krate);
@@ -62,7 +62,7 @@ fn impls_for_def(
62 62
63fn impls_for_trait( 63fn impls_for_trait(
64 sema: &Semantics<RootDatabase>, 64 sema: &Semantics<RootDatabase>,
65 node: &ast::TraitDef, 65 node: &ast::Trait,
66 krate: Crate, 66 krate: Crate,
67) -> Option<Vec<NavigationTarget>> { 67) -> Option<Vec<NavigationTarget>> {
68 let tr = sema.to_def(node)?; 68 let tr = sema.to_def(node)?;
@@ -74,135 +74,156 @@ fn impls_for_trait(
74 74
75#[cfg(test)] 75#[cfg(test)]
76mod tests { 76mod tests {
77 use crate::mock_analysis::analysis_and_position; 77 use ra_db::FileRange;
78 78
79 fn check_goto(fixture: &str, expected: &[&str]) { 79 use crate::mock_analysis::MockAnalysis;
80 let (analysis, pos) = analysis_and_position(fixture);
81 80
82 let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 81 fn check(ra_fixture: &str) {
83 assert_eq!(navs.len(), expected.len()); 82 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
84 navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start())); 83 let annotations = mock.annotations();
85 navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); 84 let analysis = mock.analysis();
85
86 let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
87
88 let key = |frange: &FileRange| (frange.file_id, frange.range.start());
89
90 let mut expected = annotations
91 .into_iter()
92 .map(|(range, data)| {
93 assert!(data.is_empty());
94 range
95 })
96 .collect::<Vec<_>>();
97 expected.sort_by_key(key);
98
99 let mut actual = navs
100 .into_iter()
101 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
102 .collect::<Vec<_>>();
103 actual.sort_by_key(key);
104
105 assert_eq!(expected, actual);
86 } 106 }
87 107
88 #[test] 108 #[test]
89 fn goto_implementation_works() { 109 fn goto_implementation_works() {
90 check_goto( 110 check(
91 " 111 r#"
92 //- /lib.rs 112struct Foo<|>;
93 struct Foo<|>; 113impl Foo {}
94 impl Foo {} 114 //^^^
95 ", 115"#,
96 &["impl IMPL_DEF FileId(1) 12..23"],
97 ); 116 );
98 } 117 }
99 118
100 #[test] 119 #[test]
101 fn goto_implementation_works_multiple_blocks() { 120 fn goto_implementation_works_multiple_blocks() {
102 check_goto( 121 check(
103 " 122 r#"
104 //- /lib.rs 123struct Foo<|>;
105 struct Foo<|>; 124impl Foo {}
106 impl Foo {} 125 //^^^
107 impl Foo {} 126impl Foo {}
108 ", 127 //^^^
109 &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"], 128"#,
110 ); 129 );
111 } 130 }
112 131
113 #[test] 132 #[test]
114 fn goto_implementation_works_multiple_mods() { 133 fn goto_implementation_works_multiple_mods() {
115 check_goto( 134 check(
116 " 135 r#"
117 //- /lib.rs 136struct Foo<|>;
118 struct Foo<|>; 137mod a {
119 mod a { 138 impl super::Foo {}
120 impl super::Foo {} 139 //^^^^^^^^^^
121 } 140}
122 mod b { 141mod b {
123 impl super::Foo {} 142 impl super::Foo {}
124 } 143 //^^^^^^^^^^
125 ", 144}
126 &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"], 145"#,
127 ); 146 );
128 } 147 }
129 148
130 #[test] 149 #[test]
131 fn goto_implementation_works_multiple_files() { 150 fn goto_implementation_works_multiple_files() {
132 check_goto( 151 check(
133 " 152 r#"
134 //- /lib.rs 153//- /lib.rs
135 struct Foo<|>; 154struct Foo<|>;
136 mod a; 155mod a;
137 mod b; 156mod b;
138 //- /a.rs 157//- /a.rs
139 impl crate::Foo {} 158impl crate::Foo {}
140 //- /b.rs 159 //^^^^^^^^^^
141 impl crate::Foo {} 160//- /b.rs
142 ", 161impl crate::Foo {}
143 &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"], 162 //^^^^^^^^^^
163"#,
144 ); 164 );
145 } 165 }
146 166
147 #[test] 167 #[test]
148 fn goto_implementation_for_trait() { 168 fn goto_implementation_for_trait() {
149 check_goto( 169 check(
150 " 170 r#"
151 //- /lib.rs 171trait T<|> {}
152 trait T<|> {} 172struct Foo;
153 struct Foo; 173impl T for Foo {}
154 impl T for Foo {} 174 //^^^
155 ", 175"#,
156 &["impl IMPL_DEF FileId(1) 23..40"],
157 ); 176 );
158 } 177 }
159 178
160 #[test] 179 #[test]
161 fn goto_implementation_for_trait_multiple_files() { 180 fn goto_implementation_for_trait_multiple_files() {
162 check_goto( 181 check(
163 " 182 r#"
164 //- /lib.rs 183//- /lib.rs
165 trait T<|> {}; 184trait T<|> {};
166 struct Foo; 185struct Foo;
167 mod a; 186mod a;
168 mod b; 187mod b;
169 //- /a.rs 188//- /a.rs
170 impl crate::T for crate::Foo {} 189impl crate::T for crate::Foo {}
171 //- /b.rs 190 //^^^^^^^^^^
172 impl crate::T for crate::Foo {} 191//- /b.rs
173 ", 192impl crate::T for crate::Foo {}
174 &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"], 193 //^^^^^^^^^^
194 "#,
175 ); 195 );
176 } 196 }
177 197
178 #[test] 198 #[test]
179 fn goto_implementation_all_impls() { 199 fn goto_implementation_all_impls() {
180 check_goto( 200 check(
181 " 201 r#"
182 //- /lib.rs 202//- /lib.rs
183 trait T {} 203trait T {}
184 struct Foo<|>; 204struct Foo<|>;
185 impl Foo {} 205impl Foo {}
186 impl T for Foo {} 206 //^^^
187 impl T for &Foo {} 207impl T for Foo {}
188 ", 208 //^^^
189 &[ 209impl T for &Foo {}
190 "impl IMPL_DEF FileId(1) 23..34", 210 //^^^^
191 "impl IMPL_DEF FileId(1) 35..52", 211"#,
192 "impl IMPL_DEF FileId(1) 53..71",
193 ],
194 ); 212 );
195 } 213 }
196 214
197 #[test] 215 #[test]
198 fn goto_implementation_to_builtin_derive() { 216 fn goto_implementation_to_builtin_derive() {
199 check_goto( 217 check(
200 " 218 r#"
201 //- /lib.rs 219 #[derive(Copy)]
202 #[derive(Copy)] 220//^^^^^^^^^^^^^^^
203 struct Foo<|>; 221struct Foo<|>;
204 ", 222
205 &["impl IMPL_DEF FileId(1) 0..15"], 223mod marker {
224 trait Copy {}
225}
226"#,
206 ); 227 );
207 } 228 }
208} 229}
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 91a3097fb..8f52feea6 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,5 +1,5 @@
1use ra_ide_db::RootDatabase; 1use ra_ide_db::RootDatabase;
2use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 2use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
3 3
4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
5 5
@@ -25,8 +25,9 @@ pub(crate) fn goto_type_definition(
25 let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| { 25 let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| {
26 let ty = match_ast! { 26 let ty = match_ast! {
27 match node { 27 match node {
28 ast::Expr(expr) => sema.type_of_expr(&expr)?, 28 ast::Expr(it) => sema.type_of_expr(&it)?,
29 ast::Pat(pat) => sema.type_of_pat(&pat)?, 29 ast::Pat(it) => sema.type_of_pat(&it)?,
30 ast::SelfParam(it) => sema.type_of_self(&it)?,
30 _ => return None, 31 _ => return None,
31 } 32 }
32 }; 33 };
@@ -34,7 +35,7 @@ pub(crate) fn goto_type_definition(
34 Some((ty, node)) 35 Some((ty, node))
35 })?; 36 })?;
36 37
37 let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?; 38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
38 39
39 let nav = adt_def.to_nav(db); 40 let nav = adt_def.to_nav(db);
40 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
@@ -44,7 +45,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
44 return tokens.max_by_key(priority); 45 return tokens.max_by_key(priority);
45 fn priority(n: &SyntaxToken) -> usize { 46 fn priority(n: &SyntaxToken) -> usize {
46 match n.kind() { 47 match n.kind() {
47 IDENT | INT_NUMBER => 2, 48 IDENT | INT_NUMBER | T![self] => 2,
48 kind if kind.is_trivia() => 0, 49 kind if kind.is_trivia() => 0,
49 _ => 1, 50 _ => 1,
50 } 51 }
@@ -53,91 +54,98 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
53 54
54#[cfg(test)] 55#[cfg(test)]
55mod tests { 56mod tests {
56 use crate::mock_analysis::analysis_and_position; 57 use ra_db::FileRange;
57 58
58 fn check_goto(fixture: &str, expected: &str) { 59 use crate::mock_analysis::MockAnalysis;
59 let (analysis, pos) = analysis_and_position(fixture);
60 60
61 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info; 61 fn check(ra_fixture: &str) {
62 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
63 let (expected, data) = mock.annotation();
64 assert!(data.is_empty());
65 let analysis = mock.analysis();
66
67 let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
62 assert_eq!(navs.len(), 1); 68 assert_eq!(navs.len(), 1);
63 let nav = navs.pop().unwrap(); 69 let nav = navs.pop().unwrap();
64 nav.assert_match(expected); 70 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
65 } 71 }
66 72
67 #[test] 73 #[test]
68 fn goto_type_definition_works_simple() { 74 fn goto_type_definition_works_simple() {
69 check_goto( 75 check(
70 " 76 r#"
71 //- /lib.rs 77struct Foo;
72 struct Foo; 78 //^^^
73 fn foo() { 79fn foo() {
74 let f: Foo; 80 let f: Foo; f<|>
75 f<|> 81}
76 } 82"#,
77 ",
78 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
79 ); 83 );
80 } 84 }
81 85
82 #[test] 86 #[test]
83 fn goto_type_definition_works_simple_ref() { 87 fn goto_type_definition_works_simple_ref() {
84 check_goto( 88 check(
85 " 89 r#"
86 //- /lib.rs 90struct Foo;
87 struct Foo; 91 //^^^
88 fn foo() { 92fn foo() {
89 let f: &Foo; 93 let f: &Foo; f<|>
90 f<|> 94}
91 } 95"#,
92 ",
93 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
94 ); 96 );
95 } 97 }
96 98
97 #[test] 99 #[test]
98 fn goto_type_definition_works_through_macro() { 100 fn goto_type_definition_works_through_macro() {
99 check_goto( 101 check(
100 " 102 r#"
101 //- /lib.rs 103macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
102 macro_rules! id { 104struct Foo {}
103 ($($tt:tt)*) => { $($tt)* } 105 //^^^
104 } 106id! {
105 struct Foo {} 107 fn bar() { let f<|> = Foo {}; }
106 id! { 108}
107 fn bar() { 109"#,
108 let f<|> = Foo {};
109 }
110 }
111 ",
112 "Foo STRUCT_DEF FileId(1) 52..65 59..62",
113 ); 110 );
114 } 111 }
115 112
116 #[test] 113 #[test]
117 fn goto_type_definition_for_param() { 114 fn goto_type_definition_for_param() {
118 check_goto( 115 check(
119 " 116 r#"
120 //- /lib.rs 117struct Foo;
121 struct Foo; 118 //^^^
122 fn foo(<|>f: Foo) {} 119fn foo(<|>f: Foo) {}
123 ", 120"#,
124 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
125 ); 121 );
126 } 122 }
127 123
128 #[test] 124 #[test]
129 fn goto_type_definition_for_tuple_field() { 125 fn goto_type_definition_for_tuple_field() {
130 check_goto( 126 check(
131 " 127 r#"
132 //- /lib.rs 128struct Foo;
133 struct Foo; 129 //^^^
134 struct Bar(Foo); 130struct Bar(Foo);
135 fn foo() { 131fn foo() {
136 let bar = Bar(Foo); 132 let bar = Bar(Foo);
137 bar.<|>0; 133 bar.<|>0;
138 } 134}
139 ", 135"#,
140 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
141 ); 136 );
142 } 137 }
138
139 #[test]
140 fn goto_def_for_self_param() {
141 check(
142 r#"
143struct Foo;
144 //^^^
145impl Foo {
146 fn f(&self<|>) {}
147}
148"#,
149 )
150 }
143} 151}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index f36b9de7e..ad68bc43c 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -16,18 +16,18 @@ use ra_ide_db::{
16 defs::{classify_name, classify_name_ref, Definition}, 16 defs::{classify_name, classify_name_ref, Definition},
17 RootDatabase, 17 RootDatabase,
18}; 18};
19use ra_syntax::{ast, ast::Path, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 19use ra_syntax::{ast, ast::Path, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
20use ra_tt::{Ident, Leaf, Literal, TokenTree}; 20use ra_tt::{Ident, Leaf, Literal, TokenTree};
21use stdx::format_to;
22use test_utils::mark;
21use url::Url; 23use url::Url;
22 24
23use crate::{ 25use crate::{
24 display::{ 26 display::{macro_label, ShortLabel, ToNav, TryToNav},
25 macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav, 27 markup::Markup,
26 },
27 runnables::runnable, 28 runnables::runnable,
28 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 29 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
29}; 30};
30use test_utils::mark;
31 31
32#[derive(Clone, Debug, PartialEq, Eq)] 32#[derive(Clone, Debug, PartialEq, Eq)]
33pub struct HoverConfig { 33pub struct HoverConfig {
@@ -76,50 +76,8 @@ pub struct HoverGotoTypeData {
76/// Contains the results when hovering over an item 76/// Contains the results when hovering over an item
77#[derive(Debug, Default)] 77#[derive(Debug, Default)]
78pub struct HoverResult { 78pub struct HoverResult {
79 results: Vec<String>, 79 pub markup: Markup,
80 actions: Vec<HoverAction>, 80 pub actions: Vec<HoverAction>,
81}
82
83impl HoverResult {
84 pub fn new() -> HoverResult {
85 Self::default()
86 }
87
88 pub fn extend(&mut self, item: Option<String>) {
89 self.results.extend(item);
90 }
91
92 pub fn is_empty(&self) -> bool {
93 self.results.is_empty()
94 }
95
96 pub fn len(&self) -> usize {
97 self.results.len()
98 }
99
100 pub fn first(&self) -> Option<&str> {
101 self.results.first().map(String::as_str)
102 }
103
104 pub fn results(&self) -> &[String] {
105 &self.results
106 }
107
108 pub fn actions(&self) -> &[HoverAction] {
109 &self.actions
110 }
111
112 pub fn push_action(&mut self, action: HoverAction) {
113 self.actions.push(action);
114 }
115
116 /// Returns the results converted into markup
117 /// for displaying in a UI
118 ///
119 /// Does not process actions!
120 pub fn to_markup(&self) -> String {
121 self.results.join("\n\n___\n")
122 }
123} 81}
124 82
125// Feature: Hover 83// Feature: Hover
@@ -132,37 +90,33 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
132 let token = pick_best(file.token_at_offset(position.offset))?; 90 let token = pick_best(file.token_at_offset(position.offset))?;
133 let token = sema.descend_into_macros(token); 91 let token = sema.descend_into_macros(token);
134 92
135 let mut res = HoverResult::new(); 93 let mut res = HoverResult::default();
136 94
137 if let Some((node, name_kind)) = match_ast! { 95 let node = token.parent();
138 match (token.parent()) { 96 let definition = match_ast! {
139 ast::NameRef(name_ref) => { 97 match node {
140 classify_name_ref(&sema, &name_ref).map(|d| (name_ref.syntax().clone(), d.definition())) 98 ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()),
141 }, 99 ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()),
142 ast::Name(name) => {
143 classify_name(&sema, &name).map(|d| (name.syntax().clone(), d.definition()))
144 },
145 _ => None, 100 _ => None,
146 } 101 }
147 } { 102 };
148 let range = sema.original_range(&node).range; 103 if let Some(definition) = definition {
149 let text = hover_text_from_name_kind(db, name_kind.clone()); 104 if let Some(markup) = hover_for_definition(db, definition) {
150 let text = text.map(|text| rewrite_links(db, &text, &name_kind).unwrap_or(text)); 105 let markup = rewrite_links(db, &markup.as_str(), &definition);
151 res.extend(text); 106 res.markup = Markup::from(markup);
152 107 if let Some(action) = show_implementations_action(db, definition) {
153 if !res.is_empty() { 108 res.actions.push(action);
154 if let Some(action) = show_implementations_action(db, name_kind) {
155 res.push_action(action);
156 } 109 }
157 110
158 if let Some(action) = runnable_action(&sema, name_kind, position.file_id) { 111 if let Some(action) = runnable_action(&sema, definition, position.file_id) {
159 res.push_action(action); 112 res.actions.push(action);
160 } 113 }
161 114
162 if let Some(action) = goto_type_action(db, name_kind) { 115 if let Some(action) = goto_type_action(db, definition) {
163 res.push_action(action); 116 res.actions.push(action);
164 } 117 }
165 118
119 let range = sema.original_range(&node).range;
166 return Some(RangeInfo::new(range, res)); 120 return Some(RangeInfo::new(range, res));
167 } 121 }
168 } 122 }
@@ -173,22 +127,16 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
173 127
174 let ty = match_ast! { 128 let ty = match_ast! {
175 match node { 129 match node {
176 ast::MacroCall(_it) => { 130 ast::Expr(it) => sema.type_of_expr(&it)?,
177 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve. 131 ast::Pat(it) => sema.type_of_pat(&it)?,
178 // (e.g expanding a builtin macro). So we give up here. 132 // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
179 return None; 133 // (e.g expanding a builtin macro). So we give up here.
180 }, 134 ast::MacroCall(_it) => return None,
181 ast::Expr(it) => { 135 _ => return None,
182 sema.type_of_expr(&it)
183 },
184 ast::Pat(it) => {
185 sema.type_of_pat(&it)
186 },
187 _ => None,
188 } 136 }
189 }?; 137 };
190 138
191 res.extend(Some(rust_code_markup(&ty.display(db)))); 139 res.markup = Markup::fenced_block(&ty.display(db));
192 let range = sema.original_range(&node).range; 140 let range = sema.original_range(&node).range;
193 Some(RangeInfo::new(range, res)) 141 Some(RangeInfo::new(range, res))
194} 142}
@@ -196,8 +144,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
196fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 144fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
197 fn to_action(nav_target: NavigationTarget) -> HoverAction { 145 fn to_action(nav_target: NavigationTarget) -> HoverAction {
198 HoverAction::Implementaion(FilePosition { 146 HoverAction::Implementaion(FilePosition {
199 file_id: nav_target.file_id(), 147 file_id: nav_target.file_id,
200 offset: nav_target.range().start(), 148 offset: nav_target.focus_or_full_range().start(),
201 }) 149 })
202 } 150 }
203 151
@@ -269,7 +217,11 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
269 .into_iter() 217 .into_iter()
270 .filter_map(|it| { 218 .filter_map(|it| {
271 Some(HoverGotoTypeData { 219 Some(HoverGotoTypeData {
272 mod_path: mod_path(db, &it)?, 220 mod_path: render_path(
221 db,
222 it.module(db)?,
223 it.name(db).map(|name| name.to_string()),
224 ),
273 nav: it.try_to_nav(db)?, 225 nav: it.try_to_nav(db)?,
274 }) 226 })
275 }) 227 })
@@ -281,15 +233,28 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
281 } 233 }
282} 234}
283 235
284fn hover_text( 236fn hover_markup(
285 docs: Option<String>, 237 docs: Option<String>,
286 desc: Option<String>, 238 desc: Option<String>,
287 mod_path: Option<String>, 239 mod_path: Option<String>,
288) -> Option<String> { 240) -> Option<Markup> {
289 if let Some(desc) = desc { 241 match desc {
290 Some(rust_code_markup_with_doc(&desc, docs.as_deref(), mod_path.as_deref())) 242 Some(desc) => {
291 } else { 243 let mut buf = String::new();
292 docs 244
245 if let Some(mod_path) = mod_path {
246 if !mod_path.is_empty() {
247 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
248 }
249 }
250 format_to!(buf, "```rust\n{}\n```", desc);
251
252 if let Some(doc) = docs {
253 format_to!(buf, "\n___\n\n{}", doc);
254 }
255 Some(buf.into())
256 }
257 None => docs.map(Markup::from),
293 } 258 }
294} 259}
295 260
@@ -311,43 +276,35 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
311 .map(|name| name.to_string()) 276 .map(|name| name.to_string())
312} 277}
313 278
314fn determine_mod_path(db: &RootDatabase, module: Module, name: Option<String>) -> String { 279fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String {
315 once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) 280 let crate_name =
316 .chain( 281 db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string);
317 module 282 let module_path = module
318 .path_to_root(db) 283 .path_to_root(db)
319 .into_iter() 284 .into_iter()
320 .rev() 285 .rev()
321 .map(|it| it.name(db).map(|name| name.to_string())), 286 .flat_map(|it| it.name(db).map(|name| name.to_string()));
322 ) 287 crate_name.into_iter().chain(module_path).chain(item_name).join("::")
323 .chain(once(name))
324 .flatten()
325 .join("::")
326}
327
328// returns None only for ModuleDef::BuiltinType
329fn mod_path(db: &RootDatabase, item: &ModuleDef) -> Option<String> {
330 Some(determine_mod_path(db, item.module(db)?, item.name(db).map(|name| name.to_string())))
331} 288}
332 289
333fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { 290fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
334 def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def))) 291 def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
335} 292}
336 293
337fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { 294fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
338 let mod_path = definition_mod_path(db, &def); 295 let mod_path = definition_mod_path(db, &def);
339 return match def { 296 return match def {
340 Definition::Macro(it) => { 297 Definition::Macro(it) => {
341 let src = it.source(db); 298 let src = it.source(db);
342 let docs = Documentation::from_ast(&src.value).map(Into::into); 299 let docs = Documentation::from_ast(&src.value).map(Into::into);
343 hover_text(docs, Some(macro_label(&src.value)), mod_path) 300 hover_markup(docs, Some(macro_label(&src.value)), mod_path)
344 } 301 }
345 Definition::Field(it) => { 302 Definition::Field(it) => {
346 let src = it.source(db); 303 let src = it.source(db);
347 match src.value { 304 match src.value {
348 FieldSource::Named(it) => { 305 FieldSource::Named(it) => {
349 let docs = Documentation::from_ast(&it).map(Into::into); 306 let docs = Documentation::from_ast(&it).map(Into::into);
350 hover_text(docs, it.short_label(), mod_path) 307 hover_markup(docs, it.short_label(), mod_path)
351 } 308 }
352 _ => None, 309 _ => None,
353 } 310 }
@@ -356,7 +313,7 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
356 ModuleDef::Module(it) => match it.definition_source(db).value { 313 ModuleDef::Module(it) => match it.definition_source(db).value {
357 ModuleSource::Module(it) => { 314 ModuleSource::Module(it) => {
358 let docs = Documentation::from_ast(&it).map(Into::into); 315 let docs = Documentation::from_ast(&it).map(Into::into);
359 hover_text(docs, it.short_label(), mod_path) 316 hover_markup(docs, it.short_label(), mod_path)
360 } 317 }
361 _ => None, 318 _ => None,
362 }, 319 },
@@ -369,23 +326,23 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
369 ModuleDef::Static(it) => from_def_source(db, it, mod_path), 326 ModuleDef::Static(it) => from_def_source(db, it, mod_path),
370 ModuleDef::Trait(it) => from_def_source(db, it, mod_path), 327 ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
371 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), 328 ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
372 ModuleDef::BuiltinType(it) => Some(it.to_string()), 329 ModuleDef::BuiltinType(it) => return Some(it.to_string().into()),
373 }, 330 },
374 Definition::Local(it) => Some(rust_code_markup(&it.ty(db).display(db))), 331 Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))),
375 Definition::TypeParam(_) | Definition::SelfType(_) => { 332 Definition::TypeParam(_) | Definition::SelfType(_) => {
376 // FIXME: Hover for generic param 333 // FIXME: Hover for generic param
377 None 334 None
378 } 335 }
379 }; 336 };
380 337
381 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String> 338 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
382 where 339 where
383 D: HasSource<Ast = A>, 340 D: HasSource<Ast = A>,
384 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, 341 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner,
385 { 342 {
386 let src = def.source(db); 343 let src = def.source(db);
387 let docs = Documentation::from_ast(&src.value).map(Into::into); 344 let docs = Documentation::from_ast(&src.value).map(Into::into);
388 hover_text(docs, src.value.short_label(), mod_path) 345 hover_markup(docs, src.value.short_label(), mod_path)
389 } 346 }
390} 347}
391 348
@@ -422,7 +379,7 @@ fn map_links<'e>(
422} 379}
423 380
424/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) 381/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
425fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> Option<String> { 382fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
426 let doc = Parser::new_with_broken_link_callback( 383 let doc = Parser::new_with_broken_link_callback(
427 markdown, 384 markdown,
428 Options::empty(), 385 Options::empty(),
@@ -452,7 +409,7 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) ->
452 }); 409 });
453 let mut out = String::new(); 410 let mut out = String::new();
454 cmark(doc, &mut out, None).ok(); 411 cmark(doc, &mut out, None).ok();
455 Some(out) 412 out
456} 413}
457 414
458#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] 415#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
@@ -665,7 +622,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
665 fn priority(n: &SyntaxToken) -> usize { 622 fn priority(n: &SyntaxToken) -> usize {
666 match n.kind() { 623 match n.kind() {
667 IDENT | INT_NUMBER => 3, 624 IDENT | INT_NUMBER => 3,
668 L_PAREN | R_PAREN => 2, 625 T!['('] | T![')'] => 2,
669 kind if kind.is_trivia() => 0, 626 kind if kind.is_trivia() => 0,
670 _ => 1, 627 _ => 1,
671 } 628 }
@@ -674,64 +631,38 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
674 631
675#[cfg(test)] 632#[cfg(test)]
676mod tests { 633mod tests {
677 use super::*; 634 use expect::{expect, Expect};
678 use insta::assert_debug_snapshot;
679
680 use ra_db::FileLoader; 635 use ra_db::FileLoader;
681 use ra_syntax::TextRange;
682 636
683 use crate::mock_analysis::analysis_and_position; 637 use crate::mock_analysis::analysis_and_position;
684 638
685 fn trim_markup(s: &str) -> String { 639 use super::*;
686 s.trim()
687 .replace("````", "```")
688 .replace("---", "___")
689 .replace("\\<-", "<-")
690 .replace("```\n\n___", "```\n___")
691 .trim_start_matches("```rust\n")
692 .trim_start_matches("test\n```\n\n```rust\n")
693 .trim_end_matches("\n```")
694 .to_string()
695 }
696
697 fn trim_markup_opt(s: Option<&str>) -> Option<String> {
698 s.map(trim_markup)
699 }
700 640
701 fn assert_impl_action(action: &HoverAction, position: u32) { 641 fn check_hover_no_result(ra_fixture: &str) {
702 let offset = match action { 642 let (analysis, position) = analysis_and_position(ra_fixture);
703 HoverAction::Implementaion(pos) => pos.offset, 643 assert!(analysis.hover(position).unwrap().is_none());
704 it => panic!("Unexpected hover action: {:#?}", it),
705 };
706 assert_eq!(offset, position.into());
707 } 644 }
708 645
709 fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) { 646 fn check(ra_fixture: &str, expect: Expect) {
710 let (analysis, position) = analysis_and_position(fixture); 647 let (analysis, position) = analysis_and_position(ra_fixture);
711 let hover = analysis.hover(position).unwrap().unwrap(); 648 let hover = analysis.hover(position).unwrap().unwrap();
712 let mut results = Vec::from(hover.info.results());
713 results.sort();
714
715 for (markup, expected) in
716 results.iter().zip(expected.iter().chain(std::iter::repeat(&"<missing>")))
717 {
718 assert_eq!(trim_markup(&markup), *expected);
719 }
720
721 assert_eq!(hover.info.len(), expected.len());
722 649
723 let content = analysis.db.file_text(position.file_id); 650 let content = analysis.db.file_text(position.file_id);
724 (content[hover.range].to_string(), hover.info.actions().to_vec()) 651 let hovered_element = &content[hover.range];
652
653 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
654 expect.assert_eq(&actual)
725 } 655 }
726 656
727 fn check_hover_no_result(fixture: &str) { 657 fn check_actions(ra_fixture: &str, expect: Expect) {
728 let (analysis, position) = analysis_and_position(fixture); 658 let (analysis, position) = analysis_and_position(ra_fixture);
729 assert!(analysis.hover(position).unwrap().is_none()); 659 let hover = analysis.hover(position).unwrap().unwrap();
660 expect.assert_debug_eq(&hover.info.actions)
730 } 661 }
731 662
732 #[test] 663 #[test]
733 fn hover_shows_type_of_an_expression() { 664 fn hover_shows_type_of_an_expression() {
734 let (analysis, position) = analysis_and_position( 665 check(
735 r#" 666 r#"
736pub fn foo() -> u32 { 1 } 667pub fn foo() -> u32 { 1 }
737 668
@@ -739,606 +670,643 @@ fn main() {
739 let foo_test = foo()<|>; 670 let foo_test = foo()<|>;
740} 671}
741"#, 672"#,
673 expect![[r#"
674 *foo()*
675 ```rust
676 u32
677 ```
678 "#]],
742 ); 679 );
743 let hover = analysis.hover(position).unwrap().unwrap();
744 assert_eq!(hover.range, TextRange::new(58.into(), 63.into()));
745 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("u32"));
746 } 680 }
747 681
748 #[test] 682 #[test]
749 fn hover_shows_long_type_of_an_expression() { 683 fn hover_shows_long_type_of_an_expression() {
750 check_hover_result( 684 check(
751 r#" 685 r#"
752 //- /main.rs 686struct Scan<A, B, C> { a: A, b: B, c: C }
753 struct Scan<A, B, C> { 687struct Iter<I> { inner: I }
754 a: A, 688enum Option<T> { Some(T), None }
755 b: B,
756 c: C,
757 }
758 689
759 struct FakeIter<I> { 690struct OtherStruct<T> { i: T }
760 inner: I,
761 }
762
763 struct OtherStruct<T> {
764 i: T,
765 }
766 691
767 enum FakeOption<T> { 692fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
768 Some(T), 693 Iter { inner: Scan { a, b, c } }
769 None, 694}
770 }
771
772 fn scan<A, B, C>(a: A, b: B, c: C) -> FakeIter<Scan<OtherStruct<A>, B, C>> {
773 FakeIter { inner: Scan { a, b, c } }
774 }
775 695
776 fn main() { 696fn main() {
777 let num: i32 = 55; 697 let num: i32 = 55;
778 let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> FakeOption<u32> { 698 let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
779 FakeOption::Some(*memo + value) 699 Option::Some(*memo + value)
780 }; 700 };
781 let number = 5u32; 701 let number = 5u32;
782 let mut iter<|> = scan(OtherStruct { i: num }, closure, number); 702 let mut iter<|> = scan(OtherStruct { i: num }, closure, number);
783 } 703}
784 "#, 704"#,
785 &["FakeIter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> FakeOption<u32>, u32>>"], 705 expect![[r#"
706 *iter*
707 ```rust
708 Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
709 ```
710 "#]],
786 ); 711 );
787 } 712 }
788 713
789 #[test] 714 #[test]
790 fn hover_shows_fn_signature() { 715 fn hover_shows_fn_signature() {
791 // Single file with result 716 // Single file with result
792 check_hover_result( 717 check(
793 r#" 718 r#"
794 //- /main.rs 719pub fn foo() -> u32 { 1 }
795 pub fn foo() -> u32 { 1 }
796 720
797 fn main() { 721fn main() { let foo_test = fo<|>o(); }
798 let foo_test = fo<|>o(); 722"#,
799 } 723 expect![[r#"
800 "#, 724 *foo*
801 &["pub fn foo() -> u32"], 725 ```rust
726 pub fn foo() -> u32
727 ```
728 "#]],
802 ); 729 );
803 730
804 // Multiple candidates but results are ambiguous. 731 // Multiple candidates but results are ambiguous.
805 check_hover_result( 732 check(
806 r#" 733 r#"
807 //- /a.rs 734//- /a.rs
808 pub fn foo() -> u32 { 1 } 735pub fn foo() -> u32 { 1 }
809 736
810 //- /b.rs 737//- /b.rs
811 pub fn foo() -> &str { "" } 738pub fn foo() -> &str { "" }
812 739
813 //- /c.rs 740//- /c.rs
814 pub fn foo(a: u32, b: u32) {} 741pub fn foo(a: u32, b: u32) {}
815 742
816 //- /main.rs 743//- /main.rs
817 mod a; 744mod a;
818 mod b; 745mod b;
819 mod c; 746mod c;
820 747
821 fn main() { 748fn main() { let foo_test = fo<|>o(); }
822 let foo_test = fo<|>o();
823 }
824 "#, 749 "#,
825 &["{unknown}"], 750 expect![[r#"
751 *foo*
752 ```rust
753 {unknown}
754 ```
755 "#]],
826 ); 756 );
827 } 757 }
828 758
829 #[test] 759 #[test]
830 fn hover_shows_fn_signature_with_type_params() { 760 fn hover_shows_fn_signature_with_type_params() {
831 check_hover_result( 761 check(
832 r#" 762 r#"
833 //- /main.rs 763pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
834 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
835 764
836 fn main() { 765fn main() { let foo_test = fo<|>o(); }
837 let foo_test = fo<|>o();
838 }
839 "#, 766 "#,
840 &["pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str"], 767 expect![[r#"
768 *foo*
769 ```rust
770 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
771 ```
772 "#]],
841 ); 773 );
842 } 774 }
843 775
844 #[test] 776 #[test]
845 fn hover_shows_fn_signature_on_fn_name() { 777 fn hover_shows_fn_signature_on_fn_name() {
846 check_hover_result( 778 check(
847 r#" 779 r#"
848 //- /main.rs 780pub fn foo<|>(a: u32, b: u32) -> u32 {}
849 pub fn foo<|>(a: u32, b: u32) -> u32 {}
850 781
851 fn main() { 782fn main() { }
852 } 783"#,
853 "#, 784 expect![[r#"
854 &["pub fn foo(a: u32, b: u32) -> u32"], 785 *foo*
786 ```rust
787 pub fn foo(a: u32, b: u32) -> u32
788 ```
789 "#]],
855 ); 790 );
856 } 791 }
857 792
858 #[test] 793 #[test]
859 fn hover_shows_struct_field_info() { 794 fn hover_shows_struct_field_info() {
860 // Hovering over the field when instantiating 795 // Hovering over the field when instantiating
861 check_hover_result( 796 check(
862 r#" 797 r#"
863 //- /main.rs 798struct Foo { field_a: u32 }
864 struct Foo {
865 field_a: u32,
866 }
867 799
868 fn main() { 800fn main() {
869 let foo = Foo { 801 let foo = Foo { field_a<|>: 0, };
870 field_a<|>: 0, 802}
871 }; 803"#,
872 } 804 expect![[r#"
873 "#, 805 *field_a*
874 &["test::Foo\n```\n\n```rust\nfield_a: u32"], 806 ```rust
807 Foo
808 ```
809
810 ```rust
811 field_a: u32
812 ```
813 "#]],
875 ); 814 );
876 815
877 // Hovering over the field in the definition 816 // Hovering over the field in the definition
878 check_hover_result( 817 check(
879 r#" 818 r#"
880 //- /main.rs 819struct Foo { field_a<|>: u32 }
881 struct Foo {
882 field_a<|>: u32,
883 }
884 820
885 fn main() { 821fn main() {
886 let foo = Foo { 822 let foo = Foo { field_a: 0 };
887 field_a: 0, 823}
888 }; 824"#,
889 } 825 expect![[r#"
890 "#, 826 *field_a*
891 &["test::Foo\n```\n\n```rust\nfield_a: u32"], 827 ```rust
828 Foo
829 ```
830
831 ```rust
832 field_a: u32
833 ```
834 "#]],
892 ); 835 );
893 } 836 }
894 837
895 #[test] 838 #[test]
896 fn hover_const_static() { 839 fn hover_const_static() {
897 check_hover_result( 840 check(
898 r#" 841 r#"const foo<|>: u32 = 0;"#,
899 //- /main.rs 842 expect![[r#"
900 const foo<|>: u32 = 0; 843 *foo*
901 "#, 844 ```rust
902 &["const foo: u32"], 845 const foo: u32
846 ```
847 "#]],
903 ); 848 );
904 849 check(
905 check_hover_result( 850 r#"static foo<|>: u32 = 0;"#,
906 r#" 851 expect![[r#"
907 //- /main.rs 852 *foo*
908 static foo<|>: u32 = 0; 853 ```rust
909 "#, 854 static foo: u32
910 &["static foo: u32"], 855 ```
856 "#]],
911 ); 857 );
912 } 858 }
913 859
914 #[test] 860 #[test]
915 fn hover_default_generic_types() { 861 fn hover_default_generic_types() {
916 check_hover_result( 862 check(
917 r#" 863 r#"
918//- /main.rs 864struct Test<K, T = u8> { k: K, t: T }
919struct Test<K, T = u8> {
920 k: K,
921 t: T,
922}
923 865
924fn main() { 866fn main() {
925 let zz<|> = Test { t: 23u8, k: 33 }; 867 let zz<|> = Test { t: 23u8, k: 33 };
926}"#, 868}"#,
927 &["Test<i32, u8>"], 869 expect![[r#"
870 *zz*
871 ```rust
872 Test<i32, u8>
873 ```
874 "#]],
928 ); 875 );
929 } 876 }
930 877
931 #[test] 878 #[test]
932 fn hover_some() { 879 fn hover_some() {
933 let (analysis, position) = analysis_and_position( 880 check(
934 " 881 r#"
935 enum Option<T> { Some(T) } 882enum Option<T> { Some(T) }
936 use Option::Some; 883use Option::Some;
937 884
938 fn main() { 885fn main() { So<|>me(12); }
939 So<|>me(12); 886"#,
940 } 887 expect![[r#"
941 ", 888 *Some*
942 ); 889 ```rust
943 let hover = analysis.hover(position).unwrap().unwrap(); 890 Option
944 assert_eq!( 891 ```
945 trim_markup_opt(hover.info.first()).as_deref(), 892
946 Some("test::Option\n```\n\n```rust\nSome") 893 ```rust
894 Some
895 ```
896 "#]],
947 ); 897 );
948 898
949 let (analysis, position) = analysis_and_position( 899 check(
950 " 900 r#"
951 enum Option<T> { Some(T) } 901enum Option<T> { Some(T) }
952 use Option::Some; 902use Option::Some;
953 903
954 fn main() { 904fn main() { let b<|>ar = Some(12); }
955 let b<|>ar = Some(12); 905"#,
956 } 906 expect![[r#"
957 ", 907 *bar*
908 ```rust
909 Option<i32>
910 ```
911 "#]],
958 ); 912 );
959 let hover = analysis.hover(position).unwrap().unwrap();
960 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Option<i32>"));
961 } 913 }
962 914
963 #[test] 915 #[test]
964 fn hover_enum_variant() { 916 fn hover_enum_variant() {
965 check_hover_result( 917 check(
966 r#" 918 r#"
967 //- /main.rs 919enum Option<T> {
968 enum Option<T> { 920 /// The None variant
969 /// The None variant 921 Non<|>e
970 Non<|>e 922}
971 } 923"#,
972 "#, 924 expect![[r#"
973 &[" 925 *None*
974test::Option 926 ```rust
975``` 927 Option
928 ```
976 929
977```rust 930 ```rust
978None 931 None
979``` 932 ```
980___ 933 ___
981 934
982The None variant 935 The None variant
983 " 936 "#]],
984 .trim()],
985 ); 937 );
986 938
987 check_hover_result( 939 check(
988 r#" 940 r#"
989 //- /main.rs 941enum Option<T> {
990 enum Option<T> { 942 /// The Some variant
991 /// The Some variant 943 Some(T)
992 Some(T) 944}
993 } 945fn main() {
994 fn main() { 946 let s = Option::Som<|>e(12);
995 let s = Option::Som<|>e(12); 947}
996 } 948"#,
997 "#, 949 expect![[r#"
998 &[" 950 *Some*
999test::Option 951 ```rust
1000``` 952 Option
953 ```
1001 954
1002```rust 955 ```rust
1003Some 956 Some
1004``` 957 ```
1005___ 958 ___
1006 959
1007The Some variant 960 The Some variant
1008 " 961 "#]],
1009 .trim()],
1010 ); 962 );
1011 } 963 }
1012 964
1013 #[test] 965 #[test]
1014 fn hover_for_local_variable() { 966 fn hover_for_local_variable() {
1015 let (analysis, position) = analysis_and_position("fn func(foo: i32) { fo<|>o; }"); 967 check(
1016 let hover = analysis.hover(position).unwrap().unwrap(); 968 r#"fn func(foo: i32) { fo<|>o; }"#,
1017 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 969 expect![[r#"
970 *foo*
971 ```rust
972 i32
973 ```
974 "#]],
975 )
1018 } 976 }
1019 977
1020 #[test] 978 #[test]
1021 fn hover_for_local_variable_pat() { 979 fn hover_for_local_variable_pat() {
1022 let (analysis, position) = analysis_and_position("fn func(fo<|>o: i32) {}"); 980 check(
1023 let hover = analysis.hover(position).unwrap().unwrap(); 981 r#"fn func(fo<|>o: i32) {}"#,
1024 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 982 expect![[r#"
983 *foo*
984 ```rust
985 i32
986 ```
987 "#]],
988 )
1025 } 989 }
1026 990
1027 #[test] 991 #[test]
1028 fn hover_local_var_edge() { 992 fn hover_local_var_edge() {
1029 let (analysis, position) = analysis_and_position( 993 check(
1030 " 994 r#"fn func(foo: i32) { if true { <|>foo; }; }"#,
1031fn func(foo: i32) { if true { <|>foo; }; } 995 expect![[r#"
1032", 996 *foo*
1033 ); 997 ```rust
1034 let hover = analysis.hover(position).unwrap().unwrap(); 998 i32
1035 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 999 ```
1000 "#]],
1001 )
1036 } 1002 }
1037 1003
1038 #[test] 1004 #[test]
1039 fn hover_for_param_edge() { 1005 fn hover_for_param_edge() {
1040 let (analysis, position) = analysis_and_position("fn func(<|>foo: i32) {}"); 1006 check(
1041 let hover = analysis.hover(position).unwrap().unwrap(); 1007 r#"fn func(<|>foo: i32) {}"#,
1042 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 1008 expect![[r#"
1009 *foo*
1010 ```rust
1011 i32
1012 ```
1013 "#]],
1014 )
1043 } 1015 }
1044 1016
1045 #[test] 1017 #[test]
1046 fn test_hover_infer_associated_method_result() { 1018 fn test_hover_infer_associated_method_result() {
1047 let (analysis, position) = analysis_and_position( 1019 check(
1048 " 1020 r#"
1049 struct Thing { x: u32 } 1021struct Thing { x: u32 }
1050 1022
1051 impl Thing { 1023impl Thing {
1052 fn new() -> Thing { 1024 fn new() -> Thing { Thing { x: 0 } }
1053 Thing { x: 0 } 1025}
1054 }
1055 }
1056 1026
1057 fn main() { 1027fn main() { let foo_<|>test = Thing::new(); }
1058 let foo_<|>test = Thing::new(); 1028 "#,
1059 } 1029 expect![[r#"
1060 ", 1030 *foo_test*
1061 ); 1031 ```rust
1062 let hover = analysis.hover(position).unwrap().unwrap(); 1032 Thing
1063 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Thing")); 1033 ```
1034 "#]],
1035 )
1064 } 1036 }
1065 1037
1066 #[test] 1038 #[test]
1067 fn test_hover_infer_associated_method_exact() { 1039 fn test_hover_infer_associated_method_exact() {
1068 let (analysis, position) = analysis_and_position( 1040 check(
1069 " 1041 r#"
1070 mod wrapper { 1042mod wrapper {
1071 struct Thing { x: u32 } 1043 struct Thing { x: u32 }
1072 1044
1073 impl Thing { 1045 impl Thing {
1074 fn new() -> Thing { 1046 fn new() -> Thing { Thing { x: 0 } }
1075 Thing { x: 0 } 1047 }
1076 } 1048}
1077 }
1078 }
1079 1049
1080 fn main() { 1050fn main() { let foo_test = wrapper::Thing::new<|>(); }
1081 let foo_test = wrapper::Thing::new<|>(); 1051"#,
1082 } 1052 expect![[r#"
1083 ", 1053 *new*
1084 ); 1054 ```rust
1085 let hover = analysis.hover(position).unwrap().unwrap(); 1055 wrapper::Thing
1086 assert_eq!( 1056 ```
1087 trim_markup_opt(hover.info.first()).as_deref(), 1057
1088 Some("test::wrapper::Thing\n```\n\n```rust\nfn new() -> Thing") 1058 ```rust
1089 ); 1059 fn new() -> Thing
1060 ```
1061 "#]],
1062 )
1090 } 1063 }
1091 1064
1092 #[test] 1065 #[test]
1093 fn test_hover_infer_associated_const_in_pattern() { 1066 fn test_hover_infer_associated_const_in_pattern() {
1094 let (analysis, position) = analysis_and_position( 1067 check(
1095 " 1068 r#"
1096 struct X; 1069struct X;
1097 impl X { 1070impl X {
1098 const C: u32 = 1; 1071 const C: u32 = 1;
1099 } 1072}
1100 1073
1101 fn main() { 1074fn main() {
1102 match 1 { 1075 match 1 {
1103 X::C<|> => {}, 1076 X::C<|> => {},
1104 2 => {}, 1077 2 => {},
1105 _ => {} 1078 _ => {}
1106 }; 1079 };
1107 } 1080}
1108 ", 1081"#,
1109 ); 1082 expect![[r#"
1110 let hover = analysis.hover(position).unwrap().unwrap(); 1083 *C*
1111 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("const C: u32")); 1084 ```rust
1085 const C: u32
1086 ```
1087 "#]],
1088 )
1112 } 1089 }
1113 1090
1114 #[test] 1091 #[test]
1115 fn test_hover_self() { 1092 fn test_hover_self() {
1116 let (analysis, position) = analysis_and_position( 1093 check(
1117 " 1094 r#"
1118 struct Thing { x: u32 } 1095struct Thing { x: u32 }
1119 impl Thing { 1096impl Thing {
1120 fn new() -> Self { 1097 fn new() -> Self { Self<|> { x: 0 } }
1121 Self<|> { x: 0 } 1098}
1122 } 1099"#,
1123 } 1100 expect![[r#"
1124 ", 1101 *Self { x: 0 }*
1125 ); 1102 ```rust
1126 let hover = analysis.hover(position).unwrap().unwrap(); 1103 Thing
1127 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("Thing")); 1104 ```
1128 1105 "#]],
1129 /* FIXME: revive these tests 1106 )
1130 let (analysis, position) = analysis_and_position( 1107 } /* FIXME: revive these tests
1131 " 1108 let (analysis, position) = analysis_and_position(
1132 struct Thing { x: u32 } 1109 "
1133 impl Thing { 1110 struct Thing { x: u32 }
1134 fn new() -> Self<|> { 1111 impl Thing {
1135 Self { x: 0 } 1112 fn new() -> Self<|> {
1136 } 1113 Self { x: 0 }
1137 } 1114 }
1138 ", 1115 }
1139 ); 1116 ",
1140 1117 );
1141 let hover = analysis.hover(position).unwrap().unwrap(); 1118
1142 assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); 1119 let hover = analysis.hover(position).unwrap().unwrap();
1143 1120 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
1144 let (analysis, position) = analysis_and_position( 1121
1145 " 1122 let (analysis, position) = analysis_and_position(
1146 enum Thing { A } 1123 "
1147 impl Thing { 1124 enum Thing { A }
1148 pub fn new() -> Self<|> { 1125 impl Thing {
1149 Thing::A 1126 pub fn new() -> Self<|> {
1150 } 1127 Thing::A
1151 } 1128 }
1152 ", 1129 }
1153 ); 1130 ",
1154 let hover = analysis.hover(position).unwrap().unwrap(); 1131 );
1155 assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); 1132 let hover = analysis.hover(position).unwrap().unwrap();
1156 1133 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
1157 let (analysis, position) = analysis_and_position( 1134
1158 " 1135 let (analysis, position) = analysis_and_position(
1159 enum Thing { A } 1136 "
1160 impl Thing { 1137 enum Thing { A }
1161 pub fn thing(a: Self<|>) { 1138 impl Thing {
1162 } 1139 pub fn thing(a: Self<|>) {
1163 } 1140 }
1164 ", 1141 }
1165 ); 1142 ",
1166 let hover = analysis.hover(position).unwrap().unwrap(); 1143 );
1167 assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing")); 1144 let hover = analysis.hover(position).unwrap().unwrap();
1168 */ 1145 assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
1169 } 1146 */
1170 1147
1171 #[test] 1148 #[test]
1172 fn test_hover_shadowing_pat() { 1149 fn test_hover_shadowing_pat() {
1173 let (analysis, position) = analysis_and_position( 1150 check(
1174 " 1151 r#"
1175 fn x() {} 1152fn x() {}
1176 1153
1177 fn y() { 1154fn y() {
1178 let x = 0i32; 1155 let x = 0i32;
1179 x<|>; 1156 x<|>;
1180 } 1157}
1181 ", 1158"#,
1182 ); 1159 expect![[r#"
1183 let hover = analysis.hover(position).unwrap().unwrap(); 1160 *x*
1184 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 1161 ```rust
1162 i32
1163 ```
1164 "#]],
1165 )
1185 } 1166 }
1186 1167
1187 #[test] 1168 #[test]
1188 fn test_hover_macro_invocation() { 1169 fn test_hover_macro_invocation() {
1189 let (analysis, position) = analysis_and_position( 1170 check(
1190 " 1171 r#"
1191 macro_rules! foo { 1172macro_rules! foo { () => {} }
1192 () => {}
1193 }
1194 1173
1195 fn f() { 1174fn f() { fo<|>o!(); }
1196 fo<|>o!(); 1175"#,
1197 } 1176 expect![[r#"
1198 ", 1177 *foo*
1199 ); 1178 ```rust
1200 let hover = analysis.hover(position).unwrap().unwrap(); 1179 macro_rules! foo
1201 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("macro_rules! foo")); 1180 ```
1181 "#]],
1182 )
1202 } 1183 }
1203 1184
1204 #[test] 1185 #[test]
1205 fn test_hover_tuple_field() { 1186 fn test_hover_tuple_field() {
1206 let (analysis, position) = analysis_and_position( 1187 check(
1207 " 1188 r#"struct TS(String, i32<|>);"#,
1208 struct TS(String, i32<|>); 1189 expect![[r#"
1209 ", 1190 *i32*
1210 ); 1191 i32
1211 let hover = analysis.hover(position).unwrap().unwrap(); 1192 "#]],
1212 assert_eq!(trim_markup_opt(hover.info.first()).as_deref(), Some("i32")); 1193 )
1213 } 1194 }
1214 1195
1215 #[test] 1196 #[test]
1216 fn test_hover_through_macro() { 1197 fn test_hover_through_macro() {
1217 let (hover_on, _) = check_hover_result( 1198 check(
1218 " 1199 r#"
1219 //- /lib.rs 1200macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1220 macro_rules! id { 1201fn foo() {}
1221 ($($tt:tt)*) => { $($tt)* } 1202id! {
1222 } 1203 fn bar() { fo<|>o(); }
1223 fn foo() {} 1204}
1224 id! { 1205"#,
1225 fn bar() { 1206 expect![[r#"
1226 fo<|>o(); 1207 *foo*
1227 } 1208 ```rust
1228 } 1209 fn foo()
1229 ", 1210 ```
1230 &["fn foo()"], 1211 "#]],
1231 ); 1212 );
1232
1233 assert_eq!(hover_on, "foo")
1234 } 1213 }
1235 1214
1236 #[test] 1215 #[test]
1237 fn test_hover_through_expr_in_macro() { 1216 fn test_hover_through_expr_in_macro() {
1238 let (hover_on, _) = check_hover_result( 1217 check(
1239 " 1218 r#"
1240 //- /lib.rs 1219macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1241 macro_rules! id { 1220fn foo(bar:u32) { let a = id!(ba<|>r); }
1242 ($($tt:tt)*) => { $($tt)* } 1221"#,
1243 } 1222 expect![[r#"
1244 fn foo(bar:u32) { 1223 *bar*
1245 let a = id!(ba<|>r); 1224 ```rust
1246 } 1225 u32
1247 ", 1226 ```
1248 &["u32"], 1227 "#]],
1249 ); 1228 );
1250
1251 assert_eq!(hover_on, "bar")
1252 } 1229 }
1253 1230
1254 #[test] 1231 #[test]
1255 fn test_hover_through_expr_in_macro_recursive() { 1232 fn test_hover_through_expr_in_macro_recursive() {
1256 let (hover_on, _) = check_hover_result( 1233 check(
1257 " 1234 r#"
1258 //- /lib.rs 1235macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1259 macro_rules! id_deep { 1236macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1260 ($($tt:tt)*) => { $($tt)* } 1237fn foo(bar:u32) { let a = id!(ba<|>r); }
1261 } 1238"#,
1262 macro_rules! id { 1239 expect![[r#"
1263 ($($tt:tt)*) => { id_deep!($($tt)*) } 1240 *bar*
1264 } 1241 ```rust
1265 fn foo(bar:u32) { 1242 u32
1266 let a = id!(ba<|>r); 1243 ```
1267 } 1244 "#]],
1268 ",
1269 &["u32"],
1270 ); 1245 );
1271
1272 assert_eq!(hover_on, "bar")
1273 } 1246 }
1274 1247
1275 #[test] 1248 #[test]
1276 fn test_hover_through_func_in_macro_recursive() { 1249 fn test_hover_through_func_in_macro_recursive() {
1277 let (hover_on, _) = check_hover_result( 1250 check(
1278 " 1251 r#"
1279 //- /lib.rs 1252macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1280 macro_rules! id_deep { 1253macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1281 ($($tt:tt)*) => { $($tt)* } 1254fn bar() -> u32 { 0 }
1282 } 1255fn foo() { let a = id!([0u32, bar(<|>)] ); }
1283 macro_rules! id { 1256"#,
1284 ($($tt:tt)*) => { id_deep!($($tt)*) } 1257 expect![[r#"
1285 } 1258 *bar()*
1286 fn bar() -> u32 { 1259 ```rust
1287 0 1260 u32
1288 } 1261 ```
1289 fn foo() { 1262 "#]],
1290 let a = id!([0u32, bar(<|>)] );
1291 }
1292 ",
1293 &["u32"],
1294 ); 1263 );
1295
1296 assert_eq!(hover_on, "bar()")
1297 } 1264 }
1298 1265
1299 #[test] 1266 #[test]
1300 fn test_hover_through_literal_string_in_macro() { 1267 fn test_hover_through_literal_string_in_macro() {
1301 let (hover_on, _) = check_hover_result( 1268 check(
1302 r#" 1269 r#"
1303 //- /lib.rs 1270macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1304 macro_rules! arr { 1271fn foo() {
1305 ($($tt:tt)*) => { [$($tt)*)] } 1272 let mastered_for_itunes = "";
1306 } 1273 let _ = arr!("Tr<|>acks", &mastered_for_itunes);
1307 fn foo() { 1274}
1308 let mastered_for_itunes = ""; 1275"#,
1309 let _ = arr!("Tr<|>acks", &mastered_for_itunes); 1276 expect![[r#"
1310 } 1277 *"Tracks"*
1311 "#, 1278 ```rust
1312 &["&str"], 1279 &str
1280 ```
1281 "#]],
1313 ); 1282 );
1314
1315 assert_eq!(hover_on, "\"Tracks\"");
1316 } 1283 }
1317 1284
1318 #[test] 1285 #[test]
1319 fn test_hover_through_assert_macro() { 1286 fn test_hover_through_assert_macro() {
1320 let (hover_on, _) = check_hover_result( 1287 check(
1321 r#" 1288 r#"
1322 //- /lib.rs 1289#[rustc_builtin_macro]
1323 #[rustc_builtin_macro] 1290macro_rules! assert {}
1324 macro_rules! assert {}
1325 1291
1326 fn bar() -> bool { true } 1292fn bar() -> bool { true }
1327 fn foo() { 1293fn foo() {
1328 assert!(ba<|>r()); 1294 assert!(ba<|>r());
1329 } 1295}
1330 "#, 1296"#,
1331 &["fn bar() -> bool"], 1297 expect![[r#"
1298 *bar*
1299 ```rust
1300 fn bar() -> bool
1301 ```
1302 "#]],
1332 ); 1303 );
1333
1334 assert_eq!(hover_on, "bar");
1335 } 1304 }
1336 1305
1337 #[test] 1306 #[test]
1338 fn test_hover_through_literal_string_in_builtin_macro() { 1307 fn test_hover_through_literal_string_in_builtin_macro() {
1339 check_hover_no_result( 1308 check_hover_no_result(
1340 r#" 1309 r#"
1341 //- /lib.rs
1342 #[rustc_builtin_macro] 1310 #[rustc_builtin_macro]
1343 macro_rules! format {} 1311 macro_rules! format {}
1344 1312
@@ -1351,122 +1319,159 @@ fn func(foo: i32) { if true { <|>foo; }; }
1351 1319
1352 #[test] 1320 #[test]
1353 fn test_hover_non_ascii_space_doc() { 1321 fn test_hover_non_ascii_space_doc() {
1354 check_hover_result( 1322 check(
1355 " 1323 "
1356 //- /lib.rs 1324/// <- `\u{3000}` here
1357 /// <- `\u{3000}` here 1325fn foo() { }
1358 fn foo() {
1359 }
1360 1326
1361 fn bar() { 1327fn bar() { fo<|>o(); }
1362 fo<|>o(); 1328",
1363 } 1329 expect![[r#"
1364 ", 1330 *foo*
1365 &["fn foo()\n```\n___\n\n<- `\u{3000}` here"], 1331 ```rust
1332 fn foo()
1333 ```
1334 ___
1335
1336 <- ` ` here
1337 "#]],
1366 ); 1338 );
1367 } 1339 }
1368 1340
1369 #[test] 1341 #[test]
1370 fn test_hover_function_show_qualifiers() { 1342 fn test_hover_function_show_qualifiers() {
1371 check_hover_result( 1343 check(
1372 " 1344 r#"async fn foo<|>() {}"#,
1373 //- /lib.rs 1345 expect![[r#"
1374 async fn foo<|>() {} 1346 *foo*
1375 ", 1347 ```rust
1376 &["async fn foo()"], 1348 async fn foo()
1377 ); 1349 ```
1378 check_hover_result( 1350 "#]],
1379 " 1351 );
1380 //- /lib.rs 1352 check(
1381 pub const unsafe fn foo<|>() {} 1353 r#"pub const unsafe fn foo<|>() {}"#,
1382 ", 1354 expect![[r#"
1383 &["pub const unsafe fn foo()"], 1355 *foo*
1384 ); 1356 ```rust
1385 check_hover_result( 1357 pub const unsafe fn foo()
1386 r#" 1358 ```
1387 //- /lib.rs 1359 "#]],
1388 pub(crate) async unsafe extern "C" fn foo<|>() {} 1360 );
1389 "#, 1361 check(
1390 &[r#"pub(crate) async unsafe extern "C" fn foo()"#], 1362 r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
1363 expect![[r#"
1364 *foo*
1365 ```rust
1366 pub(crate) async unsafe extern "C" fn foo()
1367 ```
1368 "#]],
1391 ); 1369 );
1392 } 1370 }
1393 1371
1394 #[test] 1372 #[test]
1395 fn test_hover_trait_show_qualifiers() { 1373 fn test_hover_trait_show_qualifiers() {
1396 let (_, actions) = check_hover_result( 1374 check_actions(
1397 " 1375 r"unsafe trait foo<|>() {}",
1398 //- /lib.rs 1376 expect![[r#"
1399 unsafe trait foo<|>() {} 1377 [
1400 ", 1378 Implementaion(
1401 &["unsafe trait foo"], 1379 FilePosition {
1380 file_id: FileId(
1381 1,
1382 ),
1383 offset: 13,
1384 },
1385 ),
1386 ]
1387 "#]],
1402 ); 1388 );
1403 assert_impl_action(&actions[0], 13);
1404 } 1389 }
1405 1390
1406 #[test] 1391 #[test]
1407 fn test_hover_mod_with_same_name_as_function() { 1392 fn test_hover_mod_with_same_name_as_function() {
1408 check_hover_result( 1393 check(
1409 " 1394 r#"
1410 //- /lib.rs 1395use self::m<|>y::Bar;
1411 use self::m<|>y::Bar; 1396mod my { pub struct Bar; }
1412
1413 mod my {
1414 pub struct Bar;
1415 }
1416 1397
1417 fn my() {} 1398fn my() {}
1418 ", 1399"#,
1419 &["mod my"], 1400 expect![[r#"
1401 *my*
1402 ```rust
1403 mod my
1404 ```
1405 "#]],
1420 ); 1406 );
1421 } 1407 }
1422 1408
1423 #[test] 1409 #[test]
1424 fn test_hover_struct_doc_comment() { 1410 fn test_hover_struct_doc_comment() {
1425 check_hover_result( 1411 check(
1426 r#" 1412 r#"
1427 //- /lib.rs 1413/// bar docs
1428 /// bar docs 1414struct Bar;
1429 struct Bar;
1430 1415
1431 fn foo() { 1416fn foo() { let bar = Ba<|>r; }
1432 let bar = Ba<|>r; 1417"#,
1433 } 1418 expect![[r#"
1434 "#, 1419 *Bar*
1435 &["struct Bar\n```\n___\n\nbar docs"], 1420 ```rust
1421 struct Bar
1422 ```
1423 ___
1424
1425 bar docs
1426 "#]],
1436 ); 1427 );
1437 } 1428 }
1438 1429
1439 #[test] 1430 #[test]
1440 fn test_hover_struct_doc_attr() { 1431 fn test_hover_struct_doc_attr() {
1441 check_hover_result( 1432 check(
1442 r#" 1433 r#"
1443 //- /lib.rs 1434#[doc = "bar docs"]
1444 #[doc = "bar docs"] 1435struct Bar;
1445 struct Bar;
1446 1436
1447 fn foo() { 1437fn foo() { let bar = Ba<|>r; }
1448 let bar = Ba<|>r; 1438"#,
1449 } 1439 expect![[r#"
1450 "#, 1440 *Bar*
1451 &["struct Bar\n```\n___\n\nbar docs"], 1441 ```rust
1442 struct Bar
1443 ```
1444 ___
1445
1446 bar docs
1447 "#]],
1452 ); 1448 );
1453 } 1449 }
1454 1450
1455 #[test] 1451 #[test]
1456 fn test_hover_struct_doc_attr_multiple_and_mixed() { 1452 fn test_hover_struct_doc_attr_multiple_and_mixed() {
1457 check_hover_result( 1453 check(
1458 r#" 1454 r#"
1459 //- /lib.rs 1455/// bar docs 0
1460 /// bar docs 0 1456#[doc = "bar docs 1"]
1461 #[doc = "bar docs 1"] 1457#[doc = "bar docs 2"]
1462 #[doc = "bar docs 2"] 1458struct Bar;
1463 struct Bar;
1464 1459
1465 fn foo() { 1460fn foo() { let bar = Ba<|>r; }
1466 let bar = Ba<|>r; 1461"#,
1467 } 1462 expect![[r#"
1468 "#, 1463 *Bar*
1469 &["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"], 1464 ```rust
1465 struct Bar
1466 ```
1467 ___
1468
1469 bar docs 0
1470
1471 bar docs 1
1472
1473 bar docs 2
1474 "#]],
1470 ); 1475 );
1471 } 1476 }
1472 1477
@@ -1623,27 +1628,35 @@ fn func(foo: i32) { if true { <|>foo; }; }
1623 fn test_hover_macro_generated_struct_fn_doc_comment() { 1628 fn test_hover_macro_generated_struct_fn_doc_comment() {
1624 mark::check!(hover_macro_generated_struct_fn_doc_comment); 1629 mark::check!(hover_macro_generated_struct_fn_doc_comment);
1625 1630
1626 check_hover_result( 1631 check(
1627 r#" 1632 r#"
1628 //- /lib.rs 1633macro_rules! bar {
1629 macro_rules! bar { 1634 () => {
1630 () => { 1635 struct Bar;
1631 struct Bar; 1636 impl Bar {
1632 impl Bar { 1637 /// Do the foo
1633 /// Do the foo 1638 fn foo(&self) {}
1634 fn foo(&self) {} 1639 }
1635 } 1640 }
1636 } 1641}
1637 }
1638 1642
1639 bar!(); 1643bar!();
1640 1644
1641 fn foo() { 1645fn foo() { let bar = Bar; bar.fo<|>o(); }
1642 let bar = Bar; 1646"#,
1643 bar.fo<|>o(); 1647 expect![[r#"
1644 } 1648 *foo*
1645 "#, 1649 ```rust
1646 &["test::Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], 1650 Bar
1651 ```
1652
1653 ```rust
1654 fn foo(&self)
1655 ```
1656 ___
1657
1658 Do the foo
1659 "#]],
1647 ); 1660 );
1648 } 1661 }
1649 1662
@@ -1651,1204 +1664,1155 @@ fn func(foo: i32) { if true { <|>foo; }; }
1651 fn test_hover_macro_generated_struct_fn_doc_attr() { 1664 fn test_hover_macro_generated_struct_fn_doc_attr() {
1652 mark::check!(hover_macro_generated_struct_fn_doc_attr); 1665 mark::check!(hover_macro_generated_struct_fn_doc_attr);
1653 1666
1654 check_hover_result( 1667 check(
1655 r#" 1668 r#"
1656 //- /lib.rs 1669macro_rules! bar {
1657 macro_rules! bar { 1670 () => {
1658 () => { 1671 struct Bar;
1659 struct Bar; 1672 impl Bar {
1660 impl Bar { 1673 #[doc = "Do the foo"]
1661 #[doc = "Do the foo"] 1674 fn foo(&self) {}
1662 fn foo(&self) {} 1675 }
1663 } 1676 }
1664 } 1677}
1665 }
1666 1678
1667 bar!(); 1679bar!();
1668 1680
1669 fn foo() { 1681fn foo() { let bar = Bar; bar.fo<|>o(); }
1670 let bar = Bar; 1682"#,
1671 bar.fo<|>o(); 1683 expect![[r#"
1672 } 1684 *foo*
1673 "#, 1685 ```rust
1674 &["test::Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"], 1686 Bar
1687 ```
1688
1689 ```rust
1690 fn foo(&self)
1691 ```
1692 ___
1693
1694 Do the foo
1695 "#]],
1675 ); 1696 );
1676 } 1697 }
1677 1698
1678 #[test] 1699 #[test]
1679 fn test_hover_trait_has_impl_action() { 1700 fn test_hover_trait_has_impl_action() {
1680 let (_, actions) = check_hover_result( 1701 check_actions(
1681 " 1702 r#"trait foo<|>() {}"#,
1682 //- /lib.rs 1703 expect![[r#"
1683 trait foo<|>() {} 1704 [
1684 ", 1705 Implementaion(
1685 &["trait foo"], 1706 FilePosition {
1707 file_id: FileId(
1708 1,
1709 ),
1710 offset: 6,
1711 },
1712 ),
1713 ]
1714 "#]],
1686 ); 1715 );
1687 assert_impl_action(&actions[0], 6);
1688 } 1716 }
1689 1717
1690 #[test] 1718 #[test]
1691 fn test_hover_struct_has_impl_action() { 1719 fn test_hover_struct_has_impl_action() {
1692 let (_, actions) = check_hover_result( 1720 check_actions(
1693 " 1721 r"struct foo<|>() {}",
1694 //- /lib.rs 1722 expect![[r#"
1695 struct foo<|>() {} 1723 [
1696 ", 1724 Implementaion(
1697 &["struct foo"], 1725 FilePosition {
1726 file_id: FileId(
1727 1,
1728 ),
1729 offset: 7,
1730 },
1731 ),
1732 ]
1733 "#]],
1698 ); 1734 );
1699 assert_impl_action(&actions[0], 7);
1700 } 1735 }
1701 1736
1702 #[test] 1737 #[test]
1703 fn test_hover_union_has_impl_action() { 1738 fn test_hover_union_has_impl_action() {
1704 let (_, actions) = check_hover_result( 1739 check_actions(
1705 " 1740 r#"union foo<|>() {}"#,
1706 //- /lib.rs 1741 expect![[r#"
1707 union foo<|>() {} 1742 [
1708 ", 1743 Implementaion(
1709 &["union foo"], 1744 FilePosition {
1745 file_id: FileId(
1746 1,
1747 ),
1748 offset: 6,
1749 },
1750 ),
1751 ]
1752 "#]],
1710 ); 1753 );
1711 assert_impl_action(&actions[0], 6);
1712 } 1754 }
1713 1755
1714 #[test] 1756 #[test]
1715 fn test_hover_enum_has_impl_action() { 1757 fn test_hover_enum_has_impl_action() {
1716 let (_, actions) = check_hover_result( 1758 check_actions(
1717 " 1759 r"enum foo<|>() { A, B }",
1718 //- /lib.rs 1760 expect![[r#"
1719 enum foo<|>() { 1761 [
1720 A, 1762 Implementaion(
1721 B 1763 FilePosition {
1722 } 1764 file_id: FileId(
1723 ", 1765 1,
1724 &["enum foo"], 1766 ),
1767 offset: 5,
1768 },
1769 ),
1770 ]
1771 "#]],
1725 ); 1772 );
1726 assert_impl_action(&actions[0], 5);
1727 } 1773 }
1728 1774
1729 #[test] 1775 #[test]
1730 fn test_hover_test_has_action() { 1776 fn test_hover_test_has_action() {
1731 let (_, actions) = check_hover_result( 1777 check_actions(
1732 " 1778 r#"
1733 //- /lib.rs 1779#[test]
1734 #[test] 1780fn foo_<|>test() {}
1735 fn foo_<|>test() {} 1781"#,
1736 ", 1782 expect![[r#"
1737 &["fn foo_test()"], 1783 [
1738 ); 1784 Runnable(
1739 assert_debug_snapshot!(actions, 1785 Runnable {
1740 @r###" 1786 nav: NavigationTarget {
1741 [ 1787 file_id: FileId(
1742 Runnable( 1788 1,
1743 Runnable { 1789 ),
1744 nav: NavigationTarget { 1790 full_range: 0..24,
1745 file_id: FileId( 1791 focus_range: Some(
1746 1, 1792 11..19,
1747 ), 1793 ),
1748 full_range: 0..24, 1794 name: "foo_test",
1749 name: "foo_test", 1795 kind: FN,
1750 kind: FN_DEF, 1796 container_name: None,
1751 focus_range: Some( 1797 description: None,
1752 11..19, 1798 docs: None,
1753 ), 1799 },
1754 container_name: None, 1800 kind: Test {
1755 description: None, 1801 test_id: Path(
1756 docs: None, 1802 "foo_test",
1757 }, 1803 ),
1758 kind: Test { 1804 attr: TestAttr {
1759 test_id: Path( 1805 ignore: false,
1760 "foo_test", 1806 },
1761 ),
1762 attr: TestAttr {
1763 ignore: false,
1764 }, 1807 },
1808 cfg_exprs: [],
1765 }, 1809 },
1766 cfg_exprs: [], 1810 ),
1767 }, 1811 ]
1768 ), 1812 "#]],
1769 ] 1813 );
1770 "###);
1771 } 1814 }
1772 1815
1773 #[test] 1816 #[test]
1774 fn test_hover_test_mod_has_action() { 1817 fn test_hover_test_mod_has_action() {
1775 let (_, actions) = check_hover_result( 1818 check_actions(
1776 " 1819 r#"
1777 //- /lib.rs 1820mod tests<|> {
1778 mod tests<|> { 1821 #[test]
1779 #[test] 1822 fn foo_test() {}
1780 fn foo_test() {} 1823}
1781 } 1824"#,
1782 ", 1825 expect![[r#"
1783 &["mod tests"], 1826 [
1784 ); 1827 Runnable(
1785 assert_debug_snapshot!(actions, 1828 Runnable {
1786 @r###" 1829 nav: NavigationTarget {
1787 [ 1830 file_id: FileId(
1788 Runnable( 1831 1,
1789 Runnable { 1832 ),
1790 nav: NavigationTarget { 1833 full_range: 0..46,
1791 file_id: FileId( 1834 focus_range: Some(
1792 1, 1835 4..9,
1793 ), 1836 ),
1794 full_range: 0..46, 1837 name: "tests",
1795 name: "tests", 1838 kind: MODULE,
1796 kind: MODULE, 1839 container_name: None,
1797 focus_range: Some( 1840 description: None,
1798 4..9, 1841 docs: None,
1799 ), 1842 },
1800 container_name: None, 1843 kind: TestMod {
1801 description: None, 1844 path: "tests",
1802 docs: None, 1845 },
1803 }, 1846 cfg_exprs: [],
1804 kind: TestMod {
1805 path: "tests",
1806 }, 1847 },
1807 cfg_exprs: [], 1848 ),
1808 }, 1849 ]
1809 ), 1850 "#]],
1810 ] 1851 );
1811 "###);
1812 } 1852 }
1813 1853
1814 #[test] 1854 #[test]
1815 fn test_hover_struct_has_goto_type_action() { 1855 fn test_hover_struct_has_goto_type_action() {
1816 let (_, actions) = check_hover_result( 1856 check_actions(
1817 " 1857 r#"
1818 //- /main.rs 1858struct S{ f1: u32 }
1819 struct S{ f1: u32 }
1820 1859
1821 fn main() { 1860fn main() { let s<|>t = S{ f1:0 }; }
1822 let s<|>t = S{ f1:0 }; 1861 "#,
1823 } 1862 expect![[r#"
1824 ",
1825 &["S"],
1826 );
1827 assert_debug_snapshot!(actions,
1828 @r###"
1829 [
1830 GoToType(
1831 [ 1863 [
1832 HoverGotoTypeData { 1864 GoToType(
1833 mod_path: "test::S", 1865 [
1834 nav: NavigationTarget { 1866 HoverGotoTypeData {
1835 file_id: FileId( 1867 mod_path: "S",
1836 1, 1868 nav: NavigationTarget {
1837 ), 1869 file_id: FileId(
1838 full_range: 0..19, 1870 1,
1839 name: "S", 1871 ),
1840 kind: STRUCT_DEF, 1872 full_range: 0..19,
1841 focus_range: Some( 1873 focus_range: Some(
1842 7..8, 1874 7..8,
1843 ), 1875 ),
1844 container_name: None, 1876 name: "S",
1845 description: Some( 1877 kind: STRUCT,
1846 "struct S", 1878 container_name: None,
1847 ), 1879 description: Some(
1848 docs: None, 1880 "struct S",
1849 }, 1881 ),
1850 }, 1882 docs: None,
1851 ], 1883 },
1852 ), 1884 },
1853 ] 1885 ],
1854 "###); 1886 ),
1887 ]
1888 "#]],
1889 );
1855 } 1890 }
1856 1891
1857 #[test] 1892 #[test]
1858 fn test_hover_generic_struct_has_goto_type_actions() { 1893 fn test_hover_generic_struct_has_goto_type_actions() {
1859 let (_, actions) = check_hover_result( 1894 check_actions(
1860 " 1895 r#"
1861 //- /main.rs 1896struct Arg(u32);
1862 struct Arg(u32); 1897struct S<T>{ f1: T }
1863 struct S<T>{ f1: T }
1864 1898
1865 fn main() { 1899fn main() { let s<|>t = S{ f1:Arg(0) }; }
1866 let s<|>t = S{ f1:Arg(0) }; 1900"#,
1867 } 1901 expect![[r#"
1868 ",
1869 &["S<Arg>"],
1870 );
1871 assert_debug_snapshot!(actions,
1872 @r###"
1873 [
1874 GoToType(
1875 [ 1902 [
1876 HoverGotoTypeData { 1903 GoToType(
1877 mod_path: "test::S", 1904 [
1878 nav: NavigationTarget { 1905 HoverGotoTypeData {
1879 file_id: FileId( 1906 mod_path: "S",
1880 1, 1907 nav: NavigationTarget {
1881 ), 1908 file_id: FileId(
1882 full_range: 17..37, 1909 1,
1883 name: "S", 1910 ),
1884 kind: STRUCT_DEF, 1911 full_range: 17..37,
1885 focus_range: Some( 1912 focus_range: Some(
1886 24..25, 1913 24..25,
1887 ), 1914 ),
1888 container_name: None, 1915 name: "S",
1889 description: Some( 1916 kind: STRUCT,
1890 "struct S", 1917 container_name: None,
1891 ), 1918 description: Some(
1892 docs: None, 1919 "struct S",
1893 }, 1920 ),
1894 }, 1921 docs: None,
1895 HoverGotoTypeData { 1922 },
1896 mod_path: "test::Arg", 1923 },
1897 nav: NavigationTarget { 1924 HoverGotoTypeData {
1898 file_id: FileId( 1925 mod_path: "Arg",
1899 1, 1926 nav: NavigationTarget {
1900 ), 1927 file_id: FileId(
1901 full_range: 0..16, 1928 1,
1902 name: "Arg", 1929 ),
1903 kind: STRUCT_DEF, 1930 full_range: 0..16,
1904 focus_range: Some( 1931 focus_range: Some(
1905 7..10, 1932 7..10,
1906 ), 1933 ),
1907 container_name: None, 1934 name: "Arg",
1908 description: Some( 1935 kind: STRUCT,
1909 "struct Arg", 1936 container_name: None,
1910 ), 1937 description: Some(
1911 docs: None, 1938 "struct Arg",
1912 }, 1939 ),
1913 }, 1940 docs: None,
1914 ], 1941 },
1915 ), 1942 },
1916 ] 1943 ],
1917 "###); 1944 ),
1945 ]
1946 "#]],
1947 );
1918 } 1948 }
1919 1949
1920 #[test] 1950 #[test]
1921 fn test_hover_generic_struct_has_flattened_goto_type_actions() { 1951 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1922 let (_, actions) = check_hover_result( 1952 check_actions(
1923 " 1953 r#"
1924 //- /main.rs 1954struct Arg(u32);
1925 struct Arg(u32); 1955struct S<T>{ f1: T }
1926 struct S<T>{ f1: T }
1927 1956
1928 fn main() { 1957fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
1929 let s<|>t = S{ f1: S{ f1: Arg(0) } }; 1958 "#,
1930 } 1959 expect![[r#"
1931 ",
1932 &["S<S<Arg>>"],
1933 );
1934 assert_debug_snapshot!(actions,
1935 @r###"
1936 [
1937 GoToType(
1938 [ 1960 [
1939 HoverGotoTypeData { 1961 GoToType(
1940 mod_path: "test::S", 1962 [
1941 nav: NavigationTarget { 1963 HoverGotoTypeData {
1942 file_id: FileId( 1964 mod_path: "S",
1943 1, 1965 nav: NavigationTarget {
1944 ), 1966 file_id: FileId(
1945 full_range: 17..37, 1967 1,
1946 name: "S", 1968 ),
1947 kind: STRUCT_DEF, 1969 full_range: 17..37,
1948 focus_range: Some( 1970 focus_range: Some(
1949 24..25, 1971 24..25,
1950 ), 1972 ),
1951 container_name: None, 1973 name: "S",
1952 description: Some( 1974 kind: STRUCT,
1953 "struct S", 1975 container_name: None,
1954 ), 1976 description: Some(
1955 docs: None, 1977 "struct S",
1956 }, 1978 ),
1957 }, 1979 docs: None,
1958 HoverGotoTypeData { 1980 },
1959 mod_path: "test::Arg", 1981 },
1960 nav: NavigationTarget { 1982 HoverGotoTypeData {
1961 file_id: FileId( 1983 mod_path: "Arg",
1962 1, 1984 nav: NavigationTarget {
1963 ), 1985 file_id: FileId(
1964 full_range: 0..16, 1986 1,
1965 name: "Arg", 1987 ),
1966 kind: STRUCT_DEF, 1988 full_range: 0..16,
1967 focus_range: Some( 1989 focus_range: Some(
1968 7..10, 1990 7..10,
1969 ), 1991 ),
1970 container_name: None, 1992 name: "Arg",
1971 description: Some( 1993 kind: STRUCT,
1972 "struct Arg", 1994 container_name: None,
1973 ), 1995 description: Some(
1974 docs: None, 1996 "struct Arg",
1975 }, 1997 ),
1976 }, 1998 docs: None,
1977 ], 1999 },
1978 ), 2000 },
1979 ] 2001 ],
1980 "###); 2002 ),
2003 ]
2004 "#]],
2005 );
1981 } 2006 }
1982 2007
1983 #[test] 2008 #[test]
1984 fn test_hover_tuple_has_goto_type_actions() { 2009 fn test_hover_tuple_has_goto_type_actions() {
1985 let (_, actions) = check_hover_result( 2010 check_actions(
1986 " 2011 r#"
1987 //- /main.rs 2012struct A(u32);
1988 struct A(u32); 2013struct B(u32);
1989 struct B(u32); 2014mod M {
1990 mod M { 2015 pub struct C(u32);
1991 pub struct C(u32); 2016}
1992 }
1993 2017
1994 fn main() { 2018fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
1995 let s<|>t = (A(1), B(2), M::C(3) ); 2019"#,
1996 } 2020 expect![[r#"
1997 ",
1998 &["(A, B, C)"],
1999 );
2000 assert_debug_snapshot!(actions,
2001 @r###"
2002 [
2003 GoToType(
2004 [ 2021 [
2005 HoverGotoTypeData { 2022 GoToType(
2006 mod_path: "test::A", 2023 [
2007 nav: NavigationTarget { 2024 HoverGotoTypeData {
2008 file_id: FileId( 2025 mod_path: "A",
2009 1, 2026 nav: NavigationTarget {
2010 ), 2027 file_id: FileId(
2011 full_range: 0..14, 2028 1,
2012 name: "A", 2029 ),
2013 kind: STRUCT_DEF, 2030 full_range: 0..14,
2014 focus_range: Some( 2031 focus_range: Some(
2015 7..8, 2032 7..8,
2016 ), 2033 ),
2017 container_name: None, 2034 name: "A",
2018 description: Some( 2035 kind: STRUCT,
2019 "struct A", 2036 container_name: None,
2020 ), 2037 description: Some(
2021 docs: None, 2038 "struct A",
2022 }, 2039 ),
2023 }, 2040 docs: None,
2024 HoverGotoTypeData { 2041 },
2025 mod_path: "test::B", 2042 },
2026 nav: NavigationTarget { 2043 HoverGotoTypeData {
2027 file_id: FileId( 2044 mod_path: "B",
2028 1, 2045 nav: NavigationTarget {
2029 ), 2046 file_id: FileId(
2030 full_range: 15..29, 2047 1,
2031 name: "B", 2048 ),
2032 kind: STRUCT_DEF, 2049 full_range: 15..29,
2033 focus_range: Some( 2050 focus_range: Some(
2034 22..23, 2051 22..23,
2035 ), 2052 ),
2036 container_name: None, 2053 name: "B",
2037 description: Some( 2054 kind: STRUCT,
2038 "struct B", 2055 container_name: None,
2039 ), 2056 description: Some(
2040 docs: None, 2057 "struct B",
2041 }, 2058 ),
2042 }, 2059 docs: None,
2043 HoverGotoTypeData { 2060 },
2044 mod_path: "test::M::C", 2061 },
2045 nav: NavigationTarget { 2062 HoverGotoTypeData {
2046 file_id: FileId( 2063 mod_path: "M::C",
2047 1, 2064 nav: NavigationTarget {
2048 ), 2065 file_id: FileId(
2049 full_range: 42..60, 2066 1,
2050 name: "C", 2067 ),
2051 kind: STRUCT_DEF, 2068 full_range: 42..60,
2052 focus_range: Some( 2069 focus_range: Some(
2053 53..54, 2070 53..54,
2054 ), 2071 ),
2055 container_name: None, 2072 name: "C",
2056 description: Some( 2073 kind: STRUCT,
2057 "pub struct C", 2074 container_name: None,
2058 ), 2075 description: Some(
2059 docs: None, 2076 "pub struct C",
2060 }, 2077 ),
2061 }, 2078 docs: None,
2062 ], 2079 },
2063 ), 2080 },
2064 ] 2081 ],
2065 "###); 2082 ),
2083 ]
2084 "#]],
2085 );
2066 } 2086 }
2067 2087
2068 #[test] 2088 #[test]
2069 fn test_hover_return_impl_trait_has_goto_type_action() { 2089 fn test_hover_return_impl_trait_has_goto_type_action() {
2070 let (_, actions) = check_hover_result( 2090 check_actions(
2071 " 2091 r#"
2072 //- /main.rs 2092trait Foo {}
2073 trait Foo {} 2093fn foo() -> impl Foo {}
2074
2075 fn foo() -> impl Foo {}
2076 2094
2077 fn main() { 2095fn main() { let s<|>t = foo(); }
2078 let s<|>t = foo(); 2096"#,
2079 } 2097 expect![[r#"
2080 ",
2081 &["impl Foo"],
2082 );
2083 assert_debug_snapshot!(actions,
2084 @r###"
2085 [
2086 GoToType(
2087 [ 2098 [
2088 HoverGotoTypeData { 2099 GoToType(
2089 mod_path: "test::Foo", 2100 [
2090 nav: NavigationTarget { 2101 HoverGotoTypeData {
2091 file_id: FileId( 2102 mod_path: "Foo",
2092 1, 2103 nav: NavigationTarget {
2093 ), 2104 file_id: FileId(
2094 full_range: 0..12, 2105 1,
2095 name: "Foo", 2106 ),
2096 kind: TRAIT_DEF, 2107 full_range: 0..12,
2097 focus_range: Some( 2108 focus_range: Some(
2098 6..9, 2109 6..9,
2099 ), 2110 ),
2100 container_name: None, 2111 name: "Foo",
2101 description: Some( 2112 kind: TRAIT,
2102 "trait Foo", 2113 container_name: None,
2103 ), 2114 description: Some(
2104 docs: None, 2115 "trait Foo",
2105 }, 2116 ),
2106 }, 2117 docs: None,
2107 ], 2118 },
2108 ), 2119 },
2109 ] 2120 ],
2110 "###); 2121 ),
2122 ]
2123 "#]],
2124 );
2111 } 2125 }
2112 2126
2113 #[test] 2127 #[test]
2114 fn test_hover_generic_return_impl_trait_has_goto_type_action() { 2128 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
2115 let (_, actions) = check_hover_result( 2129 check_actions(
2116 " 2130 r#"
2117 //- /main.rs 2131trait Foo<T> {}
2118 trait Foo<T> {} 2132struct S;
2119 struct S; 2133fn foo() -> impl Foo<S> {}
2120
2121 fn foo() -> impl Foo<S> {}
2122 2134
2123 fn main() { 2135fn main() { let s<|>t = foo(); }
2124 let s<|>t = foo(); 2136"#,
2125 } 2137 expect![[r#"
2126 ",
2127 &["impl Foo<S>"],
2128 );
2129 assert_debug_snapshot!(actions,
2130 @r###"
2131 [
2132 GoToType(
2133 [ 2138 [
2134 HoverGotoTypeData { 2139 GoToType(
2135 mod_path: "test::Foo", 2140 [
2136 nav: NavigationTarget { 2141 HoverGotoTypeData {
2137 file_id: FileId( 2142 mod_path: "Foo",
2138 1, 2143 nav: NavigationTarget {
2139 ), 2144 file_id: FileId(
2140 full_range: 0..15, 2145 1,
2141 name: "Foo", 2146 ),
2142 kind: TRAIT_DEF, 2147 full_range: 0..15,
2143 focus_range: Some( 2148 focus_range: Some(
2144 6..9, 2149 6..9,
2145 ), 2150 ),
2146 container_name: None, 2151 name: "Foo",
2147 description: Some( 2152 kind: TRAIT,
2148 "trait Foo", 2153 container_name: None,
2149 ), 2154 description: Some(
2150 docs: None, 2155 "trait Foo",
2151 }, 2156 ),
2152 }, 2157 docs: None,
2153 HoverGotoTypeData { 2158 },
2154 mod_path: "test::S", 2159 },
2155 nav: NavigationTarget { 2160 HoverGotoTypeData {
2156 file_id: FileId( 2161 mod_path: "S",
2157 1, 2162 nav: NavigationTarget {
2158 ), 2163 file_id: FileId(
2159 full_range: 16..25, 2164 1,
2160 name: "S", 2165 ),
2161 kind: STRUCT_DEF, 2166 full_range: 16..25,
2162 focus_range: Some( 2167 focus_range: Some(
2163 23..24, 2168 23..24,
2164 ), 2169 ),
2165 container_name: None, 2170 name: "S",
2166 description: Some( 2171 kind: STRUCT,
2167 "struct S", 2172 container_name: None,
2168 ), 2173 description: Some(
2169 docs: None, 2174 "struct S",
2170 }, 2175 ),
2171 }, 2176 docs: None,
2172 ], 2177 },
2173 ), 2178 },
2174 ] 2179 ],
2175 "###); 2180 ),
2181 ]
2182 "#]],
2183 );
2176 } 2184 }
2177 2185
2178 #[test] 2186 #[test]
2179 fn test_hover_return_impl_traits_has_goto_type_action() { 2187 fn test_hover_return_impl_traits_has_goto_type_action() {
2180 let (_, actions) = check_hover_result( 2188 check_actions(
2181 " 2189 r#"
2182 //- /main.rs 2190trait Foo {}
2183 trait Foo {} 2191trait Bar {}
2184 trait Bar {} 2192fn foo() -> impl Foo + Bar {}
2185
2186 fn foo() -> impl Foo + Bar {}
2187 2193
2188 fn main() { 2194fn main() { let s<|>t = foo(); }
2189 let s<|>t = foo(); 2195 "#,
2190 } 2196 expect![[r#"
2191 ",
2192 &["impl Foo + Bar"],
2193 );
2194 assert_debug_snapshot!(actions,
2195 @r###"
2196 [
2197 GoToType(
2198 [ 2197 [
2199 HoverGotoTypeData { 2198 GoToType(
2200 mod_path: "test::Foo", 2199 [
2201 nav: NavigationTarget { 2200 HoverGotoTypeData {
2202 file_id: FileId( 2201 mod_path: "Foo",
2203 1, 2202 nav: NavigationTarget {
2204 ), 2203 file_id: FileId(
2205 full_range: 0..12, 2204 1,
2206 name: "Foo", 2205 ),
2207 kind: TRAIT_DEF, 2206 full_range: 0..12,
2208 focus_range: Some( 2207 focus_range: Some(
2209 6..9, 2208 6..9,
2210 ), 2209 ),
2211 container_name: None, 2210 name: "Foo",
2212 description: Some( 2211 kind: TRAIT,
2213 "trait Foo", 2212 container_name: None,
2214 ), 2213 description: Some(
2215 docs: None, 2214 "trait Foo",
2216 }, 2215 ),
2217 }, 2216 docs: None,
2218 HoverGotoTypeData { 2217 },
2219 mod_path: "test::Bar", 2218 },
2220 nav: NavigationTarget { 2219 HoverGotoTypeData {
2221 file_id: FileId( 2220 mod_path: "Bar",
2222 1, 2221 nav: NavigationTarget {
2223 ), 2222 file_id: FileId(
2224 full_range: 13..25, 2223 1,
2225 name: "Bar", 2224 ),
2226 kind: TRAIT_DEF, 2225 full_range: 13..25,
2227 focus_range: Some( 2226 focus_range: Some(
2228 19..22, 2227 19..22,
2229 ), 2228 ),
2230 container_name: None, 2229 name: "Bar",
2231 description: Some( 2230 kind: TRAIT,
2232 "trait Bar", 2231 container_name: None,
2233 ), 2232 description: Some(
2234 docs: None, 2233 "trait Bar",
2235 }, 2234 ),
2236 }, 2235 docs: None,
2237 ], 2236 },
2238 ), 2237 },
2239 ] 2238 ],
2240 "###); 2239 ),
2240 ]
2241 "#]],
2242 );
2241 } 2243 }
2242 2244
2243 #[test] 2245 #[test]
2244 fn test_hover_generic_return_impl_traits_has_goto_type_action() { 2246 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
2245 let (_, actions) = check_hover_result( 2247 check_actions(
2246 " 2248 r#"
2247 //- /main.rs 2249trait Foo<T> {}
2248 trait Foo<T> {} 2250trait Bar<T> {}
2249 trait Bar<T> {} 2251struct S1 {}
2250 struct S1 {} 2252struct S2 {}
2251 struct S2 {}
2252 2253
2253 fn foo() -> impl Foo<S1> + Bar<S2> {} 2254fn foo() -> impl Foo<S1> + Bar<S2> {}
2254 2255
2255 fn main() { 2256fn main() { let s<|>t = foo(); }
2256 let s<|>t = foo(); 2257"#,
2257 } 2258 expect![[r#"
2258 ",
2259 &["impl Foo<S1> + Bar<S2>"],
2260 );
2261 assert_debug_snapshot!(actions,
2262 @r###"
2263 [
2264 GoToType(
2265 [ 2259 [
2266 HoverGotoTypeData { 2260 GoToType(
2267 mod_path: "test::Foo", 2261 [
2268 nav: NavigationTarget { 2262 HoverGotoTypeData {
2269 file_id: FileId( 2263 mod_path: "Foo",
2270 1, 2264 nav: NavigationTarget {
2271 ), 2265 file_id: FileId(
2272 full_range: 0..15, 2266 1,
2273 name: "Foo", 2267 ),
2274 kind: TRAIT_DEF, 2268 full_range: 0..15,
2275 focus_range: Some( 2269 focus_range: Some(
2276 6..9, 2270 6..9,
2277 ), 2271 ),
2278 container_name: None, 2272 name: "Foo",
2279 description: Some( 2273 kind: TRAIT,
2280 "trait Foo", 2274 container_name: None,
2281 ), 2275 description: Some(
2282 docs: None, 2276 "trait Foo",
2283 }, 2277 ),
2284 }, 2278 docs: None,
2285 HoverGotoTypeData { 2279 },
2286 mod_path: "test::Bar", 2280 },
2287 nav: NavigationTarget { 2281 HoverGotoTypeData {
2288 file_id: FileId( 2282 mod_path: "Bar",
2289 1, 2283 nav: NavigationTarget {
2290 ), 2284 file_id: FileId(
2291 full_range: 16..31, 2285 1,
2292 name: "Bar", 2286 ),
2293 kind: TRAIT_DEF, 2287 full_range: 16..31,
2294 focus_range: Some( 2288 focus_range: Some(
2295 22..25, 2289 22..25,
2296 ), 2290 ),
2297 container_name: None, 2291 name: "Bar",
2298 description: Some( 2292 kind: TRAIT,
2299 "trait Bar", 2293 container_name: None,
2300 ), 2294 description: Some(
2301 docs: None, 2295 "trait Bar",
2302 }, 2296 ),
2303 }, 2297 docs: None,
2304 HoverGotoTypeData { 2298 },
2305 mod_path: "test::S1", 2299 },
2306 nav: NavigationTarget { 2300 HoverGotoTypeData {
2307 file_id: FileId( 2301 mod_path: "S1",
2308 1, 2302 nav: NavigationTarget {
2309 ), 2303 file_id: FileId(
2310 full_range: 32..44, 2304 1,
2311 name: "S1", 2305 ),
2312 kind: STRUCT_DEF, 2306 full_range: 32..44,
2313 focus_range: Some( 2307 focus_range: Some(
2314 39..41, 2308 39..41,
2315 ), 2309 ),
2316 container_name: None, 2310 name: "S1",
2317 description: Some( 2311 kind: STRUCT,
2318 "struct S1", 2312 container_name: None,
2319 ), 2313 description: Some(
2320 docs: None, 2314 "struct S1",
2321 }, 2315 ),
2322 }, 2316 docs: None,
2323 HoverGotoTypeData { 2317 },
2324 mod_path: "test::S2", 2318 },
2325 nav: NavigationTarget { 2319 HoverGotoTypeData {
2326 file_id: FileId( 2320 mod_path: "S2",
2327 1, 2321 nav: NavigationTarget {
2328 ), 2322 file_id: FileId(
2329 full_range: 45..57, 2323 1,
2330 name: "S2", 2324 ),
2331 kind: STRUCT_DEF, 2325 full_range: 45..57,
2332 focus_range: Some( 2326 focus_range: Some(
2333 52..54, 2327 52..54,
2334 ), 2328 ),
2335 container_name: None, 2329 name: "S2",
2336 description: Some( 2330 kind: STRUCT,
2337 "struct S2", 2331 container_name: None,
2338 ), 2332 description: Some(
2339 docs: None, 2333 "struct S2",
2340 }, 2334 ),
2341 }, 2335 docs: None,
2342 ], 2336 },
2343 ), 2337 },
2344 ] 2338 ],
2345 "###); 2339 ),
2340 ]
2341 "#]],
2342 );
2346 } 2343 }
2347 2344
2348 #[test] 2345 #[test]
2349 fn test_hover_arg_impl_trait_has_goto_type_action() { 2346 fn test_hover_arg_impl_trait_has_goto_type_action() {
2350 let (_, actions) = check_hover_result( 2347 check_actions(
2351 " 2348 r#"
2352 //- /lib.rs 2349trait Foo {}
2353 trait Foo {} 2350fn foo(ar<|>g: &impl Foo) {}
2354 fn foo(ar<|>g: &impl Foo) {} 2351"#,
2355 ", 2352 expect![[r#"
2356 &["&impl Foo"],
2357 );
2358 assert_debug_snapshot!(actions,
2359 @r###"
2360 [
2361 GoToType(
2362 [ 2353 [
2363 HoverGotoTypeData { 2354 GoToType(
2364 mod_path: "test::Foo", 2355 [
2365 nav: NavigationTarget { 2356 HoverGotoTypeData {
2366 file_id: FileId( 2357 mod_path: "Foo",
2367 1, 2358 nav: NavigationTarget {
2368 ), 2359 file_id: FileId(
2369 full_range: 0..12, 2360 1,
2370 name: "Foo", 2361 ),
2371 kind: TRAIT_DEF, 2362 full_range: 0..12,
2372 focus_range: Some( 2363 focus_range: Some(
2373 6..9, 2364 6..9,
2374 ), 2365 ),
2375 container_name: None, 2366 name: "Foo",
2376 description: Some( 2367 kind: TRAIT,
2377 "trait Foo", 2368 container_name: None,
2378 ), 2369 description: Some(
2379 docs: None, 2370 "trait Foo",
2380 }, 2371 ),
2381 }, 2372 docs: None,
2382 ], 2373 },
2383 ), 2374 },
2384 ] 2375 ],
2385 "###); 2376 ),
2377 ]
2378 "#]],
2379 );
2386 } 2380 }
2387 2381
2388 #[test] 2382 #[test]
2389 fn test_hover_arg_impl_traits_has_goto_type_action() { 2383 fn test_hover_arg_impl_traits_has_goto_type_action() {
2390 let (_, actions) = check_hover_result( 2384 check_actions(
2391 " 2385 r#"
2392 //- /lib.rs 2386trait Foo {}
2393 trait Foo {} 2387trait Bar<T> {}
2394 trait Bar<T> {} 2388struct S{}
2395 struct S{}
2396 2389
2397 fn foo(ar<|>g: &impl Foo + Bar<S>) {} 2390fn foo(ar<|>g: &impl Foo + Bar<S>) {}
2398 ", 2391"#,
2399 &["&impl Foo + Bar<S>"], 2392 expect![[r#"
2400 );
2401 assert_debug_snapshot!(actions,
2402 @r###"
2403 [
2404 GoToType(
2405 [ 2393 [
2406 HoverGotoTypeData { 2394 GoToType(
2407 mod_path: "test::Foo", 2395 [
2408 nav: NavigationTarget { 2396 HoverGotoTypeData {
2409 file_id: FileId( 2397 mod_path: "Foo",
2410 1, 2398 nav: NavigationTarget {
2411 ), 2399 file_id: FileId(
2412 full_range: 0..12, 2400 1,
2413 name: "Foo", 2401 ),
2414 kind: TRAIT_DEF, 2402 full_range: 0..12,
2415 focus_range: Some( 2403 focus_range: Some(
2416 6..9, 2404 6..9,
2417 ), 2405 ),
2418 container_name: None, 2406 name: "Foo",
2419 description: Some( 2407 kind: TRAIT,
2420 "trait Foo", 2408 container_name: None,
2421 ), 2409 description: Some(
2422 docs: None, 2410 "trait Foo",
2423 }, 2411 ),
2424 }, 2412 docs: None,
2425 HoverGotoTypeData { 2413 },
2426 mod_path: "test::Bar", 2414 },
2427 nav: NavigationTarget { 2415 HoverGotoTypeData {
2428 file_id: FileId( 2416 mod_path: "Bar",
2429 1, 2417 nav: NavigationTarget {
2430 ), 2418 file_id: FileId(
2431 full_range: 13..28, 2419 1,
2432 name: "Bar", 2420 ),
2433 kind: TRAIT_DEF, 2421 full_range: 13..28,
2434 focus_range: Some( 2422 focus_range: Some(
2435 19..22, 2423 19..22,
2436 ), 2424 ),
2437 container_name: None, 2425 name: "Bar",
2438 description: Some( 2426 kind: TRAIT,
2439 "trait Bar", 2427 container_name: None,
2440 ), 2428 description: Some(
2441 docs: None, 2429 "trait Bar",
2442 }, 2430 ),
2443 }, 2431 docs: None,
2444 HoverGotoTypeData { 2432 },
2445 mod_path: "test::S", 2433 },
2446 nav: NavigationTarget { 2434 HoverGotoTypeData {
2447 file_id: FileId( 2435 mod_path: "S",
2448 1, 2436 nav: NavigationTarget {
2449 ), 2437 file_id: FileId(
2450 full_range: 29..39, 2438 1,
2451 name: "S", 2439 ),
2452 kind: STRUCT_DEF, 2440 full_range: 29..39,
2453 focus_range: Some( 2441 focus_range: Some(
2454 36..37, 2442 36..37,
2455 ), 2443 ),
2456 container_name: None, 2444 name: "S",
2457 description: Some( 2445 kind: STRUCT,
2458 "struct S", 2446 container_name: None,
2459 ), 2447 description: Some(
2460 docs: None, 2448 "struct S",
2461 }, 2449 ),
2462 }, 2450 docs: None,
2463 ], 2451 },
2464 ), 2452 },
2465 ] 2453 ],
2466 "###); 2454 ),
2455 ]
2456 "#]],
2457 );
2467 } 2458 }
2468 2459
2469 #[test] 2460 #[test]
2470 fn test_hover_arg_generic_impl_trait_has_goto_type_action() { 2461 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2471 let (_, actions) = check_hover_result( 2462 check_actions(
2472 " 2463 r#"
2473 //- /lib.rs 2464trait Foo<T> {}
2474 trait Foo<T> {} 2465struct S {}
2475 struct S {} 2466fn foo(ar<|>g: &impl Foo<S>) {}
2476 fn foo(ar<|>g: &impl Foo<S>) {} 2467"#,
2477 ", 2468 expect![[r#"
2478 &["&impl Foo<S>"],
2479 );
2480 assert_debug_snapshot!(actions,
2481 @r###"
2482 [
2483 GoToType(
2484 [ 2469 [
2485 HoverGotoTypeData { 2470 GoToType(
2486 mod_path: "test::Foo", 2471 [
2487 nav: NavigationTarget { 2472 HoverGotoTypeData {
2488 file_id: FileId( 2473 mod_path: "Foo",
2489 1, 2474 nav: NavigationTarget {
2490 ), 2475 file_id: FileId(
2491 full_range: 0..15, 2476 1,
2492 name: "Foo", 2477 ),
2493 kind: TRAIT_DEF, 2478 full_range: 0..15,
2494 focus_range: Some( 2479 focus_range: Some(
2495 6..9, 2480 6..9,
2496 ), 2481 ),
2497 container_name: None, 2482 name: "Foo",
2498 description: Some( 2483 kind: TRAIT,
2499 "trait Foo", 2484 container_name: None,
2500 ), 2485 description: Some(
2501 docs: None, 2486 "trait Foo",
2502 }, 2487 ),
2503 }, 2488 docs: None,
2504 HoverGotoTypeData { 2489 },
2505 mod_path: "test::S", 2490 },
2506 nav: NavigationTarget { 2491 HoverGotoTypeData {
2507 file_id: FileId( 2492 mod_path: "S",
2508 1, 2493 nav: NavigationTarget {
2509 ), 2494 file_id: FileId(
2510 full_range: 16..27, 2495 1,
2511 name: "S", 2496 ),
2512 kind: STRUCT_DEF, 2497 full_range: 16..27,
2513 focus_range: Some( 2498 focus_range: Some(
2514 23..24, 2499 23..24,
2515 ), 2500 ),
2516 container_name: None, 2501 name: "S",
2517 description: Some( 2502 kind: STRUCT,
2518 "struct S", 2503 container_name: None,
2519 ), 2504 description: Some(
2520 docs: None, 2505 "struct S",
2521 }, 2506 ),
2522 }, 2507 docs: None,
2523 ], 2508 },
2524 ), 2509 },
2525 ] 2510 ],
2526 "###); 2511 ),
2512 ]
2513 "#]],
2514 );
2527 } 2515 }
2528 2516
2529 #[test] 2517 #[test]
2530 fn test_hover_dyn_return_has_goto_type_action() { 2518 fn test_hover_dyn_return_has_goto_type_action() {
2531 let (_, actions) = check_hover_result( 2519 check_actions(
2532 " 2520 r#"
2533 //- /main.rs 2521trait Foo {}
2534 trait Foo {} 2522struct S;
2535 struct S; 2523impl Foo for S {}
2536 impl Foo for S {}
2537
2538 struct B<T>{}
2539 2524
2540 fn foo() -> B<dyn Foo> {} 2525struct B<T>{}
2526fn foo() -> B<dyn Foo> {}
2541 2527
2542 fn main() { 2528fn main() { let s<|>t = foo(); }
2543 let s<|>t = foo(); 2529"#,
2544 } 2530 expect![[r#"
2545 ",
2546 &["B<dyn Foo>"],
2547 );
2548 assert_debug_snapshot!(actions,
2549 @r###"
2550 [
2551 GoToType(
2552 [ 2531 [
2553 HoverGotoTypeData { 2532 GoToType(
2554 mod_path: "test::B", 2533 [
2555 nav: NavigationTarget { 2534 HoverGotoTypeData {
2556 file_id: FileId( 2535 mod_path: "B",
2557 1, 2536 nav: NavigationTarget {
2558 ), 2537 file_id: FileId(
2559 full_range: 42..55, 2538 1,
2560 name: "B", 2539 ),
2561 kind: STRUCT_DEF, 2540 full_range: 42..55,
2562 focus_range: Some( 2541 focus_range: Some(
2563 49..50, 2542 49..50,
2564 ), 2543 ),
2565 container_name: None, 2544 name: "B",
2566 description: Some( 2545 kind: STRUCT,
2567 "struct B", 2546 container_name: None,
2568 ), 2547 description: Some(
2569 docs: None, 2548 "struct B",
2570 }, 2549 ),
2571 }, 2550 docs: None,
2572 HoverGotoTypeData { 2551 },
2573 mod_path: "test::Foo", 2552 },
2574 nav: NavigationTarget { 2553 HoverGotoTypeData {
2575 file_id: FileId( 2554 mod_path: "Foo",
2576 1, 2555 nav: NavigationTarget {
2577 ), 2556 file_id: FileId(
2578 full_range: 0..12, 2557 1,
2579 name: "Foo", 2558 ),
2580 kind: TRAIT_DEF, 2559 full_range: 0..12,
2581 focus_range: Some( 2560 focus_range: Some(
2582 6..9, 2561 6..9,
2583 ), 2562 ),
2584 container_name: None, 2563 name: "Foo",
2585 description: Some( 2564 kind: TRAIT,
2586 "trait Foo", 2565 container_name: None,
2587 ), 2566 description: Some(
2588 docs: None, 2567 "trait Foo",
2589 }, 2568 ),
2590 }, 2569 docs: None,
2591 ], 2570 },
2592 ), 2571 },
2593 ] 2572 ],
2594 "###); 2573 ),
2574 ]
2575 "#]],
2576 );
2595 } 2577 }
2596 2578
2597 #[test] 2579 #[test]
2598 fn test_hover_dyn_arg_has_goto_type_action() { 2580 fn test_hover_dyn_arg_has_goto_type_action() {
2599 let (_, actions) = check_hover_result( 2581 check_actions(
2600 " 2582 r#"
2601 //- /lib.rs 2583trait Foo {}
2602 trait Foo {} 2584fn foo(ar<|>g: &dyn Foo) {}
2603 fn foo(ar<|>g: &dyn Foo) {} 2585"#,
2604 ", 2586 expect![[r#"
2605 &["&dyn Foo"],
2606 );
2607 assert_debug_snapshot!(actions,
2608 @r###"
2609 [
2610 GoToType(
2611 [ 2587 [
2612 HoverGotoTypeData { 2588 GoToType(
2613 mod_path: "test::Foo", 2589 [
2614 nav: NavigationTarget { 2590 HoverGotoTypeData {
2615 file_id: FileId( 2591 mod_path: "Foo",
2616 1, 2592 nav: NavigationTarget {
2617 ), 2593 file_id: FileId(
2618 full_range: 0..12, 2594 1,
2619 name: "Foo", 2595 ),
2620 kind: TRAIT_DEF, 2596 full_range: 0..12,
2621 focus_range: Some( 2597 focus_range: Some(
2622 6..9, 2598 6..9,
2623 ), 2599 ),
2624 container_name: None, 2600 name: "Foo",
2625 description: Some( 2601 kind: TRAIT,
2626 "trait Foo", 2602 container_name: None,
2627 ), 2603 description: Some(
2628 docs: None, 2604 "trait Foo",
2629 }, 2605 ),
2630 }, 2606 docs: None,
2631 ], 2607 },
2632 ), 2608 },
2633 ] 2609 ],
2634 "###); 2610 ),
2611 ]
2612 "#]],
2613 );
2635 } 2614 }
2636 2615
2637 #[test] 2616 #[test]
2638 fn test_hover_generic_dyn_arg_has_goto_type_action() { 2617 fn test_hover_generic_dyn_arg_has_goto_type_action() {
2639 let (_, actions) = check_hover_result( 2618 check_actions(
2640 " 2619 r#"
2641 //- /lib.rs 2620trait Foo<T> {}
2642 trait Foo<T> {} 2621struct S {}
2643 struct S {} 2622fn foo(ar<|>g: &dyn Foo<S>) {}
2644 fn foo(ar<|>g: &dyn Foo<S>) {} 2623"#,
2645 ", 2624 expect![[r#"
2646 &["&dyn Foo<S>"],
2647 );
2648 assert_debug_snapshot!(actions,
2649 @r###"
2650 [
2651 GoToType(
2652 [ 2625 [
2653 HoverGotoTypeData { 2626 GoToType(
2654 mod_path: "test::Foo", 2627 [
2655 nav: NavigationTarget { 2628 HoverGotoTypeData {
2656 file_id: FileId( 2629 mod_path: "Foo",
2657 1, 2630 nav: NavigationTarget {
2658 ), 2631 file_id: FileId(
2659 full_range: 0..15, 2632 1,
2660 name: "Foo", 2633 ),
2661 kind: TRAIT_DEF, 2634 full_range: 0..15,
2662 focus_range: Some( 2635 focus_range: Some(
2663 6..9, 2636 6..9,
2664 ), 2637 ),
2665 container_name: None, 2638 name: "Foo",
2666 description: Some( 2639 kind: TRAIT,
2667 "trait Foo", 2640 container_name: None,
2668 ), 2641 description: Some(
2669 docs: None, 2642 "trait Foo",
2670 }, 2643 ),
2671 }, 2644 docs: None,
2672 HoverGotoTypeData { 2645 },
2673 mod_path: "test::S", 2646 },
2674 nav: NavigationTarget { 2647 HoverGotoTypeData {
2675 file_id: FileId( 2648 mod_path: "S",
2676 1, 2649 nav: NavigationTarget {
2677 ), 2650 file_id: FileId(
2678 full_range: 16..27, 2651 1,
2679 name: "S", 2652 ),
2680 kind: STRUCT_DEF, 2653 full_range: 16..27,
2681 focus_range: Some( 2654 focus_range: Some(
2682 23..24, 2655 23..24,
2683 ), 2656 ),
2684 container_name: None, 2657 name: "S",
2685 description: Some( 2658 kind: STRUCT,
2686 "struct S", 2659 container_name: None,
2687 ), 2660 description: Some(
2688 docs: None, 2661 "struct S",
2689 }, 2662 ),
2690 }, 2663 docs: None,
2691 ], 2664 },
2692 ), 2665 },
2693 ] 2666 ],
2694 "###); 2667 ),
2668 ]
2669 "#]],
2670 );
2695 } 2671 }
2696 2672
2697 #[test] 2673 #[test]
2698 fn test_hover_goto_type_action_links_order() { 2674 fn test_hover_goto_type_action_links_order() {
2699 let (_, actions) = check_hover_result( 2675 check_actions(
2700 " 2676 r#"
2701 //- /lib.rs 2677trait ImplTrait<T> {}
2702 trait ImplTrait<T> {} 2678trait DynTrait<T> {}
2703 trait DynTrait<T> {} 2679struct B<T> {}
2704 struct B<T> {} 2680struct S {}
2705 struct S {}
2706 2681
2707 fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} 2682fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2708 ", 2683 "#,
2709 &["&impl ImplTrait<B<dyn DynTrait<B<S>>>>"], 2684 expect![[r#"
2710 );
2711 assert_debug_snapshot!(actions,
2712 @r###"
2713 [
2714 GoToType(
2715 [ 2685 [
2716 HoverGotoTypeData { 2686 GoToType(
2717 mod_path: "test::ImplTrait", 2687 [
2718 nav: NavigationTarget { 2688 HoverGotoTypeData {
2719 file_id: FileId( 2689 mod_path: "ImplTrait",
2720 1, 2690 nav: NavigationTarget {
2721 ), 2691 file_id: FileId(
2722 full_range: 0..21, 2692 1,
2723 name: "ImplTrait", 2693 ),
2724 kind: TRAIT_DEF, 2694 full_range: 0..21,
2725 focus_range: Some( 2695 focus_range: Some(
2726 6..15, 2696 6..15,
2727 ), 2697 ),
2728 container_name: None, 2698 name: "ImplTrait",
2729 description: Some( 2699 kind: TRAIT,
2730 "trait ImplTrait", 2700 container_name: None,
2731 ), 2701 description: Some(
2732 docs: None, 2702 "trait ImplTrait",
2733 }, 2703 ),
2734 }, 2704 docs: None,
2735 HoverGotoTypeData { 2705 },
2736 mod_path: "test::B", 2706 },
2737 nav: NavigationTarget { 2707 HoverGotoTypeData {
2738 file_id: FileId( 2708 mod_path: "B",
2739 1, 2709 nav: NavigationTarget {
2740 ), 2710 file_id: FileId(
2741 full_range: 43..57, 2711 1,
2742 name: "B", 2712 ),
2743 kind: STRUCT_DEF, 2713 full_range: 43..57,
2744 focus_range: Some( 2714 focus_range: Some(
2745 50..51, 2715 50..51,
2746 ), 2716 ),
2747 container_name: None, 2717 name: "B",
2748 description: Some( 2718 kind: STRUCT,
2749 "struct B", 2719 container_name: None,
2750 ), 2720 description: Some(
2751 docs: None, 2721 "struct B",
2752 }, 2722 ),
2753 }, 2723 docs: None,
2754 HoverGotoTypeData { 2724 },
2755 mod_path: "test::DynTrait", 2725 },
2756 nav: NavigationTarget { 2726 HoverGotoTypeData {
2757 file_id: FileId( 2727 mod_path: "DynTrait",
2758 1, 2728 nav: NavigationTarget {
2759 ), 2729 file_id: FileId(
2760 full_range: 22..42, 2730 1,
2761 name: "DynTrait", 2731 ),
2762 kind: TRAIT_DEF, 2732 full_range: 22..42,
2763 focus_range: Some( 2733 focus_range: Some(
2764 28..36, 2734 28..36,
2765 ), 2735 ),
2766 container_name: None, 2736 name: "DynTrait",
2767 description: Some( 2737 kind: TRAIT,
2768 "trait DynTrait", 2738 container_name: None,
2769 ), 2739 description: Some(
2770 docs: None, 2740 "trait DynTrait",
2771 }, 2741 ),
2772 }, 2742 docs: None,
2773 HoverGotoTypeData { 2743 },
2774 mod_path: "test::S", 2744 },
2775 nav: NavigationTarget { 2745 HoverGotoTypeData {
2776 file_id: FileId( 2746 mod_path: "S",
2777 1, 2747 nav: NavigationTarget {
2778 ), 2748 file_id: FileId(
2779 full_range: 58..69, 2749 1,
2780 name: "S", 2750 ),
2781 kind: STRUCT_DEF, 2751 full_range: 58..69,
2782 focus_range: Some( 2752 focus_range: Some(
2783 65..66, 2753 65..66,
2784 ), 2754 ),
2785 container_name: None, 2755 name: "S",
2786 description: Some( 2756 kind: STRUCT,
2787 "struct S", 2757 container_name: None,
2788 ), 2758 description: Some(
2789 docs: None, 2759 "struct S",
2790 }, 2760 ),
2791 }, 2761 docs: None,
2792 ], 2762 },
2793 ), 2763 },
2794 ] 2764 ],
2795 "###); 2765 ),
2766 ]
2767 "#]],
2768 );
2796 } 2769 }
2797 2770
2798 #[test] 2771 #[test]
2799 fn test_hover_associated_type_has_goto_type_action() { 2772 fn test_hover_associated_type_has_goto_type_action() {
2800 let (_, actions) = check_hover_result( 2773 check_actions(
2801 " 2774 r#"
2802 //- /main.rs 2775trait Foo {
2803 trait Foo { 2776 type Item;
2804 type Item; 2777 fn get(self) -> Self::Item {}
2805 fn get(self) -> Self::Item {} 2778}
2806 }
2807 2779
2808 struct Bar{} 2780struct Bar{}
2809 struct S{} 2781struct S{}
2810 2782
2811 impl Foo for S{ 2783impl Foo for S { type Item = Bar; }
2812 type Item = Bar;
2813 }
2814 2784
2815 fn test() -> impl Foo { 2785fn test() -> impl Foo { S {} }
2816 S{}
2817 }
2818 2786
2819 fn main() { 2787fn main() { let s<|>t = test().get(); }
2820 let s<|>t = test().get(); 2788"#,
2821 } 2789 expect![[r#"
2822 ",
2823 &["Foo::Item<impl Foo>"],
2824 );
2825 assert_debug_snapshot!(actions,
2826 @r###"
2827 [
2828 GoToType(
2829 [ 2790 [
2830 HoverGotoTypeData { 2791 GoToType(
2831 mod_path: "test::Foo", 2792 [
2832 nav: NavigationTarget { 2793 HoverGotoTypeData {
2833 file_id: FileId( 2794 mod_path: "Foo",
2834 1, 2795 nav: NavigationTarget {
2835 ), 2796 file_id: FileId(
2836 full_range: 0..62, 2797 1,
2837 name: "Foo", 2798 ),
2838 kind: TRAIT_DEF, 2799 full_range: 0..62,
2839 focus_range: Some( 2800 focus_range: Some(
2840 6..9, 2801 6..9,
2841 ), 2802 ),
2842 container_name: None, 2803 name: "Foo",
2843 description: Some( 2804 kind: TRAIT,
2844 "trait Foo", 2805 container_name: None,
2845 ), 2806 description: Some(
2846 docs: None, 2807 "trait Foo",
2847 }, 2808 ),
2848 }, 2809 docs: None,
2849 ], 2810 },
2850 ), 2811 },
2851 ] 2812 ],
2852 "###); 2813 ),
2814 ]
2815 "#]],
2816 );
2853 } 2817 }
2854} 2818}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index c87652555..4bbbcd258 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -1,14 +1,16 @@
1use hir::{Adt, HirDisplay, Semantics, Type}; 1use hir::{Adt, Callable, HirDisplay, Semantics, Type};
2use ra_ide_db::RootDatabase; 2use ra_ide_db::RootDatabase;
3use ra_prof::profile; 3use ra_prof::profile;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, 5 ast::{self, ArgListOwner, AstNode},
6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, 6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
7}; 7};
8
9use crate::{FileId, FunctionSignature};
10use stdx::to_lower_snake_case; 8use stdx::to_lower_snake_case;
11 9
10use crate::FileId;
11use ast::NameOwner;
12use either::Either;
13
12#[derive(Clone, Debug, PartialEq, Eq)] 14#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct InlayHintsConfig { 15pub struct InlayHintsConfig {
14 pub type_hints: bool, 16 pub type_hints: bool,
@@ -94,7 +96,7 @@ fn get_chaining_hints(
94 return None; 96 return None;
95 } 97 }
96 98
97 if matches!(expr, ast::Expr::RecordLit(_)) { 99 if matches!(expr, ast::Expr::RecordExpr(_)) {
98 return None; 100 return None;
99 } 101 }
100 102
@@ -112,7 +114,7 @@ fn get_chaining_hints(
112 // Ignoring extra whitespace and comments 114 // Ignoring extra whitespace and comments
113 let next = tokens.next()?.kind(); 115 let next = tokens.next()?.kind();
114 let next_next = tokens.next()?.kind(); 116 let next_next = tokens.next()?.kind();
115 if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { 117 if next == SyntaxKind::WHITESPACE && next_next == T![.] {
116 let ty = sema.type_of_expr(&expr)?; 118 let ty = sema.type_of_expr(&expr)?;
117 if ty.is_unknown() { 119 if ty.is_unknown() {
118 return None; 120 return None;
@@ -150,19 +152,22 @@ fn get_param_name_hints(
150 _ => return None, 152 _ => return None,
151 }; 153 };
152 154
153 let fn_signature = get_fn_signature(sema, &expr)?; 155 let callable = get_callable(sema, &expr)?;
154 let n_params_to_skip = 156 let hints = callable
155 if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { 157 .params(sema.db)
156 1 158 .into_iter()
157 } else {
158 0
159 };
160 let hints = fn_signature
161 .parameter_names
162 .iter()
163 .skip(n_params_to_skip)
164 .zip(args) 159 .zip(args)
165 .filter(|(param, arg)| should_show_param_name_hint(sema, &fn_signature, param, &arg)) 160 .filter_map(|((param, _ty), arg)| match param? {
161 Either::Left(self_param) => Some((self_param.to_string(), arg)),
162 Either::Right(pat) => {
163 let param_name = match pat {
164 ast::Pat::BindPat(it) => it.name()?.to_string(),
165 it => it.to_string(),
166 };
167 Some((param_name, arg))
168 }
169 })
170 .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, &param_name, &arg))
166 .map(|(param_name, arg)| InlayHint { 171 .map(|(param_name, arg)| InlayHint {
167 range: arg.syntax().text_range(), 172 range: arg.syntax().text_range(),
168 kind: InlayKind::ParameterHint, 173 kind: InlayKind::ParameterHint,
@@ -225,10 +230,10 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_
225 match_ast! { 230 match_ast! {
226 match node { 231 match node {
227 ast::LetStmt(it) => { 232 ast::LetStmt(it) => {
228 return it.ascribed_type().is_some() 233 return it.ty().is_some()
229 }, 234 },
230 ast::Param(it) => { 235 ast::Param(it) => {
231 return it.ascribed_type().is_some() 236 return it.ty().is_some()
232 }, 237 },
233 ast::MatchArm(_it) => { 238 ast::MatchArm(_it) => {
234 return pat_is_enum_variant(db, bind_pat, pat_ty); 239 return pat_is_enum_variant(db, bind_pat, pat_ty);
@@ -250,28 +255,28 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_
250 255
251fn should_show_param_name_hint( 256fn should_show_param_name_hint(
252 sema: &Semantics<RootDatabase>, 257 sema: &Semantics<RootDatabase>,
253 fn_signature: &FunctionSignature, 258 callable: &Callable,
254 param_name: &str, 259 param_name: &str,
255 argument: &ast::Expr, 260 argument: &ast::Expr,
256) -> bool { 261) -> bool {
257 let param_name = param_name.trim_start_matches('_'); 262 let param_name = param_name.trim_start_matches('_');
263 let fn_name = match callable.kind() {
264 hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()),
265 hir::CallableKind::TupleStruct(_)
266 | hir::CallableKind::TupleEnumVariant(_)
267 | hir::CallableKind::Closure => None,
268 };
258 if param_name.is_empty() 269 if param_name.is_empty()
259 || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) 270 || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_'))
260 || is_argument_similar_to_param_name(sema, argument, param_name) 271 || is_argument_similar_to_param_name(sema, argument, param_name)
261 || param_name.starts_with("ra_fixture") 272 || param_name.starts_with("ra_fixture")
262 { 273 {
263 return false; 274 return false;
264 } 275 }
265 276
266 let parameters_len = if fn_signature.has_self_param {
267 fn_signature.parameters.len() - 1
268 } else {
269 fn_signature.parameters.len()
270 };
271
272 // avoid displaying hints for common functions like map, filter, etc. 277 // avoid displaying hints for common functions like map, filter, etc.
273 // or other obvious words used in std 278 // or other obvious words used in std
274 !(parameters_len == 1 && is_obvious_param(param_name)) 279 !(callable.n_params() == 1 && is_obvious_param(param_name))
275} 280}
276 281
277fn is_argument_similar_to_param_name( 282fn is_argument_similar_to_param_name(
@@ -318,610 +323,264 @@ fn is_obvious_param(param_name: &str) -> bool {
318 param_name.len() == 1 || is_obvious_param_name 323 param_name.len() == 1 || is_obvious_param_name
319} 324}
320 325
321fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { 326fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Callable> {
322 match expr { 327 match expr {
323 ast::Expr::CallExpr(expr) => { 328 ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db),
324 // FIXME: Type::as_callable is broken for closures 329 ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr),
325 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?;
326 match callable_def {
327 hir::CallableDef::FunctionId(it) => {
328 Some(FunctionSignature::from_hir(sema.db, it.into()))
329 }
330 hir::CallableDef::StructId(it) => {
331 FunctionSignature::from_struct(sema.db, it.into())
332 }
333 hir::CallableDef::EnumVariantId(it) => {
334 FunctionSignature::from_enum_variant(sema.db, it.into())
335 }
336 }
337 }
338 ast::Expr::MethodCallExpr(expr) => {
339 let fn_def = sema.resolve_method_call(&expr)?;
340 Some(FunctionSignature::from_hir(sema.db, fn_def))
341 }
342 _ => None, 330 _ => None,
343 } 331 }
344} 332}
345 333
346#[cfg(test)] 334#[cfg(test)]
347mod tests { 335mod tests {
348 use crate::inlay_hints::InlayHintsConfig; 336 use expect::{expect, Expect};
349 use insta::assert_debug_snapshot; 337 use test_utils::extract_annotations;
338
339 use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file};
340
341 fn check(ra_fixture: &str) {
342 check_with_config(InlayHintsConfig::default(), ra_fixture);
343 }
344
345 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
346 let (analysis, file_id) = single_file(ra_fixture);
347 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
348 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
349 let actual =
350 inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
351 assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
352 }
350 353
351 use crate::mock_analysis::single_file; 354 fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
355 let (analysis, file_id) = single_file(ra_fixture);
356 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
357 expect.assert_debug_eq(&inlay_hints)
358 }
352 359
353 #[test] 360 #[test]
354 fn param_hints_only() { 361 fn param_hints_only() {
355 let (analysis, file_id) = single_file( 362 check_with_config(
363 InlayHintsConfig {
364 parameter_hints: true,
365 type_hints: false,
366 chaining_hints: false,
367 max_length: None,
368 },
356 r#" 369 r#"
357 fn foo(a: i32, b: i32) -> i32 { a + b } 370fn foo(a: i32, b: i32) -> i32 { a + b }
358 fn main() { 371fn main() {
359 let _x = foo(4, 4); 372 let _x = foo(
360 }"#, 373 4,
374 //^ a
375 4,
376 //^ b
377 );
378}"#,
361 ); 379 );
362 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
363 [
364 InlayHint {
365 range: 69..70,
366 kind: ParameterHint,
367 label: "a",
368 },
369 InlayHint {
370 range: 72..73,
371 kind: ParameterHint,
372 label: "b",
373 },
374 ]
375 "###);
376 } 380 }
377 381
378 #[test] 382 #[test]
379 fn hints_disabled() { 383 fn hints_disabled() {
380 let (analysis, file_id) = single_file( 384 check_with_config(
385 InlayHintsConfig {
386 type_hints: false,
387 parameter_hints: false,
388 chaining_hints: false,
389 max_length: None,
390 },
381 r#" 391 r#"
382 fn foo(a: i32, b: i32) -> i32 { a + b } 392fn foo(a: i32, b: i32) -> i32 { a + b }
383 fn main() { 393fn main() {
384 let _x = foo(4, 4); 394 let _x = foo(4, 4);
385 }"#, 395}"#,
386 ); 396 );
387 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###);
388 } 397 }
389 398
390 #[test] 399 #[test]
391 fn type_hints_only() { 400 fn type_hints_only() {
392 let (analysis, file_id) = single_file( 401 check_with_config(
402 InlayHintsConfig {
403 type_hints: true,
404 parameter_hints: false,
405 chaining_hints: false,
406 max_length: None,
407 },
393 r#" 408 r#"
394 fn foo(a: i32, b: i32) -> i32 { a + b } 409fn foo(a: i32, b: i32) -> i32 { a + b }
395 fn main() { 410fn main() {
396 let _x = foo(4, 4); 411 let _x = foo(4, 4);
397 }"#, 412 //^^ i32
413}"#,
398 ); 414 );
399 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
400 [
401 InlayHint {
402 range: 60..62,
403 kind: TypeHint,
404 label: "i32",
405 },
406 ]
407 "###);
408 } 415 }
416
409 #[test] 417 #[test]
410 fn default_generic_types_should_not_be_displayed() { 418 fn default_generic_types_should_not_be_displayed() {
411 let (analysis, file_id) = single_file( 419 check(
412 r#" 420 r#"
413struct Test<K, T = u8> { 421struct Test<K, T = u8> { k: K, t: T }
414 k: K,
415 t: T,
416}
417 422
418fn main() { 423fn main() {
419 let zz = Test { t: 23u8, k: 33 }; 424 let zz = Test { t: 23u8, k: 33 };
425 //^^ Test<i32>
420 let zz_ref = &zz; 426 let zz_ref = &zz;
427 //^^^^^^ &Test<i32>
428 let test = || zz;
429 //^^^^ || -> Test<i32>
421}"#, 430}"#,
422 ); 431 );
423
424 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
425 [
426 InlayHint {
427 range: 68..70,
428 kind: TypeHint,
429 label: "Test<i32>",
430 },
431 InlayHint {
432 range: 106..112,
433 kind: TypeHint,
434 label: "&Test<i32>",
435 },
436 ]
437 "###
438 );
439 } 432 }
440 433
441 #[test] 434 #[test]
442 fn let_statement() { 435 fn let_statement() {
443 let (analysis, file_id) = single_file( 436 check(
444 r#" 437 r#"
445#[derive(PartialEq)] 438#[derive(PartialEq)]
446enum CustomOption<T> { 439enum Option<T> { None, Some(T) }
447 None,
448 Some(T),
449}
450 440
451#[derive(PartialEq)] 441#[derive(PartialEq)]
452struct Test { 442struct Test { a: Option<u32>, b: u8 }
453 a: CustomOption<u32>,
454 b: u8,
455}
456 443
457fn main() { 444fn main() {
458 struct InnerStruct {} 445 struct InnerStruct {}
459 446
460 let test = 54; 447 let test = 54;
448 //^^^^ i32
461 let test: i32 = 33; 449 let test: i32 = 33;
462 let mut test = 33; 450 let mut test = 33;
451 //^^^^^^^^ i32
463 let _ = 22; 452 let _ = 22;
464 let test = "test"; 453 let test = "test";
454 //^^^^ &str
465 let test = InnerStruct {}; 455 let test = InnerStruct {};
466 456
467 let test = vec![222]; 457 let test = unresolved();
468 let test: Vec<_> = (0..3).collect();
469 let test = (0..3).collect::<Vec<i128>>();
470 let test = (0..3).collect::<Vec<_>>();
471
472 let mut test = Vec::new();
473 test.push(333);
474 458
475 let test = (42, 'a'); 459 let test = (42, 'a');
476 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); 460 //^^^^ (i32, char)
461 let (a, (b, (c,)) = (2, (3, (9.2,));
462 //^ i32 ^ i32 ^ f64
477 let &x = &92; 463 let &x = &92;
464 //^ i32
478}"#, 465}"#,
479 ); 466 );
480
481 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
482 [
483 InlayHint {
484 range: 192..196,
485 kind: TypeHint,
486 label: "i32",
487 },
488 InlayHint {
489 range: 235..243,
490 kind: TypeHint,
491 label: "i32",
492 },
493 InlayHint {
494 range: 274..278,
495 kind: TypeHint,
496 label: "&str",
497 },
498 InlayHint {
499 range: 538..542,
500 kind: TypeHint,
501 label: "(i32, char)",
502 },
503 InlayHint {
504 range: 565..566,
505 kind: TypeHint,
506 label: "i32",
507 },
508 InlayHint {
509 range: 569..570,
510 kind: TypeHint,
511 label: "i32",
512 },
513 InlayHint {
514 range: 572..573,
515 kind: TypeHint,
516 label: "i32",
517 },
518 InlayHint {
519 range: 576..577,
520 kind: TypeHint,
521 label: "f64",
522 },
523 InlayHint {
524 range: 579..580,
525 kind: TypeHint,
526 label: "f64",
527 },
528 InlayHint {
529 range: 583..584,
530 kind: TypeHint,
531 label: "i32",
532 },
533 InlayHint {
534 range: 626..627,
535 kind: TypeHint,
536 label: "i32",
537 },
538 ]
539 "###
540 );
541 } 467 }
542 468
543 #[test] 469 #[test]
544 fn closure_parameters() { 470 fn closure_parameters() {
545 let (analysis, file_id) = single_file( 471 check(
546 r#" 472 r#"
547fn main() { 473fn main() {
548 let mut start = 0; 474 let mut start = 0;
549 (0..2).for_each(|increment| { 475 //^^^^^^^^^ i32
550 start += increment; 476 (0..2).for_each(|increment| { start += increment; });
551 }); 477 //^^^^^^^^^ i32
478
479 let multiply =
480 //^^^^^^^^ |…| -> i32
481 | a, b| a * b
482 //^ i32 ^ i32
483 ;
552 484
553 let multiply = |a, b, c, d| a * b * c * d; 485 let _: i32 = multiply(1, 2);
554 let _: i32 = multiply(1, 2, 3, 4);
555 let multiply_ref = &multiply; 486 let multiply_ref = &multiply;
487 //^^^^^^^^^^^^ &|…| -> i32
556 488
557 let return_42 = || 42; 489 let return_42 = || 42;
490 //^^^^^^^^^ || -> i32
558}"#, 491}"#,
559 ); 492 );
560
561 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
562 [
563 InlayHint {
564 range: 20..29,
565 kind: TypeHint,
566 label: "i32",
567 },
568 InlayHint {
569 range: 56..65,
570 kind: TypeHint,
571 label: "i32",
572 },
573 InlayHint {
574 range: 114..122,
575 kind: TypeHint,
576 label: "|…| -> i32",
577 },
578 InlayHint {
579 range: 126..127,
580 kind: TypeHint,
581 label: "i32",
582 },
583 InlayHint {
584 range: 129..130,
585 kind: TypeHint,
586 label: "i32",
587 },
588 InlayHint {
589 range: 132..133,
590 kind: TypeHint,
591 label: "i32",
592 },
593 InlayHint {
594 range: 135..136,
595 kind: TypeHint,
596 label: "i32",
597 },
598 InlayHint {
599 range: 200..212,
600 kind: TypeHint,
601 label: "&|…| -> i32",
602 },
603 InlayHint {
604 range: 235..244,
605 kind: TypeHint,
606 label: "|| -> i32",
607 },
608 ]
609 "###
610 );
611 } 493 }
612 494
613 #[test] 495 #[test]
614 fn for_expression() { 496 fn for_expression() {
615 let (analysis, file_id) = single_file( 497 check(
616 r#" 498 r#"
617fn main() { 499fn main() {
618 let mut start = 0; 500 let mut start = 0;
619 for increment in 0..2 { 501 //^^^^^^^^^ i32
620 start += increment; 502 for increment in 0..2 { start += increment; }
621 } 503 //^^^^^^^^^ i32
622}"#, 504}"#,
623 ); 505 );
624
625 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
626 [
627 InlayHint {
628 range: 20..29,
629 kind: TypeHint,
630 label: "i32",
631 },
632 InlayHint {
633 range: 43..52,
634 kind: TypeHint,
635 label: "i32",
636 },
637 ]
638 "###
639 );
640 } 506 }
641 507
642 #[test] 508 #[test]
643 fn if_expr() { 509 fn if_expr() {
644 let (analysis, file_id) = single_file( 510 check(
645 r#" 511 r#"
646#[derive(PartialEq)] 512enum Option<T> { None, Some(T) }
647enum CustomOption<T> { 513use Option::*;
648 None,
649 Some(T),
650}
651
652#[derive(PartialEq)]
653struct Test {
654 a: CustomOption<u32>,
655 b: u8,
656}
657 514
658use CustomOption::*; 515struct Test { a: Option<u32>, b: u8 }
659 516
660fn main() { 517fn main() {
661 let test = Some(Test { a: Some(3), b: 1 }); 518 let test = Some(Test { a: Some(3), b: 1 });
519 //^^^^ Option<Test>
662 if let None = &test {}; 520 if let None = &test {};
663 if let test = &test {}; 521 if let test = &test {};
522 //^^^^ &Option<Test>
664 if let Some(test) = &test {}; 523 if let Some(test) = &test {};
665 if let Some(Test { a, b }) = &test {}; 524 //^^^^ &Test
666 if let Some(Test { a: x, b: y }) = &test {}; 525 if let Some(Test { a, b }) = &test {};
667 if let Some(Test { a: Some(x), b: y }) = &test {}; 526 //^ &Option<u32> ^ &u8
668 if let Some(Test { a: None, b: y }) = &test {}; 527 if let Some(Test { a: x, b: y }) = &test {};
528 //^ &Option<u32> ^ &u8
529 if let Some(Test { a: Some(x), b: y }) = &test {};
530 //^ &u32 ^ &u8
531 if let Some(Test { a: None, b: y }) = &test {};
532 //^ &u8
669 if let Some(Test { b: y, .. }) = &test {}; 533 if let Some(Test { b: y, .. }) = &test {};
670 534 //^ &u8
671 if test == None {} 535 if test == None {}
672}"#, 536}"#,
673 ); 537 );
674
675 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
676 [
677 InlayHint {
678 range: 187..191,
679 kind: TypeHint,
680 label: "CustomOption<Test>",
681 },
682 InlayHint {
683 range: 266..270,
684 kind: TypeHint,
685 label: "&CustomOption<Test>",
686 },
687 InlayHint {
688 range: 299..303,
689 kind: TypeHint,
690 label: "&Test",
691 },
692 InlayHint {
693 range: 340..341,
694 kind: TypeHint,
695 label: "&CustomOption<u32>",
696 },
697 InlayHint {
698 range: 343..344,
699 kind: TypeHint,
700 label: "&u8",
701 },
702 InlayHint {
703 range: 386..387,
704 kind: TypeHint,
705 label: "&CustomOption<u32>",
706 },
707 InlayHint {
708 range: 392..393,
709 kind: TypeHint,
710 label: "&u8",
711 },
712 InlayHint {
713 range: 440..441,
714 kind: TypeHint,
715 label: "&u32",
716 },
717 InlayHint {
718 range: 447..448,
719 kind: TypeHint,
720 label: "&u8",
721 },
722 InlayHint {
723 range: 499..500,
724 kind: TypeHint,
725 label: "&u8",
726 },
727 InlayHint {
728 range: 542..543,
729 kind: TypeHint,
730 label: "&u8",
731 },
732 ]
733 "###
734 );
735 } 538 }
736 539
737 #[test] 540 #[test]
738 fn while_expr() { 541 fn while_expr() {
739 let (analysis, file_id) = single_file( 542 check(
740 r#" 543 r#"
741#[derive(PartialEq)] 544enum Option<T> { None, Some(T) }
742enum CustomOption<T> { 545use Option::*;
743 None,
744 Some(T),
745}
746 546
747#[derive(PartialEq)] 547struct Test { a: Option<u32>, b: u8 }
748struct Test {
749 a: CustomOption<u32>,
750 b: u8,
751}
752
753use CustomOption::*;
754 548
755fn main() { 549fn main() {
756 let test = Some(Test { a: Some(3), b: 1 }); 550 let test = Some(Test { a: Some(3), b: 1 });
757 while let None = &test {}; 551 //^^^^ Option<Test>
758 while let test = &test {}; 552 while let Some(Test { a: Some(x), b: y }) = &test {};
759 while let Some(test) = &test {}; 553 //^ &u32 ^ &u8
760 while let Some(Test { a, b }) = &test {};
761 while let Some(Test { a: x, b: y }) = &test {};
762 while let Some(Test { a: Some(x), b: y }) = &test {};
763 while let Some(Test { a: None, b: y }) = &test {};
764 while let Some(Test { b: y, .. }) = &test {};
765
766 while test == None {}
767}"#, 554}"#,
768 ); 555 );
769
770 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
771 [
772 InlayHint {
773 range: 187..191,
774 kind: TypeHint,
775 label: "CustomOption<Test>",
776 },
777 InlayHint {
778 range: 272..276,
779 kind: TypeHint,
780 label: "&CustomOption<Test>",
781 },
782 InlayHint {
783 range: 308..312,
784 kind: TypeHint,
785 label: "&Test",
786 },
787 InlayHint {
788 range: 352..353,
789 kind: TypeHint,
790 label: "&CustomOption<u32>",
791 },
792 InlayHint {
793 range: 355..356,
794 kind: TypeHint,
795 label: "&u8",
796 },
797 InlayHint {
798 range: 401..402,
799 kind: TypeHint,
800 label: "&CustomOption<u32>",
801 },
802 InlayHint {
803 range: 407..408,
804 kind: TypeHint,
805 label: "&u8",
806 },
807 InlayHint {
808 range: 458..459,
809 kind: TypeHint,
810 label: "&u32",
811 },
812 InlayHint {
813 range: 465..466,
814 kind: TypeHint,
815 label: "&u8",
816 },
817 InlayHint {
818 range: 520..521,
819 kind: TypeHint,
820 label: "&u8",
821 },
822 InlayHint {
823 range: 566..567,
824 kind: TypeHint,
825 label: "&u8",
826 },
827 ]
828 "###
829 );
830 } 556 }
831 557
832 #[test] 558 #[test]
833 fn match_arm_list() { 559 fn match_arm_list() {
834 let (analysis, file_id) = single_file( 560 check(
835 r#" 561 r#"
836#[derive(PartialEq)] 562enum Option<T> { None, Some(T) }
837enum CustomOption<T> { 563use Option::*;
838 None,
839 Some(T),
840}
841 564
842#[derive(PartialEq)] 565struct Test { a: Option<u32>, b: u8 }
843struct Test {
844 a: CustomOption<u32>,
845 b: u8,
846}
847
848use CustomOption::*;
849 566
850fn main() { 567fn main() {
851 match Some(Test { a: Some(3), b: 1 }) { 568 match Some(Test { a: Some(3), b: 1 }) {
852 None => (), 569 None => (),
853 test => (), 570 test => (),
854 Some(test) => (), 571 //^^^^ Option<Test>
855 Some(Test { a, b }) => (),
856 Some(Test { a: x, b: y }) => (),
857 Some(Test { a: Some(x), b: y }) => (), 572 Some(Test { a: Some(x), b: y }) => (),
858 Some(Test { a: None, b: y }) => (), 573 //^ u32 ^ u8
859 Some(Test { b: y, .. }) => (),
860 _ => {} 574 _ => {}
861 } 575 }
862}"#, 576}"#,
863 ); 577 );
864
865 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
866 [
867 InlayHint {
868 range: 251..255,
869 kind: TypeHint,
870 label: "CustomOption<Test>",
871 },
872 InlayHint {
873 range: 276..280,
874 kind: TypeHint,
875 label: "Test",
876 },
877 InlayHint {
878 range: 309..310,
879 kind: TypeHint,
880 label: "CustomOption<u32>",
881 },
882 InlayHint {
883 range: 312..313,
884 kind: TypeHint,
885 label: "u8",
886 },
887 InlayHint {
888 range: 347..348,
889 kind: TypeHint,
890 label: "CustomOption<u32>",
891 },
892 InlayHint {
893 range: 353..354,
894 kind: TypeHint,
895 label: "u8",
896 },
897 InlayHint {
898 range: 393..394,
899 kind: TypeHint,
900 label: "u32",
901 },
902 InlayHint {
903 range: 400..401,
904 kind: TypeHint,
905 label: "u8",
906 },
907 InlayHint {
908 range: 444..445,
909 kind: TypeHint,
910 label: "u8",
911 },
912 InlayHint {
913 range: 479..480,
914 kind: TypeHint,
915 label: "u8",
916 },
917 ]
918 "###
919 );
920 } 578 }
921 579
922 #[test] 580 #[test]
923 fn hint_truncation() { 581 fn hint_truncation() {
924 let (analysis, file_id) = single_file( 582 check_with_config(
583 InlayHintsConfig { max_length: Some(8), ..Default::default() },
925 r#" 584 r#"
926struct Smol<T>(T); 585struct Smol<T>(T);
927 586
@@ -929,52 +588,25 @@ struct VeryLongOuterName<T>(T);
929 588
930fn main() { 589fn main() {
931 let a = Smol(0u32); 590 let a = Smol(0u32);
591 //^ Smol<u32>
932 let b = VeryLongOuterName(0usize); 592 let b = VeryLongOuterName(0usize);
593 //^ VeryLongOuterName<…>
933 let c = Smol(Smol(0u32)) 594 let c = Smol(Smol(0u32))
595 //^ Smol<Smol<…>>
934}"#, 596}"#,
935 ); 597 );
936
937 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
938 [
939 InlayHint {
940 range: 73..74,
941 kind: TypeHint,
942 label: "Smol<u32>",
943 },
944 InlayHint {
945 range: 97..98,
946 kind: TypeHint,
947 label: "VeryLongOuterName<…>",
948 },
949 InlayHint {
950 range: 136..137,
951 kind: TypeHint,
952 label: "Smol<Smol<…>>",
953 },
954 ]
955 "###
956 );
957 } 598 }
958 599
959 #[test] 600 #[test]
960 fn function_call_parameter_hint() { 601 fn function_call_parameter_hint() {
961 let (analysis, file_id) = single_file( 602 check(
962 r#" 603 r#"
963enum CustomOption<T> { 604enum Option<T> { None, Some(T) }
964 None, 605use Option::*;
965 Some(T),
966}
967use CustomOption::*;
968 606
969struct FileId {} 607struct FileId {}
970struct SmolStr {} 608struct SmolStr {}
971 609
972impl From<&str> for SmolStr {
973 fn from(_: &str) -> Self {
974 unimplemented!()
975 }
976}
977
978struct TextRange {} 610struct TextRange {}
979struct SyntaxKind {} 611struct SyntaxKind {}
980struct NavigationTarget {} 612struct NavigationTarget {}
@@ -982,18 +614,15 @@ struct NavigationTarget {}
982struct Test {} 614struct Test {}
983 615
984impl Test { 616impl Test {
985 fn method(&self, mut param: i32) -> i32 { 617 fn method(&self, mut param: i32) -> i32 { param * 2 }
986 param * 2
987 }
988 618
989 fn from_syntax( 619 fn from_syntax(
990 file_id: FileId, 620 file_id: FileId,
991 name: SmolStr, 621 name: SmolStr,
992 focus_range: CustomOption<TextRange>, 622 focus_range: Option<TextRange>,
993 full_range: TextRange, 623 full_range: TextRange,
994 kind: SyntaxKind, 624 kind: SyntaxKind,
995 docs: CustomOption<String>, 625 docs: Option<String>,
996 description: CustomOption<String>,
997 ) -> NavigationTarget { 626 ) -> NavigationTarget {
998 NavigationTarget {} 627 NavigationTarget {}
999 } 628 }
@@ -1005,108 +634,36 @@ fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
1005 634
1006fn main() { 635fn main() {
1007 let not_literal = 1; 636 let not_literal = 1;
1008 let _: i32 = test_func(1, 2, "hello", 3, not_literal); 637 //^^^^^^^^^^^ i32
638 let _: i32 = test_func(1, 2, "hello", 3, not_literal);
639 //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last
1009 let t: Test = Test {}; 640 let t: Test = Test {};
1010 t.method(123); 641 t.method(123);
1011 Test::method(&t, 3456); 642 //^^^ param
1012 643 Test::method(&t, 3456);
644 //^^ &self ^^^^ param
1013 Test::from_syntax( 645 Test::from_syntax(
1014 FileId {}, 646 FileId {},
647 //^^^^^^^^^ file_id
1015 "impl".into(), 648 "impl".into(),
649 //^^^^^^^^^^^^^ name
1016 None, 650 None,
651 //^^^^ focus_range
1017 TextRange {}, 652 TextRange {},
653 //^^^^^^^^^^^^ full_range
1018 SyntaxKind {}, 654 SyntaxKind {},
655 //^^^^^^^^^^^^^ kind
1019 None, 656 None,
1020 None, 657 //^^^^ docs
1021 ); 658 );
1022}"#, 659}"#,
1023 ); 660 );
1024
1025 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
1026 [
1027 InlayHint {
1028 range: 797..808,
1029 kind: TypeHint,
1030 label: "i32",
1031 },
1032 InlayHint {
1033 range: 841..842,
1034 kind: ParameterHint,
1035 label: "foo",
1036 },
1037 InlayHint {
1038 range: 844..845,
1039 kind: ParameterHint,
1040 label: "bar",
1041 },
1042 InlayHint {
1043 range: 847..854,
1044 kind: ParameterHint,
1045 label: "msg",
1046 },
1047 InlayHint {
1048 range: 859..870,
1049 kind: ParameterHint,
1050 label: "last",
1051 },
1052 InlayHint {
1053 range: 913..916,
1054 kind: ParameterHint,
1055 label: "param",
1056 },
1057 InlayHint {
1058 range: 936..938,
1059 kind: ParameterHint,
1060 label: "&self",
1061 },
1062 InlayHint {
1063 range: 940..944,
1064 kind: ParameterHint,
1065 label: "param",
1066 },
1067 InlayHint {
1068 range: 979..988,
1069 kind: ParameterHint,
1070 label: "file_id",
1071 },
1072 InlayHint {
1073 range: 998..1011,
1074 kind: ParameterHint,
1075 label: "name",
1076 },
1077 InlayHint {
1078 range: 1021..1025,
1079 kind: ParameterHint,
1080 label: "focus_range",
1081 },
1082 InlayHint {
1083 range: 1035..1047,
1084 kind: ParameterHint,
1085 label: "full_range",
1086 },
1087 InlayHint {
1088 range: 1057..1070,
1089 kind: ParameterHint,
1090 label: "kind",
1091 },
1092 InlayHint {
1093 range: 1080..1084,
1094 kind: ParameterHint,
1095 label: "docs",
1096 },
1097 InlayHint {
1098 range: 1094..1098,
1099 kind: ParameterHint,
1100 label: "description",
1101 },
1102 ]
1103 "###
1104 );
1105 } 661 }
1106 662
1107 #[test] 663 #[test]
1108 fn omitted_parameters_hints_heuristics() { 664 fn omitted_parameters_hints_heuristics() {
1109 let (analysis, file_id) = single_file( 665 check_with_config(
666 InlayHintsConfig { max_length: Some(8), ..Default::default() },
1110 r#" 667 r#"
1111fn map(f: i32) {} 668fn map(f: i32) {}
1112fn filter(predicate: i32) {} 669fn filter(predicate: i32) {}
@@ -1188,22 +745,15 @@ fn main() {
1188 let _: f64 = a.abs_sub(b); 745 let _: f64 = a.abs_sub(b);
1189}"#, 746}"#,
1190 ); 747 );
1191
1192 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1193 []
1194 "###
1195 );
1196 } 748 }
1197 749
1198 #[test] 750 #[test]
1199 fn unit_structs_have_no_type_hints() { 751 fn unit_structs_have_no_type_hints() {
1200 let (analysis, file_id) = single_file( 752 check_with_config(
753 InlayHintsConfig { max_length: Some(8), ..Default::default() },
1201 r#" 754 r#"
1202enum CustomResult<T, E> { 755enum Result<T, E> { Ok(T), Err(E) }
1203 Ok(T), 756use Result::*;
1204 Err(E),
1205}
1206use CustomResult::*;
1207 757
1208struct SyntheticSyntax; 758struct SyntheticSyntax;
1209 759
@@ -1214,135 +764,155 @@ fn main() {
1214 } 764 }
1215}"#, 765}"#,
1216 ); 766 );
1217
1218 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1219 []
1220 "###
1221 );
1222 } 767 }
1223 768
1224 #[test] 769 #[test]
1225 fn chaining_hints_ignore_comments() { 770 fn chaining_hints_ignore_comments() {
1226 let (analysis, file_id) = single_file( 771 check_expect(
772 InlayHintsConfig {
773 parameter_hints: false,
774 type_hints: false,
775 chaining_hints: true,
776 max_length: None,
777 },
1227 r#" 778 r#"
1228 struct A(B); 779struct A(B);
1229 impl A { fn into_b(self) -> B { self.0 } } 780impl A { fn into_b(self) -> B { self.0 } }
1230 struct B(C); 781struct B(C);
1231 impl B { fn into_c(self) -> C { self.0 } } 782impl B { fn into_c(self) -> C { self.0 } }
1232 struct C; 783struct C;
1233 784
1234 fn main() { 785fn main() {
1235 let c = A(B(C)) 786 let c = A(B(C))
1236 .into_b() // This is a comment 787 .into_b() // This is a comment
1237 .into_c(); 788 .into_c();
1238 }"#, 789}
790"#,
791 expect![[r#"
792 [
793 InlayHint {
794 range: 147..172,
795 kind: ChainingHint,
796 label: "B",
797 },
798 InlayHint {
799 range: 147..154,
800 kind: ChainingHint,
801 label: "A",
802 },
803 ]
804 "#]],
1239 ); 805 );
1240 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1241 [
1242 InlayHint {
1243 range: 147..172,
1244 kind: ChainingHint,
1245 label: "B",
1246 },
1247 InlayHint {
1248 range: 147..154,
1249 kind: ChainingHint,
1250 label: "A",
1251 },
1252 ]
1253 "###);
1254 } 806 }
1255 807
1256 #[test] 808 #[test]
1257 fn chaining_hints_without_newlines() { 809 fn chaining_hints_without_newlines() {
1258 let (analysis, file_id) = single_file( 810 check_with_config(
811 InlayHintsConfig {
812 parameter_hints: false,
813 type_hints: false,
814 chaining_hints: true,
815 max_length: None,
816 },
1259 r#" 817 r#"
1260 struct A(B); 818struct A(B);
1261 impl A { fn into_b(self) -> B { self.0 } } 819impl A { fn into_b(self) -> B { self.0 } }
1262 struct B(C); 820struct B(C);
1263 impl B { fn into_c(self) -> C { self.0 } } 821impl B { fn into_c(self) -> C { self.0 } }
1264 struct C; 822struct C;
1265 823
1266 fn main() { 824fn main() {
1267 let c = A(B(C)).into_b().into_c(); 825 let c = A(B(C)).into_b().into_c();
1268 }"#, 826}"#,
1269 ); 827 );
1270 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
1271 } 828 }
1272 829
1273 #[test] 830 #[test]
1274 fn struct_access_chaining_hints() { 831 fn struct_access_chaining_hints() {
1275 let (analysis, file_id) = single_file( 832 check_expect(
833 InlayHintsConfig {
834 parameter_hints: false,
835 type_hints: false,
836 chaining_hints: true,
837 max_length: None,
838 },
1276 r#" 839 r#"
1277 struct A { pub b: B } 840struct A { pub b: B }
1278 struct B { pub c: C } 841struct B { pub c: C }
1279 struct C(pub bool); 842struct C(pub bool);
1280 struct D; 843struct D;
1281 844
1282 impl D { 845impl D {
1283 fn foo(&self) -> i32 { 42 } 846 fn foo(&self) -> i32 { 42 }
1284 } 847}
1285 848
1286 fn main() { 849fn main() {
1287 let x = A { b: B { c: C(true) } } 850 let x = A { b: B { c: C(true) } }
1288 .b 851 .b
1289 .c 852 .c
1290 .0; 853 .0;
1291 let x = D 854 let x = D
1292 .foo(); 855 .foo();
1293 }"#, 856}"#,
857 expect![[r#"
858 [
859 InlayHint {
860 range: 143..190,
861 kind: ChainingHint,
862 label: "C",
863 },
864 InlayHint {
865 range: 143..179,
866 kind: ChainingHint,
867 label: "B",
868 },
869 ]
870 "#]],
1294 ); 871 );
1295 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1296 [
1297 InlayHint {
1298 range: 143..190,
1299 kind: ChainingHint,
1300 label: "C",
1301 },
1302 InlayHint {
1303 range: 143..179,
1304 kind: ChainingHint,
1305 label: "B",
1306 },
1307 ]
1308 "###);
1309 } 872 }
1310 873
1311 #[test] 874 #[test]
1312 fn generic_chaining_hints() { 875 fn generic_chaining_hints() {
1313 let (analysis, file_id) = single_file( 876 check_expect(
877 InlayHintsConfig {
878 parameter_hints: false,
879 type_hints: false,
880 chaining_hints: true,
881 max_length: None,
882 },
1314 r#" 883 r#"
1315 struct A<T>(T); 884struct A<T>(T);
1316 struct B<T>(T); 885struct B<T>(T);
1317 struct C<T>(T); 886struct C<T>(T);
1318 struct X<T,R>(T, R); 887struct X<T,R>(T, R);
1319 888
1320 impl<T> A<T> { 889impl<T> A<T> {
1321 fn new(t: T) -> Self { A(t) } 890 fn new(t: T) -> Self { A(t) }
1322 fn into_b(self) -> B<T> { B(self.0) } 891 fn into_b(self) -> B<T> { B(self.0) }
1323 } 892}
1324 impl<T> B<T> { 893impl<T> B<T> {
1325 fn into_c(self) -> C<T> { C(self.0) } 894 fn into_c(self) -> C<T> { C(self.0) }
1326 } 895}
1327 fn main() { 896fn main() {
1328 let c = A::new(X(42, true)) 897 let c = A::new(X(42, true))
1329 .into_b() 898 .into_b()
1330 .into_c(); 899 .into_c();
1331 }"#, 900}
901"#,
902 expect![[r#"
903 [
904 InlayHint {
905 range: 246..283,
906 kind: ChainingHint,
907 label: "B<X<i32, bool>>",
908 },
909 InlayHint {
910 range: 246..265,
911 kind: ChainingHint,
912 label: "A<X<i32, bool>>",
913 },
914 ]
915 "#]],
1332 ); 916 );
1333 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1334 [
1335 InlayHint {
1336 range: 246..283,
1337 kind: ChainingHint,
1338 label: "B<X<i32, bool>>",
1339 },
1340 InlayHint {
1341 range: 246..265,
1342 kind: ChainingHint,
1343 label: "A<X<i32, bool>>",
1344 },
1345 ]
1346 "###);
1347 } 917 }
1348} 918}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index ecac5134e..0fede0d87 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -17,30 +17,33 @@ macro_rules! eprintln {
17 17
18pub mod mock_analysis; 18pub mod mock_analysis;
19 19
20mod markup;
20mod prime_caches; 21mod prime_caches;
21mod status; 22mod display;
23
24mod call_hierarchy;
25mod call_info;
22mod completion; 26mod completion;
23mod runnables; 27mod diagnostics;
28mod expand_macro;
29mod extend_selection;
30mod file_structure;
31mod folding_ranges;
24mod goto_definition; 32mod goto_definition;
25mod goto_type_definition;
26mod goto_implementation; 33mod goto_implementation;
27mod extend_selection; 34mod goto_type_definition;
28mod hover; 35mod hover;
29mod call_hierarchy; 36mod inlay_hints;
30mod call_info; 37mod join_lines;
31mod syntax_highlighting; 38mod matching_brace;
32mod parent_module; 39mod parent_module;
33mod references; 40mod references;
34mod diagnostics; 41mod runnables;
42mod ssr;
43mod status;
44mod syntax_highlighting;
35mod syntax_tree; 45mod syntax_tree;
36mod folding_ranges;
37mod join_lines;
38mod typing; 46mod typing;
39mod matching_brace;
40mod display;
41mod inlay_hints;
42mod expand_macro;
43mod ssr;
44 47
45use std::sync::Arc; 48use std::sync::Arc;
46 49
@@ -59,15 +62,18 @@ use crate::display::ToNav;
59 62
60pub use crate::{ 63pub use crate::{
61 call_hierarchy::CallItem, 64 call_hierarchy::CallItem,
65 call_info::CallInfo,
62 completion::{ 66 completion::{
63 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, 67 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
64 }, 68 },
65 diagnostics::Severity, 69 diagnostics::Severity,
66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 70 display::NavigationTarget,
67 expand_macro::ExpandedMacro, 71 expand_macro::ExpandedMacro,
72 file_structure::StructureNode,
68 folding_ranges::{Fold, FoldKind}, 73 folding_ranges::{Fold, FoldKind},
69 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 74 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 75 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
76 markup::Markup,
71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, 77 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
72 runnables::{Runnable, RunnableKind, TestId}, 78 runnables::{Runnable, RunnableKind, TestId},
73 syntax_highlighting::{ 79 syntax_highlighting::{
@@ -75,8 +81,8 @@ pub use crate::{
75 }, 81 },
76}; 82};
77 83
78pub use hir::Documentation; 84pub use hir::{Documentation, Semantics};
79pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist}; 85pub use ra_assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist};
80pub use ra_db::{ 86pub use ra_db::{
81 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, 87 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
82 SourceRootId, 88 SourceRootId,
@@ -129,14 +135,6 @@ impl<T> RangeInfo<T> {
129 } 135 }
130} 136}
131 137
132/// Contains information about a call site. Specifically the
133/// `FunctionSignature`and current parameter.
134#[derive(Debug)]
135pub struct CallInfo {
136 pub signature: FunctionSignature,
137 pub active_parameter: Option<usize>,
138}
139
140/// `AnalysisHost` stores the current state of the world. 138/// `AnalysisHost` stores the current state of the world.
141#[derive(Debug)] 139#[derive(Debug)]
142pub struct AnalysisHost { 140pub struct AnalysisHost {
@@ -328,7 +326,7 @@ impl Analysis {
328 /// Returns a tree representation of symbols in the file. Useful to draw a 326 /// Returns a tree representation of symbols in the file. Useful to draw a
329 /// file outline. 327 /// file outline.
330 pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { 328 pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> {
331 self.with_db(|db| file_structure(&db.parse(file_id).tree())) 329 self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
332 } 330 }
333 331
334 /// Returns a list of the places in the file where type hints can be displayed. 332 /// Returns a list of the places in the file where type hints can be displayed.
@@ -385,7 +383,9 @@ impl Analysis {
385 position: FilePosition, 383 position: FilePosition,
386 search_scope: Option<SearchScope>, 384 search_scope: Option<SearchScope>,
387 ) -> Cancelable<Option<ReferenceSearchResult>> { 385 ) -> Cancelable<Option<ReferenceSearchResult>> {
388 self.with_db(|db| references::find_all_refs(db, position, search_scope).map(|it| it.info)) 386 self.with_db(|db| {
387 references::find_all_refs(&Semantics::new(db), position, search_scope).map(|it| it.info)
388 })
389 } 389 }
390 390
391 /// Returns a short text describing element at position. 391 /// Returns a short text describing element at position.
@@ -487,8 +487,12 @@ impl Analysis {
487 } 487 }
488 488
489 /// Computes the set of diagnostics for the given file. 489 /// Computes the set of diagnostics for the given file.
490 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 490 pub fn diagnostics(
491 self.with_db(|db| diagnostics::diagnostics(db, file_id)) 491 &self,
492 file_id: FileId,
493 enable_experimental: bool,
494 ) -> Cancelable<Vec<Diagnostic>> {
495 self.with_db(|db| diagnostics::diagnostics(db, file_id, enable_experimental))
492 } 496 }
493 497
494 /// Returns the edit required to rename reference at the position to the new 498 /// Returns the edit required to rename reference at the position to the new
@@ -505,9 +509,11 @@ impl Analysis {
505 &self, 509 &self,
506 query: &str, 510 query: &str,
507 parse_only: bool, 511 parse_only: bool,
512 position: FilePosition,
513 selections: Vec<FileRange>,
508 ) -> Cancelable<Result<SourceChange, SsrError>> { 514 ) -> Cancelable<Result<SourceChange, SsrError>> {
509 self.with_db(|db| { 515 self.with_db(|db| {
510 let edits = ssr::parse_search_replace(query, parse_only, db)?; 516 let edits = ssr::parse_search_replace(query, parse_only, db, position, selections)?;
511 Ok(SourceChange::from(edits)) 517 Ok(SourceChange::from(edits))
512 }) 518 })
513 } 519 }
@@ -526,77 +532,3 @@ fn analysis_is_send() {
526 fn is_send<T: Send>() {} 532 fn is_send<T: Send>() {}
527 is_send::<Analysis>(); 533 is_send::<Analysis>();
528} 534}
529
530#[cfg(test)]
531mod tests {
532 use crate::{display::NavigationTarget, mock_analysis::single_file, Query};
533 use ra_syntax::{
534 SmolStr,
535 SyntaxKind::{FN_DEF, STRUCT_DEF},
536 };
537
538 #[test]
539 fn test_world_symbols_with_no_container() {
540 let code = r#"
541 enum FooInner { }
542 "#;
543
544 let mut symbols = get_symbols_matching(code, "FooInner");
545
546 let s = symbols.pop().unwrap();
547
548 assert_eq!(s.name(), "FooInner");
549 assert!(s.container_name().is_none());
550 }
551
552 #[test]
553 fn test_world_symbols_include_container_name() {
554 let code = r#"
555fn foo() {
556 enum FooInner { }
557}
558 "#;
559
560 let mut symbols = get_symbols_matching(code, "FooInner");
561
562 let s = symbols.pop().unwrap();
563
564 assert_eq!(s.name(), "FooInner");
565 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
566
567 let code = r#"
568mod foo {
569 struct FooInner;
570}
571 "#;
572
573 let mut symbols = get_symbols_matching(code, "FooInner");
574
575 let s = symbols.pop().unwrap();
576
577 assert_eq!(s.name(), "FooInner");
578 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
579 }
580
581 #[test]
582 fn test_world_symbols_are_case_sensitive() {
583 let code = r#"
584fn foo() {}
585
586struct Foo;
587 "#;
588
589 let symbols = get_symbols_matching(code, "Foo");
590
591 let fn_match = symbols.iter().find(|s| s.name() == "foo").map(|s| s.kind());
592 let struct_match = symbols.iter().find(|s| s.name() == "Foo").map(|s| s.kind());
593
594 assert_eq!(fn_match, Some(FN_DEF));
595 assert_eq!(struct_match, Some(STRUCT_DEF));
596 }
597
598 fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
599 let (analysis, _) = single_file(text);
600 analysis.symbol_search(Query::new(query.into())).unwrap()
601 }
602}
diff --git a/crates/ra_ide/src/markup.rs b/crates/ra_ide/src/markup.rs
new file mode 100644
index 000000000..60c193c40
--- /dev/null
+++ b/crates/ra_ide/src/markup.rs
@@ -0,0 +1,38 @@
1//! Markdown formatting.
2//!
3//! Sometimes, we want to display a "rich text" in the UI. At the moment, we use
4//! markdown for this purpose. It doesn't feel like a right option, but that's
5//! what is used by LSP, so let's keep it simple.
6use std::fmt;
7
8#[derive(Default, Debug)]
9pub struct Markup {
10 text: String,
11}
12
13impl From<Markup> for String {
14 fn from(markup: Markup) -> Self {
15 markup.text
16 }
17}
18
19impl From<String> for Markup {
20 fn from(text: String) -> Self {
21 Markup { text }
22 }
23}
24
25impl fmt::Display for Markup {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 fmt::Display::fmt(&self.text, f)
28 }
29}
30
31impl Markup {
32 pub fn as_str(&self) -> &str {
33 self.text.as_str()
34 }
35 pub fn fenced_block(contents: &impl fmt::Display) -> Markup {
36 format!("```rust\n{}\n```", contents).into()
37 }
38}
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs
index 490ee0dc3..cf2ee1bfa 100644
--- a/crates/ra_ide/src/mock_analysis.rs
+++ b/crates/ra_ide/src/mock_analysis.rs
@@ -2,8 +2,10 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use ra_cfg::CfgOptions; 4use ra_cfg::CfgOptions;
5use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; 5use ra_db::{CrateName, FileSet, SourceRoot, VfsPath};
6use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; 6use test_utils::{
7 extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER,
8};
7 9
8use crate::{ 10use crate::{
9 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, 11 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
@@ -69,13 +71,27 @@ impl MockAnalysis {
69 } 71 }
70 72
71 pub fn id_of(&self, path: &str) -> FileId { 73 pub fn id_of(&self, path: &str) -> FileId {
72 let (idx, _) = self 74 let (file_id, _) =
73 .files 75 self.files().find(|(_, data)| path == data.path).expect("no file in this mock");
74 .iter() 76 file_id
75 .enumerate() 77 }
76 .find(|(_, data)| path == data.path) 78 pub fn annotations(&self) -> Vec<(FileRange, String)> {
77 .expect("no file in this mock"); 79 self.files()
78 FileId(idx as u32 + 1) 80 .flat_map(|(file_id, fixture)| {
81 let annotations = extract_annotations(&fixture.text);
82 annotations
83 .into_iter()
84 .map(move |(range, data)| (FileRange { file_id, range }, data))
85 })
86 .collect()
87 }
88 pub fn files(&self) -> impl Iterator<Item = (FileId, &Fixture)> + '_ {
89 self.files.iter().enumerate().map(|(idx, fixture)| (FileId(idx as u32 + 1), fixture))
90 }
91 pub fn annotation(&self) -> (FileRange, String) {
92 let mut all = self.annotations();
93 assert_eq!(all.len(), 1);
94 all.pop().unwrap()
79 } 95 }
80 pub fn analysis_host(self) -> AnalysisHost { 96 pub fn analysis_host(self) -> AnalysisHost {
81 let mut host = AnalysisHost::default(); 97 let mut host = AnalysisHost::default();
@@ -94,12 +110,12 @@ impl MockAnalysis {
94 data.edition.and_then(|it| it.parse().ok()).unwrap_or(Edition::Edition2018); 110 data.edition.and_then(|it| it.parse().ok()).unwrap_or(Edition::Edition2018);
95 111
96 let file_id = FileId(i as u32 + 1); 112 let file_id = FileId(i as u32 + 1);
97 let env = Env::from(data.env.iter()); 113 let env = data.env.into_iter().collect();
98 if path == "/lib.rs" || path == "/main.rs" { 114 if path == "/lib.rs" || path == "/main.rs" {
99 root_crate = Some(crate_graph.add_crate_root( 115 root_crate = Some(crate_graph.add_crate_root(
100 file_id, 116 file_id,
101 edition, 117 edition,
102 Some(CrateName::new("test").unwrap()), 118 Some("test".to_string()),
103 cfg, 119 cfg,
104 env, 120 env,
105 Default::default(), 121 Default::default(),
@@ -110,7 +126,7 @@ impl MockAnalysis {
110 let other_crate = crate_graph.add_crate_root( 126 let other_crate = crate_graph.add_crate_root(
111 file_id, 127 file_id,
112 edition, 128 edition,
113 Some(CrateName::new(crate_name).unwrap()), 129 Some(crate_name.to_string()),
114 cfg, 130 cfg,
115 env, 131 env,
116 Default::default(), 132 Default::default(),
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 3433fdae3..519e4bf1a 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -74,8 +74,8 @@ impl IntoIterator for ReferenceSearchResult {
74 let mut v = Vec::with_capacity(self.len()); 74 let mut v = Vec::with_capacity(self.len());
75 v.push(Reference { 75 v.push(Reference {
76 file_range: FileRange { 76 file_range: FileRange {
77 file_id: self.declaration.nav.file_id(), 77 file_id: self.declaration.nav.file_id,
78 range: self.declaration.nav.range(), 78 range: self.declaration.nav.focus_or_full_range(),
79 }, 79 },
80 kind: self.declaration.kind, 80 kind: self.declaration.kind,
81 access: self.declaration.access, 81 access: self.declaration.access,
@@ -86,12 +86,11 @@ impl IntoIterator for ReferenceSearchResult {
86} 86}
87 87
88pub(crate) fn find_all_refs( 88pub(crate) fn find_all_refs(
89 db: &RootDatabase, 89 sema: &Semantics<RootDatabase>,
90 position: FilePosition, 90 position: FilePosition,
91 search_scope: Option<SearchScope>, 91 search_scope: Option<SearchScope>,
92) -> Option<RangeInfo<ReferenceSearchResult>> { 92) -> Option<RangeInfo<ReferenceSearchResult>> {
93 let _p = profile("find_all_refs"); 93 let _p = profile("find_all_refs");
94 let sema = Semantics::new(db);
95 let syntax = sema.parse(position.file_id).syntax().clone(); 94 let syntax = sema.parse(position.file_id).syntax().clone();
96 95
97 let (opt_name, search_kind) = if let Some(name) = 96 let (opt_name, search_kind) = if let Some(name) =
@@ -108,15 +107,15 @@ pub(crate) fn find_all_refs(
108 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 107 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
109 108
110 let references = def 109 let references = def
111 .find_usages(db, search_scope) 110 .find_usages(sema, search_scope)
112 .into_iter() 111 .into_iter()
113 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 112 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
114 .collect(); 113 .collect();
115 114
116 let decl_range = def.try_to_nav(db)?.range(); 115 let decl_range = def.try_to_nav(sema.db)?.focus_or_full_range();
117 116
118 let declaration = Declaration { 117 let declaration = Declaration {
119 nav: def.try_to_nav(db)?, 118 nav: def.try_to_nav(sema.db)?,
120 kind: ReferenceKind::Other, 119 kind: ReferenceKind::Other,
121 access: decl_access(&def, &syntax, decl_range), 120 access: decl_access(&def, &syntax, decl_range),
122 }; 121 };
@@ -173,16 +172,16 @@ fn get_struct_def_name_for_struct_literal_search(
173 if let Some(name) = 172 if let Some(name) =
174 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start()) 173 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start())
175 { 174 {
176 return name.syntax().ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); 175 return name.syntax().ancestors().find_map(ast::Struct::cast).and_then(|l| l.name());
177 } 176 }
178 if sema 177 if sema
179 .find_node_at_offset_with_descend::<ast::TypeParamList>( 178 .find_node_at_offset_with_descend::<ast::GenericParamList>(
180 &syntax, 179 &syntax,
181 left.text_range().start(), 180 left.text_range().start(),
182 ) 181 )
183 .is_some() 182 .is_some()
184 { 183 {
185 return left.ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); 184 return left.ancestors().find_map(ast::Struct::cast).and_then(|l| l.name());
186 } 185 }
187 } 186 }
188 None 187 None
@@ -213,7 +212,7 @@ fn main() {
213 ); 212 );
214 check_result( 213 check_result(
215 refs, 214 refs,
216 "Foo STRUCT_DEF FileId(1) 0..26 7..10 Other", 215 "Foo STRUCT FileId(1) 0..26 7..10 Other",
217 &["FileId(1) 101..104 StructLiteral"], 216 &["FileId(1) 101..104 StructLiteral"],
218 ); 217 );
219 } 218 }
@@ -231,7 +230,7 @@ struct Foo<|> {}
231 ); 230 );
232 check_result( 231 check_result(
233 refs, 232 refs,
234 "Foo STRUCT_DEF FileId(1) 0..13 7..10 Other", 233 "Foo STRUCT FileId(1) 0..13 7..10 Other",
235 &["FileId(1) 41..44 Other", "FileId(1) 54..57 StructLiteral"], 234 &["FileId(1) 41..44 Other", "FileId(1) 54..57 StructLiteral"],
236 ); 235 );
237 } 236 }
@@ -249,7 +248,7 @@ struct Foo<T> <|>{}
249 ); 248 );
250 check_result( 249 check_result(
251 refs, 250 refs,
252 "Foo STRUCT_DEF FileId(1) 0..16 7..10 Other", 251 "Foo STRUCT FileId(1) 0..16 7..10 Other",
253 &["FileId(1) 64..67 StructLiteral"], 252 &["FileId(1) 64..67 StructLiteral"],
254 ); 253 );
255 } 254 }
@@ -268,7 +267,7 @@ fn main() {
268 ); 267 );
269 check_result( 268 check_result(
270 refs, 269 refs,
271 "Foo STRUCT_DEF FileId(1) 0..16 7..10 Other", 270 "Foo STRUCT FileId(1) 0..16 7..10 Other",
272 &["FileId(1) 54..57 StructLiteral"], 271 &["FileId(1) 54..57 StructLiteral"],
273 ); 272 );
274 } 273 }
@@ -362,7 +361,7 @@ fn main(s: Foo) {
362 ); 361 );
363 check_result( 362 check_result(
364 refs, 363 refs,
365 "spam RECORD_FIELD_DEF FileId(1) 17..30 21..25 Other", 364 "spam RECORD_FIELD FileId(1) 17..30 21..25 Other",
366 &["FileId(1) 67..71 Other Read"], 365 &["FileId(1) 67..71 Other Read"],
367 ); 366 );
368 } 367 }
@@ -377,7 +376,7 @@ impl Foo {
377} 376}
378"#, 377"#,
379 ); 378 );
380 check_result(refs, "f FN_DEF FileId(1) 27..43 30..31 Other", &[]); 379 check_result(refs, "f FN FileId(1) 27..43 30..31 Other", &[]);
381 } 380 }
382 381
383 #[test] 382 #[test]
@@ -391,7 +390,7 @@ enum Foo {
391} 390}
392"#, 391"#,
393 ); 392 );
394 check_result(refs, "B ENUM_VARIANT FileId(1) 22..23 22..23 Other", &[]); 393 check_result(refs, "B VARIANT FileId(1) 22..23 22..23 Other", &[]);
395 } 394 }
396 395
397 #[test] 396 #[test]
@@ -432,7 +431,7 @@ fn f() {
432 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 431 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
433 check_result( 432 check_result(
434 refs, 433 refs,
435 "Foo STRUCT_DEF FileId(2) 17..51 28..31 Other", 434 "Foo STRUCT FileId(2) 17..51 28..31 Other",
436 &["FileId(1) 53..56 StructLiteral", "FileId(3) 79..82 StructLiteral"], 435 &["FileId(1) 53..56 StructLiteral", "FileId(3) 79..82 StructLiteral"],
437 ); 436 );
438 } 437 }
@@ -487,7 +486,7 @@ pub(super) struct Foo<|> {
487 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 486 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
488 check_result( 487 check_result(
489 refs, 488 refs,
490 "Foo STRUCT_DEF FileId(3) 0..41 18..21 Other", 489 "Foo STRUCT FileId(3) 0..41 18..21 Other",
491 &["FileId(2) 20..23 Other", "FileId(2) 47..50 StructLiteral"], 490 &["FileId(2) 20..23 Other", "FileId(2) 47..50 StructLiteral"],
492 ); 491 );
493 } 492 }
@@ -515,7 +514,7 @@ pub(super) struct Foo<|> {
515 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 514 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
516 check_result( 515 check_result(
517 refs, 516 refs,
518 "quux FN_DEF FileId(1) 19..35 26..30 Other", 517 "quux FN FileId(1) 19..35 26..30 Other",
519 &["FileId(2) 16..20 StructLiteral", "FileId(3) 16..20 StructLiteral"], 518 &["FileId(2) 16..20 StructLiteral", "FileId(3) 16..20 StructLiteral"],
520 ); 519 );
521 520
@@ -523,7 +522,7 @@ pub(super) struct Foo<|> {
523 analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap(); 522 analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap();
524 check_result( 523 check_result(
525 refs, 524 refs,
526 "quux FN_DEF FileId(1) 19..35 26..30 Other", 525 "quux FN FileId(1) 19..35 26..30 Other",
527 &["FileId(3) 16..20 StructLiteral"], 526 &["FileId(3) 16..20 StructLiteral"],
528 ); 527 );
529 } 528 }
@@ -581,7 +580,7 @@ fn foo() {
581 ); 580 );
582 check_result( 581 check_result(
583 refs, 582 refs,
584 "f RECORD_FIELD_DEF FileId(1) 15..21 15..16 Other", 583 "f RECORD_FIELD FileId(1) 15..21 15..16 Other",
585 &["FileId(1) 55..56 Other Read", "FileId(1) 68..69 Other Write"], 584 &["FileId(1) 55..56 Other Read", "FileId(1) 68..69 Other Write"],
586 ); 585 );
587 } 586 }
@@ -620,7 +619,7 @@ fn main() {
620 ); 619 );
621 check_result( 620 check_result(
622 refs, 621 refs,
623 "new FN_DEF FileId(1) 54..101 61..64 Other", 622 "new FN FileId(1) 54..101 61..64 Other",
624 &["FileId(1) 146..149 StructLiteral"], 623 &["FileId(1) 146..149 StructLiteral"],
625 ); 624 );
626 } 625 }
@@ -647,7 +646,7 @@ fn main() {
647 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 646 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
648 check_result( 647 check_result(
649 refs, 648 refs,
650 "f FN_DEF FileId(1) 26..35 29..30 Other", 649 "f FN FileId(1) 26..35 29..30 Other",
651 &["FileId(2) 11..12 Other", "FileId(2) 28..29 StructLiteral"], 650 &["FileId(2) 11..12 Other", "FileId(2) 28..29 StructLiteral"],
652 ); 651 );
653 } 652 }
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 7ebc0adcf..31654bf79 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -7,7 +7,8 @@ use ra_ide_db::{
7 RootDatabase, 7 RootDatabase,
8}; 8};
9use ra_syntax::{ 9use ra_syntax::{
10 algo::find_node_at_offset, ast, ast::NameOwner, ast::TypeAscriptionOwner, 10 algo::find_node_at_offset,
11 ast::{self, NameOwner},
11 lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, 12 lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
12}; 13};
13use ra_text_edit::TextEdit; 14use ra_text_edit::TextEdit;
@@ -24,23 +25,24 @@ pub(crate) fn rename(
24 position: FilePosition, 25 position: FilePosition,
25 new_name: &str, 26 new_name: &str,
26) -> Option<RangeInfo<SourceChange>> { 27) -> Option<RangeInfo<SourceChange>> {
28 let sema = Semantics::new(db);
29
27 match lex_single_valid_syntax_kind(new_name)? { 30 match lex_single_valid_syntax_kind(new_name)? {
28 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), 31 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
29 SyntaxKind::SELF_KW => return rename_to_self(db, position), 32 SyntaxKind::SELF_KW => return rename_to_self(&sema, position),
30 _ => return None, 33 _ => return None,
31 } 34 }
32 35
33 let sema = Semantics::new(db);
34 let source_file = sema.parse(position.file_id); 36 let source_file = sema.parse(position.file_id);
35 let syntax = source_file.syntax(); 37 let syntax = source_file.syntax();
36 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 38 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
37 rename_mod(db, position, module, new_name) 39 rename_mod(&sema, position, module, new_name)
38 } else if let Some(self_token) = 40 } else if let Some(self_token) =
39 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 41 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
40 { 42 {
41 rename_self_to_param(db, position, self_token, new_name) 43 rename_self_to_param(&sema, position, self_token, new_name)
42 } else { 44 } else {
43 rename_reference(sema.db, position, new_name) 45 rename_reference(&sema, position, new_name)
44 } 46 }
45} 47}
46 48
@@ -97,7 +99,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
97} 99}
98 100
99fn rename_mod( 101fn rename_mod(
100 db: &RootDatabase, 102 sema: &Semantics<RootDatabase>,
101 position: FilePosition, 103 position: FilePosition,
102 module: Module, 104 module: Module,
103 new_name: &str, 105 new_name: &str,
@@ -105,34 +107,33 @@ fn rename_mod(
105 let mut source_file_edits = Vec::new(); 107 let mut source_file_edits = Vec::new();
106 let mut file_system_edits = Vec::new(); 108 let mut file_system_edits = Vec::new();
107 109
108 let src = module.definition_source(db); 110 let src = module.definition_source(sema.db);
109 let file_id = src.file_id.original_file(db); 111 let file_id = src.file_id.original_file(sema.db);
110 match src.value { 112 match src.value {
111 ModuleSource::SourceFile(..) => { 113 ModuleSource::SourceFile(..) => {
112 // mod is defined in path/to/dir/mod.rs 114 // mod is defined in path/to/dir/mod.rs
113 let dst = if module.is_mod_rs(db) { 115 let dst = if module.is_mod_rs(sema.db) {
114 format!("../{}/mod.rs", new_name) 116 format!("../{}/mod.rs", new_name)
115 } else { 117 } else {
116 format!("{}.rs", new_name) 118 format!("{}.rs", new_name)
117 }; 119 };
118 let move_file = 120 let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst };
119 FileSystemEdit::MoveFile { src: file_id, anchor: position.file_id, dst };
120 file_system_edits.push(move_file); 121 file_system_edits.push(move_file);
121 } 122 }
122 ModuleSource::Module(..) => {} 123 ModuleSource::Module(..) => {}
123 } 124 }
124 125
125 if let Some(src) = module.declaration_source(db) { 126 if let Some(src) = module.declaration_source(sema.db) {
126 let file_id = src.file_id.original_file(db); 127 let file_id = src.file_id.original_file(sema.db);
127 let name = src.value.name()?; 128 let name = src.value.name()?;
128 let edit = SourceFileEdit { 129 let edit = SourceFileEdit {
129 file_id: file_id, 130 file_id,
130 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), 131 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
131 }; 132 };
132 source_file_edits.push(edit); 133 source_file_edits.push(edit);
133 } 134 }
134 135
135 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 136 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
136 let ref_edits = refs 137 let ref_edits = refs
137 .references 138 .references
138 .into_iter() 139 .into_iter()
@@ -142,23 +143,25 @@ fn rename_mod(
142 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 143 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
143} 144}
144 145
145fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { 146fn rename_to_self(
146 let sema = Semantics::new(db); 147 sema: &Semantics<RootDatabase>,
148 position: FilePosition,
149) -> Option<RangeInfo<SourceChange>> {
147 let source_file = sema.parse(position.file_id); 150 let source_file = sema.parse(position.file_id);
148 let syn = source_file.syntax(); 151 let syn = source_file.syntax();
149 152
150 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?; 153 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
151 let params = fn_def.param_list()?; 154 let params = fn_def.param_list()?;
152 if params.self_param().is_some() { 155 if params.self_param().is_some() {
153 return None; // method already has self param 156 return None; // method already has self param
154 } 157 }
155 let first_param = params.params().next()?; 158 let first_param = params.params().next()?;
156 let mutable = match first_param.ascribed_type() { 159 let mutable = match first_param.ty() {
157 Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(), 160 Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(),
158 _ => return None, // not renaming other types 161 _ => return None, // not renaming other types
159 }; 162 };
160 163
161 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 164 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
162 165
163 let param_range = first_param.syntax().text_range(); 166 let param_range = first_param.syntax().text_range();
164 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 167 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
@@ -190,15 +193,14 @@ fn text_edit_from_self_param(
190 self_param: &ast::SelfParam, 193 self_param: &ast::SelfParam,
191 new_name: &str, 194 new_name: &str,
192) -> Option<TextEdit> { 195) -> Option<TextEdit> {
193 fn target_type_name(impl_def: &ast::ImplDef) -> Option<String> { 196 fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
194 if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() { 197 if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() {
195 return Some(p.path()?.segment()?.name_ref()?.text().to_string()); 198 return Some(p.path()?.segment()?.name_ref()?.text().to_string());
196 } 199 }
197 None 200 None
198 } 201 }
199 202
200 let impl_def = 203 let impl_def = find_node_at_offset::<ast::Impl>(syn, self_param.syntax().text_range().start())?;
201 find_node_at_offset::<ast::ImplDef>(syn, self_param.syntax().text_range().start())?;
202 let type_name = target_type_name(&impl_def)?; 204 let type_name = target_type_name(&impl_def)?;
203 205
204 let mut replacement_text = String::from(new_name); 206 let mut replacement_text = String::from(new_name);
@@ -210,17 +212,16 @@ fn text_edit_from_self_param(
210} 212}
211 213
212fn rename_self_to_param( 214fn rename_self_to_param(
213 db: &RootDatabase, 215 sema: &Semantics<RootDatabase>,
214 position: FilePosition, 216 position: FilePosition,
215 self_token: SyntaxToken, 217 self_token: SyntaxToken,
216 new_name: &str, 218 new_name: &str,
217) -> Option<RangeInfo<SourceChange>> { 219) -> Option<RangeInfo<SourceChange>> {
218 let sema = Semantics::new(db);
219 let source_file = sema.parse(position.file_id); 220 let source_file = sema.parse(position.file_id);
220 let syn = source_file.syntax(); 221 let syn = source_file.syntax();
221 222
222 let text = db.file_text(position.file_id); 223 let text = sema.db.file_text(position.file_id);
223 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?; 224 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
224 let search_range = fn_def.syntax().text_range(); 225 let search_range = fn_def.syntax().text_range();
225 226
226 let mut edits: Vec<SourceFileEdit> = vec![]; 227 let mut edits: Vec<SourceFileEdit> = vec![];
@@ -249,11 +250,11 @@ fn rename_self_to_param(
249} 250}
250 251
251fn rename_reference( 252fn rename_reference(
252 db: &RootDatabase, 253 sema: &Semantics<RootDatabase>,
253 position: FilePosition, 254 position: FilePosition,
254 new_name: &str, 255 new_name: &str,
255) -> Option<RangeInfo<SourceChange>> { 256) -> Option<RangeInfo<SourceChange>> {
256 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 257 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
257 258
258 let edit = refs 259 let edit = refs
259 .into_iter() 260 .into_iter()
@@ -269,51 +270,51 @@ fn rename_reference(
269 270
270#[cfg(test)] 271#[cfg(test)]
271mod tests { 272mod tests {
272 use insta::assert_debug_snapshot; 273 use expect::{expect, Expect};
273 use ra_text_edit::TextEditBuilder; 274 use ra_text_edit::TextEditBuilder;
274 use stdx::trim_indent; 275 use stdx::trim_indent;
275 use test_utils::{assert_eq_text, mark}; 276 use test_utils::{assert_eq_text, mark};
276 277
277 use crate::{mock_analysis::analysis_and_position, FileId}; 278 use crate::{mock_analysis::analysis_and_position, FileId};
278 279
280 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
281 let ra_fixture_after = &trim_indent(ra_fixture_after);
282 let (analysis, position) = analysis_and_position(ra_fixture_before);
283 let source_change = analysis.rename(position, new_name).unwrap();
284 let mut text_edit_builder = TextEditBuilder::default();
285 let mut file_id: Option<FileId> = None;
286 if let Some(change) = source_change {
287 for edit in change.info.source_file_edits {
288 file_id = Some(edit.file_id);
289 for indel in edit.edit.into_iter() {
290 text_edit_builder.replace(indel.delete, indel.insert);
291 }
292 }
293 }
294 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
295 text_edit_builder.finish().apply(&mut result);
296 assert_eq_text!(ra_fixture_after, &*result);
297 }
298
299 fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
300 let (analysis, position) = analysis_and_position(ra_fixture);
301 let source_change = analysis.rename(position, new_name).unwrap().unwrap();
302 expect.assert_debug_eq(&source_change)
303 }
304
279 #[test] 305 #[test]
280 fn test_rename_to_underscore() { 306 fn test_rename_to_underscore() {
281 test_rename( 307 check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#);
282 r#"
283 fn main() {
284 let i<|> = 1;
285 }"#,
286 "_",
287 r#"
288 fn main() {
289 let _ = 1;
290 }"#,
291 );
292 } 308 }
293 309
294 #[test] 310 #[test]
295 fn test_rename_to_raw_identifier() { 311 fn test_rename_to_raw_identifier() {
296 test_rename( 312 check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
297 r#"
298 fn main() {
299 let i<|> = 1;
300 }"#,
301 "r#fn",
302 r#"
303 fn main() {
304 let r#fn = 1;
305 }"#,
306 );
307 } 313 }
308 314
309 #[test] 315 #[test]
310 fn test_rename_to_invalid_identifier() { 316 fn test_rename_to_invalid_identifier() {
311 let (analysis, position) = analysis_and_position( 317 let (analysis, position) = analysis_and_position(r#"fn main() { let i<|> = 1; }"#);
312 "
313 fn main() {
314 let i<|> = 1;
315 }",
316 );
317 let new_name = "invalid!"; 318 let new_name = "invalid!";
318 let source_change = analysis.rename(position, new_name).unwrap(); 319 let source_change = analysis.rename(position, new_name).unwrap();
319 assert!(source_change.is_none()); 320 assert!(source_change.is_none());
@@ -321,318 +322,269 @@ mod tests {
321 322
322 #[test] 323 #[test]
323 fn test_rename_for_local() { 324 fn test_rename_for_local() {
324 test_rename( 325 check(
326 "k",
325 r#" 327 r#"
326 fn main() { 328fn main() {
327 let mut i = 1; 329 let mut i = 1;
328 let j = 1; 330 let j = 1;
329 i = i<|> + j; 331 i = i<|> + j;
330 332
331 { 333 { i = 0; }
332 i = 0;
333 }
334 334
335 i = 5; 335 i = 5;
336 }"#, 336}
337 "k", 337"#,
338 r#" 338 r#"
339 fn main() { 339fn main() {
340 let mut k = 1; 340 let mut k = 1;
341 let j = 1; 341 let j = 1;
342 k = k + j; 342 k = k + j;
343 343
344 { 344 { k = 0; }
345 k = 0;
346 }
347 345
348 k = 5; 346 k = 5;
349 }"#, 347}
348"#,
350 ); 349 );
351 } 350 }
352 351
353 #[test] 352 #[test]
354 fn test_rename_for_macro_args() { 353 fn test_rename_for_macro_args() {
355 test_rename( 354 check(
356 r#"
357 macro_rules! foo {($i:ident) => {$i} }
358 fn main() {
359 let a<|> = "test";
360 foo!(a);
361 }"#,
362 "b", 355 "b",
363 r#" 356 r#"
364 macro_rules! foo {($i:ident) => {$i} } 357macro_rules! foo {($i:ident) => {$i} }
365 fn main() { 358fn main() {
366 let b = "test"; 359 let a<|> = "test";
367 foo!(b); 360 foo!(a);
368 }"#, 361}
362"#,
363 r#"
364macro_rules! foo {($i:ident) => {$i} }
365fn main() {
366 let b = "test";
367 foo!(b);
368}
369"#,
369 ); 370 );
370 } 371 }
371 372
372 #[test] 373 #[test]
373 fn test_rename_for_macro_args_rev() { 374 fn test_rename_for_macro_args_rev() {
374 test_rename( 375 check(
375 r#"
376 macro_rules! foo {($i:ident) => {$i} }
377 fn main() {
378 let a = "test";
379 foo!(a<|>);
380 }"#,
381 "b", 376 "b",
382 r#" 377 r#"
383 macro_rules! foo {($i:ident) => {$i} } 378macro_rules! foo {($i:ident) => {$i} }
384 fn main() { 379fn main() {
385 let b = "test"; 380 let a = "test";
386 foo!(b); 381 foo!(a<|>);
387 }"#, 382}
383"#,
384 r#"
385macro_rules! foo {($i:ident) => {$i} }
386fn main() {
387 let b = "test";
388 foo!(b);
389}
390"#,
388 ); 391 );
389 } 392 }
390 393
391 #[test] 394 #[test]
392 fn test_rename_for_macro_define_fn() { 395 fn test_rename_for_macro_define_fn() {
393 test_rename( 396 check(
394 r#"
395 macro_rules! define_fn {($id:ident) => { fn $id{} }}
396 define_fn!(foo);
397 fn main() {
398 fo<|>o();
399 }"#,
400 "bar", 397 "bar",
401 r#" 398 r#"
402 macro_rules! define_fn {($id:ident) => { fn $id{} }} 399macro_rules! define_fn {($id:ident) => { fn $id{} }}
403 define_fn!(bar); 400define_fn!(foo);
404 fn main() { 401fn main() {
405 bar(); 402 fo<|>o();
406 }"#, 403}
404"#,
405 r#"
406macro_rules! define_fn {($id:ident) => { fn $id{} }}
407define_fn!(bar);
408fn main() {
409 bar();
410}
411"#,
407 ); 412 );
408 } 413 }
409 414
410 #[test] 415 #[test]
411 fn test_rename_for_macro_define_fn_rev() { 416 fn test_rename_for_macro_define_fn_rev() {
412 test_rename( 417 check(
413 r#"
414 macro_rules! define_fn {($id:ident) => { fn $id{} }}
415 define_fn!(fo<|>o);
416 fn main() {
417 foo();
418 }"#,
419 "bar", 418 "bar",
420 r#" 419 r#"
421 macro_rules! define_fn {($id:ident) => { fn $id{} }} 420macro_rules! define_fn {($id:ident) => { fn $id{} }}
422 define_fn!(bar); 421define_fn!(fo<|>o);
423 fn main() { 422fn main() {
424 bar(); 423 foo();
425 }"#, 424}
425"#,
426 r#"
427macro_rules! define_fn {($id:ident) => { fn $id{} }}
428define_fn!(bar);
429fn main() {
430 bar();
431}
432"#,
426 ); 433 );
427 } 434 }
428 435
429 #[test] 436 #[test]
430 fn test_rename_for_param_inside() { 437 fn test_rename_for_param_inside() {
431 test_rename( 438 check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#);
432 r#"
433 fn foo(i : u32) -> u32 {
434 i<|>
435 }"#,
436 "j",
437 r#"
438 fn foo(j : u32) -> u32 {
439 j
440 }"#,
441 );
442 } 439 }
443 440
444 #[test] 441 #[test]
445 fn test_rename_refs_for_fn_param() { 442 fn test_rename_refs_for_fn_param() {
446 test_rename( 443 check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
447 r#"
448 fn foo(i<|> : u32) -> u32 {
449 i
450 }"#,
451 "new_name",
452 r#"
453 fn foo(new_name : u32) -> u32 {
454 new_name
455 }"#,
456 );
457 } 444 }
458 445
459 #[test] 446 #[test]
460 fn test_rename_for_mut_param() { 447 fn test_rename_for_mut_param() {
461 test_rename( 448 check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
462 r#"
463 fn foo(mut i<|> : u32) -> u32 {
464 i
465 }"#,
466 "new_name",
467 r#"
468 fn foo(mut new_name : u32) -> u32 {
469 new_name
470 }"#,
471 );
472 } 449 }
473 450
474 #[test] 451 #[test]
475 fn test_rename_struct_field() { 452 fn test_rename_struct_field() {
476 test_rename( 453 check(
454 "j",
477 r#" 455 r#"
478 struct Foo { 456struct Foo { i<|>: i32 }
479 i<|>: i32,
480 }
481 457
482 impl Foo { 458impl Foo {
483 fn new(i: i32) -> Self { 459 fn new(i: i32) -> Self {
484 Self { i: i } 460 Self { i: i }
485 }
486 } 461 }
487 "#, 462}
488 "j", 463"#,
489 r#" 464 r#"
490 struct Foo { 465struct Foo { j: i32 }
491 j: i32,
492 }
493 466
494 impl Foo { 467impl Foo {
495 fn new(i: i32) -> Self { 468 fn new(i: i32) -> Self {
496 Self { j: i } 469 Self { j: i }
497 }
498 } 470 }
499 "#, 471}
472"#,
500 ); 473 );
501 } 474 }
502 475
503 #[test] 476 #[test]
504 fn test_rename_struct_field_for_shorthand() { 477 fn test_rename_struct_field_for_shorthand() {
505 mark::check!(test_rename_struct_field_for_shorthand); 478 mark::check!(test_rename_struct_field_for_shorthand);
506 test_rename( 479 check(
480 "j",
507 r#" 481 r#"
508 struct Foo { 482struct Foo { i<|>: i32 }
509 i<|>: i32,
510 }
511 483
512 impl Foo { 484impl Foo {
513 fn new(i: i32) -> Self { 485 fn new(i: i32) -> Self {
514 Self { i } 486 Self { i }
515 }
516 } 487 }
517 "#, 488}
518 "j", 489"#,
519 r#" 490 r#"
520 struct Foo { 491struct Foo { j: i32 }
521 j: i32,
522 }
523 492
524 impl Foo { 493impl Foo {
525 fn new(i: i32) -> Self { 494 fn new(i: i32) -> Self {
526 Self { j: i } 495 Self { j: i }
527 }
528 } 496 }
529 "#, 497}
498"#,
530 ); 499 );
531 } 500 }
532 501
533 #[test] 502 #[test]
534 fn test_rename_local_for_field_shorthand() { 503 fn test_rename_local_for_field_shorthand() {
535 mark::check!(test_rename_local_for_field_shorthand); 504 mark::check!(test_rename_local_for_field_shorthand);
536 test_rename( 505 check(
506 "j",
537 r#" 507 r#"
538 struct Foo { 508struct Foo { i: i32 }
539 i: i32,
540 }
541 509
542 impl Foo { 510impl Foo {
543 fn new(i<|>: i32) -> Self { 511 fn new(i<|>: i32) -> Self {
544 Self { i } 512 Self { i }
545 }
546 } 513 }
547 "#, 514}
548 "j", 515"#,
549 r#" 516 r#"
550 struct Foo { 517struct Foo { i: i32 }
551 i: i32,
552 }
553 518
554 impl Foo { 519impl Foo {
555 fn new(j: i32) -> Self { 520 fn new(j: i32) -> Self {
556 Self { i: j } 521 Self { i: j }
557 }
558 } 522 }
559 "#, 523}
524"#,
560 ); 525 );
561 } 526 }
562 527
563 #[test] 528 #[test]
564 fn test_field_shorthand_correct_struct() { 529 fn test_field_shorthand_correct_struct() {
565 test_rename( 530 check(
566 r#"
567 struct Foo {
568 i<|>: i32,
569 }
570
571 struct Bar {
572 i: i32,
573 }
574
575 impl Bar {
576 fn new(i: i32) -> Self {
577 Self { i }
578 }
579 }
580 "#,
581 "j", 531 "j",
582 r#" 532 r#"
583 struct Foo { 533struct Foo { i<|>: i32 }
584 j: i32, 534struct Bar { i: i32 }
585 }
586 535
587 struct Bar { 536impl Bar {
588 i: i32, 537 fn new(i: i32) -> Self {
538 Self { i }
589 } 539 }
540}
541"#,
542 r#"
543struct Foo { j: i32 }
544struct Bar { i: i32 }
590 545
591 impl Bar { 546impl Bar {
592 fn new(i: i32) -> Self { 547 fn new(i: i32) -> Self {
593 Self { i } 548 Self { i }
594 }
595 } 549 }
596 "#, 550}
551"#,
597 ); 552 );
598 } 553 }
599 554
600 #[test] 555 #[test]
601 fn test_shadow_local_for_struct_shorthand() { 556 fn test_shadow_local_for_struct_shorthand() {
602 test_rename( 557 check(
558 "j",
603 r#" 559 r#"
604 struct Foo { 560struct Foo { i: i32 }
605 i: i32,
606 }
607 561
608 fn baz(i<|>: i32) -> Self { 562fn baz(i<|>: i32) -> Self {
609 let x = Foo { i }; 563 let x = Foo { i };
610 { 564 {
611 let i = 0; 565 let i = 0;
612 Foo { i } 566 Foo { i }
613 }
614 } 567 }
615 "#, 568}
616 "j", 569"#,
617 r#" 570 r#"
618 struct Foo { 571struct Foo { i: i32 }
619 i: i32,
620 }
621 572
622 fn baz(j: i32) -> Self { 573fn baz(j: i32) -> Self {
623 let x = Foo { i: j }; 574 let x = Foo { i: j };
624 { 575 {
625 let i = 0; 576 let i = 0;
626 Foo { i } 577 Foo { i }
627 }
628 } 578 }
629 "#, 579}
580"#,
630 ); 581 );
631 } 582 }
632 583
633 #[test] 584 #[test]
634 fn test_rename_mod() { 585 fn test_rename_mod() {
635 let (analysis, position) = analysis_and_position( 586 check_expect(
587 "foo2",
636 r#" 588 r#"
637//- /lib.rs 589//- /lib.rs
638mod bar; 590mod bar;
@@ -641,53 +593,49 @@ mod bar;
641mod foo<|>; 593mod foo<|>;
642 594
643//- /bar/foo.rs 595//- /bar/foo.rs
644// emtpy 596// empty
645 "#, 597"#,
646 ); 598 expect![[r#"
647 let new_name = "foo2"; 599 RangeInfo {
648 let source_change = analysis.rename(position, new_name).unwrap(); 600 range: 4..7,
649 assert_debug_snapshot!(&source_change, 601 info: SourceChange {
650@r###" 602 source_file_edits: [
651 Some( 603 SourceFileEdit {
652 RangeInfo { 604 file_id: FileId(
653 range: 4..7, 605 2,
654 info: SourceChange { 606 ),
655 source_file_edits: [ 607 edit: TextEdit {
656 SourceFileEdit { 608 indels: [
657 file_id: FileId( 609 Indel {
658 2, 610 insert: "foo2",
659 ), 611 delete: 4..7,
660 edit: TextEdit { 612 },
661 indels: [ 613 ],
662 Indel { 614 },
663 insert: "foo2",
664 delete: 4..7,
665 },
666 ],
667 }, 615 },
668 }, 616 ],
669 ], 617 file_system_edits: [
670 file_system_edits: [ 618 MoveFile {
671 MoveFile { 619 src: FileId(
672 src: FileId( 620 3,
673 3, 621 ),
674 ), 622 anchor: FileId(
675 anchor: FileId( 623 3,
676 2, 624 ),
677 ), 625 dst: "foo2.rs",
678 dst: "foo2.rs", 626 },
679 }, 627 ],
680 ], 628 is_snippet: false,
681 is_snippet: false, 629 },
682 }, 630 }
683 }, 631 "#]],
684 ) 632 );
685 "###);
686 } 633 }
687 634
688 #[test] 635 #[test]
689 fn test_rename_mod_in_use_tree() { 636 fn test_rename_mod_in_use_tree() {
690 let (analysis, position) = analysis_and_position( 637 check_expect(
638 "quux",
691 r#" 639 r#"
692//- /main.rs 640//- /main.rs
693pub mod foo; 641pub mod foo;
@@ -699,140 +647,173 @@ pub struct FooContent;
699 647
700//- /bar.rs 648//- /bar.rs
701use crate::foo<|>::FooContent; 649use crate::foo<|>::FooContent;
702 "#, 650"#,
703 ); 651 expect![[r#"
704 let new_name = "qux"; 652 RangeInfo {
705 let source_change = analysis.rename(position, new_name).unwrap(); 653 range: 11..14,
706 assert_debug_snapshot!(&source_change, 654 info: SourceChange {
707@r###" 655 source_file_edits: [
708 Some( 656 SourceFileEdit {
709 RangeInfo { 657 file_id: FileId(
710 range: 11..14, 658 1,
711 info: SourceChange { 659 ),
712 source_file_edits: [ 660 edit: TextEdit {
713 SourceFileEdit { 661 indels: [
714 file_id: FileId( 662 Indel {
715 1, 663 insert: "quux",
716 ), 664 delete: 8..11,
717 edit: TextEdit { 665 },
718 indels: [ 666 ],
719 Indel { 667 },
720 insert: "qux",
721 delete: 8..11,
722 },
723 ],
724 }, 668 },
725 }, 669 SourceFileEdit {
726 SourceFileEdit { 670 file_id: FileId(
727 file_id: FileId( 671 3,
728 3, 672 ),
729 ), 673 edit: TextEdit {
730 edit: TextEdit { 674 indels: [
731 indels: [ 675 Indel {
732 Indel { 676 insert: "quux",
733 insert: "qux", 677 delete: 11..14,
734 delete: 11..14, 678 },
735 }, 679 ],
736 ], 680 },
737 }, 681 },
738 }, 682 ],
739 ], 683 file_system_edits: [
740 file_system_edits: [ 684 MoveFile {
741 MoveFile { 685 src: FileId(
742 src: FileId( 686 2,
743 2, 687 ),
744 ), 688 anchor: FileId(
745 anchor: FileId( 689 2,
746 3, 690 ),
747 ), 691 dst: "quux.rs",
748 dst: "qux.rs", 692 },
749 }, 693 ],
750 ], 694 is_snippet: false,
751 is_snippet: false, 695 },
752 }, 696 }
753 }, 697 "#]],
754 ) 698 );
755 "###);
756 } 699 }
757 700
758 #[test] 701 #[test]
759 fn test_rename_mod_in_dir() { 702 fn test_rename_mod_in_dir() {
760 let (analysis, position) = analysis_and_position( 703 check_expect(
704 "foo2",
761 r#" 705 r#"
762//- /lib.rs 706//- /lib.rs
763mod fo<|>o; 707mod fo<|>o;
764//- /foo/mod.rs 708//- /foo/mod.rs
765// emtpy 709// emtpy
766 "#, 710"#,
767 ); 711 expect![[r#"
768 let new_name = "foo2"; 712 RangeInfo {
769 let source_change = analysis.rename(position, new_name).unwrap(); 713 range: 4..7,
770 assert_debug_snapshot!(&source_change, 714 info: SourceChange {
771 @r###" 715 source_file_edits: [
772 Some( 716 SourceFileEdit {
773 RangeInfo { 717 file_id: FileId(
774 range: 4..7, 718 1,
775 info: SourceChange { 719 ),
776 source_file_edits: [ 720 edit: TextEdit {
777 SourceFileEdit { 721 indels: [
778 file_id: FileId( 722 Indel {
779 1, 723 insert: "foo2",
780 ), 724 delete: 4..7,
781 edit: TextEdit { 725 },
782 indels: [ 726 ],
783 Indel { 727 },
784 insert: "foo2",
785 delete: 4..7,
786 },
787 ],
788 }, 728 },
789 }, 729 ],
790 ], 730 file_system_edits: [
791 file_system_edits: [ 731 MoveFile {
792 MoveFile { 732 src: FileId(
793 src: FileId( 733 2,
794 2, 734 ),
795 ), 735 anchor: FileId(
796 anchor: FileId( 736 2,
797 1, 737 ),
798 ), 738 dst: "../foo2/mod.rs",
799 dst: "../foo2/mod.rs", 739 },
800 }, 740 ],
801 ], 741 is_snippet: false,
802 is_snippet: false, 742 },
803 }, 743 }
804 }, 744 "#]],
805 ) 745 );
806 "###
807 );
808 } 746 }
809 747
810 #[test] 748 #[test]
811 fn test_module_rename_in_path() { 749 fn test_rename_unusually_nested_mod() {
812 test_rename( 750 check_expect(
751 "bar",
813 r#" 752 r#"
814 mod <|>foo { 753//- /lib.rs
815 pub fn bar() {} 754mod outer { mod fo<|>o; }
755
756//- /outer/foo.rs
757// emtpy
758"#,
759 expect![[r#"
760 RangeInfo {
761 range: 16..19,
762 info: SourceChange {
763 source_file_edits: [
764 SourceFileEdit {
765 file_id: FileId(
766 1,
767 ),
768 edit: TextEdit {
769 indels: [
770 Indel {
771 insert: "bar",
772 delete: 16..19,
773 },
774 ],
775 },
776 },
777 ],
778 file_system_edits: [
779 MoveFile {
780 src: FileId(
781 2,
782 ),
783 anchor: FileId(
784 2,
785 ),
786 dst: "bar.rs",
787 },
788 ],
789 is_snippet: false,
790 },
791 }
792 "#]],
793 );
816 } 794 }
817 795
818 fn main() { 796 #[test]
819 foo::bar(); 797 fn test_module_rename_in_path() {
820 }"#, 798 check(
821 "baz", 799 "baz",
822 r#" 800 r#"
823 mod baz { 801mod <|>foo { pub fn bar() {} }
824 pub fn bar() {} 802
825 } 803fn main() { foo::bar(); }
804"#,
805 r#"
806mod baz { pub fn bar() {} }
826 807
827 fn main() { 808fn main() { baz::bar(); }
828 baz::bar(); 809"#,
829 }"#,
830 ); 810 );
831 } 811 }
832 812
833 #[test] 813 #[test]
834 fn test_rename_mod_filename_and_path() { 814 fn test_rename_mod_filename_and_path() {
835 let (analysis, position) = analysis_and_position( 815 check_expect(
816 "foo2",
836 r#" 817 r#"
837//- /lib.rs 818//- /lib.rs
838mod bar; 819mod bar;
@@ -845,229 +826,185 @@ pub mod foo<|>;
845 826
846//- /bar/foo.rs 827//- /bar/foo.rs
847// pub fn fun() {} 828// pub fn fun() {}
848 "#, 829"#,
849 ); 830 expect![[r#"
850 let new_name = "foo2"; 831 RangeInfo {
851 let source_change = analysis.rename(position, new_name).unwrap(); 832 range: 8..11,
852 assert_debug_snapshot!(&source_change, 833 info: SourceChange {
853@r###" 834 source_file_edits: [
854 Some( 835 SourceFileEdit {
855 RangeInfo { 836 file_id: FileId(
856 range: 8..11, 837 2,
857 info: SourceChange { 838 ),
858 source_file_edits: [ 839 edit: TextEdit {
859 SourceFileEdit { 840 indels: [
860 file_id: FileId( 841 Indel {
861 2, 842 insert: "foo2",
862 ), 843 delete: 8..11,
863 edit: TextEdit { 844 },
864 indels: [ 845 ],
865 Indel { 846 },
866 insert: "foo2",
867 delete: 8..11,
868 },
869 ],
870 }, 847 },
871 }, 848 SourceFileEdit {
872 SourceFileEdit { 849 file_id: FileId(
873 file_id: FileId( 850 1,
874 1, 851 ),
875 ), 852 edit: TextEdit {
876 edit: TextEdit { 853 indels: [
877 indels: [ 854 Indel {
878 Indel { 855 insert: "foo2",
879 insert: "foo2", 856 delete: 27..30,
880 delete: 27..30, 857 },
881 }, 858 ],
882 ], 859 },
883 }, 860 },
884 }, 861 ],
885 ], 862 file_system_edits: [
886 file_system_edits: [ 863 MoveFile {
887 MoveFile { 864 src: FileId(
888 src: FileId( 865 3,
889 3, 866 ),
890 ), 867 anchor: FileId(
891 anchor: FileId( 868 3,
892 2, 869 ),
893 ), 870 dst: "foo2.rs",
894 dst: "foo2.rs", 871 },
895 }, 872 ],
896 ], 873 is_snippet: false,
897 is_snippet: false, 874 },
898 }, 875 }
899 }, 876 "#]],
900 ) 877 );
901 "###);
902 } 878 }
903 879
904 #[test] 880 #[test]
905 fn test_enum_variant_from_module_1() { 881 fn test_enum_variant_from_module_1() {
906 test_rename( 882 check(
883 "Baz",
907 r#" 884 r#"
908 mod foo { 885mod foo {
909 pub enum Foo { 886 pub enum Foo { Bar<|> }
910 Bar<|>, 887}
911 }
912 }
913 888
914 fn func(f: foo::Foo) { 889fn func(f: foo::Foo) {
915 match f { 890 match f {
916 foo::Foo::Bar => {} 891 foo::Foo::Bar => {}
917 }
918 } 892 }
919 "#, 893}
920 "Baz", 894"#,
921 r#" 895 r#"
922 mod foo { 896mod foo {
923 pub enum Foo { 897 pub enum Foo { Baz }
924 Baz, 898}
925 }
926 }
927 899
928 fn func(f: foo::Foo) { 900fn func(f: foo::Foo) {
929 match f { 901 match f {
930 foo::Foo::Baz => {} 902 foo::Foo::Baz => {}
931 }
932 } 903 }
933 "#, 904}
905"#,
934 ); 906 );
935 } 907 }
936 908
937 #[test] 909 #[test]
938 fn test_enum_variant_from_module_2() { 910 fn test_enum_variant_from_module_2() {
939 test_rename( 911 check(
912 "baz",
940 r#" 913 r#"
941 mod foo { 914mod foo {
942 pub struct Foo { 915 pub struct Foo { pub bar<|>: uint }
943 pub bar<|>: uint, 916}
944 }
945 }
946 917
947 fn foo(f: foo::Foo) { 918fn foo(f: foo::Foo) {
948 let _ = f.bar; 919 let _ = f.bar;
949 } 920}
950 "#, 921"#,
951 "baz",
952 r#" 922 r#"
953 mod foo { 923mod foo {
954 pub struct Foo { 924 pub struct Foo { pub baz: uint }
955 pub baz: uint, 925}
956 }
957 }
958 926
959 fn foo(f: foo::Foo) { 927fn foo(f: foo::Foo) {
960 let _ = f.baz; 928 let _ = f.baz;
961 } 929}
962 "#, 930"#,
963 ); 931 );
964 } 932 }
965 933
966 #[test] 934 #[test]
967 fn test_parameter_to_self() { 935 fn test_parameter_to_self() {
968 test_rename( 936 check(
937 "self",
969 r#" 938 r#"
970 struct Foo { 939struct Foo { i: i32 }
971 i: i32,
972 }
973 940
974 impl Foo { 941impl Foo {
975 fn f(foo<|>: &mut Foo) -> i32 { 942 fn f(foo<|>: &mut Foo) -> i32 {
976 foo.i 943 foo.i
977 }
978 } 944 }
979 "#, 945}
980 "self", 946"#,
981 r#" 947 r#"
982 struct Foo { 948struct Foo { i: i32 }
983 i: i32,
984 }
985 949
986 impl Foo { 950impl Foo {
987 fn f(&mut self) -> i32 { 951 fn f(&mut self) -> i32 {
988 self.i 952 self.i
989 }
990 } 953 }
991 "#, 954}
955"#,
992 ); 956 );
993 } 957 }
994 958
995 #[test] 959 #[test]
996 fn test_self_to_parameter() { 960 fn test_self_to_parameter() {
997 test_rename( 961 check(
962 "foo",
998 r#" 963 r#"
999 struct Foo { 964struct Foo { i: i32 }
1000 i: i32,
1001 }
1002 965
1003 impl Foo { 966impl Foo {
1004 fn f(&mut <|>self) -> i32 { 967 fn f(&mut <|>self) -> i32 {
1005 self.i 968 self.i
1006 }
1007 } 969 }
1008 "#, 970}
1009 "foo", 971"#,
1010 r#" 972 r#"
1011 struct Foo { 973struct Foo { i: i32 }
1012 i: i32,
1013 }
1014 974
1015 impl Foo { 975impl Foo {
1016 fn f(foo: &mut Foo) -> i32 { 976 fn f(foo: &mut Foo) -> i32 {
1017 foo.i 977 foo.i
1018 }
1019 } 978 }
1020 "#, 979}
980"#,
1021 ); 981 );
1022 } 982 }
1023 983
1024 #[test] 984 #[test]
1025 fn test_self_in_path_to_parameter() { 985 fn test_self_in_path_to_parameter() {
1026 test_rename( 986 check(
987 "foo",
1027 r#" 988 r#"
1028 struct Foo { 989struct Foo { i: i32 }
1029 i: i32,
1030 }
1031 990
1032 impl Foo { 991impl Foo {
1033 fn f(&self) -> i32 { 992 fn f(&self) -> i32 {
1034 let self_var = 1; 993 let self_var = 1;
1035 self<|>.i 994 self<|>.i
1036 }
1037 } 995 }
1038 "#, 996}
1039 "foo", 997"#,
1040 r#" 998 r#"
1041 struct Foo { 999struct Foo { i: i32 }
1042 i: i32,
1043 }
1044 1000
1045 impl Foo { 1001impl Foo {
1046 fn f(foo: &Foo) -> i32 { 1002 fn f(foo: &Foo) -> i32 {
1047 let self_var = 1; 1003 let self_var = 1;
1048 foo.i 1004 foo.i
1049 }
1050 } 1005 }
1051 "#, 1006}
1007"#,
1052 ); 1008 );
1053 } 1009 }
1054
1055 fn test_rename(ra_fixture_before: &str, new_name: &str, ra_fixture_after: &str) {
1056 let ra_fixture_after = &trim_indent(ra_fixture_after);
1057 let (analysis, position) = analysis_and_position(ra_fixture_before);
1058 let source_change = analysis.rename(position, new_name).unwrap();
1059 let mut text_edit_builder = TextEditBuilder::default();
1060 let mut file_id: Option<FileId> = None;
1061 if let Some(change) = source_change {
1062 for edit in change.info.source_file_edits {
1063 file_id = Some(edit.file_id);
1064 for indel in edit.edit.into_iter() {
1065 text_edit_builder.replace(indel.delete, indel.insert);
1066 }
1067 }
1068 }
1069 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
1070 text_edit_builder.finish().apply(&mut result);
1071 assert_eq_text!(ra_fixture_after, &*result);
1072 }
1073} 1010}
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index f569a3f17..3b7162b84 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -102,7 +102,7 @@ pub(crate) fn runnable(
102) -> Option<Runnable> { 102) -> Option<Runnable> {
103 match_ast! { 103 match_ast! {
104 match item { 104 match item {
105 ast::FnDef(it) => runnable_fn(sema, it, file_id), 105 ast::Fn(it) => runnable_fn(sema, it, file_id),
106 ast::Module(it) => runnable_mod(sema, it, file_id), 106 ast::Module(it) => runnable_mod(sema, it, file_id),
107 _ => None, 107 _ => None,
108 } 108 }
@@ -111,7 +111,7 @@ pub(crate) fn runnable(
111 111
112fn runnable_fn( 112fn runnable_fn(
113 sema: &Semantics<RootDatabase>, 113 sema: &Semantics<RootDatabase>,
114 fn_def: ast::FnDef, 114 fn_def: ast::Fn,
115 file_id: FileId, 115 file_id: FileId,
116) -> Option<Runnable> { 116) -> Option<Runnable> {
117 let name_string = fn_def.name()?.text().to_string(); 117 let name_string = fn_def.name()?.text().to_string();
@@ -168,8 +168,7 @@ fn runnable_fn(
168 }; 168 };
169 169
170 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def)); 170 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &fn_def));
171 let cfg_exprs = 171 let cfg_exprs = attrs.cfg().collect();
172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
173 172
174 let nav = if let RunnableKind::DocTest { .. } = kind { 173 let nav = if let RunnableKind::DocTest { .. } = kind {
175 NavigationTarget::from_doc_commented( 174 NavigationTarget::from_doc_commented(
@@ -189,7 +188,7 @@ pub struct TestAttr {
189} 188}
190 189
191impl TestAttr { 190impl TestAttr {
192 fn from_fn(fn_def: &ast::FnDef) -> TestAttr { 191 fn from_fn(fn_def: &ast::Fn) -> TestAttr {
193 let ignore = fn_def 192 let ignore = fn_def
194 .attrs() 193 .attrs()
195 .filter_map(|attr| attr.simple_name()) 194 .filter_map(|attr| attr.simple_name())
@@ -204,7 +203,7 @@ impl TestAttr {
204/// 203///
205/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test, 204/// It may produce false positives, for example, `#[wasm_bindgen_test]` requires a different command to run the test,
206/// but it's better than not to have the runnables for the tests at all. 205/// but it's better than not to have the runnables for the tests at all.
207fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool { 206fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
208 fn_def 207 fn_def
209 .attrs() 208 .attrs()
210 .filter_map(|attr| attr.path()) 209 .filter_map(|attr| attr.path())
@@ -212,7 +211,7 @@ fn has_test_related_attribute(fn_def: &ast::FnDef) -> bool {
212 .any(|attribute_text| attribute_text.contains("test")) 211 .any(|attribute_text| attribute_text.contains("test"))
213} 212}
214 213
215fn has_doc_test(fn_def: &ast::FnDef) -> bool { 214fn has_doc_test(fn_def: &ast::Fn) -> bool {
216 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) 215 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```"))
217} 216}
218 217
@@ -221,15 +220,7 @@ fn runnable_mod(
221 module: ast::Module, 220 module: ast::Module,
222 file_id: FileId, 221 file_id: FileId,
223) -> Option<Runnable> { 222) -> Option<Runnable> {
224 let has_test_function = module 223 if !has_test_function_or_multiple_test_submodules(&module) {
225 .item_list()?
226 .items()
227 .filter_map(|it| match it {
228 ast::ModuleItem::FnDef(it) => Some(it),
229 _ => None,
230 })
231 .any(|f| has_test_related_attribute(&f));
232 if !has_test_function {
233 return None; 224 return None;
234 } 225 }
235 let module_def = sema.to_def(&module)?; 226 let module_def = sema.to_def(&module)?;
@@ -242,22 +233,56 @@ fn runnable_mod(
242 .join("::"); 233 .join("::");
243 234
244 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module)); 235 let attrs = Attrs::from_attrs_owner(sema.db, InFile::new(HirFileId::from(file_id), &module));
245 let cfg_exprs = 236 let cfg_exprs = attrs.cfg().collect();
246 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
247
248 let nav = module_def.to_nav(sema.db); 237 let nav = module_def.to_nav(sema.db);
249 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs }) 238 Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg_exprs })
250} 239}
251 240
241// We could create runnables for modules with number_of_test_submodules > 0,
242// but that bloats the runnables for no real benefit, since all tests can be run by the submodule already
243fn has_test_function_or_multiple_test_submodules(module: &ast::Module) -> bool {
244 if let Some(item_list) = module.item_list() {
245 let mut number_of_test_submodules = 0;
246
247 for item in item_list.items() {
248 match item {
249 ast::Item::Fn(f) => {
250 if has_test_related_attribute(&f) {
251 return true;
252 }
253 }
254 ast::Item::Module(submodule) => {
255 if has_test_function_or_multiple_test_submodules(&submodule) {
256 number_of_test_submodules += 1;
257 }
258 }
259 _ => (),
260 }
261 }
262
263 number_of_test_submodules > 1
264 } else {
265 false
266 }
267}
268
252#[cfg(test)] 269#[cfg(test)]
253mod tests { 270mod tests {
254 use insta::assert_debug_snapshot; 271 use expect::{expect, Expect};
255 272
256 use crate::mock_analysis::analysis_and_position; 273 use crate::mock_analysis::analysis_and_position;
257 274
258 use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; 275 use super::{RunnableAction, BENCH, BIN, DOCTEST, TEST};
259 276
260 fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { 277 fn check(
278 ra_fixture: &str,
279 // FIXME: fold this into `expect` as well
280 actions: &[&RunnableAction],
281 expect: Expect,
282 ) {
283 let (analysis, position) = analysis_and_position(ra_fixture);
284 let runnables = analysis.runnables(position.file_id).unwrap();
285 expect.assert_debug_eq(&runnables);
261 assert_eq!( 286 assert_eq!(
262 actions, 287 actions,
263 runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() 288 runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice()
@@ -266,579 +291,593 @@ mod tests {
266 291
267 #[test] 292 #[test]
268 fn test_runnables() { 293 fn test_runnables() {
269 let (analysis, pos) = analysis_and_position( 294 check(
270 r#" 295 r#"
271 //- /lib.rs 296//- /lib.rs
272 <|> //empty 297<|>
273 fn main() {} 298fn main() {}
274 299
275 #[test] 300#[test]
276 fn test_foo() {} 301fn test_foo() {}
277 302
278 #[test] 303#[test]
279 #[ignore] 304#[ignore]
280 fn test_foo() {} 305fn test_foo() {}
281 306
282 #[bench] 307#[bench]
283 fn bench() {} 308fn bench() {}
284 "#, 309"#,
285 ); 310 &[&BIN, &TEST, &TEST, &BENCH],
286 let runnables = analysis.runnables(pos.file_id).unwrap(); 311 expect![[r#"
287 assert_debug_snapshot!(&runnables, 312 [
288 @r###" 313 Runnable {
289 [ 314 nav: NavigationTarget {
290 Runnable { 315 file_id: FileId(
291 nav: NavigationTarget { 316 1,
292 file_id: FileId( 317 ),
293 1, 318 full_range: 1..13,
294 ), 319 focus_range: Some(
295 full_range: 1..21, 320 4..8,
296 name: "main", 321 ),
297 kind: FN_DEF, 322 name: "main",
298 focus_range: Some( 323 kind: FN,
299 12..16, 324 container_name: None,
300 ), 325 description: None,
301 container_name: None, 326 docs: None,
302 description: None, 327 },
303 docs: None, 328 kind: Bin,
304 }, 329 cfg_exprs: [],
305 kind: Bin, 330 },
306 cfg_exprs: [], 331 Runnable {
307 }, 332 nav: NavigationTarget {
308 Runnable { 333 file_id: FileId(
309 nav: NavigationTarget { 334 1,
310 file_id: FileId( 335 ),
311 1, 336 full_range: 15..39,
312 ), 337 focus_range: Some(
313 full_range: 23..47, 338 26..34,
314 name: "test_foo", 339 ),
315 kind: FN_DEF, 340 name: "test_foo",
316 focus_range: Some( 341 kind: FN,
317 34..42, 342 container_name: None,
318 ), 343 description: None,
319 container_name: None, 344 docs: None,
320 description: None, 345 },
321 docs: None, 346 kind: Test {
322 }, 347 test_id: Path(
323 kind: Test { 348 "test_foo",
324 test_id: Path( 349 ),
325 "test_foo", 350 attr: TestAttr {
326 ), 351 ignore: false,
327 attr: TestAttr { 352 },
328 ignore: false, 353 },
354 cfg_exprs: [],
355 },
356 Runnable {
357 nav: NavigationTarget {
358 file_id: FileId(
359 1,
360 ),
361 full_range: 41..75,
362 focus_range: Some(
363 62..70,
364 ),
365 name: "test_foo",
366 kind: FN,
367 container_name: None,
368 description: None,
369 docs: None,
370 },
371 kind: Test {
372 test_id: Path(
373 "test_foo",
374 ),
375 attr: TestAttr {
376 ignore: true,
377 },
378 },
379 cfg_exprs: [],
329 }, 380 },
330 }, 381 Runnable {
331 cfg_exprs: [], 382 nav: NavigationTarget {
332 }, 383 file_id: FileId(
333 Runnable { 384 1,
334 nav: NavigationTarget { 385 ),
335 file_id: FileId( 386 full_range: 77..99,
336 1, 387 focus_range: Some(
337 ), 388 89..94,
338 full_range: 49..83, 389 ),
339 name: "test_foo", 390 name: "bench",
340 kind: FN_DEF, 391 kind: FN,
341 focus_range: Some( 392 container_name: None,
342 70..78, 393 description: None,
343 ), 394 docs: None,
344 container_name: None, 395 },
345 description: None, 396 kind: Bench {
346 docs: None, 397 test_id: Path(
347 }, 398 "bench",
348 kind: Test { 399 ),
349 test_id: Path( 400 },
350 "test_foo", 401 cfg_exprs: [],
351 ),
352 attr: TestAttr {
353 ignore: true,
354 }, 402 },
355 }, 403 ]
356 cfg_exprs: [], 404 "#]],
357 }, 405 );
358 Runnable {
359 nav: NavigationTarget {
360 file_id: FileId(
361 1,
362 ),
363 full_range: 85..107,
364 name: "bench",
365 kind: FN_DEF,
366 focus_range: Some(
367 97..102,
368 ),
369 container_name: None,
370 description: None,
371 docs: None,
372 },
373 kind: Bench {
374 test_id: Path(
375 "bench",
376 ),
377 },
378 cfg_exprs: [],
379 },
380 ]
381 "###
382 );
383 assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]);
384 } 406 }
385 407
386 #[test] 408 #[test]
387 fn test_runnables_doc_test() { 409 fn test_runnables_doc_test() {
388 let (analysis, pos) = analysis_and_position( 410 check(
389 r#" 411 r#"
390 //- /lib.rs 412//- /lib.rs
391 <|> //empty 413<|>
392 fn main() {} 414fn main() {}
393 415
394 /// ``` 416/// ```
395 /// let x = 5; 417/// let x = 5;
396 /// ``` 418/// ```
397 fn foo() {} 419fn foo() {}
398 "#, 420"#,
421 &[&BIN, &DOCTEST],
422 expect![[r#"
423 [
424 Runnable {
425 nav: NavigationTarget {
426 file_id: FileId(
427 1,
428 ),
429 full_range: 1..13,
430 focus_range: Some(
431 4..8,
432 ),
433 name: "main",
434 kind: FN,
435 container_name: None,
436 description: None,
437 docs: None,
438 },
439 kind: Bin,
440 cfg_exprs: [],
441 },
442 Runnable {
443 nav: NavigationTarget {
444 file_id: FileId(
445 1,
446 ),
447 full_range: 15..57,
448 focus_range: None,
449 name: "foo",
450 kind: FN,
451 container_name: None,
452 description: None,
453 docs: None,
454 },
455 kind: DocTest {
456 test_id: Path(
457 "foo",
458 ),
459 },
460 cfg_exprs: [],
461 },
462 ]
463 "#]],
399 ); 464 );
400 let runnables = analysis.runnables(pos.file_id).unwrap();
401 assert_debug_snapshot!(&runnables,
402 @r###"
403 [
404 Runnable {
405 nav: NavigationTarget {
406 file_id: FileId(
407 1,
408 ),
409 full_range: 1..21,
410 name: "main",
411 kind: FN_DEF,
412 focus_range: Some(
413 12..16,
414 ),
415 container_name: None,
416 description: None,
417 docs: None,
418 },
419 kind: Bin,
420 cfg_exprs: [],
421 },
422 Runnable {
423 nav: NavigationTarget {
424 file_id: FileId(
425 1,
426 ),
427 full_range: 23..65,
428 name: "foo",
429 kind: FN_DEF,
430 focus_range: None,
431 container_name: None,
432 description: None,
433 docs: None,
434 },
435 kind: DocTest {
436 test_id: Path(
437 "foo",
438 ),
439 },
440 cfg_exprs: [],
441 },
442 ]
443 "###
444 );
445 assert_actions(&runnables, &[&BIN, &DOCTEST]);
446 } 465 }
447 466
448 #[test] 467 #[test]
449 fn test_runnables_doc_test_in_impl() { 468 fn test_runnables_doc_test_in_impl() {
450 let (analysis, pos) = analysis_and_position( 469 check(
451 r#" 470 r#"
452 //- /lib.rs 471//- /lib.rs
453 <|> //empty 472<|>
454 fn main() {} 473fn main() {}
455 474
456 struct Data; 475struct Data;
457 impl Data { 476impl Data {
458 /// ``` 477 /// ```
459 /// let x = 5; 478 /// let x = 5;
460 /// ``` 479 /// ```
461 fn foo() {} 480 fn foo() {}
462 } 481}
463 "#, 482"#,
483 &[&BIN, &DOCTEST],
484 expect![[r#"
485 [
486 Runnable {
487 nav: NavigationTarget {
488 file_id: FileId(
489 1,
490 ),
491 full_range: 1..13,
492 focus_range: Some(
493 4..8,
494 ),
495 name: "main",
496 kind: FN,
497 container_name: None,
498 description: None,
499 docs: None,
500 },
501 kind: Bin,
502 cfg_exprs: [],
503 },
504 Runnable {
505 nav: NavigationTarget {
506 file_id: FileId(
507 1,
508 ),
509 full_range: 44..98,
510 focus_range: None,
511 name: "foo",
512 kind: FN,
513 container_name: None,
514 description: None,
515 docs: None,
516 },
517 kind: DocTest {
518 test_id: Path(
519 "Data::foo",
520 ),
521 },
522 cfg_exprs: [],
523 },
524 ]
525 "#]],
464 ); 526 );
465 let runnables = analysis.runnables(pos.file_id).unwrap();
466 assert_debug_snapshot!(&runnables,
467 @r###"
468 [
469 Runnable {
470 nav: NavigationTarget {
471 file_id: FileId(
472 1,
473 ),
474 full_range: 1..21,
475 name: "main",
476 kind: FN_DEF,
477 focus_range: Some(
478 12..16,
479 ),
480 container_name: None,
481 description: None,
482 docs: None,
483 },
484 kind: Bin,
485 cfg_exprs: [],
486 },
487 Runnable {
488 nav: NavigationTarget {
489 file_id: FileId(
490 1,
491 ),
492 full_range: 52..106,
493 name: "foo",
494 kind: FN_DEF,
495 focus_range: None,
496 container_name: None,
497 description: None,
498 docs: None,
499 },
500 kind: DocTest {
501 test_id: Path(
502 "Data::foo",
503 ),
504 },
505 cfg_exprs: [],
506 },
507 ]
508 "###
509 );
510 assert_actions(&runnables, &[&BIN, &DOCTEST]);
511 } 527 }
512 528
513 #[test] 529 #[test]
514 fn test_runnables_module() { 530 fn test_runnables_module() {
515 let (analysis, pos) = analysis_and_position( 531 check(
516 r#" 532 r#"
517 //- /lib.rs 533//- /lib.rs
518 <|> //empty 534<|>
519 mod test_mod { 535mod test_mod {
520 #[test] 536 #[test]
521 fn test_foo1() {} 537 fn test_foo1() {}
522 } 538}
523 "#, 539"#,
524 ); 540 &[&TEST, &TEST],
525 let runnables = analysis.runnables(pos.file_id).unwrap(); 541 expect![[r#"
526 assert_debug_snapshot!(&runnables, 542 [
527 @r###" 543 Runnable {
528 [ 544 nav: NavigationTarget {
529 Runnable { 545 file_id: FileId(
530 nav: NavigationTarget { 546 1,
531 file_id: FileId( 547 ),
532 1, 548 full_range: 1..51,
533 ), 549 focus_range: Some(
534 full_range: 1..59, 550 5..13,
535 name: "test_mod", 551 ),
536 kind: MODULE, 552 name: "test_mod",
537 focus_range: Some( 553 kind: MODULE,
538 13..21, 554 container_name: None,
539 ), 555 description: None,
540 container_name: None, 556 docs: None,
541 description: None, 557 },
542 docs: None, 558 kind: TestMod {
543 }, 559 path: "test_mod",
544 kind: TestMod { 560 },
545 path: "test_mod", 561 cfg_exprs: [],
546 },
547 cfg_exprs: [],
548 },
549 Runnable {
550 nav: NavigationTarget {
551 file_id: FileId(
552 1,
553 ),
554 full_range: 28..57,
555 name: "test_foo1",
556 kind: FN_DEF,
557 focus_range: Some(
558 43..52,
559 ),
560 container_name: None,
561 description: None,
562 docs: None,
563 },
564 kind: Test {
565 test_id: Path(
566 "test_mod::test_foo1",
567 ),
568 attr: TestAttr {
569 ignore: false,
570 }, 562 },
571 }, 563 Runnable {
572 cfg_exprs: [], 564 nav: NavigationTarget {
573 }, 565 file_id: FileId(
574 ] 566 1,
575 "### 567 ),
576 ); 568 full_range: 20..49,
577 assert_actions(&runnables, &[&TEST, &TEST]); 569 focus_range: Some(
570 35..44,
571 ),
572 name: "test_foo1",
573 kind: FN,
574 container_name: None,
575 description: None,
576 docs: None,
577 },
578 kind: Test {
579 test_id: Path(
580 "test_mod::test_foo1",
581 ),
582 attr: TestAttr {
583 ignore: false,
584 },
585 },
586 cfg_exprs: [],
587 },
588 ]
589 "#]],
590 );
578 } 591 }
579 592
580 #[test] 593 #[test]
581 fn test_runnables_one_depth_layer_module() { 594 fn only_modules_with_test_functions_or_more_than_one_test_submodule_have_runners() {
582 let (analysis, pos) = analysis_and_position( 595 check(
583 r#" 596 r#"
584 //- /lib.rs 597//- /lib.rs
585 <|> //empty 598<|>
586 mod foo { 599mod root_tests {
587 mod test_mod { 600 mod nested_tests_0 {
588 #[test] 601 mod nested_tests_1 {
589 fn test_foo1() {} 602 #[test]
590 } 603 fn nested_test_11() {}
604
605 #[test]
606 fn nested_test_12() {}
591 } 607 }
592 "#,
593 );
594 let runnables = analysis.runnables(pos.file_id).unwrap();
595 assert_debug_snapshot!(&runnables,
596 @r###"
597 [
598 Runnable {
599 nav: NavigationTarget {
600 file_id: FileId(
601 1,
602 ),
603 full_range: 23..85,
604 name: "test_mod",
605 kind: MODULE,
606 focus_range: Some(
607 27..35,
608 ),
609 container_name: None,
610 description: None,
611 docs: None,
612 },
613 kind: TestMod {
614 path: "foo::test_mod",
615 },
616 cfg_exprs: [],
617 },
618 Runnable {
619 nav: NavigationTarget {
620 file_id: FileId(
621 1,
622 ),
623 full_range: 46..79,
624 name: "test_foo1",
625 kind: FN_DEF,
626 focus_range: Some(
627 65..74,
628 ),
629 container_name: None,
630 description: None,
631 docs: None,
632 },
633 kind: Test {
634 test_id: Path(
635 "foo::test_mod::test_foo1",
636 ),
637 attr: TestAttr {
638 ignore: false,
639 },
640 },
641 cfg_exprs: [],
642 },
643 ]
644 "###
645 );
646 assert_actions(&runnables, &[&TEST, &TEST]);
647 }
648 608
649 #[test] 609 mod nested_tests_2 {
650 fn test_runnables_multiple_depth_module() { 610 #[test]
651 let (analysis, pos) = analysis_and_position( 611 fn nested_test_2() {}
652 r#"
653 //- /lib.rs
654 <|> //empty
655 mod foo {
656 mod bar {
657 mod test_mod {
658 #[test]
659 fn test_foo1() {}
660 }
661 }
662 } 612 }
663 "#, 613
664 ); 614 mod nested_tests_3 {}
665 let runnables = analysis.runnables(pos.file_id).unwrap();
666 assert_debug_snapshot!(&runnables,
667 @r###"
668 [
669 Runnable {
670 nav: NavigationTarget {
671 file_id: FileId(
672 1,
673 ),
674 full_range: 41..115,
675 name: "test_mod",
676 kind: MODULE,
677 focus_range: Some(
678 45..53,
679 ),
680 container_name: None,
681 description: None,
682 docs: None,
683 },
684 kind: TestMod {
685 path: "foo::bar::test_mod",
686 },
687 cfg_exprs: [],
688 },
689 Runnable {
690 nav: NavigationTarget {
691 file_id: FileId(
692 1,
693 ),
694 full_range: 68..105,
695 name: "test_foo1",
696 kind: FN_DEF,
697 focus_range: Some(
698 91..100,
699 ),
700 container_name: None,
701 description: None,
702 docs: None,
703 },
704 kind: Test {
705 test_id: Path(
706 "foo::bar::test_mod::test_foo1",
707 ),
708 attr: TestAttr {
709 ignore: false,
710 },
711 },
712 cfg_exprs: [],
713 },
714 ]
715 "###
716 );
717 assert_actions(&runnables, &[&TEST, &TEST]);
718 } 615 }
719 616
720 #[test] 617 mod nested_tests_4 {}
721 fn test_runnables_with_feature() { 618}
722 let (analysis, pos) = analysis_and_position( 619"#,
723 r#" 620 &[&TEST, &TEST, &TEST, &TEST, &TEST, &TEST],
724 //- /lib.rs crate:foo cfg:feature=foo 621 expect![[r#"
725 <|> //empty 622 [
726 #[test] 623 Runnable {
727 #[cfg(feature = "foo")] 624 nav: NavigationTarget {
728 fn test_foo1() {} 625 file_id: FileId(
729 "#, 626 1,
730 ); 627 ),
731 let runnables = analysis.runnables(pos.file_id).unwrap(); 628 full_range: 22..323,
732 assert_debug_snapshot!(&runnables, 629 focus_range: Some(
733 @r###" 630 26..40,
734 [ 631 ),
735 Runnable { 632 name: "nested_tests_0",
736 nav: NavigationTarget { 633 kind: MODULE,
737 file_id: FileId( 634 container_name: None,
738 1, 635 description: None,
739 ), 636 docs: None,
740 full_range: 1..58, 637 },
741 name: "test_foo1", 638 kind: TestMod {
742 kind: FN_DEF, 639 path: "root_tests::nested_tests_0",
743 focus_range: Some( 640 },
744 44..53, 641 cfg_exprs: [],
745 ), 642 },
746 container_name: None, 643 Runnable {
747 description: None, 644 nav: NavigationTarget {
748 docs: None, 645 file_id: FileId(
749 }, 646 1,
750 kind: Test { 647 ),
751 test_id: Path( 648 full_range: 51..192,
752 "test_foo1", 649 focus_range: Some(
753 ), 650 55..69,
754 attr: TestAttr { 651 ),
755 ignore: false, 652 name: "nested_tests_1",
653 kind: MODULE,
654 container_name: None,
655 description: None,
656 docs: None,
657 },
658 kind: TestMod {
659 path: "root_tests::nested_tests_0::nested_tests_1",
660 },
661 cfg_exprs: [],
662 },
663 Runnable {
664 nav: NavigationTarget {
665 file_id: FileId(
666 1,
667 ),
668 full_range: 84..126,
669 focus_range: Some(
670 107..121,
671 ),
672 name: "nested_test_11",
673 kind: FN,
674 container_name: None,
675 description: None,
676 docs: None,
677 },
678 kind: Test {
679 test_id: Path(
680 "root_tests::nested_tests_0::nested_tests_1::nested_test_11",
681 ),
682 attr: TestAttr {
683 ignore: false,
684 },
685 },
686 cfg_exprs: [],
687 },
688 Runnable {
689 nav: NavigationTarget {
690 file_id: FileId(
691 1,
692 ),
693 full_range: 140..182,
694 focus_range: Some(
695 163..177,
696 ),
697 name: "nested_test_12",
698 kind: FN,
699 container_name: None,
700 description: None,
701 docs: None,
702 },
703 kind: Test {
704 test_id: Path(
705 "root_tests::nested_tests_0::nested_tests_1::nested_test_12",
706 ),
707 attr: TestAttr {
708 ignore: false,
709 },
710 },
711 cfg_exprs: [],
712 },
713 Runnable {
714 nav: NavigationTarget {
715 file_id: FileId(
716 1,
717 ),
718 full_range: 202..286,
719 focus_range: Some(
720 206..220,
721 ),
722 name: "nested_tests_2",
723 kind: MODULE,
724 container_name: None,
725 description: None,
726 docs: None,
727 },
728 kind: TestMod {
729 path: "root_tests::nested_tests_0::nested_tests_2",
730 },
731 cfg_exprs: [],
756 }, 732 },
757 }, 733 Runnable {
758 cfg_exprs: [ 734 nav: NavigationTarget {
759 KeyValue { 735 file_id: FileId(
760 key: "feature", 736 1,
761 value: "foo", 737 ),
738 full_range: 235..276,
739 focus_range: Some(
740 258..271,
741 ),
742 name: "nested_test_2",
743 kind: FN,
744 container_name: None,
745 description: None,
746 docs: None,
747 },
748 kind: Test {
749 test_id: Path(
750 "root_tests::nested_tests_0::nested_tests_2::nested_test_2",
751 ),
752 attr: TestAttr {
753 ignore: false,
754 },
755 },
756 cfg_exprs: [],
762 }, 757 },
763 ], 758 ]
764 }, 759 "#]],
765 ] 760 );
766 "###
767 );
768 assert_actions(&runnables, &[&TEST]);
769 } 761 }
770 762
771 #[test] 763 #[test]
772 fn test_runnables_with_features() { 764 fn test_runnables_with_feature() {
773 let (analysis, pos) = analysis_and_position( 765 check(
774 r#" 766 r#"
775 //- /lib.rs crate:foo cfg:feature=foo,feature=bar 767//- /lib.rs crate:foo cfg:feature=foo
776 <|> //empty 768<|>
777 #[test] 769#[test]
778 #[cfg(all(feature = "foo", feature = "bar"))] 770#[cfg(feature = "foo")]
779 fn test_foo1() {} 771fn test_foo1() {}
780 "#, 772"#,
781 ); 773 &[&TEST],
782 let runnables = analysis.runnables(pos.file_id).unwrap(); 774 expect![[r#"
783 assert_debug_snapshot!(&runnables, 775 [
784 @r###" 776 Runnable {
785 [ 777 nav: NavigationTarget {
786 Runnable { 778 file_id: FileId(
787 nav: NavigationTarget { 779 1,
788 file_id: FileId( 780 ),
789 1, 781 full_range: 1..50,
790 ), 782 focus_range: Some(
791 full_range: 1..80, 783 36..45,
792 name: "test_foo1", 784 ),
793 kind: FN_DEF, 785 name: "test_foo1",
794 focus_range: Some( 786 kind: FN,
795 66..75, 787 container_name: None,
796 ), 788 description: None,
797 container_name: None, 789 docs: None,
798 description: None, 790 },
799 docs: None, 791 kind: Test {
800 }, 792 test_id: Path(
801 kind: Test { 793 "test_foo1",
802 test_id: Path( 794 ),
803 "test_foo1", 795 attr: TestAttr {
804 ), 796 ignore: false,
805 attr: TestAttr { 797 },
806 ignore: false, 798 },
807 }, 799 cfg_exprs: [
808 },
809 cfg_exprs: [
810 All(
811 [
812 KeyValue { 800 KeyValue {
813 key: "feature", 801 key: "feature",
814 value: "foo", 802 value: "foo",
815 }, 803 },
816 KeyValue { 804 ],
817 key: "feature", 805 },
818 value: "bar", 806 ]
807 "#]],
808 );
809 }
810
811 #[test]
812 fn test_runnables_with_features() {
813 check(
814 r#"
815//- /lib.rs crate:foo cfg:feature=foo,feature=bar
816<|>
817#[test]
818#[cfg(all(feature = "foo", feature = "bar"))]
819fn test_foo1() {}
820"#,
821 &[&TEST],
822 expect![[r#"
823 [
824 Runnable {
825 nav: NavigationTarget {
826 file_id: FileId(
827 1,
828 ),
829 full_range: 1..72,
830 focus_range: Some(
831 58..67,
832 ),
833 name: "test_foo1",
834 kind: FN,
835 container_name: None,
836 description: None,
837 docs: None,
838 },
839 kind: Test {
840 test_id: Path(
841 "test_foo1",
842 ),
843 attr: TestAttr {
844 ignore: false,
819 }, 845 },
846 },
847 cfg_exprs: [
848 All(
849 [
850 KeyValue {
851 key: "feature",
852 value: "foo",
853 },
854 KeyValue {
855 key: "feature",
856 value: "bar",
857 },
858 ],
859 ),
820 ], 860 ],
821 ), 861 },
822 ], 862 ]
823 }, 863 "#]],
824 ] 864 );
825 "###
826 );
827 assert_actions(&runnables, &[&TEST]);
828 } 865 }
829 866
830 #[test] 867 #[test]
831 fn test_runnables_no_test_function_in_module() { 868 fn test_runnables_no_test_function_in_module() {
832 let (analysis, pos) = analysis_and_position( 869 check(
833 r#" 870 r#"
834 //- /lib.rs 871//- /lib.rs
835 <|> //empty 872<|>
836 mod test_mod { 873mod test_mod {
837 fn foo1() {} 874 fn foo1() {}
838 } 875}
839 "#, 876"#,
877 &[],
878 expect![[r#"
879 []
880 "#]],
840 ); 881 );
841 let runnables = analysis.runnables(pos.file_id).unwrap();
842 assert!(runnables.is_empty())
843 } 882 }
844} 883}
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
deleted file mode 100644
index e8155def7..000000000
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ /dev/null
@@ -1,101 +0,0 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; }
36</style>
37<pre><code><span class="comment documentation">/// ```</span>
38<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> _ = </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="generic injected">;</span>
39<span class="comment documentation">/// ```</span>
40<span class="keyword">struct</span> <span class="struct declaration">Foo</span> {
41 <span class="field declaration">bar</span>: <span class="builtin_type">bool</span>,
42}
43
44<span class="keyword">impl</span> <span class="struct">Foo</span> {
45 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>;
46
47 <span class="comment documentation">/// Constructs a new `Foo`.</span>
48 <span class="comment documentation">///</span>
49 <span class="comment documentation">/// # Examples</span>
50 <span class="comment documentation">///</span>
51 <span class="comment documentation">/// ```</span>
52 <span class="comment documentation">/// #</span><span class="generic injected"> </span><span class="attribute injected">#![</span><span class="function attribute injected">allow</span><span class="attribute injected">(unused_mut)]</span>
53 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="generic injected">: </span><span class="struct injected">Foo</span><span class="generic injected"> = </span><span class="struct injected">Foo</span><span class="generic injected">::</span><span class="function injected">new</span><span class="generic injected">();</span>
54 <span class="comment documentation">/// ```</span>
55 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> {
56 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> }
57 }
58
59 <span class="comment documentation">/// `bar` method on `Foo`.</span>
60 <span class="comment documentation">///</span>
61 <span class="comment documentation">/// # Examples</span>
62 <span class="comment documentation">///</span>
63 <span class="comment documentation">/// ```</span>
64 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="generic injected"> </span><span class="module injected">x</span><span class="generic injected">::</span><span class="module injected">y</span><span class="generic injected">;</span>
65 <span class="comment documentation">///</span>
66 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">foo</span><span class="generic injected"> = </span><span class="struct injected">Foo</span><span class="generic injected">::</span><span class="function injected">new</span><span class="generic injected">();</span>
67 <span class="comment documentation">///</span>
68 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
69 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="generic injected">(foo.bar());</span>
70 <span class="comment documentation">///</span>
71 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">bar</span><span class="generic injected"> = </span><span class="variable injected">foo</span><span class="generic injected">.</span><span class="field injected">bar</span><span class="generic injected"> || </span><span class="struct injected">Foo</span><span class="generic injected">::</span><span class="constant injected">bar</span><span class="generic injected">;</span>
72 <span class="comment documentation">///</span>
73 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line
74 </span><span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
75 <span class="comment documentation">///</span>
76 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="generic injected"> = </span><span class="string_literal injected">"Foo
77 </span><span class="comment documentation">/// </span><span class="string_literal injected"> bar
78 </span><span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="generic injected">;</span>
79 <span class="comment documentation">///</span>
80 <span class="comment documentation">/// ```</span>
81 <span class="comment documentation">///</span>
82 <span class="comment documentation">/// ```rust,no_run</span>
83 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">foobar</span><span class="generic injected"> = </span><span class="struct injected">Foo</span><span class="generic injected">::</span><span class="function injected">new</span><span class="generic injected">().</span><span class="function injected">bar</span><span class="generic injected">();</span>
84 <span class="comment documentation">/// ```</span>
85 <span class="comment documentation">///</span>
86 <span class="comment documentation">/// ```sh</span>
87 <span class="comment documentation">/// echo 1</span>
88 <span class="comment documentation">/// ```</span>
89 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> {
90 <span class="bool_literal">true</span>
91 }
92}
93
94<span class="comment documentation">/// ```</span>
95<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="generic injected">(</span><span class="numeric_literal injected">1</span><span class="generic injected">);</span>
96<span class="comment documentation">/// ```</span>
97<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> {
98 ($expr:expr) =&gt; {
99 $expr
100 }
101}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
deleted file mode 100644
index d184b5691..000000000
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ /dev/null
@@ -1,95 +0,0 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; }
36</style>
37<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> {
38 ($($arg:tt)*) =&gt; ({
39 $<span class="keyword">crate</span>::io::_print($<span class="keyword">crate</span>::format_args_nl!($($arg)*));
40 })
41}
42#[rustc_builtin_macro]
43<span class="macro">macro_rules!</span> <span class="macro declaration">format_args_nl</span> {
44 ($fmt:expr) =&gt; {{ <span class="comment">/* compiler built-in */</span> }};
45 ($fmt:expr, $($args:tt)*) =&gt; {{ <span class="comment">/* compiler built-in */</span> }};
46}
47
48<span class="keyword">fn</span> <span class="function declaration">main</span>() {
49 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
50 <span class="macro">println!</span>(<span class="string_literal">"Hello"</span>); <span class="comment">// =&gt; "Hello"</span>
51 <span class="macro">println!</span>(<span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); <span class="comment">// =&gt; "Hello, world!"</span>
52 <span class="macro">println!</span>(<span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>); <span class="comment">// =&gt; "The number is 1"</span>
53 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span>, (<span class="numeric_literal">3</span>, <span class="numeric_literal">4</span>)); <span class="comment">// =&gt; "(3, 4)"</span>
54 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span>, value=<span class="numeric_literal">4</span>); <span class="comment">// =&gt; "4"</span>
55 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "1 2"</span>
56 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">42</span>); <span class="comment">// =&gt; "0042" with leading zerosV</span>
57 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1 1 2"</span>
58 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// =&gt; "test"</span>
59 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1"</span>
60 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// =&gt; "a 3 b"</span>
61 <span class="macro">println!</span>(<span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "{2}"</span>
62 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
63 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>);
64 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>);
65 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, width = <span class="numeric_literal">5</span>);
66 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
67 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
68 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
69 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
70 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
71 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>);
72 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
73 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>);
74 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>);
75 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>);
76 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>);
77 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
78 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
79 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
80 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, prec = <span class="numeric_literal">5</span>, number = <span class="numeric_literal">0.01</span>);
81 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="numeric_literal">1234.56</span>);
82 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>);
83 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>);
84 <span class="macro">println!</span>(<span class="string_literal">"Hello {{}}"</span>);
85 <span class="macro">println!</span>(<span class="string_literal">"{{ Hello"</span>);
86
87 <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>);
88
89 <span class="comment">// escape sequences</span>
90 <span class="macro">println!</span>(<span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span>);
91 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span>);
92
93 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>);
94 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>);
95}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
deleted file mode 100644
index 8d0b38f95..000000000
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ /dev/null
@@ -1,117 +0,0 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; }
36</style>
37<pre><code><span class="attribute">#[</span><span class="function attribute">derive</span><span class="attribute">(Clone, Debug)]</span>
38<span class="keyword">struct</span> <span class="struct declaration">Foo</span> {
39 <span class="keyword">pub</span> <span class="field declaration">x</span>: <span class="builtin_type">i32</span>,
40 <span class="keyword">pub</span> <span class="field declaration">y</span>: <span class="builtin_type">i32</span>,
41}
42
43<span class="keyword">trait</span> <span class="trait declaration">Bar</span> {
44 <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">i32</span>;
45}
46
47<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> {
48 <span class="keyword">fn</span> <span class="function declaration">bar</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">i32</span> {
49 <span class="self_keyword">self</span>.<span class="field">x</span>
50 }
51}
52
53<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable">STATIC_MUT</span>: <span class="builtin_type">i32</span> = <span class="numeric_literal">0</span>;
54
55<span class="keyword">fn</span> <span class="function declaration">foo</span>&lt;<span class="lifetime declaration">'a</span>, <span class="type_param declaration">T</span>&gt;() -&gt; <span class="type_param">T</span> {
56 <span class="function">foo</span>::&lt;<span class="lifetime">'a</span>, <span class="builtin_type">i32</span>&gt;()
57}
58
59<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> {
60 ($($tt:tt)*) =&gt; {$($tt)*}
61}
62
63<span class="macro">def_fn!</span> {
64 <span class="keyword">fn</span> <span class="function declaration">bar</span>() -&gt; <span class="builtin_type">u32</span> {
65 <span class="numeric_literal">100</span>
66 }
67}
68
69<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> {
70 ($expr:expr) =&gt; {
71 $expr
72 }
73}
74
75<span class="comment">// comment</span>
76<span class="keyword">fn</span> <span class="function declaration">main</span>() {
77 <span class="macro">println!</span>(<span class="string_literal">"Hello, {}!"</span>, <span class="numeric_literal">92</span>);
78
79 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> = <span class="unresolved_reference">Vec</span>::<span class="unresolved_reference">new</span>();
80 <span class="keyword control">if</span> <span class="bool_literal">true</span> {
81 <span class="keyword">let</span> <span class="variable declaration">x</span> = <span class="numeric_literal">92</span>;
82 <span class="variable mutable">vec</span>.<span class="unresolved_reference">push</span>(<span class="struct">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="numeric_literal">1</span> });
83 }
84 <span class="keyword unsafe">unsafe</span> {
85 <span class="variable mutable">vec</span>.<span class="unresolved_reference">set_len</span>(<span class="numeric_literal">0</span>);
86 <span class="static mutable">STATIC_MUT</span> = <span class="numeric_literal">1</span>;
87 }
88
89 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> {
90 <span class="comment">// Do nothing</span>
91 }
92
93 <span class="macro">noop!</span>(<span class="macro">noop</span><span class="macro">!</span>(<span class="numeric_literal">1</span>));
94
95 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> = <span class="numeric_literal">42</span>;
96 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> = &<span class="keyword">mut</span> <span class="variable mutable">x</span>;
97 <span class="keyword">let</span> <span class="variable declaration">z</span> = &<span class="variable mutable">y</span>;
98
99 <span class="keyword">let</span> <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable declaration">z</span>, <span class="field">y</span> } = <span class="struct">Foo</span> { <span class="field">x</span>: <span class="variable">z</span>, <span class="field">y</span> };
100
101 <span class="variable">y</span>;
102}
103
104<span class="keyword">enum</span> <span class="enum declaration">Option</span>&lt;<span class="type_param declaration">T</span>&gt; {
105 <span class="enum_variant declaration">Some</span>(<span class="type_param">T</span>),
106 <span class="enum_variant declaration">None</span>,
107}
108<span class="keyword">use</span> <span class="enum">Option</span>::*;
109
110<span class="keyword">impl</span>&lt;<span class="type_param declaration">T</span>&gt; <span class="enum">Option</span>&lt;<span class="type_param">T</span>&gt; {
111 <span class="keyword">fn</span> <span class="function declaration">and</span>&lt;<span class="type_param declaration">U</span>&gt;(<span class="self_keyword">self</span>, <span class="variable declaration">other</span>: <span class="enum">Option</span>&lt;<span class="type_param">U</span>&gt;) -&gt; <span class="enum">Option</span>&lt;(<span class="type_param">T</span>, <span class="type_param">U</span>)&gt; {
112 <span class="keyword control">match</span> <span class="variable">other</span> {
113 <span class="enum_variant">None</span> =&gt; <span class="macro">unimplemented!</span>(),
114 <span class="variable declaration">Nope</span> =&gt; <span class="variable">Nope</span>,
115 }
116 }
117}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 6cb96608b..4348b43be 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -1,15 +1,43 @@
1use ra_db::SourceDatabaseExt; 1use ra_db::{FilePosition, FileRange};
2use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; 2use ra_ide_db::RootDatabase;
3 3
4use crate::SourceFileEdit; 4use crate::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrError, SsrRule}; 5use ra_ssr::{MatchFinder, SsrError, SsrRule};
6 6
7// Feature: Structural Seach and Replace 7// Feature: Structural Search and Replace
8// 8//
9// Search and replace with named wildcards that will match any expression, type, path, pattern or item. 9// Search and replace with named wildcards that will match any expression, type, path, pattern or item.
10// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. 10// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
11// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement. 11// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
12// Within a macro call, a placeholder will match up until whatever token follows the placeholder. 12// Within a macro call, a placeholder will match up until whatever token follows the placeholder.
13//
14// All paths in both the search pattern and the replacement template must resolve in the context
15// in which this command is invoked. Paths in the search pattern will then match the code if they
16// resolve to the same item, even if they're written differently. For example if we invoke the
17// command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers
18// to `foo::Bar` will match.
19//
20// Paths in the replacement template will be rendered appropriately for the context in which the
21// replacement occurs. For example if our replacement template is `foo::Bar` and we match some
22// code in the `foo` module, we'll insert just `Bar`.
23//
24// Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match
25// `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`.
26//
27// The scope of the search / replace will be restricted to the current selection if any, otherwise
28// it will apply to the whole workspace.
29//
30// Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
31//
32// Supported constraints:
33//
34// |===
35// | Constraint | Restricts placeholder
36//
37// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`)
38// | not(a) | Negates the constraint `a`
39// |===
40//
13// Available via the command `rust-analyzer.ssr`. 41// Available via the command `rust-analyzer.ssr`.
14// 42//
15// ```rust 43// ```rust
@@ -31,21 +59,14 @@ pub fn parse_search_replace(
31 rule: &str, 59 rule: &str,
32 parse_only: bool, 60 parse_only: bool,
33 db: &RootDatabase, 61 db: &RootDatabase,
62 resolve_context: FilePosition,
63 selections: Vec<FileRange>,
34) -> Result<Vec<SourceFileEdit>, SsrError> { 64) -> Result<Vec<SourceFileEdit>, SsrError> {
35 let mut edits = vec![];
36 let rule: SsrRule = rule.parse()?; 65 let rule: SsrRule = rule.parse()?;
66 let mut match_finder = MatchFinder::in_context(db, resolve_context, selections);
67 match_finder.add_rule(rule)?;
37 if parse_only { 68 if parse_only {
38 return Ok(edits); 69 return Ok(Vec::new());
39 }
40 let mut match_finder = MatchFinder::new(db);
41 match_finder.add_rule(rule);
42 for &root in db.local_roots().iter() {
43 let sr = db.source_root(root);
44 for file_id in sr.iter() {
45 if let Some(edit) = match_finder.edits_for_file(file_id) {
46 edits.push(SourceFileEdit { file_id, edit });
47 }
48 }
49 } 70 }
50 Ok(edits) 71 Ok(match_finder.edits())
51} 72}
diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs
index 45411b357..08e6f69cb 100644
--- a/crates/ra_ide/src/status.rs
+++ b/crates/ra_ide/src/status.rs
@@ -2,10 +2,7 @@ use std::{fmt, iter::FromIterator, sync::Arc};
2 2
3use hir::MacroFile; 3use hir::MacroFile;
4use ra_db::{ 4use ra_db::{
5 salsa::{ 5 salsa::debug::{DebugQueryTable, TableEntry},
6 debug::{DebugQueryTable, TableEntry},
7 Database,
8 },
9 FileTextQuery, SourceRootId, 6 FileTextQuery, SourceRootId,
10}; 7};
11use ra_ide_db::{ 8use ra_ide_db::{
@@ -14,15 +11,15 @@ use ra_ide_db::{
14}; 11};
15use ra_prof::{memory_usage, Bytes}; 12use ra_prof::{memory_usage, Bytes};
16use ra_syntax::{ast, Parse, SyntaxNode}; 13use ra_syntax::{ast, Parse, SyntaxNode};
14use rustc_hash::FxHashMap;
17 15
18use crate::FileId; 16use crate::FileId;
19use rustc_hash::FxHashMap;
20 17
21fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 18fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
22 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>() 19 ra_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
23} 20}
24fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 21fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
25 db.query(hir::db::ParseMacroQuery).entries::<SyntaxTreeStats>() 22 hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>()
26} 23}
27 24
28// Feature: Status 25// Feature: Status
@@ -35,10 +32,10 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
35// | VS Code | **Rust Analyzer: Status** 32// | VS Code | **Rust Analyzer: Status**
36// |=== 33// |===
37pub(crate) fn status(db: &RootDatabase) -> String { 34pub(crate) fn status(db: &RootDatabase) -> String {
38 let files_stats = db.query(FileTextQuery).entries::<FilesStats>(); 35 let files_stats = FileTextQuery.in_db(db).entries::<FilesStats>();
39 let syntax_tree_stats = syntax_tree_stats(db); 36 let syntax_tree_stats = syntax_tree_stats(db);
40 let macro_syntax_tree_stats = macro_syntax_tree_stats(db); 37 let macro_syntax_tree_stats = macro_syntax_tree_stats(db);
41 let symbols_stats = db.query(LibrarySymbolsQuery).entries::<LibrarySymbolsStats>(); 38 let symbols_stats = LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>();
42 format!( 39 format!(
43 "{}\n{}\n{}\n{} (macros)\n\n\nmemory:\n{}\ngc {:?} seconds ago", 40 "{}\n{}\n{}\n{} (macros)\n\n\nmemory:\n{}\ngc {:?} seconds ago",
44 files_stats, 41 files_stats,
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 028b55902..e3a96f9d5 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -464,7 +464,7 @@ fn highlight_element(
464 let db = sema.db; 464 let db = sema.db;
465 let mut binding_hash = None; 465 let mut binding_hash = None;
466 let highlight: Highlight = match element.kind() { 466 let highlight: Highlight = match element.kind() {
467 FN_DEF => { 467 FN => {
468 bindings_shadow_count.clear(); 468 bindings_shadow_count.clear();
469 return None; 469 return None;
470 } 470 }
@@ -539,20 +539,52 @@ fn highlight_element(
539 _ => h, 539 _ => h,
540 } 540 }
541 } 541 }
542 T![*] => { 542 p if p.is_punct() => match p {
543 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?; 543 T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => {
544 544 HighlightTag::Operator.into()
545 let expr = prefix_expr.expr()?;
546 let ty = sema.type_of_expr(&expr)?;
547 if !ty.is_raw_ptr() {
548 return None;
549 } else {
550 HighlightTag::Operator | HighlightModifier::Unsafe
551 } 545 }
552 } 546 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
553 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 547 HighlightTag::Macro.into()
554 Highlight::new(HighlightTag::Macro) 548 }
555 } 549 T![*] if element.parent().and_then(ast::PointerType::cast).is_some() => {
550 HighlightTag::Keyword.into()
551 }
552 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
553 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
554
555 let expr = prefix_expr.expr()?;
556 let ty = sema.type_of_expr(&expr)?;
557 if ty.is_raw_ptr() {
558 HighlightTag::Operator | HighlightModifier::Unsafe
559 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
560 HighlightTag::Operator.into()
561 } else {
562 HighlightTag::Punctuation.into()
563 }
564 }
565 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
566 HighlightTag::NumericLiteral.into()
567 }
568 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
569 HighlightTag::Operator.into()
570 }
571 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
572 HighlightTag::Operator.into()
573 }
574 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
575 HighlightTag::Operator.into()
576 }
577 _ if element.parent().and_then(ast::RangePat::cast).is_some() => {
578 HighlightTag::Operator.into()
579 }
580 _ if element.parent().and_then(ast::DotDotPat::cast).is_some() => {
581 HighlightTag::Operator.into()
582 }
583 _ if element.parent().and_then(ast::Attr::cast).is_some() => {
584 HighlightTag::Attribute.into()
585 }
586 _ => HighlightTag::Punctuation.into(),
587 },
556 588
557 k if k.is_keyword() => { 589 k if k.is_keyword() => {
558 let h = Highlight::new(HighlightTag::Keyword); 590 let h = Highlight::new(HighlightTag::Keyword);
@@ -566,10 +598,31 @@ fn highlight_element(
566 | T![return] 598 | T![return]
567 | T![while] 599 | T![while]
568 | T![in] => h | HighlightModifier::ControlFlow, 600 | T![in] => h | HighlightModifier::ControlFlow,
569 T![for] if !is_child_of_impl(element) => h | HighlightModifier::ControlFlow, 601 T![for] if !is_child_of_impl(&element) => h | HighlightModifier::ControlFlow,
570 T![unsafe] => h | HighlightModifier::Unsafe, 602 T![unsafe] => h | HighlightModifier::Unsafe,
571 T![true] | T![false] => HighlightTag::BoolLiteral.into(), 603 T![true] | T![false] => HighlightTag::BoolLiteral.into(),
572 T![self] => HighlightTag::SelfKeyword.into(), 604 T![self] => {
605 let self_param_is_mut = element
606 .parent()
607 .and_then(ast::SelfParam::cast)
608 .and_then(|p| p.mut_token())
609 .is_some();
610 // closure to enforce lazyness
611 let self_path = || {
612 sema.resolve_path(&element.parent()?.parent().and_then(ast::Path::cast)?)
613 };
614 if self_param_is_mut
615 || matches!(self_path(),
616 Some(hir::PathResolution::Local(local))
617 if local.is_self(db)
618 && (local.is_mut(db) || local.ty(db).is_mutable_reference())
619 )
620 {
621 HighlightTag::SelfKeyword | HighlightModifier::Mutable
622 } else {
623 HighlightTag::SelfKeyword.into()
624 }
625 }
573 _ => h, 626 _ => h,
574 } 627 }
575 } 628 }
@@ -592,9 +645,9 @@ fn highlight_element(
592 } 645 }
593} 646}
594 647
595fn is_child_of_impl(element: SyntaxElement) -> bool { 648fn is_child_of_impl(element: &SyntaxElement) -> bool {
596 match element.parent() { 649 match element.parent() {
597 Some(e) => e.kind() == IMPL_DEF, 650 Some(e) => e.kind() == IMPL,
598 _ => false, 651 _ => false,
599 } 652 }
600} 653}
@@ -630,9 +683,10 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
630 }, 683 },
631 Definition::SelfType(_) => HighlightTag::SelfType, 684 Definition::SelfType(_) => HighlightTag::SelfType,
632 Definition::TypeParam(_) => HighlightTag::TypeParam, 685 Definition::TypeParam(_) => HighlightTag::TypeParam,
633 // FIXME: distinguish between locals and parameters
634 Definition::Local(local) => { 686 Definition::Local(local) => {
635 let mut h = Highlight::new(HighlightTag::Local); 687 let tag =
688 if local.is_param(db) { HighlightTag::ValueParam } else { HighlightTag::Local };
689 let mut h = Highlight::new(tag);
636 if local.is_mut(db) || local.ty(db).is_mutable_reference() { 690 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
637 h |= HighlightModifier::Mutable; 691 h |= HighlightModifier::Mutable;
638 } 692 }
@@ -651,18 +705,18 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
651 }; 705 };
652 706
653 let tag = match parent.kind() { 707 let tag = match parent.kind() {
654 STRUCT_DEF => HighlightTag::Struct, 708 STRUCT => HighlightTag::Struct,
655 ENUM_DEF => HighlightTag::Enum, 709 ENUM => HighlightTag::Enum,
656 UNION_DEF => HighlightTag::Union, 710 UNION => HighlightTag::Union,
657 TRAIT_DEF => HighlightTag::Trait, 711 TRAIT => HighlightTag::Trait,
658 TYPE_ALIAS_DEF => HighlightTag::TypeAlias, 712 TYPE_ALIAS => HighlightTag::TypeAlias,
659 TYPE_PARAM => HighlightTag::TypeParam, 713 TYPE_PARAM => HighlightTag::TypeParam,
660 RECORD_FIELD_DEF => HighlightTag::Field, 714 RECORD_FIELD => HighlightTag::Field,
661 MODULE => HighlightTag::Module, 715 MODULE => HighlightTag::Module,
662 FN_DEF => HighlightTag::Function, 716 FN => HighlightTag::Function,
663 CONST_DEF => HighlightTag::Constant, 717 CONST => HighlightTag::Constant,
664 STATIC_DEF => HighlightTag::Static, 718 STATIC => HighlightTag::Static,
665 ENUM_VARIANT => HighlightTag::EnumVariant, 719 VARIANT => HighlightTag::EnumVariant,
666 BIND_PAT => HighlightTag::Local, 720 BIND_PAT => HighlightTag::Local,
667 _ => default, 721 _ => default,
668 }; 722 };
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 0c74f7370..a5e7d2867 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -1,5 +1,6 @@
1//! Renders a bit of code as HTML. 1//! Renders a bit of code as HTML.
2 2
3use oorandom::Rand32;
3use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
4use ra_syntax::{AstNode, TextRange, TextSize}; 5use ra_syntax::{AstNode, TextRange, TextSize};
5 6
@@ -9,13 +10,12 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
9 let parse = db.parse(file_id); 10 let parse = db.parse(file_id);
10 11
11 fn rainbowify(seed: u64) -> String { 12 fn rainbowify(seed: u64) -> String {
12 use rand::prelude::*; 13 let mut rng = Rand32::new(seed);
13 let mut rng = SmallRng::seed_from_u64(seed);
14 format!( 14 format!(
15 "hsl({h},{s}%,{l}%)", 15 "hsl({h},{s}%,{l}%)",
16 h = rng.gen_range::<u16, _, _>(0, 361), 16 h = rng.rand_range(0..361),
17 s = rng.gen_range::<u16, _, _>(42, 99), 17 s = rng.rand_range(42..99),
18 l = rng.gen_range::<u16, _, _>(40, 91), 18 l = rng.rand_range(40..91),
19 ) 19 )
20 } 20 }
21 21
@@ -83,14 +83,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
83.bool_literal { color: #BFE6EB; } 83.bool_literal { color: #BFE6EB; }
84.macro { color: #94BFF3; } 84.macro { color: #94BFF3; }
85.module { color: #AFD8AF; } 85.module { color: #AFD8AF; }
86.value_param { color: #DCDCCC; }
86.variable { color: #DCDCCC; } 87.variable { color: #DCDCCC; }
87.format_specifier { color: #CC696B; } 88.format_specifier { color: #CC696B; }
88.mutable { text-decoration: underline; } 89.mutable { text-decoration: underline; }
89.unresolved_reference { color: #FC5555; }
90.escape_sequence { color: #94BFF3; } 90.escape_sequence { color: #94BFF3; }
91
92.keyword { color: #F0DFAF; font-weight: bold; } 91.keyword { color: #F0DFAF; font-weight: bold; }
93.keyword.unsafe { color: #BC8383; font-weight: bold; } 92.keyword.unsafe { color: #BC8383; font-weight: bold; }
94.control { font-style: italic; } 93.control { font-style: italic; }
94
95.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
95</style> 96</style>
96"; 97";
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 181c21256..8665b480f 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -25,7 +25,7 @@ pub(super) fn highlight_injection(
25 return None; 25 return None;
26 } 26 }
27 let value = literal.value()?; 27 let value = literal.value()?;
28 let (analysis, tmp_file_id) = Analysis::from_single_file(value); 28 let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned());
29 29
30 if let Some(range) = literal.open_quote_text_range() { 30 if let Some(range) = literal.open_quote_text_range() {
31 acc.add(HighlightedRange { 31 acc.add(HighlightedRange {
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index 13d9dd195..49ec94bdc 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -32,6 +32,7 @@ pub enum HighlightTag {
32 Macro, 32 Macro,
33 Module, 33 Module,
34 NumericLiteral, 34 NumericLiteral,
35 Punctuation,
35 SelfKeyword, 36 SelfKeyword,
36 SelfType, 37 SelfType,
37 Static, 38 Static,
@@ -41,6 +42,7 @@ pub enum HighlightTag {
41 TypeAlias, 42 TypeAlias,
42 TypeParam, 43 TypeParam,
43 Union, 44 Union,
45 ValueParam,
44 Local, 46 Local,
45 UnresolvedReference, 47 UnresolvedReference,
46 FormatSpecifier, 48 FormatSpecifier,
@@ -82,6 +84,7 @@ impl HighlightTag {
82 HighlightTag::Generic => "generic", 84 HighlightTag::Generic => "generic",
83 HighlightTag::Keyword => "keyword", 85 HighlightTag::Keyword => "keyword",
84 HighlightTag::Lifetime => "lifetime", 86 HighlightTag::Lifetime => "lifetime",
87 HighlightTag::Punctuation => "punctuation",
85 HighlightTag::Macro => "macro", 88 HighlightTag::Macro => "macro",
86 HighlightTag::Module => "module", 89 HighlightTag::Module => "module",
87 HighlightTag::NumericLiteral => "numeric_literal", 90 HighlightTag::NumericLiteral => "numeric_literal",
@@ -95,6 +98,7 @@ impl HighlightTag {
95 HighlightTag::TypeAlias => "type_alias", 98 HighlightTag::TypeAlias => "type_alias",
96 HighlightTag::TypeParam => "type_param", 99 HighlightTag::TypeParam => "type_param",
97 HighlightTag::Union => "union", 100 HighlightTag::Union => "union",
101 HighlightTag::ValueParam => "value_param",
98 HighlightTag::Local => "variable", 102 HighlightTag::Local => "variable",
99 HighlightTag::UnresolvedReference => "unresolved_reference", 103 HighlightTag::UnresolvedReference => "unresolved_reference",
100 } 104 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index b7fad9719..87a6e2523 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,7 @@
1use std::fs; 1use std::fs;
2 2
3use test_utils::{assert_eq_text, project_dir, read_text}; 3use expect::{expect_file, ExpectFile};
4use test_utils::project_dir;
4 5
5use crate::{mock_analysis::single_file, FileRange, TextRange}; 6use crate::{mock_analysis::single_file, FileRange, TextRange};
6 7
@@ -24,6 +25,16 @@ impl Bar for Foo {
24 } 25 }
25} 26}
26 27
28impl Foo {
29 fn baz(mut self) -> i32 {
30 self.x
31 }
32
33 fn qux(&mut self) {
34 self.x = 0;
35 }
36}
37
27static mut STATIC_MUT: i32 = 0; 38static mut STATIC_MUT: i32 = 0;
28 39
29fn foo<'a, T>() -> T { 40fn foo<'a, T>() -> T {
@@ -91,7 +102,7 @@ impl<T> Option<T> {
91} 102}
92"# 103"#
93 .trim(), 104 .trim(),
94 "crates/ra_ide/src/snapshots/highlighting.html", 105 expect_file!["crates/ra_ide/test_data/highlighting.html"],
95 false, 106 false,
96 ); 107 );
97} 108}
@@ -114,7 +125,7 @@ fn bar() {
114} 125}
115"# 126"#
116 .trim(), 127 .trim(),
117 "crates/ra_ide/src/snapshots/rainbow_highlighting.html", 128 expect_file!["crates/ra_ide/test_data/rainbow_highlighting.html"],
118 true, 129 true,
119 ); 130 );
120} 131}
@@ -167,7 +178,7 @@ fn main() {
167 ); 178 );
168}"## 179}"##
169 .trim(), 180 .trim(),
170 "crates/ra_ide/src/snapshots/highlight_injection.html", 181 expect_file!["crates/ra_ide/test_data/highlight_injection.html"],
171 false, 182 false,
172 ); 183 );
173} 184}
@@ -250,7 +261,7 @@ fn main() {
250 println!("{ничоси}", ничоси = 92); 261 println!("{ничоси}", ничоси = 92);
251}"# 262}"#
252 .trim(), 263 .trim(),
253 "crates/ra_ide/src/snapshots/highlight_strings.html", 264 expect_file!["crates/ra_ide/test_data/highlight_strings.html"],
254 false, 265 false,
255 ); 266 );
256} 267}
@@ -278,7 +289,7 @@ fn main() {
278} 289}
279"# 290"#
280 .trim(), 291 .trim(),
281 "crates/ra_ide/src/snapshots/highlight_unsafe.html", 292 expect_file!["crates/ra_ide/test_data/highlight_unsafe.html"],
282 false, 293 false,
283 ); 294 );
284} 295}
@@ -354,7 +365,7 @@ macro_rules! noop {
354} 365}
355"# 366"#
356 .trim(), 367 .trim(),
357 "crates/ra_ide/src/snapshots/highlight_doctest.html", 368 expect_file!["crates/ra_ide/test_data/highlight_doctest.html"],
358 false, 369 false,
359 ); 370 );
360} 371}
@@ -362,11 +373,8 @@ macro_rules! noop {
362/// Highlights the code given by the `ra_fixture` argument, renders the 373/// Highlights the code given by the `ra_fixture` argument, renders the
363/// result as HTML, and compares it with the HTML file given as `snapshot`. 374/// result as HTML, and compares it with the HTML file given as `snapshot`.
364/// Note that the `snapshot` file is overwritten by the rendered HTML. 375/// Note that the `snapshot` file is overwritten by the rendered HTML.
365fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { 376fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
366 let (analysis, file_id) = single_file(ra_fixture); 377 let (analysis, file_id) = single_file(ra_fixture);
367 let dst_file = project_dir().join(snapshot);
368 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); 378 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
369 let expected_html = &read_text(&dst_file); 379 expect.assert_eq(actual_html)
370 fs::write(dst_file, &actual_html).unwrap();
371 assert_eq_text!(expected_html, actual_html);
372} 380}
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs
index f716a3861..07217e808 100644
--- a/crates/ra_ide/src/syntax_tree.rs
+++ b/crates/ra_ide/src/syntax_tree.rs
@@ -116,7 +116,7 @@ mod tests {
116 syn.trim(), 116 syn.trim(),
117 r#" 117 r#"
118[email protected] 118[email protected]
119 FN_DEF@0..11 119 [email protected]
120 [email protected] "fn" 120 [email protected] "fn"
121 [email protected] " " 121 [email protected] " "
122 [email protected] 122 [email protected]
@@ -148,7 +148,7 @@ fn test() {
148 syn.trim(), 148 syn.trim(),
149 r#" 149 r#"
150[email protected] 150[email protected]
151 FN_DEF@0..60 151 [email protected]
152 [email protected] "fn" 152 [email protected] "fn"
153 [email protected] " " 153 [email protected] " "
154 [email protected] 154 [email protected]
@@ -190,7 +190,7 @@ [email protected]
190 assert_eq_text!( 190 assert_eq_text!(
191 syn.trim(), 191 syn.trim(),
192 r#" 192 r#"
193FN_DEF@0..11 193[email protected]
194 [email protected] "fn" 194 [email protected] "fn"
195 [email protected] " " 195 [email protected] " "
196 [email protected] 196 [email protected]
@@ -258,7 +258,7 @@ fn bar() {
258 syn.trim(), 258 syn.trim(),
259 r#" 259 r#"
260[email protected] 260[email protected]
261 FN_DEF@0..12 261 [email protected]
262 [email protected] "fn" 262 [email protected] "fn"
263 [email protected] " " 263 [email protected] " "
264 [email protected] 264 [email protected]
@@ -292,7 +292,7 @@ fn bar() {
292 syn.trim(), 292 syn.trim(),
293 r#" 293 r#"
294[email protected] 294[email protected]
295 FN_DEF@0..12 295 [email protected]
296 [email protected] "fn" 296 [email protected] "fn"
297 [email protected] " " 297 [email protected] " "
298 [email protected] 298 [email protected]
@@ -325,7 +325,7 @@ fn bar() {
325 syn.trim(), 325 syn.trim(),
326 r#" 326 r#"
327[email protected] 327[email protected]
328 FN_DEF@0..12 328 [email protected]
329 [email protected] "fn" 329 [email protected] "fn"
330 [email protected] " " 330 [email protected] " "
331 [email protected] 331 [email protected]
@@ -339,7 +339,7 @@ [email protected]
339 [email protected] "\n" 339 [email protected] "\n"
340 [email protected] "}" 340 [email protected] "}"
341 [email protected] "\n" 341 [email protected] "\n"
342 FN_DEF@13..25 342 [email protected]
343 [email protected] "fn" 343 [email protected] "fn"
344 [email protected] " " 344 [email protected] " "
345 [email protected] 345 [email protected]
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs
index 83776d2b6..d3ce744b4 100644
--- a/crates/ra_ide/src/typing.rs
+++ b/crates/ra_ide/src/typing.rs
@@ -39,7 +39,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
39// Some features trigger on typing certain characters: 39// Some features trigger on typing certain characters:
40// 40//
41// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression 41// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
42// - Enter inside comments automatically inserts `///`
43// - typing `.` in a chain method call auto-indents 42// - typing `.` in a chain method call auto-indents
44pub(crate) fn on_char_typed( 43pub(crate) fn on_char_typed(
45 db: &RootDatabase, 44 db: &RootDatabase,
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs
index 2faaa8ff0..143b1ae41 100644
--- a/crates/ra_ide/src/typing/on_enter.rs
+++ b/crates/ra_ide/src/typing/on_enter.rs
@@ -7,10 +7,31 @@ use ra_syntax::{
7 ast::{self, AstToken}, 7 ast::{self, AstToken},
8 AstNode, SmolStr, SourceFile, 8 AstNode, SmolStr, SourceFile,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxToken, TextSize, TokenAtOffset, 10 SyntaxToken, TextRange, TextSize, TokenAtOffset,
11}; 11};
12use ra_text_edit::TextEdit; 12use ra_text_edit::TextEdit;
13use test_utils::mark;
13 14
15// Feature: On Enter
16//
17// rust-analyzer can override kbd:[Enter] key to make it smarter:
18//
19// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
20// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
21//
22// This action needs to be assigned to shortcut explicitly.
23//
24// VS Code::
25//
26// Add the following to `keybindings.json`:
27// [source,json]
28// ----
29// {
30// "key": "Enter",
31// "command": "rust-analyzer.onEnter",
32// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
33// }
34// ----
14pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 35pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
15 let parse = db.parse(position.file_id); 36 let parse = db.parse(position.file_id);
16 let file = parse.tree(); 37 let file = parse.tree();
@@ -30,15 +51,25 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
30 return None; 51 return None;
31 } 52 }
32 53
54 let mut remove_last_space = false;
33 // Continuing single-line non-doc comments (like this one :) ) is annoying 55 // Continuing single-line non-doc comments (like this one :) ) is annoying
34 if prefix == "//" && comment_range.end() == position.offset && !followed_by_comment(&comment) { 56 if prefix == "//" && comment_range.end() == position.offset {
35 return None; 57 if comment.text().ends_with(' ') {
58 mark::hit!(continues_end_of_line_comment_with_space);
59 remove_last_space = true;
60 } else if !followed_by_comment(&comment) {
61 return None;
62 }
36 } 63 }
37 64
38 let indent = node_indent(&file, comment.syntax())?; 65 let indent = node_indent(&file, comment.syntax())?;
39 let inserted = format!("\n{}{} $0", indent, prefix); 66 let inserted = format!("\n{}{} $0", indent, prefix);
40 let edit = TextEdit::insert(position.offset, inserted); 67 let delete = if remove_last_space {
41 68 TextRange::new(position.offset - TextSize::of(' '), position.offset)
69 } else {
70 TextRange::empty(position.offset)
71 };
72 let edit = TextEdit::replace(delete, inserted);
42 Some(edit) 73 Some(edit)
43} 74}
44 75
@@ -75,10 +106,10 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> {
75 106
76#[cfg(test)] 107#[cfg(test)]
77mod tests { 108mod tests {
78 use test_utils::assert_eq_text; 109 use stdx::trim_indent;
110 use test_utils::{assert_eq_text, mark};
79 111
80 use crate::mock_analysis::analysis_and_position; 112 use crate::mock_analysis::analysis_and_position;
81 use stdx::trim_indent;
82 113
83 fn apply_on_enter(before: &str) -> Option<String> { 114 fn apply_on_enter(before: &str) -> Option<String> {
84 let (analysis, position) = analysis_and_position(&before); 115 let (analysis, position) = analysis_and_position(&before);
@@ -192,7 +223,7 @@ fn main() {
192 } 223 }
193 224
194 #[test] 225 #[test]
195 fn does_not_continue_end_of_code_comment() { 226 fn does_not_continue_end_of_line_comment() {
196 do_check_noop( 227 do_check_noop(
197 r" 228 r"
198fn main() { 229fn main() {
@@ -202,4 +233,24 @@ fn main() {
202", 233",
203 ); 234 );
204 } 235 }
236
237 #[test]
238 fn continues_end_of_line_comment_with_space() {
239 mark::check!(continues_end_of_line_comment_with_space);
240 do_check(
241 r#"
242fn main() {
243 // Fix me <|>
244 let x = 1 + 1;
245}
246"#,
247 r#"
248fn main() {
249 // Fix me
250 // $0
251 let x = 1 + 1;
252}
253"#,
254 );
255 }
205} 256}
diff --git a/crates/ra_ide/test_data/highlight_doctest.html b/crates/ra_ide/test_data/highlight_doctest.html
new file mode 100644
index 000000000..6322d404f
--- /dev/null
+++ b/crates/ra_ide/test_data/highlight_doctest.html
@@ -0,0 +1,102 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
28.variable { color: #DCDCCC; }
29.format_specifier { color: #CC696B; }
30.mutable { text-decoration: underline; }
31.escape_sequence { color: #94BFF3; }
32.keyword { color: #F0DFAF; font-weight: bold; }
33.keyword.unsafe { color: #BC8383; font-weight: bold; }
34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
37</style>
38<pre><code><span class="comment documentation">/// ```</span>
39<span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="punctuation injected">_</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="string_literal injected">"early doctests should not go boom"</span><span class="punctuation injected">;</span><span class="punctuation injected">
40</span><span class="comment documentation">/// ```</span>
41<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span>
42 <span class="field declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span><span class="punctuation">,</span>
43<span class="punctuation">}</span>
44
45<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
46 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span><span class="punctuation">:</span> <span class="builtin_type">bool</span> <span class="operator">=</span> <span class="bool_literal">true</span><span class="punctuation">;</span>
47
48 <span class="comment documentation">/// Constructs a new `Foo`.</span>
49 <span class="comment documentation">///</span>
50 <span class="comment documentation">/// # Examples</span>
51 <span class="comment documentation">///</span>
52 <span class="comment documentation">/// ```</span>
53 <span class="comment documentation">/// #</span><span class="generic injected"> </span><span class="attribute injected">#</span><span class="attribute injected">!</span><span class="attribute injected">[</span><span class="function attribute injected">allow</span><span class="punctuation injected">(</span><span class="attribute injected">unused_mut</span><span class="punctuation injected">)</span><span class="attribute injected">]</span>
54 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="keyword injected">mut</span><span class="generic injected"> </span><span class="variable declaration injected mutable">foo</span><span class="punctuation injected">:</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
55</span> <span class="comment documentation">/// ```</span>
56 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
57 <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">bar</span><span class="punctuation">:</span> <span class="bool_literal">true</span> <span class="punctuation">}</span>
58 <span class="punctuation">}</span>
59
60 <span class="comment documentation">/// `bar` method on `Foo`.</span>
61 <span class="comment documentation">///</span>
62 <span class="comment documentation">/// # Examples</span>
63 <span class="comment documentation">///</span>
64 <span class="comment documentation">/// ```</span>
65 <span class="comment documentation">/// </span><span class="keyword injected">use</span><span class="generic injected"> </span><span class="module injected">x</span><span class="operator injected">::</span><span class="module injected">y</span><span class="punctuation injected">;</span>
66 <span class="comment documentation">///</span>
67 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">foo</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span>
68 <span class="comment documentation">///</span>
69 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
70 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="punctuation injected">(</span><span class="generic injected">foo</span><span class="punctuation injected">.</span><span class="generic injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span>
71 <span class="comment documentation">///</span>
72 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">bar</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="variable injected">foo</span><span class="punctuation injected">.</span><span class="field injected">bar</span><span class="generic injected"> </span><span class="operator injected">||</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="punctuation injected">;</span>
73 <span class="comment documentation">///</span>
74 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line
75 </span><span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
76 <span class="comment documentation">///</span>
77 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="string_literal injected">"Foo
78 </span><span class="comment documentation">/// </span><span class="string_literal injected"> bar
79 </span><span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="punctuation injected">;</span>
80 <span class="comment documentation">///</span>
81 <span class="comment documentation">/// ```</span>
82 <span class="comment documentation">///</span>
83 <span class="comment documentation">/// ```rust,no_run</span>
84 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="generic injected"> </span><span class="variable declaration injected">foobar</span><span class="generic injected"> </span><span class="operator injected">=</span><span class="generic injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">.</span><span class="function injected">bar</span><span class="punctuation injected">(</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
85</span> <span class="comment documentation">/// ```</span>
86 <span class="comment documentation">///</span>
87 <span class="comment documentation">/// ```sh</span>
88 <span class="comment documentation">/// echo 1</span>
89 <span class="comment documentation">/// ```</span>
90 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">bool</span> <span class="punctuation">{</span>
91 <span class="bool_literal">true</span>
92 <span class="punctuation">}</span>
93<span class="punctuation">}</span>
94
95<span class="comment documentation">/// ```</span>
96<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="punctuation injected">(</span><span class="numeric_literal injected">1</span><span class="punctuation injected">)</span><span class="punctuation injected">;</span><span class="punctuation injected">
97</span><span class="comment documentation">/// ```</span>
98<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
99 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
100 <span class="punctuation">$</span>expr
101 <span class="punctuation">}</span>
102<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/test_data/highlight_injection.html
index 1b0349bae..18addd00d 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/test_data/highlight_injection.html
@@ -24,24 +24,25 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
24.bool_literal { color: #BFE6EB; } 24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; } 25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; } 26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
27.variable { color: #DCDCCC; } 28.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; } 29.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; } 30.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; } 31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; } 32.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; } 33.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; } 34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
36</style> 37</style>
37<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span>(<span class="variable declaration">ra_fixture</span>: &<span class="builtin_type">str</span>) {} 38<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
38 39
39<span class="keyword">fn</span> <span class="function declaration">main</span>() { 40<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
40 <span class="function">fixture</span>(<span class="string_literal">r#"</span> 41 <span class="function">fixture</span><span class="punctuation">(</span><span class="string_literal">r#"</span>
41 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> { 42 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="punctuation">{</span>
42 <span class="keyword">fn</span> <span class="function declaration">foo</span>() { 43 <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
43 <span class="macro">println!</span>(<span class="string_literal">"2 + 2 = {}"</span>, <span class="numeric_literal">4</span>); 44 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span>
44 } 45 <span class="punctuation">}</span>
45 }<span class="string_literal">"#</span> 46 <span class="punctuation">}</span><span class="string_literal">"#</span>
46 ); 47 <span class="punctuation">)</span><span class="punctuation">;</span>
47}</code></pre> \ No newline at end of file 48<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/test_data/highlight_strings.html b/crates/ra_ide/test_data/highlight_strings.html
new file mode 100644
index 000000000..1b681b2c6
--- /dev/null
+++ b/crates/ra_ide/test_data/highlight_strings.html
@@ -0,0 +1,96 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
28.variable { color: #DCDCCC; }
29.format_specifier { color: #CC696B; }
30.mutable { text-decoration: underline; }
31.escape_sequence { color: #94BFF3; }
32.keyword { color: #F0DFAF; font-weight: bold; }
33.keyword.unsafe { color: #BC8383; font-weight: bold; }
34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
37</style>
38<pre><code><span class="macro">macro_rules!</span> <span class="macro declaration">println</span> <span class="punctuation">{</span>
39 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">(</span><span class="punctuation">{</span>
40 <span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>io<span class="punctuation">:</span><span class="punctuation">:</span>_print<span class="punctuation">(</span><span class="punctuation">$</span><span class="keyword">crate</span><span class="punctuation">:</span><span class="punctuation">:</span>format_args_nl<span class="punctuation">!</span><span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>arg<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
41 <span class="punctuation">}</span><span class="punctuation">)</span>
42<span class="punctuation">}</span>
43#[rustc_builtin_macro]
44<span class="macro">macro_rules!</span> <span class="macro declaration">format_args_nl</span> <span class="punctuation">{</span>
45 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
46 <span class="punctuation">(</span><span class="punctuation">$</span>fmt<span class="punctuation">:</span>expr<span class="punctuation">,</span> <span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>args<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">{</span> <span class="comment">/* compiler built-in */</span> <span class="punctuation">}</span><span class="punctuation">}</span><span class="punctuation">;</span>
47<span class="punctuation">}</span>
48
49<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
50 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
51 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello"</span>
52 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "Hello, world!"</span>
53 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "The number is 1"</span>
54 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="punctuation">(</span><span class="numeric_literal">3</span><span class="punctuation">,</span> <span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "(3, 4)"</span>
55 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> value<span class="operator">=</span><span class="numeric_literal">4</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "4"</span>
56 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "1 2"</span>
57 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">42</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span>
58 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1 1 2"</span>
59 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> argument <span class="operator">=</span> <span class="string_literal">"test"</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "test"</span>
60 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">1</span><span class="punctuation">,</span> name <span class="operator">=</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "2 1"</span>
61 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> a<span class="operator">=</span><span class="string_literal">"a"</span><span class="punctuation">,</span> b<span class="operator">=</span><span class="char_literal">'b'</span><span class="punctuation">,</span> c<span class="operator">=</span><span class="numeric_literal">3</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "a 3 b"</span>
62 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">}}"</span><span class="punctuation">,</span> <span class="numeric_literal">2</span><span class="punctuation">)</span><span class="punctuation">;</span> <span class="comment">// =&gt; "{2}"</span>
63 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
64 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span>
65 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
66 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> width <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span>
67 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
68 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
69 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
70 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">)</span><span class="punctuation">;</span>
71 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span>
72 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span>
73 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span>
74 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="punctuation">-</span><span class="numeric_literal">5</span><span class="punctuation">)</span><span class="punctuation">;</span>
75 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="numeric_literal">27</span><span class="punctuation">)</span><span class="punctuation">;</span>
76 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
77 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
78 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
79 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
80 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
81 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> <span class="string_literal">"x"</span><span class="punctuation">,</span> prec <span class="operator">=</span> <span class="numeric_literal">5</span><span class="punctuation">,</span> number <span class="operator">=</span> <span class="numeric_literal">0.01</span><span class="punctuation">)</span><span class="punctuation">;</span>
82 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="numeric_literal">1234.56</span><span class="punctuation">)</span><span class="punctuation">;</span>
83 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span>
84 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span><span class="punctuation">,</span> <span class="string_literal">"Hello"</span><span class="punctuation">,</span> <span class="numeric_literal">3</span><span class="punctuation">,</span> name<span class="operator">=</span><span class="string_literal">"1234.56"</span><span class="punctuation">)</span><span class="punctuation">;</span>
85 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello {{}}"</span><span class="punctuation">)</span><span class="punctuation">;</span>
86 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"{{ Hello"</span><span class="punctuation">)</span><span class="punctuation">;</span>
87
88 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span><span class="punctuation">,</span> <span class="string_literal">"world"</span><span class="punctuation">)</span><span class="punctuation">;</span>
89
90 <span class="comment">// escape sequences</span>
91 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal">World"</span><span class="punctuation">)</span><span class="punctuation">;</span>
92 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal"> World"</span><span class="punctuation">)</span><span class="punctuation">;</span>
93
94 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> A <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span>
95 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span><span class="punctuation">,</span> ничоси <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span>
96<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html
index 6936e949f..b81b6f1c3 100644
--- a/crates/ra_ide/src/snapshots/highlight_unsafe.html
+++ b/crates/ra_ide/test_data/highlight_unsafe.html
@@ -24,30 +24,31 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
24.bool_literal { color: #BFE6EB; } 24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; } 25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; } 26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
27.variable { color: #DCDCCC; } 28.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; } 29.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; } 30.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; } 31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; } 32.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; } 33.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; } 34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
36</style> 37</style>
37<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span>() {} 38<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
38 39
39<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span>; 40<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span>
40 41
41<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> { 42<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span>
42 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span>(&<span class="self_keyword">self</span>) {} 43 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
43} 44<span class="punctuation">}</span>
44 45
45<span class="keyword">fn</span> <span class="function declaration">main</span>() { 46<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
46 <span class="keyword">let</span> <span class="variable declaration">x</span> = &<span class="numeric_literal">5</span> <span class="keyword">as</span> *<span class="keyword">const</span> <span class="builtin_type">usize</span>; 47 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span>
47 <span class="keyword unsafe">unsafe</span> { 48 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
48 <span class="function unsafe">unsafe_fn</span>(); 49 <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
49 <span class="struct">HasUnsafeFn</span>.<span class="function unsafe">unsafe_method</span>(); 50 <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
50 <span class="keyword">let</span> <span class="variable declaration">y</span> = <span class="operator unsafe">*</span>(<span class="variable">x</span>); 51 <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span>
51 <span class="keyword">let</span> <span class="variable declaration">z</span> = -<span class="variable">x</span>; 52 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span>
52 } 53 <span class="punctuation">}</span>
53}</code></pre> \ No newline at end of file 54<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/test_data/highlighting.html b/crates/ra_ide/test_data/highlighting.html
new file mode 100644
index 000000000..345a2f023
--- /dev/null
+++ b/crates/ra_ide/test_data/highlighting.html
@@ -0,0 +1,128 @@
1
2<style>
3body { margin: 0; }
4pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5
6.lifetime { color: #DFAF8F; font-style: italic; }
7.comment { color: #7F9F7F; }
8.documentation { color: #629755; }
9.injected { opacity: 0.65 ; }
10.struct, .enum { color: #7CB8BB; }
11.enum_variant { color: #BDE0F3; }
12.string_literal { color: #CC9393; }
13.field { color: #94BFF3; }
14.function { color: #93E0E3; }
15.function.unsafe { color: #BC8383; }
16.operator.unsafe { color: #BC8383; }
17.parameter { color: #94BFF3; }
18.text { color: #DCDCCC; }
19.type { color: #7CB8BB; }
20.builtin_type { color: #8CD0D3; }
21.type_param { color: #DFAF8F; }
22.attribute { color: #94BFF3; }
23.numeric_literal { color: #BFEBBF; }
24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
28.variable { color: #DCDCCC; }
29.format_specifier { color: #CC696B; }
30.mutable { text-decoration: underline; }
31.escape_sequence { color: #94BFF3; }
32.keyword { color: #F0DFAF; font-weight: bold; }
33.keyword.unsafe { color: #BC8383; font-weight: bold; }
34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
37</style>
38<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="function attribute">derive</span><span class="punctuation">(</span><span class="attribute">Clone</span><span class="punctuation">,</span><span class="attribute"> Debug</span><span class="punctuation">)</span><span class="attribute">]</span>
39<span class="keyword">struct</span> <span class="struct declaration">Foo</span> <span class="punctuation">{</span>
40 <span class="keyword">pub</span> <span class="field declaration">x</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span>
41 <span class="keyword">pub</span> <span class="field declaration">y</span><span class="punctuation">:</span> <span class="builtin_type">i32</span><span class="punctuation">,</span>
42<span class="punctuation">}</span>
43
44<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="punctuation">{</span>
45 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="punctuation">;</span>
46<span class="punctuation">}</span>
47
48<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
49 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span>
50 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
51 <span class="punctuation">}</span>
52<span class="punctuation">}</span>
53
54<span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span>
55 <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="punctuation">{</span>
56 <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span>
57 <span class="punctuation">}</span>
58
59 <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span>
60 <span class="self_keyword mutable">self</span><span class="punctuation">.</span><span class="field">x</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
61 <span class="punctuation">}</span>
62<span class="punctuation">}</span>
63
64<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span>
65
66<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">&lt;</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="type_param">T</span> <span class="punctuation">{</span>
67 <span class="function">foo</span><span class="operator">::</span><span class="punctuation">&lt;</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span>
68<span class="punctuation">}</span>
69
70<span class="macro">macro_rules!</span> <span class="macro declaration">def_fn</span> <span class="punctuation">{</span>
71 <span class="punctuation">(</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">:</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span><span class="punctuation">$</span><span class="punctuation">(</span><span class="punctuation">$</span>tt<span class="punctuation">)</span><span class="punctuation">*</span><span class="punctuation">}</span>
72<span class="punctuation">}</span>
73
74<span class="macro">def_fn!</span> <span class="punctuation">{</span>
75 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-</span><span class="operator">&gt;</span> <span class="builtin_type">u32</span> <span class="punctuation">{</span>
76 <span class="numeric_literal">100</span>
77 <span class="punctuation">}</span>
78<span class="punctuation">}</span>
79
80<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> <span class="punctuation">{</span>
81 <span class="punctuation">(</span><span class="punctuation">$</span>expr<span class="punctuation">:</span>expr<span class="punctuation">)</span> <span class="operator">=</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
82 <span class="punctuation">$</span>expr
83 <span class="punctuation">}</span>
84<span class="punctuation">}</span>
85
86<span class="comment">// comment</span>
87<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
88 <span class="macro">println!</span><span class="punctuation">(</span><span class="string_literal">"Hello, {}!"</span><span class="punctuation">,</span> <span class="numeric_literal">92</span><span class="punctuation">)</span><span class="punctuation">;</span>
89
90 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">vec</span> <span class="operator">=</span> <span class="unresolved_reference">Vec</span><span class="operator">::</span><span class="unresolved_reference">new</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
91 <span class="keyword control">if</span> <span class="bool_literal">true</span> <span class="punctuation">{</span>
92 <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="numeric_literal">92</span><span class="punctuation">;</span>
93 <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">push</span><span class="punctuation">(</span><span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="numeric_literal">1</span> <span class="punctuation">}</span><span class="punctuation">)</span><span class="punctuation">;</span>
94 <span class="punctuation">}</span>
95 <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span>
96 <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span>
97 <span class="static mutable">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span>
98 <span class="punctuation">}</span>
99
100 <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span>
101 <span class="comment">// Do nothing</span>
102 <span class="punctuation">}</span>
103
104 <span class="macro">noop!</span><span class="punctuation">(</span><span class="macro">noop</span><span class="macro">!</span><span class="punctuation">(</span><span class="numeric_literal">1</span><span class="punctuation">)</span><span class="punctuation">)</span><span class="punctuation">;</span>
105
106 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">x</span> <span class="operator">=</span> <span class="numeric_literal">42</span><span class="punctuation">;</span>
107 <span class="keyword">let</span> <span class="variable declaration mutable">y</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">mut</span> <span class="variable mutable">x</span><span class="punctuation">;</span>
108 <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="operator">&</span><span class="variable mutable">y</span><span class="punctuation">;</span>
109
110 <span class="keyword">let</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable declaration">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">:</span> <span class="variable">z</span><span class="punctuation">,</span> <span class="field">y</span> <span class="punctuation">}</span><span class="punctuation">;</span>
111
112 <span class="variable">y</span><span class="punctuation">;</span>
113<span class="punctuation">}</span>
114
115<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
116 <span class="enum_variant declaration">Some</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">)</span><span class="punctuation">,</span>
117 <span class="enum_variant declaration">None</span><span class="punctuation">,</span>
118<span class="punctuation">}</span>
119<span class="keyword">use</span> <span class="enum">Option</span><span class="operator">::</span><span class="punctuation">*</span><span class="punctuation">;</span>
120
121<span class="keyword">impl</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
122 <span class="keyword">fn</span> <span class="function declaration">and</span><span class="punctuation">&lt;</span><span class="type_param declaration">U</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">other</span><span class="punctuation">:</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="type_param">U</span><span class="punctuation">&gt;</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="enum">Option</span><span class="punctuation">&lt;</span><span class="punctuation">(</span><span class="type_param">T</span><span class="punctuation">,</span> <span class="type_param">U</span><span class="punctuation">)</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
123 <span class="keyword control">match</span> <span class="value_param">other</span> <span class="punctuation">{</span>
124 <span class="enum_variant">None</span> <span class="operator">=&gt;</span> <span class="macro">unimplemented!</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span>
125 <span class="variable declaration">Nope</span> <span class="operator">=&gt;</span> <span class="variable">Nope</span><span class="punctuation">,</span>
126 <span class="punctuation">}</span>
127 <span class="punctuation">}</span>
128<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/test_data/rainbow_highlighting.html
index 9516c7441..401e87a73 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/test_data/rainbow_highlighting.html
@@ -24,25 +24,26 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
24.bool_literal { color: #BFE6EB; } 24.bool_literal { color: #BFE6EB; }
25.macro { color: #94BFF3; } 25.macro { color: #94BFF3; }
26.module { color: #AFD8AF; } 26.module { color: #AFD8AF; }
27.value_param { color: #DCDCCC; }
27.variable { color: #DCDCCC; } 28.variable { color: #DCDCCC; }
28.format_specifier { color: #CC696B; } 29.format_specifier { color: #CC696B; }
29.mutable { text-decoration: underline; } 30.mutable { text-decoration: underline; }
30.unresolved_reference { color: #FC5555; }
31.escape_sequence { color: #94BFF3; } 31.escape_sequence { color: #94BFF3; }
32
33.keyword { color: #F0DFAF; font-weight: bold; } 32.keyword { color: #F0DFAF; font-weight: bold; }
34.keyword.unsafe { color: #BC8383; font-weight: bold; } 33.keyword.unsafe { color: #BC8383; font-weight: bold; }
35.control { font-style: italic; } 34.control { font-style: italic; }
35
36.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
36</style> 37</style>
37<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span>() { 38<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
38 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>; 39 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span>
39 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(17,51%,74%);">x</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.<span class="unresolved_reference">to_string</span>(); 40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="2705725358298919760" style="color: hsl(76,47%,83%);">x</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="punctuation">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
40 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(127,76%,66%);">y</span> = <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span>.<span class="unresolved_reference">to_string</span>(); 41 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="3365759661443752373" style="color: hsl(15,86%,51%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span><span class="punctuation">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
41 42
42 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span> = <span class="string_literal">"other color please!"</span>; 43 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="punctuation">;</span>
43 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(85,49%,84%);">y</span> = <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(19,74%,76%);">x</span>.<span class="unresolved_reference">to_string</span>(); 44 <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="6717528807933952652" style="color: hsl(90,74%,79%);">y</span> <span class="operator">=</span> <span class="variable" data-binding-hash="794745962933817518" style="color: hsl(127,71%,87%);">x</span><span class="punctuation">.</span><span class="unresolved_reference">to_string</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span>
44} 45<span class="punctuation">}</span>
45 46
46<span class="keyword">fn</span> <span class="function declaration">bar</span>() { 47<span class="keyword">fn</span> <span class="function declaration">bar</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
47 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(261,57%,61%);">hello</span> = <span class="string_literal">"hello"</span>; 48 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="punctuation">;</span>
48}</code></pre> \ No newline at end of file 49<span class="punctuation">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml
index b14206c9b..f345f1de8 100644
--- a/crates/ra_ide_db/Cargo.toml
+++ b/crates/ra_ide_db/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_ide_db" 3name = "ra_ide_db"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -15,10 +16,11 @@ log = "0.4.8"
15rayon = "1.3.0" 16rayon = "1.3.0"
16fst = { version = "0.4", default-features = false } 17fst = { version = "0.4", default-features = false }
17rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
18superslice = "1.0.0"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
20either = "1.5.3" 20either = "1.5.3"
21 21
22stdx = { path = "../stdx" }
23
22ra_syntax = { path = "../ra_syntax" } 24ra_syntax = { path = "../ra_syntax" }
23ra_text_edit = { path = "../ra_text_edit" } 25ra_text_edit = { path = "../ra_text_edit" }
24ra_db = { path = "../ra_db" } 26ra_db = { path = "../ra_db" }
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index b507000f2..32d9a8d1f 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -5,8 +5,7 @@ use std::{fmt, sync::Arc, time};
5 5
6use ra_db::{ 6use ra_db::{
7 salsa::{Database, Durability, SweepStrategy}, 7 salsa::{Database, Durability, SweepStrategy},
8 CrateGraph, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, 8 CrateGraph, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
9 SourceRootId,
10}; 9};
11use ra_prof::{memory_usage, profile, Bytes}; 10use ra_prof::{memory_usage, profile, Bytes};
12use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
@@ -57,14 +56,14 @@ impl AnalysisChange {
57#[derive(Debug)] 56#[derive(Debug)]
58struct AddFile { 57struct AddFile {
59 file_id: FileId, 58 file_id: FileId,
60 path: RelativePathBuf, 59 path: String,
61 text: Arc<String>, 60 text: Arc<String>,
62} 61}
63 62
64#[derive(Debug)] 63#[derive(Debug)]
65struct RemoveFile { 64struct RemoveFile {
66 file_id: FileId, 65 file_id: FileId,
67 path: RelativePathBuf, 66 path: String,
68} 67}
69 68
70#[derive(Default)] 69#[derive(Default)]
@@ -147,37 +146,46 @@ impl RootDatabase {
147 146
148 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 147 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
149 148
150 self.query(ra_db::ParseQuery).sweep(sweep); 149 ra_db::ParseQuery.in_db(self).sweep(sweep);
151 self.query(hir::db::ParseMacroQuery).sweep(sweep); 150 hir::db::ParseMacroQuery.in_db(self).sweep(sweep);
152 151
153 // Macros do take significant space, but less then the syntax trees 152 // Macros do take significant space, but less then the syntax trees
154 // self.query(hir::db::MacroDefQuery).sweep(sweep); 153 // self.query(hir::db::MacroDefQuery).sweep(sweep);
155 // self.query(hir::db::MacroArgQuery).sweep(sweep); 154 // self.query(hir::db::MacroArgTextQuery).sweep(sweep);
156 // self.query(hir::db::MacroExpandQuery).sweep(sweep); 155 // self.query(hir::db::MacroExpandQuery).sweep(sweep);
157 156
158 self.query(hir::db::AstIdMapQuery).sweep(sweep); 157 hir::db::AstIdMapQuery.in_db(self).sweep(sweep);
159 158
160 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 159 hir::db::BodyWithSourceMapQuery.in_db(self).sweep(sweep);
161 160
162 self.query(hir::db::ExprScopesQuery).sweep(sweep); 161 hir::db::ExprScopesQuery.in_db(self).sweep(sweep);
163 self.query(hir::db::InferQueryQuery).sweep(sweep); 162 hir::db::InferQueryQuery.in_db(self).sweep(sweep);
164 self.query(hir::db::BodyQuery).sweep(sweep); 163 hir::db::BodyQuery.in_db(self).sweep(sweep);
165 } 164 }
166 165
166 // Feature: Memory Usage
167 //
168 // Clears rust-analyzer's internal database and prints memory usage statistics.
169 //
170 // |===
171 // | Editor | Action Name
172 //
173 // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
174 // |===
167 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { 175 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
168 let mut acc: Vec<(String, Bytes)> = vec![]; 176 let mut acc: Vec<(String, Bytes)> = vec![];
169 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 177 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
170 macro_rules! sweep_each_query { 178 macro_rules! sweep_each_query {
171 ($($q:path)*) => {$( 179 ($($q:path)*) => {$(
172 let before = memory_usage().allocated; 180 let before = memory_usage().allocated;
173 self.query($q).sweep(sweep); 181 $q.in_db(self).sweep(sweep);
174 let after = memory_usage().allocated; 182 let after = memory_usage().allocated;
175 let q: $q = Default::default(); 183 let q: $q = Default::default();
176 let name = format!("{:?}", q); 184 let name = format!("{:?}", q);
177 acc.push((name, before - after)); 185 acc.push((name, before - after));
178 186
179 let before = memory_usage().allocated; 187 let before = memory_usage().allocated;
180 self.query($q).sweep(sweep.discard_everything()); 188 $q.in_db(self).sweep(sweep.discard_everything());
181 let after = memory_usage().allocated; 189 let after = memory_usage().allocated;
182 let q: $q = Default::default(); 190 let q: $q = Default::default();
183 let name = format!("{:?} (deps)", q); 191 let name = format!("{:?} (deps)", q);
@@ -191,12 +199,10 @@ impl RootDatabase {
191 199
192 // AstDatabase 200 // AstDatabase
193 hir::db::AstIdMapQuery 201 hir::db::AstIdMapQuery
194 hir::db::InternMacroQuery 202 hir::db::MacroArgTextQuery
195 hir::db::MacroArgQuery
196 hir::db::MacroDefQuery 203 hir::db::MacroDefQuery
197 hir::db::ParseMacroQuery 204 hir::db::ParseMacroQuery
198 hir::db::MacroExpandQuery 205 hir::db::MacroExpandQuery
199 hir::db::InternEagerExpansionQuery
200 206
201 // DefDatabase 207 // DefDatabase
202 hir::db::ItemTreeQuery 208 hir::db::ItemTreeQuery
@@ -221,17 +227,6 @@ impl RootDatabase {
221 hir::db::DocumentationQuery 227 hir::db::DocumentationQuery
222 hir::db::ImportMapQuery 228 hir::db::ImportMapQuery
223 229
224 // InternDatabase
225 hir::db::InternFunctionQuery
226 hir::db::InternStructQuery
227 hir::db::InternUnionQuery
228 hir::db::InternEnumQuery
229 hir::db::InternConstQuery
230 hir::db::InternStaticQuery
231 hir::db::InternTraitQuery
232 hir::db::InternTypeAliasQuery
233 hir::db::InternImplQuery
234
235 // HirDatabase 230 // HirDatabase
236 hir::db::InferQueryQuery 231 hir::db::InferQueryQuery
237 hir::db::TyQuery 232 hir::db::TyQuery
@@ -243,12 +238,9 @@ impl RootDatabase {
243 hir::db::GenericPredicatesForParamQuery 238 hir::db::GenericPredicatesForParamQuery
244 hir::db::GenericPredicatesQuery 239 hir::db::GenericPredicatesQuery
245 hir::db::GenericDefaultsQuery 240 hir::db::GenericDefaultsQuery
246 hir::db::ImplsInCrateQuery 241 hir::db::InherentImplsInCrateQuery
247 hir::db::ImplsFromDepsQuery 242 hir::db::TraitImplsInCrateQuery
248 hir::db::InternTypeCtorQuery 243 hir::db::TraitImplsInDepsQuery
249 hir::db::InternTypeParamIdQuery
250 hir::db::InternChalkImplQuery
251 hir::db::InternAssocTyValueQuery
252 hir::db::AssociatedTyDataQuery 244 hir::db::AssociatedTyDataQuery
253 hir::db::TraitDatumQuery 245 hir::db::TraitDatumQuery
254 hir::db::StructDatumQuery 246 hir::db::StructDatumQuery
@@ -263,6 +255,33 @@ impl RootDatabase {
263 // LineIndexDatabase 255 // LineIndexDatabase
264 crate::LineIndexQuery 256 crate::LineIndexQuery
265 ]; 257 ];
258
259 // To collect interned data, we need to bump the revision counter by performing a synthetic
260 // write.
261 // We do this after collecting the non-interned queries to correctly attribute memory used
262 // by interned data.
263 self.salsa_runtime_mut().synthetic_write(Durability::HIGH);
264
265 sweep_each_query![
266 // AstDatabase
267 hir::db::InternMacroQuery
268 hir::db::InternEagerExpansionQuery
269
270 // InternDatabase
271 hir::db::InternFunctionQuery
272 hir::db::InternStructQuery
273 hir::db::InternUnionQuery
274 hir::db::InternEnumQuery
275 hir::db::InternConstQuery
276 hir::db::InternStaticQuery
277 hir::db::InternTraitQuery
278 hir::db::InternTypeAliasQuery
279 hir::db::InternImplQuery
280
281 // HirDatabase
282 hir::db::InternTypeParamIdQuery
283 ];
284
266 acc.sort_by_key(|it| std::cmp::Reverse(it.1)); 285 acc.sort_by_key(|it| std::cmp::Reverse(it.1));
267 acc 286 acc
268 } 287 }
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index bc6e89cbc..80c99935d 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -136,7 +136,7 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
136 136
137 match_ast! { 137 match_ast! {
138 match parent { 138 match parent {
139 ast::Alias(it) => { 139 ast::Rename(it) => {
140 let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; 140 let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?;
141 let path = use_tree.path()?; 141 let path = use_tree.path()?;
142 let path_segment = path.segment()?; 142 let path_segment = path.segment()?;
@@ -159,7 +159,7 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
159 159
160 Some(NameClass::Definition(Definition::Local(local))) 160 Some(NameClass::Definition(Definition::Local(local)))
161 }, 161 },
162 ast::RecordFieldDef(it) => { 162 ast::RecordField(it) => {
163 let field: hir::Field = sema.to_def(&it)?; 163 let field: hir::Field = sema.to_def(&it)?;
164 Some(NameClass::Definition(Definition::Field(field))) 164 Some(NameClass::Definition(Definition::Field(field)))
165 }, 165 },
@@ -167,39 +167,39 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
167 let def = sema.to_def(&it)?; 167 let def = sema.to_def(&it)?;
168 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 168 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
169 }, 169 },
170 ast::StructDef(it) => { 170 ast::Struct(it) => {
171 let def: hir::Struct = sema.to_def(&it)?; 171 let def: hir::Struct = sema.to_def(&it)?;
172 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 172 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
173 }, 173 },
174 ast::UnionDef(it) => { 174 ast::Union(it) => {
175 let def: hir::Union = sema.to_def(&it)?; 175 let def: hir::Union = sema.to_def(&it)?;
176 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 176 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
177 }, 177 },
178 ast::EnumDef(it) => { 178 ast::Enum(it) => {
179 let def: hir::Enum = sema.to_def(&it)?; 179 let def: hir::Enum = sema.to_def(&it)?;
180 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 180 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
181 }, 181 },
182 ast::TraitDef(it) => { 182 ast::Trait(it) => {
183 let def: hir::Trait = sema.to_def(&it)?; 183 let def: hir::Trait = sema.to_def(&it)?;
184 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 184 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
185 }, 185 },
186 ast::StaticDef(it) => { 186 ast::Static(it) => {
187 let def: hir::Static = sema.to_def(&it)?; 187 let def: hir::Static = sema.to_def(&it)?;
188 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 188 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
189 }, 189 },
190 ast::EnumVariant(it) => { 190 ast::Variant(it) => {
191 let def: hir::EnumVariant = sema.to_def(&it)?; 191 let def: hir::EnumVariant = sema.to_def(&it)?;
192 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 192 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
193 }, 193 },
194 ast::FnDef(it) => { 194 ast::Fn(it) => {
195 let def: hir::Function = sema.to_def(&it)?; 195 let def: hir::Function = sema.to_def(&it)?;
196 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 196 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
197 }, 197 },
198 ast::ConstDef(it) => { 198 ast::Const(it) => {
199 let def: hir::Const = sema.to_def(&it)?; 199 let def: hir::Const = sema.to_def(&it)?;
200 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 200 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
201 }, 201 },
202 ast::TypeAliasDef(it) => { 202 ast::TypeAlias(it) => {
203 let def: hir::TypeAlias = sema.to_def(&it)?; 203 let def: hir::TypeAlias = sema.to_def(&it)?;
204 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 204 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
205 }, 205 },
@@ -253,7 +253,7 @@ pub fn classify_name_ref(
253 } 253 }
254 } 254 }
255 255
256 if let Some(record_field) = ast::RecordField::for_field_name(name_ref) { 256 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
257 if let Some((field, local)) = sema.resolve_record_field(&record_field) { 257 if let Some((field, local)) = sema.resolve_record_field(&record_field) {
258 let field = Definition::Field(field); 258 let field = Definition::Field(field);
259 let res = match local { 259 let res = match local {
@@ -271,28 +271,61 @@ pub fn classify_name_ref(
271 } 271 }
272 } 272 }
273 273
274 if ast::AssocTypeArg::cast(parent.clone()).is_some() {
275 // `Trait<Assoc = Ty>`
276 // ^^^^^
277 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
278 let resolved = sema.resolve_path(&path)?;
279 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
280 if let Some(ty) = tr
281 .items(sema.db)
282 .iter()
283 .filter_map(|assoc| match assoc {
284 hir::AssocItem::TypeAlias(it) => Some(*it),
285 _ => None,
286 })
287 .find(|alias| alias.name(sema.db).to_string() == **name_ref.text())
288 {
289 return Some(NameRefClass::Definition(Definition::ModuleDef(
290 ModuleDef::TypeAlias(ty),
291 )));
292 }
293 }
294 }
295
274 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 296 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
275 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) { 297 if let Some(path) = macro_call.path() {
276 return Some(NameRefClass::Definition(Definition::Macro(macro_def))); 298 if path.qualifier().is_none() {
299 // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment
300 // paths are handled below (allowing `log<|>::info!` to resolve to the log crate).
301 if let Some(macro_def) = sema.resolve_macro_call(&macro_call) {
302 return Some(NameRefClass::Definition(Definition::Macro(macro_def)));
303 }
304 }
277 } 305 }
278 } 306 }
279 307
280 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; 308 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
281 let resolved = sema.resolve_path(&path)?; 309 let resolved = sema.resolve_path(&path)?;
282 let res = match resolved { 310 Some(NameRefClass::Definition(resolved.into()))
283 PathResolution::Def(def) => Definition::ModuleDef(def), 311}
284 PathResolution::AssocItem(item) => { 312
285 let def = match item { 313impl From<PathResolution> for Definition {
286 hir::AssocItem::Function(it) => it.into(), 314 fn from(path_resolution: PathResolution) -> Self {
287 hir::AssocItem::Const(it) => it.into(), 315 match path_resolution {
288 hir::AssocItem::TypeAlias(it) => it.into(), 316 PathResolution::Def(def) => Definition::ModuleDef(def),
289 }; 317 PathResolution::AssocItem(item) => {
290 Definition::ModuleDef(def) 318 let def = match item {
319 hir::AssocItem::Function(it) => it.into(),
320 hir::AssocItem::Const(it) => it.into(),
321 hir::AssocItem::TypeAlias(it) => it.into(),
322 };
323 Definition::ModuleDef(def)
324 }
325 PathResolution::Local(local) => Definition::Local(local),
326 PathResolution::TypeParam(par) => Definition::TypeParam(par),
327 PathResolution::Macro(def) => Definition::Macro(def),
328 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
291 } 329 }
292 PathResolution::Local(local) => Definition::Local(local), 330 }
293 PathResolution::TypeParam(par) => Definition::TypeParam(par),
294 PathResolution::Macro(def) => Definition::Macro(def),
295 PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
296 };
297 Some(NameRefClass::Definition(res))
298} 331}
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index fff112e66..1fba71ff8 100644
--- a/crates/ra_ide_db/src/imports_locator.rs
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -13,57 +13,53 @@ use crate::{
13use either::Either; 13use either::Either;
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15 15
16pub struct ImportsLocator<'a> { 16pub fn find_imports<'a>(
17 sema: Semantics<'a, RootDatabase>, 17 sema: &Semantics<'a, RootDatabase>,
18 krate: Crate, 18 krate: Crate,
19} 19 name_to_import: &str,
20 20) -> Vec<Either<ModuleDef, MacroDef>> {
21impl<'a> ImportsLocator<'a> { 21 let _p = profile("search_for_imports");
22 pub fn new(db: &'a RootDatabase, krate: Crate) -> Self { 22 let db = sema.db;
23 Self { sema: Semantics::new(db), krate }
24 }
25 23
26 pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { 24 // Query dependencies first.
27 let _p = profile("search_for_imports"); 25 let mut candidates: FxHashSet<_> =
28 let db = self.sema.db; 26 krate.query_external_importables(db, name_to_import).collect();
29 27
30 // Query dependencies first. 28 // Query the local crate using the symbol index.
31 let mut candidates: FxHashSet<_> = 29 let local_results = {
32 self.krate.query_external_importables(db, name_to_import).collect(); 30 let mut query = Query::new(name_to_import.to_string());
31 query.exact();
32 query.limit(40);
33 symbol_index::crate_symbols(db, krate.into(), query)
34 };
33 35
34 // Query the local crate using the symbol index. 36 candidates.extend(
35 let local_results = { 37 local_results
36 let mut query = Query::new(name_to_import.to_string()); 38 .into_iter()
37 query.exact(); 39 .filter_map(|import_candidate| get_name_definition(sema, &import_candidate))
38 query.limit(40); 40 .filter_map(|name_definition_to_import| match name_definition_to_import {
39 symbol_index::crate_symbols(db, self.krate.into(), query) 41 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
40 }; 42 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
43 _ => None,
44 }),
45 );
41 46
42 candidates.extend( 47 candidates.into_iter().collect()
43 local_results 48}
44 .into_iter()
45 .filter_map(|import_candidate| self.get_name_definition(&import_candidate))
46 .filter_map(|name_definition_to_import| match name_definition_to_import {
47 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
48 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
49 _ => None,
50 }),
51 );
52
53 candidates.into_iter().collect()
54 }
55 49
56 fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { 50fn get_name_definition<'a>(
57 let _p = profile("get_name_definition"); 51 sema: &Semantics<'a, RootDatabase>,
58 let file_id = import_candidate.file_id; 52 import_candidate: &FileSymbol,
53) -> Option<Definition> {
54 let _p = profile("get_name_definition");
55 let file_id = import_candidate.file_id;
59 56
60 let candidate_node = import_candidate.ptr.to_node(self.sema.parse(file_id).syntax()); 57 let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax());
61 let candidate_name_node = if candidate_node.kind() != NAME { 58 let candidate_name_node = if candidate_node.kind() != NAME {
62 candidate_node.children().find(|it| it.kind() == NAME)? 59 candidate_node.children().find(|it| it.kind() == NAME)?
63 } else { 60 } else {
64 candidate_node 61 candidate_node
65 }; 62 };
66 let name = ast::Name::cast(candidate_name_node)?; 63 let name = ast::Name::cast(candidate_name_node)?;
67 classify_name(&self.sema, &name)?.into_definition() 64 classify_name(sema, &name)?.into_definition()
68 }
69} 65}
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index a808de4f1..6900cac73 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -11,11 +11,11 @@ pub mod imports_locator;
11pub mod source_change; 11pub mod source_change;
12mod wasm_shims; 12mod wasm_shims;
13 13
14use std::sync::Arc; 14use std::{fmt, sync::Arc};
15 15
16use hir::db::{AstDatabase, DefDatabase}; 16use hir::db::{AstDatabase, DefDatabase, HirDatabase};
17use ra_db::{ 17use ra_db::{
18 salsa::{self, Database, Durability}, 18 salsa::{self, Durability},
19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, 19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
20 Upcast, 20 Upcast,
21}; 21};
@@ -33,13 +33,18 @@ use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
33 hir::db::DefDatabaseStorage, 33 hir::db::DefDatabaseStorage,
34 hir::db::HirDatabaseStorage 34 hir::db::HirDatabaseStorage
35)] 35)]
36#[derive(Debug)]
37pub struct RootDatabase { 36pub struct RootDatabase {
38 runtime: salsa::Runtime<RootDatabase>, 37 storage: salsa::Storage<RootDatabase>,
39 pub last_gc: crate::wasm_shims::Instant, 38 pub last_gc: crate::wasm_shims::Instant,
40 pub last_gc_check: crate::wasm_shims::Instant, 39 pub last_gc_check: crate::wasm_shims::Instant,
41} 40}
42 41
42impl fmt::Debug for RootDatabase {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.debug_struct("RootDatabase").finish()
45 }
46}
47
43impl Upcast<dyn AstDatabase> for RootDatabase { 48impl Upcast<dyn AstDatabase> for RootDatabase {
44 fn upcast(&self) -> &(dyn AstDatabase + 'static) { 49 fn upcast(&self) -> &(dyn AstDatabase + 'static) {
45 &*self 50 &*self
@@ -52,6 +57,12 @@ impl Upcast<dyn DefDatabase> for RootDatabase {
52 } 57 }
53} 58}
54 59
60impl Upcast<dyn HirDatabase> for RootDatabase {
61 fn upcast(&self) -> &(dyn HirDatabase + 'static) {
62 &*self
63 }
64}
65
55impl FileLoader for RootDatabase { 66impl FileLoader for RootDatabase {
56 fn file_text(&self, file_id: FileId) -> Arc<String> { 67 fn file_text(&self, file_id: FileId) -> Arc<String> {
57 FileLoaderDelegate(self).file_text(file_id) 68 FileLoaderDelegate(self).file_text(file_id)
@@ -65,17 +76,11 @@ impl FileLoader for RootDatabase {
65} 76}
66 77
67impl salsa::Database for RootDatabase { 78impl salsa::Database for RootDatabase {
68 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
69 &self.runtime
70 }
71 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
72 &mut self.runtime
73 }
74 fn on_propagated_panic(&self) -> ! { 79 fn on_propagated_panic(&self) -> ! {
75 Canceled::throw() 80 Canceled::throw()
76 } 81 }
77 fn salsa_event(&self, event: impl Fn() -> salsa::Event<RootDatabase>) { 82 fn salsa_event(&self, event: salsa::Event) {
78 match event().kind { 83 match event.kind {
79 salsa::EventKind::DidValidateMemoizedValue { .. } 84 salsa::EventKind::DidValidateMemoizedValue { .. }
80 | salsa::EventKind::WillExecute { .. } => { 85 | salsa::EventKind::WillExecute { .. } => {
81 self.check_canceled(); 86 self.check_canceled();
@@ -94,7 +99,7 @@ impl Default for RootDatabase {
94impl RootDatabase { 99impl RootDatabase {
95 pub fn new(lru_capacity: Option<usize>) -> RootDatabase { 100 pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
96 let mut db = RootDatabase { 101 let mut db = RootDatabase {
97 runtime: salsa::Runtime::default(), 102 storage: salsa::Storage::default(),
98 last_gc: crate::wasm_shims::Instant::now(), 103 last_gc: crate::wasm_shims::Instant::now(),
99 last_gc_check: crate::wasm_shims::Instant::now(), 104 last_gc_check: crate::wasm_shims::Instant::now(),
100 }; 105 };
@@ -107,16 +112,16 @@ impl RootDatabase {
107 112
108 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) { 113 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
109 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP); 114 let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP);
110 self.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity); 115 ra_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
111 self.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity); 116 hir::db::ParseMacroQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
112 self.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); 117 hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
113 } 118 }
114} 119}
115 120
116impl salsa::ParallelDatabase for RootDatabase { 121impl salsa::ParallelDatabase for RootDatabase {
117 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> { 122 fn snapshot(&self) -> salsa::Snapshot<RootDatabase> {
118 salsa::Snapshot::new(RootDatabase { 123 salsa::Snapshot::new(RootDatabase {
119 runtime: self.runtime.snapshot(self), 124 storage: self.storage.snapshot(),
120 last_gc: self.last_gc, 125 last_gc: self.last_gc,
121 last_gc_check: self.last_gc_check, 126 last_gc_check: self.last_gc_check,
122 }) 127 })
@@ -128,7 +133,7 @@ pub trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
128 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>; 133 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
129} 134}
130 135
131fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> { 136fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
132 let text = db.file_text(file_id); 137 let text = db.file_text(file_id);
133 Arc::new(LineIndex::new(&*text)) 138 Arc::new(LineIndex::new(&*text))
134} 139}
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs
index c7c744fce..2ab662098 100644
--- a/crates/ra_ide_db/src/line_index.rs
+++ b/crates/ra_ide_db/src/line_index.rs
@@ -4,7 +4,7 @@ use std::iter;
4 4
5use ra_syntax::{TextRange, TextSize}; 5use ra_syntax::{TextRange, TextSize};
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use superslice::Ext; 7use stdx::partition_point;
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct LineIndex { 10pub struct LineIndex {
@@ -89,7 +89,7 @@ impl LineIndex {
89 } 89 }
90 90
91 pub fn line_col(&self, offset: TextSize) -> LineCol { 91 pub fn line_col(&self, offset: TextSize) -> LineCol {
92 let line = self.newlines.upper_bound(&offset) - 1; 92 let line = partition_point(&self.newlines, |&it| it <= offset) - 1;
93 let line_start_offset = self.newlines[line]; 93 let line_start_offset = self.newlines[line];
94 let col = offset - line_start_offset; 94 let col = offset - line_start_offset;
95 95
@@ -103,8 +103,8 @@ impl LineIndex {
103 } 103 }
104 104
105 pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { 105 pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
106 let lo = self.newlines.lower_bound(&range.start()); 106 let lo = partition_point(&self.newlines, |&it| it < range.start());
107 let hi = self.newlines.upper_bound(&range.end()); 107 let hi = partition_point(&self.newlines, |&it| it <= range.end());
108 let all = iter::once(range.start()) 108 let all = iter::once(range.start())
109 .chain(self.newlines[lo..hi].iter().copied()) 109 .chain(self.newlines[lo..hi].iter().copied())
110 .chain(iter::once(range.end())); 110 .chain(iter::once(range.end()));
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index 44d5c35e6..0b862b449 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -60,6 +60,10 @@ impl SearchScope {
60 SearchScope::new(std::iter::once((file, None)).collect()) 60 SearchScope::new(std::iter::once((file, None)).collect())
61 } 61 }
62 62
63 pub fn files(files: &[FileId]) -> SearchScope {
64 SearchScope::new(files.iter().map(|f| (*f, None)).collect())
65 }
66
63 pub fn intersection(&self, other: &SearchScope) -> SearchScope { 67 pub fn intersection(&self, other: &SearchScope) -> SearchScope {
64 let (mut small, mut large) = (&self.entries, &other.entries); 68 let (mut small, mut large) = (&self.entries, &other.entries);
65 if small.len() > large.len() { 69 if small.len() > large.len() {
@@ -180,20 +184,20 @@ impl Definition {
180 184
181 pub fn find_usages( 185 pub fn find_usages(
182 &self, 186 &self,
183 db: &RootDatabase, 187 sema: &Semantics<RootDatabase>,
184 search_scope: Option<SearchScope>, 188 search_scope: Option<SearchScope>,
185 ) -> Vec<Reference> { 189 ) -> Vec<Reference> {
186 let _p = profile("Definition::find_usages"); 190 let _p = profile("Definition::find_usages");
187 191
188 let search_scope = { 192 let search_scope = {
189 let base = self.search_scope(db); 193 let base = self.search_scope(sema.db);
190 match search_scope { 194 match search_scope {
191 None => base, 195 None => base,
192 Some(scope) => base.intersection(&scope), 196 Some(scope) => base.intersection(&scope),
193 } 197 }
194 }; 198 };
195 199
196 let name = match self.name(db) { 200 let name = match self.name(sema.db) {
197 None => return Vec::new(), 201 None => return Vec::new(),
198 Some(it) => it.to_string(), 202 Some(it) => it.to_string(),
199 }; 203 };
@@ -202,11 +206,10 @@ impl Definition {
202 let mut refs = vec![]; 206 let mut refs = vec![];
203 207
204 for (file_id, search_range) in search_scope { 208 for (file_id, search_range) in search_scope {
205 let text = db.file_text(file_id); 209 let text = sema.db.file_text(file_id);
206 let search_range = 210 let search_range =
207 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str()))); 211 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str())));
208 212
209 let sema = Semantics::new(db);
210 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); 213 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
211 214
212 for (idx, _) in text.match_indices(pat) { 215 for (idx, _) in text.match_indices(pat) {
@@ -222,9 +225,6 @@ impl Definition {
222 continue; 225 continue;
223 }; 226 };
224 227
225 // FIXME: reuse sb
226 // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098
227
228 match classify_name_ref(&sema, &name_ref) { 228 match classify_name_ref(&sema, &name_ref) {
229 Some(NameRefClass::Definition(def)) if &def == self => { 229 Some(NameRefClass::Definition(def)) if &def == self => {
230 let kind = if is_record_lit_name_ref(&name_ref) 230 let kind = if is_record_lit_name_ref(&name_ref)
@@ -315,7 +315,7 @@ fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool {
315 name_ref 315 name_ref
316 .syntax() 316 .syntax()
317 .ancestors() 317 .ancestors()
318 .find_map(ast::RecordLit::cast) 318 .find_map(ast::RecordExpr::cast)
319 .and_then(|l| l.path()) 319 .and_then(|l| l.path())
320 .and_then(|p| p.segment()) 320 .and_then(|p| p.segment())
321 .map(|p| p.name_ref().as_ref() == Some(name_ref)) 321 .map(|p| p.name_ref().as_ref() == Some(name_ref))
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs
index 0bbd3c3e5..abb83f421 100644
--- a/crates/ra_ide_db/src/source_change.rs
+++ b/crates/ra_ide_db/src/source_change.rs
@@ -6,7 +6,7 @@
6use ra_db::FileId; 6use ra_db::FileId;
7use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
8 8
9#[derive(Debug, Clone)] 9#[derive(Default, Debug, Clone)]
10pub struct SourceChange { 10pub struct SourceChange {
11 pub source_file_edits: Vec<SourceFileEdit>, 11 pub source_file_edits: Vec<SourceFileEdit>,
12 pub file_system_edits: Vec<FileSystemEdit>, 12 pub file_system_edits: Vec<FileSystemEdit>,
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index 5a09e7d1d..35a2c5be3 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -87,7 +87,7 @@ impl Query {
87} 87}
88 88
89#[salsa::query_group(SymbolsDatabaseStorage)] 89#[salsa::query_group(SymbolsDatabaseStorage)]
90pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDatabase { 90pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt {
91 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>; 91 fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
92 fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>; 92 fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
93 /// The set of "local" (that is, from the current workspace) roots. 93 /// The set of "local" (that is, from the current workspace) roots.
@@ -100,9 +100,7 @@ pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt + ParallelDa
100 fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>; 100 fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
101} 101}
102 102
103fn library_symbols( 103fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
104 db: &(impl SymbolsDatabase + ParallelDatabase),
105) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
106 let _p = profile("library_symbols"); 104 let _p = profile("library_symbols");
107 105
108 let roots = db.library_roots(); 106 let roots = db.library_roots();
@@ -123,7 +121,7 @@ fn library_symbols(
123 Arc::new(res) 121 Arc::new(res)
124} 122}
125 123
126fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 124fn file_symbols(db: &dyn SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
127 db.check_canceled(); 125 db.check_canceled();
128 let parse = db.parse(file_id); 126 let parse = db.parse(file_id);
129 127
@@ -346,7 +344,7 @@ impl Query {
346} 344}
347 345
348fn is_type(kind: SyntaxKind) -> bool { 346fn is_type(kind: SyntaxKind) -> bool {
349 matches!(kind, STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF) 347 matches!(kind, STRUCT | ENUM | TRAIT | TYPE_ALIAS)
350} 348}
351 349
352/// The actual data that is stored in the index. It should be as compact as 350/// The actual data that is stored in the index. It should be as compact as
@@ -399,14 +397,14 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
399 } 397 }
400 match_ast! { 398 match_ast! {
401 match node { 399 match node {
402 ast::FnDef(it) => decl(it), 400 ast::Fn(it) => decl(it),
403 ast::StructDef(it) => decl(it), 401 ast::Struct(it) => decl(it),
404 ast::EnumDef(it) => decl(it), 402 ast::Enum(it) => decl(it),
405 ast::TraitDef(it) => decl(it), 403 ast::Trait(it) => decl(it),
406 ast::Module(it) => decl(it), 404 ast::Module(it) => decl(it),
407 ast::TypeAliasDef(it) => decl(it), 405 ast::TypeAlias(it) => decl(it),
408 ast::ConstDef(it) => decl(it), 406 ast::Const(it) => decl(it),
409 ast::StaticDef(it) => decl(it), 407 ast::Static(it) => decl(it),
410 ast::MacroCall(it) => { 408 ast::MacroCall(it) => {
411 if it.is_macro_rules().is_some() { 409 if it.is_macro_rules().is_some() {
412 decl(it) 410 decl(it)
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index 4dec24914..a26746a19 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_mbe" 3name = "ra_mbe"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 9c450eaba..dec7ba22e 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -9,6 +9,9 @@ mod syntax_bridge;
9mod tt_iter; 9mod tt_iter;
10mod subtree_source; 10mod subtree_source;
11 11
12#[cfg(test)]
13mod tests;
14
12pub use tt::{Delimiter, Punct}; 15pub use tt::{Delimiter, Punct};
13 16
14use crate::{ 17use crate::{
@@ -273,6 +276,3 @@ impl<T: Default> From<Result<T, ExpandError>> for ExpandResult<T> {
273 .map_or_else(|e| ExpandResult(Default::default(), Some(e)), |it| ExpandResult(it, None)) 276 .map_or_else(|e| ExpandResult(Default::default(), Some(e)), |it| ExpandResult(it, None))
274 } 277 }
275} 278}
276
277#[cfg(test)]
278mod tests;
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 78f9efa1b..f9e515b81 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -260,7 +260,7 @@ impl<'a> TtIter<'a> {
260 | ('|', '=', None) 260 | ('|', '=', None)
261 | ('|', '|', None) => { 261 | ('|', '|', None) => {
262 let tt2 = self.next().unwrap().clone(); 262 let tt2 = self.next().unwrap().clone();
263 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt.clone(), tt2] }.into()) 263 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
264 } 264 }
265 _ => Ok(tt), 265 _ => Ok(tt),
266 } 266 }
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index fc4133a67..5fc48507f 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -825,7 +825,7 @@ mod tests {
825 #[test] 825 #[test]
826 fn test_token_tree_multi_char_punct() { 826 fn test_token_tree_multi_char_punct() {
827 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap(); 827 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap();
828 let struct_def = source_file.syntax().descendants().find_map(ast::StructDef::cast).unwrap(); 828 let struct_def = source_file.syntax().descendants().find_map(ast::Struct::cast).unwrap();
829 let tt = ast_to_token_tree(&struct_def).unwrap().0; 829 let tt = ast_to_token_tree(&struct_def).unwrap().0;
830 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap(); 830 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap();
831 } 831 }
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index c43003fd6..707e84f42 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -258,7 +258,7 @@ fn test_expr_order() {
258 assert_eq_text!( 258 assert_eq_text!(
259 dump.trim(), 259 dump.trim(),
260 r#"[email protected] 260 r#"[email protected]
261 FN_DEF@0..15 261 [email protected]
262 [email protected] "fn" 262 [email protected] "fn"
263 [email protected] 263 [email protected]
264 [email protected] "bar" 264 [email protected] "bar"
@@ -490,13 +490,13 @@ fn test_expand_to_item_list() {
490 format!("{:#?}", tree).trim(), 490 format!("{:#?}", tree).trim(),
491 r#" 491 r#"
492[email protected] 492[email protected]
493 STRUCT_DEF@0..20 493 [email protected]
494 [email protected] "struct" 494 [email protected] "struct"
495 [email protected] 495 [email protected]
496 [email protected] "Foo" 496 [email protected] "Foo"
497 RECORD_FIELD_DEF_[email protected] 497 [email protected]
498 [email protected] "{" 498 [email protected] "{"
499 RECORD_FIELD_DEF@10..19 499 [email protected]
500 [email protected] 500 [email protected]
501 [email protected] "field" 501 [email protected] "field"
502 [email protected] ":" 502 [email protected] ":"
@@ -506,13 +506,13 @@ [email protected]
506 [email protected] 506 [email protected]
507 [email protected] "u32" 507 [email protected] "u32"
508 [email protected] "}" 508 [email protected] "}"
509 STRUCT_DEF@20..40 509 [email protected]
510 [email protected] "struct" 510 [email protected] "struct"
511 [email protected] 511 [email protected]
512 [email protected] "Bar" 512 [email protected] "Bar"
513 RECORD_FIELD_DEF_[email protected] 513 [email protected]
514 [email protected] "{" 514 [email protected] "{"
515 RECORD_FIELD_DEF@30..39 515 [email protected]
516 [email protected] 516 [email protected]
517 [email protected] "field" 517 [email protected] "field"
518 [email protected] ":" 518 [email protected] ":"
@@ -1467,7 +1467,7 @@ macro_rules! quick_error {
1467 buf [ ] 1467 buf [ ]
1468 queue [ ] 1468 queue [ ]
1469 ) => { 1469 ) => {
1470 quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*] 1470 quick_error!(ENUMINITION [enum $name $( #[$meta] )*]
1471 body [] 1471 body []
1472 queue [$( 1472 queue [$(
1473 $( #[$imeta] )* 1473 $( #[$imeta] )*
@@ -1489,7 +1489,7 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1489"#, 1489"#,
1490 ); 1490 );
1491 1491
1492 assert_eq!(expanded.to_string(), "quick_error ! (ENUM_DEFINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;"); 1492 assert_eq!(expanded.to_string(), "quick_error ! (ENUMINITION [enum Wrapped # [derive (Debug)]] body [] queue [=> One : UNIT [] => Two : TUPLE [s : String]]) ;");
1493} 1493}
1494 1494
1495#[test] 1495#[test]
diff --git a/crates/ra_parser/Cargo.toml b/crates/ra_parser/Cargo.toml
index 0da581fd5..72ec3e4d9 100644
--- a/crates/ra_parser/Cargo.toml
+++ b/crates/ra_parser/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_parser"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index caedeead0..c2e1d701e 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -142,19 +142,19 @@ pub(crate) fn reparser(
142) -> Option<fn(&mut Parser)> { 142) -> Option<fn(&mut Parser)> {
143 let res = match node { 143 let res = match node {
144 BLOCK_EXPR => expressions::block_expr, 144 BLOCK_EXPR => expressions::block_expr,
145 RECORD_FIELD_DEF_LIST => items::record_field_def_list, 145 RECORD_FIELD_LIST => items::record_field_def_list,
146 RECORD_FIELD_LIST => items::record_field_list, 146 RECORD_EXPR_FIELD_LIST => items::record_field_list,
147 ENUM_VARIANT_LIST => items::enum_variant_list, 147 VARIANT_LIST => items::enum_variant_list,
148 MATCH_ARM_LIST => items::match_arm_list, 148 MATCH_ARM_LIST => items::match_arm_list,
149 USE_TREE_LIST => items::use_tree_list, 149 USE_TREE_LIST => items::use_tree_list,
150 EXTERN_ITEM_LIST => items::extern_item_list, 150 EXTERN_ITEM_LIST => items::extern_item_list,
151 TOKEN_TREE if first_child? == T!['{'] => items::token_tree, 151 TOKEN_TREE if first_child? == T!['{'] => items::token_tree,
152 ITEM_LIST => match parent? { 152 ASSOC_ITEM_LIST => match parent? {
153 IMPL_DEF => items::impl_item_list, 153 IMPL => items::impl_item_list,
154 TRAIT_DEF => items::trait_item_list, 154 TRAIT => items::trait_item_list,
155 MODULE => items::mod_item_list,
156 _ => return None, 155 _ => return None,
157 }, 156 },
157 ITEM_LIST => items::mod_item_list,
158 _ => return None, 158 _ => return None,
159 }; 159 };
160 Some(res) 160 Some(res)
@@ -224,7 +224,7 @@ fn opt_alias(p: &mut Parser) {
224 if !p.eat(T![_]) { 224 if !p.eat(T![_]) {
225 name(p); 225 name(p);
226 } 226 }
227 m.complete(p, ALIAS); 227 m.complete(p, RENAME);
228 } 228 }
229} 229}
230 230
@@ -270,10 +270,6 @@ fn name_ref(p: &mut Parser) {
270 let m = p.start(); 270 let m = p.start();
271 p.bump(IDENT); 271 p.bump(IDENT);
272 m.complete(p, NAME_REF); 272 m.complete(p, NAME_REF);
273 } else if p.at(T![self]) {
274 let m = p.start();
275 p.bump(T![self]);
276 m.complete(p, T![self]);
277 } else { 273 } else {
278 p.err_and_bump("expected identifier"); 274 p.err_and_bump("expected identifier");
279 } 275 }
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 6e72eea66..e1c25a838 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -587,7 +587,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
587 match p.current() { 587 match p.current() {
588 T!['{'] if !r.forbid_structs => { 588 T!['{'] if !r.forbid_structs => {
589 record_field_list(p); 589 record_field_list(p);
590 (m.complete(p, RECORD_LIT), BlockLike::NotBlock) 590 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
591 } 591 }
592 T![!] if !p.at(T![!=]) => { 592 T![!] if !p.at(T![!=]) => {
593 let block_like = items::macro_call_after_excl(p); 593 let block_like = items::macro_call_after_excl(p);
@@ -627,7 +627,7 @@ pub(crate) fn record_field_list(p: &mut Parser) {
627 p.expect(T![:]); 627 p.expect(T![:]);
628 } 628 }
629 expr(p); 629 expr(p);
630 m.complete(p, RECORD_FIELD); 630 m.complete(p, RECORD_EXPR_FIELD);
631 } 631 }
632 T![.] if p.at(T![..]) => { 632 T![.] if p.at(T![..]) => {
633 m.abandon(p); 633 m.abandon(p);
@@ -648,5 +648,5 @@ pub(crate) fn record_field_list(p: &mut Parser) {
648 } 648 }
649 } 649 }
650 p.expect(T!['}']); 650 p.expect(T!['}']);
651 m.complete(p, RECORD_FIELD_LIST); 651 m.complete(p, RECORD_EXPR_FIELD_LIST);
652} 652}
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 97642bc24..cca524cea 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -180,7 +180,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
180 // unsafe const fn bar() {} 180 // unsafe const fn bar() {}
181 T![fn] => { 181 T![fn] => {
182 fn_def(p); 182 fn_def(p);
183 m.complete(p, FN_DEF); 183 m.complete(p, FN);
184 } 184 }
185 185
186 // test unsafe_trait 186 // test unsafe_trait
@@ -193,7 +193,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
193 // unsafe auto trait T {} 193 // unsafe auto trait T {}
194 T![trait] => { 194 T![trait] => {
195 traits::trait_def(p); 195 traits::trait_def(p);
196 m.complete(p, TRAIT_DEF); 196 m.complete(p, TRAIT);
197 } 197 }
198 198
199 // test unsafe_impl 199 // test unsafe_impl
@@ -221,7 +221,7 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul
221 // unsafe default impl Foo {} 221 // unsafe default impl Foo {}
222 T![impl] => { 222 T![impl] => {
223 traits::impl_def(p); 223 traits::impl_def(p);
224 m.complete(p, IMPL_DEF); 224 m.complete(p, IMPL);
225 } 225 }
226 226
227 // test existential_type 227 // test existential_type
@@ -304,10 +304,16 @@ fn extern_crate_item(p: &mut Parser, m: Marker) {
304 p.bump(T![extern]); 304 p.bump(T![extern]);
305 assert!(p.at(T![crate])); 305 assert!(p.at(T![crate]));
306 p.bump(T![crate]); 306 p.bump(T![crate]);
307 name_ref(p); 307
308 if p.at(T![self]) {
309 p.bump(T![self]);
310 } else {
311 name_ref(p);
312 }
313
308 opt_alias(p); 314 opt_alias(p);
309 p.expect(T![;]); 315 p.expect(T![;]);
310 m.complete(p, EXTERN_CRATE_ITEM); 316 m.complete(p, EXTERN_CRATE);
311} 317}
312 318
313pub(crate) fn extern_item_list(p: &mut Parser) { 319pub(crate) fn extern_item_list(p: &mut Parser) {
@@ -374,7 +380,7 @@ fn type_def(p: &mut Parser, m: Marker) {
374 types::type_(p); 380 types::type_(p);
375 } 381 }
376 p.expect(T![;]); 382 p.expect(T![;]);
377 m.complete(p, TYPE_ALIAS_DEF); 383 m.complete(p, TYPE_ALIAS);
378} 384}
379 385
380pub(crate) fn mod_item(p: &mut Parser, m: Marker) { 386pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
diff --git a/crates/ra_parser/src/grammar/items/adt.rs b/crates/ra_parser/src/grammar/items/adt.rs
index 74b9f514b..addfb59d4 100644
--- a/crates/ra_parser/src/grammar/items/adt.rs
+++ b/crates/ra_parser/src/grammar/items/adt.rs
@@ -5,13 +5,13 @@ use super::*;
5pub(super) fn struct_def(p: &mut Parser, m: Marker) { 5pub(super) fn struct_def(p: &mut Parser, m: Marker) {
6 assert!(p.at(T![struct])); 6 assert!(p.at(T![struct]));
7 p.bump(T![struct]); 7 p.bump(T![struct]);
8 struct_or_union(p, m, T![struct], STRUCT_DEF); 8 struct_or_union(p, m, T![struct], STRUCT);
9} 9}
10 10
11pub(super) fn union_def(p: &mut Parser, m: Marker) { 11pub(super) fn union_def(p: &mut Parser, m: Marker) {
12 assert!(p.at_contextual_kw("union")); 12 assert!(p.at_contextual_kw("union"));
13 p.bump_remap(T![union]); 13 p.bump_remap(T![union]);
14 struct_or_union(p, m, T![union], UNION_DEF); 14 struct_or_union(p, m, T![union], UNION);
15} 15}
16 16
17fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { 17fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
@@ -64,7 +64,7 @@ pub(super) fn enum_def(p: &mut Parser, m: Marker) {
64 } else { 64 } else {
65 p.error("expected `{`") 65 p.error("expected `{`")
66 } 66 }
67 m.complete(p, ENUM_DEF); 67 m.complete(p, ENUM);
68} 68}
69 69
70pub(crate) fn enum_variant_list(p: &mut Parser) { 70pub(crate) fn enum_variant_list(p: &mut Parser) {
@@ -91,7 +91,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
91 if p.eat(T![=]) { 91 if p.eat(T![=]) {
92 expressions::expr(p); 92 expressions::expr(p);
93 } 93 }
94 var.complete(p, ENUM_VARIANT); 94 var.complete(p, VARIANT);
95 } else { 95 } else {
96 var.abandon(p); 96 var.abandon(p);
97 p.err_and_bump("expected enum variant"); 97 p.err_and_bump("expected enum variant");
@@ -101,7 +101,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
101 } 101 }
102 } 102 }
103 p.expect(T!['}']); 103 p.expect(T!['}']);
104 m.complete(p, ENUM_VARIANT_LIST); 104 m.complete(p, VARIANT_LIST);
105} 105}
106 106
107pub(crate) fn record_field_def_list(p: &mut Parser) { 107pub(crate) fn record_field_def_list(p: &mut Parser) {
@@ -119,7 +119,7 @@ pub(crate) fn record_field_def_list(p: &mut Parser) {
119 } 119 }
120 } 120 }
121 p.expect(T!['}']); 121 p.expect(T!['}']);
122 m.complete(p, RECORD_FIELD_DEF_LIST); 122 m.complete(p, RECORD_FIELD_LIST);
123 123
124 fn record_field_def(p: &mut Parser) { 124 fn record_field_def(p: &mut Parser) {
125 let m = p.start(); 125 let m = p.start();
@@ -134,7 +134,7 @@ pub(crate) fn record_field_def_list(p: &mut Parser) {
134 name(p); 134 name(p);
135 p.expect(T![:]); 135 p.expect(T![:]);
136 types::type_(p); 136 types::type_(p);
137 m.complete(p, RECORD_FIELD_DEF); 137 m.complete(p, RECORD_FIELD);
138 } else { 138 } else {
139 m.abandon(p); 139 m.abandon(p);
140 p.err_and_bump("expected field declaration"); 140 p.err_and_bump("expected field declaration");
@@ -167,12 +167,12 @@ fn tuple_field_def_list(p: &mut Parser) {
167 break; 167 break;
168 } 168 }
169 types::type_(p); 169 types::type_(p);
170 m.complete(p, TUPLE_FIELD_DEF); 170 m.complete(p, TUPLE_FIELD);
171 171
172 if !p.at(T![')']) { 172 if !p.at(T![')']) {
173 p.expect(T![,]); 173 p.expect(T![,]);
174 } 174 }
175 } 175 }
176 p.expect(T![')']); 176 p.expect(T![')']);
177 m.complete(p, TUPLE_FIELD_DEF_LIST); 177 m.complete(p, TUPLE_FIELD_LIST);
178} 178}
diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs
index 742a7e056..35ad766dc 100644
--- a/crates/ra_parser/src/grammar/items/consts.rs
+++ b/crates/ra_parser/src/grammar/items/consts.rs
@@ -3,11 +3,11 @@
3use super::*; 3use super::*;
4 4
5pub(super) fn static_def(p: &mut Parser, m: Marker) { 5pub(super) fn static_def(p: &mut Parser, m: Marker) {
6 const_or_static(p, m, T![static], STATIC_DEF) 6 const_or_static(p, m, T![static], STATIC)
7} 7}
8 8
9pub(super) fn const_def(p: &mut Parser, m: Marker) { 9pub(super) fn const_def(p: &mut Parser, m: Marker) {
10 const_or_static(p, m, T![const], CONST_DEF) 10 const_or_static(p, m, T![const], CONST)
11} 11}
12 12
13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { 13fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
index c819e33be..ef9c8ff5b 100644
--- a/crates/ra_parser/src/grammar/items/traits.rs
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -50,7 +50,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) {
50 item_or_macro(p, true, ItemFlavor::Trait); 50 item_or_macro(p, true, ItemFlavor::Trait);
51 } 51 }
52 p.expect(T!['}']); 52 p.expect(T!['}']);
53 m.complete(p, ITEM_LIST); 53 m.complete(p, ASSOC_ITEM_LIST);
54} 54}
55 55
56// test impl_def 56// test impl_def
@@ -107,7 +107,7 @@ pub(crate) fn impl_item_list(p: &mut Parser) {
107 item_or_macro(p, true, ItemFlavor::Mod); 107 item_or_macro(p, true, ItemFlavor::Mod);
108 } 108 }
109 p.expect(T!['}']); 109 p.expect(T!['}']);
110 m.complete(p, ITEM_LIST); 110 m.complete(p, ASSOC_ITEM_LIST);
111} 111}
112 112
113// test impl_type_params 113// test impl_type_params
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index 3a0c7a31a..8e836a77e 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -7,7 +7,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) {
7 p.bump(T![use]); 7 p.bump(T![use]);
8 use_tree(p, true); 8 use_tree(p, true);
9 p.expect(T![;]); 9 p.expect(T![;]);
10 m.complete(p, USE_ITEM); 10 m.complete(p, USE);
11} 11}
12 12
13/// Parse a use 'tree', such as `some::path` in `use some::path;` 13/// Parse a use 'tree', such as `some::path` in `use some::path;`
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index d1330d4b9..90dabb4c0 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -36,7 +36,7 @@ fn type_param_list(p: &mut Parser) {
36 } 36 }
37 } 37 }
38 p.expect(T![>]); 38 p.expect(T![>]);
39 m.complete(p, TYPE_PARAM_LIST); 39 m.complete(p, GENERIC_PARAM_LIST);
40} 40}
41 41
42fn lifetime_param(p: &mut Parser, m: Marker) { 42fn lifetime_param(p: &mut Parser, m: Marker) {
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index e7404492a..be4da67bc 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -1,7 +1,7 @@
1//! Generated file, do not edit by hand, see `xtask/src/codegen` 1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2 2
3#![allow(bad_style, missing_docs, unreachable_pub)] 3#![allow(bad_style, missing_docs, unreachable_pub)]
4#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`."] 4#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 5#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
6#[repr(u16)] 6#[repr(u16)]
7pub enum SyntaxKind { 7pub enum SyntaxKind {
@@ -123,19 +123,19 @@ pub enum SyntaxKind {
123 L_DOLLAR, 123 L_DOLLAR,
124 R_DOLLAR, 124 R_DOLLAR,
125 SOURCE_FILE, 125 SOURCE_FILE,
126 STRUCT_DEF, 126 STRUCT,
127 UNION_DEF, 127 UNION,
128 ENUM_DEF, 128 ENUM,
129 FN_DEF, 129 FN,
130 RET_TYPE, 130 RET_TYPE,
131 EXTERN_CRATE_ITEM, 131 EXTERN_CRATE,
132 MODULE, 132 MODULE,
133 USE_ITEM, 133 USE,
134 STATIC_DEF, 134 STATIC,
135 CONST_DEF, 135 CONST,
136 TRAIT_DEF, 136 TRAIT,
137 IMPL_DEF, 137 IMPL,
138 TYPE_ALIAS_DEF, 138 TYPE_ALIAS,
139 MACRO_CALL, 139 MACRO_CALL,
140 TOKEN_TREE, 140 TOKEN_TREE,
141 MACRO_DEF, 141 MACRO_DEF,
@@ -188,9 +188,9 @@ pub enum SyntaxKind {
188 MATCH_ARM_LIST, 188 MATCH_ARM_LIST,
189 MATCH_ARM, 189 MATCH_ARM,
190 MATCH_GUARD, 190 MATCH_GUARD,
191 RECORD_LIT, 191 RECORD_EXPR,
192 RECORD_FIELD_LIST, 192 RECORD_EXPR_FIELD_LIST,
193 RECORD_FIELD, 193 RECORD_EXPR_FIELD,
194 EFFECT_EXPR, 194 EFFECT_EXPR,
195 BOX_EXPR, 195 BOX_EXPR,
196 CALL_EXPR, 196 CALL_EXPR,
@@ -206,13 +206,14 @@ pub enum SyntaxKind {
206 BIN_EXPR, 206 BIN_EXPR,
207 EXTERN_BLOCK, 207 EXTERN_BLOCK,
208 EXTERN_ITEM_LIST, 208 EXTERN_ITEM_LIST,
209 ENUM_VARIANT, 209 VARIANT,
210 RECORD_FIELD_DEF_LIST, 210 RECORD_FIELD_LIST,
211 RECORD_FIELD_DEF, 211 RECORD_FIELD,
212 TUPLE_FIELD_DEF_LIST, 212 TUPLE_FIELD_LIST,
213 TUPLE_FIELD_DEF, 213 TUPLE_FIELD,
214 ENUM_VARIANT_LIST, 214 VARIANT_LIST,
215 ITEM_LIST, 215 ITEM_LIST,
216 ASSOC_ITEM_LIST,
216 ATTR, 217 ATTR,
217 META_ITEM, 218 META_ITEM,
218 USE_TREE, 219 USE_TREE,
@@ -220,7 +221,7 @@ pub enum SyntaxKind {
220 PATH, 221 PATH,
221 PATH_SEGMENT, 222 PATH_SEGMENT,
222 LITERAL, 223 LITERAL,
223 ALIAS, 224 RENAME,
224 VISIBILITY, 225 VISIBILITY,
225 WHERE_CLAUSE, 226 WHERE_CLAUSE,
226 WHERE_PRED, 227 WHERE_PRED,
@@ -229,7 +230,8 @@ pub enum SyntaxKind {
229 NAME_REF, 230 NAME_REF,
230 LET_STMT, 231 LET_STMT,
231 EXPR_STMT, 232 EXPR_STMT,
232 TYPE_PARAM_LIST, 233 GENERIC_PARAM_LIST,
234 GENERIC_PARAM,
233 LIFETIME_PARAM, 235 LIFETIME_PARAM,
234 TYPE_PARAM, 236 TYPE_PARAM,
235 CONST_PARAM, 237 CONST_PARAM,
@@ -362,4 +364,4 @@ impl SyntaxKind {
362 } 364 }
363} 365}
364#[macro_export] 366#[macro_export]
365macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; } 367macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; [ shebang ] => { $ crate :: SyntaxKind :: SHEBANG } ; }
diff --git a/crates/ra_proc_macro/Cargo.toml b/crates/ra_proc_macro/Cargo.toml
index d009ceb82..c4b6e9e7b 100644
--- a/crates/ra_proc_macro/Cargo.toml
+++ b/crates/ra_proc_macro/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_proc_macro"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml
index 582102945..bc119a6c7 100644
--- a/crates/ra_proc_macro_srv/Cargo.toml
+++ b/crates/ra_proc_macro_srv/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_proc_macro_srv"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
@@ -18,7 +19,7 @@ memmap = "0.7"
18test_utils = { path = "../test_utils" } 19test_utils = { path = "../test_utils" }
19 20
20[dev-dependencies] 21[dev-dependencies]
21cargo_metadata = "0.10.0" 22cargo_metadata = "0.11.1"
22difference = "2.0.0" 23difference = "2.0.0"
23# used as proc macro test target 24# used as proc macro test target
24serde_derive = "1.0.106" 25serde_derive = "1.0.106"
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs
index aa84e951c..1addbbd54 100644
--- a/crates/ra_proc_macro_srv/src/dylib.rs
+++ b/crates/ra_proc_macro_srv/src/dylib.rs
@@ -45,7 +45,7 @@ fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
45 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html 45 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html
46 // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be 46 // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be
47 // prepended with an underscore. 47 // prepended with an underscore.
48 if s.name.starts_with("_") { 48 if s.name.starts_with('_') {
49 &s.name[1..] 49 &s.name[1..]
50 } else { 50 } else {
51 &s.name 51 &s.name
diff --git a/crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs b/crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs
index 4b5dc7fd0..cb4b3bdb0 100644
--- a/crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs
+++ b/crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs
@@ -18,7 +18,7 @@ macro_rules! define_handles {
18 } 18 }
19 19
20 impl HandleCounters { 20 impl HandleCounters {
21 // FIXME(eddyb) use a reference to the `static COUNTERS`, intead of 21 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
22 // a wrapper `fn` pointer, once `const fn` can reference `static`s. 22 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
23 extern "C" fn get() -> &'static Self { 23 extern "C" fn get() -> &'static Self {
24 static COUNTERS: HandleCounters = HandleCounters { 24 static COUNTERS: HandleCounters = HandleCounters {
@@ -205,10 +205,16 @@ impl Clone for Literal {
205 } 205 }
206} 206}
207 207
208// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
209impl fmt::Debug for Literal { 208impl fmt::Debug for Literal {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 f.write_str(&self.debug()) 210 f.debug_struct("Literal")
211 // format the kind without quotes, as in `kind: Float`
212 // .field("kind", &format_args!("{}", &self.debug_kind()))
213 .field("symbol", &self.symbol())
214 // format `Some("...")` on one line even in {:#?} mode
215 // .field("suffix", &format_args!("{:?}", &self.suffix()))
216 .field("span", &self.span())
217 .finish()
212 } 218 }
213} 219}
214 220
@@ -339,7 +345,7 @@ impl Bridge<'_> {
339#[repr(C)] 345#[repr(C)]
340#[derive(Copy, Clone)] 346#[derive(Copy, Clone)]
341pub struct Client<F> { 347pub struct Client<F> {
342 // FIXME(eddyb) use a reference to the `static COUNTERS`, intead of 348 // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of
343 // a wrapper `fn` pointer, once `const fn` can reference `static`s. 349 // a wrapper `fn` pointer, once `const fn` can reference `static`s.
344 pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, 350 pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
345 pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>, 351 pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>,
diff --git a/crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs b/crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs
index b8addff4a..273a97715 100644
--- a/crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs
+++ b/crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs
@@ -11,6 +11,9 @@ pub struct Closure<'a, A, R> {
11 11
12struct Env; 12struct Env;
13 13
14// impl<'a, A, R> !Sync for Closure<'a, A, R> {}
15// impl<'a, A, R> !Send for Closure<'a, A, R> {}
16
14impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> { 17impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
15 fn from(f: &'a mut F) -> Self { 18 fn from(f: &'a mut F) -> Self {
16 unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: &mut Env, arg: A) -> R { 19 unsafe extern "C" fn call<A, R, F: FnMut(A) -> R>(env: &mut Env, arg: A) -> R {
diff --git a/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
index 6ae3926b2..aeb05aad4 100644
--- a/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
+++ b/crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs
@@ -108,8 +108,9 @@ macro_rules! with_api {
108 Literal { 108 Literal {
109 fn drop($self: $S::Literal); 109 fn drop($self: $S::Literal);
110 fn clone($self: &$S::Literal) -> $S::Literal; 110 fn clone($self: &$S::Literal) -> $S::Literal;
111 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls. 111 fn debug_kind($self: &$S::Literal) -> String;
112 fn debug($self: &$S::Literal) -> String; 112 fn symbol($self: &$S::Literal) -> String;
113 fn suffix($self: &$S::Literal) -> Option<String>;
113 fn integer(n: &str) -> $S::Literal; 114 fn integer(n: &str) -> $S::Literal;
114 fn typed_integer(n: &str, kind: &str) -> $S::Literal; 115 fn typed_integer(n: &str, kind: &str) -> $S::Literal;
115 fn float(n: &str) -> $S::Literal; 116 fn float(n: &str) -> $S::Literal;
@@ -222,6 +223,9 @@ pub struct Bridge<'a> {
222 dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>, 223 dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>,
223} 224}
224 225
226// impl<'a> !Sync for Bridge<'a> {}
227// impl<'a> !Send for Bridge<'a> {}
228
225#[forbid(unsafe_code)] 229#[forbid(unsafe_code)]
226#[allow(non_camel_case_types)] 230#[allow(non_camel_case_types)]
227mod api_tags { 231mod api_tags {
diff --git a/crates/ra_proc_macro_srv/src/rustc_server.rs b/crates/ra_proc_macro_srv/src/rustc_server.rs
index f481d70b2..cc32d5a6d 100644
--- a/crates/ra_proc_macro_srv/src/rustc_server.rs
+++ b/crates/ra_proc_macro_srv/src/rustc_server.rs
@@ -463,9 +463,16 @@ impl server::Ident for Rustc {
463} 463}
464 464
465impl server::Literal for Rustc { 465impl server::Literal for Rustc {
466 // FIXME(eddyb) `Literal` should not expose internal `Debug` impls. 466 fn debug_kind(&mut self, _literal: &Self::Literal) -> String {
467 fn debug(&mut self, literal: &Self::Literal) -> String { 467 // r-a: debug_kind and suffix are unsupported; corresponding client code has been changed to not call these.
468 format!("{:?}", literal) 468 // They must still be present to be ABI-compatible and work with upstream proc_macro.
469 "".to_owned()
470 }
471 fn symbol(&mut self, literal: &Self::Literal) -> String {
472 literal.text.to_string()
473 }
474 fn suffix(&mut self, _literal: &Self::Literal) -> Option<String> {
475 None
469 } 476 }
470 477
471 fn integer(&mut self, n: &str) -> Self::Literal { 478 fn integer(&mut self, n: &str) -> Self::Literal {
diff --git a/crates/ra_proc_macro_srv/src/tests/mod.rs b/crates/ra_proc_macro_srv/src/tests/mod.rs
index 82cefbb29..8e6f28abd 100644
--- a/crates/ra_proc_macro_srv/src/tests/mod.rs
+++ b/crates/ra_proc_macro_srv/src/tests/mod.rs
@@ -11,7 +11,7 @@ fn test_derive_serialize_proc_macro() {
11 "serde_derive", 11 "serde_derive",
12 "Serialize", 12 "Serialize",
13 "1.0", 13 "1.0",
14 r##"struct Foo {}"##, 14 r"struct Foo {}",
15 include_str!("fixtures/test_serialize_proc_macro.txt"), 15 include_str!("fixtures/test_serialize_proc_macro.txt"),
16 ); 16 );
17} 17}
@@ -22,9 +22,7 @@ fn test_derive_serialize_proc_macro_failed() {
22 "serde_derive", 22 "serde_derive",
23 "Serialize", 23 "Serialize",
24 "1.0", 24 "1.0",
25 r##" 25 r"struct {}",
26 struct {}
27"##,
28 r##" 26 r##"
29SUBTREE $ 27SUBTREE $
30 IDENT compile_error 4294967295 28 IDENT compile_error 4294967295
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs
index 8d85f2d8a..dcb00671f 100644
--- a/crates/ra_proc_macro_srv/src/tests/utils.rs
+++ b/crates/ra_proc_macro_srv/src/tests/utils.rs
@@ -44,12 +44,12 @@ pub fn assert_expand(
44 crate_name: &str, 44 crate_name: &str,
45 macro_name: &str, 45 macro_name: &str,
46 version: &str, 46 version: &str,
47 fixture: &str, 47 ra_fixture: &str,
48 expect: &str, 48 expect: &str,
49) { 49) {
50 let path = fixtures::dylib_path(crate_name, version); 50 let path = fixtures::dylib_path(crate_name, version);
51 let expander = dylib::Expander::new(&path).unwrap(); 51 let expander = dylib::Expander::new(&path).unwrap();
52 let fixture = parse_string(fixture).unwrap(); 52 let fixture = parse_string(ra_fixture).unwrap();
53 53
54 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); 54 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap();
55 assert_eq_text!(&format!("{:?}", res), &expect.trim()); 55 assert_eq_text!(&format!("{:?}", res), &expect.trim());
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index c33b5121a..c82b9f76d 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_prof"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
@@ -12,11 +13,15 @@ doctest = false
12ra_arena = { path = "../ra_arena" } 13ra_arena = { path = "../ra_arena" }
13once_cell = "1.3.1" 14once_cell = "1.3.1"
14backtrace = { version = "0.3.44", optional = true } 15backtrace = { version = "0.3.44", optional = true }
16cfg-if = "0.1.10"
17libc = "0.2.73"
15 18
16[target.'cfg(not(target_env = "msvc"))'.dependencies] 19[target.'cfg(target_os = "linux")'.dependencies]
17jemallocator = { version = "0.3.2", optional = true } 20perf-event = "0.4"
18jemalloc-ctl = { version = "0.3.3", optional = true }
19 21
20[features] 22[features]
21jemalloc = [ "jemallocator", "jemalloc-ctl" ]
22cpu_profiler = [] 23cpu_profiler = []
24
25# Uncomment to enable for the whole crate graph
26# default = [ "backtrace" ]
27# default = [ "cpu_profiler" ]
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index 89df7f04b..eb50965ae 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -1,5 +1,6 @@
1//! A collection of tools for profiling rust-analyzer. 1//! A collection of tools for profiling rust-analyzer.
2 2
3mod stop_watch;
3mod memory_usage; 4mod memory_usage;
4#[cfg(feature = "cpu_profiler")] 5#[cfg(feature = "cpu_profiler")]
5mod google_cpu_profiler; 6mod google_cpu_profiler;
@@ -11,14 +12,9 @@ use std::cell::RefCell;
11pub use crate::{ 12pub use crate::{
12 hprof::{init, init_from, profile}, 13 hprof::{init, init_from, profile},
13 memory_usage::{Bytes, MemoryUsage}, 14 memory_usage::{Bytes, MemoryUsage},
15 stop_watch::{StopWatch, StopWatchSpan},
14}; 16};
15 17
16// We use jemalloc mainly to get heap usage statistics, actual performance
17// difference is not measures.
18#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
19#[global_allocator]
20static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
21
22/// Prints backtrace to stderr, useful for debugging. 18/// Prints backtrace to stderr, useful for debugging.
23#[cfg(feature = "backtrace")] 19#[cfg(feature = "backtrace")]
24pub fn print_backtrace() { 20pub fn print_backtrace() {
@@ -43,6 +39,7 @@ pub struct Scope {
43} 39}
44 40
45impl Scope { 41impl Scope {
42 #[must_use]
46 pub fn enter() -> Scope { 43 pub fn enter() -> Scope {
47 let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true)); 44 let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
48 Scope { prev } 45 Scope { prev }
@@ -65,7 +62,8 @@ impl Drop for Scope {
65/// 2. Build with `cpu_profiler` feature. 62/// 2. Build with `cpu_profiler` feature.
66/// 3. Tun the code, the *raw* output would be in the `./out.profile` file. 63/// 3. Tun the code, the *raw* output would be in the `./out.profile` file.
67/// 4. Install pprof for visualization (https://github.com/google/pprof). 64/// 4. Install pprof for visualization (https://github.com/google/pprof).
68/// 5. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. 65/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000`
66/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results.
69/// 67///
70/// For example, here's how I run profiling on NixOS: 68/// For example, here's how I run profiling on NixOS:
71/// 69///
@@ -73,11 +71,16 @@ impl Drop for Scope {
73/// $ nix-shell -p gperftools --run \ 71/// $ nix-shell -p gperftools --run \
74/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' 72/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null'
75/// ``` 73/// ```
74///
75/// See this diff for how to profile completions:
76///
77/// https://github.com/rust-analyzer/rust-analyzer/pull/5306
76#[derive(Debug)] 78#[derive(Debug)]
77pub struct CpuProfiler { 79pub struct CpuProfiler {
78 _private: (), 80 _private: (),
79} 81}
80 82
83#[must_use]
81pub fn cpu_profiler() -> CpuProfiler { 84pub fn cpu_profiler() -> CpuProfiler {
82 #[cfg(feature = "cpu_profiler")] 85 #[cfg(feature = "cpu_profiler")]
83 { 86 {
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index 9768f656c..c2ecbd33c 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -1,46 +1,58 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3use std::fmt; 2use std::fmt;
4 3
4use cfg_if::cfg_if;
5
6#[derive(Copy, Clone)]
5pub struct MemoryUsage { 7pub struct MemoryUsage {
6 pub allocated: Bytes, 8 pub allocated: Bytes,
7 pub resident: Bytes,
8} 9}
9 10
10impl MemoryUsage { 11impl fmt::Display for MemoryUsage {
11 #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] 12 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
12 pub fn current() -> MemoryUsage { 13 write!(fmt, "{}", self.allocated)
13 jemalloc_ctl::epoch::advance().unwrap();
14 MemoryUsage {
15 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap()),
16 resident: Bytes(jemalloc_ctl::stats::resident::read().unwrap()),
17 }
18 } 14 }
15}
19 16
20 #[cfg(any(not(feature = "jemalloc"), target_env = "msvc"))] 17impl std::ops::Sub for MemoryUsage {
21 pub fn current() -> MemoryUsage { 18 type Output = MemoryUsage;
22 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } 19 fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
20 MemoryUsage { allocated: self.allocated - rhs.allocated }
23 } 21 }
24} 22}
25 23
26impl fmt::Display for MemoryUsage { 24impl MemoryUsage {
27 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 25 pub fn current() -> MemoryUsage {
28 write!(fmt, "{} allocated {} resident", self.allocated, self.resident,) 26 cfg_if! {
27 if #[cfg(target_os = "linux")] {
28 // Note: This is incredibly slow.
29 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
30 MemoryUsage { allocated: Bytes(alloc) }
31 } else {
32 MemoryUsage { allocated: Bytes(0) }
33 }
34 }
29 } 35 }
30} 36}
31 37
32#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 38#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
33pub struct Bytes(usize); 39pub struct Bytes(isize);
40
41impl Bytes {
42 pub fn megabytes(self) -> isize {
43 self.0 / 1024 / 1024
44 }
45}
34 46
35impl fmt::Display for Bytes { 47impl fmt::Display for Bytes {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 let bytes = self.0; 49 let bytes = self.0;
38 let mut value = bytes; 50 let mut value = bytes;
39 let mut suffix = "b"; 51 let mut suffix = "b";
40 if value > 4096 { 52 if value.abs() > 4096 {
41 value /= 1024; 53 value /= 1024;
42 suffix = "kb"; 54 suffix = "kb";
43 if value > 4096 { 55 if value.abs() > 4096 {
44 value /= 1024; 56 value /= 1024;
45 suffix = "mb"; 57 suffix = "mb";
46 } 58 }
@@ -51,7 +63,7 @@ impl fmt::Display for Bytes {
51 63
52impl std::ops::AddAssign<usize> for Bytes { 64impl std::ops::AddAssign<usize> for Bytes {
53 fn add_assign(&mut self, x: usize) { 65 fn add_assign(&mut self, x: usize) {
54 self.0 += x; 66 self.0 += x as isize;
55 } 67 }
56} 68}
57 69
diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs
new file mode 100644
index 000000000..5e276190e
--- /dev/null
+++ b/crates/ra_prof/src/stop_watch.rs
@@ -0,0 +1,86 @@
1//! Like `std::time::Instant`, but also measures memory & CPU cycles.
2use std::{
3 fmt,
4 time::{Duration, Instant},
5};
6
7use crate::MemoryUsage;
8
9pub struct StopWatch {
10 time: Instant,
11 #[cfg(target_os = "linux")]
12 counter: Option<perf_event::Counter>,
13 memory: Option<MemoryUsage>,
14}
15
16pub struct StopWatchSpan {
17 pub time: Duration,
18 pub instructions: Option<u64>,
19 pub memory: Option<MemoryUsage>,
20}
21
22impl StopWatch {
23 pub fn start() -> StopWatch {
24 #[cfg(target_os = "linux")]
25 let counter = {
26 let mut counter = perf_event::Builder::new()
27 .build()
28 .map_err(|err| eprintln!("Failed to create perf counter: {}", err))
29 .ok();
30 if let Some(counter) = &mut counter {
31 if let Err(err) = counter.enable() {
32 eprintln!("Failed to start perf counter: {}", err)
33 }
34 }
35 counter
36 };
37 let time = Instant::now();
38 StopWatch {
39 time,
40 #[cfg(target_os = "linux")]
41 counter,
42 memory: None,
43 }
44 }
45 pub fn memory(mut self, yes: bool) -> StopWatch {
46 if yes {
47 self.memory = Some(MemoryUsage::current());
48 }
49 self
50 }
51 pub fn elapsed(&mut self) -> StopWatchSpan {
52 let time = self.time.elapsed();
53
54 #[cfg(target_os = "linux")]
55 let instructions = self.counter.as_mut().and_then(|it| {
56 it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok()
57 });
58 #[cfg(not(target_os = "linux"))]
59 let instructions = None;
60
61 let memory = self.memory.map(|it| MemoryUsage::current() - it);
62 StopWatchSpan { time, instructions, memory }
63 }
64}
65
66impl fmt::Display for StopWatchSpan {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "{:.2?}", self.time)?;
69 if let Some(mut instructions) = self.instructions {
70 let mut prefix = "";
71 if instructions > 10000 {
72 instructions /= 1000;
73 prefix = "k"
74 }
75 if instructions > 10000 {
76 instructions /= 1000;
77 prefix = "m"
78 }
79 write!(f, ", {}{}i", instructions, prefix)?;
80 }
81 if let Some(memory) = self.memory {
82 write!(f, ", {}", memory)?;
83 }
84 Ok(())
85 }
86}
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index b1b44dcf7..99adea8e4 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_project_model" 3name = "ra_project_model"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
@@ -11,7 +12,7 @@ doctest = false
11log = "0.4.8" 12log = "0.4.8"
12rustc-hash = "1.1.0" 13rustc-hash = "1.1.0"
13 14
14cargo_metadata = "0.10.0" 15cargo_metadata = "0.11.1"
15 16
16ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
17ra_cfg = { path = "../ra_cfg" } 18ra_cfg = { path = "../ra_cfg" }
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 3b124020d..10513542e 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,6 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ffi::OsStr, ops, path::Path, process::Command}; 3use std::{
4 ffi::OsStr,
5 ops,
6 path::{Path, PathBuf},
7 process::Command,
8};
4 9
5use anyhow::{Context, Result}; 10use anyhow::{Context, Result};
6use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 11use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
@@ -9,6 +14,8 @@ use ra_arena::{Arena, Idx};
9use ra_db::Edition; 14use ra_db::Edition;
10use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
11 16
17use crate::cfg_flag::CfgFlag;
18
12/// `CargoWorkspace` represents the logical structure of, well, a Cargo 19/// `CargoWorkspace` represents the logical structure of, well, a Cargo
13/// workspace. It pretty closely mirrors `cargo metadata` output. 20/// workspace. It pretty closely mirrors `cargo metadata` output.
14/// 21///
@@ -19,7 +26,7 @@ use rustc_hash::FxHashMap;
19/// 26///
20/// We use absolute paths here, `cargo metadata` guarantees to always produce 27/// We use absolute paths here, `cargo metadata` guarantees to always produce
21/// abs paths. 28/// abs paths.
22#[derive(Debug, Clone)] 29#[derive(Debug, Clone, Eq, PartialEq)]
23pub struct CargoWorkspace { 30pub struct CargoWorkspace {
24 packages: Arena<PackageData>, 31 packages: Arena<PackageData>,
25 targets: Arena<TargetData>, 32 targets: Arena<TargetData>,
@@ -40,7 +47,7 @@ impl ops::Index<Target> for CargoWorkspace {
40 } 47 }
41} 48}
42 49
43#[derive(Clone, Debug, PartialEq, Eq)] 50#[derive(Default, Clone, Debug, PartialEq, Eq)]
44pub struct CargoConfig { 51pub struct CargoConfig {
45 /// Do not activate the `default` feature. 52 /// Do not activate the `default` feature.
46 pub no_default_features: bool, 53 pub no_default_features: bool,
@@ -59,23 +66,11 @@ pub struct CargoConfig {
59 pub target: Option<String>, 66 pub target: Option<String>,
60} 67}
61 68
62impl Default for CargoConfig {
63 fn default() -> Self {
64 CargoConfig {
65 no_default_features: false,
66 all_features: false,
67 features: Vec::new(),
68 load_out_dirs_from_check: false,
69 target: None,
70 }
71 }
72}
73
74pub type Package = Idx<PackageData>; 69pub type Package = Idx<PackageData>;
75 70
76pub type Target = Idx<TargetData>; 71pub type Target = Idx<TargetData>;
77 72
78#[derive(Debug, Clone)] 73#[derive(Debug, Clone, Eq, PartialEq)]
79pub struct PackageData { 74pub struct PackageData {
80 pub version: String, 75 pub version: String,
81 pub name: String, 76 pub name: String,
@@ -85,18 +80,18 @@ pub struct PackageData {
85 pub dependencies: Vec<PackageDependency>, 80 pub dependencies: Vec<PackageDependency>,
86 pub edition: Edition, 81 pub edition: Edition,
87 pub features: Vec<String>, 82 pub features: Vec<String>,
88 pub cfgs: Vec<String>, 83 pub cfgs: Vec<CfgFlag>,
89 pub out_dir: Option<AbsPathBuf>, 84 pub out_dir: Option<AbsPathBuf>,
90 pub proc_macro_dylib_path: Option<AbsPathBuf>, 85 pub proc_macro_dylib_path: Option<AbsPathBuf>,
91} 86}
92 87
93#[derive(Debug, Clone)] 88#[derive(Debug, Clone, Eq, PartialEq)]
94pub struct PackageDependency { 89pub struct PackageDependency {
95 pub pkg: Package, 90 pub pkg: Package,
96 pub name: String, 91 pub name: String,
97} 92}
98 93
99#[derive(Debug, Clone)] 94#[derive(Debug, Clone, Eq, PartialEq)]
100pub struct TargetData { 95pub struct TargetData {
101 pub package: Package, 96 pub package: Package,
102 pub name: String, 97 pub name: String,
@@ -141,28 +136,31 @@ impl PackageData {
141 136
142impl CargoWorkspace { 137impl CargoWorkspace {
143 pub fn from_cargo_metadata( 138 pub fn from_cargo_metadata(
144 cargo_toml: &Path, 139 cargo_toml: &AbsPath,
145 cargo_features: &CargoConfig, 140 cargo_features: &CargoConfig,
146 ) -> Result<CargoWorkspace> { 141 ) -> Result<CargoWorkspace> {
147 let mut meta = MetadataCommand::new(); 142 let mut meta = MetadataCommand::new();
148 meta.cargo_path(ra_toolchain::cargo()); 143 meta.cargo_path(ra_toolchain::cargo());
149 meta.manifest_path(cargo_toml); 144 meta.manifest_path(cargo_toml.to_path_buf());
150 if cargo_features.all_features { 145 if cargo_features.all_features {
151 meta.features(CargoOpt::AllFeatures); 146 meta.features(CargoOpt::AllFeatures);
152 } else if cargo_features.no_default_features { 147 } else {
153 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 148 if cargo_features.no_default_features {
154 // https://github.com/oli-obk/cargo_metadata/issues/79 149 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
155 meta.features(CargoOpt::NoDefaultFeatures); 150 // https://github.com/oli-obk/cargo_metadata/issues/79
156 } else if !cargo_features.features.is_empty() { 151 meta.features(CargoOpt::NoDefaultFeatures);
157 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); 152 }
153 if !cargo_features.features.is_empty() {
154 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
155 }
158 } 156 }
159 if let Some(parent) = cargo_toml.parent() { 157 if let Some(parent) = cargo_toml.parent() {
160 meta.current_dir(parent); 158 meta.current_dir(parent.to_path_buf());
161 } 159 }
162 if let Some(target) = cargo_features.target.as_ref() { 160 if let Some(target) = cargo_features.target.as_ref() {
163 meta.other_options(vec![String::from("--filter-platform"), target.clone()]); 161 meta.other_options(vec![String::from("--filter-platform"), target.clone()]);
164 } 162 }
165 let meta = meta.exec().with_context(|| { 163 let mut meta = meta.exec().with_context(|| {
166 format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) 164 format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
167 })?; 165 })?;
168 166
@@ -182,6 +180,7 @@ impl CargoWorkspace {
182 180
183 let ws_members = &meta.workspace_members; 181 let ws_members = &meta.workspace_members;
184 182
183 meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
185 for meta_pkg in meta.packages { 184 for meta_pkg in meta.packages {
186 let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = 185 let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
187 meta_pkg; 186 meta_pkg;
@@ -217,7 +216,7 @@ impl CargoWorkspace {
217 } 216 }
218 } 217 }
219 let resolve = meta.resolve.expect("metadata executed with deps"); 218 let resolve = meta.resolve.expect("metadata executed with deps");
220 for node in resolve.nodes { 219 for mut node in resolve.nodes {
221 let source = match pkg_by_id.get(&node.id) { 220 let source = match pkg_by_id.get(&node.id) {
222 Some(&src) => src, 221 Some(&src) => src,
223 // FIXME: replace this and a similar branch below with `.unwrap`, once 222 // FIXME: replace this and a similar branch below with `.unwrap`, once
@@ -228,6 +227,7 @@ impl CargoWorkspace {
228 continue; 227 continue;
229 } 228 }
230 }; 229 };
230 node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
231 for dep_node in node.deps { 231 for dep_node in node.deps {
232 let pkg = match pkg_by_id.get(&dep_node.pkg) { 232 let pkg = match pkg_by_id.get(&dep_node.pkg) {
233 Some(&pkg) => pkg, 233 Some(&pkg) => pkg,
@@ -281,7 +281,7 @@ impl CargoWorkspace {
281pub struct ExternResources { 281pub struct ExternResources {
282 out_dirs: FxHashMap<PackageId, AbsPathBuf>, 282 out_dirs: FxHashMap<PackageId, AbsPathBuf>,
283 proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>, 283 proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>,
284 cfgs: FxHashMap<PackageId, Vec<String>>, 284 cfgs: FxHashMap<PackageId, Vec<CfgFlag>>,
285} 285}
286 286
287pub fn load_extern_resources( 287pub fn load_extern_resources(
@@ -292,12 +292,16 @@ pub fn load_extern_resources(
292 cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); 292 cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
293 if cargo_features.all_features { 293 if cargo_features.all_features {
294 cmd.arg("--all-features"); 294 cmd.arg("--all-features");
295 } else if cargo_features.no_default_features {
296 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
297 // https://github.com/oli-obk/cargo_metadata/issues/79
298 cmd.arg("--no-default-features");
299 } else { 295 } else {
300 cmd.args(&cargo_features.features); 296 if cargo_features.no_default_features {
297 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
298 // https://github.com/oli-obk/cargo_metadata/issues/79
299 cmd.arg("--no-default-features");
300 }
301 if !cargo_features.features.is_empty() {
302 cmd.arg("--features");
303 cmd.arg(cargo_features.features.join(" "));
304 }
301 } 305 }
302 306
303 let output = cmd.output()?; 307 let output = cmd.output()?;
@@ -308,9 +312,25 @@ pub fn load_extern_resources(
308 if let Ok(message) = message { 312 if let Ok(message) = message {
309 match message { 313 match message {
310 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { 314 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => {
311 let out_dir = AbsPathBuf::assert(out_dir); 315 let cfgs = {
312 res.out_dirs.insert(package_id.clone(), out_dir); 316 let mut acc = Vec::new();
313 res.cfgs.insert(package_id, cfgs); 317 for cfg in cfgs {
318 match cfg.parse::<CfgFlag>() {
319 Ok(it) => acc.push(it),
320 Err(err) => {
321 anyhow::bail!("invalid cfg from cargo-metadata: {}", err)
322 }
323 };
324 }
325 acc
326 };
327 // cargo_metadata crate returns default (empty) path for
328 // older cargos, which is not absolute, so work around that.
329 if out_dir != PathBuf::default() {
330 let out_dir = AbsPathBuf::assert(out_dir);
331 res.out_dirs.insert(package_id.clone(), out_dir);
332 res.cfgs.insert(package_id, cfgs);
333 }
314 } 334 }
315 Message::CompilerArtifact(message) => { 335 Message::CompilerArtifact(message) => {
316 if message.target.kind.contains(&"proc-macro".to_string()) { 336 if message.target.kind.contains(&"proc-macro".to_string()) {
diff --git a/crates/ra_project_model/src/cfg_flag.rs b/crates/ra_project_model/src/cfg_flag.rs
new file mode 100644
index 000000000..bd50056c6
--- /dev/null
+++ b/crates/ra_project_model/src/cfg_flag.rs
@@ -0,0 +1,51 @@
1//! Parsing of CfgFlags as command line arguments, as in
2//!
3//! rustc main.rs --cfg foo --cfg 'feature="bar"'
4use std::str::FromStr;
5
6use ra_cfg::CfgOptions;
7use stdx::split_once;
8
9#[derive(Clone, Eq, PartialEq, Debug)]
10pub enum CfgFlag {
11 Atom(String),
12 KeyValue { key: String, value: String },
13}
14
15impl FromStr for CfgFlag {
16 type Err = String;
17 fn from_str(s: &str) -> Result<Self, Self::Err> {
18 let res = match split_once(s, '=') {
19 Some((key, value)) => {
20 if !(value.starts_with('"') && value.ends_with('"')) {
21 return Err(format!("Invalid cfg ({:?}), value should be in quotes", s));
22 }
23 let key = key.to_string();
24 let value = value[1..value.len() - 1].to_string();
25 CfgFlag::KeyValue { key, value }
26 }
27 None => CfgFlag::Atom(s.into()),
28 };
29 Ok(res)
30 }
31}
32
33impl<'de> serde::Deserialize<'de> for CfgFlag {
34 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35 where
36 D: serde::Deserializer<'de>,
37 {
38 String::deserialize(deserializer)?.parse().map_err(serde::de::Error::custom)
39 }
40}
41
42impl Extend<CfgFlag> for CfgOptions {
43 fn extend<T: IntoIterator<Item = CfgFlag>>(&mut self, iter: T) {
44 for cfg_flag in iter {
45 match cfg_flag {
46 CfgFlag::Atom(it) => self.insert_atom(it.into()),
47 CfgFlag::KeyValue { key, value } => self.insert_key_value(key.into(), value.into()),
48 }
49 }
50 }
51}
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 8b85b4831..300e75135 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -3,12 +3,12 @@
3mod cargo_workspace; 3mod cargo_workspace;
4mod project_json; 4mod project_json;
5mod sysroot; 5mod sysroot;
6mod cfg_flag;
6 7
7use std::{ 8use std::{
8 fs::{self, read_dir, ReadDir}, 9 fs::{self, read_dir, ReadDir},
9 io, 10 io,
10 path::Path, 11 process::Command,
11 process::{Command, Output},
12}; 12};
13 13
14use anyhow::{bail, Context, Result}; 14use anyhow::{bail, Context, Result};
@@ -17,14 +17,17 @@ use ra_cfg::CfgOptions;
17use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; 17use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId};
18use rustc_hash::{FxHashMap, FxHashSet}; 18use rustc_hash::{FxHashMap, FxHashSet};
19 19
20use crate::cfg_flag::CfgFlag;
21
20pub use crate::{ 22pub use crate::{
21 cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, 23 cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind},
22 project_json::{ProjectJson, ProjectJsonData}, 24 project_json::{ProjectJson, ProjectJsonData},
23 sysroot::Sysroot, 25 sysroot::Sysroot,
24}; 26};
27
25pub use ra_proc_macro::ProcMacroClient; 28pub use ra_proc_macro::ProcMacroClient;
26 29
27#[derive(Debug, Clone)] 30#[derive(Debug, Clone, Eq, PartialEq)]
28pub enum ProjectWorkspace { 31pub enum ProjectWorkspace {
29 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. 32 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
30 Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, 33 Cargo { cargo: CargoWorkspace, sysroot: Sysroot },
@@ -35,30 +38,12 @@ pub enum ProjectWorkspace {
35/// `PackageRoot` describes a package root folder. 38/// `PackageRoot` describes a package root folder.
36/// Which may be an external dependency, or a member of 39/// Which may be an external dependency, or a member of
37/// the current workspace. 40/// the current workspace.
38#[derive(Debug, Clone)] 41#[derive(Debug, Clone, Eq, PartialEq, Hash)]
39pub struct PackageRoot { 42pub struct PackageRoot {
40 /// Path to the root folder
41 path: AbsPathBuf,
42 /// Is a member of the current workspace 43 /// Is a member of the current workspace
43 is_member: bool, 44 pub is_member: bool,
44 out_dir: Option<AbsPathBuf>, 45 pub include: Vec<AbsPathBuf>,
45} 46 pub exclude: Vec<AbsPathBuf>,
46impl PackageRoot {
47 pub fn new_member(path: AbsPathBuf) -> PackageRoot {
48 Self { path, is_member: true, out_dir: None }
49 }
50 pub fn new_non_member(path: AbsPathBuf) -> PackageRoot {
51 Self { path, is_member: false, out_dir: None }
52 }
53 pub fn path(&self) -> &AbsPath {
54 &self.path
55 }
56 pub fn out_dir(&self) -> Option<&AbsPath> {
57 self.out_dir.as_deref()
58 }
59 pub fn is_member(&self) -> bool {
60 self.is_member
61 }
62} 47}
63 48
64#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] 49#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
@@ -150,7 +135,7 @@ impl ProjectManifest {
150impl ProjectWorkspace { 135impl ProjectWorkspace {
151 pub fn load( 136 pub fn load(
152 manifest: ProjectManifest, 137 manifest: ProjectManifest,
153 cargo_features: &CargoConfig, 138 cargo_config: &CargoConfig,
154 with_sysroot: bool, 139 with_sysroot: bool,
155 ) -> Result<ProjectWorkspace> { 140 ) -> Result<ProjectWorkspace> {
156 let res = match manifest { 141 let res = match manifest {
@@ -166,7 +151,7 @@ impl ProjectWorkspace {
166 ProjectWorkspace::Json { project } 151 ProjectWorkspace::Json { project }
167 } 152 }
168 ProjectManifest::CargoToml(cargo_toml) => { 153 ProjectManifest::CargoToml(cargo_toml) => {
169 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) 154 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_config)
170 .with_context(|| { 155 .with_context(|| {
171 format!( 156 format!(
172 "Failed to read Cargo metadata from Cargo.toml file {}", 157 "Failed to read Cargo metadata from Cargo.toml file {}",
@@ -195,18 +180,40 @@ impl ProjectWorkspace {
195 /// the root is a member of the current workspace 180 /// the root is a member of the current workspace
196 pub fn to_roots(&self) -> Vec<PackageRoot> { 181 pub fn to_roots(&self) -> Vec<PackageRoot> {
197 match self { 182 match self {
198 ProjectWorkspace::Json { project } => { 183 ProjectWorkspace::Json { project } => project
199 project.roots.iter().map(|r| PackageRoot::new_member(r.path.clone())).collect() 184 .crates
200 } 185 .iter()
186 .map(|krate| PackageRoot {
187 is_member: krate.is_workspace_member,
188 include: krate.include.clone(),
189 exclude: krate.exclude.clone(),
190 })
191 .collect::<FxHashSet<_>>()
192 .into_iter()
193 .collect::<Vec<_>>(),
201 ProjectWorkspace::Cargo { cargo, sysroot } => cargo 194 ProjectWorkspace::Cargo { cargo, sysroot } => cargo
202 .packages() 195 .packages()
203 .map(|pkg| PackageRoot { 196 .map(|pkg| {
204 path: cargo[pkg].root().to_path_buf(), 197 let is_member = cargo[pkg].is_member;
205 is_member: cargo[pkg].is_member, 198 let pkg_root = cargo[pkg].root().to_path_buf();
206 out_dir: cargo[pkg].out_dir.clone(), 199
200 let mut include = vec![pkg_root.clone()];
201 include.extend(cargo[pkg].out_dir.clone());
202
203 let mut exclude = vec![pkg_root.join(".git")];
204 if is_member {
205 exclude.push(pkg_root.join("target"));
206 } else {
207 exclude.push(pkg_root.join("tests"));
208 exclude.push(pkg_root.join("examples"));
209 exclude.push(pkg_root.join("benches"));
210 }
211 PackageRoot { is_member, include, exclude }
207 }) 212 })
208 .chain(sysroot.crates().map(|krate| { 213 .chain(sysroot.crates().map(|krate| PackageRoot {
209 PackageRoot::new_non_member(sysroot[krate].root_dir().to_path_buf()) 214 is_member: false,
215 include: vec![sysroot[krate].root_dir().to_path_buf()],
216 exclude: Vec::new(),
210 })) 217 }))
211 .collect(), 218 .collect(),
212 } 219 }
@@ -246,6 +253,7 @@ impl ProjectWorkspace {
246 let mut crate_graph = CrateGraph::default(); 253 let mut crate_graph = CrateGraph::default();
247 match self { 254 match self {
248 ProjectWorkspace::Json { project } => { 255 ProjectWorkspace::Json { project } => {
256 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
249 let crates: FxHashMap<_, _> = project 257 let crates: FxHashMap<_, _> = project
250 .crates 258 .crates
251 .iter() 259 .iter()
@@ -254,17 +262,20 @@ impl ProjectWorkspace {
254 let file_path = &krate.root_module; 262 let file_path = &krate.root_module;
255 let file_id = load(&file_path)?; 263 let file_id = load(&file_path)?;
256 264
257 let mut env = Env::default(); 265 let env = krate.env.clone().into_iter().collect();
258 if let Some(out_dir) = &krate.out_dir {
259 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
260 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
261 env.set("OUT_DIR", out_dir);
262 }
263 }
264 let proc_macro = krate 266 let proc_macro = krate
265 .proc_macro_dylib_path 267 .proc_macro_dylib_path
266 .clone() 268 .clone()
267 .map(|it| proc_macro_client.by_dylib_path(&it)); 269 .map(|it| proc_macro_client.by_dylib_path(&it));
270
271 let target = krate.target.as_deref().or(target);
272 let target_cfgs = cfg_cache
273 .entry(target)
274 .or_insert_with(|| get_rustc_cfg_options(target));
275
276 let mut cfg_options = CfgOptions::default();
277 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
278
268 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env 279 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
269 Some(( 280 Some((
270 CrateId(seq_index as u32), 281 CrateId(seq_index as u32),
@@ -273,7 +284,7 @@ impl ProjectWorkspace {
273 krate.edition, 284 krate.edition,
274 // FIXME json definitions can store the crate name 285 // FIXME json definitions can store the crate name
275 None, 286 None,
276 krate.cfg.clone(), 287 cfg_options,
277 env, 288 env,
278 proc_macro.unwrap_or_default(), 289 proc_macro.unwrap_or_default(),
279 ), 290 ),
@@ -288,10 +299,7 @@ impl ProjectWorkspace {
288 if let (Some(&from), Some(&to)) = 299 if let (Some(&from), Some(&to)) =
289 (crates.get(&from_crate_id), crates.get(&to_crate_id)) 300 (crates.get(&from_crate_id), crates.get(&to_crate_id))
290 { 301 {
291 if crate_graph 302 if crate_graph.add_dep(from, dep.name.clone(), to).is_err() {
292 .add_dep(from, CrateName::new(&dep.name).unwrap(), to)
293 .is_err()
294 {
295 log::error!( 303 log::error!(
296 "cyclic dependency {:?} -> {:?}", 304 "cyclic dependency {:?} -> {:?}",
297 from_crate_id, 305 from_crate_id,
@@ -303,7 +311,8 @@ impl ProjectWorkspace {
303 } 311 }
304 } 312 }
305 ProjectWorkspace::Cargo { cargo, sysroot } => { 313 ProjectWorkspace::Cargo { cargo, sysroot } => {
306 let mut cfg_options = get_rustc_cfg_options(target); 314 let mut cfg_options = CfgOptions::default();
315 cfg_options.extend(get_rustc_cfg_options(target));
307 316
308 let sysroot_crates: FxHashMap<_, _> = sysroot 317 let sysroot_crates: FxHashMap<_, _> = sysroot
309 .crates() 318 .crates()
@@ -312,13 +321,11 @@ impl ProjectWorkspace {
312 321
313 let env = Env::default(); 322 let env = Env::default();
314 let proc_macro = vec![]; 323 let proc_macro = vec![];
315 let crate_name = CrateName::new(&sysroot[krate].name) 324 let name = sysroot[krate].name.clone();
316 .expect("Sysroot crate names should not contain dashes");
317
318 let crate_id = crate_graph.add_crate_root( 325 let crate_id = crate_graph.add_crate_root(
319 file_id, 326 file_id,
320 Edition::Edition2018, 327 Edition::Edition2018,
321 Some(crate_name), 328 Some(name),
322 cfg_options.clone(), 329 cfg_options.clone(),
323 env, 330 env,
324 proc_macro, 331 proc_macro,
@@ -352,6 +359,7 @@ impl ProjectWorkspace {
352 359
353 // Add test cfg for non-sysroot crates 360 // Add test cfg for non-sysroot crates
354 cfg_options.insert_atom("test".into()); 361 cfg_options.insert_atom("test".into());
362 cfg_options.insert_atom("debug_assertions".into());
355 363
356 // Next, create crates for each package, target pair 364 // Next, create crates for each package, target pair
357 for pkg in cargo.packages() { 365 for pkg in cargo.packages() {
@@ -365,15 +373,7 @@ impl ProjectWorkspace {
365 for feature in cargo[pkg].features.iter() { 373 for feature in cargo[pkg].features.iter() {
366 opts.insert_key_value("feature".into(), feature.into()); 374 opts.insert_key_value("feature".into(), feature.into());
367 } 375 }
368 for cfg in cargo[pkg].cfgs.iter() { 376 opts.extend(cargo[pkg].cfgs.iter().cloned());
369 match cfg.find('=') {
370 Some(split) => opts.insert_key_value(
371 cfg[..split].into(),
372 cfg[split + 1..].trim_matches('"').into(),
373 ),
374 None => opts.insert_atom(cfg.into()),
375 };
376 }
377 opts 377 opts
378 }; 378 };
379 let mut env = Env::default(); 379 let mut env = Env::default();
@@ -392,7 +392,7 @@ impl ProjectWorkspace {
392 let crate_id = crate_graph.add_crate_root( 392 let crate_id = crate_graph.add_crate_root(
393 file_id, 393 file_id,
394 edition, 394 edition,
395 Some(CrateName::normalize_dashes(&cargo[pkg].name)), 395 Some(cargo[pkg].name.clone()),
396 cfg_options, 396 cfg_options,
397 env, 397 env,
398 proc_macro.clone(), 398 proc_macro.clone(),
@@ -499,66 +499,37 @@ impl ProjectWorkspace {
499 } 499 }
500 crate_graph 500 crate_graph
501 } 501 }
502
503 pub fn workspace_root_for(&self, path: &Path) -> Option<&AbsPath> {
504 match self {
505 ProjectWorkspace::Cargo { cargo, .. } => {
506 Some(cargo.workspace_root()).filter(|root| path.starts_with(root))
507 }
508 ProjectWorkspace::Json { project: ProjectJson { roots, .. }, .. } => roots
509 .iter()
510 .find(|root| path.starts_with(&root.path))
511 .map(|root| root.path.as_path()),
512 }
513 }
514} 502}
515 503
516fn get_rustc_cfg_options(target: Option<&str>) -> CfgOptions { 504fn get_rustc_cfg_options(target: Option<&str>) -> Vec<CfgFlag> {
517 let mut cfg_options = CfgOptions::default(); 505 let mut res = Vec::new();
518 506
519 // Some nightly-only cfgs, which are required for stdlib 507 // Some nightly-only cfgs, which are required for stdlib
520 { 508 res.push(CfgFlag::Atom("target_thread_local".into()));
521 cfg_options.insert_atom("target_thread_local".into()); 509 for &ty in ["8", "16", "32", "64", "cas", "ptr"].iter() {
522 for &target_has_atomic in ["8", "16", "32", "64", "cas", "ptr"].iter() { 510 for &key in ["target_has_atomic", "target_has_atomic_load_store"].iter() {
523 cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into()); 511 res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
524 cfg_options
525 .insert_key_value("target_has_atomic_load_store".into(), target_has_atomic.into());
526 } 512 }
527 } 513 }
528 514
529 let rustc_cfgs = || -> Result<String> { 515 let rustc_cfgs = {
530 // `cfg(test)` and `cfg(debug_assertion)` are handled outside, so we suppress them here.
531 let mut cmd = Command::new(ra_toolchain::rustc()); 516 let mut cmd = Command::new(ra_toolchain::rustc());
532 cmd.args(&["--print", "cfg", "-O"]); 517 cmd.args(&["--print", "cfg", "-O"]);
533 if let Some(target) = target { 518 if let Some(target) = target {
534 cmd.args(&["--target", target]); 519 cmd.args(&["--target", target]);
535 } 520 }
536 let output = output(cmd)?; 521 utf8_stdout(cmd)
537 Ok(String::from_utf8(output.stdout)?) 522 };
538 }();
539 523
540 match rustc_cfgs { 524 match rustc_cfgs {
541 Ok(rustc_cfgs) => { 525 Ok(rustc_cfgs) => res.extend(rustc_cfgs.lines().map(|it| it.parse().unwrap())),
542 for line in rustc_cfgs.lines() {
543 match line.find('=') {
544 None => cfg_options.insert_atom(line.into()),
545 Some(pos) => {
546 let key = &line[..pos];
547 let value = line[pos + 1..].trim_matches('"');
548 cfg_options.insert_key_value(key.into(), value.into());
549 }
550 }
551 }
552 }
553 Err(e) => log::error!("failed to get rustc cfgs: {:#}", e), 526 Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
554 } 527 }
555 528
556 cfg_options.insert_atom("debug_assertions".into()); 529 res
557
558 cfg_options
559} 530}
560 531
561fn output(mut cmd: Command) -> Result<Output> { 532fn utf8_stdout(mut cmd: Command) -> Result<String> {
562 let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?; 533 let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?;
563 if !output.status.success() { 534 if !output.status.success() {
564 match String::from_utf8(output.stderr) { 535 match String::from_utf8(output.stderr) {
@@ -568,5 +539,6 @@ fn output(mut cmd: Command) -> Result<Output> {
568 _ => bail!("{:?} failed, {}", cmd, output.status), 539 _ => bail!("{:?} failed, {}", cmd, output.status),
569 } 540 }
570 } 541 }
571 Ok(output) 542 let stdout = String::from_utf8(output.stdout)?;
543 Ok(stdout)
572} 544}
diff --git a/crates/ra_project_model/src/project_json.rs b/crates/ra_project_model/src/project_json.rs
index 4b5dcd634..e3f3163f6 100644
--- a/crates/ra_project_model/src/project_json.rs
+++ b/crates/ra_project_model/src/project_json.rs
@@ -3,70 +3,78 @@
3use std::path::PathBuf; 3use std::path::PathBuf;
4 4
5use paths::{AbsPath, AbsPathBuf}; 5use paths::{AbsPath, AbsPathBuf};
6use ra_cfg::CfgOptions; 6use ra_db::{CrateId, CrateName, Dependency, Edition};
7use ra_db::{CrateId, Dependency, Edition}; 7use rustc_hash::FxHashMap;
8use rustc_hash::FxHashSet; 8use serde::{de, Deserialize};
9use serde::Deserialize; 9
10use stdx::split_delim; 10use crate::cfg_flag::CfgFlag;
11 11
12/// Roots and crates that compose this Rust project. 12/// Roots and crates that compose this Rust project.
13#[derive(Clone, Debug)] 13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ProjectJson { 14pub struct ProjectJson {
15 pub(crate) roots: Vec<Root>,
16 pub(crate) crates: Vec<Crate>, 15 pub(crate) crates: Vec<Crate>,
17} 16}
18 17
19/// A root points to the directory which contains Rust crates. rust-analyzer watches all files in
20/// all roots. Roots might be nested.
21#[derive(Clone, Debug)]
22pub struct Root {
23 pub(crate) path: AbsPathBuf,
24}
25
26/// A crate points to the root module of a crate and lists the dependencies of the crate. This is 18/// A crate points to the root module of a crate and lists the dependencies of the crate. This is
27/// useful in creating the crate graph. 19/// useful in creating the crate graph.
28#[derive(Clone, Debug)] 20#[derive(Clone, Debug, Eq, PartialEq)]
29pub struct Crate { 21pub struct Crate {
30 pub(crate) root_module: AbsPathBuf, 22 pub(crate) root_module: AbsPathBuf,
31 pub(crate) edition: Edition, 23 pub(crate) edition: Edition,
32 pub(crate) deps: Vec<Dependency>, 24 pub(crate) deps: Vec<Dependency>,
33 pub(crate) cfg: CfgOptions, 25 pub(crate) cfg: Vec<CfgFlag>,
34 pub(crate) out_dir: Option<AbsPathBuf>, 26 pub(crate) target: Option<String>,
27 pub(crate) env: FxHashMap<String, String>,
35 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, 28 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
29 pub(crate) is_workspace_member: bool,
30 pub(crate) include: Vec<AbsPathBuf>,
31 pub(crate) exclude: Vec<AbsPathBuf>,
36} 32}
37 33
38impl ProjectJson { 34impl ProjectJson {
39 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { 35 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
40 ProjectJson { 36 ProjectJson {
41 roots: data.roots.into_iter().map(|path| Root { path: base.join(path) }).collect(),
42 crates: data 37 crates: data
43 .crates 38 .crates
44 .into_iter() 39 .into_iter()
45 .map(|crate_data| Crate { 40 .map(|crate_data| {
46 root_module: base.join(crate_data.root_module), 41 let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| {
47 edition: crate_data.edition.into(), 42 crate_data.root_module.is_relative()
48 deps: crate_data 43 && !crate_data.root_module.starts_with("..")
49 .deps 44 || crate_data.root_module.starts_with(base)
50 .into_iter() 45 });
51 .map(|dep_data| Dependency { 46 let root_module = base.join(crate_data.root_module);
52 crate_id: CrateId(dep_data.krate as u32), 47 let (include, exclude) = match crate_data.source {
53 name: dep_data.name.into(), 48 Some(src) => {
54 }) 49 let absolutize = |dirs: Vec<PathBuf>| {
55 .collect::<Vec<_>>(), 50 dirs.into_iter().map(|it| base.join(it)).collect::<Vec<_>>()
56 cfg: { 51 };
57 let mut cfg = CfgOptions::default(); 52 (absolutize(src.include_dirs), absolutize(src.exclude_dirs))
58 for entry in &crate_data.cfg {
59 match split_delim(entry, '=') {
60 Some((key, value)) => {
61 cfg.insert_key_value(key.into(), value.into());
62 }
63 None => cfg.insert_atom(entry.into()),
64 }
65 } 53 }
66 cfg 54 None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
67 }, 55 };
68 out_dir: crate_data.out_dir.map(|it| base.join(it)), 56
69 proc_macro_dylib_path: crate_data.proc_macro_dylib_path.map(|it| base.join(it)), 57 Crate {
58 root_module,
59 edition: crate_data.edition.into(),
60 deps: crate_data
61 .deps
62 .into_iter()
63 .map(|dep_data| Dependency {
64 crate_id: CrateId(dep_data.krate as u32),
65 name: dep_data.name,
66 })
67 .collect::<Vec<_>>(),
68 cfg: crate_data.cfg,
69 target: crate_data.target,
70 env: crate_data.env,
71 proc_macro_dylib_path: crate_data
72 .proc_macro_dylib_path
73 .map(|it| base.join(it)),
74 is_workspace_member,
75 include,
76 exclude,
77 }
70 }) 78 })
71 .collect::<Vec<_>>(), 79 .collect::<Vec<_>>(),
72 } 80 }
@@ -75,7 +83,6 @@ impl ProjectJson {
75 83
76#[derive(Deserialize)] 84#[derive(Deserialize)]
77pub struct ProjectJsonData { 85pub struct ProjectJsonData {
78 roots: Vec<PathBuf>,
79 crates: Vec<CrateData>, 86 crates: Vec<CrateData>,
80} 87}
81 88
@@ -85,9 +92,13 @@ struct CrateData {
85 edition: EditionData, 92 edition: EditionData,
86 deps: Vec<DepData>, 93 deps: Vec<DepData>,
87 #[serde(default)] 94 #[serde(default)]
88 cfg: FxHashSet<String>, 95 cfg: Vec<CfgFlag>,
89 out_dir: Option<PathBuf>, 96 target: Option<String>,
97 #[serde(default)]
98 env: FxHashMap<String, String>,
90 proc_macro_dylib_path: Option<PathBuf>, 99 proc_macro_dylib_path: Option<PathBuf>,
100 is_workspace_member: Option<bool>,
101 source: Option<CrateSource>,
91} 102}
92 103
93#[derive(Deserialize)] 104#[derive(Deserialize)]
@@ -113,5 +124,20 @@ struct DepData {
113 /// Identifies a crate by position in the crates array. 124 /// Identifies a crate by position in the crates array.
114 #[serde(rename = "crate")] 125 #[serde(rename = "crate")]
115 krate: usize, 126 krate: usize,
116 name: String, 127 #[serde(deserialize_with = "deserialize_crate_name")]
128 name: CrateName,
129}
130
131#[derive(Deserialize)]
132struct CrateSource {
133 include_dirs: Vec<PathBuf>,
134 exclude_dirs: Vec<PathBuf>,
135}
136
137fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
138where
139 D: de::Deserializer<'de>,
140{
141 let name = String::deserialize(de)?;
142 CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {:?}", err)))
117} 143}
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index 943ff92df..a10ade375 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -3,19 +3,19 @@
3use std::{convert::TryFrom, env, ops, path::Path, process::Command}; 3use std::{convert::TryFrom, env, ops, path::Path, process::Command};
4 4
5use anyhow::{bail, format_err, Result}; 5use anyhow::{bail, format_err, Result};
6use paths::{AbsPath, AbsPathBuf};
6use ra_arena::{Arena, Idx}; 7use ra_arena::{Arena, Idx};
7 8
8use crate::output; 9use crate::utf8_stdout;
9use paths::{AbsPath, AbsPathBuf};
10 10
11#[derive(Default, Debug, Clone)] 11#[derive(Default, Debug, Clone, Eq, PartialEq)]
12pub struct Sysroot { 12pub struct Sysroot {
13 crates: Arena<SysrootCrateData>, 13 crates: Arena<SysrootCrateData>,
14} 14}
15 15
16pub type SysrootCrate = Idx<SysrootCrateData>; 16pub type SysrootCrate = Idx<SysrootCrateData>;
17 17
18#[derive(Debug, Clone)] 18#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct SysrootCrateData { 19pub struct SysrootCrateData {
20 pub name: String, 20 pub name: String,
21 pub root: AbsPathBuf, 21 pub root: AbsPathBuf,
@@ -54,6 +54,8 @@ impl Sysroot {
54 let src = get_or_install_rust_src(cargo_toml)?; 54 let src = get_or_install_rust_src(cargo_toml)?;
55 let mut sysroot = Sysroot { crates: Arena::default() }; 55 let mut sysroot = Sysroot { crates: Arena::default() };
56 for name in SYSROOT_CRATES.trim().lines() { 56 for name in SYSROOT_CRATES.trim().lines() {
57 // FIXME: remove this path when 1.47 comes out
58 // https://github.com/rust-lang/rust/pull/73265
57 let root = src.join(format!("lib{}", name)).join("lib.rs"); 59 let root = src.join(format!("lib{}", name)).join("lib.rs");
58 if root.exists() { 60 if root.exists() {
59 sysroot.crates.alloc(SysrootCrateData { 61 sysroot.crates.alloc(SysrootCrateData {
@@ -61,6 +63,15 @@ impl Sysroot {
61 root, 63 root,
62 deps: Vec::new(), 64 deps: Vec::new(),
63 }); 65 });
66 } else {
67 let root = src.join(name).join("src/lib.rs");
68 if root.exists() {
69 sysroot.crates.alloc(SysrootCrateData {
70 name: name.into(),
71 root,
72 deps: Vec::new(),
73 });
74 }
64 } 75 }
65 } 76 }
66 if let Some(std) = sysroot.std() { 77 if let Some(std) = sysroot.std() {
@@ -92,26 +103,40 @@ fn get_or_install_rust_src(cargo_toml: &AbsPath) -> Result<AbsPathBuf> {
92 let current_dir = cargo_toml.parent().unwrap(); 103 let current_dir = cargo_toml.parent().unwrap();
93 let mut rustc = Command::new(ra_toolchain::rustc()); 104 let mut rustc = Command::new(ra_toolchain::rustc());
94 rustc.current_dir(current_dir).args(&["--print", "sysroot"]); 105 rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
95 let rustc_output = output(rustc)?; 106 let stdout = utf8_stdout(rustc)?;
96 let stdout = String::from_utf8(rustc_output.stdout)?;
97 let sysroot_path = AbsPath::assert(Path::new(stdout.trim())); 107 let sysroot_path = AbsPath::assert(Path::new(stdout.trim()));
98 let src_path = sysroot_path.join("lib/rustlib/src/rust/src"); 108 let mut src = get_rust_src(sysroot_path);
99 109 if src.is_none() {
100 if !src_path.exists() {
101 let mut rustup = Command::new(ra_toolchain::rustup()); 110 let mut rustup = Command::new(ra_toolchain::rustup());
102 rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]); 111 rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
103 let _output = output(rustup)?; 112 utf8_stdout(rustup)?;
113 src = get_rust_src(sysroot_path);
104 } 114 }
105 if !src_path.exists() { 115 match src {
106 bail!( 116 Some(r) => Ok(r),
117 None => bail!(
107 "can't load standard library from sysroot\n\ 118 "can't load standard library from sysroot\n\
108 {}\n\ 119 {}\n\
109 (discovered via `rustc --print sysroot`)\n\ 120 (discovered via `rustc --print sysroot`)\n\
110 try running `rustup component add rust-src` or set `RUST_SRC_PATH`", 121 try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
111 src_path.display(), 122 sysroot_path.display(),
112 ) 123 ),
124 }
125}
126
127fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
128 // try the new path first since the old one still exists
129 let mut src_path = sysroot_path.join("lib/rustlib/src/rust/library");
130 if !src_path.exists() {
131 // FIXME: remove this path when 1.47 comes out
132 // https://github.com/rust-lang/rust/pull/73265
133 src_path = sysroot_path.join("lib/rustlib/src/rust/src");
134 }
135 if src_path.exists() {
136 Some(src_path)
137 } else {
138 None
113 } 139 }
114 Ok(src_path)
115} 140}
116 141
117impl SysrootCrateData { 142impl SysrootCrateData {
@@ -121,43 +146,28 @@ impl SysrootCrateData {
121} 146}
122 147
123const SYSROOT_CRATES: &str = " 148const SYSROOT_CRATES: &str = "
124std
125core
126alloc 149alloc
127collections 150core
128libc 151panic_abort
129panic_unwind 152panic_unwind
130proc_macro 153proc_macro
131rustc_unicode 154profiler_builtins
132std_unicode 155rtstartup
133test 156std
134alloc_jemalloc 157stdarch
135alloc_system
136compiler_builtins
137getopts
138panic_unwind
139panic_abort
140rand
141term 158term
142unwind 159test
143build_helper 160unwind";
144rustc_asan
145rustc_lsan
146rustc_msan
147rustc_tsan
148syntax";
149 161
150const STD_DEPS: &str = " 162const STD_DEPS: &str = "
151alloc 163alloc
152alloc_jemalloc
153alloc_system
154core 164core
155panic_abort 165panic_abort
156rand 166panic_unwind
157compiler_builtins 167profiler_builtins
158unwind 168rtstartup
159rustc_asan 169proc_macro
160rustc_lsan 170stdarch
161rustc_msan 171term
162rustc_tsan 172test
163build_helper"; 173unwind";
diff --git a/crates/ra_ssr/Cargo.toml b/crates/ra_ssr/Cargo.toml
index 3c2f15a83..84e4b171e 100644
--- a/crates/ra_ssr/Cargo.toml
+++ b/crates/ra_ssr/Cargo.toml
@@ -17,3 +17,7 @@ ra_db = { path = "../ra_db" }
17ra_ide_db = { path = "../ra_ide_db" } 17ra_ide_db = { path = "../ra_ide_db" }
18hir = { path = "../ra_hir", package = "ra_hir" } 18hir = { path = "../ra_hir", package = "ra_hir" }
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20test_utils = { path = "../test_utils" }
21
22[dev-dependencies]
23expect = { path = "../expect" }
diff --git a/crates/ra_ssr/src/errors.rs b/crates/ra_ssr/src/errors.rs
new file mode 100644
index 000000000..c02bacae6
--- /dev/null
+++ b/crates/ra_ssr/src/errors.rs
@@ -0,0 +1,29 @@
1//! Code relating to errors produced by SSR.
2
3/// Constructs an SsrError taking arguments like the format macro.
4macro_rules! _error {
5 ($fmt:expr) => {$crate::SsrError::new(format!($fmt))};
6 ($fmt:expr, $($arg:tt)+) => {$crate::SsrError::new(format!($fmt, $($arg)+))}
7}
8pub(crate) use _error as error;
9
10/// Returns from the current function with an error, supplied by arguments as for format!
11macro_rules! _bail {
12 ($($tokens:tt)*) => {return Err(crate::errors::error!($($tokens)*))}
13}
14pub(crate) use _bail as bail;
15
16#[derive(Debug, PartialEq)]
17pub struct SsrError(pub(crate) String);
18
19impl std::fmt::Display for SsrError {
20 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21 write!(f, "Parse error: {}", self.0)
22 }
23}
24
25impl SsrError {
26 pub(crate) fn new(message: impl Into<String>) -> SsrError {
27 SsrError(message.into())
28 }
29}
diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs
index e148f4564..73abfecb2 100644
--- a/crates/ra_ssr/src/lib.rs
+++ b/crates/ra_ssr/src/lib.rs
@@ -4,136 +4,288 @@
4//! based on a template. 4//! based on a template.
5 5
6mod matching; 6mod matching;
7mod nester;
7mod parsing; 8mod parsing;
8mod replacing; 9mod replacing;
10mod resolving;
11mod search;
12#[macro_use]
13mod errors;
9#[cfg(test)] 14#[cfg(test)]
10mod tests; 15mod tests;
11 16
12use crate::matching::Match; 17use crate::errors::bail;
18pub use crate::errors::SsrError;
19pub use crate::matching::Match;
20use crate::matching::MatchFailureReason;
13use hir::Semantics; 21use hir::Semantics;
14use ra_db::{FileId, FileRange}; 22use ra_db::{FileId, FilePosition, FileRange};
15use ra_syntax::{ast, AstNode, SmolStr, SyntaxNode}; 23use ra_ide_db::source_change::SourceFileEdit;
16use ra_text_edit::TextEdit; 24use ra_syntax::{ast, AstNode, SyntaxNode, TextRange};
25use resolving::ResolvedRule;
17use rustc_hash::FxHashMap; 26use rustc_hash::FxHashMap;
18 27
19// A structured search replace rule. Create by calling `parse` on a str. 28// A structured search replace rule. Create by calling `parse` on a str.
20#[derive(Debug)] 29#[derive(Debug)]
21pub struct SsrRule { 30pub struct SsrRule {
22 /// A structured pattern that we're searching for. 31 /// A structured pattern that we're searching for.
23 pattern: SsrPattern, 32 pattern: parsing::RawPattern,
24 /// What we'll replace it with. 33 /// What we'll replace it with.
25 template: parsing::SsrTemplate, 34 template: parsing::RawPattern,
35 parsed_rules: Vec<parsing::ParsedRule>,
26} 36}
27 37
28#[derive(Debug)] 38#[derive(Debug)]
29struct SsrPattern { 39pub struct SsrPattern {
30 raw: parsing::RawSearchPattern, 40 raw: parsing::RawPattern,
31 /// Placeholders keyed by the stand-in ident that we use in Rust source code. 41 parsed_rules: Vec<parsing::ParsedRule>,
32 placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
33 // We store our search pattern, parsed as each different kind of thing we can look for. As we
34 // traverse the AST, we get the appropriate one of these for the type of node we're on. For many
35 // search patterns, only some of these will be present.
36 expr: Option<SyntaxNode>,
37 type_ref: Option<SyntaxNode>,
38 item: Option<SyntaxNode>,
39 path: Option<SyntaxNode>,
40 pattern: Option<SyntaxNode>,
41} 42}
42 43
43#[derive(Debug, PartialEq)]
44pub struct SsrError(String);
45
46#[derive(Debug, Default)] 44#[derive(Debug, Default)]
47pub struct SsrMatches { 45pub struct SsrMatches {
48 matches: Vec<Match>, 46 pub matches: Vec<Match>,
49} 47}
50 48
51/// Searches a crate for pattern matches and possibly replaces them with something else. 49/// Searches a crate for pattern matches and possibly replaces them with something else.
52pub struct MatchFinder<'db> { 50pub struct MatchFinder<'db> {
53 /// Our source of information about the user's code. 51 /// Our source of information about the user's code.
54 sema: Semantics<'db, ra_ide_db::RootDatabase>, 52 sema: Semantics<'db, ra_ide_db::RootDatabase>,
55 rules: Vec<SsrRule>, 53 rules: Vec<ResolvedRule>,
54 resolution_scope: resolving::ResolutionScope<'db>,
55 restrict_ranges: Vec<FileRange>,
56} 56}
57 57
58impl<'db> MatchFinder<'db> { 58impl<'db> MatchFinder<'db> {
59 pub fn new(db: &'db ra_ide_db::RootDatabase) -> MatchFinder<'db> { 59 /// Constructs a new instance where names will be looked up as if they appeared at
60 MatchFinder { sema: Semantics::new(db), rules: Vec::new() } 60 /// `lookup_context`.
61 pub fn in_context(
62 db: &'db ra_ide_db::RootDatabase,
63 lookup_context: FilePosition,
64 mut restrict_ranges: Vec<FileRange>,
65 ) -> MatchFinder<'db> {
66 restrict_ranges.retain(|range| !range.range.is_empty());
67 let sema = Semantics::new(db);
68 let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context);
69 MatchFinder {
70 sema: Semantics::new(db),
71 rules: Vec::new(),
72 resolution_scope,
73 restrict_ranges,
74 }
61 } 75 }
62 76
63 pub fn add_rule(&mut self, rule: SsrRule) { 77 /// Constructs an instance using the start of the first file in `db` as the lookup context.
64 self.rules.push(rule); 78 pub fn at_first_file(db: &'db ra_ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
79 use ra_db::SourceDatabaseExt;
80 use ra_ide_db::symbol_index::SymbolsDatabase;
81 if let Some(first_file_id) = db
82 .local_roots()
83 .iter()
84 .next()
85 .and_then(|root| db.source_root(root.clone()).iter().next())
86 {
87 Ok(MatchFinder::in_context(
88 db,
89 FilePosition { file_id: first_file_id, offset: 0.into() },
90 vec![],
91 ))
92 } else {
93 bail!("No files to search");
94 }
65 } 95 }
66 96
67 pub fn edits_for_file(&self, file_id: FileId) -> Option<TextEdit> { 97 /// Adds a rule to be applied. The order in which rules are added matters. Earlier rules take
68 let matches = self.find_matches_in_file(file_id); 98 /// precedence. If a node is matched by an earlier rule, then later rules won't be permitted to
69 if matches.matches.is_empty() { 99 /// match to it.
70 None 100 pub fn add_rule(&mut self, rule: SsrRule) -> Result<(), SsrError> {
71 } else { 101 for parsed_rule in rule.parsed_rules {
72 use ra_db::SourceDatabaseExt; 102 self.rules.push(ResolvedRule::new(
73 Some(replacing::matches_to_edit(&matches, &self.sema.db.file_text(file_id))) 103 parsed_rule,
104 &self.resolution_scope,
105 self.rules.len(),
106 )?);
74 } 107 }
108 Ok(())
75 } 109 }
76 110
77 fn find_matches_in_file(&self, file_id: FileId) -> SsrMatches { 111 /// Finds matches for all added rules and returns edits for all found matches.
112 pub fn edits(&self) -> Vec<SourceFileEdit> {
113 use ra_db::SourceDatabaseExt;
114 let mut matches_by_file = FxHashMap::default();
115 for m in self.matches().matches {
116 matches_by_file
117 .entry(m.range.file_id)
118 .or_insert_with(|| SsrMatches::default())
119 .matches
120 .push(m);
121 }
122 let mut edits = vec![];
123 for (file_id, matches) in matches_by_file {
124 let edit =
125 replacing::matches_to_edit(&matches, &self.sema.db.file_text(file_id), &self.rules);
126 edits.push(SourceFileEdit { file_id, edit });
127 }
128 edits
129 }
130
131 /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you
132 /// intend to do replacement, use `add_rule` instead.
133 pub fn add_search_pattern(&mut self, pattern: SsrPattern) -> Result<(), SsrError> {
134 for parsed_rule in pattern.parsed_rules {
135 self.rules.push(ResolvedRule::new(
136 parsed_rule,
137 &self.resolution_scope,
138 self.rules.len(),
139 )?);
140 }
141 Ok(())
142 }
143
144 /// Returns matches for all added rules.
145 pub fn matches(&self) -> SsrMatches {
146 let mut matches = Vec::new();
147 let mut usage_cache = search::UsageCache::default();
148 for rule in &self.rules {
149 self.find_matches_for_rule(rule, &mut usage_cache, &mut matches);
150 }
151 nester::nest_and_remove_collisions(matches, &self.sema)
152 }
153
154 /// Finds all nodes in `file_id` whose text is exactly equal to `snippet` and attempts to match
155 /// them, while recording reasons why they don't match. This API is useful for command
156 /// line-based debugging where providing a range is difficult.
157 pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
158 use ra_db::SourceDatabaseExt;
78 let file = self.sema.parse(file_id); 159 let file = self.sema.parse(file_id);
79 let code = file.syntax(); 160 let mut res = Vec::new();
80 let mut matches = SsrMatches::default(); 161 let file_text = self.sema.db.file_text(file_id);
81 self.find_matches(code, &None, &mut matches); 162 let mut remaining_text = file_text.as_str();
82 matches 163 let mut base = 0;
164 let len = snippet.len() as u32;
165 while let Some(offset) = remaining_text.find(snippet) {
166 let start = base + offset as u32;
167 let end = start + len;
168 self.output_debug_for_nodes_at_range(
169 file.syntax(),
170 FileRange { file_id, range: TextRange::new(start.into(), end.into()) },
171 &None,
172 &mut res,
173 );
174 remaining_text = &remaining_text[offset + snippet.len()..];
175 base = end;
176 }
177 res
83 } 178 }
84 179
85 fn find_matches( 180 fn output_debug_for_nodes_at_range(
86 &self, 181 &self,
87 code: &SyntaxNode, 182 node: &SyntaxNode,
183 range: FileRange,
88 restrict_range: &Option<FileRange>, 184 restrict_range: &Option<FileRange>,
89 matches_out: &mut SsrMatches, 185 out: &mut Vec<MatchDebugInfo>,
90 ) { 186 ) {
91 for rule in &self.rules { 187 for node in node.children() {
92 if let Ok(mut m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) { 188 let node_range = self.sema.original_range(&node);
93 // Continue searching in each of our placeholders. 189 if node_range.file_id != range.file_id || !node_range.range.contains_range(range.range)
94 for placeholder_value in m.placeholder_values.values_mut() { 190 {
95 if let Some(placeholder_node) = &placeholder_value.node { 191 continue;
96 // Don't search our placeholder if it's the entire matched node, otherwise we'd 192 }
97 // find the same match over and over until we got a stack overflow. 193 if node_range.range == range.range {
98 if placeholder_node != code { 194 for rule in &self.rules {
99 self.find_matches( 195 // For now we ignore rules that have a different kind than our node, otherwise
100 placeholder_node, 196 // we get lots of noise. If at some point we add support for restricting rules
101 restrict_range, 197 // to a particular kind of thing (e.g. only match type references), then we can
102 &mut placeholder_value.inner_matches, 198 // relax this. We special-case expressions, since function calls can match
103 ); 199 // method calls.
104 } 200 if rule.pattern.node.kind() != node.kind()
201 && !(ast::Expr::can_cast(rule.pattern.node.kind())
202 && ast::Expr::can_cast(node.kind()))
203 {
204 continue;
105 } 205 }
206 out.push(MatchDebugInfo {
207 matched: matching::get_match(true, rule, &node, restrict_range, &self.sema)
208 .map_err(|e| MatchFailureReason {
209 reason: e.reason.unwrap_or_else(|| {
210 "Match failed, but no reason was given".to_owned()
211 }),
212 }),
213 pattern: rule.pattern.node.clone(),
214 node: node.clone(),
215 });
106 } 216 }
107 matches_out.matches.push(m); 217 } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) {
108 return; 218 if let Some(expanded) = self.sema.expand(&macro_call) {
109 } 219 if let Some(tt) = macro_call.token_tree() {
110 } 220 self.output_debug_for_nodes_at_range(
111 // If we've got a macro call, we already tried matching it pre-expansion, which is the only 221 &expanded,
112 // way to match the whole macro, now try expanding it and matching the expansion. 222 range,
113 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) { 223 &Some(self.sema.original_range(tt.syntax())),
114 if let Some(expanded) = self.sema.expand(&macro_call) { 224 out,
115 if let Some(tt) = macro_call.token_tree() { 225 );
116 // When matching within a macro expansion, we only want to allow matches of 226 }
117 // nodes that originated entirely from within the token tree of the macro call.
118 // i.e. we don't want to match something that came from the macro itself.
119 self.find_matches(
120 &expanded,
121 &Some(self.sema.original_range(tt.syntax())),
122 matches_out,
123 );
124 } 227 }
125 } 228 }
229 self.output_debug_for_nodes_at_range(&node, range, restrict_range, out);
126 } 230 }
127 for child in code.children() { 231 }
128 self.find_matches(&child, restrict_range, matches_out); 232}
233
234pub struct MatchDebugInfo {
235 node: SyntaxNode,
236 /// Our search pattern parsed as an expression or item, etc
237 pattern: SyntaxNode,
238 matched: Result<Match, MatchFailureReason>,
239}
240
241impl std::fmt::Debug for MatchDebugInfo {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 match &self.matched {
244 Ok(_) => writeln!(f, "Node matched")?,
245 Err(reason) => writeln!(f, "Node failed to match because: {}", reason.reason)?,
129 } 246 }
247 writeln!(
248 f,
249 "============ AST ===========\n\
250 {:#?}",
251 self.node
252 )?;
253 writeln!(f, "========= PATTERN ==========")?;
254 writeln!(f, "{:#?}", self.pattern)?;
255 writeln!(f, "============================")?;
256 Ok(())
130 } 257 }
131} 258}
132 259
133impl std::fmt::Display for SsrError { 260impl SsrMatches {
134 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 261 /// Returns `self` with any nested matches removed and made into top-level matches.
135 write!(f, "Parse error: {}", self.0) 262 pub fn flattened(self) -> SsrMatches {
263 let mut out = SsrMatches::default();
264 self.flatten_into(&mut out);
265 out
266 }
267
268 fn flatten_into(self, out: &mut SsrMatches) {
269 for mut m in self.matches {
270 for p in m.placeholder_values.values_mut() {
271 std::mem::replace(&mut p.inner_matches, SsrMatches::default()).flatten_into(out);
272 }
273 out.matches.push(m);
274 }
275 }
276}
277
278impl Match {
279 pub fn matched_text(&self) -> String {
280 self.matched_node.text().to_string()
136 } 281 }
137} 282}
138 283
139impl std::error::Error for SsrError {} 284impl std::error::Error for SsrError {}
285
286#[cfg(test)]
287impl MatchDebugInfo {
288 pub(crate) fn match_failure_reason(&self) -> Option<&str> {
289 self.matched.as_ref().err().map(|r| r.reason.as_str())
290 }
291}
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index bb87bda43..74e15c631 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -2,17 +2,17 @@
2//! process of matching, placeholder values are recorded. 2//! process of matching, placeholder values are recorded.
3 3
4use crate::{ 4use crate::{
5 parsing::{Placeholder, SsrTemplate}, 5 parsing::{Constraint, NodeKind, Placeholder},
6 SsrMatches, SsrPattern, SsrRule, 6 resolving::{ResolvedPattern, ResolvedRule},
7 SsrMatches,
7}; 8};
8use hir::Semantics; 9use hir::Semantics;
9use ra_db::FileRange; 10use ra_db::FileRange;
10use ra_syntax::ast::{AstNode, AstToken}; 11use ra_syntax::ast::{AstNode, AstToken};
11use ra_syntax::{ 12use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken};
12 ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
13};
14use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
15use std::{cell::Cell, iter::Peekable}; 14use std::{cell::Cell, iter::Peekable};
15use test_utils::mark;
16 16
17// Creates a match error. If we're currently attempting to match some code that we thought we were 17// Creates a match error. If we're currently attempting to match some code that we thought we were
18// going to match, as indicated by the --debug-snippet flag, then populate the reason field. 18// going to match, as indicated by the --debug-snippet flag, then populate the reason field.
@@ -44,14 +44,16 @@ macro_rules! fail_match {
44 44
45/// Information about a match that was found. 45/// Information about a match that was found.
46#[derive(Debug)] 46#[derive(Debug)]
47pub(crate) struct Match { 47pub struct Match {
48 pub(crate) range: TextRange, 48 pub(crate) range: FileRange,
49 pub(crate) matched_node: SyntaxNode, 49 pub(crate) matched_node: SyntaxNode,
50 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>, 50 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>,
51 pub(crate) ignored_comments: Vec<ast::Comment>, 51 pub(crate) ignored_comments: Vec<ast::Comment>,
52 // A copy of the template for the rule that produced this match. We store this on the match for 52 pub(crate) rule_index: usize,
53 // if/when we do replacement. 53 /// The depth of matched_node.
54 pub(crate) template: SsrTemplate, 54 pub(crate) depth: usize,
55 // Each path in the template rendered for the module in which the match was found.
56 pub(crate) rendered_template_paths: FxHashMap<SyntaxNode, hir::ModPath>,
55} 57}
56 58
57/// Represents a `$var` in an SSR query. 59/// Represents a `$var` in an SSR query.
@@ -87,64 +89,67 @@ pub(crate) struct MatchFailed {
87/// parent module, we don't populate nested matches. 89/// parent module, we don't populate nested matches.
88pub(crate) fn get_match( 90pub(crate) fn get_match(
89 debug_active: bool, 91 debug_active: bool,
90 rule: &SsrRule, 92 rule: &ResolvedRule,
91 code: &SyntaxNode, 93 code: &SyntaxNode,
92 restrict_range: &Option<FileRange>, 94 restrict_range: &Option<FileRange>,
93 sema: &Semantics<ra_ide_db::RootDatabase>, 95 sema: &Semantics<ra_ide_db::RootDatabase>,
94) -> Result<Match, MatchFailed> { 96) -> Result<Match, MatchFailed> {
95 record_match_fails_reasons_scope(debug_active, || { 97 record_match_fails_reasons_scope(debug_active, || {
96 MatchState::try_match(rule, code, restrict_range, sema) 98 Matcher::try_match(rule, code, restrict_range, sema)
97 }) 99 })
98} 100}
99 101
100/// Inputs to matching. This cannot be part of `MatchState`, since we mutate `MatchState` and in at 102/// Checks if our search pattern matches a particular node of the AST.
101/// least one case need to hold a borrow of a placeholder from the input pattern while calling a 103struct Matcher<'db, 'sema> {
102/// mutable `MatchState` method.
103struct MatchInputs<'pattern> {
104 ssr_pattern: &'pattern SsrPattern,
105}
106
107/// State used while attempting to match our search pattern against a particular node of the AST.
108struct MatchState<'db, 'sema> {
109 sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>, 104 sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>,
110 /// If any placeholders come from anywhere outside of this range, then the match will be 105 /// If any placeholders come from anywhere outside of this range, then the match will be
111 /// rejected. 106 /// rejected.
112 restrict_range: Option<FileRange>, 107 restrict_range: Option<FileRange>,
113 /// The match that we're building. We do two passes for a successful match. On the first pass, 108 rule: &'sema ResolvedRule,
114 /// this is None so that we can avoid doing things like storing copies of what placeholders 109}
115 /// matched to. If that pass succeeds, then we do a second pass where we collect those details. 110
116 /// This means that if we have a pattern like `$a.foo()` we won't do an insert into the 111/// Which phase of matching we're currently performing. We do two phases because most attempted
117 /// placeholders map for every single method call in the codebase. Instead we'll discard all the 112/// matches will fail and it means we can defer more expensive checks to the second phase.
118 /// method calls that aren't calls to `foo` on the first pass and only insert into the 113enum Phase<'a> {
119 /// placeholders map on the second pass. Likewise for ignored comments. 114 /// On the first phase, we perform cheap checks. No state is mutated and nothing is recorded.
120 match_out: Option<Match>, 115 First,
116 /// On the second phase, we construct the `Match`. Things like what placeholders bind to is
117 /// recorded.
118 Second(&'a mut Match),
121} 119}
122 120
123impl<'db, 'sema> MatchState<'db, 'sema> { 121impl<'db, 'sema> Matcher<'db, 'sema> {
124 fn try_match( 122 fn try_match(
125 rule: &SsrRule, 123 rule: &ResolvedRule,
126 code: &SyntaxNode, 124 code: &SyntaxNode,
127 restrict_range: &Option<FileRange>, 125 restrict_range: &Option<FileRange>,
128 sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>, 126 sema: &'sema Semantics<'db, ra_ide_db::RootDatabase>,
129 ) -> Result<Match, MatchFailed> { 127 ) -> Result<Match, MatchFailed> {
130 let mut match_state = 128 let match_state = Matcher { sema, restrict_range: restrict_range.clone(), rule };
131 MatchState { sema, restrict_range: restrict_range.clone(), match_out: None };
132 let match_inputs = MatchInputs { ssr_pattern: &rule.pattern };
133 let pattern_tree = rule.pattern.tree_for_kind(code.kind())?;
134 // First pass at matching, where we check that node types and idents match. 129 // First pass at matching, where we check that node types and idents match.
135 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?; 130 match_state.attempt_match_node(&mut Phase::First, &rule.pattern.node, code)?;
136 match_state.validate_range(&sema.original_range(code))?; 131 match_state.validate_range(&sema.original_range(code))?;
137 match_state.match_out = Some(Match { 132 let mut the_match = Match {
138 range: sema.original_range(code).range, 133 range: sema.original_range(code),
139 matched_node: code.clone(), 134 matched_node: code.clone(),
140 placeholder_values: FxHashMap::default(), 135 placeholder_values: FxHashMap::default(),
141 ignored_comments: Vec::new(), 136 ignored_comments: Vec::new(),
142 template: rule.template.clone(), 137 rule_index: rule.index,
143 }); 138 depth: 0,
139 rendered_template_paths: FxHashMap::default(),
140 };
144 // Second matching pass, where we record placeholder matches, ignored comments and maybe do 141 // Second matching pass, where we record placeholder matches, ignored comments and maybe do
145 // any other more expensive checks that we didn't want to do on the first pass. 142 // any other more expensive checks that we didn't want to do on the first pass.
146 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?; 143 match_state.attempt_match_node(
147 Ok(match_state.match_out.unwrap()) 144 &mut Phase::Second(&mut the_match),
145 &rule.pattern.node,
146 code,
147 )?;
148 the_match.depth = sema.ancestors_with_macros(the_match.matched_node.clone()).count();
149 if let Some(template) = &rule.template {
150 the_match.render_template_paths(template, sema)?;
151 }
152 Ok(the_match)
148 } 153 }
149 154
150 /// Checks that `range` is within the permitted range if any. This is applicable when we're 155 /// Checks that `range` is within the permitted range if any. This is applicable when we're
@@ -162,79 +167,91 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
162 } 167 }
163 168
164 fn attempt_match_node( 169 fn attempt_match_node(
165 &mut self, 170 &self,
166 match_inputs: &MatchInputs, 171 phase: &mut Phase,
167 pattern: &SyntaxNode, 172 pattern: &SyntaxNode,
168 code: &SyntaxNode, 173 code: &SyntaxNode,
169 ) -> Result<(), MatchFailed> { 174 ) -> Result<(), MatchFailed> {
170 // Handle placeholders. 175 // Handle placeholders.
171 if let Some(placeholder) = 176 if let Some(placeholder) = self.get_placeholder(&SyntaxElement::Node(pattern.clone())) {
172 match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone())) 177 for constraint in &placeholder.constraints {
173 { 178 self.check_constraint(constraint, code)?;
174 if self.match_out.is_none() {
175 return Ok(());
176 } 179 }
177 let original_range = self.sema.original_range(code); 180 if let Phase::Second(matches_out) = phase {
178 // We validated the range for the node when we started the match, so the placeholder 181 let original_range = self.sema.original_range(code);
179 // probably can't fail range validation, but just to be safe... 182 // We validated the range for the node when we started the match, so the placeholder
180 self.validate_range(&original_range)?; 183 // probably can't fail range validation, but just to be safe...
181 if let Some(match_out) = &mut self.match_out { 184 self.validate_range(&original_range)?;
182 match_out.placeholder_values.insert( 185 matches_out.placeholder_values.insert(
183 Var(placeholder.ident.to_string()), 186 Var(placeholder.ident.to_string()),
184 PlaceholderMatch::new(code, original_range), 187 PlaceholderMatch::new(code, original_range),
185 ); 188 );
186 } 189 }
187 return Ok(()); 190 return Ok(());
188 } 191 }
189 // Non-placeholders. 192 // We allow a UFCS call to match a method call, provided they resolve to the same function.
193 if let Some(pattern_function) = self.rule.pattern.ufcs_function_calls.get(pattern) {
194 if let (Some(pattern), Some(code)) =
195 (ast::CallExpr::cast(pattern.clone()), ast::MethodCallExpr::cast(code.clone()))
196 {
197 return self.attempt_match_ufcs(phase, &pattern, &code, *pattern_function);
198 }
199 }
190 if pattern.kind() != code.kind() { 200 if pattern.kind() != code.kind() {
191 fail_match!("Pattern had a {:?}, code had {:?}", pattern.kind(), code.kind()); 201 fail_match!(
202 "Pattern had `{}` ({:?}), code had `{}` ({:?})",
203 pattern.text(),
204 pattern.kind(),
205 code.text(),
206 code.kind()
207 );
192 } 208 }
193 // Some kinds of nodes have special handling. For everything else, we fall back to default 209 // Some kinds of nodes have special handling. For everything else, we fall back to default
194 // matching. 210 // matching.
195 match code.kind() { 211 match code.kind() {
196 SyntaxKind::RECORD_FIELD_LIST => { 212 SyntaxKind::RECORD_EXPR_FIELD_LIST => {
197 self.attempt_match_record_field_list(match_inputs, pattern, code) 213 self.attempt_match_record_field_list(phase, pattern, code)
198 } 214 }
199 SyntaxKind::TOKEN_TREE => self.attempt_match_token_tree(match_inputs, pattern, code), 215 SyntaxKind::TOKEN_TREE => self.attempt_match_token_tree(phase, pattern, code),
200 _ => self.attempt_match_node_children(match_inputs, pattern, code), 216 SyntaxKind::PATH => self.attempt_match_path(phase, pattern, code),
217 _ => self.attempt_match_node_children(phase, pattern, code),
201 } 218 }
202 } 219 }
203 220
204 fn attempt_match_node_children( 221 fn attempt_match_node_children(
205 &mut self, 222 &self,
206 match_inputs: &MatchInputs, 223 phase: &mut Phase,
207 pattern: &SyntaxNode, 224 pattern: &SyntaxNode,
208 code: &SyntaxNode, 225 code: &SyntaxNode,
209 ) -> Result<(), MatchFailed> { 226 ) -> Result<(), MatchFailed> {
210 self.attempt_match_sequences( 227 self.attempt_match_sequences(
211 match_inputs, 228 phase,
212 PatternIterator::new(pattern), 229 PatternIterator::new(pattern),
213 code.children_with_tokens(), 230 code.children_with_tokens(),
214 ) 231 )
215 } 232 }
216 233
217 fn attempt_match_sequences( 234 fn attempt_match_sequences(
218 &mut self, 235 &self,
219 match_inputs: &MatchInputs, 236 phase: &mut Phase,
220 pattern_it: PatternIterator, 237 pattern_it: PatternIterator,
221 mut code_it: SyntaxElementChildren, 238 mut code_it: SyntaxElementChildren,
222 ) -> Result<(), MatchFailed> { 239 ) -> Result<(), MatchFailed> {
223 let mut pattern_it = pattern_it.peekable(); 240 let mut pattern_it = pattern_it.peekable();
224 loop { 241 loop {
225 match self.next_non_trivial(&mut code_it) { 242 match phase.next_non_trivial(&mut code_it) {
226 None => { 243 None => {
227 if let Some(p) = pattern_it.next() { 244 if let Some(p) = pattern_it.next() {
228 fail_match!("Part of the pattern was unmached: {:?}", p); 245 fail_match!("Part of the pattern was unmatched: {:?}", p);
229 } 246 }
230 return Ok(()); 247 return Ok(());
231 } 248 }
232 Some(SyntaxElement::Token(c)) => { 249 Some(SyntaxElement::Token(c)) => {
233 self.attempt_match_token(&mut pattern_it, &c)?; 250 self.attempt_match_token(phase, &mut pattern_it, &c)?;
234 } 251 }
235 Some(SyntaxElement::Node(c)) => match pattern_it.next() { 252 Some(SyntaxElement::Node(c)) => match pattern_it.next() {
236 Some(SyntaxElement::Node(p)) => { 253 Some(SyntaxElement::Node(p)) => {
237 self.attempt_match_node(match_inputs, &p, &c)?; 254 self.attempt_match_node(phase, &p, &c)?;
238 } 255 }
239 Some(p) => fail_match!("Pattern wanted '{}', code has {}", p, c.text()), 256 Some(p) => fail_match!("Pattern wanted '{}', code has {}", p, c.text()),
240 None => fail_match!("Pattern reached end, code has {}", c.text()), 257 None => fail_match!("Pattern reached end, code has {}", c.text()),
@@ -244,11 +261,12 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
244 } 261 }
245 262
246 fn attempt_match_token( 263 fn attempt_match_token(
247 &mut self, 264 &self,
265 phase: &mut Phase,
248 pattern: &mut Peekable<PatternIterator>, 266 pattern: &mut Peekable<PatternIterator>,
249 code: &ra_syntax::SyntaxToken, 267 code: &ra_syntax::SyntaxToken,
250 ) -> Result<(), MatchFailed> { 268 ) -> Result<(), MatchFailed> {
251 self.record_ignored_comments(code); 269 phase.record_ignored_comments(code);
252 // Ignore whitespace and comments. 270 // Ignore whitespace and comments.
253 if code.kind().is_trivia() { 271 if code.kind().is_trivia() {
254 return Ok(()); 272 return Ok(());
@@ -294,18 +312,94 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
294 Ok(()) 312 Ok(())
295 } 313 }
296 314
315 fn check_constraint(
316 &self,
317 constraint: &Constraint,
318 code: &SyntaxNode,
319 ) -> Result<(), MatchFailed> {
320 match constraint {
321 Constraint::Kind(kind) => {
322 kind.matches(code)?;
323 }
324 Constraint::Not(sub) => {
325 if self.check_constraint(&*sub, code).is_ok() {
326 fail_match!("Constraint {:?} failed for '{}'", constraint, code.text());
327 }
328 }
329 }
330 Ok(())
331 }
332
333 /// Paths are matched based on whether they refer to the same thing, even if they're written
334 /// differently.
335 fn attempt_match_path(
336 &self,
337 phase: &mut Phase,
338 pattern: &SyntaxNode,
339 code: &SyntaxNode,
340 ) -> Result<(), MatchFailed> {
341 if let Some(pattern_resolved) = self.rule.pattern.resolved_paths.get(pattern) {
342 let pattern_path = ast::Path::cast(pattern.clone()).unwrap();
343 let code_path = ast::Path::cast(code.clone()).unwrap();
344 if let (Some(pattern_segment), Some(code_segment)) =
345 (pattern_path.segment(), code_path.segment())
346 {
347 // Match everything within the segment except for the name-ref, which is handled
348 // separately via comparing what the path resolves to below.
349 self.attempt_match_opt(
350 phase,
351 pattern_segment.type_arg_list(),
352 code_segment.type_arg_list(),
353 )?;
354 self.attempt_match_opt(
355 phase,
356 pattern_segment.param_list(),
357 code_segment.param_list(),
358 )?;
359 }
360 if matches!(phase, Phase::Second(_)) {
361 let resolution = self
362 .sema
363 .resolve_path(&code_path)
364 .ok_or_else(|| match_error!("Failed to resolve path `{}`", code.text()))?;
365 if pattern_resolved.resolution != resolution {
366 fail_match!("Pattern had path `{}` code had `{}`", pattern.text(), code.text());
367 }
368 }
369 } else {
370 return self.attempt_match_node_children(phase, pattern, code);
371 }
372 Ok(())
373 }
374
375 fn attempt_match_opt<T: AstNode>(
376 &self,
377 phase: &mut Phase,
378 pattern: Option<T>,
379 code: Option<T>,
380 ) -> Result<(), MatchFailed> {
381 match (pattern, code) {
382 (Some(p), Some(c)) => self.attempt_match_node(phase, &p.syntax(), &c.syntax()),
383 (None, None) => Ok(()),
384 (Some(p), None) => fail_match!("Pattern `{}` had nothing to match", p.syntax().text()),
385 (None, Some(c)) => {
386 fail_match!("Nothing in pattern to match code `{}`", c.syntax().text())
387 }
388 }
389 }
390
297 /// We want to allow the records to match in any order, so we have special matching logic for 391 /// We want to allow the records to match in any order, so we have special matching logic for
298 /// them. 392 /// them.
299 fn attempt_match_record_field_list( 393 fn attempt_match_record_field_list(
300 &mut self, 394 &self,
301 match_inputs: &MatchInputs, 395 phase: &mut Phase,
302 pattern: &SyntaxNode, 396 pattern: &SyntaxNode,
303 code: &SyntaxNode, 397 code: &SyntaxNode,
304 ) -> Result<(), MatchFailed> { 398 ) -> Result<(), MatchFailed> {
305 // Build a map keyed by field name. 399 // Build a map keyed by field name.
306 let mut fields_by_name = FxHashMap::default(); 400 let mut fields_by_name = FxHashMap::default();
307 for child in code.children() { 401 for child in code.children() {
308 if let Some(record) = ast::RecordField::cast(child.clone()) { 402 if let Some(record) = ast::RecordExprField::cast(child.clone()) {
309 if let Some(name) = record.field_name() { 403 if let Some(name) = record.field_name() {
310 fields_by_name.insert(name.text().clone(), child.clone()); 404 fields_by_name.insert(name.text().clone(), child.clone());
311 } 405 }
@@ -314,11 +408,11 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
314 for p in pattern.children_with_tokens() { 408 for p in pattern.children_with_tokens() {
315 if let SyntaxElement::Node(p) = p { 409 if let SyntaxElement::Node(p) = p {
316 if let Some(name_element) = p.first_child_or_token() { 410 if let Some(name_element) = p.first_child_or_token() {
317 if match_inputs.get_placeholder(&name_element).is_some() { 411 if self.get_placeholder(&name_element).is_some() {
318 // If the pattern is using placeholders for field names then order 412 // If the pattern is using placeholders for field names then order
319 // independence doesn't make sense. Fall back to regular ordered 413 // independence doesn't make sense. Fall back to regular ordered
320 // matching. 414 // matching.
321 return self.attempt_match_node_children(match_inputs, pattern, code); 415 return self.attempt_match_node_children(phase, pattern, code);
322 } 416 }
323 if let Some(ident) = only_ident(name_element) { 417 if let Some(ident) = only_ident(name_element) {
324 let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| { 418 let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| {
@@ -327,7 +421,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
327 ident 421 ident
328 ) 422 )
329 })?; 423 })?;
330 self.attempt_match_node(match_inputs, &p, &code_record)?; 424 self.attempt_match_node(phase, &p, &code_record)?;
331 } 425 }
332 } 426 }
333 } 427 }
@@ -347,16 +441,15 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
347 /// pattern matches the macro invocation. For matches within the macro call, we'll already have 441 /// pattern matches the macro invocation. For matches within the macro call, we'll already have
348 /// expanded the macro. 442 /// expanded the macro.
349 fn attempt_match_token_tree( 443 fn attempt_match_token_tree(
350 &mut self, 444 &self,
351 match_inputs: &MatchInputs, 445 phase: &mut Phase,
352 pattern: &SyntaxNode, 446 pattern: &SyntaxNode,
353 code: &ra_syntax::SyntaxNode, 447 code: &ra_syntax::SyntaxNode,
354 ) -> Result<(), MatchFailed> { 448 ) -> Result<(), MatchFailed> {
355 let mut pattern = PatternIterator::new(pattern).peekable(); 449 let mut pattern = PatternIterator::new(pattern).peekable();
356 let mut children = code.children_with_tokens(); 450 let mut children = code.children_with_tokens();
357 while let Some(child) = children.next() { 451 while let Some(child) = children.next() {
358 if let Some(placeholder) = pattern.peek().and_then(|p| match_inputs.get_placeholder(p)) 452 if let Some(placeholder) = pattern.peek().and_then(|p| self.get_placeholder(p)) {
359 {
360 pattern.next(); 453 pattern.next();
361 let next_pattern_token = pattern 454 let next_pattern_token = pattern
362 .peek() 455 .peek()
@@ -382,7 +475,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
382 if Some(first_token.to_string()) == next_pattern_token { 475 if Some(first_token.to_string()) == next_pattern_token {
383 if let Some(SyntaxElement::Node(p)) = pattern.next() { 476 if let Some(SyntaxElement::Node(p)) = pattern.next() {
384 // We have a subtree that starts with the next token in our pattern. 477 // We have a subtree that starts with the next token in our pattern.
385 self.attempt_match_token_tree(match_inputs, &p, &n)?; 478 self.attempt_match_token_tree(phase, &p, &n)?;
386 break; 479 break;
387 } 480 }
388 } 481 }
@@ -391,7 +484,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
391 }; 484 };
392 last_matched_token = next; 485 last_matched_token = next;
393 } 486 }
394 if let Some(match_out) = &mut self.match_out { 487 if let Phase::Second(match_out) = phase {
395 match_out.placeholder_values.insert( 488 match_out.placeholder_values.insert(
396 Var(placeholder.ident.to_string()), 489 Var(placeholder.ident.to_string()),
397 PlaceholderMatch::from_range(FileRange { 490 PlaceholderMatch::from_range(FileRange {
@@ -407,11 +500,11 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
407 // Match literal (non-placeholder) tokens. 500 // Match literal (non-placeholder) tokens.
408 match child { 501 match child {
409 SyntaxElement::Token(token) => { 502 SyntaxElement::Token(token) => {
410 self.attempt_match_token(&mut pattern, &token)?; 503 self.attempt_match_token(phase, &mut pattern, &token)?;
411 } 504 }
412 SyntaxElement::Node(node) => match pattern.next() { 505 SyntaxElement::Node(node) => match pattern.next() {
413 Some(SyntaxElement::Node(p)) => { 506 Some(SyntaxElement::Node(p)) => {
414 self.attempt_match_token_tree(match_inputs, &p, &node)?; 507 self.attempt_match_token_tree(phase, &p, &node)?;
415 } 508 }
416 Some(SyntaxElement::Token(p)) => fail_match!( 509 Some(SyntaxElement::Token(p)) => fail_match!(
417 "Pattern has token '{}', code has subtree '{}'", 510 "Pattern has token '{}', code has subtree '{}'",
@@ -428,6 +521,65 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
428 Ok(()) 521 Ok(())
429 } 522 }
430 523
524 fn attempt_match_ufcs(
525 &self,
526 phase: &mut Phase,
527 pattern: &ast::CallExpr,
528 code: &ast::MethodCallExpr,
529 pattern_function: hir::Function,
530 ) -> Result<(), MatchFailed> {
531 use ast::ArgListOwner;
532 let code_resolved_function = self
533 .sema
534 .resolve_method_call(code)
535 .ok_or_else(|| match_error!("Failed to resolve method call"))?;
536 if pattern_function != code_resolved_function {
537 fail_match!("Method call resolved to a different function");
538 }
539 // Check arguments.
540 let mut pattern_args = pattern
541 .arg_list()
542 .ok_or_else(|| match_error!("Pattern function call has no args"))?
543 .args();
544 self.attempt_match_opt(phase, pattern_args.next(), code.expr())?;
545 let mut code_args =
546 code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args();
547 loop {
548 match (pattern_args.next(), code_args.next()) {
549 (None, None) => return Ok(()),
550 (p, c) => self.attempt_match_opt(phase, p, c)?,
551 }
552 }
553 }
554
555 fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> {
556 only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident))
557 }
558}
559
560impl Match {
561 fn render_template_paths(
562 &mut self,
563 template: &ResolvedPattern,
564 sema: &Semantics<ra_ide_db::RootDatabase>,
565 ) -> Result<(), MatchFailed> {
566 let module = sema
567 .scope(&self.matched_node)
568 .module()
569 .ok_or_else(|| match_error!("Matched node isn't in a module"))?;
570 for (path, resolved_path) in &template.resolved_paths {
571 if let hir::PathResolution::Def(module_def) = resolved_path.resolution {
572 let mod_path = module.find_use_path(sema.db, module_def).ok_or_else(|| {
573 match_error!("Failed to render template path `{}` at match location")
574 })?;
575 self.rendered_template_paths.insert(path.clone(), mod_path);
576 }
577 }
578 Ok(())
579 }
580}
581
582impl Phase<'_> {
431 fn next_non_trivial(&mut self, code_it: &mut SyntaxElementChildren) -> Option<SyntaxElement> { 583 fn next_non_trivial(&mut self, code_it: &mut SyntaxElementChildren) -> Option<SyntaxElement> {
432 loop { 584 loop {
433 let c = code_it.next(); 585 let c = code_it.next();
@@ -443,7 +595,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
443 595
444 fn record_ignored_comments(&mut self, token: &SyntaxToken) { 596 fn record_ignored_comments(&mut self, token: &SyntaxToken) {
445 if token.kind() == SyntaxKind::COMMENT { 597 if token.kind() == SyntaxKind::COMMENT {
446 if let Some(match_out) = &mut self.match_out { 598 if let Phase::Second(match_out) = self {
447 if let Some(comment) = ast::Comment::cast(token.clone()) { 599 if let Some(comment) = ast::Comment::cast(token.clone()) {
448 match_out.ignored_comments.push(comment); 600 match_out.ignored_comments.push(comment);
449 } 601 }
@@ -452,13 +604,6 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
452 } 604 }
453} 605}
454 606
455impl MatchInputs<'_> {
456 fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> {
457 only_ident(element.clone())
458 .and_then(|ident| self.ssr_pattern.placeholders_by_stand_in.get(ident.text()))
459 }
460}
461
462fn is_closing_token(kind: SyntaxKind) -> bool { 607fn is_closing_token(kind: SyntaxKind) -> bool {
463 kind == SyntaxKind::R_PAREN || kind == SyntaxKind::R_CURLY || kind == SyntaxKind::R_BRACK 608 kind == SyntaxKind::R_PAREN || kind == SyntaxKind::R_CURLY || kind == SyntaxKind::R_BRACK
464} 609}
@@ -495,25 +640,18 @@ impl PlaceholderMatch {
495 } 640 }
496} 641}
497 642
498impl SsrPattern { 643impl NodeKind {
499 pub(crate) fn tree_for_kind(&self, kind: SyntaxKind) -> Result<&SyntaxNode, MatchFailed> { 644 fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> {
500 let (tree, kind_name) = if ast::Expr::can_cast(kind) { 645 let ok = match self {
501 (&self.expr, "expression") 646 Self::Literal => {
502 } else if ast::TypeRef::can_cast(kind) { 647 mark::hit!(literal_constraint);
503 (&self.type_ref, "type reference") 648 ast::Literal::can_cast(node.kind())
504 } else if ast::ModuleItem::can_cast(kind) { 649 }
505 (&self.item, "item")
506 } else if ast::Path::can_cast(kind) {
507 (&self.path, "path")
508 } else if ast::Pat::can_cast(kind) {
509 (&self.pattern, "pattern")
510 } else {
511 fail_match!("Matching nodes of kind {:?} is not supported", kind);
512 }; 650 };
513 match tree { 651 if !ok {
514 Some(tree) => Ok(tree), 652 fail_match!("Code '{}' isn't of kind {:?}", node.text(), self);
515 None => fail_match!("Pattern cannot be parsed as a {}", kind_name),
516 } 653 }
654 Ok(())
517 } 655 }
518} 656}
519 657
@@ -561,18 +699,17 @@ impl PatternIterator {
561#[cfg(test)] 699#[cfg(test)]
562mod tests { 700mod tests {
563 use super::*; 701 use super::*;
564 use crate::MatchFinder; 702 use crate::{MatchFinder, SsrRule};
565 703
566 #[test] 704 #[test]
567 fn parse_match_replace() { 705 fn parse_match_replace() {
568 let rule: SsrRule = "foo($x) ==>> bar($x)".parse().unwrap(); 706 let rule: SsrRule = "foo($x) ==>> bar($x)".parse().unwrap();
569 let input = "fn main() { foo(1+2); }"; 707 let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }";
570 708
571 use ra_db::fixture::WithFixture; 709 let (db, position, selections) = crate::tests::single_file(input);
572 let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(input); 710 let mut match_finder = MatchFinder::in_context(&db, position, selections);
573 let mut match_finder = MatchFinder::new(&db); 711 match_finder.add_rule(rule).unwrap();
574 match_finder.add_rule(rule); 712 let matches = match_finder.matches();
575 let matches = match_finder.find_matches_in_file(file_id);
576 assert_eq!(matches.matches.len(), 1); 713 assert_eq!(matches.matches.len(), 1);
577 assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)"); 714 assert_eq!(matches.matches[0].matched_node.text(), "foo(1+2)");
578 assert_eq!(matches.matches[0].placeholder_values.len(), 1); 715 assert_eq!(matches.matches[0].placeholder_values.len(), 1);
@@ -585,9 +722,11 @@ mod tests {
585 "1+2" 722 "1+2"
586 ); 723 );
587 724
588 let edit = crate::replacing::matches_to_edit(&matches, input); 725 let edits = match_finder.edits();
726 assert_eq!(edits.len(), 1);
727 let edit = &edits[0];
589 let mut after = input.to_string(); 728 let mut after = input.to_string();
590 edit.apply(&mut after); 729 edit.edit.apply(&mut after);
591 assert_eq!(after, "fn main() { bar(1+2); }"); 730 assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }");
592 } 731 }
593} 732}
diff --git a/crates/ra_ssr/src/nester.rs b/crates/ra_ssr/src/nester.rs
new file mode 100644
index 000000000..b3e20579b
--- /dev/null
+++ b/crates/ra_ssr/src/nester.rs
@@ -0,0 +1,98 @@
1//! Converts a flat collection of matches into a nested form suitable for replacement. When there
2//! are multiple matches for a node, or that overlap, priority is given to the earlier rule. Nested
3//! matches are only permitted if the inner match is contained entirely within a placeholder of an
4//! outer match.
5//!
6//! For example, if our search pattern is `foo(foo($a))` and the code had `foo(foo(foo(foo(42))))`,
7//! then we'll get 3 matches, however only the outermost and innermost matches can be accepted. The
8//! middle match would take the second `foo` from the outer match.
9
10use crate::{Match, SsrMatches};
11use ra_syntax::SyntaxNode;
12use rustc_hash::FxHashMap;
13
14pub(crate) fn nest_and_remove_collisions(
15 mut matches: Vec<Match>,
16 sema: &hir::Semantics<ra_ide_db::RootDatabase>,
17) -> SsrMatches {
18 // We sort the matches by depth then by rule index. Sorting by depth means that by the time we
19 // see a match, any parent matches or conflicting matches will have already been seen. Sorting
20 // by rule_index means that if there are two matches for the same node, the rule added first
21 // will take precedence.
22 matches.sort_by(|a, b| a.depth.cmp(&b.depth).then_with(|| a.rule_index.cmp(&b.rule_index)));
23 let mut collector = MatchCollector::default();
24 for m in matches {
25 collector.add_match(m, sema);
26 }
27 collector.into()
28}
29
30#[derive(Default)]
31struct MatchCollector {
32 matches_by_node: FxHashMap<SyntaxNode, Match>,
33}
34
35impl MatchCollector {
36 /// Attempts to add `m` to matches. If it conflicts with an existing match, it is discarded. If
37 /// it is entirely within the a placeholder of an existing match, then it is added as a child
38 /// match of the existing match.
39 fn add_match(&mut self, m: Match, sema: &hir::Semantics<ra_ide_db::RootDatabase>) {
40 let matched_node = m.matched_node.clone();
41 if let Some(existing) = self.matches_by_node.get_mut(&matched_node) {
42 try_add_sub_match(m, existing, sema);
43 return;
44 }
45 for ancestor in sema.ancestors_with_macros(m.matched_node.clone()) {
46 if let Some(existing) = self.matches_by_node.get_mut(&ancestor) {
47 try_add_sub_match(m, existing, sema);
48 return;
49 }
50 }
51 self.matches_by_node.insert(matched_node, m);
52 }
53}
54
55/// Attempts to add `m` as a sub-match of `existing`.
56fn try_add_sub_match(
57 m: Match,
58 existing: &mut Match,
59 sema: &hir::Semantics<ra_ide_db::RootDatabase>,
60) {
61 for p in existing.placeholder_values.values_mut() {
62 // Note, no need to check if p.range.file is equal to m.range.file, since we
63 // already know we're within `existing`.
64 if p.range.range.contains_range(m.range.range) {
65 // Convert the inner matches in `p` into a temporary MatchCollector. When
66 // we're done, we then convert it back into an SsrMatches. If we expected
67 // lots of inner matches, it might be worthwhile keeping a MatchCollector
68 // around for each placeholder match. However we expect most placeholder
69 // will have 0 and a few will have 1. More than that should hopefully be
70 // exceptional.
71 let mut collector = MatchCollector::default();
72 for m in std::mem::replace(&mut p.inner_matches.matches, Vec::new()) {
73 collector.matches_by_node.insert(m.matched_node.clone(), m);
74 }
75 collector.add_match(m, sema);
76 p.inner_matches = collector.into();
77 break;
78 }
79 }
80}
81
82impl From<MatchCollector> for SsrMatches {
83 fn from(mut match_collector: MatchCollector) -> Self {
84 let mut matches = SsrMatches::default();
85 for (_, m) in match_collector.matches_by_node.drain() {
86 matches.matches.push(m);
87 }
88 matches.matches.sort_by(|a, b| {
89 // Order matches by file_id then by start range. This should be sufficient since ranges
90 // shouldn't be overlapping.
91 a.range
92 .file_id
93 .cmp(&b.range.file_id)
94 .then_with(|| a.range.range.start().cmp(&b.range.range.start()))
95 });
96 matches
97 }
98}
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs
index 1ae166d19..78e03f394 100644
--- a/crates/ra_ssr/src/parsing.rs
+++ b/crates/ra_ssr/src/parsing.rs
@@ -5,24 +5,22 @@
5//! search patterns, we go further and parse the pattern as each kind of thing that we can match. 5//! search patterns, we go further and parse the pattern as each kind of thing that we can match.
6//! e.g. expressions, type references etc. 6//! e.g. expressions, type references etc.
7 7
8use crate::errors::bail;
8use crate::{SsrError, SsrPattern, SsrRule}; 9use crate::{SsrError, SsrPattern, SsrRule};
9use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind}; 10use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T};
10use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap, FxHashSet};
11use std::str::FromStr; 12use std::str::FromStr;
13use test_utils::mark;
12 14
13/// Returns from the current function with an error, supplied by arguments as for format! 15#[derive(Debug)]
14macro_rules! bail { 16pub(crate) struct ParsedRule {
15 ($e:expr) => {return Err($crate::SsrError::new($e))}; 17 pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>,
16 ($fmt:expr, $($arg:tt)+) => {return Err($crate::SsrError::new(format!($fmt, $($arg)+)))} 18 pub(crate) pattern: SyntaxNode,
17} 19 pub(crate) template: Option<SyntaxNode>,
18
19#[derive(Clone, Debug)]
20pub(crate) struct SsrTemplate {
21 pub(crate) tokens: Vec<PatternElement>,
22} 20}
23 21
24#[derive(Debug)] 22#[derive(Debug)]
25pub(crate) struct RawSearchPattern { 23pub(crate) struct RawPattern {
26 tokens: Vec<PatternElement>, 24 tokens: Vec<PatternElement>,
27} 25}
28 26
@@ -39,6 +37,18 @@ pub(crate) struct Placeholder {
39 pub(crate) ident: SmolStr, 37 pub(crate) ident: SmolStr,
40 /// A unique name used in place of this placeholder when we parse the pattern as Rust code. 38 /// A unique name used in place of this placeholder when we parse the pattern as Rust code.
41 stand_in_name: String, 39 stand_in_name: String,
40 pub(crate) constraints: Vec<Constraint>,
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
44pub(crate) enum Constraint {
45 Kind(NodeKind),
46 Not(Box<Constraint>),
47}
48
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub(crate) enum NodeKind {
51 Literal,
42} 52}
43 53
44#[derive(Debug, Clone, PartialEq, Eq)] 54#[derive(Debug, Clone, PartialEq, Eq)]
@@ -47,6 +57,78 @@ pub(crate) struct Token {
47 pub(crate) text: SmolStr, 57 pub(crate) text: SmolStr,
48} 58}
49 59
60impl ParsedRule {
61 fn new(
62 pattern: &RawPattern,
63 template: Option<&RawPattern>,
64 ) -> Result<Vec<ParsedRule>, SsrError> {
65 let raw_pattern = pattern.as_rust_code();
66 let raw_template = template.map(|t| t.as_rust_code());
67 let raw_template = raw_template.as_ref().map(|s| s.as_str());
68 let mut builder = RuleBuilder {
69 placeholders_by_stand_in: pattern.placeholders_by_stand_in(),
70 rules: Vec::new(),
71 };
72 builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse));
73 builder.try_add(ast::TypeRef::parse(&raw_pattern), raw_template.map(ast::TypeRef::parse));
74 builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
75 builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
76 builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
77 builder.build()
78 }
79}
80
81struct RuleBuilder {
82 placeholders_by_stand_in: FxHashMap<SmolStr, Placeholder>,
83 rules: Vec<ParsedRule>,
84}
85
86impl RuleBuilder {
87 fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) {
88 match (pattern, template) {
89 (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
90 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
91 pattern: pattern.syntax().clone(),
92 template: Some(template.syntax().clone()),
93 }),
94 (Ok(pattern), None) => self.rules.push(ParsedRule {
95 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
96 pattern: pattern.syntax().clone(),
97 template: None,
98 }),
99 _ => {}
100 }
101 }
102
103 fn build(mut self) -> Result<Vec<ParsedRule>, SsrError> {
104 if self.rules.is_empty() {
105 bail!("Not a valid Rust expression, type, item, path or pattern");
106 }
107 // If any rules contain paths, then we reject any rules that don't contain paths. Allowing a
108 // mix leads to strange semantics, since the path-based rules only match things where the
109 // path refers to semantically the same thing, whereas the non-path-based rules could match
110 // anything. Specifically, if we have a rule like `foo ==>> bar` we only want to match the
111 // `foo` that is in the current scope, not any `foo`. However "foo" can be parsed as a
112 // pattern (BIND_PAT -> NAME -> IDENT). Allowing such a rule through would result in
113 // renaming everything called `foo` to `bar`. It'd also be slow, since without a path, we'd
114 // have to use the slow-scan search mechanism.
115 if self.rules.iter().any(|rule| contains_path(&rule.pattern)) {
116 let old_len = self.rules.len();
117 self.rules.retain(|rule| contains_path(&rule.pattern));
118 if self.rules.len() < old_len {
119 mark::hit!(pattern_is_a_single_segment_path);
120 }
121 }
122 Ok(self.rules)
123 }
124}
125
126/// Returns whether there are any paths in `node`.
127fn contains_path(node: &SyntaxNode) -> bool {
128 node.kind() == SyntaxKind::PATH
129 || node.descendants().any(|node| node.kind() == SyntaxKind::PATH)
130}
131
50impl FromStr for SsrRule { 132impl FromStr for SsrRule {
51 type Err = SsrError; 133 type Err = SsrError;
52 134
@@ -55,27 +137,30 @@ impl FromStr for SsrRule {
55 let pattern = it.next().expect("at least empty string").trim(); 137 let pattern = it.next().expect("at least empty string").trim();
56 let template = it 138 let template = it
57 .next() 139 .next()
58 .ok_or_else(|| SsrError("Cannot find delemiter `==>>`".into()))? 140 .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))?
59 .trim() 141 .trim()
60 .to_string(); 142 .to_string();
61 if it.next().is_some() { 143 if it.next().is_some() {
62 return Err(SsrError("More than one delimiter found".into())); 144 return Err(SsrError("More than one delimiter found".into()));
63 } 145 }
64 let rule = SsrRule { pattern: pattern.parse()?, template: template.parse()? }; 146 let raw_pattern = pattern.parse()?;
147 let raw_template = template.parse()?;
148 let parsed_rules = ParsedRule::new(&raw_pattern, Some(&raw_template))?;
149 let rule = SsrRule { pattern: raw_pattern, template: raw_template, parsed_rules };
65 validate_rule(&rule)?; 150 validate_rule(&rule)?;
66 Ok(rule) 151 Ok(rule)
67 } 152 }
68} 153}
69 154
70impl FromStr for RawSearchPattern { 155impl FromStr for RawPattern {
71 type Err = SsrError; 156 type Err = SsrError;
72 157
73 fn from_str(pattern_str: &str) -> Result<RawSearchPattern, SsrError> { 158 fn from_str(pattern_str: &str) -> Result<RawPattern, SsrError> {
74 Ok(RawSearchPattern { tokens: parse_pattern(pattern_str)? }) 159 Ok(RawPattern { tokens: parse_pattern(pattern_str)? })
75 } 160 }
76} 161}
77 162
78impl RawSearchPattern { 163impl RawPattern {
79 /// Returns this search pattern as Rust source code that we can feed to the Rust parser. 164 /// Returns this search pattern as Rust source code that we can feed to the Rust parser.
80 fn as_rust_code(&self) -> String { 165 fn as_rust_code(&self) -> String {
81 let mut res = String::new(); 166 let mut res = String::new();
@@ -88,7 +173,7 @@ impl RawSearchPattern {
88 res 173 res
89 } 174 }
90 175
91 fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> { 176 pub(crate) fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> {
92 let mut res = FxHashMap::default(); 177 let mut res = FxHashMap::default();
93 for t in &self.tokens { 178 for t in &self.tokens {
94 if let PatternElement::Placeholder(placeholder) = t { 179 if let PatternElement::Placeholder(placeholder) = t {
@@ -103,41 +188,9 @@ impl FromStr for SsrPattern {
103 type Err = SsrError; 188 type Err = SsrError;
104 189
105 fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> { 190 fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> {
106 let raw: RawSearchPattern = pattern_str.parse()?; 191 let raw_pattern = pattern_str.parse()?;
107 let raw_str = raw.as_rust_code(); 192 let parsed_rules = ParsedRule::new(&raw_pattern, None)?;
108 let res = SsrPattern { 193 Ok(SsrPattern { raw: raw_pattern, parsed_rules })
109 expr: ast::Expr::parse(&raw_str).ok().map(|n| n.syntax().clone()),
110 type_ref: ast::TypeRef::parse(&raw_str).ok().map(|n| n.syntax().clone()),
111 item: ast::ModuleItem::parse(&raw_str).ok().map(|n| n.syntax().clone()),
112 path: ast::Path::parse(&raw_str).ok().map(|n| n.syntax().clone()),
113 pattern: ast::Pat::parse(&raw_str).ok().map(|n| n.syntax().clone()),
114 placeholders_by_stand_in: raw.placeholders_by_stand_in(),
115 raw,
116 };
117 if res.expr.is_none()
118 && res.type_ref.is_none()
119 && res.item.is_none()
120 && res.path.is_none()
121 && res.pattern.is_none()
122 {
123 bail!("Pattern is not a valid Rust expression, type, item, path or pattern");
124 }
125 Ok(res)
126 }
127}
128
129impl FromStr for SsrTemplate {
130 type Err = SsrError;
131
132 fn from_str(pattern_str: &str) -> Result<SsrTemplate, SsrError> {
133 let tokens = parse_pattern(pattern_str)?;
134 // Validate that the template is a valid fragment of Rust code. We reuse the validation
135 // logic for search patterns since the only thing that differs is the error message.
136 if SsrPattern::from_str(pattern_str).is_err() {
137 bail!("Replacement is not a valid Rust expression, type, item, path or pattern");
138 }
139 // Our actual template needs to preserve whitespace, so we can't reuse `tokens`.
140 Ok(SsrTemplate { tokens })
141 } 194 }
142} 195}
143 196
@@ -149,7 +202,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
149 let mut placeholder_names = FxHashSet::default(); 202 let mut placeholder_names = FxHashSet::default();
150 let mut tokens = tokenize(pattern_str)?.into_iter(); 203 let mut tokens = tokenize(pattern_str)?.into_iter();
151 while let Some(token) = tokens.next() { 204 while let Some(token) = tokens.next() {
152 if token.kind == SyntaxKind::DOLLAR { 205 if token.kind == T![$] {
153 let placeholder = parse_placeholder(&mut tokens)?; 206 let placeholder = parse_placeholder(&mut tokens)?;
154 if !placeholder_names.insert(placeholder.ident.clone()) { 207 if !placeholder_names.insert(placeholder.ident.clone()) {
155 bail!("Name `{}` repeats more than once", placeholder.ident); 208 bail!("Name `{}` repeats more than once", placeholder.ident);
@@ -166,7 +219,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
166/// pattern didn't define. 219/// pattern didn't define.
167fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> { 220fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
168 let mut defined_placeholders = FxHashSet::default(); 221 let mut defined_placeholders = FxHashSet::default();
169 for p in &rule.pattern.raw.tokens { 222 for p in &rule.pattern.tokens {
170 if let PatternElement::Placeholder(placeholder) = p { 223 if let PatternElement::Placeholder(placeholder) = p {
171 defined_placeholders.insert(&placeholder.ident); 224 defined_placeholders.insert(&placeholder.ident);
172 } 225 }
@@ -177,6 +230,9 @@ fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
177 if !defined_placeholders.contains(&placeholder.ident) { 230 if !defined_placeholders.contains(&placeholder.ident) {
178 undefined.push(format!("${}", placeholder.ident)); 231 undefined.push(format!("${}", placeholder.ident));
179 } 232 }
233 if !placeholder.constraints.is_empty() {
234 bail!("Replacement placeholders cannot have constraints");
235 }
180 } 236 }
181 } 237 }
182 if !undefined.is_empty() { 238 if !undefined.is_empty() {
@@ -205,29 +261,90 @@ fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
205 261
206fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> { 262fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
207 let mut name = None; 263 let mut name = None;
264 let mut constraints = Vec::new();
208 if let Some(token) = tokens.next() { 265 if let Some(token) = tokens.next() {
209 match token.kind { 266 match token.kind {
210 SyntaxKind::IDENT => { 267 SyntaxKind::IDENT => {
211 name = Some(token.text); 268 name = Some(token.text);
212 } 269 }
270 T!['{'] => {
271 let token =
272 tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
273 if token.kind == SyntaxKind::IDENT {
274 name = Some(token.text);
275 }
276 loop {
277 let token = tokens
278 .next()
279 .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
280 match token.kind {
281 T![:] => {
282 constraints.push(parse_constraint(tokens)?);
283 }
284 T!['}'] => break,
285 _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
286 }
287 }
288 }
213 _ => { 289 _ => {
214 bail!("Placeholders should be $name"); 290 bail!("Placeholders should either be $name or ${{name:constraints}}");
215 } 291 }
216 } 292 }
217 } 293 }
218 let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?; 294 let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
219 Ok(Placeholder::new(name)) 295 Ok(Placeholder::new(name, constraints))
220} 296}
221 297
222impl Placeholder { 298fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
223 fn new(name: SmolStr) -> Self { 299 let constraint_type = tokens
224 Self { stand_in_name: format!("__placeholder_{}", name), ident: name } 300 .next()
301 .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
302 .text
303 .to_string();
304 match constraint_type.as_str() {
305 "kind" => {
306 expect_token(tokens, "(")?;
307 let t = tokens.next().ok_or_else(|| {
308 SsrError::new("Unexpected end of constraint while looking for kind")
309 })?;
310 if t.kind != SyntaxKind::IDENT {
311 bail!("Expected ident, found {:?} while parsing kind constraint", t.kind);
312 }
313 expect_token(tokens, ")")?;
314 Ok(Constraint::Kind(NodeKind::from(&t.text)?))
315 }
316 "not" => {
317 expect_token(tokens, "(")?;
318 let sub = parse_constraint(tokens)?;
319 expect_token(tokens, ")")?;
320 Ok(Constraint::Not(Box::new(sub)))
321 }
322 x => bail!("Unsupported constraint type '{}'", x),
323 }
324}
325
326fn expect_token(tokens: &mut std::vec::IntoIter<Token>, expected: &str) -> Result<(), SsrError> {
327 if let Some(t) = tokens.next() {
328 if t.text == expected {
329 return Ok(());
330 }
331 bail!("Expected {} found {}", expected, t.text);
332 }
333 bail!("Expected {} found end of stream", expected);
334}
335
336impl NodeKind {
337 fn from(name: &SmolStr) -> Result<NodeKind, SsrError> {
338 Ok(match name.as_str() {
339 "literal" => NodeKind::Literal,
340 _ => bail!("Unknown node kind '{}'", name),
341 })
225 } 342 }
226} 343}
227 344
228impl SsrError { 345impl Placeholder {
229 fn new(message: impl Into<String>) -> SsrError { 346 fn new(name: SmolStr, constraints: Vec<Constraint>) -> Self {
230 SsrError(message.into()) 347 Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name }
231 } 348 }
232} 349}
233 350
@@ -241,31 +358,31 @@ mod tests {
241 PatternElement::Token(Token { kind, text: SmolStr::new(text) }) 358 PatternElement::Token(Token { kind, text: SmolStr::new(text) })
242 } 359 }
243 fn placeholder(name: &str) -> PatternElement { 360 fn placeholder(name: &str) -> PatternElement {
244 PatternElement::Placeholder(Placeholder::new(SmolStr::new(name))) 361 PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new()))
245 } 362 }
246 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap(); 363 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
247 assert_eq!( 364 assert_eq!(
248 result.pattern.raw.tokens, 365 result.pattern.tokens,
249 vec![ 366 vec![
250 token(SyntaxKind::IDENT, "foo"), 367 token(SyntaxKind::IDENT, "foo"),
251 token(SyntaxKind::L_PAREN, "("), 368 token(T!['('], "("),
252 placeholder("a"), 369 placeholder("a"),
253 token(SyntaxKind::COMMA, ","), 370 token(T![,], ","),
254 token(SyntaxKind::WHITESPACE, " "), 371 token(SyntaxKind::WHITESPACE, " "),
255 placeholder("b"), 372 placeholder("b"),
256 token(SyntaxKind::R_PAREN, ")"), 373 token(T![')'], ")"),
257 ] 374 ]
258 ); 375 );
259 assert_eq!( 376 assert_eq!(
260 result.template.tokens, 377 result.template.tokens,
261 vec![ 378 vec![
262 token(SyntaxKind::IDENT, "bar"), 379 token(SyntaxKind::IDENT, "bar"),
263 token(SyntaxKind::L_PAREN, "("), 380 token(T!['('], "("),
264 placeholder("b"), 381 placeholder("b"),
265 token(SyntaxKind::COMMA, ","), 382 token(T![,], ","),
266 token(SyntaxKind::WHITESPACE, " "), 383 token(SyntaxKind::WHITESPACE, " "),
267 placeholder("a"), 384 placeholder("a"),
268 token(SyntaxKind::R_PAREN, ")"), 385 token(T![')'], ")"),
269 ] 386 ]
270 ); 387 );
271 } 388 }
diff --git a/crates/ra_ssr/src/replacing.rs b/crates/ra_ssr/src/replacing.rs
index 70ce1c185..0943244ff 100644
--- a/crates/ra_ssr/src/replacing.rs
+++ b/crates/ra_ssr/src/replacing.rs
@@ -1,64 +1,194 @@
1//! Code for applying replacement templates for matches that have previously been found. 1//! Code for applying replacement templates for matches that have previously been found.
2 2
3use crate::matching::Var; 3use crate::matching::Var;
4use crate::parsing::PatternElement; 4use crate::{resolving::ResolvedRule, Match, SsrMatches};
5use crate::{Match, SsrMatches}; 5use ra_syntax::ast::{self, AstToken};
6use ra_syntax::ast::AstToken; 6use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize};
7use ra_syntax::TextSize;
8use ra_text_edit::TextEdit; 7use ra_text_edit::TextEdit;
8use rustc_hash::{FxHashMap, FxHashSet};
9 9
10/// Returns a text edit that will replace each match in `matches` with its corresponding replacement 10/// Returns a text edit that will replace each match in `matches` with its corresponding replacement
11/// template. Placeholders in the template will have been substituted with whatever they matched to 11/// template. Placeholders in the template will have been substituted with whatever they matched to
12/// in the original code. 12/// in the original code.
13pub(crate) fn matches_to_edit(matches: &SsrMatches, file_src: &str) -> TextEdit { 13pub(crate) fn matches_to_edit(
14 matches_to_edit_at_offset(matches, file_src, 0.into()) 14 matches: &SsrMatches,
15 file_src: &str,
16 rules: &[ResolvedRule],
17) -> TextEdit {
18 matches_to_edit_at_offset(matches, file_src, 0.into(), rules)
15} 19}
16 20
17fn matches_to_edit_at_offset( 21fn matches_to_edit_at_offset(
18 matches: &SsrMatches, 22 matches: &SsrMatches,
19 file_src: &str, 23 file_src: &str,
20 relative_start: TextSize, 24 relative_start: TextSize,
25 rules: &[ResolvedRule],
21) -> TextEdit { 26) -> TextEdit {
22 let mut edit_builder = ra_text_edit::TextEditBuilder::default(); 27 let mut edit_builder = ra_text_edit::TextEditBuilder::default();
23 for m in &matches.matches { 28 for m in &matches.matches {
24 edit_builder 29 edit_builder.replace(
25 .replace(m.range.checked_sub(relative_start).unwrap(), render_replace(m, file_src)); 30 m.range.range.checked_sub(relative_start).unwrap(),
31 render_replace(m, file_src, rules),
32 );
26 } 33 }
27 edit_builder.finish() 34 edit_builder.finish()
28} 35}
29 36
30fn render_replace(match_info: &Match, file_src: &str) -> String { 37struct ReplacementRenderer<'a> {
31 let mut out = String::new(); 38 match_info: &'a Match,
32 for r in &match_info.template.tokens { 39 file_src: &'a str,
33 match r { 40 rules: &'a [ResolvedRule],
34 PatternElement::Token(t) => out.push_str(t.text.as_str()), 41 rule: &'a ResolvedRule,
35 PatternElement::Placeholder(p) => { 42 out: String,
36 if let Some(placeholder_value) = 43 // Map from a range within `out` to a token in `template` that represents a placeholder. This is
37 match_info.placeholder_values.get(&Var(p.ident.to_string())) 44 // used to validate that the generated source code doesn't split any placeholder expansions (see
38 { 45 // below).
39 let range = &placeholder_value.range.range; 46 placeholder_tokens_by_range: FxHashMap<TextRange, SyntaxToken>,
40 let mut matched_text = 47 // Which placeholder tokens need to be wrapped in parenthesis in order to ensure that when `out`
41 file_src[usize::from(range.start())..usize::from(range.end())].to_owned(); 48 // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1
42 let edit = matches_to_edit_at_offset( 49 // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis.
43 &placeholder_value.inner_matches, 50 placeholder_tokens_requiring_parenthesis: FxHashSet<SyntaxToken>,
44 file_src, 51}
45 range.start(), 52
46 ); 53fn render_replace(match_info: &Match, file_src: &str, rules: &[ResolvedRule]) -> String {
47 edit.apply(&mut matched_text); 54 let rule = &rules[match_info.rule_index];
48 out.push_str(&matched_text); 55 let template = rule
49 } else { 56 .template
50 // We validated that all placeholder references were valid before we 57 .as_ref()
51 // started, so this shouldn't happen. 58 .expect("You called MatchFinder::edits after calling MatchFinder::add_search_pattern");
52 panic!( 59 let mut renderer = ReplacementRenderer {
53 "Internal error: replacement referenced unknown placeholder {}", 60 match_info,
54 p.ident 61 file_src,
55 ); 62 rules,
63 rule,
64 out: String::new(),
65 placeholder_tokens_requiring_parenthesis: FxHashSet::default(),
66 placeholder_tokens_by_range: FxHashMap::default(),
67 };
68 renderer.render_node(&template.node);
69 renderer.maybe_rerender_with_extra_parenthesis(&template.node);
70 for comment in &match_info.ignored_comments {
71 renderer.out.push_str(&comment.syntax().to_string());
72 }
73 renderer.out
74}
75
76impl ReplacementRenderer<'_> {
77 fn render_node_children(&mut self, node: &SyntaxNode) {
78 for node_or_token in node.children_with_tokens() {
79 self.render_node_or_token(&node_or_token);
80 }
81 }
82
83 fn render_node_or_token(&mut self, node_or_token: &SyntaxElement) {
84 match node_or_token {
85 SyntaxElement::Token(token) => {
86 self.render_token(&token);
87 }
88 SyntaxElement::Node(child_node) => {
89 self.render_node(&child_node);
90 }
91 }
92 }
93
94 fn render_node(&mut self, node: &SyntaxNode) {
95 use ra_syntax::ast::AstNode;
96 if let Some(mod_path) = self.match_info.rendered_template_paths.get(&node) {
97 self.out.push_str(&mod_path.to_string());
98 // Emit everything except for the segment's name-ref, since we already effectively
99 // emitted that as part of `mod_path`.
100 if let Some(path) = ast::Path::cast(node.clone()) {
101 if let Some(segment) = path.segment() {
102 for node_or_token in segment.syntax().children_with_tokens() {
103 if node_or_token.kind() != SyntaxKind::NAME_REF {
104 self.render_node_or_token(&node_or_token);
105 }
106 }
56 } 107 }
57 } 108 }
109 } else {
110 self.render_node_children(&node);
58 } 111 }
59 } 112 }
60 for comment in &match_info.ignored_comments { 113
61 out.push_str(&comment.syntax().to_string()); 114 fn render_token(&mut self, token: &SyntaxToken) {
115 if let Some(placeholder) = self.rule.get_placeholder(&token) {
116 if let Some(placeholder_value) =
117 self.match_info.placeholder_values.get(&Var(placeholder.ident.to_string()))
118 {
119 let range = &placeholder_value.range.range;
120 let mut matched_text =
121 self.file_src[usize::from(range.start())..usize::from(range.end())].to_owned();
122 let edit = matches_to_edit_at_offset(
123 &placeholder_value.inner_matches,
124 self.file_src,
125 range.start(),
126 self.rules,
127 );
128 let needs_parenthesis =
129 self.placeholder_tokens_requiring_parenthesis.contains(token);
130 edit.apply(&mut matched_text);
131 if needs_parenthesis {
132 self.out.push('(');
133 }
134 self.placeholder_tokens_by_range.insert(
135 TextRange::new(
136 TextSize::of(&self.out),
137 TextSize::of(&self.out) + TextSize::of(&matched_text),
138 ),
139 token.clone(),
140 );
141 self.out.push_str(&matched_text);
142 if needs_parenthesis {
143 self.out.push(')');
144 }
145 } else {
146 // We validated that all placeholder references were valid before we
147 // started, so this shouldn't happen.
148 panic!(
149 "Internal error: replacement referenced unknown placeholder {}",
150 placeholder.ident
151 );
152 }
153 } else {
154 self.out.push_str(token.text().as_str());
155 }
156 }
157
158 // Checks if the resulting code, when parsed doesn't split any placeholders due to different
159 // order of operations between the search pattern and the replacement template. If any do, then
160 // we rerender the template and wrap the problematic placeholders with parenthesis.
161 fn maybe_rerender_with_extra_parenthesis(&mut self, template: &SyntaxNode) {
162 if let Some(node) = parse_as_kind(&self.out, template.kind()) {
163 self.remove_node_ranges(node);
164 if self.placeholder_tokens_by_range.is_empty() {
165 return;
166 }
167 self.placeholder_tokens_requiring_parenthesis =
168 self.placeholder_tokens_by_range.values().cloned().collect();
169 self.out.clear();
170 self.render_node(template);
171 }
172 }
173
174 fn remove_node_ranges(&mut self, node: SyntaxNode) {
175 self.placeholder_tokens_by_range.remove(&node.text_range());
176 for child in node.children() {
177 self.remove_node_ranges(child);
178 }
179 }
180}
181
182fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option<SyntaxNode> {
183 use ra_syntax::ast::AstNode;
184 if ast::Expr::can_cast(kind) {
185 if let Ok(expr) = ast::Expr::parse(code) {
186 return Some(expr.syntax().clone());
187 }
188 } else if ast::Item::can_cast(kind) {
189 if let Ok(item) = ast::Item::parse(code) {
190 return Some(item.syntax().clone());
191 }
62 } 192 }
63 out 193 None
64} 194}
diff --git a/crates/ra_ssr/src/resolving.rs b/crates/ra_ssr/src/resolving.rs
new file mode 100644
index 000000000..78d456546
--- /dev/null
+++ b/crates/ra_ssr/src/resolving.rs
@@ -0,0 +1,228 @@
1//! This module is responsible for resolving paths within rules.
2
3use crate::errors::error;
4use crate::{parsing, SsrError};
5use parsing::Placeholder;
6use ra_db::FilePosition;
7use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};
8use rustc_hash::{FxHashMap, FxHashSet};
9use test_utils::mark;
10
11pub(crate) struct ResolutionScope<'db> {
12 scope: hir::SemanticsScope<'db>,
13 hygiene: hir::Hygiene,
14}
15
16pub(crate) struct ResolvedRule {
17 pub(crate) pattern: ResolvedPattern,
18 pub(crate) template: Option<ResolvedPattern>,
19 pub(crate) index: usize,
20}
21
22pub(crate) struct ResolvedPattern {
23 pub(crate) placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
24 pub(crate) node: SyntaxNode,
25 // Paths in `node` that we've resolved.
26 pub(crate) resolved_paths: FxHashMap<SyntaxNode, ResolvedPath>,
27 pub(crate) ufcs_function_calls: FxHashMap<SyntaxNode, hir::Function>,
28}
29
30pub(crate) struct ResolvedPath {
31 pub(crate) resolution: hir::PathResolution,
32 /// The depth of the ast::Path that was resolved within the pattern.
33 pub(crate) depth: u32,
34}
35
36impl ResolvedRule {
37 pub(crate) fn new(
38 rule: parsing::ParsedRule,
39 resolution_scope: &ResolutionScope,
40 index: usize,
41 ) -> Result<ResolvedRule, SsrError> {
42 let resolver =
43 Resolver { resolution_scope, placeholders_by_stand_in: rule.placeholders_by_stand_in };
44 let resolved_template = if let Some(template) = rule.template {
45 Some(resolver.resolve_pattern_tree(template)?)
46 } else {
47 None
48 };
49 Ok(ResolvedRule {
50 pattern: resolver.resolve_pattern_tree(rule.pattern)?,
51 template: resolved_template,
52 index,
53 })
54 }
55
56 pub(crate) fn get_placeholder(&self, token: &SyntaxToken) -> Option<&Placeholder> {
57 if token.kind() != SyntaxKind::IDENT {
58 return None;
59 }
60 self.pattern.placeholders_by_stand_in.get(token.text())
61 }
62}
63
64struct Resolver<'a, 'db> {
65 resolution_scope: &'a ResolutionScope<'db>,
66 placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
67}
68
69impl Resolver<'_, '_> {
70 fn resolve_pattern_tree(&self, pattern: SyntaxNode) -> Result<ResolvedPattern, SsrError> {
71 let mut resolved_paths = FxHashMap::default();
72 self.resolve(pattern.clone(), 0, &mut resolved_paths)?;
73 let ufcs_function_calls = resolved_paths
74 .iter()
75 .filter_map(|(path_node, resolved)| {
76 if let Some(grandparent) = path_node.parent().and_then(|parent| parent.parent()) {
77 if grandparent.kind() == SyntaxKind::CALL_EXPR {
78 if let hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) =
79 &resolved.resolution
80 {
81 return Some((grandparent, *function));
82 }
83 }
84 }
85 None
86 })
87 .collect();
88 Ok(ResolvedPattern {
89 node: pattern,
90 resolved_paths,
91 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
92 ufcs_function_calls,
93 })
94 }
95
96 fn resolve(
97 &self,
98 node: SyntaxNode,
99 depth: u32,
100 resolved_paths: &mut FxHashMap<SyntaxNode, ResolvedPath>,
101 ) -> Result<(), SsrError> {
102 use ra_syntax::ast::AstNode;
103 if let Some(path) = ast::Path::cast(node.clone()) {
104 // Check if this is an appropriate place in the path to resolve. If the path is
105 // something like `a::B::<i32>::c` then we want to resolve `a::B`. If the path contains
106 // a placeholder. e.g. `a::$b::c` then we want to resolve `a`.
107 if !path_contains_type_arguments(path.qualifier())
108 && !self.path_contains_placeholder(&path)
109 {
110 let resolution = self
111 .resolution_scope
112 .resolve_path(&path)
113 .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?;
114 resolved_paths.insert(node, ResolvedPath { resolution, depth });
115 return Ok(());
116 }
117 }
118 for node in node.children() {
119 self.resolve(node, depth + 1, resolved_paths)?;
120 }
121 Ok(())
122 }
123
124 /// Returns whether `path` contains a placeholder, but ignores any placeholders within type
125 /// arguments.
126 fn path_contains_placeholder(&self, path: &ast::Path) -> bool {
127 if let Some(segment) = path.segment() {
128 if let Some(name_ref) = segment.name_ref() {
129 if self.placeholders_by_stand_in.contains_key(name_ref.text()) {
130 return true;
131 }
132 }
133 }
134 if let Some(qualifier) = path.qualifier() {
135 return self.path_contains_placeholder(&qualifier);
136 }
137 false
138 }
139}
140
141impl<'db> ResolutionScope<'db> {
142 pub(crate) fn new(
143 sema: &hir::Semantics<'db, ra_ide_db::RootDatabase>,
144 resolve_context: FilePosition,
145 ) -> ResolutionScope<'db> {
146 use ra_syntax::ast::AstNode;
147 let file = sema.parse(resolve_context.file_id);
148 // Find a node at the requested position, falling back to the whole file.
149 let node = file
150 .syntax()
151 .token_at_offset(resolve_context.offset)
152 .left_biased()
153 .map(|token| token.parent())
154 .unwrap_or_else(|| file.syntax().clone());
155 let node = pick_node_for_resolution(node);
156 let scope = sema.scope(&node);
157 ResolutionScope {
158 scope,
159 hygiene: hir::Hygiene::new(sema.db, resolve_context.file_id.into()),
160 }
161 }
162
163 fn resolve_path(&self, path: &ast::Path) -> Option<hir::PathResolution> {
164 let hir_path = hir::Path::from_src(path.clone(), &self.hygiene)?;
165 // First try resolving the whole path. This will work for things like
166 // `std::collections::HashMap`, but will fail for things like
167 // `std::collections::HashMap::new`.
168 if let Some(resolution) = self.scope.resolve_hir_path(&hir_path) {
169 return Some(resolution);
170 }
171 // Resolution failed, try resolving the qualifier (e.g. `std::collections::HashMap` and if
172 // that succeeds, then iterate through the candidates on the resolved type with the provided
173 // name.
174 let resolved_qualifier = self.scope.resolve_hir_path_qualifier(&hir_path.qualifier()?)?;
175 if let hir::PathResolution::Def(hir::ModuleDef::Adt(adt)) = resolved_qualifier {
176 adt.ty(self.scope.db).iterate_path_candidates(
177 self.scope.db,
178 self.scope.module()?.krate(),
179 &FxHashSet::default(),
180 Some(hir_path.segments().last()?.name),
181 |_ty, assoc_item| Some(hir::PathResolution::AssocItem(assoc_item)),
182 )
183 } else {
184 None
185 }
186 }
187}
188
189/// Returns a suitable node for resolving paths in the current scope. If we create a scope based on
190/// a statement node, then we can't resolve local variables that were defined in the current scope
191/// (only in parent scopes). So we find another node, ideally a child of the statement where local
192/// variable resolution is permitted.
193fn pick_node_for_resolution(node: SyntaxNode) -> SyntaxNode {
194 match node.kind() {
195 SyntaxKind::EXPR_STMT => {
196 if let Some(n) = node.first_child() {
197 mark::hit!(cursor_after_semicolon);
198 return n;
199 }
200 }
201 SyntaxKind::LET_STMT | SyntaxKind::BIND_PAT => {
202 if let Some(next) = node.next_sibling() {
203 return pick_node_for_resolution(next);
204 }
205 }
206 SyntaxKind::NAME => {
207 if let Some(parent) = node.parent() {
208 return pick_node_for_resolution(parent);
209 }
210 }
211 _ => {}
212 }
213 node
214}
215
216/// Returns whether `path` or any of its qualifiers contains type arguments.
217fn path_contains_type_arguments(path: Option<ast::Path>) -> bool {
218 if let Some(path) = path {
219 if let Some(segment) = path.segment() {
220 if segment.type_arg_list().is_some() {
221 mark::hit!(type_arguments_within_path);
222 return true;
223 }
224 }
225 return path_contains_type_arguments(path.qualifier());
226 }
227 false
228}
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs
new file mode 100644
index 000000000..213dc494f
--- /dev/null
+++ b/crates/ra_ssr/src/search.rs
@@ -0,0 +1,273 @@
1//! Searching for matches.
2
3use crate::{
4 matching,
5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
6 Match, MatchFinder,
7};
8use ra_db::{FileId, FileRange};
9use ra_ide_db::{
10 defs::Definition,
11 search::{Reference, SearchScope},
12};
13use ra_syntax::{ast, AstNode, SyntaxKind, SyntaxNode};
14use rustc_hash::FxHashSet;
15use test_utils::mark;
16
17/// A cache for the results of find_usages. This is for when we have multiple patterns that have the
18/// same path. e.g. if the pattern was `foo::Bar` that can parse as a path, an expression, a type
19/// and as a pattern. In each, the usages of `foo::Bar` are the same and we'd like to avoid finding
20/// them more than once.
21#[derive(Default)]
22pub(crate) struct UsageCache {
23 usages: Vec<(Definition, Vec<Reference>)>,
24}
25
26impl<'db> MatchFinder<'db> {
27 /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make
28 /// replacement impossible, so further processing is required in order to properly nest matches
29 /// and remove overlapping matches. This is done in the `nesting` module.
30 pub(crate) fn find_matches_for_rule(
31 &self,
32 rule: &ResolvedRule,
33 usage_cache: &mut UsageCache,
34 matches_out: &mut Vec<Match>,
35 ) {
36 if pick_path_for_usages(&rule.pattern).is_none() {
37 self.slow_scan(rule, matches_out);
38 return;
39 }
40 self.find_matches_for_pattern_tree(rule, &rule.pattern, usage_cache, matches_out);
41 }
42
43 fn find_matches_for_pattern_tree(
44 &self,
45 rule: &ResolvedRule,
46 pattern: &ResolvedPattern,
47 usage_cache: &mut UsageCache,
48 matches_out: &mut Vec<Match>,
49 ) {
50 if let Some(resolved_path) = pick_path_for_usages(pattern) {
51 let definition: Definition = resolved_path.resolution.clone().into();
52 for reference in self.find_usages(usage_cache, definition) {
53 if let Some(node_to_match) = self.find_node_to_match(resolved_path, reference) {
54 if !is_search_permitted_ancestors(&node_to_match) {
55 mark::hit!(use_declaration_with_braces);
56 continue;
57 }
58 self.try_add_match(rule, &node_to_match, &None, matches_out);
59 }
60 }
61 }
62 }
63
64 fn find_node_to_match(
65 &self,
66 resolved_path: &ResolvedPath,
67 reference: &Reference,
68 ) -> Option<SyntaxNode> {
69 let file = self.sema.parse(reference.file_range.file_id);
70 let depth = resolved_path.depth as usize;
71 let offset = reference.file_range.range.start();
72 if let Some(path) =
73 self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset)
74 {
75 self.sema.ancestors_with_macros(path.syntax().clone()).skip(depth).next()
76 } else if let Some(path) =
77 self.sema.find_node_at_offset_with_descend::<ast::MethodCallExpr>(file.syntax(), offset)
78 {
79 // If the pattern contained a path and we found a reference to that path that wasn't
80 // itself a path, but was a method call, then we need to adjust how far up to try
81 // matching by how deep the path was within a CallExpr. The structure would have been
82 // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the
83 // path was part of a CallExpr because if it wasn't then all that will happen is we'll
84 // fail to match, which is the desired behavior.
85 const PATH_DEPTH_IN_CALL_EXPR: usize = 2;
86 if depth < PATH_DEPTH_IN_CALL_EXPR {
87 return None;
88 }
89 self.sema
90 .ancestors_with_macros(path.syntax().clone())
91 .skip(depth - PATH_DEPTH_IN_CALL_EXPR)
92 .next()
93 } else {
94 None
95 }
96 }
97
98 fn find_usages<'a>(
99 &self,
100 usage_cache: &'a mut UsageCache,
101 definition: Definition,
102 ) -> &'a [Reference] {
103 // Logically if a lookup succeeds we should just return it. Unfortunately returning it would
104 // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a
105 // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two
106 // lookups in the case of a cache hit.
107 if usage_cache.find(&definition).is_none() {
108 let usages = definition.find_usages(&self.sema, Some(self.search_scope()));
109 usage_cache.usages.push((definition, usages));
110 return &usage_cache.usages.last().unwrap().1;
111 }
112 usage_cache.find(&definition).unwrap()
113 }
114
115 /// Returns the scope within which we want to search. We don't want un unrestricted search
116 /// scope, since we don't want to find references in external dependencies.
117 fn search_scope(&self) -> SearchScope {
118 // FIXME: We should ideally have a test that checks that we edit local roots and not library
119 // roots. This probably would require some changes to fixtures, since currently everything
120 // seems to get put into a single source root.
121 let mut files = Vec::new();
122 self.search_files_do(|file_id| {
123 files.push(file_id);
124 });
125 SearchScope::files(&files)
126 }
127
128 fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) {
129 self.search_files_do(|file_id| {
130 let file = self.sema.parse(file_id);
131 let code = file.syntax();
132 self.slow_scan_node(code, rule, &None, matches_out);
133 })
134 }
135
136 fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
137 if self.restrict_ranges.is_empty() {
138 // Unrestricted search.
139 use ra_db::SourceDatabaseExt;
140 use ra_ide_db::symbol_index::SymbolsDatabase;
141 for &root in self.sema.db.local_roots().iter() {
142 let sr = self.sema.db.source_root(root);
143 for file_id in sr.iter() {
144 callback(file_id);
145 }
146 }
147 } else {
148 // Search is restricted, deduplicate file IDs (generally only one).
149 let mut files = FxHashSet::default();
150 for range in &self.restrict_ranges {
151 if files.insert(range.file_id) {
152 callback(range.file_id);
153 }
154 }
155 }
156 }
157
158 fn slow_scan_node(
159 &self,
160 code: &SyntaxNode,
161 rule: &ResolvedRule,
162 restrict_range: &Option<FileRange>,
163 matches_out: &mut Vec<Match>,
164 ) {
165 if !is_search_permitted(code) {
166 return;
167 }
168 self.try_add_match(rule, &code, restrict_range, matches_out);
169 // If we've got a macro call, we already tried matching it pre-expansion, which is the only
170 // way to match the whole macro, now try expanding it and matching the expansion.
171 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) {
172 if let Some(expanded) = self.sema.expand(&macro_call) {
173 if let Some(tt) = macro_call.token_tree() {
174 // When matching within a macro expansion, we only want to allow matches of
175 // nodes that originated entirely from within the token tree of the macro call.
176 // i.e. we don't want to match something that came from the macro itself.
177 self.slow_scan_node(
178 &expanded,
179 rule,
180 &Some(self.sema.original_range(tt.syntax())),
181 matches_out,
182 );
183 }
184 }
185 }
186 for child in code.children() {
187 self.slow_scan_node(&child, rule, restrict_range, matches_out);
188 }
189 }
190
191 fn try_add_match(
192 &self,
193 rule: &ResolvedRule,
194 code: &SyntaxNode,
195 restrict_range: &Option<FileRange>,
196 matches_out: &mut Vec<Match>,
197 ) {
198 if !self.within_range_restrictions(code) {
199 mark::hit!(replace_nonpath_within_selection);
200 return;
201 }
202 if let Ok(m) = matching::get_match(false, rule, code, restrict_range, &self.sema) {
203 matches_out.push(m);
204 }
205 }
206
207 /// Returns whether `code` is within one of our range restrictions if we have any. No range
208 /// restrictions is considered unrestricted and always returns true.
209 fn within_range_restrictions(&self, code: &SyntaxNode) -> bool {
210 if self.restrict_ranges.is_empty() {
211 // There is no range restriction.
212 return true;
213 }
214 let node_range = self.sema.original_range(code);
215 for range in &self.restrict_ranges {
216 if range.file_id == node_range.file_id && range.range.contains_range(node_range.range) {
217 return true;
218 }
219 }
220 false
221 }
222}
223
224/// Returns whether we support matching within `node` and all of its ancestors.
225fn is_search_permitted_ancestors(node: &SyntaxNode) -> bool {
226 if let Some(parent) = node.parent() {
227 if !is_search_permitted_ancestors(&parent) {
228 return false;
229 }
230 }
231 is_search_permitted(node)
232}
233
234/// Returns whether we support matching within this kind of node.
235fn is_search_permitted(node: &SyntaxNode) -> bool {
236 // FIXME: Properly handle use declarations. At the moment, if our search pattern is `foo::bar`
237 // and the code is `use foo::{baz, bar}`, we'll match `bar`, since it resolves to `foo::bar`.
238 // However we'll then replace just the part we matched `bar`. We probably need to instead remove
239 // `bar` and insert a new use declaration.
240 node.kind() != SyntaxKind::USE
241}
242
243impl UsageCache {
244 fn find(&mut self, definition: &Definition) -> Option<&[Reference]> {
245 // We expect a very small number of cache entries (generally 1), so a linear scan should be
246 // fast enough and avoids the need to implement Hash for Definition.
247 for (d, refs) in &self.usages {
248 if d == definition {
249 return Some(refs);
250 }
251 }
252 None
253 }
254}
255
256/// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't
257/// something that we can find references to. We then somewhat arbitrarily pick the path that is the
258/// longest as this is hopefully more likely to be less common, making it faster to find.
259fn pick_path_for_usages(pattern: &ResolvedPattern) -> Option<&ResolvedPath> {
260 // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are
261 // private to the current module, then we definitely would want to pick them over say a path
262 // from std. Possibly we should go further than this and intersect the search scopes for all
263 // resolved paths then search only in that scope.
264 pattern
265 .resolved_paths
266 .iter()
267 .filter(|(_, p)| {
268 !matches!(p.resolution, hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_)))
269 })
270 .map(|(node, resolved)| (node.text().len(), resolved))
271 .max_by(|(a, _), (b, _)| a.cmp(b))
272 .map(|(_, resolved)| resolved)
273}
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index 8be60c293..a4fa2cb44 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -1,150 +1,9 @@
1use crate::matching::MatchFailureReason; 1use crate::{MatchFinder, SsrRule};
2use crate::{matching, Match, MatchFinder, SsrMatches, SsrPattern, SsrRule}; 2use expect::{expect, Expect};
3use matching::record_match_fails_reasons_scope; 3use ra_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
4use ra_db::{FileId, FileRange, SourceDatabaseExt}; 4use rustc_hash::FxHashSet;
5use ra_syntax::ast::AstNode; 5use std::sync::Arc;
6use ra_syntax::{ast, SyntaxKind, SyntaxNode, TextRange}; 6use test_utils::{mark, RangeOrOffset};
7
8struct MatchDebugInfo {
9 node: SyntaxNode,
10 /// Our search pattern parsed as the same kind of syntax node as `node`. e.g. expression, item,
11 /// etc. Will be absent if the pattern can't be parsed as that kind.
12 pattern: Result<SyntaxNode, MatchFailureReason>,
13 matched: Result<Match, MatchFailureReason>,
14}
15
16impl SsrPattern {
17 pub(crate) fn tree_for_kind_with_reason(
18 &self,
19 kind: SyntaxKind,
20 ) -> Result<&SyntaxNode, MatchFailureReason> {
21 record_match_fails_reasons_scope(true, || self.tree_for_kind(kind))
22 .map_err(|e| MatchFailureReason { reason: e.reason.unwrap() })
23 }
24}
25
26impl std::fmt::Debug for MatchDebugInfo {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(f, "========= PATTERN ==========\n")?;
29 match &self.pattern {
30 Ok(pattern) => {
31 write!(f, "{:#?}", pattern)?;
32 }
33 Err(err) => {
34 write!(f, "{}", err.reason)?;
35 }
36 }
37 write!(
38 f,
39 "\n============ AST ===========\n\
40 {:#?}\n============================",
41 self.node
42 )?;
43 match &self.matched {
44 Ok(_) => write!(f, "Node matched")?,
45 Err(reason) => write!(f, "Node failed to match because: {}", reason.reason)?,
46 }
47 Ok(())
48 }
49}
50
51impl SsrMatches {
52 /// Returns `self` with any nested matches removed and made into top-level matches.
53 pub(crate) fn flattened(self) -> SsrMatches {
54 let mut out = SsrMatches::default();
55 self.flatten_into(&mut out);
56 out
57 }
58
59 fn flatten_into(self, out: &mut SsrMatches) {
60 for mut m in self.matches {
61 for p in m.placeholder_values.values_mut() {
62 std::mem::replace(&mut p.inner_matches, SsrMatches::default()).flatten_into(out);
63 }
64 out.matches.push(m);
65 }
66 }
67}
68
69impl Match {
70 pub(crate) fn matched_text(&self) -> String {
71 self.matched_node.text().to_string()
72 }
73}
74
75impl<'db> MatchFinder<'db> {
76 /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you
77 /// intend to do replacement, use `add_rule` instead.
78 fn add_search_pattern(&mut self, pattern: SsrPattern) {
79 self.add_rule(SsrRule { pattern, template: "()".parse().unwrap() })
80 }
81
82 /// Finds all nodes in `file_id` whose text is exactly equal to `snippet` and attempts to match
83 /// them, while recording reasons why they don't match. This API is useful for command
84 /// line-based debugging where providing a range is difficult.
85 fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
86 let file = self.sema.parse(file_id);
87 let mut res = Vec::new();
88 let file_text = self.sema.db.file_text(file_id);
89 let mut remaining_text = file_text.as_str();
90 let mut base = 0;
91 let len = snippet.len() as u32;
92 while let Some(offset) = remaining_text.find(snippet) {
93 let start = base + offset as u32;
94 let end = start + len;
95 self.output_debug_for_nodes_at_range(
96 file.syntax(),
97 TextRange::new(start.into(), end.into()),
98 &None,
99 &mut res,
100 );
101 remaining_text = &remaining_text[offset + snippet.len()..];
102 base = end;
103 }
104 res
105 }
106
107 fn output_debug_for_nodes_at_range(
108 &self,
109 node: &SyntaxNode,
110 range: TextRange,
111 restrict_range: &Option<FileRange>,
112 out: &mut Vec<MatchDebugInfo>,
113 ) {
114 for node in node.children() {
115 if !node.text_range().contains_range(range) {
116 continue;
117 }
118 if node.text_range() == range {
119 for rule in &self.rules {
120 let pattern =
121 rule.pattern.tree_for_kind_with_reason(node.kind()).map(|p| p.clone());
122 out.push(MatchDebugInfo {
123 matched: matching::get_match(true, rule, &node, restrict_range, &self.sema)
124 .map_err(|e| MatchFailureReason {
125 reason: e.reason.unwrap_or_else(|| {
126 "Match failed, but no reason was given".to_owned()
127 }),
128 }),
129 pattern,
130 node: node.clone(),
131 });
132 }
133 } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) {
134 if let Some(expanded) = self.sema.expand(&macro_call) {
135 if let Some(tt) = macro_call.token_tree() {
136 self.output_debug_for_nodes_at_range(
137 &expanded,
138 range,
139 &Some(self.sema.original_range(tt.syntax())),
140 out,
141 );
142 }
143 }
144 }
145 }
146 }
147}
148 7
149fn parse_error_text(query: &str) -> String { 8fn parse_error_text(query: &str) -> String {
150 format!("{}", query.parse::<SsrRule>().unwrap_err()) 9 format!("{}", query.parse::<SsrRule>().unwrap_err())
@@ -152,12 +11,12 @@ fn parse_error_text(query: &str) -> String {
152 11
153#[test] 12#[test]
154fn parser_empty_query() { 13fn parser_empty_query() {
155 assert_eq!(parse_error_text(""), "Parse error: Cannot find delemiter `==>>`"); 14 assert_eq!(parse_error_text(""), "Parse error: Cannot find delimiter `==>>`");
156} 15}
157 16
158#[test] 17#[test]
159fn parser_no_delimiter() { 18fn parser_no_delimiter() {
160 assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delemiter `==>>`"); 19 assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delimiter `==>>`");
161} 20}
162 21
163#[test] 22#[test]
@@ -180,7 +39,7 @@ fn parser_repeated_name() {
180fn parser_invalid_pattern() { 39fn parser_invalid_pattern() {
181 assert_eq!( 40 assert_eq!(
182 parse_error_text(" ==>> ()"), 41 parse_error_text(" ==>> ()"),
183 "Parse error: Pattern is not a valid Rust expression, type, item, path or pattern" 42 "Parse error: Not a valid Rust expression, type, item, path or pattern"
184 ); 43 );
185} 44}
186 45
@@ -188,7 +47,7 @@ fn parser_invalid_pattern() {
188fn parser_invalid_template() { 47fn parser_invalid_template() {
189 assert_eq!( 48 assert_eq!(
190 parse_error_text("() ==>> )"), 49 parse_error_text("() ==>> )"),
191 "Parse error: Replacement is not a valid Rust expression, type, item, path or pattern" 50 "Parse error: Not a valid Rust expression, type, item, path or pattern"
192 ); 51 );
193} 52}
194 53
@@ -200,72 +59,112 @@ fn parser_undefined_placeholder_in_replacement() {
200 ); 59 );
201} 60}
202 61
203fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FileId) { 62/// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be
63/// the start of the file. If there's a second cursor marker, then we'll return a single range.
64pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
204 use ra_db::fixture::WithFixture; 65 use ra_db::fixture::WithFixture;
205 ra_ide_db::RootDatabase::with_single_file(code) 66 use ra_ide_db::symbol_index::SymbolsDatabase;
206} 67 let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
207 68 ra_ide_db::RootDatabase::with_range_or_offset(code)
208fn assert_ssr_transform(rule: &str, input: &str, result: &str) { 69 } else {
209 assert_ssr_transforms(&[rule], input, result); 70 let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(code);
71 (db, file_id, RangeOrOffset::Offset(0.into()))
72 };
73 let selections;
74 let position;
75 match range_or_offset {
76 RangeOrOffset::Range(range) => {
77 position = FilePosition { file_id, offset: range.start() };
78 selections = vec![FileRange { file_id, range: range }];
79 }
80 RangeOrOffset::Offset(offset) => {
81 position = FilePosition { file_id, offset };
82 selections = vec![];
83 }
84 }
85 let mut local_roots = FxHashSet::default();
86 local_roots.insert(ra_db::fixture::WORKSPACE);
87 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
88 (db, position, selections)
210} 89}
211 90
212fn normalize_code(code: &str) -> String { 91fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) {
213 let (db, file_id) = single_file(code); 92 assert_ssr_transforms(&[rule], input, expected);
214 db.file_text(file_id).to_string()
215} 93}
216 94
217fn assert_ssr_transforms(rules: &[&str], input: &str, result: &str) { 95fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) {
218 let (db, file_id) = single_file(input); 96 let (db, position, selections) = single_file(input);
219 let mut match_finder = MatchFinder::new(&db); 97 let mut match_finder = MatchFinder::in_context(&db, position, selections);
220 for rule in rules { 98 for rule in rules {
221 let rule: SsrRule = rule.parse().unwrap(); 99 let rule: SsrRule = rule.parse().unwrap();
222 match_finder.add_rule(rule); 100 match_finder.add_rule(rule).unwrap();
223 } 101 }
224 if let Some(edits) = match_finder.edits_for_file(file_id) { 102 let edits = match_finder.edits();
225 // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters 103 if edits.is_empty() {
226 // stuff.
227 let mut after = db.file_text(file_id).to_string();
228 edits.apply(&mut after);
229 // Likewise, we need to make sure that whatever transformations fixture parsing applies,
230 // also get appplied to our expected result.
231 let result = normalize_code(result);
232 assert_eq!(after, result);
233 } else {
234 panic!("No edits were made"); 104 panic!("No edits were made");
235 } 105 }
106 assert_eq!(edits[0].file_id, position.file_id);
107 // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters
108 // stuff.
109 let mut actual = db.file_text(position.file_id).to_string();
110 edits[0].edit.apply(&mut actual);
111 expected.assert_eq(&actual);
112}
113
114fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet: &str) {
115 let debug_info = match_finder.debug_where_text_equal(file_id, snippet);
116 println!(
117 "Match debug info: {} nodes had text exactly equal to '{}'",
118 debug_info.len(),
119 snippet
120 );
121 for (index, d) in debug_info.iter().enumerate() {
122 println!("Node #{}\n{:#?}\n", index, d);
123 }
236} 124}
237 125
238fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { 126fn assert_matches(pattern: &str, code: &str, expected: &[&str]) {
239 let (db, file_id) = single_file(code); 127 let (db, position, selections) = single_file(code);
240 let mut match_finder = MatchFinder::new(&db); 128 let mut match_finder = MatchFinder::in_context(&db, position, selections);
241 match_finder.add_search_pattern(pattern.parse().unwrap()); 129 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
242 let matched_strings: Vec<String> = match_finder 130 let matched_strings: Vec<String> =
243 .find_matches_in_file(file_id) 131 match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect();
244 .flattened()
245 .matches
246 .iter()
247 .map(|m| m.matched_text())
248 .collect();
249 if matched_strings != expected && !expected.is_empty() { 132 if matched_strings != expected && !expected.is_empty() {
250 let debug_info = match_finder.debug_where_text_equal(file_id, &expected[0]); 133 print_match_debug_info(&match_finder, position.file_id, &expected[0]);
251 eprintln!("Test is about to fail. Some possibly useful info: {} nodes had text exactly equal to '{}'", debug_info.len(), &expected[0]);
252 for d in debug_info {
253 eprintln!("{:#?}", d);
254 }
255 } 134 }
256 assert_eq!(matched_strings, expected); 135 assert_eq!(matched_strings, expected);
257} 136}
258 137
259fn assert_no_match(pattern: &str, code: &str) { 138fn assert_no_match(pattern: &str, code: &str) {
260 assert_matches(pattern, code, &[]); 139 let (db, position, selections) = single_file(code);
140 let mut match_finder = MatchFinder::in_context(&db, position, selections);
141 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
142 let matches = match_finder.matches().flattened().matches;
143 if !matches.is_empty() {
144 print_match_debug_info(&match_finder, position.file_id, &matches[0].matched_text());
145 panic!("Got {} matches when we expected none: {:#?}", matches.len(), matches);
146 }
147}
148
149fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) {
150 let (db, position, selections) = single_file(code);
151 let mut match_finder = MatchFinder::in_context(&db, position, selections);
152 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
153 let mut reasons = Vec::new();
154 for d in match_finder.debug_where_text_equal(position.file_id, snippet) {
155 if let Some(reason) = d.match_failure_reason() {
156 reasons.push(reason.to_owned());
157 }
158 }
159 assert_eq!(reasons, vec![expected_reason]);
261} 160}
262 161
263#[test] 162#[test]
264fn ssr_function_to_method() { 163fn ssr_function_to_method() {
265 assert_ssr_transform( 164 assert_ssr_transform(
266 "my_function($a, $b) ==>> ($a).my_method($b)", 165 "my_function($a, $b) ==>> ($a).my_method($b)",
267 "loop { my_function( other_func(x, y), z + w) }", 166 "fn my_function() {} fn main() { loop { my_function( other_func(x, y), z + w) } }",
268 "loop { (other_func(x, y)).my_method(z + w) }", 167 expect![["fn my_function() {} fn main() { loop { (other_func(x, y)).my_method(z + w) } }"]],
269 ) 168 )
270} 169}
271 170
@@ -273,8 +172,19 @@ fn ssr_function_to_method() {
273fn ssr_nested_function() { 172fn ssr_nested_function() {
274 assert_ssr_transform( 173 assert_ssr_transform(
275 "foo($a, $b, $c) ==>> bar($c, baz($a, $b))", 174 "foo($a, $b, $c) ==>> bar($c, baz($a, $b))",
276 "fn main { foo (x + value.method(b), x+y-z, true && false) }", 175 r#"
277 "fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }", 176 //- /lib.rs crate:foo
177 fn foo() {}
178 fn bar() {}
179 fn baz() {}
180 fn main { foo (x + value.method(b), x+y-z, true && false) }
181 "#,
182 expect![[r#"
183 fn foo() {}
184 fn bar() {}
185 fn baz() {}
186 fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }
187 "#]],
278 ) 188 )
279} 189}
280 190
@@ -282,8 +192,8 @@ fn ssr_nested_function() {
282fn ssr_expected_spacing() { 192fn ssr_expected_spacing() {
283 assert_ssr_transform( 193 assert_ssr_transform(
284 "foo($x) + bar() ==>> bar($x)", 194 "foo($x) + bar() ==>> bar($x)",
285 "fn main() { foo(5) + bar() }", 195 "fn foo() {} fn bar() {} fn main() { foo(5) + bar() }",
286 "fn main() { bar(5) }", 196 expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]],
287 ); 197 );
288} 198}
289 199
@@ -291,8 +201,8 @@ fn ssr_expected_spacing() {
291fn ssr_with_extra_space() { 201fn ssr_with_extra_space() {
292 assert_ssr_transform( 202 assert_ssr_transform(
293 "foo($x ) + bar() ==>> bar($x)", 203 "foo($x ) + bar() ==>> bar($x)",
294 "fn main() { foo( 5 ) +bar( ) }", 204 "fn foo() {} fn bar() {} fn main() { foo( 5 ) +bar( ) }",
295 "fn main() { bar(5) }", 205 expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]],
296 ); 206 );
297} 207}
298 208
@@ -300,8 +210,8 @@ fn ssr_with_extra_space() {
300fn ssr_keeps_nested_comment() { 210fn ssr_keeps_nested_comment() {
301 assert_ssr_transform( 211 assert_ssr_transform(
302 "foo($x) ==>> bar($x)", 212 "foo($x) ==>> bar($x)",
303 "fn main() { foo(other(5 /* using 5 */)) }", 213 "fn foo() {} fn bar() {} fn main() { foo(other(5 /* using 5 */)) }",
304 "fn main() { bar(other(5 /* using 5 */)) }", 214 expect![["fn foo() {} fn bar() {} fn main() { bar(other(5 /* using 5 */)) }"]],
305 ) 215 )
306} 216}
307 217
@@ -309,17 +219,25 @@ fn ssr_keeps_nested_comment() {
309fn ssr_keeps_comment() { 219fn ssr_keeps_comment() {
310 assert_ssr_transform( 220 assert_ssr_transform(
311 "foo($x) ==>> bar($x)", 221 "foo($x) ==>> bar($x)",
312 "fn main() { foo(5 /* using 5 */) }", 222 "fn foo() {} fn bar() {} fn main() { foo(5 /* using 5 */) }",
313 "fn main() { bar(5)/* using 5 */ }", 223 expect![["fn foo() {} fn bar() {} fn main() { bar(5)/* using 5 */ }"]],
314 ) 224 )
315} 225}
316 226
317#[test] 227#[test]
318fn ssr_struct_lit() { 228fn ssr_struct_lit() {
319 assert_ssr_transform( 229 assert_ssr_transform(
320 "foo{a: $a, b: $b} ==>> foo::new($a, $b)", 230 "Foo{a: $a, b: $b} ==>> Foo::new($a, $b)",
321 "fn main() { foo{b:2, a:1} }", 231 r#"
322 "fn main() { foo::new(1, 2) }", 232 struct Foo() {}
233 impl Foo { fn new() {} }
234 fn main() { Foo{b:2, a:1} }
235 "#,
236 expect![[r#"
237 struct Foo() {}
238 impl Foo { fn new() {} }
239 fn main() { Foo::new(1, 2) }
240 "#]],
323 ) 241 )
324} 242}
325 243
@@ -341,16 +259,18 @@ fn match_fn_definition() {
341 259
342#[test] 260#[test]
343fn match_struct_definition() { 261fn match_struct_definition() {
344 assert_matches( 262 let code = r#"
345 "struct $n {$f: Option<String>}", 263 struct Option<T> {}
346 "struct Bar {} struct Foo {name: Option<String>}", 264 struct Bar {}
347 &["struct Foo {name: Option<String>}"], 265 struct Foo {name: Option<String>}"#;
348 ); 266 assert_matches("struct $n {$f: Option<String>}", code, &["struct Foo {name: Option<String>}"]);
349} 267}
350 268
351#[test] 269#[test]
352fn match_expr() { 270fn match_expr() {
353 let code = "fn f() -> i32 {foo(40 + 2, 42)}"; 271 let code = r#"
272 fn foo() {}
273 fn f() -> i32 {foo(40 + 2, 42)}"#;
354 assert_matches("foo($a, $b)", code, &["foo(40 + 2, 42)"]); 274 assert_matches("foo($a, $b)", code, &["foo(40 + 2, 42)"]);
355 assert_no_match("foo($a, $b, $c)", code); 275 assert_no_match("foo($a, $b, $c)", code);
356 assert_no_match("foo($a)", code); 276 assert_no_match("foo($a)", code);
@@ -379,7 +299,9 @@ fn match_nested_method_calls_with_macro_call() {
379 299
380#[test] 300#[test]
381fn match_complex_expr() { 301fn match_complex_expr() {
382 let code = "fn f() -> i32 {foo(bar(40, 2), 42)}"; 302 let code = r#"
303 fn foo() {} fn bar() {}
304 fn f() -> i32 {foo(bar(40, 2), 42)}"#;
383 assert_matches("foo($a, $b)", code, &["foo(bar(40, 2), 42)"]); 305 assert_matches("foo($a, $b)", code, &["foo(bar(40, 2), 42)"]);
384 assert_no_match("foo($a, $b, $c)", code); 306 assert_no_match("foo($a, $b, $c)", code);
385 assert_no_match("foo($a)", code); 307 assert_no_match("foo($a)", code);
@@ -390,71 +312,162 @@ fn match_complex_expr() {
390#[test] 312#[test]
391fn match_with_trailing_commas() { 313fn match_with_trailing_commas() {
392 // Code has comma, pattern doesn't. 314 // Code has comma, pattern doesn't.
393 assert_matches("foo($a, $b)", "fn f() {foo(1, 2,);}", &["foo(1, 2,)"]); 315 assert_matches("foo($a, $b)", "fn foo() {} fn f() {foo(1, 2,);}", &["foo(1, 2,)"]);
394 assert_matches("Foo{$a, $b}", "fn f() {Foo{1, 2,};}", &["Foo{1, 2,}"]); 316 assert_matches("Foo{$a, $b}", "struct Foo {} fn f() {Foo{1, 2,};}", &["Foo{1, 2,}"]);
395 317
396 // Pattern has comma, code doesn't. 318 // Pattern has comma, code doesn't.
397 assert_matches("foo($a, $b,)", "fn f() {foo(1, 2);}", &["foo(1, 2)"]); 319 assert_matches("foo($a, $b,)", "fn foo() {} fn f() {foo(1, 2);}", &["foo(1, 2)"]);
398 assert_matches("Foo{$a, $b,}", "fn f() {Foo{1, 2};}", &["Foo{1, 2}"]); 320 assert_matches("Foo{$a, $b,}", "struct Foo {} fn f() {Foo{1, 2};}", &["Foo{1, 2}"]);
399} 321}
400 322
401#[test] 323#[test]
402fn match_type() { 324fn match_type() {
403 assert_matches("i32", "fn f() -> i32 {1 + 2}", &["i32"]); 325 assert_matches("i32", "fn f() -> i32 {1 + 2}", &["i32"]);
404 assert_matches("Option<$a>", "fn f() -> Option<i32> {42}", &["Option<i32>"]); 326 assert_matches(
405 assert_no_match("Option<$a>", "fn f() -> Result<i32, ()> {42}"); 327 "Option<$a>",
328 "struct Option<T> {} fn f() -> Option<i32> {42}",
329 &["Option<i32>"],
330 );
331 assert_no_match(
332 "Option<$a>",
333 "struct Option<T> {} struct Result<T, E> {} fn f() -> Result<i32, ()> {42}",
334 );
406} 335}
407 336
408#[test] 337#[test]
409fn match_struct_instantiation() { 338fn match_struct_instantiation() {
410 assert_matches( 339 let code = r#"
411 "Foo {bar: 1, baz: 2}", 340 struct Foo {bar: i32, baz: i32}
412 "fn f() {Foo {bar: 1, baz: 2}}", 341 fn f() {Foo {bar: 1, baz: 2}}"#;
413 &["Foo {bar: 1, baz: 2}"], 342 assert_matches("Foo {bar: 1, baz: 2}", code, &["Foo {bar: 1, baz: 2}"]);
414 );
415 // Now with placeholders for all parts of the struct. 343 // Now with placeholders for all parts of the struct.
416 assert_matches( 344 assert_matches("Foo {$a: $b, $c: $d}", code, &["Foo {bar: 1, baz: 2}"]);
417 "Foo {$a: $b, $c: $d}", 345 assert_matches("Foo {}", "struct Foo {} fn f() {Foo {}}", &["Foo {}"]);
418 "fn f() {Foo {bar: 1, baz: 2}}",
419 &["Foo {bar: 1, baz: 2}"],
420 );
421 assert_matches("Foo {}", "fn f() {Foo {}}", &["Foo {}"]);
422} 346}
423 347
424#[test] 348#[test]
425fn match_path() { 349fn match_path() {
426 assert_matches("foo::bar", "fn f() {foo::bar(42)}", &["foo::bar"]); 350 let code = r#"
427 assert_matches("$a::bar", "fn f() {foo::bar(42)}", &["foo::bar"]); 351 mod foo {
428 assert_matches("foo::$b", "fn f() {foo::bar(42)}", &["foo::bar"]); 352 pub fn bar() {}
353 }
354 fn f() {foo::bar(42)}"#;
355 assert_matches("foo::bar", code, &["foo::bar"]);
356 assert_matches("$a::bar", code, &["foo::bar"]);
357 assert_matches("foo::$b", code, &["foo::bar"]);
429} 358}
430 359
431#[test] 360#[test]
432fn match_pattern() { 361fn match_pattern() {
433 assert_matches("Some($a)", "fn f() {if let Some(x) = foo() {}}", &["Some(x)"]); 362 assert_matches("Some($a)", "struct Some(); fn f() {if let Some(x) = foo() {}}", &["Some(x)"]);
363}
364
365// If our pattern has a full path, e.g. a::b::c() and the code has c(), but c resolves to
366// a::b::c, then we should match.
367#[test]
368fn match_fully_qualified_fn_path() {
369 let code = r#"
370 mod a {
371 pub mod b {
372 pub fn c(_: i32) {}
373 }
374 }
375 use a::b::c;
376 fn f1() {
377 c(42);
378 }
379 "#;
380 assert_matches("a::b::c($a)", code, &["c(42)"]);
381}
382
383#[test]
384fn match_resolved_type_name() {
385 let code = r#"
386 mod m1 {
387 pub mod m2 {
388 pub trait Foo<T> {}
389 }
390 }
391 mod m3 {
392 trait Foo<T> {}
393 fn f1(f: Option<&dyn Foo<bool>>) {}
394 }
395 mod m4 {
396 use crate::m1::m2::Foo;
397 fn f1(f: Option<&dyn Foo<i32>>) {}
398 }
399 "#;
400 assert_matches("m1::m2::Foo<$t>", code, &["Foo<i32>"]);
401}
402
403#[test]
404fn type_arguments_within_path() {
405 mark::check!(type_arguments_within_path);
406 let code = r#"
407 mod foo {
408 pub struct Bar<T> {t: T}
409 impl<T> Bar<T> {
410 pub fn baz() {}
411 }
412 }
413 fn f1() {foo::Bar::<i32>::baz();}
414 "#;
415 assert_no_match("foo::Bar::<i64>::baz()", code);
416 assert_matches("foo::Bar::<i32>::baz()", code, &["foo::Bar::<i32>::baz()"]);
417}
418
419#[test]
420fn literal_constraint() {
421 mark::check!(literal_constraint);
422 let code = r#"
423 enum Option<T> { Some(T), None }
424 use Option::Some;
425 fn f1() {
426 let x1 = Some(42);
427 let x2 = Some("foo");
428 let x3 = Some(x1);
429 let x4 = Some(40 + 2);
430 let x5 = Some(true);
431 }
432 "#;
433 assert_matches("Some(${a:kind(literal)})", code, &["Some(42)", "Some(\"foo\")", "Some(true)"]);
434 assert_matches("Some(${a:not(kind(literal))})", code, &["Some(x1)", "Some(40 + 2)"]);
434} 435}
435 436
436#[test] 437#[test]
437fn match_reordered_struct_instantiation() { 438fn match_reordered_struct_instantiation() {
438 assert_matches( 439 assert_matches(
439 "Foo {aa: 1, b: 2, ccc: 3}", 440 "Foo {aa: 1, b: 2, ccc: 3}",
440 "fn f() {Foo {b: 2, ccc: 3, aa: 1}}", 441 "struct Foo {} fn f() {Foo {b: 2, ccc: 3, aa: 1}}",
441 &["Foo {b: 2, ccc: 3, aa: 1}"], 442 &["Foo {b: 2, ccc: 3, aa: 1}"],
442 ); 443 );
443 assert_no_match("Foo {a: 1}", "fn f() {Foo {b: 1}}"); 444 assert_no_match("Foo {a: 1}", "struct Foo {} fn f() {Foo {b: 1}}");
444 assert_no_match("Foo {a: 1}", "fn f() {Foo {a: 2}}"); 445 assert_no_match("Foo {a: 1}", "struct Foo {} fn f() {Foo {a: 2}}");
445 assert_no_match("Foo {a: 1, b: 2}", "fn f() {Foo {a: 1}}"); 446 assert_no_match("Foo {a: 1, b: 2}", "struct Foo {} fn f() {Foo {a: 1}}");
446 assert_no_match("Foo {a: 1, b: 2}", "fn f() {Foo {b: 2}}"); 447 assert_no_match("Foo {a: 1, b: 2}", "struct Foo {} fn f() {Foo {b: 2}}");
447 assert_no_match("Foo {a: 1, }", "fn f() {Foo {a: 1, b: 2}}"); 448 assert_no_match("Foo {a: 1, }", "struct Foo {} fn f() {Foo {a: 1, b: 2}}");
448 assert_no_match("Foo {a: 1, z: 9}", "fn f() {Foo {a: 1}}"); 449 assert_no_match("Foo {a: 1, z: 9}", "struct Foo {} fn f() {Foo {a: 1}}");
449} 450}
450 451
451#[test] 452#[test]
452fn match_macro_invocation() { 453fn match_macro_invocation() {
453 assert_matches("foo!($a)", "fn() {foo(foo!(foo()))}", &["foo!(foo())"]); 454 assert_matches(
454 assert_matches("foo!(41, $a, 43)", "fn() {foo!(41, 42, 43)}", &["foo!(41, 42, 43)"]); 455 "foo!($a)",
455 assert_no_match("foo!(50, $a, 43)", "fn() {foo!(41, 42, 43}"); 456 "macro_rules! foo {() => {}} fn() {foo(foo!(foo()))}",
456 assert_no_match("foo!(41, $a, 50)", "fn() {foo!(41, 42, 43}"); 457 &["foo!(foo())"],
457 assert_matches("foo!($a())", "fn() {foo!(bar())}", &["foo!(bar())"]); 458 );
459 assert_matches(
460 "foo!(41, $a, 43)",
461 "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43)}",
462 &["foo!(41, 42, 43)"],
463 );
464 assert_no_match("foo!(50, $a, 43)", "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43}");
465 assert_no_match("foo!(41, $a, 50)", "macro_rules! foo {() => {}} fn() {foo!(41, 42, 43}");
466 assert_matches(
467 "foo!($a())",
468 "macro_rules! foo {() => {}} fn() {foo!(bar())}",
469 &["foo!(bar())"],
470 );
458} 471}
459 472
460// When matching within a macro expansion, we only allow matches of nodes that originated from 473// When matching within a macro expansion, we only allow matches of nodes that originated from
@@ -489,15 +502,20 @@ fn no_match_split_expression() {
489 502
490#[test] 503#[test]
491fn replace_function_call() { 504fn replace_function_call() {
492 assert_ssr_transform("foo() ==>> bar()", "fn f1() {foo(); foo();}", "fn f1() {bar(); bar();}"); 505 // This test also makes sure that we ignore empty-ranges.
506 assert_ssr_transform(
507 "foo() ==>> bar()",
508 "fn foo() {<|><|>} fn bar() {} fn f1() {foo(); foo();}",
509 expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]],
510 );
493} 511}
494 512
495#[test] 513#[test]
496fn replace_function_call_with_placeholders() { 514fn replace_function_call_with_placeholders() {
497 assert_ssr_transform( 515 assert_ssr_transform(
498 "foo($a, $b) ==>> bar($b, $a)", 516 "foo($a, $b) ==>> bar($b, $a)",
499 "fn f1() {foo(5, 42)}", 517 "fn foo() {} fn bar() {} fn f1() {foo(5, 42)}",
500 "fn f1() {bar(42, 5)}", 518 expect![["fn foo() {} fn bar() {} fn f1() {bar(42, 5)}"]],
501 ); 519 );
502} 520}
503 521
@@ -505,26 +523,120 @@ fn replace_function_call_with_placeholders() {
505fn replace_nested_function_calls() { 523fn replace_nested_function_calls() {
506 assert_ssr_transform( 524 assert_ssr_transform(
507 "foo($a) ==>> bar($a)", 525 "foo($a) ==>> bar($a)",
508 "fn f1() {foo(foo(42))}", 526 "fn foo() {} fn bar() {} fn f1() {foo(foo(42))}",
509 "fn f1() {bar(bar(42))}", 527 expect![["fn foo() {} fn bar() {} fn f1() {bar(bar(42))}"]],
510 ); 528 );
511} 529}
512 530
513#[test] 531#[test]
514fn replace_type() { 532fn replace_associated_function_call() {
515 assert_ssr_transform( 533 assert_ssr_transform(
516 "Result<(), $a> ==>> Option<$a>", 534 "Foo::new() ==>> Bar::new()",
517 "fn f1() -> Result<(), Vec<Error>> {foo()}", 535 r#"
518 "fn f1() -> Option<Vec<Error>> {foo()}", 536 struct Foo {}
537 impl Foo { fn new() {} }
538 struct Bar {}
539 impl Bar { fn new() {} }
540 fn f1() {Foo::new();}
541 "#,
542 expect![[r#"
543 struct Foo {}
544 impl Foo { fn new() {} }
545 struct Bar {}
546 impl Bar { fn new() {} }
547 fn f1() {Bar::new();}
548 "#]],
519 ); 549 );
520} 550}
521 551
522#[test] 552#[test]
523fn replace_struct_init() { 553fn replace_path_in_different_contexts() {
554 // Note the <|> inside module a::b which marks the point where the rule is interpreted. We
555 // replace foo with bar, but both need different path qualifiers in different contexts. In f4,
556 // foo is unqualified because of a use statement, however the replacement needs to be fully
557 // qualified.
524 assert_ssr_transform( 558 assert_ssr_transform(
525 "Foo {a: $a, b: $b} ==>> Foo::new($a, $b)", 559 "c::foo() ==>> c::bar()",
526 "fn f1() {Foo{b: 1, a: 2}}", 560 r#"
527 "fn f1() {Foo::new(2, 1)}", 561 mod a {
562 pub mod b {<|>
563 pub mod c {
564 pub fn foo() {}
565 pub fn bar() {}
566 fn f1() { foo() }
567 }
568 fn f2() { c::foo() }
569 }
570 fn f3() { b::c::foo() }
571 }
572 use a::b::c::foo;
573 fn f4() { foo() }
574 "#,
575 expect![[r#"
576 mod a {
577 pub mod b {
578 pub mod c {
579 pub fn foo() {}
580 pub fn bar() {}
581 fn f1() { bar() }
582 }
583 fn f2() { c::bar() }
584 }
585 fn f3() { b::c::bar() }
586 }
587 use a::b::c::foo;
588 fn f4() { a::b::c::bar() }
589 "#]],
590 );
591}
592
593#[test]
594fn replace_associated_function_with_generics() {
595 assert_ssr_transform(
596 "c::Foo::<$a>::new() ==>> d::Bar::<$a>::default()",
597 r#"
598 mod c {
599 pub struct Foo<T> {v: T}
600 impl<T> Foo<T> { pub fn new() {} }
601 fn f1() {
602 Foo::<i32>::new();
603 }
604 }
605 mod d {
606 pub struct Bar<T> {v: T}
607 impl<T> Bar<T> { pub fn default() {} }
608 fn f1() {
609 super::c::Foo::<i32>::new();
610 }
611 }
612 "#,
613 expect![[r#"
614 mod c {
615 pub struct Foo<T> {v: T}
616 impl<T> Foo<T> { pub fn new() {} }
617 fn f1() {
618 crate::d::Bar::<i32>::default();
619 }
620 }
621 mod d {
622 pub struct Bar<T> {v: T}
623 impl<T> Bar<T> { pub fn default() {} }
624 fn f1() {
625 Bar::<i32>::default();
626 }
627 }
628 "#]],
629 );
630}
631
632#[test]
633fn replace_type() {
634 assert_ssr_transform(
635 "Result<(), $a> ==>> Option<$a>",
636 "struct Result<T, E> {} struct Option<T> {} fn f1() -> Result<(), Vec<Error>> {foo()}",
637 expect![[
638 "struct Result<T, E> {} struct Option<T> {} fn f1() -> Option<Vec<Error>> {foo()}"
639 ]],
528 ); 640 );
529} 641}
530 642
@@ -532,13 +644,13 @@ fn replace_struct_init() {
532fn replace_macro_invocations() { 644fn replace_macro_invocations() {
533 assert_ssr_transform( 645 assert_ssr_transform(
534 "try!($a) ==>> $a?", 646 "try!($a) ==>> $a?",
535 "fn f1() -> Result<(), E> {bar(try!(foo()));}", 647 "macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(try!(foo()));}",
536 "fn f1() -> Result<(), E> {bar(foo()?);}", 648 expect![["macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(foo()?);}"]],
537 ); 649 );
538 assert_ssr_transform( 650 assert_ssr_transform(
539 "foo!($a($b)) ==>> foo($b, $a)", 651 "foo!($a($b)) ==>> foo($b, $a)",
540 "fn f1() {foo!(abc(def() + 2));}", 652 "macro_rules! foo {() => {}} fn f1() {foo!(abc(def() + 2));}",
541 "fn f1() {foo(def() + 2, abc);}", 653 expect![["macro_rules! foo {() => {}} fn f1() {foo(def() + 2, abc);}"]],
542 ); 654 );
543} 655}
544 656
@@ -547,12 +659,12 @@ fn replace_binary_op() {
547 assert_ssr_transform( 659 assert_ssr_transform(
548 "$a + $b ==>> $b + $a", 660 "$a + $b ==>> $b + $a",
549 "fn f() {2 * 3 + 4 * 5}", 661 "fn f() {2 * 3 + 4 * 5}",
550 "fn f() {4 * 5 + 2 * 3}", 662 expect![["fn f() {4 * 5 + 2 * 3}"]],
551 ); 663 );
552 assert_ssr_transform( 664 assert_ssr_transform(
553 "$a + $b ==>> $b + $a", 665 "$a + $b ==>> $b + $a",
554 "fn f() {1 + 2 + 3 + 4}", 666 "fn f() {1 + 2 + 3 + 4}",
555 "fn f() {4 + 3 + 2 + 1}", 667 expect![[r#"fn f() {4 + (3 + (2 + 1))}"#]],
556 ); 668 );
557} 669}
558 670
@@ -565,8 +677,23 @@ fn match_binary_op() {
565fn multiple_rules() { 677fn multiple_rules() {
566 assert_ssr_transforms( 678 assert_ssr_transforms(
567 &["$a + 1 ==>> add_one($a)", "$a + $b ==>> add($a, $b)"], 679 &["$a + 1 ==>> add_one($a)", "$a + $b ==>> add($a, $b)"],
568 "fn f() -> i32 {3 + 2 + 1}", 680 "fn add() {} fn add_one() {} fn f() -> i32 {3 + 2 + 1}",
569 "fn f() -> i32 {add_one(add(3, 2))}", 681 expect![["fn add() {} fn add_one() {} fn f() -> i32 {add_one(add(3, 2))}"]],
682 )
683}
684
685#[test]
686fn multiple_rules_with_nested_matches() {
687 assert_ssr_transforms(
688 &["foo1($a) ==>> bar1($a)", "foo2($a) ==>> bar2($a)"],
689 r#"
690 fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {}
691 fn f() {foo1(foo2(foo1(foo2(foo1(42)))))}
692 "#,
693 expect![[r#"
694 fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {}
695 fn f() {bar1(bar2(bar1(bar2(bar1(42)))))}
696 "#]],
570 ) 697 )
571} 698}
572 699
@@ -598,12 +725,37 @@ fn replace_within_macro_expansion() {
598 macro_rules! macro1 { 725 macro_rules! macro1 {
599 ($a:expr) => {$a} 726 ($a:expr) => {$a}
600 } 727 }
601 fn f() {macro1!(5.x().foo().o2())}"#, 728 fn bar() {}
729 fn f() {macro1!(5.x().foo().o2())}
730 "#,
731 expect![[r#"
732 macro_rules! macro1 {
733 ($a:expr) => {$a}
734 }
735 fn bar() {}
736 fn f() {macro1!(bar(5.x()).o2())}
737 "#]],
738 )
739}
740
741#[test]
742fn replace_outside_and_within_macro_expansion() {
743 assert_ssr_transform(
744 "foo($a) ==>> bar($a)",
602 r#" 745 r#"
746 fn foo() {} fn bar() {}
603 macro_rules! macro1 { 747 macro_rules! macro1 {
604 ($a:expr) => {$a} 748 ($a:expr) => {$a}
605 } 749 }
606 fn f() {macro1!(bar(5.x()).o2())}"#, 750 fn f() {foo(foo(macro1!(foo(foo(42)))))}
751 "#,
752 expect![[r#"
753 fn foo() {} fn bar() {}
754 macro_rules! macro1 {
755 ($a:expr) => {$a}
756 }
757 fn f() {bar(bar(macro1!(bar(bar(42)))))}
758 "#]],
607 ) 759 )
608} 760}
609 761
@@ -615,11 +767,280 @@ fn preserves_whitespace_within_macro_expansion() {
615 macro_rules! macro1 { 767 macro_rules! macro1 {
616 ($a:expr) => {$a} 768 ($a:expr) => {$a}
617 } 769 }
618 fn f() {macro1!(1 * 2 + 3 + 4}"#, 770 fn f() {macro1!(1 * 2 + 3 + 4}
619 r#" 771 "#,
772 expect![[r#"
620 macro_rules! macro1 { 773 macro_rules! macro1 {
621 ($a:expr) => {$a} 774 ($a:expr) => {$a}
622 } 775 }
623 fn f() {macro1!(4 - 3 - 1 * 2}"#, 776 fn f() {macro1!(4 - (3 - 1 * 2)}
777 "#]],
778 )
779}
780
781#[test]
782fn add_parenthesis_when_necessary() {
783 assert_ssr_transform(
784 "foo($a) ==>> $a.to_string()",
785 r#"
786 fn foo(_: i32) {}
787 fn bar3(v: i32) {
788 foo(1 + 2);
789 foo(-v);
790 }
791 "#,
792 expect![[r#"
793 fn foo(_: i32) {}
794 fn bar3(v: i32) {
795 (1 + 2).to_string();
796 (-v).to_string();
797 }
798 "#]],
799 )
800}
801
802#[test]
803fn match_failure_reasons() {
804 let code = r#"
805 fn bar() {}
806 macro_rules! foo {
807 ($a:expr) => {
808 1 + $a + 2
809 };
810 }
811 fn f1() {
812 bar(1, 2);
813 foo!(5 + 43.to_string() + 5);
814 }
815 "#;
816 assert_match_failure_reason(
817 "bar($a, 3)",
818 code,
819 "bar(1, 2)",
820 r#"Pattern wanted token '3' (INT_NUMBER), but code had token '2' (INT_NUMBER)"#,
821 );
822 assert_match_failure_reason(
823 "42.to_string()",
824 code,
825 "43.to_string()",
826 r#"Pattern wanted token '42' (INT_NUMBER), but code had token '43' (INT_NUMBER)"#,
827 );
828}
829
830#[test]
831fn overlapping_possible_matches() {
832 // There are three possible matches here, however the middle one, `foo(foo(foo(42)))` shouldn't
833 // match because it overlaps with the outer match. The inner match is permitted since it's is
834 // contained entirely within the placeholder of the outer match.
835 assert_matches(
836 "foo(foo($a))",
837 "fn foo() {} fn main() {foo(foo(foo(foo(42))))}",
838 &["foo(foo(42))", "foo(foo(foo(foo(42))))"],
839 );
840}
841
842#[test]
843fn use_declaration_with_braces() {
844 // It would be OK for a path rule to match and alter a use declaration. We shouldn't mess it up
845 // though. In particular, we must not change `use foo::{baz, bar}` to `use foo::{baz,
846 // foo2::bar2}`.
847 mark::check!(use_declaration_with_braces);
848 assert_ssr_transform(
849 "foo::bar ==>> foo2::bar2",
850 r#"
851 mod foo { pub fn bar() {} pub fn baz() {} }
852 mod foo2 { pub fn bar2() {} }
853 use foo::{baz, bar};
854 fn main() { bar() }
855 "#,
856 expect![["
857 mod foo { pub fn bar() {} pub fn baz() {} }
858 mod foo2 { pub fn bar2() {} }
859 use foo::{baz, bar};
860 fn main() { foo2::bar2() }
861 "]],
862 )
863}
864
865#[test]
866fn ufcs_matches_method_call() {
867 let code = r#"
868 struct Foo {}
869 impl Foo {
870 fn new(_: i32) -> Foo { Foo {} }
871 fn do_stuff(&self, _: i32) {}
872 }
873 struct Bar {}
874 impl Bar {
875 fn new(_: i32) -> Bar { Bar {} }
876 fn do_stuff(&self, v: i32) {}
877 }
878 fn main() {
879 let b = Bar {};
880 let f = Foo {};
881 b.do_stuff(1);
882 f.do_stuff(2);
883 Foo::new(4).do_stuff(3);
884 // Too many / too few args - should never match
885 f.do_stuff(2, 10);
886 f.do_stuff();
887 }
888 "#;
889 assert_matches("Foo::do_stuff($a, $b)", code, &["f.do_stuff(2)", "Foo::new(4).do_stuff(3)"]);
890 // The arguments needs special handling in the case of a function call matching a method call
891 // and the first argument is different.
892 assert_matches("Foo::do_stuff($a, 2)", code, &["f.do_stuff(2)"]);
893 assert_matches("Foo::do_stuff(Foo::new(4), $b)", code, &["Foo::new(4).do_stuff(3)"]);
894
895 assert_ssr_transform(
896 "Foo::do_stuff(Foo::new($a), $b) ==>> Bar::new($b).do_stuff($a)",
897 code,
898 expect![[r#"
899 struct Foo {}
900 impl Foo {
901 fn new(_: i32) -> Foo { Foo {} }
902 fn do_stuff(&self, _: i32) {}
903 }
904 struct Bar {}
905 impl Bar {
906 fn new(_: i32) -> Bar { Bar {} }
907 fn do_stuff(&self, v: i32) {}
908 }
909 fn main() {
910 let b = Bar {};
911 let f = Foo {};
912 b.do_stuff(1);
913 f.do_stuff(2);
914 Bar::new(3).do_stuff(4);
915 // Too many / too few args - should never match
916 f.do_stuff(2, 10);
917 f.do_stuff();
918 }
919 "#]],
920 );
921}
922
923#[test]
924fn pattern_is_a_single_segment_path() {
925 mark::check!(pattern_is_a_single_segment_path);
926 // The first function should not be altered because the `foo` in scope at the cursor position is
927 // a different `foo`. This case is special because "foo" can be parsed as a pattern (BIND_PAT ->
928 // NAME -> IDENT), which contains no path. If we're not careful we'll end up matching the `foo`
929 // in `let foo` from the first function. Whether we should match the `let foo` in the second
930 // function is less clear. At the moment, we don't. Doing so sounds like a rename operation,
931 // which isn't really what SSR is for, especially since the replacement `bar` must be able to be
932 // resolved, which means if we rename `foo` we'll get a name collision.
933 assert_ssr_transform(
934 "foo ==>> bar",
935 r#"
936 fn f1() -> i32 {
937 let foo = 1;
938 let bar = 2;
939 foo
940 }
941 fn f1() -> i32 {
942 let foo = 1;
943 let bar = 2;
944 foo<|>
945 }
946 "#,
947 expect![[r#"
948 fn f1() -> i32 {
949 let foo = 1;
950 let bar = 2;
951 foo
952 }
953 fn f1() -> i32 {
954 let foo = 1;
955 let bar = 2;
956 bar
957 }
958 "#]],
959 );
960}
961
962#[test]
963fn replace_local_variable_reference() {
964 // The pattern references a local variable `foo` in the block containing the cursor. We should
965 // only replace references to this variable `foo`, not other variables that just happen to have
966 // the same name.
967 mark::check!(cursor_after_semicolon);
968 assert_ssr_transform(
969 "foo + $a ==>> $a - foo",
970 r#"
971 fn bar1() -> i32 {
972 let mut res = 0;
973 let foo = 5;
974 res += foo + 1;
975 let foo = 10;
976 res += foo + 2;<|>
977 res += foo + 3;
978 let foo = 15;
979 res += foo + 4;
980 res
981 }
982 "#,
983 expect![[r#"
984 fn bar1() -> i32 {
985 let mut res = 0;
986 let foo = 5;
987 res += foo + 1;
988 let foo = 10;
989 res += 2 - foo;
990 res += 3 - foo;
991 let foo = 15;
992 res += foo + 4;
993 res
994 }
995 "#]],
624 ) 996 )
625} 997}
998
999#[test]
1000fn replace_path_within_selection() {
1001 assert_ssr_transform(
1002 "foo ==>> bar",
1003 r#"
1004 fn main() {
1005 let foo = 41;
1006 let bar = 42;
1007 do_stuff(foo);
1008 do_stuff(foo);<|>
1009 do_stuff(foo);
1010 do_stuff(foo);<|>
1011 do_stuff(foo);
1012 }"#,
1013 expect![[r#"
1014 fn main() {
1015 let foo = 41;
1016 let bar = 42;
1017 do_stuff(foo);
1018 do_stuff(foo);
1019 do_stuff(bar);
1020 do_stuff(bar);
1021 do_stuff(foo);
1022 }"#]],
1023 );
1024}
1025
1026#[test]
1027fn replace_nonpath_within_selection() {
1028 mark::check!(replace_nonpath_within_selection);
1029 assert_ssr_transform(
1030 "$a + $b ==>> $b * $a",
1031 r#"
1032 fn main() {
1033 let v = 1 + 2;<|>
1034 let v2 = 3 + 3;
1035 let v3 = 4 + 5;<|>
1036 let v4 = 6 + 7;
1037 }"#,
1038 expect![[r#"
1039 fn main() {
1040 let v = 1 + 2;
1041 let v2 = 3 * 3;
1042 let v3 = 5 * 4;
1043 let v4 = 6 + 7;
1044 }"#]],
1045 );
1046}
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 49696ce75..fc4d7aa04 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "666.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "671.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
@@ -31,4 +31,6 @@ serde = { version = "1.0.106", features = ["derive"] }
31 31
32[dev-dependencies] 32[dev-dependencies]
33test_utils = { path = "../test_utils" } 33test_utils = { path = "../test_utils" }
34expect = { path = "../expect" }
34walkdir = "2.3.1" 35walkdir = "2.3.1"
36rayon = "1"
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 9d02aeef3..fd426ece9 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -2,9 +2,9 @@
2 2
3mod generated; 3mod generated;
4mod traits; 4mod traits;
5mod tokens; 5mod token_ext;
6mod extensions; 6mod node_ext;
7mod expr_extensions; 7mod expr_ext;
8pub mod edit; 8pub mod edit;
9pub mod make; 9pub mod make;
10 10
@@ -16,13 +16,13 @@ use crate::{
16}; 16};
17 17
18pub use self::{ 18pub use self::{
19 expr_extensions::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp}, 19 expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
20 extensions::{ 20 generated::{nodes::*, tokens::*},
21 node_ext::{
21 AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, 22 AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
22 StructKind, TypeBoundKind, VisibilityKind, 23 StructKind, TypeBoundKind, VisibilityKind,
23 }, 24 },
24 generated::{nodes::*, tokens::*}, 25 token_ext::*,
25 tokens::*,
26 traits::*, 26 traits::*,
27}; 27};
28 28
@@ -139,7 +139,7 @@ fn test_doc_comment_of_statics() {
139 ) 139 )
140 .ok() 140 .ok()
141 .unwrap(); 141 .unwrap();
142 let st = file.syntax().descendants().find_map(StaticDef::cast).unwrap(); 142 let st = file.syntax().descendants().find_map(Static::cast).unwrap();
143 assert_eq!("Number of levels", st.doc_comment_text().unwrap()); 143 assert_eq!("Number of levels", st.doc_comment_text().unwrap());
144} 144}
145 145
@@ -235,7 +235,7 @@ fn test_comments_preserve_trailing_whitespace() {
235 ) 235 )
236 .ok() 236 .ok()
237 .unwrap(); 237 .unwrap();
238 let def = file.syntax().descendants().find_map(StructDef::cast).unwrap(); 238 let def = file.syntax().descendants().find_map(Struct::cast).unwrap();
239 assert_eq!( 239 assert_eq!(
240 "Representation of a Realm. \nIn the specification these are called Realm Records.", 240 "Representation of a Realm. \nIn the specification these are called Realm Records.",
241 def.doc_comment_text().unwrap() 241 def.doc_comment_text().unwrap()
@@ -286,7 +286,7 @@ where
286 let mut bounds = pred.type_bound_list().unwrap().bounds(); 286 let mut bounds = pred.type_bound_list().unwrap().bounds();
287 287
288 assert!(pred.for_token().is_none()); 288 assert!(pred.for_token().is_none());
289 assert!(pred.type_param_list().is_none()); 289 assert!(pred.generic_param_list().is_none());
290 assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); 290 assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string());
291 assert_bound("Clone", bounds.next()); 291 assert_bound("Clone", bounds.next());
292 assert_bound("Copy", bounds.next()); 292 assert_bound("Copy", bounds.next());
@@ -325,7 +325,7 @@ where
325 let mut bounds = pred.type_bound_list().unwrap().bounds(); 325 let mut bounds = pred.type_bound_list().unwrap().bounds();
326 326
327 assert!(pred.for_token().is_some()); 327 assert!(pred.for_token().is_some());
328 assert_eq!("<'a>", pred.type_param_list().unwrap().syntax().text().to_string()); 328 assert_eq!("<'a>", pred.generic_param_list().unwrap().syntax().text().to_string());
329 assert_eq!("F", pred.type_ref().unwrap().syntax().text().to_string()); 329 assert_eq!("F", pred.type_ref().unwrap().syntax().text().to_string());
330 assert_bound("Fn(&'a str)", bounds.next()); 330 assert_bound("Fn(&'a str)", bounds.next());
331} 331}
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 2ef173a03..8d3e42f25 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -29,9 +29,9 @@ impl ast::BinExpr {
29 } 29 }
30} 30}
31 31
32impl ast::FnDef { 32impl ast::Fn {
33 #[must_use] 33 #[must_use]
34 pub fn with_body(&self, body: ast::BlockExpr) -> ast::FnDef { 34 pub fn with_body(&self, body: ast::BlockExpr) -> ast::Fn {
35 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); 35 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
36 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() { 36 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.body() {
37 old_body.syntax().clone().into() 37 old_body.syntax().clone().into()
@@ -80,9 +80,12 @@ where
80 } 80 }
81} 81}
82 82
83impl ast::ItemList { 83impl ast::AssocItemList {
84 #[must_use] 84 #[must_use]
85 pub fn append_items(&self, items: impl IntoIterator<Item = ast::AssocItem>) -> ast::ItemList { 85 pub fn append_items(
86 &self,
87 items: impl IntoIterator<Item = ast::AssocItem>,
88 ) -> ast::AssocItemList {
86 let mut res = self.clone(); 89 let mut res = self.clone();
87 if !self.syntax().text().contains_char('\n') { 90 if !self.syntax().text().contains_char('\n') {
88 res = make_multiline(res); 91 res = make_multiline(res);
@@ -92,7 +95,7 @@ impl ast::ItemList {
92 } 95 }
93 96
94 #[must_use] 97 #[must_use]
95 pub fn append_item(&self, item: ast::AssocItem) -> ast::ItemList { 98 pub fn append_item(&self, item: ast::AssocItem) -> ast::AssocItemList {
96 let (indent, position) = match self.assoc_items().last() { 99 let (indent, position) = match self.assoc_items().last() {
97 Some(it) => ( 100 Some(it) => (
98 leading_indent(it.syntax()).unwrap_or_default().to_string(), 101 leading_indent(it.syntax()).unwrap_or_default().to_string(),
@@ -113,18 +116,18 @@ impl ast::ItemList {
113 } 116 }
114} 117}
115 118
116impl ast::RecordFieldList { 119impl ast::RecordExprFieldList {
117 #[must_use] 120 #[must_use]
118 pub fn append_field(&self, field: &ast::RecordField) -> ast::RecordFieldList { 121 pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList {
119 self.insert_field(InsertPosition::Last, field) 122 self.insert_field(InsertPosition::Last, field)
120 } 123 }
121 124
122 #[must_use] 125 #[must_use]
123 pub fn insert_field( 126 pub fn insert_field(
124 &self, 127 &self,
125 position: InsertPosition<&'_ ast::RecordField>, 128 position: InsertPosition<&'_ ast::RecordExprField>,
126 field: &ast::RecordField, 129 field: &ast::RecordExprField,
127 ) -> ast::RecordFieldList { 130 ) -> ast::RecordExprFieldList {
128 let is_multiline = self.syntax().text().contains_char('\n'); 131 let is_multiline = self.syntax().text().contains_char('\n');
129 let ws; 132 let ws;
130 let space = if is_multiline { 133 let space = if is_multiline {
@@ -189,6 +192,21 @@ impl ast::RecordFieldList {
189 } 192 }
190} 193}
191 194
195impl ast::TypeAlias {
196 #[must_use]
197 pub fn remove_bounds(&self) -> ast::TypeAlias {
198 let colon = match self.colon_token() {
199 Some(it) => it,
200 None => return self.clone(),
201 };
202 let end = match self.type_bound_list() {
203 Some(it) => it.syntax().clone().into(),
204 None => colon.clone().into(),
205 };
206 self.replace_children(colon.into()..=end, iter::empty())
207 }
208}
209
192impl ast::TypeParam { 210impl ast::TypeParam {
193 #[must_use] 211 #[must_use]
194 pub fn remove_bounds(&self) -> ast::TypeParam { 212 pub fn remove_bounds(&self) -> ast::TypeParam {
@@ -244,9 +262,9 @@ impl ast::PathSegment {
244 } 262 }
245} 263}
246 264
247impl ast::UseItem { 265impl ast::Use {
248 #[must_use] 266 #[must_use]
249 pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::UseItem { 267 pub fn with_use_tree(&self, use_tree: ast::UseTree) -> ast::Use {
250 if let Some(old) = self.use_tree() { 268 if let Some(old) = self.use_tree() {
251 return self.replace_descendant(old, use_tree); 269 return self.replace_descendant(old, use_tree);
252 } 270 }
@@ -300,9 +318,9 @@ impl ast::UseTree {
300 None => return self.clone(), 318 None => return self.clone(),
301 }; 319 };
302 let use_tree = make::use_tree( 320 let use_tree = make::use_tree(
303 suffix.clone(), 321 suffix,
304 self.use_tree_list(), 322 self.use_tree_list(),
305 self.alias(), 323 self.rename(),
306 self.star_token().is_some(), 324 self.star_token().is_some(),
307 ); 325 );
308 let nested = make::use_tree_list(iter::once(use_tree)); 326 let nested = make::use_tree_list(iter::once(use_tree));
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_ext.rs
index db5438d68..f5ba87223 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_ext.rs
@@ -7,6 +7,8 @@ use crate::{
7 SyntaxToken, T, 7 SyntaxToken, T,
8}; 8};
9 9
10impl ast::AttrsOwner for ast::Expr {}
11
10impl ast::Expr { 12impl ast::Expr {
11 pub fn is_block_like(&self) -> bool { 13 pub fn is_block_like(&self) -> bool {
12 match self { 14 match self {
@@ -331,13 +333,12 @@ impl ast::Literal {
331 333
332 match token.kind() { 334 match token.kind() {
333 INT_NUMBER => { 335 INT_NUMBER => {
334 // FYI: there was a bug here previously, thus an if statement bellow is necessary. 336 // FYI: there was a bug here previously, thus the if statement below is necessary.
335 // The lexer treats e.g. `1f64` as an integer literal. See 337 // The lexer treats e.g. `1f64` as an integer literal. See
336 // https://github.com/rust-analyzer/rust-analyzer/issues/1592 338 // https://github.com/rust-analyzer/rust-analyzer/issues/1592
337 // and the comments on the linked PR. 339 // and the comments on the linked PR.
338 340
339 let text = token.text(); 341 let text = token.text();
340
341 if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) { 342 if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) {
342 LiteralKind::FloatNumber { suffix } 343 LiteralKind::FloatNumber { suffix }
343 } else { 344 } else {
@@ -399,7 +400,7 @@ impl ast::BlockExpr {
399 Some(it) => it, 400 Some(it) => it,
400 None => return true, 401 None => return true,
401 }; 402 };
402 !matches!(parent.kind(), FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR) 403 !matches!(parent.kind(), FN | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR)
403 } 404 }
404} 405}
405 406
@@ -410,8 +411,8 @@ fn test_literal_with_attr() {
410 assert_eq!(lit.token().text(), r#""Hello""#); 411 assert_eq!(lit.token().text(), r#""Hello""#);
411} 412}
412 413
413impl ast::RecordField { 414impl ast::RecordExprField {
414 pub fn parent_record_lit(&self) -> ast::RecordLit { 415 pub fn parent_record_lit(&self) -> ast::RecordExpr {
415 self.syntax().ancestors().find_map(ast::RecordLit::cast).unwrap() 416 self.syntax().ancestors().find_map(ast::RecordExpr::cast).unwrap()
416 } 417 }
417} 418}
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 58141da11..4306efe13 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -5,557 +5,529 @@ use crate::{
5 SyntaxKind::{self, *}, 5 SyntaxKind::{self, *},
6 SyntaxNode, SyntaxToken, T, 6 SyntaxNode, SyntaxToken, T,
7}; 7};
8/// The entire Rust source file. Includes all top-level inner attributes and module items.
9///
10/// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
11#[derive(Debug, Clone, PartialEq, Eq, Hash)] 8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct SourceFile { 9pub struct SourceFile {
13 pub(crate) syntax: SyntaxNode, 10 pub(crate) syntax: SyntaxNode,
14} 11}
15impl ast::ModuleItemOwner for SourceFile {}
16impl ast::AttrsOwner for SourceFile {} 12impl ast::AttrsOwner for SourceFile {}
17impl ast::DocCommentsOwner for SourceFile {} 13impl ast::ModuleItemOwner for SourceFile {}
18impl SourceFile { 14impl SourceFile {
19 pub fn modules(&self) -> AstChildren<Module> { support::children(&self.syntax) } 15 pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) }
20} 16}
21/// Function definition either with body or not. 17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22/// Includes all of its attributes and doc comments. 18pub struct Attr {
23///
24/// ```
25/// ❰
26/// /// Docs
27/// #[attr]
28/// pub extern "C" fn foo<T>(#[attr] Patern {p}: Pattern) -> u32
29/// where
30/// T: Debug
31/// {
32/// 42
33/// }
34/// ❱
35///
36/// extern "C" {
37/// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱
38/// }
39/// ```
40///
41/// - [Reference](https://doc.rust-lang.org/reference/items/functions.html)
42/// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions)
43#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub struct FnDef {
45 pub(crate) syntax: SyntaxNode, 19 pub(crate) syntax: SyntaxNode,
46} 20}
47impl ast::VisibilityOwner for FnDef {} 21impl Attr {
48impl ast::NameOwner for FnDef {} 22 pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
49impl ast::TypeParamsOwner for FnDef {} 23 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
50impl ast::DocCommentsOwner for FnDef {} 24 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
51impl ast::AttrsOwner for FnDef {} 25 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
52impl FnDef { 26 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
53 pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) } 27 pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
28 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
29 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
30}
31#[derive(Debug, Clone, PartialEq, Eq, Hash)]
32pub struct Const {
33 pub(crate) syntax: SyntaxNode,
34}
35impl ast::AttrsOwner for Const {}
36impl ast::NameOwner for Const {}
37impl ast::VisibilityOwner for Const {}
38impl Const {
39 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
54 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 40 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
41 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
42 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
43 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
44 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
45 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
46 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
47}
48#[derive(Debug, Clone, PartialEq, Eq, Hash)]
49pub struct Enum {
50 pub(crate) syntax: SyntaxNode,
51}
52impl ast::AttrsOwner for Enum {}
53impl ast::NameOwner for Enum {}
54impl ast::VisibilityOwner for Enum {}
55impl ast::GenericParamsOwner for Enum {}
56impl Enum {
57 pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
58 pub fn variant_list(&self) -> Option<VariantList> { support::child(&self.syntax) }
59}
60#[derive(Debug, Clone, PartialEq, Eq, Hash)]
61pub struct ExternBlock {
62 pub(crate) syntax: SyntaxNode,
63}
64impl ast::AttrsOwner for ExternBlock {}
65impl ExternBlock {
66 pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
67 pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) }
68}
69#[derive(Debug, Clone, PartialEq, Eq, Hash)]
70pub struct ExternCrate {
71 pub(crate) syntax: SyntaxNode,
72}
73impl ast::AttrsOwner for ExternCrate {}
74impl ast::VisibilityOwner for ExternCrate {}
75impl ExternCrate {
76 pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
77 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
78 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
79 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
80 pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
81 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
82}
83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
84pub struct Fn {
85 pub(crate) syntax: SyntaxNode,
86}
87impl ast::AttrsOwner for Fn {}
88impl ast::NameOwner for Fn {}
89impl ast::VisibilityOwner for Fn {}
90impl ast::GenericParamsOwner for Fn {}
91impl Fn {
55 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } 92 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
56 pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } 93 pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
94 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
57 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } 95 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
96 pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
58 pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) } 97 pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) }
59 pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } 98 pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
60 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } 99 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
61 pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) } 100 pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
62 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 101 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
63} 102}
64/// Return type annotation.
65///
66/// ```
67/// fn foo(a: u32) ❰ -> Option<u32> ❱ { Some(a) }
68/// ```
69///
70/// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
71#[derive(Debug, Clone, PartialEq, Eq, Hash)] 103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
72pub struct RetType { 104pub struct Impl {
73 pub(crate) syntax: SyntaxNode, 105 pub(crate) syntax: SyntaxNode,
74} 106}
75impl RetType { 107impl ast::AttrsOwner for Impl {}
76 pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) } 108impl ast::VisibilityOwner for Impl {}
109impl ast::GenericParamsOwner for Impl {}
110impl Impl {
111 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
112 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
113 pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
114 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
77 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 115 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
116 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
117 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
118 pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
119}
120#[derive(Debug, Clone, PartialEq, Eq, Hash)]
121pub struct MacroCall {
122 pub(crate) syntax: SyntaxNode,
123}
124impl ast::AttrsOwner for MacroCall {}
125impl ast::NameOwner for MacroCall {}
126impl MacroCall {
127 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
128 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
129 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
130 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
131}
132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
133pub struct Module {
134 pub(crate) syntax: SyntaxNode,
135}
136impl ast::AttrsOwner for Module {}
137impl ast::NameOwner for Module {}
138impl ast::VisibilityOwner for Module {}
139impl Module {
140 pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
141 pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
142 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
143}
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145pub struct Static {
146 pub(crate) syntax: SyntaxNode,
147}
148impl ast::AttrsOwner for Static {}
149impl ast::NameOwner for Static {}
150impl ast::VisibilityOwner for Static {}
151impl Static {
152 pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) }
153 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
154 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
155 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
156 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
157 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
158 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
78} 159}
79/// Struct definition. 160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80/// Includes all of its attributes and doc comments. 161pub struct Struct {
81///
82/// ```
83/// ❰
84/// /// Docs
85/// #[attr]
86/// struct Foo<T> where T: Debug {
87/// /// Docs
88/// #[attr]
89/// pub a: u32,
90/// b: T,
91/// }
92/// ❱
93///
94/// ❰ struct Foo; ❱
95/// ❰ struct Foo<T>(#[attr] T) where T: Debug; ❱
96/// ```
97///
98/// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
99#[derive(Debug, Clone, PartialEq, Eq, Hash)]
100pub struct StructDef {
101 pub(crate) syntax: SyntaxNode, 162 pub(crate) syntax: SyntaxNode,
102} 163}
103impl ast::VisibilityOwner for StructDef {} 164impl ast::AttrsOwner for Struct {}
104impl ast::NameOwner for StructDef {} 165impl ast::NameOwner for Struct {}
105impl ast::TypeParamsOwner for StructDef {} 166impl ast::VisibilityOwner for Struct {}
106impl ast::AttrsOwner for StructDef {} 167impl ast::GenericParamsOwner for Struct {}
107impl ast::DocCommentsOwner for StructDef {} 168impl Struct {
108impl StructDef {
109 pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) } 169 pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) }
110 pub fn field_def_list(&self) -> Option<FieldDefList> { support::child(&self.syntax) }
111 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 170 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
171 pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
112} 172}
113/// Union definition. 173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
114/// Includes all of its attributes and doc comments. 174pub struct Trait {
115/// 175 pub(crate) syntax: SyntaxNode,
116/// ``` 176}
117/// ❰ 177impl ast::AttrsOwner for Trait {}
118/// /// Docs 178impl ast::NameOwner for Trait {}
119/// #[attr] 179impl ast::VisibilityOwner for Trait {}
120/// pub union Foo<T> where T: Debug { 180impl ast::GenericParamsOwner for Trait {}
121/// /// Docs 181impl ast::TypeBoundsOwner for Trait {}
122/// #[attr] 182impl Trait {
123/// a: T, 183 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
124/// b: u32, 184 pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
125/// } 185 pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
126/// ❱ 186 pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
127/// ``` 187}
128/// 188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
129/// [Reference](https://doc.rust-lang.org/reference/items/unions.html) 189pub struct TypeAlias {
130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131pub struct UnionDef {
132 pub(crate) syntax: SyntaxNode, 190 pub(crate) syntax: SyntaxNode,
133} 191}
134impl ast::VisibilityOwner for UnionDef {} 192impl ast::AttrsOwner for TypeAlias {}
135impl ast::NameOwner for UnionDef {} 193impl ast::NameOwner for TypeAlias {}
136impl ast::TypeParamsOwner for UnionDef {} 194impl ast::VisibilityOwner for TypeAlias {}
137impl ast::AttrsOwner for UnionDef {} 195impl ast::GenericParamsOwner for TypeAlias {}
138impl ast::DocCommentsOwner for UnionDef {} 196impl ast::TypeBoundsOwner for TypeAlias {}
139impl UnionDef { 197impl TypeAlias {
198 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
199 pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
200 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
201 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
202 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
203}
204#[derive(Debug, Clone, PartialEq, Eq, Hash)]
205pub struct Union {
206 pub(crate) syntax: SyntaxNode,
207}
208impl ast::AttrsOwner for Union {}
209impl ast::NameOwner for Union {}
210impl ast::VisibilityOwner for Union {}
211impl ast::GenericParamsOwner for Union {}
212impl Union {
140 pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) } 213 pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) }
141 pub fn record_field_def_list(&self) -> Option<RecordFieldDefList> { 214 pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) }
142 support::child(&self.syntax) 215}
143 } 216#[derive(Debug, Clone, PartialEq, Eq, Hash)]
217pub struct Use {
218 pub(crate) syntax: SyntaxNode,
219}
220impl ast::AttrsOwner for Use {}
221impl ast::VisibilityOwner for Use {}
222impl Use {
223 pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
224 pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
225 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
226}
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct Visibility {
229 pub(crate) syntax: SyntaxNode,
230}
231impl Visibility {
232 pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) }
233 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
234 pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
235 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
236 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
237 pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
238 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
239 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
240}
241#[derive(Debug, Clone, PartialEq, Eq, Hash)]
242pub struct Name {
243 pub(crate) syntax: SyntaxNode,
244}
245impl Name {
246 pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
247}
248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
249pub struct ItemList {
250 pub(crate) syntax: SyntaxNode,
251}
252impl ast::AttrsOwner for ItemList {}
253impl ast::ModuleItemOwner for ItemList {}
254impl ItemList {
255 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
256 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
257}
258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
259pub struct NameRef {
260 pub(crate) syntax: SyntaxNode,
144} 261}
145/// Record field definition list including enclosing curly braces. 262impl NameRef {
146/// 263 pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
147/// ``` 264}
148/// struct Foo // same for union 265#[derive(Debug, Clone, PartialEq, Eq, Hash)]
149/// ❰ 266pub struct Rename {
150/// { 267 pub(crate) syntax: SyntaxNode,
151/// a: u32, 268}
152/// b: bool, 269impl ast::NameOwner for Rename {}
153/// } 270impl Rename {
154/// ❱ 271 pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
155/// ``` 272 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
156/// 273}
157/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) 274#[derive(Debug, Clone, PartialEq, Eq, Hash)]
158#[derive(Debug, Clone, PartialEq, Eq, Hash)] 275pub struct UseTree {
159pub struct RecordFieldDefList { 276 pub(crate) syntax: SyntaxNode,
277}
278impl UseTree {
279 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
280 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
281 pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
282 pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
283 pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) }
284}
285#[derive(Debug, Clone, PartialEq, Eq, Hash)]
286pub struct Path {
287 pub(crate) syntax: SyntaxNode,
288}
289impl Path {
290 pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
291 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
292 pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
293}
294#[derive(Debug, Clone, PartialEq, Eq, Hash)]
295pub struct UseTreeList {
160 pub(crate) syntax: SyntaxNode, 296 pub(crate) syntax: SyntaxNode,
161} 297}
162impl RecordFieldDefList { 298impl UseTreeList {
163 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 299 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
164 pub fn fields(&self) -> AstChildren<RecordFieldDef> { support::children(&self.syntax) } 300 pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
165 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 301 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
166} 302}
167/// Record field definition including its attributes and doc comments. 303#[derive(Debug, Clone, PartialEq, Eq, Hash)]
168/// 304pub struct Abi {
169/// ` ``
170/// same for union
171/// struct Foo {
172/// ❰
173/// /// Docs
174/// #[attr]
175/// pub a: u32
176/// ❱
177///
178/// ❰ b: bool ❱
179/// }
180/// ```
181///
182/// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
183#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184pub struct RecordFieldDef {
185 pub(crate) syntax: SyntaxNode, 305 pub(crate) syntax: SyntaxNode,
186} 306}
187impl ast::VisibilityOwner for RecordFieldDef {} 307impl Abi {
188impl ast::NameOwner for RecordFieldDef {} 308 pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
189impl ast::AttrsOwner for RecordFieldDef {} 309}
190impl ast::DocCommentsOwner for RecordFieldDef {} 310#[derive(Debug, Clone, PartialEq, Eq, Hash)]
191impl ast::TypeAscriptionOwner for RecordFieldDef {} 311pub struct GenericParamList {
192impl RecordFieldDef {} 312 pub(crate) syntax: SyntaxNode,
193/// Tuple field definition list including enclosing parens. 313}
194/// 314impl GenericParamList {
195/// ``` 315 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
196/// struct Foo ❰ (u32, String, Vec<u32>) ❱; 316 pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
197/// ``` 317 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
198/// 318}
199/// [Reference](https://doc.rust-lang.org/reference/items/structs.html) 319#[derive(Debug, Clone, PartialEq, Eq, Hash)]
200#[derive(Debug, Clone, PartialEq, Eq, Hash)] 320pub struct ParamList {
201pub struct TupleFieldDefList {
202 pub(crate) syntax: SyntaxNode, 321 pub(crate) syntax: SyntaxNode,
203} 322}
204impl TupleFieldDefList { 323impl ParamList {
205 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } 324 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
206 pub fn fields(&self) -> AstChildren<TupleFieldDef> { support::children(&self.syntax) } 325 pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) }
326 pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
327 pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
207 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 328 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
208} 329}
209/// Tuple field definition including its attributes.
210///
211/// ```
212/// struct Foo(❰ #[attr] u32 ❱);
213/// ```
214///
215/// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
216#[derive(Debug, Clone, PartialEq, Eq, Hash)] 330#[derive(Debug, Clone, PartialEq, Eq, Hash)]
217pub struct TupleFieldDef { 331pub struct RetType {
218 pub(crate) syntax: SyntaxNode, 332 pub(crate) syntax: SyntaxNode,
219} 333}
220impl ast::VisibilityOwner for TupleFieldDef {} 334impl RetType {
221impl ast::AttrsOwner for TupleFieldDef {} 335 pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) }
222impl TupleFieldDef { 336 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
223 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
224} 337}
225/// Enum definition. 338#[derive(Debug, Clone, PartialEq, Eq, Hash)]
226/// Includes all of its attributes and doc comments. 339pub struct WhereClause {
227///
228/// ```
229/// ❰
230/// /// Docs
231/// #[attr]
232/// pub enum Foo<T> where T: Debug {
233/// /// Docs
234/// #[attr]
235/// Bar,
236/// Baz(#[attr] u32),
237/// Bruh {
238/// a: u32,
239/// /// Docs
240/// #[attr]
241/// b: T,
242/// }
243/// }
244/// ❱
245/// ```
246///
247/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
249pub struct EnumDef {
250 pub(crate) syntax: SyntaxNode, 340 pub(crate) syntax: SyntaxNode,
251} 341}
252impl ast::VisibilityOwner for EnumDef {} 342impl WhereClause {
253impl ast::NameOwner for EnumDef {} 343 pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) }
254impl ast::TypeParamsOwner for EnumDef {} 344 pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) }
255impl ast::AttrsOwner for EnumDef {} 345}
256impl ast::DocCommentsOwner for EnumDef {} 346#[derive(Debug, Clone, PartialEq, Eq, Hash)]
257impl EnumDef { 347pub struct BlockExpr {
258 pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) }
259 pub fn variant_list(&self) -> Option<EnumVariantList> { support::child(&self.syntax) }
260}
261/// Enum variant definition list including enclosing curly braces.
262///
263/// ```
264/// enum Foo
265/// ❰
266/// {
267/// Bar,
268/// Baz(u32),
269/// Bruh {
270/// a: u32
271/// }
272/// }
273/// ❱
274/// ```
275///
276/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
277#[derive(Debug, Clone, PartialEq, Eq, Hash)]
278pub struct EnumVariantList {
279 pub(crate) syntax: SyntaxNode, 348 pub(crate) syntax: SyntaxNode,
280} 349}
281impl EnumVariantList { 350impl ast::AttrsOwner for BlockExpr {}
351impl ast::ModuleItemOwner for BlockExpr {}
352impl BlockExpr {
353 pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
282 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 354 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
283 pub fn variants(&self) -> AstChildren<EnumVariant> { support::children(&self.syntax) } 355 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
356 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
284 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 357 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
285} 358}
286/// Enum variant definition including its attributes and discriminant value definition. 359#[derive(Debug, Clone, PartialEq, Eq, Hash)]
287/// 360pub struct SelfParam {
288/// ```
289/// enum Foo {
290/// ❰
291/// /// Docs
292/// #[attr]
293/// Bar
294/// ❱
295///
296/// // same for tuple and record variants
297/// }
298/// ```
299///
300/// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
301#[derive(Debug, Clone, PartialEq, Eq, Hash)]
302pub struct EnumVariant {
303 pub(crate) syntax: SyntaxNode, 361 pub(crate) syntax: SyntaxNode,
304} 362}
305impl ast::VisibilityOwner for EnumVariant {} 363impl ast::AttrsOwner for SelfParam {}
306impl ast::NameOwner for EnumVariant {} 364impl SelfParam {
307impl ast::DocCommentsOwner for EnumVariant {} 365 pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
308impl ast::AttrsOwner for EnumVariant {} 366 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
309impl EnumVariant { 367 support::token(&self.syntax, T![lifetime])
310 pub fn field_def_list(&self) -> Option<FieldDefList> { support::child(&self.syntax) } 368 }
311 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 369 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
312 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 370 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
371 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
372 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
313} 373}
314/// Trait definition. 374#[derive(Debug, Clone, PartialEq, Eq, Hash)]
315/// Includes all of its attributes and doc comments. 375pub struct Param {
316///
317/// ```
318/// ❰
319/// /// Docs
320/// #[attr]
321/// pub unsafe trait Foo<T>: Debug where T: Debug {
322/// // ...
323/// }
324/// ❱
325/// ```
326///
327/// [Reference](https://doc.rust-lang.org/reference/items/traits.html)
328#[derive(Debug, Clone, PartialEq, Eq, Hash)]
329pub struct TraitDef {
330 pub(crate) syntax: SyntaxNode, 376 pub(crate) syntax: SyntaxNode,
331} 377}
332impl ast::VisibilityOwner for TraitDef {} 378impl ast::AttrsOwner for Param {}
333impl ast::NameOwner for TraitDef {} 379impl Param {
334impl ast::AttrsOwner for TraitDef {} 380 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
335impl ast::DocCommentsOwner for TraitDef {} 381 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
336impl ast::TypeParamsOwner for TraitDef {} 382 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
337impl ast::TypeBoundsOwner for TraitDef {} 383 pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
338impl TraitDef {
339 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
340 pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
341 pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
342 pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
343} 384}
344/// Module definition either with body or not.
345/// Includes all of its inner and outer attributes, module items, doc comments.
346///
347/// ```
348/// ❰
349/// /// Docs
350/// #[attr]
351/// pub mod foo;
352/// ❱
353///
354/// ❰
355/// /// Docs
356/// #[attr]
357/// pub mod bar {
358/// //! Inner docs
359/// #![inner_attr]
360/// }
361/// ❱
362/// ```
363///
364/// [Reference](https://doc.rust-lang.org/reference/items/modules.html)
365#[derive(Debug, Clone, PartialEq, Eq, Hash)] 385#[derive(Debug, Clone, PartialEq, Eq, Hash)]
366pub struct Module { 386pub struct TypeBoundList {
367 pub(crate) syntax: SyntaxNode, 387 pub(crate) syntax: SyntaxNode,
368} 388}
369impl ast::VisibilityOwner for Module {} 389impl TypeBoundList {
370impl ast::NameOwner for Module {} 390 pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) }
371impl ast::AttrsOwner for Module {}
372impl ast::DocCommentsOwner for Module {}
373impl Module {
374 pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) }
375 pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) }
376 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
377} 391}
378/// Item defintion list.
379/// This is used for both top-level items and impl block items.
380///
381/// ```
382/// ❰
383/// fn foo {}
384/// struct Bar;
385/// enum Baz;
386/// trait Bruh;
387/// const BRUUH: u32 = 42;
388/// ❱
389///
390/// impl Foo
391/// ❰
392/// {
393/// fn bar() {}
394/// const BAZ: u32 = 42;
395/// }
396/// ❱
397/// ```
398///
399/// [Reference](https://doc.rust-lang.org/reference/items.html)
400#[derive(Debug, Clone, PartialEq, Eq, Hash)] 392#[derive(Debug, Clone, PartialEq, Eq, Hash)]
401pub struct ItemList { 393pub struct RecordFieldList {
402 pub(crate) syntax: SyntaxNode, 394 pub(crate) syntax: SyntaxNode,
403} 395}
404impl ast::ModuleItemOwner for ItemList {} 396impl RecordFieldList {
405impl ItemList {
406 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 397 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
407 pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) } 398 pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) }
408 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 399 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
409} 400}
410/// Constant variable definition. 401#[derive(Debug, Clone, PartialEq, Eq, Hash)]
411/// Includes all of its attributes and doc comments. 402pub struct TupleFieldList {
412///
413/// ```
414/// ❰
415/// /// Docs
416/// #[attr]
417/// pub const FOO: u32 = 42;
418/// ❱
419/// ```
420///
421/// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html)
422#[derive(Debug, Clone, PartialEq, Eq, Hash)]
423pub struct ConstDef {
424 pub(crate) syntax: SyntaxNode, 403 pub(crate) syntax: SyntaxNode,
425} 404}
426impl ast::VisibilityOwner for ConstDef {} 405impl TupleFieldList {
427impl ast::NameOwner for ConstDef {} 406 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
428impl ast::TypeParamsOwner for ConstDef {} 407 pub fn fields(&self) -> AstChildren<TupleField> { support::children(&self.syntax) }
429impl ast::AttrsOwner for ConstDef {} 408 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
430impl ast::DocCommentsOwner for ConstDef {} 409}
431impl ast::TypeAscriptionOwner for ConstDef {} 410#[derive(Debug, Clone, PartialEq, Eq, Hash)]
432impl ConstDef { 411pub struct RecordField {
433 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } 412 pub(crate) syntax: SyntaxNode,
434 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 413}
435 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 414impl ast::AttrsOwner for RecordField {}
436 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } 415impl ast::NameOwner for RecordField {}
437 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 416impl ast::VisibilityOwner for RecordField {}
417impl RecordField {
418 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
419 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
438} 420}
439/// Static variable definition. 421#[derive(Debug, Clone, PartialEq, Eq, Hash)]
440/// Includes all of its attributes and doc comments. 422pub struct TupleField {
441///
442/// ```
443/// ❰
444/// /// Docs
445/// #[attr]
446/// pub static mut FOO: u32 = 42;
447/// ❱
448/// ```
449///
450/// [Reference](https://doc.rust-lang.org/reference/items/static-items.html)
451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452pub struct StaticDef {
453 pub(crate) syntax: SyntaxNode, 423 pub(crate) syntax: SyntaxNode,
454} 424}
455impl ast::VisibilityOwner for StaticDef {} 425impl ast::AttrsOwner for TupleField {}
456impl ast::NameOwner for StaticDef {} 426impl ast::VisibilityOwner for TupleField {}
457impl ast::TypeParamsOwner for StaticDef {} 427impl TupleField {
458impl ast::AttrsOwner for StaticDef {} 428 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
459impl ast::DocCommentsOwner for StaticDef {} 429}
460impl ast::TypeAscriptionOwner for StaticDef {} 430#[derive(Debug, Clone, PartialEq, Eq, Hash)]
461impl StaticDef { 431pub struct VariantList {
462 pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) } 432 pub(crate) syntax: SyntaxNode,
463 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } 433}
434impl VariantList {
435 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
436 pub fn variants(&self) -> AstChildren<Variant> { support::children(&self.syntax) }
437 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
438}
439#[derive(Debug, Clone, PartialEq, Eq, Hash)]
440pub struct Variant {
441 pub(crate) syntax: SyntaxNode,
442}
443impl ast::AttrsOwner for Variant {}
444impl ast::NameOwner for Variant {}
445impl ast::VisibilityOwner for Variant {}
446impl Variant {
447 pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
464 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 448 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
465 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } 449 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
466 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
467} 450}
468/// Type alias definition. 451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
469/// Includes associated type clauses with type bounds. 452pub struct AssocItemList {
470///
471/// ```
472/// ❰
473/// /// Docs
474/// #[attr]
475/// pub type Foo<T> where T: Debug = T;
476/// ❱
477///
478/// trait Bar {
479/// ❰ type Baz: Debug; ❱
480/// ❰ type Bruh = String; ❱
481/// ❰ type Bruuh: Debug = u32; ❱
482/// }
483/// ```
484///
485/// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html)
486#[derive(Debug, Clone, PartialEq, Eq, Hash)]
487pub struct TypeAliasDef {
488 pub(crate) syntax: SyntaxNode, 453 pub(crate) syntax: SyntaxNode,
489} 454}
490impl ast::VisibilityOwner for TypeAliasDef {} 455impl ast::AttrsOwner for AssocItemList {}
491impl ast::NameOwner for TypeAliasDef {} 456impl AssocItemList {
492impl ast::TypeParamsOwner for TypeAliasDef {} 457 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
493impl ast::AttrsOwner for TypeAliasDef {} 458 pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) }
494impl ast::DocCommentsOwner for TypeAliasDef {} 459 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
495impl ast::TypeBoundsOwner for TypeAliasDef {} 460}
496impl TypeAliasDef { 461#[derive(Debug, Clone, PartialEq, Eq, Hash)]
497 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } 462pub struct ExternItemList {
498 pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) } 463 pub(crate) syntax: SyntaxNode,
464}
465impl ast::AttrsOwner for ExternItemList {}
466impl ExternItemList {
467 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
468 pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
469 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
470}
471#[derive(Debug, Clone, PartialEq, Eq, Hash)]
472pub struct LifetimeParam {
473 pub(crate) syntax: SyntaxNode,
474}
475impl ast::AttrsOwner for LifetimeParam {}
476impl LifetimeParam {
477 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
478 support::token(&self.syntax, T![lifetime])
479 }
480}
481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
482pub struct TypeParam {
483 pub(crate) syntax: SyntaxNode,
484}
485impl ast::AttrsOwner for TypeParam {}
486impl ast::NameOwner for TypeParam {}
487impl ast::TypeBoundsOwner for TypeParam {}
488impl TypeParam {
499 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 489 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
500 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 490 pub fn default_type(&self) -> Option<TypeRef> { support::child(&self.syntax) }
501 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
502} 491}
503/// Inherent and trait impl definition. 492#[derive(Debug, Clone, PartialEq, Eq, Hash)]
504/// Includes all of its inner and outer attributes. 493pub struct ConstParam {
505///
506/// ```
507/// ❰
508/// #[attr]
509/// unsafe impl<T> const !Foo for Bar where T: Debug {
510/// #![inner_attr]
511/// // ...
512/// }
513/// ❱
514/// ```
515///
516/// [Reference](https://doc.rust-lang.org/reference/items/implementations.html)
517#[derive(Debug, Clone, PartialEq, Eq, Hash)]
518pub struct ImplDef {
519 pub(crate) syntax: SyntaxNode, 494 pub(crate) syntax: SyntaxNode,
520} 495}
521impl ast::TypeParamsOwner for ImplDef {} 496impl ast::AttrsOwner for ConstParam {}
522impl ast::AttrsOwner for ImplDef {} 497impl ast::NameOwner for ConstParam {}
523impl ast::DocCommentsOwner for ImplDef {} 498impl ConstParam {
524impl ImplDef {
525 pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) }
526 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 499 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
527 pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } 500 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
528 pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) } 501 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
529 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } 502 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
530 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } 503 pub fn default_val(&self) -> Option<Expr> { support::child(&self.syntax) }
531 pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) } 504}
505#[derive(Debug, Clone, PartialEq, Eq, Hash)]
506pub struct Literal {
507 pub(crate) syntax: SyntaxNode,
508}
509impl Literal {}
510#[derive(Debug, Clone, PartialEq, Eq, Hash)]
511pub struct TokenTree {
512 pub(crate) syntax: SyntaxNode,
513}
514impl TokenTree {
515 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
516 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
517 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
518 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
519 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
520 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
532} 521}
533/// Parenthesized type reference.
534/// Note: parens are only used for grouping, this is not a tuple type.
535///
536/// ```
537/// // This is effectively just `u32`.
538/// // Single-item tuple must be defined with a trailing comma: `(u32,)`
539/// type Foo = ❰ (u32) ❱;
540///
541/// let bar: &'static ❰ (dyn Debug) ❱ = "bruh";
542/// ```
543#[derive(Debug, Clone, PartialEq, Eq, Hash)] 522#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544pub struct ParenType { 523pub struct ParenType {
545 pub(crate) syntax: SyntaxNode, 524 pub(crate) syntax: SyntaxNode,
546} 525}
547impl ParenType { 526impl ParenType {
548 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } 527 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
549 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 528 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
550 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 529 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
551} 530}
552/// Unnamed tuple type.
553///
554/// ```
555/// let foo: ❰ (u32, bool) ❱ = (42, true);
556/// ```
557///
558/// [Reference](https://doc.rust-lang.org/reference/types/tuple.html)
559#[derive(Debug, Clone, PartialEq, Eq, Hash)] 531#[derive(Debug, Clone, PartialEq, Eq, Hash)]
560pub struct TupleType { 532pub struct TupleType {
561 pub(crate) syntax: SyntaxNode, 533 pub(crate) syntax: SyntaxNode,
@@ -565,17 +537,6 @@ impl TupleType {
565 pub fn fields(&self) -> AstChildren<TypeRef> { support::children(&self.syntax) } 537 pub fn fields(&self) -> AstChildren<TypeRef> { support::children(&self.syntax) }
566 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 538 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
567} 539}
568/// The never type (i.e. the exclamation point).
569///
570/// ```
571/// type T = ❰ ! ❱;
572///
573/// fn no_return() -> ❰ ! ❱ {
574/// loop {}
575/// }
576/// ```
577///
578/// [Reference](https://doc.rust-lang.org/reference/types/never.html)
579#[derive(Debug, Clone, PartialEq, Eq, Hash)] 540#[derive(Debug, Clone, PartialEq, Eq, Hash)]
580pub struct NeverType { 541pub struct NeverType {
581 pub(crate) syntax: SyntaxNode, 542 pub(crate) syntax: SyntaxNode,
@@ -583,17 +544,6 @@ pub struct NeverType {
583impl NeverType { 544impl NeverType {
584 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } 545 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
585} 546}
586/// Path to a type.
587/// Includes single identifier type names and elaborate paths with
588/// generic parameters.
589///
590/// ```
591/// type Foo = ❰ String ❱;
592/// type Bar = ❰ std::vec::Vec<T> ❱;
593/// type Baz = ❰ ::bruh::<Bruuh as Iterator>::Item ❱;
594/// ```
595///
596/// [Reference](https://doc.rust-lang.org/reference/paths.html)
597#[derive(Debug, Clone, PartialEq, Eq, Hash)] 547#[derive(Debug, Clone, PartialEq, Eq, Hash)]
598pub struct PathType { 548pub struct PathType {
599 pub(crate) syntax: SyntaxNode, 549 pub(crate) syntax: SyntaxNode,
@@ -601,14 +551,6 @@ pub struct PathType {
601impl PathType { 551impl PathType {
602 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } 552 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
603} 553}
604/// Raw pointer type.
605///
606/// ```
607/// type Foo = ❰ *const u32 ❱;
608/// type Bar = ❰ *mut u32 ❱;
609/// ```
610///
611/// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut)
612#[derive(Debug, Clone, PartialEq, Eq, Hash)] 554#[derive(Debug, Clone, PartialEq, Eq, Hash)]
613pub struct PointerType { 555pub struct PointerType {
614 pub(crate) syntax: SyntaxNode, 556 pub(crate) syntax: SyntaxNode,
@@ -617,49 +559,28 @@ impl PointerType {
617 pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) } 559 pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
618 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 560 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
619 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } 561 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
620 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 562 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
621} 563}
622/// Array type.
623///
624/// ```
625/// type Foo = ❰ [u32; 24 - 3] ❱;
626/// ```
627///
628/// [Reference](https://doc.rust-lang.org/reference/types/array.html)
629#[derive(Debug, Clone, PartialEq, Eq, Hash)] 564#[derive(Debug, Clone, PartialEq, Eq, Hash)]
630pub struct ArrayType { 565pub struct ArrayType {
631 pub(crate) syntax: SyntaxNode, 566 pub(crate) syntax: SyntaxNode,
632} 567}
633impl ArrayType { 568impl ArrayType {
634 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } 569 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
635 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 570 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
636 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 571 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
637 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 572 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
638 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 573 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
639} 574}
640/// Slice type.
641///
642/// ```
643/// type Foo = ❰ [u8] ❱;
644/// ```
645///
646/// [Reference](https://doc.rust-lang.org/reference/types/slice.html)
647#[derive(Debug, Clone, PartialEq, Eq, Hash)] 575#[derive(Debug, Clone, PartialEq, Eq, Hash)]
648pub struct SliceType { 576pub struct SliceType {
649 pub(crate) syntax: SyntaxNode, 577 pub(crate) syntax: SyntaxNode,
650} 578}
651impl SliceType { 579impl SliceType {
652 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } 580 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
653 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 581 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
654 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 582 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
655} 583}
656/// Reference type.
657///
658/// ```
659/// type Foo = ❰ &'static str ❱;
660/// ```
661///
662/// [Reference](https://doc.rust-lang.org/reference/types/pointer.html)
663#[derive(Debug, Clone, PartialEq, Eq, Hash)] 584#[derive(Debug, Clone, PartialEq, Eq, Hash)]
664pub struct ReferenceType { 585pub struct ReferenceType {
665 pub(crate) syntax: SyntaxNode, 586 pub(crate) syntax: SyntaxNode,
@@ -670,15 +591,8 @@ impl ReferenceType {
670 support::token(&self.syntax, T![lifetime]) 591 support::token(&self.syntax, T![lifetime])
671 } 592 }
672 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } 593 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
673 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 594 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
674} 595}
675/// Placeholder type (i.e. the underscore).
676///
677/// ```
678/// let foo: ❰ _ ❱ = 42_u32;
679/// ```
680///
681/// [Reference](https://doc.rust-lang.org/reference/types/inferred.html)
682#[derive(Debug, Clone, PartialEq, Eq, Hash)] 596#[derive(Debug, Clone, PartialEq, Eq, Hash)]
683pub struct PlaceholderType { 597pub struct PlaceholderType {
684 pub(crate) syntax: SyntaxNode, 598 pub(crate) syntax: SyntaxNode,
@@ -686,15 +600,6 @@ pub struct PlaceholderType {
686impl PlaceholderType { 600impl PlaceholderType {
687 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } 601 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
688} 602}
689/// Function pointer type (not to be confused with `Fn*` family of traits).
690///
691/// ```
692/// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱;
693///
694/// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱;
695/// ```
696///
697/// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html)
698#[derive(Debug, Clone, PartialEq, Eq, Hash)] 603#[derive(Debug, Clone, PartialEq, Eq, Hash)]
699pub struct FnPointerType { 604pub struct FnPointerType {
700 pub(crate) syntax: SyntaxNode, 605 pub(crate) syntax: SyntaxNode,
@@ -706,59 +611,31 @@ impl FnPointerType {
706 pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } 611 pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
707 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } 612 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
708} 613}
709/// Higher order type.
710///
711/// ```
712/// type Foo = ❰ for<'a> fn(&'a str) ❱;
713/// ```
714///
715/// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html)
716#[derive(Debug, Clone, PartialEq, Eq, Hash)] 614#[derive(Debug, Clone, PartialEq, Eq, Hash)]
717pub struct ForType { 615pub struct ForType {
718 pub(crate) syntax: SyntaxNode, 616 pub(crate) syntax: SyntaxNode,
719} 617}
720impl ForType { 618impl ForType {
721 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } 619 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
722 pub fn type_param_list(&self) -> Option<TypeParamList> { support::child(&self.syntax) } 620 pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
723 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 621 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
724} 622}
725/// Opaque `impl Trait` type.
726///
727/// ```
728/// fn foo(bar: ❰ impl Debug + Eq ❱) {}
729/// ```
730///
731/// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html)
732#[derive(Debug, Clone, PartialEq, Eq, Hash)] 623#[derive(Debug, Clone, PartialEq, Eq, Hash)]
733pub struct ImplTraitType { 624pub struct ImplTraitType {
734 pub(crate) syntax: SyntaxNode, 625 pub(crate) syntax: SyntaxNode,
735} 626}
736impl ast::TypeBoundsOwner for ImplTraitType {}
737impl ImplTraitType { 627impl ImplTraitType {
738 pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) } 628 pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) }
629 pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
739} 630}
740/// Trait object type.
741///
742/// ```
743/// type Foo = ❰ dyn Debug ❱;
744/// ```
745///
746/// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html)
747#[derive(Debug, Clone, PartialEq, Eq, Hash)] 631#[derive(Debug, Clone, PartialEq, Eq, Hash)]
748pub struct DynTraitType { 632pub struct DynTraitType {
749 pub(crate) syntax: SyntaxNode, 633 pub(crate) syntax: SyntaxNode,
750} 634}
751impl ast::TypeBoundsOwner for DynTraitType {}
752impl DynTraitType { 635impl DynTraitType {
753 pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) } 636 pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) }
637 pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) }
754} 638}
755/// Tuple literal.
756///
757/// ```
758/// ❰ (42, true) ❱;
759/// ```
760///
761/// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html)
762#[derive(Debug, Clone, PartialEq, Eq, Hash)] 639#[derive(Debug, Clone, PartialEq, Eq, Hash)]
763pub struct TupleExpr { 640pub struct TupleExpr {
764 pub(crate) syntax: SyntaxNode, 641 pub(crate) syntax: SyntaxNode,
@@ -769,15 +646,6 @@ impl TupleExpr {
769 pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) } 646 pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
770 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 647 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
771} 648}
772/// Array literal.
773///
774/// ```
775/// ❰ [#![inner_attr] true, false, true] ❱;
776///
777/// ❰ ["baz"; 24] ❱;
778/// ```
779///
780/// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
781#[derive(Debug, Clone, PartialEq, Eq, Hash)] 649#[derive(Debug, Clone, PartialEq, Eq, Hash)]
782pub struct ArrayExpr { 650pub struct ArrayExpr {
783 pub(crate) syntax: SyntaxNode, 651 pub(crate) syntax: SyntaxNode,
@@ -786,17 +654,10 @@ impl ast::AttrsOwner for ArrayExpr {}
786impl ArrayExpr { 654impl ArrayExpr {
787 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } 655 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
788 pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) } 656 pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
657 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
789 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 658 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
790 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 659 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
791} 660}
792/// Parenthesized expression.
793/// Note: parens are only used for grouping, this is not a tuple literal.
794///
795/// ```
796/// ❰ (#![inner_attr] 2 + 2) ❱ * 2;
797/// ```
798///
799/// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html)
800#[derive(Debug, Clone, PartialEq, Eq, Hash)] 661#[derive(Debug, Clone, PartialEq, Eq, Hash)]
801pub struct ParenExpr { 662pub struct ParenExpr {
802 pub(crate) syntax: SyntaxNode, 663 pub(crate) syntax: SyntaxNode,
@@ -807,19 +668,6 @@ impl ParenExpr {
807 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 668 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
808 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 669 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
809} 670}
810/// Path to a symbol in expression context.
811/// Includes single identifier variable names and elaborate paths with
812/// generic parameters.
813///
814/// ```
815/// ❰ Some::<i32> ❱;
816/// ❰ foo ❱ + 42;
817/// ❰ Vec::<i32>::push ❱;
818/// ❰ <[i32]>::reverse ❱;
819/// ❰ <String as std::borrow::Borrow<str>>::borrow ❱;
820/// ```
821///
822/// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html)
823#[derive(Debug, Clone, PartialEq, Eq, Hash)] 671#[derive(Debug, Clone, PartialEq, Eq, Hash)]
824pub struct PathExpr { 672pub struct PathExpr {
825 pub(crate) syntax: SyntaxNode, 673 pub(crate) syntax: SyntaxNode,
@@ -827,17 +675,6 @@ pub struct PathExpr {
827impl PathExpr { 675impl PathExpr {
828 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } 676 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
829} 677}
830/// Anonymous callable object literal a.k.a. closure, lambda or functor.
831///
832/// ```
833/// ❰ || 42 ❱;
834/// ❰ |a: u32| val + 1 ❱;
835/// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱;
836/// ❰ move || baz ❱;
837/// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱
838/// ```
839///
840/// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html)
841#[derive(Debug, Clone, PartialEq, Eq, Hash)] 678#[derive(Debug, Clone, PartialEq, Eq, Hash)]
842pub struct LambdaExpr { 679pub struct LambdaExpr {
843 pub(crate) syntax: SyntaxNode, 680 pub(crate) syntax: SyntaxNode,
@@ -851,25 +688,6 @@ impl LambdaExpr {
851 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } 688 pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
852 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } 689 pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
853} 690}
854/// If expression. Includes both regular `if` and `if let` forms.
855/// Beware that `else if` is a special case syntax sugar, because in general
856/// there has to be block expression after `else`.
857///
858/// ```
859/// ❰ if bool_cond { 42 } ❱
860/// ❰ if bool_cond { 42 } else { 24 } ❱
861/// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱
862///
863/// ❰
864/// if let Pattern(foo) = bar {
865/// foo
866/// } else {
867/// panic!();
868/// }
869/// ❱
870/// ```
871///
872/// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
873#[derive(Debug, Clone, PartialEq, Eq, Hash)] 691#[derive(Debug, Clone, PartialEq, Eq, Hash)]
874pub struct IfExpr { 692pub struct IfExpr {
875 pub(crate) syntax: SyntaxNode, 693 pub(crate) syntax: SyntaxNode,
@@ -879,40 +697,16 @@ impl IfExpr {
879 pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) } 697 pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
880 pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) } 698 pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
881} 699}
882/// Unconditional loop expression.
883///
884/// ```
885/// ❰
886/// loop {
887/// // yeah, it's that simple...
888/// }
889/// ❱
890/// ```
891///
892/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html)
893#[derive(Debug, Clone, PartialEq, Eq, Hash)] 700#[derive(Debug, Clone, PartialEq, Eq, Hash)]
894pub struct LoopExpr { 701pub struct Condition {
895 pub(crate) syntax: SyntaxNode, 702 pub(crate) syntax: SyntaxNode,
896} 703}
897impl ast::AttrsOwner for LoopExpr {} 704impl Condition {
898impl ast::LoopBodyOwner for LoopExpr {} 705 pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
899impl LoopExpr { 706 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
900 pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) } 707 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
708 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
901} 709}
902/// Block expression with an optional prefix (label, try ketword,
903/// unsafe keyword, async keyword...).
904///
905/// ```
906/// ❰
907/// 'label: try {
908/// None?
909/// }
910/// ❱
911/// ```
912///
913/// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html)
914/// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks)
915/// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks)
916#[derive(Debug, Clone, PartialEq, Eq, Hash)] 710#[derive(Debug, Clone, PartialEq, Eq, Hash)]
917pub struct EffectExpr { 711pub struct EffectExpr {
918 pub(crate) syntax: SyntaxNode, 712 pub(crate) syntax: SyntaxNode,
@@ -925,19 +719,24 @@ impl EffectExpr {
925 pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } 719 pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
926 pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } 720 pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
927} 721}
928/// For loop expression. 722#[derive(Debug, Clone, PartialEq, Eq, Hash)]
929/// Note: record struct literals are not valid as iterable expression 723pub struct Label {
930/// due to ambiguity. 724 pub(crate) syntax: SyntaxNode,
931/// 725}
932/// ``` 726impl Label {
933/// ❰ 727 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
934/// for i in (0..4) { 728 support::token(&self.syntax, T![lifetime])
935/// dbg!(i); 729 }
936/// } 730}
937/// ❱ 731#[derive(Debug, Clone, PartialEq, Eq, Hash)]
938/// ``` 732pub struct LoopExpr {
939/// 733 pub(crate) syntax: SyntaxNode,
940/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops) 734}
735impl ast::AttrsOwner for LoopExpr {}
736impl ast::LoopBodyOwner for LoopExpr {}
737impl LoopExpr {
738 pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
739}
941#[derive(Debug, Clone, PartialEq, Eq, Hash)] 740#[derive(Debug, Clone, PartialEq, Eq, Hash)]
942pub struct ForExpr { 741pub struct ForExpr {
943 pub(crate) syntax: SyntaxNode, 742 pub(crate) syntax: SyntaxNode,
@@ -950,22 +749,6 @@ impl ForExpr {
950 pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) } 749 pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
951 pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) } 750 pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
952} 751}
953/// While loop expression. Includes both regular `while` and `while let` forms.
954///
955/// ```
956/// ❰
957/// while bool_cond {
958/// 42;
959/// }
960/// ❱
961/// ❰
962/// while let Pattern(foo) = bar {
963/// bar += 1;
964/// }
965/// ❱
966/// ```
967///
968/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
969#[derive(Debug, Clone, PartialEq, Eq, Hash)] 752#[derive(Debug, Clone, PartialEq, Eq, Hash)]
970pub struct WhileExpr { 753pub struct WhileExpr {
971 pub(crate) syntax: SyntaxNode, 754 pub(crate) syntax: SyntaxNode,
@@ -976,22 +759,6 @@ impl WhileExpr {
976 pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) } 759 pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
977 pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) } 760 pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
978} 761}
979/// Continue expression.
980///
981/// ```
982/// while bool_cond {
983/// ❰ continue ❱;
984/// }
985///
986/// 'outer: loop {
987/// loop {
988/// ❰ continue 'outer ❱;
989/// }
990/// }
991///
992/// ```
993///
994/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)
995#[derive(Debug, Clone, PartialEq, Eq, Hash)] 762#[derive(Debug, Clone, PartialEq, Eq, Hash)]
996pub struct ContinueExpr { 763pub struct ContinueExpr {
997 pub(crate) syntax: SyntaxNode, 764 pub(crate) syntax: SyntaxNode,
@@ -1005,25 +772,6 @@ impl ContinueExpr {
1005 support::token(&self.syntax, T![lifetime]) 772 support::token(&self.syntax, T![lifetime])
1006 } 773 }
1007} 774}
1008/// Break expression.
1009///
1010/// ```
1011/// while bool_cond {
1012/// ❰ break ❱;
1013/// }
1014/// 'outer: loop {
1015/// for foo in bar {
1016/// ❰ break 'outer ❱;
1017/// }
1018/// }
1019/// 'outer: loop {
1020/// loop {
1021/// ❰ break 'outer 42 ❱;
1022/// }
1023/// }
1024/// ```
1025///
1026/// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions)
1027#[derive(Debug, Clone, PartialEq, Eq, Hash)] 775#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1028pub struct BreakExpr { 776pub struct BreakExpr {
1029 pub(crate) syntax: SyntaxNode, 777 pub(crate) syntax: SyntaxNode,
@@ -1036,104 +784,33 @@ impl BreakExpr {
1036 } 784 }
1037 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 785 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1038} 786}
1039/// Label.
1040///
1041/// ```
1042/// ❰ 'outer: ❱ loop {}
1043///
1044/// let foo = ❰ 'bar: ❱ loop {}
1045///
1046/// ❰ 'baz: ❱ {
1047/// break 'baz;
1048/// }
1049/// ```
1050///
1051/// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels)
1052/// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1053#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1054pub struct Label {
1055 pub(crate) syntax: SyntaxNode,
1056}
1057impl Label {
1058 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
1059 support::token(&self.syntax, T![lifetime])
1060 }
1061}
1062/// Block expression. Includes unsafe blocks and block labels.
1063///
1064/// ```
1065/// let foo = ❰
1066/// {
1067/// #![inner_attr]
1068/// ❰ { } ❱
1069///
1070/// ❰ 'label: { break 'label } ❱
1071/// }
1072/// ❱;
1073/// ```
1074///
1075/// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html)
1076/// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1077#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1078pub struct BlockExpr {
1079 pub(crate) syntax: SyntaxNode,
1080}
1081impl ast::AttrsOwner for BlockExpr {}
1082impl ast::ModuleItemOwner for BlockExpr {}
1083impl BlockExpr {
1084 pub fn label(&self) -> Option<Label> { support::child(&self.syntax) }
1085 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
1086 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
1087 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1088 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
1089}
1090/// Return expression.
1091///
1092/// ```
1093/// || ❰ return 42 ❱;
1094///
1095/// fn bar() {
1096/// ❰ return ❱;
1097/// }
1098/// ```
1099///
1100/// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html)
1101#[derive(Debug, Clone, PartialEq, Eq, Hash)] 787#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1102pub struct ReturnExpr { 788pub struct ReturnExpr {
1103 pub(crate) syntax: SyntaxNode, 789 pub(crate) syntax: SyntaxNode,
1104} 790}
1105impl ast::AttrsOwner for ReturnExpr {} 791impl ast::AttrsOwner for ReturnExpr {}
1106impl ReturnExpr { 792impl ReturnExpr {
793 pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) }
1107 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 794 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1108} 795}
1109/// Call expression (not to be confused with method call expression, it is
1110/// a separate ast node).
1111///
1112/// ```
1113/// ❰ foo() ❱;
1114/// ❰ &str::len("bar") ❱;
1115/// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱;
1116/// ```
1117///
1118/// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
1119#[derive(Debug, Clone, PartialEq, Eq, Hash)] 796#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1120pub struct CallExpr { 797pub struct CallExpr {
1121 pub(crate) syntax: SyntaxNode, 798 pub(crate) syntax: SyntaxNode,
1122} 799}
800impl ast::AttrsOwner for CallExpr {}
1123impl ast::ArgListOwner for CallExpr {} 801impl ast::ArgListOwner for CallExpr {}
1124impl CallExpr { 802impl CallExpr {
1125 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 803 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1126} 804}
1127/// Method call expression. 805#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1128/// 806pub struct ArgList {
1129/// ``` 807 pub(crate) syntax: SyntaxNode,
1130/// ❰ receiver_expr.method() ❱; 808}
1131/// ❰ receiver_expr.method::<T>(42, true) ❱; 809impl ArgList {
1132/// 810 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
1133/// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱; 811 pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
1134/// ``` 812 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
1135/// 813}
1136/// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html)
1137#[derive(Debug, Clone, PartialEq, Eq, Hash)] 814#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1138pub struct MethodCallExpr { 815pub struct MethodCallExpr {
1139 pub(crate) syntax: SyntaxNode, 816 pub(crate) syntax: SyntaxNode,
@@ -1146,31 +823,19 @@ impl MethodCallExpr {
1146 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 823 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
1147 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) } 824 pub fn type_arg_list(&self) -> Option<TypeArgList> { support::child(&self.syntax) }
1148} 825}
1149/// Index expression a.k.a. subscript operator call.
1150///
1151/// ```
1152/// ❰ foo[42] ❱;
1153/// ```
1154///
1155/// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
1156#[derive(Debug, Clone, PartialEq, Eq, Hash)] 826#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1157pub struct IndexExpr { 827pub struct TypeArgList {
1158 pub(crate) syntax: SyntaxNode, 828 pub(crate) syntax: SyntaxNode,
1159} 829}
1160impl ast::AttrsOwner for IndexExpr {} 830impl TypeArgList {
1161impl IndexExpr { 831 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
1162 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } 832 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
1163 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 833 pub fn type_args(&self) -> AstChildren<TypeArg> { support::children(&self.syntax) }
834 pub fn lifetime_args(&self) -> AstChildren<LifetimeArg> { support::children(&self.syntax) }
835 pub fn assoc_type_args(&self) -> AstChildren<AssocTypeArg> { support::children(&self.syntax) }
836 pub fn const_args(&self) -> AstChildren<ConstArg> { support::children(&self.syntax) }
837 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
1164} 838}
1165/// Field access expression.
1166///
1167/// ```
1168/// ❰ expr.bar ❱;
1169///
1170/// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱;
1171/// ```
1172///
1173/// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html)
1174#[derive(Debug, Clone, PartialEq, Eq, Hash)] 839#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1175pub struct FieldExpr { 840pub struct FieldExpr {
1176 pub(crate) syntax: SyntaxNode, 841 pub(crate) syntax: SyntaxNode,
@@ -1181,13 +846,15 @@ impl FieldExpr {
1181 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } 846 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
1182 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 847 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
1183} 848}
1184/// Await operator call expression. 849#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1185/// 850pub struct IndexExpr {
1186/// ``` 851 pub(crate) syntax: SyntaxNode,
1187/// ❰ expr.await ❱; 852}
1188/// ``` 853impl ast::AttrsOwner for IndexExpr {}
1189/// 854impl IndexExpr {
1190/// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html) 855 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
856 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
857}
1191#[derive(Debug, Clone, PartialEq, Eq, Hash)] 858#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1192pub struct AwaitExpr { 859pub struct AwaitExpr {
1193 pub(crate) syntax: SyntaxNode, 860 pub(crate) syntax: SyntaxNode,
@@ -1198,13 +865,6 @@ impl AwaitExpr {
1198 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } 865 pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
1199 pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) } 866 pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) }
1200} 867}
1201/// The question mark operator call.
1202///
1203/// ```
1204/// ❰ expr? ❱;
1205/// ```
1206///
1207/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)
1208#[derive(Debug, Clone, PartialEq, Eq, Hash)] 868#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1209pub struct TryExpr { 869pub struct TryExpr {
1210 pub(crate) syntax: SyntaxNode, 870 pub(crate) syntax: SyntaxNode,
@@ -1214,13 +874,6 @@ impl TryExpr {
1214 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 874 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1215 pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) } 875 pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
1216} 876}
1217/// Type cast expression.
1218///
1219/// ```
1220/// ❰ expr as T ❱;
1221/// ```
1222///
1223/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
1224#[derive(Debug, Clone, PartialEq, Eq, Hash)] 877#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1225pub struct CastExpr { 878pub struct CastExpr {
1226 pub(crate) syntax: SyntaxNode, 879 pub(crate) syntax: SyntaxNode,
@@ -1229,18 +882,8 @@ impl ast::AttrsOwner for CastExpr {}
1229impl CastExpr { 882impl CastExpr {
1230 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 883 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1231 pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } 884 pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
1232 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 885 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
1233} 886}
1234/// Borrow operator call.
1235///
1236/// ```
1237/// ❰ &foo ❱;
1238/// ❰ &mut bar ❱;
1239/// ❰ &raw const bar ❱;
1240/// ❰ &raw mut bar ❱;
1241/// ```
1242///
1243/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators)
1244#[derive(Debug, Clone, PartialEq, Eq, Hash)] 887#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1245pub struct RefExpr { 888pub struct RefExpr {
1246 pub(crate) syntax: SyntaxNode, 889 pub(crate) syntax: SyntaxNode,
@@ -1253,15 +896,6 @@ impl RefExpr {
1253 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 896 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
1254 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 897 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1255} 898}
1256/// Prefix operator call. This is either `!` or `*` or `-`.
1257///
1258/// ```
1259/// ❰ !foo ❱;
1260/// ❰ *bar ❱;
1261/// ❰ -42 ❱;
1262/// ```
1263///
1264/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html)
1265#[derive(Debug, Clone, PartialEq, Eq, Hash)] 899#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1266pub struct PrefixExpr { 900pub struct PrefixExpr {
1267 pub(crate) syntax: SyntaxNode, 901 pub(crate) syntax: SyntaxNode,
@@ -1270,13 +904,6 @@ impl ast::AttrsOwner for PrefixExpr {}
1270impl PrefixExpr { 904impl PrefixExpr {
1271 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 905 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1272} 906}
1273/// Box operator call.
1274///
1275/// ```
1276/// ❰ box 42 ❱;
1277/// ```
1278///
1279/// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md)
1280#[derive(Debug, Clone, PartialEq, Eq, Hash)] 907#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1281pub struct BoxExpr { 908pub struct BoxExpr {
1282 pub(crate) syntax: SyntaxNode, 909 pub(crate) syntax: SyntaxNode,
@@ -1286,69 +913,18 @@ impl BoxExpr {
1286 pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) } 913 pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
1287 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 914 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1288} 915}
1289/// Range operator call.
1290///
1291/// ```
1292/// ❰ 0..42 ❱;
1293/// ❰ ..42 ❱;
1294/// ❰ 0.. ❱;
1295/// ❰ .. ❱;
1296/// ❰ 0..=42 ❱;
1297/// ❰ ..=42 ❱;
1298/// ```
1299///
1300/// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html)
1301#[derive(Debug, Clone, PartialEq, Eq, Hash)] 916#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1302pub struct RangeExpr { 917pub struct RangeExpr {
1303 pub(crate) syntax: SyntaxNode, 918 pub(crate) syntax: SyntaxNode,
1304} 919}
1305impl ast::AttrsOwner for RangeExpr {} 920impl ast::AttrsOwner for RangeExpr {}
1306impl RangeExpr {} 921impl RangeExpr {}
1307/// Binary operator call.
1308/// Includes all arithmetic, logic, bitwise and assignment operators.
1309///
1310/// ```
1311/// ❰ 2 + ❰ 2 * 2 ❱ ❱;
1312/// ❰ ❰ true && false ❱ || true ❱;
1313/// ```
1314///
1315/// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators)
1316#[derive(Debug, Clone, PartialEq, Eq, Hash)] 922#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1317pub struct BinExpr { 923pub struct BinExpr {
1318 pub(crate) syntax: SyntaxNode, 924 pub(crate) syntax: SyntaxNode,
1319} 925}
1320impl ast::AttrsOwner for BinExpr {} 926impl ast::AttrsOwner for BinExpr {}
1321impl BinExpr {} 927impl BinExpr {}
1322/// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal.
1323///
1324/// ```
1325/// ❰ "str" ❱;
1326/// ❰ br##"raw byte str"## ❱;
1327/// ❰ 'c' ❱;
1328/// ❰ b'c' ❱;
1329/// ❰ 42 ❱;
1330/// ❰ 1e9 ❱;
1331/// ❰ true ❱;
1332/// ```
1333///
1334/// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html)
1335#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1336pub struct Literal {
1337 pub(crate) syntax: SyntaxNode,
1338}
1339impl Literal {}
1340/// Match expression.
1341///
1342/// ```
1343/// ❰
1344/// match expr {
1345/// Pat1 => {}
1346/// Pat2(_) => 42,
1347/// }
1348/// ❱
1349/// ```
1350///
1351/// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1352#[derive(Debug, Clone, PartialEq, Eq, Hash)] 928#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1353pub struct MatchExpr { 929pub struct MatchExpr {
1354 pub(crate) syntax: SyntaxNode, 930 pub(crate) syntax: SyntaxNode,
@@ -1359,40 +935,15 @@ impl MatchExpr {
1359 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 935 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1360 pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) } 936 pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) }
1361} 937}
1362/// Match arm list part of match expression. Includes its inner attributes.
1363///
1364/// ```
1365/// match expr
1366/// ❰
1367/// {
1368/// #![inner_attr]
1369/// Pat1 => {}
1370/// Pat2(_) => 42,
1371/// }
1372/// ❱
1373/// ```
1374///
1375/// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1376#[derive(Debug, Clone, PartialEq, Eq, Hash)] 938#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1377pub struct MatchArmList { 939pub struct MatchArmList {
1378 pub(crate) syntax: SyntaxNode, 940 pub(crate) syntax: SyntaxNode,
1379} 941}
1380impl ast::AttrsOwner for MatchArmList {}
1381impl MatchArmList { 942impl MatchArmList {
1382 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 943 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
1383 pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) } 944 pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) }
1384 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 945 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
1385} 946}
1386/// Match arm.
1387/// Note: record struct literals are not valid as target match expression
1388/// due to ambiguity.
1389/// ```
1390/// match expr {
1391/// ❰ #[attr] Pattern(it) if bool_cond => it ❱,
1392/// }
1393/// ```
1394///
1395/// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1396#[derive(Debug, Clone, PartialEq, Eq, Hash)] 947#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1397pub struct MatchArm { 948pub struct MatchArm {
1398 pub(crate) syntax: SyntaxNode, 949 pub(crate) syntax: SyntaxNode,
@@ -1404,15 +955,6 @@ impl MatchArm {
1404 pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) } 955 pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) }
1405 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 956 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1406} 957}
1407/// Match guard.
1408///
1409/// ```
1410/// match expr {
1411/// Pattern(it) ❰ if bool_cond ❱ => it,
1412/// }
1413/// ```
1414///
1415/// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards)
1416#[derive(Debug, Clone, PartialEq, Eq, Hash)] 958#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1417pub struct MatchGuard { 959pub struct MatchGuard {
1418 pub(crate) syntax: SyntaxNode, 960 pub(crate) syntax: SyntaxNode,
@@ -1421,76 +963,37 @@ impl MatchGuard {
1421 pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) } 963 pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
1422 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 964 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1423} 965}
1424/// Record literal expression. The same syntax is used for structs, 966#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1425/// unions and record enum variants. 967pub struct RecordExpr {
1426///
1427/// ```
1428/// ❰
1429/// foo::Bar {
1430/// #![inner_attr]
1431/// baz: 42,
1432/// bruh: true,
1433/// ..spread
1434/// }
1435/// ❱
1436/// ```
1437///
1438/// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1439#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1440pub struct RecordLit {
1441 pub(crate) syntax: SyntaxNode, 968 pub(crate) syntax: SyntaxNode,
1442} 969}
1443impl RecordLit { 970impl RecordExpr {
1444 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } 971 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1445 pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) } 972 pub fn record_expr_field_list(&self) -> Option<RecordExprFieldList> {
973 support::child(&self.syntax)
974 }
1446} 975}
1447/// Record field list including enclosing curly braces.
1448///
1449/// foo::Bar ❰
1450/// {
1451/// baz: 42,
1452/// ..spread
1453/// }
1454/// ❱
1455///
1456/// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1457#[derive(Debug, Clone, PartialEq, Eq, Hash)] 976#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1458pub struct RecordFieldList { 977pub struct RecordExprFieldList {
1459 pub(crate) syntax: SyntaxNode, 978 pub(crate) syntax: SyntaxNode,
1460} 979}
1461impl RecordFieldList { 980impl RecordExprFieldList {
1462 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 981 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
1463 pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) } 982 pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) }
1464 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) } 983 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
1465 pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) } 984 pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) }
1466 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 985 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
1467} 986}
1468/// Record field.
1469///
1470/// ```
1471/// foo::Bar {
1472/// ❰ #[attr] baz: 42 ❱
1473/// }
1474/// ```
1475///
1476/// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1477#[derive(Debug, Clone, PartialEq, Eq, Hash)] 987#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1478pub struct RecordField { 988pub struct RecordExprField {
1479 pub(crate) syntax: SyntaxNode, 989 pub(crate) syntax: SyntaxNode,
1480} 990}
1481impl ast::AttrsOwner for RecordField {} 991impl ast::AttrsOwner for RecordExprField {}
1482impl RecordField { 992impl RecordExprField {
1483 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } 993 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
1484 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } 994 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
1485 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 995 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1486} 996}
1487/// Disjunction of patterns.
1488///
1489/// ```
1490/// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh;
1491/// ```
1492///
1493/// [Reference](https://doc.rust-lang.org/reference/patterns.html)
1494#[derive(Debug, Clone, PartialEq, Eq, Hash)] 997#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1495pub struct OrPat { 998pub struct OrPat {
1496 pub(crate) syntax: SyntaxNode, 999 pub(crate) syntax: SyntaxNode,
@@ -1498,14 +1001,6 @@ pub struct OrPat {
1498impl OrPat { 1001impl OrPat {
1499 pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) } 1002 pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
1500} 1003}
1501/// Parenthesized pattern.
1502/// Note: parens are only used for grouping, this is not a tuple pattern.
1503///
1504/// ```
1505/// if let ❰ &(0..=42) ❱ = foo {}
1506/// ```
1507///
1508/// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns
1509#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1004#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1510pub struct ParenPat { 1005pub struct ParenPat {
1511 pub(crate) syntax: SyntaxNode, 1006 pub(crate) syntax: SyntaxNode,
@@ -1515,16 +1010,6 @@ impl ParenPat {
1515 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1010 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
1516 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 1011 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
1517} 1012}
1518/// Reference pattern.
1519/// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns.
1520///
1521/// ```
1522/// let ❰ &mut foo ❱ = bar;
1523///
1524/// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz;
1525/// ```
1526///
1527/// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns)
1528#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1013#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1529pub struct RefPat { 1014pub struct RefPat {
1530 pub(crate) syntax: SyntaxNode, 1015 pub(crate) syntax: SyntaxNode,
@@ -1534,31 +1019,14 @@ impl RefPat {
1534 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } 1019 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
1535 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1020 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
1536} 1021}
1537/// Box pattern.
1538///
1539/// ```
1540/// let ❰ box foo ❱ = box 42;
1541/// ```
1542///
1543/// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html)
1544#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1022#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1545pub struct BoxPat { 1023pub struct BoxPat {
1546 pub(crate) syntax: SyntaxNode, 1024 pub(crate) syntax: SyntaxNode,
1547} 1025}
1548impl BoxPat { 1026impl BoxPat {
1549 pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) } 1027 pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) }
1550 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1028 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1551} 1029}
1552/// Bind pattern.
1553///
1554/// ```
1555/// match foo {
1556/// Some(❰ ref mut bar ❱) => {}
1557/// ❰ baz @ None ❱ => {}
1558/// }
1559/// ```
1560///
1561/// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns)
1562#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1030#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1563pub struct BindPat { 1031pub struct BindPat {
1564 pub(crate) syntax: SyntaxNode, 1032 pub(crate) syntax: SyntaxNode,
@@ -1571,13 +1039,6 @@ impl BindPat {
1571 pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) } 1039 pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) }
1572 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1040 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
1573} 1041}
1574/// Placeholder pattern a.k.a. the wildcard pattern or the underscore.
1575///
1576/// ```
1577/// let ❰ _ ❱ = foo;
1578/// ```
1579///
1580/// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern)
1581#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1042#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1582pub struct PlaceholderPat { 1043pub struct PlaceholderPat {
1583 pub(crate) syntax: SyntaxNode, 1044 pub(crate) syntax: SyntaxNode,
@@ -1585,16 +1046,6 @@ pub struct PlaceholderPat {
1585impl PlaceholderPat { 1046impl PlaceholderPat {
1586 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } 1047 pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
1587} 1048}
1588/// Rest-of-the record/tuple pattern.
1589/// Note: this is not the unbonded range pattern (even more: it doesn't exist).
1590///
1591/// ```
1592/// let Foo { bar, ❰ .. ❱ } = baz;
1593/// let (❰ .. ❱, bruh) = (42, 24, 42);
1594/// let Bruuh(❰ .. ❱) = bruuuh;
1595/// ```
1596///
1597/// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1598#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1049#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1599pub struct DotDotPat { 1050pub struct DotDotPat {
1600 pub(crate) syntax: SyntaxNode, 1051 pub(crate) syntax: SyntaxNode,
@@ -1602,15 +1053,6 @@ pub struct DotDotPat {
1602impl DotDotPat { 1053impl DotDotPat {
1603 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) } 1054 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
1604} 1055}
1605/// Path pattern.
1606/// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`).
1607///
1608/// ```
1609/// let ❰ foo::bar::Baz ❱ { .. } = bruh;
1610/// if let ❰ CONST ❱ = 42 {}
1611/// ```
1612///
1613/// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns)
1614#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1056#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1615pub struct PathPat { 1057pub struct PathPat {
1616 pub(crate) syntax: SyntaxNode, 1058 pub(crate) syntax: SyntaxNode,
@@ -1618,13 +1060,6 @@ pub struct PathPat {
1618impl PathPat { 1060impl PathPat {
1619 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } 1061 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1620} 1062}
1621/// Slice pattern.
1622///
1623/// ```
1624/// let ❰ [foo, bar, baz] ❱ = [1, 2, 3];
1625/// ```
1626///
1627/// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns)
1628#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1063#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1629pub struct SlicePat { 1064pub struct SlicePat {
1630 pub(crate) syntax: SyntaxNode, 1065 pub(crate) syntax: SyntaxNode,
@@ -1634,33 +1069,14 @@ impl SlicePat {
1634 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) } 1069 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
1635 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 1070 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
1636} 1071}
1637/// Range pattern.
1638///
1639/// ```
1640/// match foo {
1641/// ❰ 0..42 ❱ => {}
1642/// ❰ 0..=42 ❱ => {}
1643/// }
1644/// ```
1645///
1646/// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns)
1647#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1072#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1648pub struct RangePat { 1073pub struct RangePat {
1649 pub(crate) syntax: SyntaxNode, 1074 pub(crate) syntax: SyntaxNode,
1650} 1075}
1651impl RangePat {} 1076impl RangePat {
1652/// Literal pattern. 1077 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
1653/// Includes only bool, number, char, and string literals. 1078 pub fn dotdoteq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..=]) }
1654/// 1079}
1655/// ```
1656/// match foo {
1657/// Number(❰ 42 ❱) => {}
1658/// String(❰ "42" ❱) => {}
1659/// Bool(❰ true ❱) => {}
1660/// }
1661/// ```
1662///
1663/// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns)
1664#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1080#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1665pub struct LiteralPat { 1081pub struct LiteralPat {
1666 pub(crate) syntax: SyntaxNode, 1082 pub(crate) syntax: SyntaxNode,
@@ -1668,13 +1084,6 @@ pub struct LiteralPat {
1668impl LiteralPat { 1084impl LiteralPat {
1669 pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) } 1085 pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
1670} 1086}
1671/// Macro invocation in pattern position.
1672///
1673/// ```
1674/// let ❰ foo!(my custom syntax) ❱ = baz;
1675///
1676/// ```
1677/// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation)
1678#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1087#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1679pub struct MacroPat { 1088pub struct MacroPat {
1680 pub(crate) syntax: SyntaxNode, 1089 pub(crate) syntax: SyntaxNode,
@@ -1682,37 +1091,22 @@ pub struct MacroPat {
1682impl MacroPat { 1091impl MacroPat {
1683 pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) } 1092 pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) }
1684} 1093}
1685/// Record literal pattern.
1686///
1687/// ```
1688/// let ❰ foo::Bar { baz, .. } ❱ = bruh;
1689/// ```
1690///
1691/// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1692#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1094#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1693pub struct RecordPat { 1095pub struct RecordPat {
1694 pub(crate) syntax: SyntaxNode, 1096 pub(crate) syntax: SyntaxNode,
1695} 1097}
1696impl RecordPat { 1098impl RecordPat {
1099 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1697 pub fn record_field_pat_list(&self) -> Option<RecordFieldPatList> { 1100 pub fn record_field_pat_list(&self) -> Option<RecordFieldPatList> {
1698 support::child(&self.syntax) 1101 support::child(&self.syntax)
1699 } 1102 }
1700 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1701} 1103}
1702/// Record literal's field patterns list including enclosing curly braces.
1703///
1704/// ```
1705/// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh;
1706/// ``
1707///
1708/// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1709#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1104#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1710pub struct RecordFieldPatList { 1105pub struct RecordFieldPatList {
1711 pub(crate) syntax: SyntaxNode, 1106 pub(crate) syntax: SyntaxNode,
1712} 1107}
1713impl RecordFieldPatList { 1108impl RecordFieldPatList {
1714 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 1109 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
1715 pub fn pats(&self) -> AstChildren<RecordInnerPat> { support::children(&self.syntax) }
1716 pub fn record_field_pats(&self) -> AstChildren<RecordFieldPat> { 1110 pub fn record_field_pats(&self) -> AstChildren<RecordFieldPat> {
1717 support::children(&self.syntax) 1111 support::children(&self.syntax)
1718 } 1112 }
@@ -1720,15 +1114,6 @@ impl RecordFieldPatList {
1720 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) } 1114 pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
1721 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 1115 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
1722} 1116}
1723/// Record literal's field pattern.
1724/// Note: record literal can also match tuple structs.
1725///
1726/// ```
1727/// let Foo { ❰ bar: _ ❱ } = baz;
1728/// let TupleStruct { ❰ 0: _ ❱ } = bruh;
1729/// ```
1730///
1731/// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1732#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1733pub struct RecordFieldPat { 1118pub struct RecordFieldPat {
1734 pub(crate) syntax: SyntaxNode, 1119 pub(crate) syntax: SyntaxNode,
@@ -1739,13 +1124,6 @@ impl RecordFieldPat {
1739 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } 1124 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
1740 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1125 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
1741} 1126}
1742/// Tuple struct literal pattern.
1743///
1744/// ```
1745/// let ❰ foo::Bar(baz, bruh) ❱ = bruuh;
1746/// ```
1747///
1748/// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns)
1749#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1750pub struct TupleStructPat { 1128pub struct TupleStructPat {
1751 pub(crate) syntax: SyntaxNode, 1129 pub(crate) syntax: SyntaxNode,
@@ -1756,14 +1134,6 @@ impl TupleStructPat {
1756 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) } 1134 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
1757 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 1135 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
1758} 1136}
1759/// Tuple pattern.
1760/// Note: this doesn't include tuple structs (see `TupleStructPat`)
1761///
1762/// ```
1763/// let ❰ (foo, bar, .., baz) ❱ = bruh;
1764/// ```
1765///
1766/// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns)
1767#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1137#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1768pub struct TuplePat { 1138pub struct TuplePat {
1769 pub(crate) syntax: SyntaxNode, 1139 pub(crate) syntax: SyntaxNode,
@@ -1773,234 +1143,28 @@ impl TuplePat {
1773 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) } 1143 pub fn args(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
1774 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } 1144 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
1775} 1145}
1776/// Visibility.
1777///
1778/// ```
1779/// ❰ pub mod ❱ foo;
1780/// ❰ pub(crate) ❱ struct Bar;
1781/// ❰ pub(self) ❱ enum Baz {}
1782/// ❰ pub(super) ❱ fn bruh() {}
1783/// ❰ pub(in bruuh::bruuuh) ❱ type T = u64;
1784/// ```
1785///
1786/// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html)
1787#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1788pub struct Visibility {
1789 pub(crate) syntax: SyntaxNode,
1790}
1791impl Visibility {
1792 pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) }
1793 pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) }
1794 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
1795 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
1796}
1797/// Single identifier.
1798/// Note(@matklad): `Name` is for things that install a new name into the scope,
1799/// `NameRef` is a usage of a name. Most of the time, this definition/reference
1800/// distinction can be determined purely syntactically, ie in
1801/// ```
1802/// fn foo() { foo() }
1803/// ```
1804/// the first foo is `Name`, the second one is `NameRef`.
1805/// The notable exception are patterns, where in
1806/// ``
1807/// let x = 92
1808/// ```
1809/// `x` can be semantically either a name or a name ref, depeding on
1810/// wether there's an `x` constant in scope.
1811/// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db).
1812///
1813/// ```
1814/// let ❰ foo ❱ = bar;
1815/// struct ❰ Baz ❱;
1816/// fn ❰ bruh ❱() {}
1817/// ```
1818///
1819/// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1820#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1821pub struct Name {
1822 pub(crate) syntax: SyntaxNode,
1823}
1824impl Name {
1825 pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) }
1826}
1827/// Reference to a name.
1828/// See the explanation on the difference between `Name` and `NameRef`
1829/// in `Name` ast node docs.
1830///
1831/// ```
1832/// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱;
1833/// ```
1834///
1835/// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1836#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1837pub struct NameRef {
1838 pub(crate) syntax: SyntaxNode,
1839}
1840impl NameRef {}
1841/// Macro call.
1842/// Includes all of its attributes and doc comments.
1843///
1844/// ```
1845/// ❰
1846/// /// Docs
1847/// #[attr]
1848/// macro_rules! foo { // macro rules is also a macro call
1849/// ($bar: tt) => {}
1850/// }
1851/// ❱
1852///
1853/// // semicolon is a part of `MacroCall` when it is used in item positions
1854/// ❰ foo!(); ❱
1855///
1856/// fn main() {
1857/// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi
1858/// }
1859/// ```
1860///
1861/// [Reference](https://doc.rust-lang.org/reference/macros.html)
1862#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1146#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1863pub struct MacroCall { 1147pub struct MacroDef {
1864 pub(crate) syntax: SyntaxNode, 1148 pub(crate) syntax: SyntaxNode,
1865} 1149}
1866impl ast::NameOwner for MacroCall {} 1150impl ast::NameOwner for MacroDef {}
1867impl ast::AttrsOwner for MacroCall {} 1151impl MacroDef {
1868impl ast::DocCommentsOwner for MacroCall {}
1869impl MacroCall {
1870 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1871 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
1872 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } 1152 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
1873 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
1874}
1875/// Attribute.
1876///
1877/// ```
1878/// ❰ #![inner_attr] ❱
1879///
1880/// ❰ #[attr] ❱
1881/// ❰ #[foo = "bar"] ❱
1882/// ❰ #[baz(bruh::bruuh = "42")] ❱
1883/// struct Foo;
1884/// ```
1885///
1886/// [Reference](https://doc.rust-lang.org/reference/attributes.html)
1887#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1888pub struct Attr {
1889 pub(crate) syntax: SyntaxNode,
1890} 1153}
1891impl Attr {
1892 pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
1893 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
1894 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
1895 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
1896 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
1897 pub fn input(&self) -> Option<AttrInput> { support::child(&self.syntax) }
1898 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
1899}
1900/// Stores a list of lexer tokens and other `TokenTree`s.
1901/// It appears in attributes, macro_rules and macro call (foo!)
1902///
1903/// ```
1904/// macro_call! ❰ { my syntax here } ❱;
1905/// ```
1906///
1907/// [Reference](https://doc.rust-lang.org/reference/macros.html)
1908#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1154#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1909pub struct TokenTree { 1155pub struct MacroItems {
1910 pub(crate) syntax: SyntaxNode,
1911}
1912impl TokenTree {}
1913/// Generic lifetime, type and constants parameters list **declaration**.
1914///
1915/// ```
1916/// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {}
1917///
1918/// struct Baz❰ <T> ❱(T);
1919///
1920/// impl❰ <T> ❱ Bruh<T> {}
1921///
1922/// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str;
1923/// ```
1924///
1925/// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1926#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1927pub struct TypeParamList {
1928 pub(crate) syntax: SyntaxNode,
1929}
1930impl TypeParamList {
1931 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
1932 pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
1933 pub fn type_params(&self) -> AstChildren<TypeParam> { support::children(&self.syntax) }
1934 pub fn lifetime_params(&self) -> AstChildren<LifetimeParam> { support::children(&self.syntax) }
1935 pub fn const_params(&self) -> AstChildren<ConstParam> { support::children(&self.syntax) }
1936 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
1937}
1938/// Single type parameter **declaration**.
1939///
1940/// ```
1941/// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {}
1942/// ```
1943///
1944/// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1945#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1946pub struct TypeParam {
1947 pub(crate) syntax: SyntaxNode,
1948}
1949impl ast::NameOwner for TypeParam {}
1950impl ast::AttrsOwner for TypeParam {}
1951impl ast::TypeBoundsOwner for TypeParam {}
1952impl TypeParam {
1953 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
1954 pub fn default_type(&self) -> Option<TypeRef> { support::child(&self.syntax) }
1955}
1956/// Const generic parameter **declaration**.
1957/// ```
1958/// fn foo<T, U, ❰ const BAR: usize ❱, ❰ const BAZ: bool ❱>() {}
1959/// ```
1960///
1961/// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
1962#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1963pub struct ConstParam {
1964 pub(crate) syntax: SyntaxNode, 1156 pub(crate) syntax: SyntaxNode,
1965} 1157}
1966impl ast::NameOwner for ConstParam {} 1158impl ast::ModuleItemOwner for MacroItems {}
1967impl ast::AttrsOwner for ConstParam {} 1159impl MacroItems {}
1968impl ast::TypeAscriptionOwner for ConstParam {}
1969impl ConstParam {
1970 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
1971 pub fn default_val(&self) -> Option<Expr> { support::child(&self.syntax) }
1972}
1973/// Lifetime parameter **declaration**.
1974///
1975/// ```
1976/// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {}
1977/// ```
1978///
1979/// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1980#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1160#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1981pub struct LifetimeParam { 1161pub struct MacroStmts {
1982 pub(crate) syntax: SyntaxNode, 1162 pub(crate) syntax: SyntaxNode,
1983} 1163}
1984impl ast::AttrsOwner for LifetimeParam {} 1164impl MacroStmts {
1985impl LifetimeParam { 1165 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
1986 pub fn lifetime_token(&self) -> Option<SyntaxToken> { 1166 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
1987 support::token(&self.syntax, T![lifetime])
1988 }
1989} 1167}
1990/// Type bound declaration clause.
1991///
1992/// ```
1993/// fn foo<T: ❰ ?Sized ❱ + ❰ Debug ❱>() {}
1994///
1995/// trait Bar<T>
1996/// where
1997/// T: ❰ Send ❱ + ❰ Sync ❱
1998/// {
1999/// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱;
2000/// }
2001/// ```
2002///
2003/// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
2004#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2005pub struct TypeBound { 1169pub struct TypeBound {
2006 pub(crate) syntax: SyntaxNode, 1170 pub(crate) syntax: SyntaxNode,
@@ -2012,40 +1176,6 @@ impl TypeBound {
2012 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } 1176 pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) }
2013 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 1177 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
2014} 1178}
2015/// Type bounds list.
2016///
2017/// ```
2018///
2019/// fn foo<T: ❰ ?Sized + Debug ❱>() {}
2020///
2021/// trait Bar<T>
2022/// where
2023/// T: ❰ Send + Sync ❱
2024/// {
2025/// type Baz: ❰ !Sync + Debug ❱;
2026/// }
2027/// ```
2028///
2029/// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
2030#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2031pub struct TypeBoundList {
2032 pub(crate) syntax: SyntaxNode,
2033}
2034impl TypeBoundList {
2035 pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) }
2036}
2037/// Single where predicate.
2038///
2039/// ```
2040/// trait Foo<'a, 'b, T>
2041/// where
2042/// ❰ 'a: 'b ❱,
2043/// ❰ T: IntoIterator ❱,
2044/// ❰ for<'c> <T as IntoIterator>::Item: Bar<'c> ❱
2045/// {}
2046/// ```
2047///
2048/// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
2049#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1179#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2050pub struct WherePred { 1180pub struct WherePred {
2051 pub(crate) syntax: SyntaxNode, 1181 pub(crate) syntax: SyntaxNode,
@@ -2053,64 +1183,12 @@ pub struct WherePred {
2053impl ast::TypeBoundsOwner for WherePred {} 1183impl ast::TypeBoundsOwner for WherePred {}
2054impl WherePred { 1184impl WherePred {
2055 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } 1185 pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
2056 pub fn type_param_list(&self) -> Option<TypeParamList> { support::child(&self.syntax) } 1186 pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
2057 pub fn lifetime_token(&self) -> Option<SyntaxToken> { 1187 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
2058 support::token(&self.syntax, T![lifetime]) 1188 support::token(&self.syntax, T![lifetime])
2059 } 1189 }
2060 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 1190 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
2061} 1191}
2062/// Where clause.
2063///
2064/// ```
2065/// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {}
2066///
2067/// ```
2068///
2069/// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
2070#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2071pub struct WhereClause {
2072 pub(crate) syntax: SyntaxNode,
2073}
2074impl WhereClause {
2075 pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) }
2076 pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) }
2077}
2078/// Abi declaration.
2079/// Note: the abi string is optional.
2080///
2081/// ```
2082/// ❰ extern "C" ❱ {
2083/// fn foo() {}
2084/// }
2085///
2086/// type Bar = ❰ extern ❱ fn() -> u32;
2087///
2088/// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool;
2089/// ```
2090///
2091/// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2092/// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions)
2093#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2094pub struct Abi {
2095 pub(crate) syntax: SyntaxNode,
2096}
2097impl Abi {}
2098/// Expression statement.
2099///
2100/// ```
2101/// ❰ 42; ❱
2102/// ❰ foo(); ❱
2103/// ❰ (); ❱
2104/// ❰ {}; ❱
2105///
2106/// // constructions with trailing curly brace can omit the semicolon
2107/// // but only when there are satements immediately after them (this is important!)
2108/// ❰ if bool_cond { } ❱
2109/// ❰ loop {} ❱
2110/// ❰ somestatment; ❱
2111/// ```
2112///
2113/// [Reference](https://doc.rust-lang.org/reference/statements.html)
2114#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1192#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2115pub struct ExprStmt { 1193pub struct ExprStmt {
2116 pub(crate) syntax: SyntaxNode, 1194 pub(crate) syntax: SyntaxNode,
@@ -2120,267 +1198,20 @@ impl ExprStmt {
2120 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 1198 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
2121 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 1199 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
2122} 1200}
2123/// Let statement.
2124///
2125/// ```
2126/// ❰ #[attr] let foo; ❱
2127/// ❰ let bar: u64; ❱
2128/// ❰ let baz = 42; ❱
2129/// ❰ let bruh: bool = true; ❱
2130/// ```
2131///
2132/// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements)
2133#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1201#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2134pub struct LetStmt { 1202pub struct LetStmt {
2135 pub(crate) syntax: SyntaxNode, 1203 pub(crate) syntax: SyntaxNode,
2136} 1204}
2137impl ast::AttrsOwner for LetStmt {} 1205impl ast::AttrsOwner for LetStmt {}
2138impl ast::TypeAscriptionOwner for LetStmt {}
2139impl LetStmt { 1206impl LetStmt {
2140 pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) } 1207 pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
2141 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } 1208 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
1209 pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
1210 pub fn ty(&self) -> Option<TypeRef> { support::child(&self.syntax) }
2142 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 1211 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
2143 pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) } 1212 pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) }
2144 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } 1213 pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
2145} 1214}
2146/// Condition of `if` or `while` expression.
2147///
2148/// ```
2149/// if ❰ true ❱ {}
2150/// if ❰ let Pat(foo) = bar ❱ {}
2151///
2152/// while ❰ true ❱ {}
2153/// while ❰ let Pat(baz) = bruh ❱ {}
2154/// ```
2155///
2156/// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
2157/// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
2158#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2159pub struct Condition {
2160 pub(crate) syntax: SyntaxNode,
2161}
2162impl Condition {
2163 pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
2164 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
2165 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
2166 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
2167}
2168/// Parameter list **declaration**.
2169///
2170/// ```
2171/// fn foo❰ (a: u32, b: bool) ❱ -> u32 {}
2172/// let bar = ❰ |a, b| ❱ {};
2173///
2174/// impl Baz {
2175/// fn bruh❰ (&self, a: u32) ❱ {}
2176/// }
2177/// ```
2178///
2179/// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script
2180#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2181pub struct ParamList {
2182 pub(crate) syntax: SyntaxNode,
2183}
2184impl ParamList {
2185 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
2186 pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) }
2187 pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) }
2188 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
2189}
2190/// Self parameter **declaration**.
2191///
2192/// ```
2193/// impl Bruh {
2194/// fn foo(❰ self ❱) {}
2195/// fn bar(❰ &self ❱) {}
2196/// fn baz(❰ &mut self ❱) {}
2197/// fn blah<'a>(❰ &'a self ❱) {}
2198/// fn blin(❰ self: Box<Self> ❱) {}
2199/// }
2200/// ```
2201///
2202/// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
2203#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2204pub struct SelfParam {
2205 pub(crate) syntax: SyntaxNode,
2206}
2207impl ast::TypeAscriptionOwner for SelfParam {}
2208impl ast::AttrsOwner for SelfParam {}
2209impl SelfParam {
2210 pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) }
2211 pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) }
2212 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
2213 support::token(&self.syntax, T![lifetime])
2214 }
2215 pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) }
2216}
2217/// Parameter **declaration**.
2218///
2219/// ```
2220/// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {}
2221///
2222/// extern "C" {
2223/// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32;
2224/// }
2225/// ```
2226///
2227/// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
2228#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2229pub struct Param {
2230 pub(crate) syntax: SyntaxNode,
2231}
2232impl ast::TypeAscriptionOwner for Param {}
2233impl ast::AttrsOwner for Param {}
2234impl Param {
2235 pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
2236 pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) }
2237}
2238/// Use declaration.
2239///
2240/// ```
2241/// ❰ #[attr] pub use foo; ❱
2242/// ❰ use bar as baz; ❱
2243/// ❰ use bruh::{self, bruuh}; ❱
2244/// ❰ use { blin::blen, blah::* };
2245/// ```
2246///
2247/// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
2248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2249pub struct UseItem {
2250 pub(crate) syntax: SyntaxNode,
2251}
2252impl ast::AttrsOwner for UseItem {}
2253impl ast::VisibilityOwner for UseItem {}
2254impl UseItem {
2255 pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) }
2256 pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) }
2257}
2258/// Use tree.
2259///
2260/// ```
2261/// pub use ❰ foo::❰ * ❱ ❱;
2262/// use ❰ bar as baz ❱;
2263/// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱;
2264/// use ❰ { ❰ blin::blen ❱ } ❱
2265/// ```
2266///
2267/// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
2268#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2269pub struct UseTree {
2270 pub(crate) syntax: SyntaxNode,
2271}
2272impl UseTree {
2273 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
2274 pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) }
2275 pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) }
2276 pub fn alias(&self) -> Option<Alias> { support::child(&self.syntax) }
2277}
2278/// Item alias.
2279/// Note: this is not the type alias.
2280///
2281/// ```
2282/// use foo ❰ as bar ❱;
2283/// use baz::{bruh ❰ as _ ❱};
2284/// extern crate bruuh ❰ as blin ❱;
2285/// ```
2286///
2287/// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
2288#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2289pub struct Alias {
2290 pub(crate) syntax: SyntaxNode,
2291}
2292impl ast::NameOwner for Alias {}
2293impl Alias {
2294 pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
2295}
2296/// Sublist of use trees.
2297///
2298/// ```
2299/// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱;
2300/// use ❰ { blin::blen::❰ {} ❱ } ❱
2301/// ```
2302///
2303/// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
2304#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2305pub struct UseTreeList {
2306 pub(crate) syntax: SyntaxNode,
2307}
2308impl UseTreeList {
2309 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
2310 pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) }
2311 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
2312}
2313/// Extern crate item.
2314///
2315/// ```
2316/// ❰ #[attr] pub extern crate foo; ❱
2317/// ❰ extern crate self as bar; ❱
2318/// ```
2319///
2320/// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html)
2321#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2322pub struct ExternCrateItem {
2323 pub(crate) syntax: SyntaxNode,
2324}
2325impl ast::AttrsOwner for ExternCrateItem {}
2326impl ast::VisibilityOwner for ExternCrateItem {}
2327impl ExternCrateItem {
2328 pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
2329 pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) }
2330 pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
2331 pub fn alias(&self) -> Option<Alias> { support::child(&self.syntax) }
2332}
2333/// Call site arguments list.
2334///
2335/// ```
2336/// foo::<T, U>❰ (42, true) ❱;
2337/// ```
2338///
2339/// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
2340#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2341pub struct ArgList {
2342 pub(crate) syntax: SyntaxNode,
2343}
2344impl ArgList {
2345 pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
2346 pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
2347 pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
2348}
2349/// Path to a symbol. Includes single identifier names and elaborate paths with
2350/// generic parameters.
2351///
2352/// ```
2353/// (0..10).❰ ❰ collect ❱ ::<Vec<_>> ❱();
2354/// ❰ ❰ ❰ Vec ❱ ::<u8> ❱ ::with_capacity ❱(1024);
2355/// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱();
2356/// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱();
2357/// ```
2358///
2359/// [Reference](https://doc.rust-lang.org/reference/paths.html)
2360#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2361pub struct Path {
2362 pub(crate) syntax: SyntaxNode,
2363}
2364impl Path {
2365 pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) }
2366 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
2367 pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) }
2368}
2369/// Segment of the path to a symbol.
2370/// Only path segment of an absolute path holds the `::` token,
2371/// all other `::` tokens that connect path segments reside under `Path` itself.`
2372///
2373/// ```
2374/// (0..10).❰ collect ❱ :: ❰ <Vec<_>> ❱();
2375/// ❰ Vec ❱ :: ❰ <u8> ❱ :: ❰ with_capacity ❱(1024);
2376/// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱();
2377/// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱();
2378///
2379/// // Note that only in this case `::` token is inlcuded:
2380/// ❰ ::foo ❱;
2381/// ```
2382///
2383/// [Reference](https://doc.rust-lang.org/reference/paths.html)
2384#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1215#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2385pub struct PathSegment { 1216pub struct PathSegment {
2386 pub(crate) syntax: SyntaxNode, 1217 pub(crate) syntax: SyntaxNode,
@@ -2398,50 +1229,22 @@ impl PathSegment {
2398 pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } 1229 pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
2399 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } 1230 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
2400} 1231}
2401/// List of type arguments that are passed at generic instantiation site.
2402///
2403/// ```
2404/// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar;
2405///
2406/// Vec❰ ::<bool> ❱::();
2407/// ```
2408///
2409/// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
2410#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1232#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2411pub struct TypeArgList { 1233pub struct TypeArg {
2412 pub(crate) syntax: SyntaxNode, 1234 pub(crate) syntax: SyntaxNode,
2413} 1235}
2414impl TypeArgList { 1236impl TypeArg {
2415 pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } 1237 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
2416 pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
2417 pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) }
2418 pub fn type_args(&self) -> AstChildren<TypeArg> { support::children(&self.syntax) }
2419 pub fn lifetime_args(&self) -> AstChildren<LifetimeArg> { support::children(&self.syntax) }
2420 pub fn assoc_type_args(&self) -> AstChildren<AssocTypeArg> { support::children(&self.syntax) }
2421 pub fn const_args(&self) -> AstChildren<ConstArg> { support::children(&self.syntax) }
2422 pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
2423} 1238}
2424/// Type argument that is passed at generic instantiation site.
2425///
2426/// ```
2427/// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz;
2428/// ```
2429///
2430/// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
2431#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1239#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2432pub struct TypeArg { 1240pub struct LifetimeArg {
2433 pub(crate) syntax: SyntaxNode, 1241 pub(crate) syntax: SyntaxNode,
2434} 1242}
2435impl TypeArg { 1243impl LifetimeArg {
2436 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 1244 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
1245 support::token(&self.syntax, T![lifetime])
1246 }
2437} 1247}
2438/// Associated type argument that is passed at generic instantiation site.
2439/// ```
2440/// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh;
2441///
2442/// trait Bruh<T>: Iterator<❰ Item: Debug ❱> {}
2443/// ```
2444///
2445#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2446pub struct AssocTypeArg { 1249pub struct AssocTypeArg {
2447 pub(crate) syntax: SyntaxNode, 1250 pub(crate) syntax: SyntaxNode,
@@ -2452,33 +1255,6 @@ impl AssocTypeArg {
2452 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } 1255 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
2453 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) } 1256 pub fn type_ref(&self) -> Option<TypeRef> { support::child(&self.syntax) }
2454} 1257}
2455/// Lifetime argument that is passed at generic instantiation site.
2456///
2457/// ```
2458/// fn foo<'a>(s: &'a str) {
2459/// bar::<❰ 'a ❱>(s);
2460/// }
2461/// ```
2462///
2463/// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
2464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2465pub struct LifetimeArg {
2466 pub(crate) syntax: SyntaxNode,
2467}
2468impl LifetimeArg {
2469 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
2470 support::token(&self.syntax, T![lifetime])
2471 }
2472}
2473/// Constant value argument that is passed at generic instantiation site.
2474///
2475/// ```
2476/// foo::<u32, ❰ { true } ❱>();
2477///
2478/// bar::<❰ { 2 + 2} ❱>();
2479/// ```
2480///
2481/// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
2482#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2483pub struct ConstArg { 1259pub struct ConstArg {
2484 pub(crate) syntax: SyntaxNode, 1260 pub(crate) syntax: SyntaxNode,
@@ -2487,136 +1263,24 @@ impl ConstArg {
2487 pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) } 1263 pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) }
2488 pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } 1264 pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
2489} 1265}
2490/// FIXME: (@edwin0cheng) Remove it to use ItemList instead
2491/// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243
2492///
2493/// [Reference](https://doc.rust-lang.org/reference/macros.html)
2494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2495pub struct MacroItems {
2496 pub(crate) syntax: SyntaxNode,
2497}
2498impl ast::ModuleItemOwner for MacroItems {}
2499impl MacroItems {}
2500/// FIXME: (@edwin0cheng) add some documentation here. As per the writing
2501/// of this comment this ast node is not used.
2502///
2503/// ```
2504/// // FIXME: example here
2505/// ```
2506///
2507/// [Reference](https://doc.rust-lang.org/reference/macros.html)
2508#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2509pub struct MacroStmts {
2510 pub(crate) syntax: SyntaxNode,
2511}
2512impl MacroStmts {
2513 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
2514 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
2515}
2516/// List of items in an extern block.
2517///
2518/// ```
2519/// extern "C" ❰
2520/// {
2521/// fn foo();
2522/// static var: u32;
2523/// }
2524/// ❱
2525/// ```
2526///
2527/// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2528#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2529pub struct ExternItemList {
2530 pub(crate) syntax: SyntaxNode,
2531}
2532impl ast::ModuleItemOwner for ExternItemList {}
2533impl ExternItemList {
2534 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
2535 pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) }
2536 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
2537}
2538/// Extern block.
2539///
2540/// ```
2541/// ❰
2542/// extern "C" {
2543/// fn foo();
2544/// }
2545/// ❱
2546///
2547/// ```
2548///
2549/// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2550#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2551pub struct ExternBlock {
2552 pub(crate) syntax: SyntaxNode,
2553}
2554impl ExternBlock {
2555 pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
2556 pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) }
2557}
2558/// Meta item in an attribute.
2559///
2560/// ```
2561/// #[❰ bar::baz = "42" ❱]
2562/// #[❰ bruh(bruuh("true")) ❱]
2563/// struct Foo;
2564/// ```
2565///
2566/// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax)
2567#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2568pub struct MetaItem {
2569 pub(crate) syntax: SyntaxNode,
2570}
2571impl MetaItem {
2572 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
2573 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
2574 pub fn attr_input(&self) -> Option<AttrInput> { support::child(&self.syntax) }
2575 pub fn nested_meta_items(&self) -> AstChildren<MetaItem> { support::children(&self.syntax) }
2576}
2577/// Macro 2.0 definition.
2578/// Their syntax is still WIP by rustc team...
2579/// ```
2580/// ❰
2581/// macro foo { }
2582/// ❱
2583/// ```
2584///
2585/// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md)
2586#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2587pub struct MacroDef {
2588 pub(crate) syntax: SyntaxNode,
2589}
2590impl MacroDef {
2591 pub fn name(&self) -> Option<Name> { support::child(&self.syntax) }
2592 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
2593}
2594/// Any kind of nominal type definition.
2595#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1266#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2596pub enum NominalDef { 1267pub enum Item {
2597 StructDef(StructDef), 1268 Const(Const),
2598 EnumDef(EnumDef), 1269 Enum(Enum),
2599 UnionDef(UnionDef), 1270 ExternBlock(ExternBlock),
2600} 1271 ExternCrate(ExternCrate),
2601impl ast::NameOwner for NominalDef {} 1272 Fn(Fn),
2602impl ast::TypeParamsOwner for NominalDef {} 1273 Impl(Impl),
2603impl ast::AttrsOwner for NominalDef {} 1274 MacroCall(MacroCall),
2604/// Any kind of **declared** generic parameter 1275 Module(Module),
2605#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1276 Static(Static),
2606pub enum GenericParam { 1277 Struct(Struct),
2607 LifetimeParam(LifetimeParam), 1278 Trait(Trait),
2608 TypeParam(TypeParam), 1279 TypeAlias(TypeAlias),
2609 ConstParam(ConstParam), 1280 Union(Union),
2610} 1281 Use(Use),
2611/// Any kind of generic argument passed at instantiation site
2612#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2613pub enum GenericArg {
2614 LifetimeArg(LifetimeArg),
2615 TypeArg(TypeArg),
2616 ConstArg(ConstArg),
2617 AssocTypeArg(AssocTypeArg),
2618} 1282}
2619/// Any kind of construct valid in type context 1283impl ast::AttrsOwner for Item {}
2620#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1284#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2621pub enum TypeRef { 1285pub enum TypeRef {
2622 ParenType(ParenType), 1286 ParenType(ParenType),
@@ -2633,50 +1297,29 @@ pub enum TypeRef {
2633 ImplTraitType(ImplTraitType), 1297 ImplTraitType(ImplTraitType),
2634 DynTraitType(DynTraitType), 1298 DynTraitType(DynTraitType),
2635} 1299}
2636/// Any kind of top-level item that may appear in a module
2637#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2638pub enum ModuleItem {
2639 StructDef(StructDef),
2640 UnionDef(UnionDef),
2641 EnumDef(EnumDef),
2642 FnDef(FnDef),
2643 TraitDef(TraitDef),
2644 TypeAliasDef(TypeAliasDef),
2645 ImplDef(ImplDef),
2646 UseItem(UseItem),
2647 ExternCrateItem(ExternCrateItem),
2648 ConstDef(ConstDef),
2649 StaticDef(StaticDef),
2650 Module(Module),
2651 MacroCall(MacroCall),
2652 ExternBlock(ExternBlock),
2653}
2654impl ast::NameOwner for ModuleItem {}
2655impl ast::AttrsOwner for ModuleItem {}
2656impl ast::VisibilityOwner for ModuleItem {}
2657/// Any kind of item that may appear in an impl block
2658///
2659/// // FIXME: impl blocks can also contain MacroCall
2660#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2661pub enum AssocItem { 1301pub enum Pat {
2662 FnDef(FnDef), 1302 OrPat(OrPat),
2663 TypeAliasDef(TypeAliasDef), 1303 ParenPat(ParenPat),
2664 ConstDef(ConstDef), 1304 RefPat(RefPat),
1305 BoxPat(BoxPat),
1306 BindPat(BindPat),
1307 PlaceholderPat(PlaceholderPat),
1308 DotDotPat(DotDotPat),
1309 PathPat(PathPat),
1310 RecordPat(RecordPat),
1311 TupleStructPat(TupleStructPat),
1312 TuplePat(TuplePat),
1313 SlicePat(SlicePat),
1314 RangePat(RangePat),
1315 LiteralPat(LiteralPat),
1316 MacroPat(MacroPat),
2665} 1317}
2666impl ast::NameOwner for AssocItem {}
2667impl ast::AttrsOwner for AssocItem {}
2668/// Any kind of item that may appear in an extern block
2669///
2670/// // FIXME: extern blocks can also contain MacroCall
2671#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1318#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2672pub enum ExternItem { 1319pub enum FieldList {
2673 FnDef(FnDef), 1320 RecordFieldList(RecordFieldList),
2674 StaticDef(StaticDef), 1321 TupleFieldList(TupleFieldList),
2675} 1322}
2676impl ast::NameOwner for ExternItem {}
2677impl ast::AttrsOwner for ExternItem {}
2678impl ast::VisibilityOwner for ExternItem {}
2679/// Any kind of expression
2680#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1323#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2681pub enum Expr { 1324pub enum Expr {
2682 TupleExpr(TupleExpr), 1325 TupleExpr(TupleExpr),
@@ -2694,7 +1337,7 @@ pub enum Expr {
2694 BlockExpr(BlockExpr), 1337 BlockExpr(BlockExpr),
2695 ReturnExpr(ReturnExpr), 1338 ReturnExpr(ReturnExpr),
2696 MatchExpr(MatchExpr), 1339 MatchExpr(MatchExpr),
2697 RecordLit(RecordLit), 1340 RecordExpr(RecordExpr),
2698 CallExpr(CallExpr), 1341 CallExpr(CallExpr),
2699 IndexExpr(IndexExpr), 1342 IndexExpr(IndexExpr),
2700 MethodCallExpr(MethodCallExpr), 1343 MethodCallExpr(MethodCallExpr),
@@ -2711,53 +1354,46 @@ pub enum Expr {
2711 MacroCall(MacroCall), 1354 MacroCall(MacroCall),
2712 BoxExpr(BoxExpr), 1355 BoxExpr(BoxExpr),
2713} 1356}
2714impl ast::AttrsOwner for Expr {}
2715/// Any kind of pattern
2716#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1357#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2717pub enum Pat { 1358pub enum AssocItem {
2718 OrPat(OrPat), 1359 Fn(Fn),
2719 ParenPat(ParenPat), 1360 TypeAlias(TypeAlias),
2720 RefPat(RefPat), 1361 Const(Const),
2721 BoxPat(BoxPat), 1362 MacroCall(MacroCall),
2722 BindPat(BindPat),
2723 PlaceholderPat(PlaceholderPat),
2724 DotDotPat(DotDotPat),
2725 PathPat(PathPat),
2726 RecordPat(RecordPat),
2727 TupleStructPat(TupleStructPat),
2728 TuplePat(TuplePat),
2729 SlicePat(SlicePat),
2730 RangePat(RangePat),
2731 LiteralPat(LiteralPat),
2732 MacroPat(MacroPat),
2733} 1363}
2734/// Any kind of pattern that appears directly inside of the curly 1364impl ast::AttrsOwner for AssocItem {}
2735/// braces of a record pattern 1365impl ast::NameOwner for AssocItem {}
2736#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2737pub enum RecordInnerPat { 1367pub enum ExternItem {
2738 RecordFieldPat(RecordFieldPat), 1368 Fn(Fn),
2739 BindPat(BindPat), 1369 Static(Static),
1370 MacroCall(MacroCall),
2740} 1371}
2741/// Any kind of input to an attribute 1372impl ast::AttrsOwner for ExternItem {}
1373impl ast::NameOwner for ExternItem {}
2742#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1374#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2743pub enum AttrInput { 1375pub enum GenericParam {
2744 Literal(Literal), 1376 LifetimeParam(LifetimeParam),
2745 TokenTree(TokenTree), 1377 TypeParam(TypeParam),
1378 ConstParam(ConstParam),
2746} 1379}
2747/// Any kind of statement 1380impl ast::AttrsOwner for GenericParam {}
2748/// Note: there are no empty statements, these are just represented as
2749/// bare semicolons without a dedicated statement ast node.
2750#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1381#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2751pub enum Stmt { 1382pub enum Stmt {
2752 LetStmt(LetStmt), 1383 LetStmt(LetStmt),
2753 ExprStmt(ExprStmt), 1384 ExprStmt(ExprStmt),
2754} 1385}
2755/// Any kind of fields list (record or tuple field lists) 1386impl ast::AttrsOwner for Stmt {}
2756#[derive(Debug, Clone, PartialEq, Eq, Hash)] 1387#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2757pub enum FieldDefList { 1388pub enum AdtDef {
2758 RecordFieldDefList(RecordFieldDefList), 1389 Struct(Struct),
2759 TupleFieldDefList(TupleFieldDefList), 1390 Enum(Enum),
1391 Union(Union),
2760} 1392}
1393impl ast::AttrsOwner for AdtDef {}
1394impl ast::GenericParamsOwner for AdtDef {}
1395impl ast::NameOwner for AdtDef {}
1396impl ast::VisibilityOwner for AdtDef {}
2761impl AstNode for SourceFile { 1397impl AstNode for SourceFile {
2762 fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE } 1398 fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
2763 fn cast(syntax: SyntaxNode) -> Option<Self> { 1399 fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2769,8 +1405,8 @@ impl AstNode for SourceFile {
2769 } 1405 }
2770 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1406 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2771} 1407}
2772impl AstNode for FnDef { 1408impl AstNode for Attr {
2773 fn can_cast(kind: SyntaxKind) -> bool { kind == FN_DEF } 1409 fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
2774 fn cast(syntax: SyntaxNode) -> Option<Self> { 1410 fn cast(syntax: SyntaxNode) -> Option<Self> {
2775 if Self::can_cast(syntax.kind()) { 1411 if Self::can_cast(syntax.kind()) {
2776 Some(Self { syntax }) 1412 Some(Self { syntax })
@@ -2780,8 +1416,8 @@ impl AstNode for FnDef {
2780 } 1416 }
2781 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1417 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2782} 1418}
2783impl AstNode for RetType { 1419impl AstNode for Const {
2784 fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE } 1420 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
2785 fn cast(syntax: SyntaxNode) -> Option<Self> { 1421 fn cast(syntax: SyntaxNode) -> Option<Self> {
2786 if Self::can_cast(syntax.kind()) { 1422 if Self::can_cast(syntax.kind()) {
2787 Some(Self { syntax }) 1423 Some(Self { syntax })
@@ -2791,8 +1427,8 @@ impl AstNode for RetType {
2791 } 1427 }
2792 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1428 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2793} 1429}
2794impl AstNode for StructDef { 1430impl AstNode for Enum {
2795 fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT_DEF } 1431 fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
2796 fn cast(syntax: SyntaxNode) -> Option<Self> { 1432 fn cast(syntax: SyntaxNode) -> Option<Self> {
2797 if Self::can_cast(syntax.kind()) { 1433 if Self::can_cast(syntax.kind()) {
2798 Some(Self { syntax }) 1434 Some(Self { syntax })
@@ -2802,8 +1438,8 @@ impl AstNode for StructDef {
2802 } 1438 }
2803 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1439 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2804} 1440}
2805impl AstNode for UnionDef { 1441impl AstNode for ExternBlock {
2806 fn can_cast(kind: SyntaxKind) -> bool { kind == UNION_DEF } 1442 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
2807 fn cast(syntax: SyntaxNode) -> Option<Self> { 1443 fn cast(syntax: SyntaxNode) -> Option<Self> {
2808 if Self::can_cast(syntax.kind()) { 1444 if Self::can_cast(syntax.kind()) {
2809 Some(Self { syntax }) 1445 Some(Self { syntax })
@@ -2813,8 +1449,8 @@ impl AstNode for UnionDef {
2813 } 1449 }
2814 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1450 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2815} 1451}
2816impl AstNode for RecordFieldDefList { 1452impl AstNode for ExternCrate {
2817 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_DEF_LIST } 1453 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
2818 fn cast(syntax: SyntaxNode) -> Option<Self> { 1454 fn cast(syntax: SyntaxNode) -> Option<Self> {
2819 if Self::can_cast(syntax.kind()) { 1455 if Self::can_cast(syntax.kind()) {
2820 Some(Self { syntax }) 1456 Some(Self { syntax })
@@ -2824,8 +1460,8 @@ impl AstNode for RecordFieldDefList {
2824 } 1460 }
2825 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1461 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2826} 1462}
2827impl AstNode for RecordFieldDef { 1463impl AstNode for Fn {
2828 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_DEF } 1464 fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
2829 fn cast(syntax: SyntaxNode) -> Option<Self> { 1465 fn cast(syntax: SyntaxNode) -> Option<Self> {
2830 if Self::can_cast(syntax.kind()) { 1466 if Self::can_cast(syntax.kind()) {
2831 Some(Self { syntax }) 1467 Some(Self { syntax })
@@ -2835,8 +1471,8 @@ impl AstNode for RecordFieldDef {
2835 } 1471 }
2836 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1472 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2837} 1473}
2838impl AstNode for TupleFieldDefList { 1474impl AstNode for Impl {
2839 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_DEF_LIST } 1475 fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
2840 fn cast(syntax: SyntaxNode) -> Option<Self> { 1476 fn cast(syntax: SyntaxNode) -> Option<Self> {
2841 if Self::can_cast(syntax.kind()) { 1477 if Self::can_cast(syntax.kind()) {
2842 Some(Self { syntax }) 1478 Some(Self { syntax })
@@ -2846,8 +1482,8 @@ impl AstNode for TupleFieldDefList {
2846 } 1482 }
2847 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1483 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2848} 1484}
2849impl AstNode for TupleFieldDef { 1485impl AstNode for MacroCall {
2850 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_DEF } 1486 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
2851 fn cast(syntax: SyntaxNode) -> Option<Self> { 1487 fn cast(syntax: SyntaxNode) -> Option<Self> {
2852 if Self::can_cast(syntax.kind()) { 1488 if Self::can_cast(syntax.kind()) {
2853 Some(Self { syntax }) 1489 Some(Self { syntax })
@@ -2857,8 +1493,8 @@ impl AstNode for TupleFieldDef {
2857 } 1493 }
2858 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1494 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2859} 1495}
2860impl AstNode for EnumDef { 1496impl AstNode for Module {
2861 fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM_DEF } 1497 fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
2862 fn cast(syntax: SyntaxNode) -> Option<Self> { 1498 fn cast(syntax: SyntaxNode) -> Option<Self> {
2863 if Self::can_cast(syntax.kind()) { 1499 if Self::can_cast(syntax.kind()) {
2864 Some(Self { syntax }) 1500 Some(Self { syntax })
@@ -2868,8 +1504,8 @@ impl AstNode for EnumDef {
2868 } 1504 }
2869 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1505 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2870} 1506}
2871impl AstNode for EnumVariantList { 1507impl AstNode for Static {
2872 fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM_VARIANT_LIST } 1508 fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
2873 fn cast(syntax: SyntaxNode) -> Option<Self> { 1509 fn cast(syntax: SyntaxNode) -> Option<Self> {
2874 if Self::can_cast(syntax.kind()) { 1510 if Self::can_cast(syntax.kind()) {
2875 Some(Self { syntax }) 1511 Some(Self { syntax })
@@ -2879,8 +1515,8 @@ impl AstNode for EnumVariantList {
2879 } 1515 }
2880 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1516 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2881} 1517}
2882impl AstNode for EnumVariant { 1518impl AstNode for Struct {
2883 fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM_VARIANT } 1519 fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
2884 fn cast(syntax: SyntaxNode) -> Option<Self> { 1520 fn cast(syntax: SyntaxNode) -> Option<Self> {
2885 if Self::can_cast(syntax.kind()) { 1521 if Self::can_cast(syntax.kind()) {
2886 Some(Self { syntax }) 1522 Some(Self { syntax })
@@ -2890,8 +1526,8 @@ impl AstNode for EnumVariant {
2890 } 1526 }
2891 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1527 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2892} 1528}
2893impl AstNode for TraitDef { 1529impl AstNode for Trait {
2894 fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_DEF } 1530 fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
2895 fn cast(syntax: SyntaxNode) -> Option<Self> { 1531 fn cast(syntax: SyntaxNode) -> Option<Self> {
2896 if Self::can_cast(syntax.kind()) { 1532 if Self::can_cast(syntax.kind()) {
2897 Some(Self { syntax }) 1533 Some(Self { syntax })
@@ -2901,8 +1537,8 @@ impl AstNode for TraitDef {
2901 } 1537 }
2902 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1538 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2903} 1539}
2904impl AstNode for Module { 1540impl AstNode for TypeAlias {
2905 fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE } 1541 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
2906 fn cast(syntax: SyntaxNode) -> Option<Self> { 1542 fn cast(syntax: SyntaxNode) -> Option<Self> {
2907 if Self::can_cast(syntax.kind()) { 1543 if Self::can_cast(syntax.kind()) {
2908 Some(Self { syntax }) 1544 Some(Self { syntax })
@@ -2912,8 +1548,8 @@ impl AstNode for Module {
2912 } 1548 }
2913 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1549 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2914} 1550}
2915impl AstNode for ItemList { 1551impl AstNode for Union {
2916 fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST } 1552 fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
2917 fn cast(syntax: SyntaxNode) -> Option<Self> { 1553 fn cast(syntax: SyntaxNode) -> Option<Self> {
2918 if Self::can_cast(syntax.kind()) { 1554 if Self::can_cast(syntax.kind()) {
2919 Some(Self { syntax }) 1555 Some(Self { syntax })
@@ -2923,8 +1559,8 @@ impl AstNode for ItemList {
2923 } 1559 }
2924 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1560 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2925} 1561}
2926impl AstNode for ConstDef { 1562impl AstNode for Use {
2927 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_DEF } 1563 fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
2928 fn cast(syntax: SyntaxNode) -> Option<Self> { 1564 fn cast(syntax: SyntaxNode) -> Option<Self> {
2929 if Self::can_cast(syntax.kind()) { 1565 if Self::can_cast(syntax.kind()) {
2930 Some(Self { syntax }) 1566 Some(Self { syntax })
@@ -2934,8 +1570,8 @@ impl AstNode for ConstDef {
2934 } 1570 }
2935 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1571 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2936} 1572}
2937impl AstNode for StaticDef { 1573impl AstNode for Visibility {
2938 fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC_DEF } 1574 fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
2939 fn cast(syntax: SyntaxNode) -> Option<Self> { 1575 fn cast(syntax: SyntaxNode) -> Option<Self> {
2940 if Self::can_cast(syntax.kind()) { 1576 if Self::can_cast(syntax.kind()) {
2941 Some(Self { syntax }) 1577 Some(Self { syntax })
@@ -2945,8 +1581,8 @@ impl AstNode for StaticDef {
2945 } 1581 }
2946 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1582 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2947} 1583}
2948impl AstNode for TypeAliasDef { 1584impl AstNode for Name {
2949 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS_DEF } 1585 fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
2950 fn cast(syntax: SyntaxNode) -> Option<Self> { 1586 fn cast(syntax: SyntaxNode) -> Option<Self> {
2951 if Self::can_cast(syntax.kind()) { 1587 if Self::can_cast(syntax.kind()) {
2952 Some(Self { syntax }) 1588 Some(Self { syntax })
@@ -2956,8 +1592,8 @@ impl AstNode for TypeAliasDef {
2956 } 1592 }
2957 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1593 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2958} 1594}
2959impl AstNode for ImplDef { 1595impl AstNode for ItemList {
2960 fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_DEF } 1596 fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
2961 fn cast(syntax: SyntaxNode) -> Option<Self> { 1597 fn cast(syntax: SyntaxNode) -> Option<Self> {
2962 if Self::can_cast(syntax.kind()) { 1598 if Self::can_cast(syntax.kind()) {
2963 Some(Self { syntax }) 1599 Some(Self { syntax })
@@ -2967,8 +1603,8 @@ impl AstNode for ImplDef {
2967 } 1603 }
2968 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1604 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2969} 1605}
2970impl AstNode for ParenType { 1606impl AstNode for NameRef {
2971 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE } 1607 fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
2972 fn cast(syntax: SyntaxNode) -> Option<Self> { 1608 fn cast(syntax: SyntaxNode) -> Option<Self> {
2973 if Self::can_cast(syntax.kind()) { 1609 if Self::can_cast(syntax.kind()) {
2974 Some(Self { syntax }) 1610 Some(Self { syntax })
@@ -2978,8 +1614,8 @@ impl AstNode for ParenType {
2978 } 1614 }
2979 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1615 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2980} 1616}
2981impl AstNode for TupleType { 1617impl AstNode for Rename {
2982 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE } 1618 fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
2983 fn cast(syntax: SyntaxNode) -> Option<Self> { 1619 fn cast(syntax: SyntaxNode) -> Option<Self> {
2984 if Self::can_cast(syntax.kind()) { 1620 if Self::can_cast(syntax.kind()) {
2985 Some(Self { syntax }) 1621 Some(Self { syntax })
@@ -2989,8 +1625,8 @@ impl AstNode for TupleType {
2989 } 1625 }
2990 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1626 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2991} 1627}
2992impl AstNode for NeverType { 1628impl AstNode for UseTree {
2993 fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE } 1629 fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
2994 fn cast(syntax: SyntaxNode) -> Option<Self> { 1630 fn cast(syntax: SyntaxNode) -> Option<Self> {
2995 if Self::can_cast(syntax.kind()) { 1631 if Self::can_cast(syntax.kind()) {
2996 Some(Self { syntax }) 1632 Some(Self { syntax })
@@ -3000,8 +1636,8 @@ impl AstNode for NeverType {
3000 } 1636 }
3001 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1637 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3002} 1638}
3003impl AstNode for PathType { 1639impl AstNode for Path {
3004 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE } 1640 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
3005 fn cast(syntax: SyntaxNode) -> Option<Self> { 1641 fn cast(syntax: SyntaxNode) -> Option<Self> {
3006 if Self::can_cast(syntax.kind()) { 1642 if Self::can_cast(syntax.kind()) {
3007 Some(Self { syntax }) 1643 Some(Self { syntax })
@@ -3011,8 +1647,8 @@ impl AstNode for PathType {
3011 } 1647 }
3012 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1648 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3013} 1649}
3014impl AstNode for PointerType { 1650impl AstNode for UseTreeList {
3015 fn can_cast(kind: SyntaxKind) -> bool { kind == POINTER_TYPE } 1651 fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
3016 fn cast(syntax: SyntaxNode) -> Option<Self> { 1652 fn cast(syntax: SyntaxNode) -> Option<Self> {
3017 if Self::can_cast(syntax.kind()) { 1653 if Self::can_cast(syntax.kind()) {
3018 Some(Self { syntax }) 1654 Some(Self { syntax })
@@ -3022,8 +1658,8 @@ impl AstNode for PointerType {
3022 } 1658 }
3023 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1659 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3024} 1660}
3025impl AstNode for ArrayType { 1661impl AstNode for Abi {
3026 fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE } 1662 fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
3027 fn cast(syntax: SyntaxNode) -> Option<Self> { 1663 fn cast(syntax: SyntaxNode) -> Option<Self> {
3028 if Self::can_cast(syntax.kind()) { 1664 if Self::can_cast(syntax.kind()) {
3029 Some(Self { syntax }) 1665 Some(Self { syntax })
@@ -3033,8 +1669,8 @@ impl AstNode for ArrayType {
3033 } 1669 }
3034 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1670 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3035} 1671}
3036impl AstNode for SliceType { 1672impl AstNode for GenericParamList {
3037 fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE } 1673 fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
3038 fn cast(syntax: SyntaxNode) -> Option<Self> { 1674 fn cast(syntax: SyntaxNode) -> Option<Self> {
3039 if Self::can_cast(syntax.kind()) { 1675 if Self::can_cast(syntax.kind()) {
3040 Some(Self { syntax }) 1676 Some(Self { syntax })
@@ -3044,8 +1680,8 @@ impl AstNode for SliceType {
3044 } 1680 }
3045 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1681 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3046} 1682}
3047impl AstNode for ReferenceType { 1683impl AstNode for ParamList {
3048 fn can_cast(kind: SyntaxKind) -> bool { kind == REFERENCE_TYPE } 1684 fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
3049 fn cast(syntax: SyntaxNode) -> Option<Self> { 1685 fn cast(syntax: SyntaxNode) -> Option<Self> {
3050 if Self::can_cast(syntax.kind()) { 1686 if Self::can_cast(syntax.kind()) {
3051 Some(Self { syntax }) 1687 Some(Self { syntax })
@@ -3055,8 +1691,8 @@ impl AstNode for ReferenceType {
3055 } 1691 }
3056 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1692 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3057} 1693}
3058impl AstNode for PlaceholderType { 1694impl AstNode for RetType {
3059 fn can_cast(kind: SyntaxKind) -> bool { kind == PLACEHOLDER_TYPE } 1695 fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
3060 fn cast(syntax: SyntaxNode) -> Option<Self> { 1696 fn cast(syntax: SyntaxNode) -> Option<Self> {
3061 if Self::can_cast(syntax.kind()) { 1697 if Self::can_cast(syntax.kind()) {
3062 Some(Self { syntax }) 1698 Some(Self { syntax })
@@ -3066,8 +1702,8 @@ impl AstNode for PlaceholderType {
3066 } 1702 }
3067 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1703 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3068} 1704}
3069impl AstNode for FnPointerType { 1705impl AstNode for WhereClause {
3070 fn can_cast(kind: SyntaxKind) -> bool { kind == FN_POINTER_TYPE } 1706 fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
3071 fn cast(syntax: SyntaxNode) -> Option<Self> { 1707 fn cast(syntax: SyntaxNode) -> Option<Self> {
3072 if Self::can_cast(syntax.kind()) { 1708 if Self::can_cast(syntax.kind()) {
3073 Some(Self { syntax }) 1709 Some(Self { syntax })
@@ -3077,8 +1713,8 @@ impl AstNode for FnPointerType {
3077 } 1713 }
3078 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1714 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3079} 1715}
3080impl AstNode for ForType { 1716impl AstNode for BlockExpr {
3081 fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE } 1717 fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
3082 fn cast(syntax: SyntaxNode) -> Option<Self> { 1718 fn cast(syntax: SyntaxNode) -> Option<Self> {
3083 if Self::can_cast(syntax.kind()) { 1719 if Self::can_cast(syntax.kind()) {
3084 Some(Self { syntax }) 1720 Some(Self { syntax })
@@ -3088,8 +1724,8 @@ impl AstNode for ForType {
3088 } 1724 }
3089 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1725 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3090} 1726}
3091impl AstNode for ImplTraitType { 1727impl AstNode for SelfParam {
3092 fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE } 1728 fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
3093 fn cast(syntax: SyntaxNode) -> Option<Self> { 1729 fn cast(syntax: SyntaxNode) -> Option<Self> {
3094 if Self::can_cast(syntax.kind()) { 1730 if Self::can_cast(syntax.kind()) {
3095 Some(Self { syntax }) 1731 Some(Self { syntax })
@@ -3099,8 +1735,8 @@ impl AstNode for ImplTraitType {
3099 } 1735 }
3100 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1736 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3101} 1737}
3102impl AstNode for DynTraitType { 1738impl AstNode for Param {
3103 fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE } 1739 fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
3104 fn cast(syntax: SyntaxNode) -> Option<Self> { 1740 fn cast(syntax: SyntaxNode) -> Option<Self> {
3105 if Self::can_cast(syntax.kind()) { 1741 if Self::can_cast(syntax.kind()) {
3106 Some(Self { syntax }) 1742 Some(Self { syntax })
@@ -3110,8 +1746,8 @@ impl AstNode for DynTraitType {
3110 } 1746 }
3111 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1747 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3112} 1748}
3113impl AstNode for TupleExpr { 1749impl AstNode for TypeBoundList {
3114 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR } 1750 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
3115 fn cast(syntax: SyntaxNode) -> Option<Self> { 1751 fn cast(syntax: SyntaxNode) -> Option<Self> {
3116 if Self::can_cast(syntax.kind()) { 1752 if Self::can_cast(syntax.kind()) {
3117 Some(Self { syntax }) 1753 Some(Self { syntax })
@@ -3121,8 +1757,8 @@ impl AstNode for TupleExpr {
3121 } 1757 }
3122 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1758 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3123} 1759}
3124impl AstNode for ArrayExpr { 1760impl AstNode for RecordFieldList {
3125 fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR } 1761 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
3126 fn cast(syntax: SyntaxNode) -> Option<Self> { 1762 fn cast(syntax: SyntaxNode) -> Option<Self> {
3127 if Self::can_cast(syntax.kind()) { 1763 if Self::can_cast(syntax.kind()) {
3128 Some(Self { syntax }) 1764 Some(Self { syntax })
@@ -3132,8 +1768,8 @@ impl AstNode for ArrayExpr {
3132 } 1768 }
3133 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1769 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3134} 1770}
3135impl AstNode for ParenExpr { 1771impl AstNode for TupleFieldList {
3136 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR } 1772 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
3137 fn cast(syntax: SyntaxNode) -> Option<Self> { 1773 fn cast(syntax: SyntaxNode) -> Option<Self> {
3138 if Self::can_cast(syntax.kind()) { 1774 if Self::can_cast(syntax.kind()) {
3139 Some(Self { syntax }) 1775 Some(Self { syntax })
@@ -3143,8 +1779,8 @@ impl AstNode for ParenExpr {
3143 } 1779 }
3144 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1780 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3145} 1781}
3146impl AstNode for PathExpr { 1782impl AstNode for RecordField {
3147 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR } 1783 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
3148 fn cast(syntax: SyntaxNode) -> Option<Self> { 1784 fn cast(syntax: SyntaxNode) -> Option<Self> {
3149 if Self::can_cast(syntax.kind()) { 1785 if Self::can_cast(syntax.kind()) {
3150 Some(Self { syntax }) 1786 Some(Self { syntax })
@@ -3154,8 +1790,8 @@ impl AstNode for PathExpr {
3154 } 1790 }
3155 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1791 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3156} 1792}
3157impl AstNode for LambdaExpr { 1793impl AstNode for TupleField {
3158 fn can_cast(kind: SyntaxKind) -> bool { kind == LAMBDA_EXPR } 1794 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
3159 fn cast(syntax: SyntaxNode) -> Option<Self> { 1795 fn cast(syntax: SyntaxNode) -> Option<Self> {
3160 if Self::can_cast(syntax.kind()) { 1796 if Self::can_cast(syntax.kind()) {
3161 Some(Self { syntax }) 1797 Some(Self { syntax })
@@ -3165,8 +1801,8 @@ impl AstNode for LambdaExpr {
3165 } 1801 }
3166 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1802 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3167} 1803}
3168impl AstNode for IfExpr { 1804impl AstNode for VariantList {
3169 fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR } 1805 fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
3170 fn cast(syntax: SyntaxNode) -> Option<Self> { 1806 fn cast(syntax: SyntaxNode) -> Option<Self> {
3171 if Self::can_cast(syntax.kind()) { 1807 if Self::can_cast(syntax.kind()) {
3172 Some(Self { syntax }) 1808 Some(Self { syntax })
@@ -3176,8 +1812,8 @@ impl AstNode for IfExpr {
3176 } 1812 }
3177 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1813 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3178} 1814}
3179impl AstNode for LoopExpr { 1815impl AstNode for Variant {
3180 fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR } 1816 fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
3181 fn cast(syntax: SyntaxNode) -> Option<Self> { 1817 fn cast(syntax: SyntaxNode) -> Option<Self> {
3182 if Self::can_cast(syntax.kind()) { 1818 if Self::can_cast(syntax.kind()) {
3183 Some(Self { syntax }) 1819 Some(Self { syntax })
@@ -3187,8 +1823,8 @@ impl AstNode for LoopExpr {
3187 } 1823 }
3188 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1824 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3189} 1825}
3190impl AstNode for EffectExpr { 1826impl AstNode for AssocItemList {
3191 fn can_cast(kind: SyntaxKind) -> bool { kind == EFFECT_EXPR } 1827 fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
3192 fn cast(syntax: SyntaxNode) -> Option<Self> { 1828 fn cast(syntax: SyntaxNode) -> Option<Self> {
3193 if Self::can_cast(syntax.kind()) { 1829 if Self::can_cast(syntax.kind()) {
3194 Some(Self { syntax }) 1830 Some(Self { syntax })
@@ -3198,8 +1834,8 @@ impl AstNode for EffectExpr {
3198 } 1834 }
3199 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1835 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3200} 1836}
3201impl AstNode for ForExpr { 1837impl AstNode for ExternItemList {
3202 fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR } 1838 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
3203 fn cast(syntax: SyntaxNode) -> Option<Self> { 1839 fn cast(syntax: SyntaxNode) -> Option<Self> {
3204 if Self::can_cast(syntax.kind()) { 1840 if Self::can_cast(syntax.kind()) {
3205 Some(Self { syntax }) 1841 Some(Self { syntax })
@@ -3209,8 +1845,8 @@ impl AstNode for ForExpr {
3209 } 1845 }
3210 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1846 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3211} 1847}
3212impl AstNode for WhileExpr { 1848impl AstNode for LifetimeParam {
3213 fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR } 1849 fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
3214 fn cast(syntax: SyntaxNode) -> Option<Self> { 1850 fn cast(syntax: SyntaxNode) -> Option<Self> {
3215 if Self::can_cast(syntax.kind()) { 1851 if Self::can_cast(syntax.kind()) {
3216 Some(Self { syntax }) 1852 Some(Self { syntax })
@@ -3220,8 +1856,8 @@ impl AstNode for WhileExpr {
3220 } 1856 }
3221 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1857 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3222} 1858}
3223impl AstNode for ContinueExpr { 1859impl AstNode for TypeParam {
3224 fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR } 1860 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
3225 fn cast(syntax: SyntaxNode) -> Option<Self> { 1861 fn cast(syntax: SyntaxNode) -> Option<Self> {
3226 if Self::can_cast(syntax.kind()) { 1862 if Self::can_cast(syntax.kind()) {
3227 Some(Self { syntax }) 1863 Some(Self { syntax })
@@ -3231,8 +1867,8 @@ impl AstNode for ContinueExpr {
3231 } 1867 }
3232 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1868 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3233} 1869}
3234impl AstNode for BreakExpr { 1870impl AstNode for ConstParam {
3235 fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR } 1871 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
3236 fn cast(syntax: SyntaxNode) -> Option<Self> { 1872 fn cast(syntax: SyntaxNode) -> Option<Self> {
3237 if Self::can_cast(syntax.kind()) { 1873 if Self::can_cast(syntax.kind()) {
3238 Some(Self { syntax }) 1874 Some(Self { syntax })
@@ -3242,8 +1878,8 @@ impl AstNode for BreakExpr {
3242 } 1878 }
3243 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1879 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3244} 1880}
3245impl AstNode for Label { 1881impl AstNode for Literal {
3246 fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL } 1882 fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
3247 fn cast(syntax: SyntaxNode) -> Option<Self> { 1883 fn cast(syntax: SyntaxNode) -> Option<Self> {
3248 if Self::can_cast(syntax.kind()) { 1884 if Self::can_cast(syntax.kind()) {
3249 Some(Self { syntax }) 1885 Some(Self { syntax })
@@ -3253,8 +1889,8 @@ impl AstNode for Label {
3253 } 1889 }
3254 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1890 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3255} 1891}
3256impl AstNode for BlockExpr { 1892impl AstNode for TokenTree {
3257 fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR } 1893 fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
3258 fn cast(syntax: SyntaxNode) -> Option<Self> { 1894 fn cast(syntax: SyntaxNode) -> Option<Self> {
3259 if Self::can_cast(syntax.kind()) { 1895 if Self::can_cast(syntax.kind()) {
3260 Some(Self { syntax }) 1896 Some(Self { syntax })
@@ -3264,8 +1900,8 @@ impl AstNode for BlockExpr {
3264 } 1900 }
3265 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1901 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3266} 1902}
3267impl AstNode for ReturnExpr { 1903impl AstNode for ParenType {
3268 fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR } 1904 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
3269 fn cast(syntax: SyntaxNode) -> Option<Self> { 1905 fn cast(syntax: SyntaxNode) -> Option<Self> {
3270 if Self::can_cast(syntax.kind()) { 1906 if Self::can_cast(syntax.kind()) {
3271 Some(Self { syntax }) 1907 Some(Self { syntax })
@@ -3275,8 +1911,8 @@ impl AstNode for ReturnExpr {
3275 } 1911 }
3276 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1912 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3277} 1913}
3278impl AstNode for CallExpr { 1914impl AstNode for TupleType {
3279 fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR } 1915 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
3280 fn cast(syntax: SyntaxNode) -> Option<Self> { 1916 fn cast(syntax: SyntaxNode) -> Option<Self> {
3281 if Self::can_cast(syntax.kind()) { 1917 if Self::can_cast(syntax.kind()) {
3282 Some(Self { syntax }) 1918 Some(Self { syntax })
@@ -3286,8 +1922,8 @@ impl AstNode for CallExpr {
3286 } 1922 }
3287 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1923 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3288} 1924}
3289impl AstNode for MethodCallExpr { 1925impl AstNode for NeverType {
3290 fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR } 1926 fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
3291 fn cast(syntax: SyntaxNode) -> Option<Self> { 1927 fn cast(syntax: SyntaxNode) -> Option<Self> {
3292 if Self::can_cast(syntax.kind()) { 1928 if Self::can_cast(syntax.kind()) {
3293 Some(Self { syntax }) 1929 Some(Self { syntax })
@@ -3297,8 +1933,8 @@ impl AstNode for MethodCallExpr {
3297 } 1933 }
3298 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1934 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3299} 1935}
3300impl AstNode for IndexExpr { 1936impl AstNode for PathType {
3301 fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR } 1937 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
3302 fn cast(syntax: SyntaxNode) -> Option<Self> { 1938 fn cast(syntax: SyntaxNode) -> Option<Self> {
3303 if Self::can_cast(syntax.kind()) { 1939 if Self::can_cast(syntax.kind()) {
3304 Some(Self { syntax }) 1940 Some(Self { syntax })
@@ -3308,8 +1944,8 @@ impl AstNode for IndexExpr {
3308 } 1944 }
3309 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1945 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3310} 1946}
3311impl AstNode for FieldExpr { 1947impl AstNode for PointerType {
3312 fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR } 1948 fn can_cast(kind: SyntaxKind) -> bool { kind == POINTER_TYPE }
3313 fn cast(syntax: SyntaxNode) -> Option<Self> { 1949 fn cast(syntax: SyntaxNode) -> Option<Self> {
3314 if Self::can_cast(syntax.kind()) { 1950 if Self::can_cast(syntax.kind()) {
3315 Some(Self { syntax }) 1951 Some(Self { syntax })
@@ -3319,8 +1955,8 @@ impl AstNode for FieldExpr {
3319 } 1955 }
3320 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1956 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3321} 1957}
3322impl AstNode for AwaitExpr { 1958impl AstNode for ArrayType {
3323 fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR } 1959 fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
3324 fn cast(syntax: SyntaxNode) -> Option<Self> { 1960 fn cast(syntax: SyntaxNode) -> Option<Self> {
3325 if Self::can_cast(syntax.kind()) { 1961 if Self::can_cast(syntax.kind()) {
3326 Some(Self { syntax }) 1962 Some(Self { syntax })
@@ -3330,8 +1966,8 @@ impl AstNode for AwaitExpr {
3330 } 1966 }
3331 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1967 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3332} 1968}
3333impl AstNode for TryExpr { 1969impl AstNode for SliceType {
3334 fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR } 1970 fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
3335 fn cast(syntax: SyntaxNode) -> Option<Self> { 1971 fn cast(syntax: SyntaxNode) -> Option<Self> {
3336 if Self::can_cast(syntax.kind()) { 1972 if Self::can_cast(syntax.kind()) {
3337 Some(Self { syntax }) 1973 Some(Self { syntax })
@@ -3341,8 +1977,8 @@ impl AstNode for TryExpr {
3341 } 1977 }
3342 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1978 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3343} 1979}
3344impl AstNode for CastExpr { 1980impl AstNode for ReferenceType {
3345 fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR } 1981 fn can_cast(kind: SyntaxKind) -> bool { kind == REFERENCE_TYPE }
3346 fn cast(syntax: SyntaxNode) -> Option<Self> { 1982 fn cast(syntax: SyntaxNode) -> Option<Self> {
3347 if Self::can_cast(syntax.kind()) { 1983 if Self::can_cast(syntax.kind()) {
3348 Some(Self { syntax }) 1984 Some(Self { syntax })
@@ -3352,8 +1988,8 @@ impl AstNode for CastExpr {
3352 } 1988 }
3353 fn syntax(&self) -> &SyntaxNode { &self.syntax } 1989 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3354} 1990}
3355impl AstNode for RefExpr { 1991impl AstNode for PlaceholderType {
3356 fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR } 1992 fn can_cast(kind: SyntaxKind) -> bool { kind == PLACEHOLDER_TYPE }
3357 fn cast(syntax: SyntaxNode) -> Option<Self> { 1993 fn cast(syntax: SyntaxNode) -> Option<Self> {
3358 if Self::can_cast(syntax.kind()) { 1994 if Self::can_cast(syntax.kind()) {
3359 Some(Self { syntax }) 1995 Some(Self { syntax })
@@ -3363,8 +1999,8 @@ impl AstNode for RefExpr {
3363 } 1999 }
3364 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2000 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3365} 2001}
3366impl AstNode for PrefixExpr { 2002impl AstNode for FnPointerType {
3367 fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR } 2003 fn can_cast(kind: SyntaxKind) -> bool { kind == FN_POINTER_TYPE }
3368 fn cast(syntax: SyntaxNode) -> Option<Self> { 2004 fn cast(syntax: SyntaxNode) -> Option<Self> {
3369 if Self::can_cast(syntax.kind()) { 2005 if Self::can_cast(syntax.kind()) {
3370 Some(Self { syntax }) 2006 Some(Self { syntax })
@@ -3374,8 +2010,8 @@ impl AstNode for PrefixExpr {
3374 } 2010 }
3375 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2011 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3376} 2012}
3377impl AstNode for BoxExpr { 2013impl AstNode for ForType {
3378 fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_EXPR } 2014 fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
3379 fn cast(syntax: SyntaxNode) -> Option<Self> { 2015 fn cast(syntax: SyntaxNode) -> Option<Self> {
3380 if Self::can_cast(syntax.kind()) { 2016 if Self::can_cast(syntax.kind()) {
3381 Some(Self { syntax }) 2017 Some(Self { syntax })
@@ -3385,8 +2021,8 @@ impl AstNode for BoxExpr {
3385 } 2021 }
3386 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2022 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3387} 2023}
3388impl AstNode for RangeExpr { 2024impl AstNode for ImplTraitType {
3389 fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR } 2025 fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
3390 fn cast(syntax: SyntaxNode) -> Option<Self> { 2026 fn cast(syntax: SyntaxNode) -> Option<Self> {
3391 if Self::can_cast(syntax.kind()) { 2027 if Self::can_cast(syntax.kind()) {
3392 Some(Self { syntax }) 2028 Some(Self { syntax })
@@ -3396,8 +2032,8 @@ impl AstNode for RangeExpr {
3396 } 2032 }
3397 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2033 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3398} 2034}
3399impl AstNode for BinExpr { 2035impl AstNode for DynTraitType {
3400 fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR } 2036 fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
3401 fn cast(syntax: SyntaxNode) -> Option<Self> { 2037 fn cast(syntax: SyntaxNode) -> Option<Self> {
3402 if Self::can_cast(syntax.kind()) { 2038 if Self::can_cast(syntax.kind()) {
3403 Some(Self { syntax }) 2039 Some(Self { syntax })
@@ -3407,8 +2043,8 @@ impl AstNode for BinExpr {
3407 } 2043 }
3408 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2044 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3409} 2045}
3410impl AstNode for Literal { 2046impl AstNode for TupleExpr {
3411 fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL } 2047 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
3412 fn cast(syntax: SyntaxNode) -> Option<Self> { 2048 fn cast(syntax: SyntaxNode) -> Option<Self> {
3413 if Self::can_cast(syntax.kind()) { 2049 if Self::can_cast(syntax.kind()) {
3414 Some(Self { syntax }) 2050 Some(Self { syntax })
@@ -3418,8 +2054,8 @@ impl AstNode for Literal {
3418 } 2054 }
3419 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2055 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3420} 2056}
3421impl AstNode for MatchExpr { 2057impl AstNode for ArrayExpr {
3422 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR } 2058 fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
3423 fn cast(syntax: SyntaxNode) -> Option<Self> { 2059 fn cast(syntax: SyntaxNode) -> Option<Self> {
3424 if Self::can_cast(syntax.kind()) { 2060 if Self::can_cast(syntax.kind()) {
3425 Some(Self { syntax }) 2061 Some(Self { syntax })
@@ -3429,8 +2065,8 @@ impl AstNode for MatchExpr {
3429 } 2065 }
3430 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2066 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3431} 2067}
3432impl AstNode for MatchArmList { 2068impl AstNode for ParenExpr {
3433 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST } 2069 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
3434 fn cast(syntax: SyntaxNode) -> Option<Self> { 2070 fn cast(syntax: SyntaxNode) -> Option<Self> {
3435 if Self::can_cast(syntax.kind()) { 2071 if Self::can_cast(syntax.kind()) {
3436 Some(Self { syntax }) 2072 Some(Self { syntax })
@@ -3440,8 +2076,8 @@ impl AstNode for MatchArmList {
3440 } 2076 }
3441 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2077 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3442} 2078}
3443impl AstNode for MatchArm { 2079impl AstNode for PathExpr {
3444 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM } 2080 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
3445 fn cast(syntax: SyntaxNode) -> Option<Self> { 2081 fn cast(syntax: SyntaxNode) -> Option<Self> {
3446 if Self::can_cast(syntax.kind()) { 2082 if Self::can_cast(syntax.kind()) {
3447 Some(Self { syntax }) 2083 Some(Self { syntax })
@@ -3451,8 +2087,8 @@ impl AstNode for MatchArm {
3451 } 2087 }
3452 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2088 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3453} 2089}
3454impl AstNode for MatchGuard { 2090impl AstNode for LambdaExpr {
3455 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD } 2091 fn can_cast(kind: SyntaxKind) -> bool { kind == LAMBDA_EXPR }
3456 fn cast(syntax: SyntaxNode) -> Option<Self> { 2092 fn cast(syntax: SyntaxNode) -> Option<Self> {
3457 if Self::can_cast(syntax.kind()) { 2093 if Self::can_cast(syntax.kind()) {
3458 Some(Self { syntax }) 2094 Some(Self { syntax })
@@ -3462,8 +2098,8 @@ impl AstNode for MatchGuard {
3462 } 2098 }
3463 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2099 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3464} 2100}
3465impl AstNode for RecordLit { 2101impl AstNode for IfExpr {
3466 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_LIT } 2102 fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
3467 fn cast(syntax: SyntaxNode) -> Option<Self> { 2103 fn cast(syntax: SyntaxNode) -> Option<Self> {
3468 if Self::can_cast(syntax.kind()) { 2104 if Self::can_cast(syntax.kind()) {
3469 Some(Self { syntax }) 2105 Some(Self { syntax })
@@ -3473,8 +2109,8 @@ impl AstNode for RecordLit {
3473 } 2109 }
3474 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2110 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3475} 2111}
3476impl AstNode for RecordFieldList { 2112impl AstNode for Condition {
3477 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST } 2113 fn can_cast(kind: SyntaxKind) -> bool { kind == CONDITION }
3478 fn cast(syntax: SyntaxNode) -> Option<Self> { 2114 fn cast(syntax: SyntaxNode) -> Option<Self> {
3479 if Self::can_cast(syntax.kind()) { 2115 if Self::can_cast(syntax.kind()) {
3480 Some(Self { syntax }) 2116 Some(Self { syntax })
@@ -3484,8 +2120,8 @@ impl AstNode for RecordFieldList {
3484 } 2120 }
3485 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2121 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3486} 2122}
3487impl AstNode for RecordField { 2123impl AstNode for EffectExpr {
3488 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD } 2124 fn can_cast(kind: SyntaxKind) -> bool { kind == EFFECT_EXPR }
3489 fn cast(syntax: SyntaxNode) -> Option<Self> { 2125 fn cast(syntax: SyntaxNode) -> Option<Self> {
3490 if Self::can_cast(syntax.kind()) { 2126 if Self::can_cast(syntax.kind()) {
3491 Some(Self { syntax }) 2127 Some(Self { syntax })
@@ -3495,8 +2131,8 @@ impl AstNode for RecordField {
3495 } 2131 }
3496 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2132 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3497} 2133}
3498impl AstNode for OrPat { 2134impl AstNode for Label {
3499 fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT } 2135 fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
3500 fn cast(syntax: SyntaxNode) -> Option<Self> { 2136 fn cast(syntax: SyntaxNode) -> Option<Self> {
3501 if Self::can_cast(syntax.kind()) { 2137 if Self::can_cast(syntax.kind()) {
3502 Some(Self { syntax }) 2138 Some(Self { syntax })
@@ -3506,8 +2142,8 @@ impl AstNode for OrPat {
3506 } 2142 }
3507 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2143 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3508} 2144}
3509impl AstNode for ParenPat { 2145impl AstNode for LoopExpr {
3510 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT } 2146 fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
3511 fn cast(syntax: SyntaxNode) -> Option<Self> { 2147 fn cast(syntax: SyntaxNode) -> Option<Self> {
3512 if Self::can_cast(syntax.kind()) { 2148 if Self::can_cast(syntax.kind()) {
3513 Some(Self { syntax }) 2149 Some(Self { syntax })
@@ -3517,8 +2153,8 @@ impl AstNode for ParenPat {
3517 } 2153 }
3518 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2154 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3519} 2155}
3520impl AstNode for RefPat { 2156impl AstNode for ForExpr {
3521 fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT } 2157 fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
3522 fn cast(syntax: SyntaxNode) -> Option<Self> { 2158 fn cast(syntax: SyntaxNode) -> Option<Self> {
3523 if Self::can_cast(syntax.kind()) { 2159 if Self::can_cast(syntax.kind()) {
3524 Some(Self { syntax }) 2160 Some(Self { syntax })
@@ -3528,8 +2164,8 @@ impl AstNode for RefPat {
3528 } 2164 }
3529 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2165 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3530} 2166}
3531impl AstNode for BoxPat { 2167impl AstNode for WhileExpr {
3532 fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT } 2168 fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
3533 fn cast(syntax: SyntaxNode) -> Option<Self> { 2169 fn cast(syntax: SyntaxNode) -> Option<Self> {
3534 if Self::can_cast(syntax.kind()) { 2170 if Self::can_cast(syntax.kind()) {
3535 Some(Self { syntax }) 2171 Some(Self { syntax })
@@ -3539,8 +2175,8 @@ impl AstNode for BoxPat {
3539 } 2175 }
3540 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2176 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3541} 2177}
3542impl AstNode for BindPat { 2178impl AstNode for ContinueExpr {
3543 fn can_cast(kind: SyntaxKind) -> bool { kind == BIND_PAT } 2179 fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
3544 fn cast(syntax: SyntaxNode) -> Option<Self> { 2180 fn cast(syntax: SyntaxNode) -> Option<Self> {
3545 if Self::can_cast(syntax.kind()) { 2181 if Self::can_cast(syntax.kind()) {
3546 Some(Self { syntax }) 2182 Some(Self { syntax })
@@ -3550,8 +2186,8 @@ impl AstNode for BindPat {
3550 } 2186 }
3551 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2187 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3552} 2188}
3553impl AstNode for PlaceholderPat { 2189impl AstNode for BreakExpr {
3554 fn can_cast(kind: SyntaxKind) -> bool { kind == PLACEHOLDER_PAT } 2190 fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
3555 fn cast(syntax: SyntaxNode) -> Option<Self> { 2191 fn cast(syntax: SyntaxNode) -> Option<Self> {
3556 if Self::can_cast(syntax.kind()) { 2192 if Self::can_cast(syntax.kind()) {
3557 Some(Self { syntax }) 2193 Some(Self { syntax })
@@ -3561,8 +2197,8 @@ impl AstNode for PlaceholderPat {
3561 } 2197 }
3562 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2198 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3563} 2199}
3564impl AstNode for DotDotPat { 2200impl AstNode for ReturnExpr {
3565 fn can_cast(kind: SyntaxKind) -> bool { kind == DOT_DOT_PAT } 2201 fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
3566 fn cast(syntax: SyntaxNode) -> Option<Self> { 2202 fn cast(syntax: SyntaxNode) -> Option<Self> {
3567 if Self::can_cast(syntax.kind()) { 2203 if Self::can_cast(syntax.kind()) {
3568 Some(Self { syntax }) 2204 Some(Self { syntax })
@@ -3572,8 +2208,8 @@ impl AstNode for DotDotPat {
3572 } 2208 }
3573 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2209 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3574} 2210}
3575impl AstNode for PathPat { 2211impl AstNode for CallExpr {
3576 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT } 2212 fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
3577 fn cast(syntax: SyntaxNode) -> Option<Self> { 2213 fn cast(syntax: SyntaxNode) -> Option<Self> {
3578 if Self::can_cast(syntax.kind()) { 2214 if Self::can_cast(syntax.kind()) {
3579 Some(Self { syntax }) 2215 Some(Self { syntax })
@@ -3583,8 +2219,8 @@ impl AstNode for PathPat {
3583 } 2219 }
3584 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2220 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3585} 2221}
3586impl AstNode for SlicePat { 2222impl AstNode for ArgList {
3587 fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT } 2223 fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
3588 fn cast(syntax: SyntaxNode) -> Option<Self> { 2224 fn cast(syntax: SyntaxNode) -> Option<Self> {
3589 if Self::can_cast(syntax.kind()) { 2225 if Self::can_cast(syntax.kind()) {
3590 Some(Self { syntax }) 2226 Some(Self { syntax })
@@ -3594,8 +2230,8 @@ impl AstNode for SlicePat {
3594 } 2230 }
3595 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2231 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3596} 2232}
3597impl AstNode for RangePat { 2233impl AstNode for MethodCallExpr {
3598 fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT } 2234 fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
3599 fn cast(syntax: SyntaxNode) -> Option<Self> { 2235 fn cast(syntax: SyntaxNode) -> Option<Self> {
3600 if Self::can_cast(syntax.kind()) { 2236 if Self::can_cast(syntax.kind()) {
3601 Some(Self { syntax }) 2237 Some(Self { syntax })
@@ -3605,8 +2241,8 @@ impl AstNode for RangePat {
3605 } 2241 }
3606 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2242 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3607} 2243}
3608impl AstNode for LiteralPat { 2244impl AstNode for TypeArgList {
3609 fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT } 2245 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG_LIST }
3610 fn cast(syntax: SyntaxNode) -> Option<Self> { 2246 fn cast(syntax: SyntaxNode) -> Option<Self> {
3611 if Self::can_cast(syntax.kind()) { 2247 if Self::can_cast(syntax.kind()) {
3612 Some(Self { syntax }) 2248 Some(Self { syntax })
@@ -3616,8 +2252,8 @@ impl AstNode for LiteralPat {
3616 } 2252 }
3617 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2253 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3618} 2254}
3619impl AstNode for MacroPat { 2255impl AstNode for FieldExpr {
3620 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT } 2256 fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
3621 fn cast(syntax: SyntaxNode) -> Option<Self> { 2257 fn cast(syntax: SyntaxNode) -> Option<Self> {
3622 if Self::can_cast(syntax.kind()) { 2258 if Self::can_cast(syntax.kind()) {
3623 Some(Self { syntax }) 2259 Some(Self { syntax })
@@ -3627,8 +2263,8 @@ impl AstNode for MacroPat {
3627 } 2263 }
3628 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2264 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3629} 2265}
3630impl AstNode for RecordPat { 2266impl AstNode for IndexExpr {
3631 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT } 2267 fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
3632 fn cast(syntax: SyntaxNode) -> Option<Self> { 2268 fn cast(syntax: SyntaxNode) -> Option<Self> {
3633 if Self::can_cast(syntax.kind()) { 2269 if Self::can_cast(syntax.kind()) {
3634 Some(Self { syntax }) 2270 Some(Self { syntax })
@@ -3638,8 +2274,8 @@ impl AstNode for RecordPat {
3638 } 2274 }
3639 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2275 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3640} 2276}
3641impl AstNode for RecordFieldPatList { 2277impl AstNode for AwaitExpr {
3642 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_PAT_LIST } 2278 fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
3643 fn cast(syntax: SyntaxNode) -> Option<Self> { 2279 fn cast(syntax: SyntaxNode) -> Option<Self> {
3644 if Self::can_cast(syntax.kind()) { 2280 if Self::can_cast(syntax.kind()) {
3645 Some(Self { syntax }) 2281 Some(Self { syntax })
@@ -3649,8 +2285,8 @@ impl AstNode for RecordFieldPatList {
3649 } 2285 }
3650 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2286 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3651} 2287}
3652impl AstNode for RecordFieldPat { 2288impl AstNode for TryExpr {
3653 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_PAT } 2289 fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
3654 fn cast(syntax: SyntaxNode) -> Option<Self> { 2290 fn cast(syntax: SyntaxNode) -> Option<Self> {
3655 if Self::can_cast(syntax.kind()) { 2291 if Self::can_cast(syntax.kind()) {
3656 Some(Self { syntax }) 2292 Some(Self { syntax })
@@ -3660,8 +2296,8 @@ impl AstNode for RecordFieldPat {
3660 } 2296 }
3661 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2297 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3662} 2298}
3663impl AstNode for TupleStructPat { 2299impl AstNode for CastExpr {
3664 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT } 2300 fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
3665 fn cast(syntax: SyntaxNode) -> Option<Self> { 2301 fn cast(syntax: SyntaxNode) -> Option<Self> {
3666 if Self::can_cast(syntax.kind()) { 2302 if Self::can_cast(syntax.kind()) {
3667 Some(Self { syntax }) 2303 Some(Self { syntax })
@@ -3671,8 +2307,8 @@ impl AstNode for TupleStructPat {
3671 } 2307 }
3672 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2308 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3673} 2309}
3674impl AstNode for TuplePat { 2310impl AstNode for RefExpr {
3675 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT } 2311 fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
3676 fn cast(syntax: SyntaxNode) -> Option<Self> { 2312 fn cast(syntax: SyntaxNode) -> Option<Self> {
3677 if Self::can_cast(syntax.kind()) { 2313 if Self::can_cast(syntax.kind()) {
3678 Some(Self { syntax }) 2314 Some(Self { syntax })
@@ -3682,8 +2318,8 @@ impl AstNode for TuplePat {
3682 } 2318 }
3683 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2319 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3684} 2320}
3685impl AstNode for Visibility { 2321impl AstNode for PrefixExpr {
3686 fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY } 2322 fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
3687 fn cast(syntax: SyntaxNode) -> Option<Self> { 2323 fn cast(syntax: SyntaxNode) -> Option<Self> {
3688 if Self::can_cast(syntax.kind()) { 2324 if Self::can_cast(syntax.kind()) {
3689 Some(Self { syntax }) 2325 Some(Self { syntax })
@@ -3693,8 +2329,8 @@ impl AstNode for Visibility {
3693 } 2329 }
3694 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2330 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3695} 2331}
3696impl AstNode for Name { 2332impl AstNode for BoxExpr {
3697 fn can_cast(kind: SyntaxKind) -> bool { kind == NAME } 2333 fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_EXPR }
3698 fn cast(syntax: SyntaxNode) -> Option<Self> { 2334 fn cast(syntax: SyntaxNode) -> Option<Self> {
3699 if Self::can_cast(syntax.kind()) { 2335 if Self::can_cast(syntax.kind()) {
3700 Some(Self { syntax }) 2336 Some(Self { syntax })
@@ -3704,8 +2340,8 @@ impl AstNode for Name {
3704 } 2340 }
3705 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2341 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3706} 2342}
3707impl AstNode for NameRef { 2343impl AstNode for RangeExpr {
3708 fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF } 2344 fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
3709 fn cast(syntax: SyntaxNode) -> Option<Self> { 2345 fn cast(syntax: SyntaxNode) -> Option<Self> {
3710 if Self::can_cast(syntax.kind()) { 2346 if Self::can_cast(syntax.kind()) {
3711 Some(Self { syntax }) 2347 Some(Self { syntax })
@@ -3715,8 +2351,8 @@ impl AstNode for NameRef {
3715 } 2351 }
3716 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2352 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3717} 2353}
3718impl AstNode for MacroCall { 2354impl AstNode for BinExpr {
3719 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL } 2355 fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
3720 fn cast(syntax: SyntaxNode) -> Option<Self> { 2356 fn cast(syntax: SyntaxNode) -> Option<Self> {
3721 if Self::can_cast(syntax.kind()) { 2357 if Self::can_cast(syntax.kind()) {
3722 Some(Self { syntax }) 2358 Some(Self { syntax })
@@ -3726,8 +2362,8 @@ impl AstNode for MacroCall {
3726 } 2362 }
3727 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2363 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3728} 2364}
3729impl AstNode for Attr { 2365impl AstNode for MatchExpr {
3730 fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR } 2366 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
3731 fn cast(syntax: SyntaxNode) -> Option<Self> { 2367 fn cast(syntax: SyntaxNode) -> Option<Self> {
3732 if Self::can_cast(syntax.kind()) { 2368 if Self::can_cast(syntax.kind()) {
3733 Some(Self { syntax }) 2369 Some(Self { syntax })
@@ -3737,8 +2373,8 @@ impl AstNode for Attr {
3737 } 2373 }
3738 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2374 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3739} 2375}
3740impl AstNode for TokenTree { 2376impl AstNode for MatchArmList {
3741 fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE } 2377 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
3742 fn cast(syntax: SyntaxNode) -> Option<Self> { 2378 fn cast(syntax: SyntaxNode) -> Option<Self> {
3743 if Self::can_cast(syntax.kind()) { 2379 if Self::can_cast(syntax.kind()) {
3744 Some(Self { syntax }) 2380 Some(Self { syntax })
@@ -3748,8 +2384,8 @@ impl AstNode for TokenTree {
3748 } 2384 }
3749 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2385 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3750} 2386}
3751impl AstNode for TypeParamList { 2387impl AstNode for MatchArm {
3752 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM_LIST } 2388 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
3753 fn cast(syntax: SyntaxNode) -> Option<Self> { 2389 fn cast(syntax: SyntaxNode) -> Option<Self> {
3754 if Self::can_cast(syntax.kind()) { 2390 if Self::can_cast(syntax.kind()) {
3755 Some(Self { syntax }) 2391 Some(Self { syntax })
@@ -3759,8 +2395,8 @@ impl AstNode for TypeParamList {
3759 } 2395 }
3760 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2396 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3761} 2397}
3762impl AstNode for TypeParam { 2398impl AstNode for MatchGuard {
3763 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM } 2399 fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
3764 fn cast(syntax: SyntaxNode) -> Option<Self> { 2400 fn cast(syntax: SyntaxNode) -> Option<Self> {
3765 if Self::can_cast(syntax.kind()) { 2401 if Self::can_cast(syntax.kind()) {
3766 Some(Self { syntax }) 2402 Some(Self { syntax })
@@ -3770,8 +2406,8 @@ impl AstNode for TypeParam {
3770 } 2406 }
3771 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2407 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3772} 2408}
3773impl AstNode for ConstParam { 2409impl AstNode for RecordExpr {
3774 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM } 2410 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
3775 fn cast(syntax: SyntaxNode) -> Option<Self> { 2411 fn cast(syntax: SyntaxNode) -> Option<Self> {
3776 if Self::can_cast(syntax.kind()) { 2412 if Self::can_cast(syntax.kind()) {
3777 Some(Self { syntax }) 2413 Some(Self { syntax })
@@ -3781,8 +2417,8 @@ impl AstNode for ConstParam {
3781 } 2417 }
3782 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2418 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3783} 2419}
3784impl AstNode for LifetimeParam { 2420impl AstNode for RecordExprFieldList {
3785 fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM } 2421 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
3786 fn cast(syntax: SyntaxNode) -> Option<Self> { 2422 fn cast(syntax: SyntaxNode) -> Option<Self> {
3787 if Self::can_cast(syntax.kind()) { 2423 if Self::can_cast(syntax.kind()) {
3788 Some(Self { syntax }) 2424 Some(Self { syntax })
@@ -3792,8 +2428,8 @@ impl AstNode for LifetimeParam {
3792 } 2428 }
3793 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2429 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3794} 2430}
3795impl AstNode for TypeBound { 2431impl AstNode for RecordExprField {
3796 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND } 2432 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
3797 fn cast(syntax: SyntaxNode) -> Option<Self> { 2433 fn cast(syntax: SyntaxNode) -> Option<Self> {
3798 if Self::can_cast(syntax.kind()) { 2434 if Self::can_cast(syntax.kind()) {
3799 Some(Self { syntax }) 2435 Some(Self { syntax })
@@ -3803,8 +2439,8 @@ impl AstNode for TypeBound {
3803 } 2439 }
3804 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2440 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3805} 2441}
3806impl AstNode for TypeBoundList { 2442impl AstNode for OrPat {
3807 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST } 2443 fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
3808 fn cast(syntax: SyntaxNode) -> Option<Self> { 2444 fn cast(syntax: SyntaxNode) -> Option<Self> {
3809 if Self::can_cast(syntax.kind()) { 2445 if Self::can_cast(syntax.kind()) {
3810 Some(Self { syntax }) 2446 Some(Self { syntax })
@@ -3814,8 +2450,8 @@ impl AstNode for TypeBoundList {
3814 } 2450 }
3815 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2451 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3816} 2452}
3817impl AstNode for WherePred { 2453impl AstNode for ParenPat {
3818 fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED } 2454 fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
3819 fn cast(syntax: SyntaxNode) -> Option<Self> { 2455 fn cast(syntax: SyntaxNode) -> Option<Self> {
3820 if Self::can_cast(syntax.kind()) { 2456 if Self::can_cast(syntax.kind()) {
3821 Some(Self { syntax }) 2457 Some(Self { syntax })
@@ -3825,8 +2461,8 @@ impl AstNode for WherePred {
3825 } 2461 }
3826 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2462 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3827} 2463}
3828impl AstNode for WhereClause { 2464impl AstNode for RefPat {
3829 fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE } 2465 fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
3830 fn cast(syntax: SyntaxNode) -> Option<Self> { 2466 fn cast(syntax: SyntaxNode) -> Option<Self> {
3831 if Self::can_cast(syntax.kind()) { 2467 if Self::can_cast(syntax.kind()) {
3832 Some(Self { syntax }) 2468 Some(Self { syntax })
@@ -3836,8 +2472,8 @@ impl AstNode for WhereClause {
3836 } 2472 }
3837 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2473 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3838} 2474}
3839impl AstNode for Abi { 2475impl AstNode for BoxPat {
3840 fn can_cast(kind: SyntaxKind) -> bool { kind == ABI } 2476 fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
3841 fn cast(syntax: SyntaxNode) -> Option<Self> { 2477 fn cast(syntax: SyntaxNode) -> Option<Self> {
3842 if Self::can_cast(syntax.kind()) { 2478 if Self::can_cast(syntax.kind()) {
3843 Some(Self { syntax }) 2479 Some(Self { syntax })
@@ -3847,8 +2483,8 @@ impl AstNode for Abi {
3847 } 2483 }
3848 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2484 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3849} 2485}
3850impl AstNode for ExprStmt { 2486impl AstNode for BindPat {
3851 fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT } 2487 fn can_cast(kind: SyntaxKind) -> bool { kind == BIND_PAT }
3852 fn cast(syntax: SyntaxNode) -> Option<Self> { 2488 fn cast(syntax: SyntaxNode) -> Option<Self> {
3853 if Self::can_cast(syntax.kind()) { 2489 if Self::can_cast(syntax.kind()) {
3854 Some(Self { syntax }) 2490 Some(Self { syntax })
@@ -3858,8 +2494,8 @@ impl AstNode for ExprStmt {
3858 } 2494 }
3859 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2495 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3860} 2496}
3861impl AstNode for LetStmt { 2497impl AstNode for PlaceholderPat {
3862 fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT } 2498 fn can_cast(kind: SyntaxKind) -> bool { kind == PLACEHOLDER_PAT }
3863 fn cast(syntax: SyntaxNode) -> Option<Self> { 2499 fn cast(syntax: SyntaxNode) -> Option<Self> {
3864 if Self::can_cast(syntax.kind()) { 2500 if Self::can_cast(syntax.kind()) {
3865 Some(Self { syntax }) 2501 Some(Self { syntax })
@@ -3869,8 +2505,8 @@ impl AstNode for LetStmt {
3869 } 2505 }
3870 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2506 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3871} 2507}
3872impl AstNode for Condition { 2508impl AstNode for DotDotPat {
3873 fn can_cast(kind: SyntaxKind) -> bool { kind == CONDITION } 2509 fn can_cast(kind: SyntaxKind) -> bool { kind == DOT_DOT_PAT }
3874 fn cast(syntax: SyntaxNode) -> Option<Self> { 2510 fn cast(syntax: SyntaxNode) -> Option<Self> {
3875 if Self::can_cast(syntax.kind()) { 2511 if Self::can_cast(syntax.kind()) {
3876 Some(Self { syntax }) 2512 Some(Self { syntax })
@@ -3880,8 +2516,8 @@ impl AstNode for Condition {
3880 } 2516 }
3881 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2517 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3882} 2518}
3883impl AstNode for ParamList { 2519impl AstNode for PathPat {
3884 fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST } 2520 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
3885 fn cast(syntax: SyntaxNode) -> Option<Self> { 2521 fn cast(syntax: SyntaxNode) -> Option<Self> {
3886 if Self::can_cast(syntax.kind()) { 2522 if Self::can_cast(syntax.kind()) {
3887 Some(Self { syntax }) 2523 Some(Self { syntax })
@@ -3891,8 +2527,8 @@ impl AstNode for ParamList {
3891 } 2527 }
3892 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2528 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3893} 2529}
3894impl AstNode for SelfParam { 2530impl AstNode for SlicePat {
3895 fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM } 2531 fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
3896 fn cast(syntax: SyntaxNode) -> Option<Self> { 2532 fn cast(syntax: SyntaxNode) -> Option<Self> {
3897 if Self::can_cast(syntax.kind()) { 2533 if Self::can_cast(syntax.kind()) {
3898 Some(Self { syntax }) 2534 Some(Self { syntax })
@@ -3902,8 +2538,8 @@ impl AstNode for SelfParam {
3902 } 2538 }
3903 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2539 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3904} 2540}
3905impl AstNode for Param { 2541impl AstNode for RangePat {
3906 fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM } 2542 fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
3907 fn cast(syntax: SyntaxNode) -> Option<Self> { 2543 fn cast(syntax: SyntaxNode) -> Option<Self> {
3908 if Self::can_cast(syntax.kind()) { 2544 if Self::can_cast(syntax.kind()) {
3909 Some(Self { syntax }) 2545 Some(Self { syntax })
@@ -3913,8 +2549,8 @@ impl AstNode for Param {
3913 } 2549 }
3914 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2550 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3915} 2551}
3916impl AstNode for UseItem { 2552impl AstNode for LiteralPat {
3917 fn can_cast(kind: SyntaxKind) -> bool { kind == USE_ITEM } 2553 fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
3918 fn cast(syntax: SyntaxNode) -> Option<Self> { 2554 fn cast(syntax: SyntaxNode) -> Option<Self> {
3919 if Self::can_cast(syntax.kind()) { 2555 if Self::can_cast(syntax.kind()) {
3920 Some(Self { syntax }) 2556 Some(Self { syntax })
@@ -3924,8 +2560,8 @@ impl AstNode for UseItem {
3924 } 2560 }
3925 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2561 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3926} 2562}
3927impl AstNode for UseTree { 2563impl AstNode for MacroPat {
3928 fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE } 2564 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
3929 fn cast(syntax: SyntaxNode) -> Option<Self> { 2565 fn cast(syntax: SyntaxNode) -> Option<Self> {
3930 if Self::can_cast(syntax.kind()) { 2566 if Self::can_cast(syntax.kind()) {
3931 Some(Self { syntax }) 2567 Some(Self { syntax })
@@ -3935,8 +2571,8 @@ impl AstNode for UseTree {
3935 } 2571 }
3936 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2572 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3937} 2573}
3938impl AstNode for Alias { 2574impl AstNode for RecordPat {
3939 fn can_cast(kind: SyntaxKind) -> bool { kind == ALIAS } 2575 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
3940 fn cast(syntax: SyntaxNode) -> Option<Self> { 2576 fn cast(syntax: SyntaxNode) -> Option<Self> {
3941 if Self::can_cast(syntax.kind()) { 2577 if Self::can_cast(syntax.kind()) {
3942 Some(Self { syntax }) 2578 Some(Self { syntax })
@@ -3946,8 +2582,8 @@ impl AstNode for Alias {
3946 } 2582 }
3947 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2583 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3948} 2584}
3949impl AstNode for UseTreeList { 2585impl AstNode for RecordFieldPatList {
3950 fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST } 2586 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_PAT_LIST }
3951 fn cast(syntax: SyntaxNode) -> Option<Self> { 2587 fn cast(syntax: SyntaxNode) -> Option<Self> {
3952 if Self::can_cast(syntax.kind()) { 2588 if Self::can_cast(syntax.kind()) {
3953 Some(Self { syntax }) 2589 Some(Self { syntax })
@@ -3957,8 +2593,8 @@ impl AstNode for UseTreeList {
3957 } 2593 }
3958 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2594 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3959} 2595}
3960impl AstNode for ExternCrateItem { 2596impl AstNode for RecordFieldPat {
3961 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE_ITEM } 2597 fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_PAT }
3962 fn cast(syntax: SyntaxNode) -> Option<Self> { 2598 fn cast(syntax: SyntaxNode) -> Option<Self> {
3963 if Self::can_cast(syntax.kind()) { 2599 if Self::can_cast(syntax.kind()) {
3964 Some(Self { syntax }) 2600 Some(Self { syntax })
@@ -3968,8 +2604,8 @@ impl AstNode for ExternCrateItem {
3968 } 2604 }
3969 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2605 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3970} 2606}
3971impl AstNode for ArgList { 2607impl AstNode for TupleStructPat {
3972 fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST } 2608 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
3973 fn cast(syntax: SyntaxNode) -> Option<Self> { 2609 fn cast(syntax: SyntaxNode) -> Option<Self> {
3974 if Self::can_cast(syntax.kind()) { 2610 if Self::can_cast(syntax.kind()) {
3975 Some(Self { syntax }) 2611 Some(Self { syntax })
@@ -3979,8 +2615,8 @@ impl AstNode for ArgList {
3979 } 2615 }
3980 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2616 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3981} 2617}
3982impl AstNode for Path { 2618impl AstNode for TuplePat {
3983 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } 2619 fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
3984 fn cast(syntax: SyntaxNode) -> Option<Self> { 2620 fn cast(syntax: SyntaxNode) -> Option<Self> {
3985 if Self::can_cast(syntax.kind()) { 2621 if Self::can_cast(syntax.kind()) {
3986 Some(Self { syntax }) 2622 Some(Self { syntax })
@@ -3990,8 +2626,8 @@ impl AstNode for Path {
3990 } 2626 }
3991 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2627 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3992} 2628}
3993impl AstNode for PathSegment { 2629impl AstNode for MacroDef {
3994 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT } 2630 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
3995 fn cast(syntax: SyntaxNode) -> Option<Self> { 2631 fn cast(syntax: SyntaxNode) -> Option<Self> {
3996 if Self::can_cast(syntax.kind()) { 2632 if Self::can_cast(syntax.kind()) {
3997 Some(Self { syntax }) 2633 Some(Self { syntax })
@@ -4001,8 +2637,8 @@ impl AstNode for PathSegment {
4001 } 2637 }
4002 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2638 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4003} 2639}
4004impl AstNode for TypeArgList { 2640impl AstNode for MacroItems {
4005 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG_LIST } 2641 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
4006 fn cast(syntax: SyntaxNode) -> Option<Self> { 2642 fn cast(syntax: SyntaxNode) -> Option<Self> {
4007 if Self::can_cast(syntax.kind()) { 2643 if Self::can_cast(syntax.kind()) {
4008 Some(Self { syntax }) 2644 Some(Self { syntax })
@@ -4012,8 +2648,8 @@ impl AstNode for TypeArgList {
4012 } 2648 }
4013 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2649 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4014} 2650}
4015impl AstNode for TypeArg { 2651impl AstNode for MacroStmts {
4016 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG } 2652 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
4017 fn cast(syntax: SyntaxNode) -> Option<Self> { 2653 fn cast(syntax: SyntaxNode) -> Option<Self> {
4018 if Self::can_cast(syntax.kind()) { 2654 if Self::can_cast(syntax.kind()) {
4019 Some(Self { syntax }) 2655 Some(Self { syntax })
@@ -4023,8 +2659,8 @@ impl AstNode for TypeArg {
4023 } 2659 }
4024 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2660 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4025} 2661}
4026impl AstNode for AssocTypeArg { 2662impl AstNode for TypeBound {
4027 fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG } 2663 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
4028 fn cast(syntax: SyntaxNode) -> Option<Self> { 2664 fn cast(syntax: SyntaxNode) -> Option<Self> {
4029 if Self::can_cast(syntax.kind()) { 2665 if Self::can_cast(syntax.kind()) {
4030 Some(Self { syntax }) 2666 Some(Self { syntax })
@@ -4034,8 +2670,8 @@ impl AstNode for AssocTypeArg {
4034 } 2670 }
4035 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2671 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4036} 2672}
4037impl AstNode for LifetimeArg { 2673impl AstNode for WherePred {
4038 fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG } 2674 fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
4039 fn cast(syntax: SyntaxNode) -> Option<Self> { 2675 fn cast(syntax: SyntaxNode) -> Option<Self> {
4040 if Self::can_cast(syntax.kind()) { 2676 if Self::can_cast(syntax.kind()) {
4041 Some(Self { syntax }) 2677 Some(Self { syntax })
@@ -4045,8 +2681,8 @@ impl AstNode for LifetimeArg {
4045 } 2681 }
4046 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2682 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4047} 2683}
4048impl AstNode for ConstArg { 2684impl AstNode for ExprStmt {
4049 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG } 2685 fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
4050 fn cast(syntax: SyntaxNode) -> Option<Self> { 2686 fn cast(syntax: SyntaxNode) -> Option<Self> {
4051 if Self::can_cast(syntax.kind()) { 2687 if Self::can_cast(syntax.kind()) {
4052 Some(Self { syntax }) 2688 Some(Self { syntax })
@@ -4056,8 +2692,8 @@ impl AstNode for ConstArg {
4056 } 2692 }
4057 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2693 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4058} 2694}
4059impl AstNode for MacroItems { 2695impl AstNode for LetStmt {
4060 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS } 2696 fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
4061 fn cast(syntax: SyntaxNode) -> Option<Self> { 2697 fn cast(syntax: SyntaxNode) -> Option<Self> {
4062 if Self::can_cast(syntax.kind()) { 2698 if Self::can_cast(syntax.kind()) {
4063 Some(Self { syntax }) 2699 Some(Self { syntax })
@@ -4067,8 +2703,8 @@ impl AstNode for MacroItems {
4067 } 2703 }
4068 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2704 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4069} 2705}
4070impl AstNode for MacroStmts { 2706impl AstNode for PathSegment {
4071 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS } 2707 fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
4072 fn cast(syntax: SyntaxNode) -> Option<Self> { 2708 fn cast(syntax: SyntaxNode) -> Option<Self> {
4073 if Self::can_cast(syntax.kind()) { 2709 if Self::can_cast(syntax.kind()) {
4074 Some(Self { syntax }) 2710 Some(Self { syntax })
@@ -4078,8 +2714,8 @@ impl AstNode for MacroStmts {
4078 } 2714 }
4079 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2715 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4080} 2716}
4081impl AstNode for ExternItemList { 2717impl AstNode for TypeArg {
4082 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST } 2718 fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
4083 fn cast(syntax: SyntaxNode) -> Option<Self> { 2719 fn cast(syntax: SyntaxNode) -> Option<Self> {
4084 if Self::can_cast(syntax.kind()) { 2720 if Self::can_cast(syntax.kind()) {
4085 Some(Self { syntax }) 2721 Some(Self { syntax })
@@ -4089,8 +2725,8 @@ impl AstNode for ExternItemList {
4089 } 2725 }
4090 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2726 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4091} 2727}
4092impl AstNode for ExternBlock { 2728impl AstNode for LifetimeArg {
4093 fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK } 2729 fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
4094 fn cast(syntax: SyntaxNode) -> Option<Self> { 2730 fn cast(syntax: SyntaxNode) -> Option<Self> {
4095 if Self::can_cast(syntax.kind()) { 2731 if Self::can_cast(syntax.kind()) {
4096 Some(Self { syntax }) 2732 Some(Self { syntax })
@@ -4100,8 +2736,8 @@ impl AstNode for ExternBlock {
4100 } 2736 }
4101 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2737 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4102} 2738}
4103impl AstNode for MetaItem { 2739impl AstNode for AssocTypeArg {
4104 fn can_cast(kind: SyntaxKind) -> bool { kind == META_ITEM } 2740 fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
4105 fn cast(syntax: SyntaxNode) -> Option<Self> { 2741 fn cast(syntax: SyntaxNode) -> Option<Self> {
4106 if Self::can_cast(syntax.kind()) { 2742 if Self::can_cast(syntax.kind()) {
4107 Some(Self { syntax }) 2743 Some(Self { syntax })
@@ -4111,8 +2747,8 @@ impl AstNode for MetaItem {
4111 } 2747 }
4112 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2748 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4113} 2749}
4114impl AstNode for MacroDef { 2750impl AstNode for ConstArg {
4115 fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF } 2751 fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
4116 fn cast(syntax: SyntaxNode) -> Option<Self> { 2752 fn cast(syntax: SyntaxNode) -> Option<Self> {
4117 if Self::can_cast(syntax.kind()) { 2753 if Self::can_cast(syntax.kind()) {
4118 Some(Self { syntax }) 2754 Some(Self { syntax })
@@ -4122,107 +2758,92 @@ impl AstNode for MacroDef {
4122 } 2758 }
4123 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2759 fn syntax(&self) -> &SyntaxNode { &self.syntax }
4124} 2760}
4125impl From<StructDef> for NominalDef { 2761impl From<Const> for Item {
4126 fn from(node: StructDef) -> NominalDef { NominalDef::StructDef(node) } 2762 fn from(node: Const) -> Item { Item::Const(node) }
4127} 2763}
4128impl From<EnumDef> for NominalDef { 2764impl From<Enum> for Item {
4129 fn from(node: EnumDef) -> NominalDef { NominalDef::EnumDef(node) } 2765 fn from(node: Enum) -> Item { Item::Enum(node) }
4130} 2766}
4131impl From<UnionDef> for NominalDef { 2767impl From<ExternBlock> for Item {
4132 fn from(node: UnionDef) -> NominalDef { NominalDef::UnionDef(node) } 2768 fn from(node: ExternBlock) -> Item { Item::ExternBlock(node) }
4133} 2769}
4134impl AstNode for NominalDef { 2770impl From<ExternCrate> for Item {
4135 fn can_cast(kind: SyntaxKind) -> bool { 2771 fn from(node: ExternCrate) -> Item { Item::ExternCrate(node) }
4136 match kind {
4137 STRUCT_DEF | ENUM_DEF | UNION_DEF => true,
4138 _ => false,
4139 }
4140 }
4141 fn cast(syntax: SyntaxNode) -> Option<Self> {
4142 let res = match syntax.kind() {
4143 STRUCT_DEF => NominalDef::StructDef(StructDef { syntax }),
4144 ENUM_DEF => NominalDef::EnumDef(EnumDef { syntax }),
4145 UNION_DEF => NominalDef::UnionDef(UnionDef { syntax }),
4146 _ => return None,
4147 };
4148 Some(res)
4149 }
4150 fn syntax(&self) -> &SyntaxNode {
4151 match self {
4152 NominalDef::StructDef(it) => &it.syntax,
4153 NominalDef::EnumDef(it) => &it.syntax,
4154 NominalDef::UnionDef(it) => &it.syntax,
4155 }
4156 }
4157} 2772}
4158impl From<LifetimeParam> for GenericParam { 2773impl From<Fn> for Item {
4159 fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) } 2774 fn from(node: Fn) -> Item { Item::Fn(node) }
4160} 2775}
4161impl From<TypeParam> for GenericParam { 2776impl From<Impl> for Item {
4162 fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) } 2777 fn from(node: Impl) -> Item { Item::Impl(node) }
4163} 2778}
4164impl From<ConstParam> for GenericParam { 2779impl From<MacroCall> for Item {
4165 fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) } 2780 fn from(node: MacroCall) -> Item { Item::MacroCall(node) }
4166} 2781}
4167impl AstNode for GenericParam { 2782impl From<Module> for Item {
4168 fn can_cast(kind: SyntaxKind) -> bool { 2783 fn from(node: Module) -> Item { Item::Module(node) }
4169 match kind { 2784}
4170 LIFETIME_PARAM | TYPE_PARAM | CONST_PARAM => true, 2785impl From<Static> for Item {
4171 _ => false, 2786 fn from(node: Static) -> Item { Item::Static(node) }
4172 } 2787}
4173 } 2788impl From<Struct> for Item {
4174 fn cast(syntax: SyntaxNode) -> Option<Self> { 2789 fn from(node: Struct) -> Item { Item::Struct(node) }
4175 let res = match syntax.kind() {
4176 LIFETIME_PARAM => GenericParam::LifetimeParam(LifetimeParam { syntax }),
4177 TYPE_PARAM => GenericParam::TypeParam(TypeParam { syntax }),
4178 CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }),
4179 _ => return None,
4180 };
4181 Some(res)
4182 }
4183 fn syntax(&self) -> &SyntaxNode {
4184 match self {
4185 GenericParam::LifetimeParam(it) => &it.syntax,
4186 GenericParam::TypeParam(it) => &it.syntax,
4187 GenericParam::ConstParam(it) => &it.syntax,
4188 }
4189 }
4190} 2790}
4191impl From<LifetimeArg> for GenericArg { 2791impl From<Trait> for Item {
4192 fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) } 2792 fn from(node: Trait) -> Item { Item::Trait(node) }
4193} 2793}
4194impl From<TypeArg> for GenericArg { 2794impl From<TypeAlias> for Item {
4195 fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) } 2795 fn from(node: TypeAlias) -> Item { Item::TypeAlias(node) }
4196} 2796}
4197impl From<ConstArg> for GenericArg { 2797impl From<Union> for Item {
4198 fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) } 2798 fn from(node: Union) -> Item { Item::Union(node) }
4199} 2799}
4200impl From<AssocTypeArg> for GenericArg { 2800impl From<Use> for Item {
4201 fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) } 2801 fn from(node: Use) -> Item { Item::Use(node) }
4202} 2802}
4203impl AstNode for GenericArg { 2803impl AstNode for Item {
4204 fn can_cast(kind: SyntaxKind) -> bool { 2804 fn can_cast(kind: SyntaxKind) -> bool {
4205 match kind { 2805 match kind {
4206 LIFETIME_ARG | TYPE_ARG | CONST_ARG | ASSOC_TYPE_ARG => true, 2806 CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MODULE
2807 | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
4207 _ => false, 2808 _ => false,
4208 } 2809 }
4209 } 2810 }
4210 fn cast(syntax: SyntaxNode) -> Option<Self> { 2811 fn cast(syntax: SyntaxNode) -> Option<Self> {
4211 let res = match syntax.kind() { 2812 let res = match syntax.kind() {
4212 LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }), 2813 CONST => Item::Const(Const { syntax }),
4213 TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }), 2814 ENUM => Item::Enum(Enum { syntax }),
4214 CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }), 2815 EXTERN_BLOCK => Item::ExternBlock(ExternBlock { syntax }),
4215 ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }), 2816 EXTERN_CRATE => Item::ExternCrate(ExternCrate { syntax }),
2817 FN => Item::Fn(Fn { syntax }),
2818 IMPL => Item::Impl(Impl { syntax }),
2819 MACRO_CALL => Item::MacroCall(MacroCall { syntax }),
2820 MODULE => Item::Module(Module { syntax }),
2821 STATIC => Item::Static(Static { syntax }),
2822 STRUCT => Item::Struct(Struct { syntax }),
2823 TRAIT => Item::Trait(Trait { syntax }),
2824 TYPE_ALIAS => Item::TypeAlias(TypeAlias { syntax }),
2825 UNION => Item::Union(Union { syntax }),
2826 USE => Item::Use(Use { syntax }),
4216 _ => return None, 2827 _ => return None,
4217 }; 2828 };
4218 Some(res) 2829 Some(res)
4219 } 2830 }
4220 fn syntax(&self) -> &SyntaxNode { 2831 fn syntax(&self) -> &SyntaxNode {
4221 match self { 2832 match self {
4222 GenericArg::LifetimeArg(it) => &it.syntax, 2833 Item::Const(it) => &it.syntax,
4223 GenericArg::TypeArg(it) => &it.syntax, 2834 Item::Enum(it) => &it.syntax,
4224 GenericArg::ConstArg(it) => &it.syntax, 2835 Item::ExternBlock(it) => &it.syntax,
4225 GenericArg::AssocTypeArg(it) => &it.syntax, 2836 Item::ExternCrate(it) => &it.syntax,
2837 Item::Fn(it) => &it.syntax,
2838 Item::Impl(it) => &it.syntax,
2839 Item::MacroCall(it) => &it.syntax,
2840 Item::Module(it) => &it.syntax,
2841 Item::Static(it) => &it.syntax,
2842 Item::Struct(it) => &it.syntax,
2843 Item::Trait(it) => &it.syntax,
2844 Item::TypeAlias(it) => &it.syntax,
2845 Item::Union(it) => &it.syntax,
2846 Item::Use(it) => &it.syntax,
4226 } 2847 }
4227 } 2848 }
4228} 2849}
@@ -4311,154 +2932,126 @@ impl AstNode for TypeRef {
4311 } 2932 }
4312 } 2933 }
4313} 2934}
4314impl From<StructDef> for ModuleItem { 2935impl From<OrPat> for Pat {
4315 fn from(node: StructDef) -> ModuleItem { ModuleItem::StructDef(node) } 2936 fn from(node: OrPat) -> Pat { Pat::OrPat(node) }
4316}
4317impl From<UnionDef> for ModuleItem {
4318 fn from(node: UnionDef) -> ModuleItem { ModuleItem::UnionDef(node) }
4319}
4320impl From<EnumDef> for ModuleItem {
4321 fn from(node: EnumDef) -> ModuleItem { ModuleItem::EnumDef(node) }
4322}
4323impl From<FnDef> for ModuleItem {
4324 fn from(node: FnDef) -> ModuleItem { ModuleItem::FnDef(node) }
4325} 2937}
4326impl From<TraitDef> for ModuleItem { 2938impl From<ParenPat> for Pat {
4327 fn from(node: TraitDef) -> ModuleItem { ModuleItem::TraitDef(node) } 2939 fn from(node: ParenPat) -> Pat { Pat::ParenPat(node) }
4328} 2940}
4329impl From<TypeAliasDef> for ModuleItem { 2941impl From<RefPat> for Pat {
4330 fn from(node: TypeAliasDef) -> ModuleItem { ModuleItem::TypeAliasDef(node) } 2942 fn from(node: RefPat) -> Pat { Pat::RefPat(node) }
4331} 2943}
4332impl From<ImplDef> for ModuleItem { 2944impl From<BoxPat> for Pat {
4333 fn from(node: ImplDef) -> ModuleItem { ModuleItem::ImplDef(node) } 2945 fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) }
4334} 2946}
4335impl From<UseItem> for ModuleItem { 2947impl From<BindPat> for Pat {
4336 fn from(node: UseItem) -> ModuleItem { ModuleItem::UseItem(node) } 2948 fn from(node: BindPat) -> Pat { Pat::BindPat(node) }
4337} 2949}
4338impl From<ExternCrateItem> for ModuleItem { 2950impl From<PlaceholderPat> for Pat {
4339 fn from(node: ExternCrateItem) -> ModuleItem { ModuleItem::ExternCrateItem(node) } 2951 fn from(node: PlaceholderPat) -> Pat { Pat::PlaceholderPat(node) }
4340} 2952}
4341impl From<ConstDef> for ModuleItem { 2953impl From<DotDotPat> for Pat {
4342 fn from(node: ConstDef) -> ModuleItem { ModuleItem::ConstDef(node) } 2954 fn from(node: DotDotPat) -> Pat { Pat::DotDotPat(node) }
4343} 2955}
4344impl From<StaticDef> for ModuleItem { 2956impl From<PathPat> for Pat {
4345 fn from(node: StaticDef) -> ModuleItem { ModuleItem::StaticDef(node) } 2957 fn from(node: PathPat) -> Pat { Pat::PathPat(node) }
4346} 2958}
4347impl From<Module> for ModuleItem { 2959impl From<RecordPat> for Pat {
4348 fn from(node: Module) -> ModuleItem { ModuleItem::Module(node) } 2960 fn from(node: RecordPat) -> Pat { Pat::RecordPat(node) }
4349} 2961}
4350impl From<MacroCall> for ModuleItem { 2962impl From<TupleStructPat> for Pat {
4351 fn from(node: MacroCall) -> ModuleItem { ModuleItem::MacroCall(node) } 2963 fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) }
4352} 2964}
4353impl From<ExternBlock> for ModuleItem { 2965impl From<TuplePat> for Pat {
4354 fn from(node: ExternBlock) -> ModuleItem { ModuleItem::ExternBlock(node) } 2966 fn from(node: TuplePat) -> Pat { Pat::TuplePat(node) }
4355} 2967}
4356impl AstNode for ModuleItem { 2968impl From<SlicePat> for Pat {
4357 fn can_cast(kind: SyntaxKind) -> bool { 2969 fn from(node: SlicePat) -> Pat { Pat::SlicePat(node) }
4358 match kind {
4359 STRUCT_DEF | UNION_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | TYPE_ALIAS_DEF | IMPL_DEF
4360 | USE_ITEM | EXTERN_CRATE_ITEM | CONST_DEF | STATIC_DEF | MODULE | MACRO_CALL
4361 | EXTERN_BLOCK => true,
4362 _ => false,
4363 }
4364 }
4365 fn cast(syntax: SyntaxNode) -> Option<Self> {
4366 let res = match syntax.kind() {
4367 STRUCT_DEF => ModuleItem::StructDef(StructDef { syntax }),
4368 UNION_DEF => ModuleItem::UnionDef(UnionDef { syntax }),
4369 ENUM_DEF => ModuleItem::EnumDef(EnumDef { syntax }),
4370 FN_DEF => ModuleItem::FnDef(FnDef { syntax }),
4371 TRAIT_DEF => ModuleItem::TraitDef(TraitDef { syntax }),
4372 TYPE_ALIAS_DEF => ModuleItem::TypeAliasDef(TypeAliasDef { syntax }),
4373 IMPL_DEF => ModuleItem::ImplDef(ImplDef { syntax }),
4374 USE_ITEM => ModuleItem::UseItem(UseItem { syntax }),
4375 EXTERN_CRATE_ITEM => ModuleItem::ExternCrateItem(ExternCrateItem { syntax }),
4376 CONST_DEF => ModuleItem::ConstDef(ConstDef { syntax }),
4377 STATIC_DEF => ModuleItem::StaticDef(StaticDef { syntax }),
4378 MODULE => ModuleItem::Module(Module { syntax }),
4379 MACRO_CALL => ModuleItem::MacroCall(MacroCall { syntax }),
4380 EXTERN_BLOCK => ModuleItem::ExternBlock(ExternBlock { syntax }),
4381 _ => return None,
4382 };
4383 Some(res)
4384 }
4385 fn syntax(&self) -> &SyntaxNode {
4386 match self {
4387 ModuleItem::StructDef(it) => &it.syntax,
4388 ModuleItem::UnionDef(it) => &it.syntax,
4389 ModuleItem::EnumDef(it) => &it.syntax,
4390 ModuleItem::FnDef(it) => &it.syntax,
4391 ModuleItem::TraitDef(it) => &it.syntax,
4392 ModuleItem::TypeAliasDef(it) => &it.syntax,
4393 ModuleItem::ImplDef(it) => &it.syntax,
4394 ModuleItem::UseItem(it) => &it.syntax,
4395 ModuleItem::ExternCrateItem(it) => &it.syntax,
4396 ModuleItem::ConstDef(it) => &it.syntax,
4397 ModuleItem::StaticDef(it) => &it.syntax,
4398 ModuleItem::Module(it) => &it.syntax,
4399 ModuleItem::MacroCall(it) => &it.syntax,
4400 ModuleItem::ExternBlock(it) => &it.syntax,
4401 }
4402 }
4403} 2970}
4404impl From<FnDef> for AssocItem { 2971impl From<RangePat> for Pat {
4405 fn from(node: FnDef) -> AssocItem { AssocItem::FnDef(node) } 2972 fn from(node: RangePat) -> Pat { Pat::RangePat(node) }
4406} 2973}
4407impl From<TypeAliasDef> for AssocItem { 2974impl From<LiteralPat> for Pat {
4408 fn from(node: TypeAliasDef) -> AssocItem { AssocItem::TypeAliasDef(node) } 2975 fn from(node: LiteralPat) -> Pat { Pat::LiteralPat(node) }
4409} 2976}
4410impl From<ConstDef> for AssocItem { 2977impl From<MacroPat> for Pat {
4411 fn from(node: ConstDef) -> AssocItem { AssocItem::ConstDef(node) } 2978 fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) }
4412} 2979}
4413impl AstNode for AssocItem { 2980impl AstNode for Pat {
4414 fn can_cast(kind: SyntaxKind) -> bool { 2981 fn can_cast(kind: SyntaxKind) -> bool {
4415 match kind { 2982 match kind {
4416 FN_DEF | TYPE_ALIAS_DEF | CONST_DEF => true, 2983 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT
2984 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
2985 | LITERAL_PAT | MACRO_PAT => true,
4417 _ => false, 2986 _ => false,
4418 } 2987 }
4419 } 2988 }
4420 fn cast(syntax: SyntaxNode) -> Option<Self> { 2989 fn cast(syntax: SyntaxNode) -> Option<Self> {
4421 let res = match syntax.kind() { 2990 let res = match syntax.kind() {
4422 FN_DEF => AssocItem::FnDef(FnDef { syntax }), 2991 OR_PAT => Pat::OrPat(OrPat { syntax }),
4423 TYPE_ALIAS_DEF => AssocItem::TypeAliasDef(TypeAliasDef { syntax }), 2992 PAREN_PAT => Pat::ParenPat(ParenPat { syntax }),
4424 CONST_DEF => AssocItem::ConstDef(ConstDef { syntax }), 2993 REF_PAT => Pat::RefPat(RefPat { syntax }),
2994 BOX_PAT => Pat::BoxPat(BoxPat { syntax }),
2995 BIND_PAT => Pat::BindPat(BindPat { syntax }),
2996 PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }),
2997 DOT_DOT_PAT => Pat::DotDotPat(DotDotPat { syntax }),
2998 PATH_PAT => Pat::PathPat(PathPat { syntax }),
2999 RECORD_PAT => Pat::RecordPat(RecordPat { syntax }),
3000 TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }),
3001 TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }),
3002 SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
3003 RANGE_PAT => Pat::RangePat(RangePat { syntax }),
3004 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
3005 MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
4425 _ => return None, 3006 _ => return None,
4426 }; 3007 };
4427 Some(res) 3008 Some(res)
4428 } 3009 }
4429 fn syntax(&self) -> &SyntaxNode { 3010 fn syntax(&self) -> &SyntaxNode {
4430 match self { 3011 match self {
4431 AssocItem::FnDef(it) => &it.syntax, 3012 Pat::OrPat(it) => &it.syntax,
4432 AssocItem::TypeAliasDef(it) => &it.syntax, 3013 Pat::ParenPat(it) => &it.syntax,
4433 AssocItem::ConstDef(it) => &it.syntax, 3014 Pat::RefPat(it) => &it.syntax,
3015 Pat::BoxPat(it) => &it.syntax,
3016 Pat::BindPat(it) => &it.syntax,
3017 Pat::PlaceholderPat(it) => &it.syntax,
3018 Pat::DotDotPat(it) => &it.syntax,
3019 Pat::PathPat(it) => &it.syntax,
3020 Pat::RecordPat(it) => &it.syntax,
3021 Pat::TupleStructPat(it) => &it.syntax,
3022 Pat::TuplePat(it) => &it.syntax,
3023 Pat::SlicePat(it) => &it.syntax,
3024 Pat::RangePat(it) => &it.syntax,
3025 Pat::LiteralPat(it) => &it.syntax,
3026 Pat::MacroPat(it) => &it.syntax,
4434 } 3027 }
4435 } 3028 }
4436} 3029}
4437impl From<FnDef> for ExternItem { 3030impl From<RecordFieldList> for FieldList {
4438 fn from(node: FnDef) -> ExternItem { ExternItem::FnDef(node) } 3031 fn from(node: RecordFieldList) -> FieldList { FieldList::RecordFieldList(node) }
4439} 3032}
4440impl From<StaticDef> for ExternItem { 3033impl From<TupleFieldList> for FieldList {
4441 fn from(node: StaticDef) -> ExternItem { ExternItem::StaticDef(node) } 3034 fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
4442} 3035}
4443impl AstNode for ExternItem { 3036impl AstNode for FieldList {
4444 fn can_cast(kind: SyntaxKind) -> bool { 3037 fn can_cast(kind: SyntaxKind) -> bool {
4445 match kind { 3038 match kind {
4446 FN_DEF | STATIC_DEF => true, 3039 RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true,
4447 _ => false, 3040 _ => false,
4448 } 3041 }
4449 } 3042 }
4450 fn cast(syntax: SyntaxNode) -> Option<Self> { 3043 fn cast(syntax: SyntaxNode) -> Option<Self> {
4451 let res = match syntax.kind() { 3044 let res = match syntax.kind() {
4452 FN_DEF => ExternItem::FnDef(FnDef { syntax }), 3045 RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
4453 STATIC_DEF => ExternItem::StaticDef(StaticDef { syntax }), 3046 TUPLE_FIELD_LIST => FieldList::TupleFieldList(TupleFieldList { syntax }),
4454 _ => return None, 3047 _ => return None,
4455 }; 3048 };
4456 Some(res) 3049 Some(res)
4457 } 3050 }
4458 fn syntax(&self) -> &SyntaxNode { 3051 fn syntax(&self) -> &SyntaxNode {
4459 match self { 3052 match self {
4460 ExternItem::FnDef(it) => &it.syntax, 3053 FieldList::RecordFieldList(it) => &it.syntax,
4461 ExternItem::StaticDef(it) => &it.syntax, 3054 FieldList::TupleFieldList(it) => &it.syntax,
4462 } 3055 }
4463 } 3056 }
4464} 3057}
@@ -4507,8 +3100,8 @@ impl From<ReturnExpr> for Expr {
4507impl From<MatchExpr> for Expr { 3100impl From<MatchExpr> for Expr {
4508 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } 3101 fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
4509} 3102}
4510impl From<RecordLit> for Expr { 3103impl From<RecordExpr> for Expr {
4511 fn from(node: RecordLit) -> Expr { Expr::RecordLit(node) } 3104 fn from(node: RecordExpr) -> Expr { Expr::RecordExpr(node) }
4512} 3105}
4513impl From<CallExpr> for Expr { 3106impl From<CallExpr> for Expr {
4514 fn from(node: CallExpr) -> Expr { Expr::CallExpr(node) } 3107 fn from(node: CallExpr) -> Expr { Expr::CallExpr(node) }
@@ -4560,7 +3153,7 @@ impl AstNode for Expr {
4560 match kind { 3153 match kind {
4561 TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR 3154 TUPLE_EXPR | ARRAY_EXPR | PAREN_EXPR | PATH_EXPR | LAMBDA_EXPR | IF_EXPR
4562 | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL 3155 | LOOP_EXPR | FOR_EXPR | WHILE_EXPR | CONTINUE_EXPR | BREAK_EXPR | LABEL
4563 | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_LIT | CALL_EXPR | INDEX_EXPR 3156 | BLOCK_EXPR | RETURN_EXPR | MATCH_EXPR | RECORD_EXPR | CALL_EXPR | INDEX_EXPR
4564 | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | EFFECT_EXPR | CAST_EXPR 3157 | METHOD_CALL_EXPR | FIELD_EXPR | AWAIT_EXPR | TRY_EXPR | EFFECT_EXPR | CAST_EXPR
4565 | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | BOX_EXPR => { 3158 | REF_EXPR | PREFIX_EXPR | RANGE_EXPR | BIN_EXPR | LITERAL | MACRO_CALL | BOX_EXPR => {
4566 true 3159 true
@@ -4585,7 +3178,7 @@ impl AstNode for Expr {
4585 BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }), 3178 BLOCK_EXPR => Expr::BlockExpr(BlockExpr { syntax }),
4586 RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }), 3179 RETURN_EXPR => Expr::ReturnExpr(ReturnExpr { syntax }),
4587 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), 3180 MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
4588 RECORD_LIT => Expr::RecordLit(RecordLit { syntax }), 3181 RECORD_EXPR => Expr::RecordExpr(RecordExpr { syntax }),
4589 CALL_EXPR => Expr::CallExpr(CallExpr { syntax }), 3182 CALL_EXPR => Expr::CallExpr(CallExpr { syntax }),
4590 INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }), 3183 INDEX_EXPR => Expr::IndexExpr(IndexExpr { syntax }),
4591 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), 3184 METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
@@ -4622,7 +3215,7 @@ impl AstNode for Expr {
4622 Expr::BlockExpr(it) => &it.syntax, 3215 Expr::BlockExpr(it) => &it.syntax,
4623 Expr::ReturnExpr(it) => &it.syntax, 3216 Expr::ReturnExpr(it) => &it.syntax,
4624 Expr::MatchExpr(it) => &it.syntax, 3217 Expr::MatchExpr(it) => &it.syntax,
4625 Expr::RecordLit(it) => &it.syntax, 3218 Expr::RecordExpr(it) => &it.syntax,
4626 Expr::CallExpr(it) => &it.syntax, 3219 Expr::CallExpr(it) => &it.syntax,
4627 Expr::IndexExpr(it) => &it.syntax, 3220 Expr::IndexExpr(it) => &it.syntax,
4628 Expr::MethodCallExpr(it) => &it.syntax, 3221 Expr::MethodCallExpr(it) => &it.syntax,
@@ -4641,154 +3234,107 @@ impl AstNode for Expr {
4641 } 3234 }
4642 } 3235 }
4643} 3236}
4644impl From<OrPat> for Pat { 3237impl From<Fn> for AssocItem {
4645 fn from(node: OrPat) -> Pat { Pat::OrPat(node) } 3238 fn from(node: Fn) -> AssocItem { AssocItem::Fn(node) }
4646}
4647impl From<ParenPat> for Pat {
4648 fn from(node: ParenPat) -> Pat { Pat::ParenPat(node) }
4649}
4650impl From<RefPat> for Pat {
4651 fn from(node: RefPat) -> Pat { Pat::RefPat(node) }
4652}
4653impl From<BoxPat> for Pat {
4654 fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) }
4655}
4656impl From<BindPat> for Pat {
4657 fn from(node: BindPat) -> Pat { Pat::BindPat(node) }
4658}
4659impl From<PlaceholderPat> for Pat {
4660 fn from(node: PlaceholderPat) -> Pat { Pat::PlaceholderPat(node) }
4661}
4662impl From<DotDotPat> for Pat {
4663 fn from(node: DotDotPat) -> Pat { Pat::DotDotPat(node) }
4664}
4665impl From<PathPat> for Pat {
4666 fn from(node: PathPat) -> Pat { Pat::PathPat(node) }
4667}
4668impl From<RecordPat> for Pat {
4669 fn from(node: RecordPat) -> Pat { Pat::RecordPat(node) }
4670}
4671impl From<TupleStructPat> for Pat {
4672 fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) }
4673}
4674impl From<TuplePat> for Pat {
4675 fn from(node: TuplePat) -> Pat { Pat::TuplePat(node) }
4676}
4677impl From<SlicePat> for Pat {
4678 fn from(node: SlicePat) -> Pat { Pat::SlicePat(node) }
4679} 3239}
4680impl From<RangePat> for Pat { 3240impl From<TypeAlias> for AssocItem {
4681 fn from(node: RangePat) -> Pat { Pat::RangePat(node) } 3241 fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
4682} 3242}
4683impl From<LiteralPat> for Pat { 3243impl From<Const> for AssocItem {
4684 fn from(node: LiteralPat) -> Pat { Pat::LiteralPat(node) } 3244 fn from(node: Const) -> AssocItem { AssocItem::Const(node) }
4685} 3245}
4686impl From<MacroPat> for Pat { 3246impl From<MacroCall> for AssocItem {
4687 fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } 3247 fn from(node: MacroCall) -> AssocItem { AssocItem::MacroCall(node) }
4688} 3248}
4689impl AstNode for Pat { 3249impl AstNode for AssocItem {
4690 fn can_cast(kind: SyntaxKind) -> bool { 3250 fn can_cast(kind: SyntaxKind) -> bool {
4691 match kind { 3251 match kind {
4692 OR_PAT | PAREN_PAT | REF_PAT | BOX_PAT | BIND_PAT | PLACEHOLDER_PAT | DOT_DOT_PAT 3252 FN | TYPE_ALIAS | CONST | MACRO_CALL => true,
4693 | PATH_PAT | RECORD_PAT | TUPLE_STRUCT_PAT | TUPLE_PAT | SLICE_PAT | RANGE_PAT
4694 | LITERAL_PAT | MACRO_PAT => true,
4695 _ => false, 3253 _ => false,
4696 } 3254 }
4697 } 3255 }
4698 fn cast(syntax: SyntaxNode) -> Option<Self> { 3256 fn cast(syntax: SyntaxNode) -> Option<Self> {
4699 let res = match syntax.kind() { 3257 let res = match syntax.kind() {
4700 OR_PAT => Pat::OrPat(OrPat { syntax }), 3258 FN => AssocItem::Fn(Fn { syntax }),
4701 PAREN_PAT => Pat::ParenPat(ParenPat { syntax }), 3259 TYPE_ALIAS => AssocItem::TypeAlias(TypeAlias { syntax }),
4702 REF_PAT => Pat::RefPat(RefPat { syntax }), 3260 CONST => AssocItem::Const(Const { syntax }),
4703 BOX_PAT => Pat::BoxPat(BoxPat { syntax }), 3261 MACRO_CALL => AssocItem::MacroCall(MacroCall { syntax }),
4704 BIND_PAT => Pat::BindPat(BindPat { syntax }),
4705 PLACEHOLDER_PAT => Pat::PlaceholderPat(PlaceholderPat { syntax }),
4706 DOT_DOT_PAT => Pat::DotDotPat(DotDotPat { syntax }),
4707 PATH_PAT => Pat::PathPat(PathPat { syntax }),
4708 RECORD_PAT => Pat::RecordPat(RecordPat { syntax }),
4709 TUPLE_STRUCT_PAT => Pat::TupleStructPat(TupleStructPat { syntax }),
4710 TUPLE_PAT => Pat::TuplePat(TuplePat { syntax }),
4711 SLICE_PAT => Pat::SlicePat(SlicePat { syntax }),
4712 RANGE_PAT => Pat::RangePat(RangePat { syntax }),
4713 LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }),
4714 MACRO_PAT => Pat::MacroPat(MacroPat { syntax }),
4715 _ => return None, 3262 _ => return None,
4716 }; 3263 };
4717 Some(res) 3264 Some(res)
4718 } 3265 }
4719 fn syntax(&self) -> &SyntaxNode { 3266 fn syntax(&self) -> &SyntaxNode {
4720 match self { 3267 match self {
4721 Pat::OrPat(it) => &it.syntax, 3268 AssocItem::Fn(it) => &it.syntax,
4722 Pat::ParenPat(it) => &it.syntax, 3269 AssocItem::TypeAlias(it) => &it.syntax,
4723 Pat::RefPat(it) => &it.syntax, 3270 AssocItem::Const(it) => &it.syntax,
4724 Pat::BoxPat(it) => &it.syntax, 3271 AssocItem::MacroCall(it) => &it.syntax,
4725 Pat::BindPat(it) => &it.syntax,
4726 Pat::PlaceholderPat(it) => &it.syntax,
4727 Pat::DotDotPat(it) => &it.syntax,
4728 Pat::PathPat(it) => &it.syntax,
4729 Pat::RecordPat(it) => &it.syntax,
4730 Pat::TupleStructPat(it) => &it.syntax,
4731 Pat::TuplePat(it) => &it.syntax,
4732 Pat::SlicePat(it) => &it.syntax,
4733 Pat::RangePat(it) => &it.syntax,
4734 Pat::LiteralPat(it) => &it.syntax,
4735 Pat::MacroPat(it) => &it.syntax,
4736 } 3272 }
4737 } 3273 }
4738} 3274}
4739impl From<RecordFieldPat> for RecordInnerPat { 3275impl From<Fn> for ExternItem {
4740 fn from(node: RecordFieldPat) -> RecordInnerPat { RecordInnerPat::RecordFieldPat(node) } 3276 fn from(node: Fn) -> ExternItem { ExternItem::Fn(node) }
4741} 3277}
4742impl From<BindPat> for RecordInnerPat { 3278impl From<Static> for ExternItem {
4743 fn from(node: BindPat) -> RecordInnerPat { RecordInnerPat::BindPat(node) } 3279 fn from(node: Static) -> ExternItem { ExternItem::Static(node) }
4744} 3280}
4745impl AstNode for RecordInnerPat { 3281impl From<MacroCall> for ExternItem {
3282 fn from(node: MacroCall) -> ExternItem { ExternItem::MacroCall(node) }
3283}
3284impl AstNode for ExternItem {
4746 fn can_cast(kind: SyntaxKind) -> bool { 3285 fn can_cast(kind: SyntaxKind) -> bool {
4747 match kind { 3286 match kind {
4748 RECORD_FIELD_PAT | BIND_PAT => true, 3287 FN | STATIC | MACRO_CALL => true,
4749 _ => false, 3288 _ => false,
4750 } 3289 }
4751 } 3290 }
4752 fn cast(syntax: SyntaxNode) -> Option<Self> { 3291 fn cast(syntax: SyntaxNode) -> Option<Self> {
4753 let res = match syntax.kind() { 3292 let res = match syntax.kind() {
4754 RECORD_FIELD_PAT => RecordInnerPat::RecordFieldPat(RecordFieldPat { syntax }), 3293 FN => ExternItem::Fn(Fn { syntax }),
4755 BIND_PAT => RecordInnerPat::BindPat(BindPat { syntax }), 3294 STATIC => ExternItem::Static(Static { syntax }),
3295 MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }),
4756 _ => return None, 3296 _ => return None,
4757 }; 3297 };
4758 Some(res) 3298 Some(res)
4759 } 3299 }
4760 fn syntax(&self) -> &SyntaxNode { 3300 fn syntax(&self) -> &SyntaxNode {
4761 match self { 3301 match self {
4762 RecordInnerPat::RecordFieldPat(it) => &it.syntax, 3302 ExternItem::Fn(it) => &it.syntax,
4763 RecordInnerPat::BindPat(it) => &it.syntax, 3303 ExternItem::Static(it) => &it.syntax,
3304 ExternItem::MacroCall(it) => &it.syntax,
4764 } 3305 }
4765 } 3306 }
4766} 3307}
4767impl From<Literal> for AttrInput { 3308impl From<LifetimeParam> for GenericParam {
4768 fn from(node: Literal) -> AttrInput { AttrInput::Literal(node) } 3309 fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) }
3310}
3311impl From<TypeParam> for GenericParam {
3312 fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) }
4769} 3313}
4770impl From<TokenTree> for AttrInput { 3314impl From<ConstParam> for GenericParam {
4771 fn from(node: TokenTree) -> AttrInput { AttrInput::TokenTree(node) } 3315 fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) }
4772} 3316}
4773impl AstNode for AttrInput { 3317impl AstNode for GenericParam {
4774 fn can_cast(kind: SyntaxKind) -> bool { 3318 fn can_cast(kind: SyntaxKind) -> bool {
4775 match kind { 3319 match kind {
4776 LITERAL | TOKEN_TREE => true, 3320 LIFETIME_PARAM | TYPE_PARAM | CONST_PARAM => true,
4777 _ => false, 3321 _ => false,
4778 } 3322 }
4779 } 3323 }
4780 fn cast(syntax: SyntaxNode) -> Option<Self> { 3324 fn cast(syntax: SyntaxNode) -> Option<Self> {
4781 let res = match syntax.kind() { 3325 let res = match syntax.kind() {
4782 LITERAL => AttrInput::Literal(Literal { syntax }), 3326 LIFETIME_PARAM => GenericParam::LifetimeParam(LifetimeParam { syntax }),
4783 TOKEN_TREE => AttrInput::TokenTree(TokenTree { syntax }), 3327 TYPE_PARAM => GenericParam::TypeParam(TypeParam { syntax }),
3328 CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }),
4784 _ => return None, 3329 _ => return None,
4785 }; 3330 };
4786 Some(res) 3331 Some(res)
4787 } 3332 }
4788 fn syntax(&self) -> &SyntaxNode { 3333 fn syntax(&self) -> &SyntaxNode {
4789 match self { 3334 match self {
4790 AttrInput::Literal(it) => &it.syntax, 3335 GenericParam::LifetimeParam(it) => &it.syntax,
4791 AttrInput::TokenTree(it) => &it.syntax, 3336 GenericParam::TypeParam(it) => &it.syntax,
3337 GenericParam::ConstParam(it) => &it.syntax,
4792 } 3338 }
4793 } 3339 }
4794} 3340}
@@ -4820,47 +3366,40 @@ impl AstNode for Stmt {
4820 } 3366 }
4821 } 3367 }
4822} 3368}
4823impl From<RecordFieldDefList> for FieldDefList { 3369impl From<Struct> for AdtDef {
4824 fn from(node: RecordFieldDefList) -> FieldDefList { FieldDefList::RecordFieldDefList(node) } 3370 fn from(node: Struct) -> AdtDef { AdtDef::Struct(node) }
3371}
3372impl From<Enum> for AdtDef {
3373 fn from(node: Enum) -> AdtDef { AdtDef::Enum(node) }
4825} 3374}
4826impl From<TupleFieldDefList> for FieldDefList { 3375impl From<Union> for AdtDef {
4827 fn from(node: TupleFieldDefList) -> FieldDefList { FieldDefList::TupleFieldDefList(node) } 3376 fn from(node: Union) -> AdtDef { AdtDef::Union(node) }
4828} 3377}
4829impl AstNode for FieldDefList { 3378impl AstNode for AdtDef {
4830 fn can_cast(kind: SyntaxKind) -> bool { 3379 fn can_cast(kind: SyntaxKind) -> bool {
4831 match kind { 3380 match kind {
4832 RECORD_FIELD_DEF_LIST | TUPLE_FIELD_DEF_LIST => true, 3381 STRUCT | ENUM | UNION => true,
4833 _ => false, 3382 _ => false,
4834 } 3383 }
4835 } 3384 }
4836 fn cast(syntax: SyntaxNode) -> Option<Self> { 3385 fn cast(syntax: SyntaxNode) -> Option<Self> {
4837 let res = match syntax.kind() { 3386 let res = match syntax.kind() {
4838 RECORD_FIELD_DEF_LIST => { 3387 STRUCT => AdtDef::Struct(Struct { syntax }),
4839 FieldDefList::RecordFieldDefList(RecordFieldDefList { syntax }) 3388 ENUM => AdtDef::Enum(Enum { syntax }),
4840 } 3389 UNION => AdtDef::Union(Union { syntax }),
4841 TUPLE_FIELD_DEF_LIST => FieldDefList::TupleFieldDefList(TupleFieldDefList { syntax }),
4842 _ => return None, 3390 _ => return None,
4843 }; 3391 };
4844 Some(res) 3392 Some(res)
4845 } 3393 }
4846 fn syntax(&self) -> &SyntaxNode { 3394 fn syntax(&self) -> &SyntaxNode {
4847 match self { 3395 match self {
4848 FieldDefList::RecordFieldDefList(it) => &it.syntax, 3396 AdtDef::Struct(it) => &it.syntax,
4849 FieldDefList::TupleFieldDefList(it) => &it.syntax, 3397 AdtDef::Enum(it) => &it.syntax,
3398 AdtDef::Union(it) => &it.syntax,
4850 } 3399 }
4851 } 3400 }
4852} 3401}
4853impl std::fmt::Display for NominalDef { 3402impl std::fmt::Display for Item {
4854 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4855 std::fmt::Display::fmt(self.syntax(), f)
4856 }
4857}
4858impl std::fmt::Display for GenericParam {
4859 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4860 std::fmt::Display::fmt(self.syntax(), f)
4861 }
4862}
4863impl std::fmt::Display for GenericArg {
4864 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4865 std::fmt::Display::fmt(self.syntax(), f) 3404 std::fmt::Display::fmt(self.syntax(), f)
4866 } 3405 }
@@ -4870,17 +3409,12 @@ impl std::fmt::Display for TypeRef {
4870 std::fmt::Display::fmt(self.syntax(), f) 3409 std::fmt::Display::fmt(self.syntax(), f)
4871 } 3410 }
4872} 3411}
4873impl std::fmt::Display for ModuleItem { 3412impl std::fmt::Display for Pat {
4874 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4875 std::fmt::Display::fmt(self.syntax(), f)
4876 }
4877}
4878impl std::fmt::Display for AssocItem {
4879 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3413 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4880 std::fmt::Display::fmt(self.syntax(), f) 3414 std::fmt::Display::fmt(self.syntax(), f)
4881 } 3415 }
4882} 3416}
4883impl std::fmt::Display for ExternItem { 3417impl std::fmt::Display for FieldList {
4884 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3418 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4885 std::fmt::Display::fmt(self.syntax(), f) 3419 std::fmt::Display::fmt(self.syntax(), f)
4886 } 3420 }
@@ -4890,17 +3424,17 @@ impl std::fmt::Display for Expr {
4890 std::fmt::Display::fmt(self.syntax(), f) 3424 std::fmt::Display::fmt(self.syntax(), f)
4891 } 3425 }
4892} 3426}
4893impl std::fmt::Display for Pat { 3427impl std::fmt::Display for AssocItem {
4894 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3428 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4895 std::fmt::Display::fmt(self.syntax(), f) 3429 std::fmt::Display::fmt(self.syntax(), f)
4896 } 3430 }
4897} 3431}
4898impl std::fmt::Display for RecordInnerPat { 3432impl std::fmt::Display for ExternItem {
4899 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4900 std::fmt::Display::fmt(self.syntax(), f) 3434 std::fmt::Display::fmt(self.syntax(), f)
4901 } 3435 }
4902} 3436}
4903impl std::fmt::Display for AttrInput { 3437impl std::fmt::Display for GenericParam {
4904 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3438 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4905 std::fmt::Display::fmt(self.syntax(), f) 3439 std::fmt::Display::fmt(self.syntax(), f)
4906 } 3440 }
@@ -4910,7 +3444,7 @@ impl std::fmt::Display for Stmt {
4910 std::fmt::Display::fmt(self.syntax(), f) 3444 std::fmt::Display::fmt(self.syntax(), f)
4911 } 3445 }
4912} 3446}
4913impl std::fmt::Display for FieldDefList { 3447impl std::fmt::Display for AdtDef {
4914 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3448 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4915 std::fmt::Display::fmt(self.syntax(), f) 3449 std::fmt::Display::fmt(self.syntax(), f)
4916 } 3450 }
@@ -4920,617 +3454,617 @@ impl std::fmt::Display for SourceFile {
4920 std::fmt::Display::fmt(self.syntax(), f) 3454 std::fmt::Display::fmt(self.syntax(), f)
4921 } 3455 }
4922} 3456}
4923impl std::fmt::Display for FnDef { 3457impl std::fmt::Display for Attr {
4924 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3458 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4925 std::fmt::Display::fmt(self.syntax(), f) 3459 std::fmt::Display::fmt(self.syntax(), f)
4926 } 3460 }
4927} 3461}
4928impl std::fmt::Display for RetType { 3462impl std::fmt::Display for Const {
4929 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3463 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4930 std::fmt::Display::fmt(self.syntax(), f) 3464 std::fmt::Display::fmt(self.syntax(), f)
4931 } 3465 }
4932} 3466}
4933impl std::fmt::Display for StructDef { 3467impl std::fmt::Display for Enum {
4934 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3468 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4935 std::fmt::Display::fmt(self.syntax(), f) 3469 std::fmt::Display::fmt(self.syntax(), f)
4936 } 3470 }
4937} 3471}
4938impl std::fmt::Display for UnionDef { 3472impl std::fmt::Display for ExternBlock {
4939 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4940 std::fmt::Display::fmt(self.syntax(), f) 3474 std::fmt::Display::fmt(self.syntax(), f)
4941 } 3475 }
4942} 3476}
4943impl std::fmt::Display for RecordFieldDefList { 3477impl std::fmt::Display for ExternCrate {
4944 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3478 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4945 std::fmt::Display::fmt(self.syntax(), f) 3479 std::fmt::Display::fmt(self.syntax(), f)
4946 } 3480 }
4947} 3481}
4948impl std::fmt::Display for RecordFieldDef { 3482impl std::fmt::Display for Fn {
4949 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3483 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4950 std::fmt::Display::fmt(self.syntax(), f) 3484 std::fmt::Display::fmt(self.syntax(), f)
4951 } 3485 }
4952} 3486}
4953impl std::fmt::Display for TupleFieldDefList { 3487impl std::fmt::Display for Impl {
4954 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4955 std::fmt::Display::fmt(self.syntax(), f) 3489 std::fmt::Display::fmt(self.syntax(), f)
4956 } 3490 }
4957} 3491}
4958impl std::fmt::Display for TupleFieldDef { 3492impl std::fmt::Display for MacroCall {
4959 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3493 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4960 std::fmt::Display::fmt(self.syntax(), f) 3494 std::fmt::Display::fmt(self.syntax(), f)
4961 } 3495 }
4962} 3496}
4963impl std::fmt::Display for EnumDef { 3497impl std::fmt::Display for Module {
4964 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3498 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4965 std::fmt::Display::fmt(self.syntax(), f) 3499 std::fmt::Display::fmt(self.syntax(), f)
4966 } 3500 }
4967} 3501}
4968impl std::fmt::Display for EnumVariantList { 3502impl std::fmt::Display for Static {
4969 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3503 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4970 std::fmt::Display::fmt(self.syntax(), f) 3504 std::fmt::Display::fmt(self.syntax(), f)
4971 } 3505 }
4972} 3506}
4973impl std::fmt::Display for EnumVariant { 3507impl std::fmt::Display for Struct {
4974 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4975 std::fmt::Display::fmt(self.syntax(), f) 3509 std::fmt::Display::fmt(self.syntax(), f)
4976 } 3510 }
4977} 3511}
4978impl std::fmt::Display for TraitDef { 3512impl std::fmt::Display for Trait {
4979 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3513 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4980 std::fmt::Display::fmt(self.syntax(), f) 3514 std::fmt::Display::fmt(self.syntax(), f)
4981 } 3515 }
4982} 3516}
4983impl std::fmt::Display for Module { 3517impl std::fmt::Display for TypeAlias {
4984 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3518 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4985 std::fmt::Display::fmt(self.syntax(), f) 3519 std::fmt::Display::fmt(self.syntax(), f)
4986 } 3520 }
4987} 3521}
4988impl std::fmt::Display for ItemList { 3522impl std::fmt::Display for Union {
4989 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3523 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4990 std::fmt::Display::fmt(self.syntax(), f) 3524 std::fmt::Display::fmt(self.syntax(), f)
4991 } 3525 }
4992} 3526}
4993impl std::fmt::Display for ConstDef { 3527impl std::fmt::Display for Use {
4994 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3528 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4995 std::fmt::Display::fmt(self.syntax(), f) 3529 std::fmt::Display::fmt(self.syntax(), f)
4996 } 3530 }
4997} 3531}
4998impl std::fmt::Display for StaticDef { 3532impl std::fmt::Display for Visibility {
4999 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3533 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5000 std::fmt::Display::fmt(self.syntax(), f) 3534 std::fmt::Display::fmt(self.syntax(), f)
5001 } 3535 }
5002} 3536}
5003impl std::fmt::Display for TypeAliasDef { 3537impl std::fmt::Display for Name {
5004 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3538 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5005 std::fmt::Display::fmt(self.syntax(), f) 3539 std::fmt::Display::fmt(self.syntax(), f)
5006 } 3540 }
5007} 3541}
5008impl std::fmt::Display for ImplDef { 3542impl std::fmt::Display for ItemList {
5009 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3543 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5010 std::fmt::Display::fmt(self.syntax(), f) 3544 std::fmt::Display::fmt(self.syntax(), f)
5011 } 3545 }
5012} 3546}
5013impl std::fmt::Display for ParenType { 3547impl std::fmt::Display for NameRef {
5014 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3548 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5015 std::fmt::Display::fmt(self.syntax(), f) 3549 std::fmt::Display::fmt(self.syntax(), f)
5016 } 3550 }
5017} 3551}
5018impl std::fmt::Display for TupleType { 3552impl std::fmt::Display for Rename {
5019 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3553 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5020 std::fmt::Display::fmt(self.syntax(), f) 3554 std::fmt::Display::fmt(self.syntax(), f)
5021 } 3555 }
5022} 3556}
5023impl std::fmt::Display for NeverType { 3557impl std::fmt::Display for UseTree {
5024 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3558 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5025 std::fmt::Display::fmt(self.syntax(), f) 3559 std::fmt::Display::fmt(self.syntax(), f)
5026 } 3560 }
5027} 3561}
5028impl std::fmt::Display for PathType { 3562impl std::fmt::Display for Path {
5029 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3563 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5030 std::fmt::Display::fmt(self.syntax(), f) 3564 std::fmt::Display::fmt(self.syntax(), f)
5031 } 3565 }
5032} 3566}
5033impl std::fmt::Display for PointerType { 3567impl std::fmt::Display for UseTreeList {
5034 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3568 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5035 std::fmt::Display::fmt(self.syntax(), f) 3569 std::fmt::Display::fmt(self.syntax(), f)
5036 } 3570 }
5037} 3571}
5038impl std::fmt::Display for ArrayType { 3572impl std::fmt::Display for Abi {
5039 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3573 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5040 std::fmt::Display::fmt(self.syntax(), f) 3574 std::fmt::Display::fmt(self.syntax(), f)
5041 } 3575 }
5042} 3576}
5043impl std::fmt::Display for SliceType { 3577impl std::fmt::Display for GenericParamList {
5044 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5045 std::fmt::Display::fmt(self.syntax(), f) 3579 std::fmt::Display::fmt(self.syntax(), f)
5046 } 3580 }
5047} 3581}
5048impl std::fmt::Display for ReferenceType { 3582impl std::fmt::Display for ParamList {
5049 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3583 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5050 std::fmt::Display::fmt(self.syntax(), f) 3584 std::fmt::Display::fmt(self.syntax(), f)
5051 } 3585 }
5052} 3586}
5053impl std::fmt::Display for PlaceholderType { 3587impl std::fmt::Display for RetType {
5054 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3588 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5055 std::fmt::Display::fmt(self.syntax(), f) 3589 std::fmt::Display::fmt(self.syntax(), f)
5056 } 3590 }
5057} 3591}
5058impl std::fmt::Display for FnPointerType { 3592impl std::fmt::Display for WhereClause {
5059 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3593 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5060 std::fmt::Display::fmt(self.syntax(), f) 3594 std::fmt::Display::fmt(self.syntax(), f)
5061 } 3595 }
5062} 3596}
5063impl std::fmt::Display for ForType { 3597impl std::fmt::Display for BlockExpr {
5064 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3598 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5065 std::fmt::Display::fmt(self.syntax(), f) 3599 std::fmt::Display::fmt(self.syntax(), f)
5066 } 3600 }
5067} 3601}
5068impl std::fmt::Display for ImplTraitType { 3602impl std::fmt::Display for SelfParam {
5069 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3603 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5070 std::fmt::Display::fmt(self.syntax(), f) 3604 std::fmt::Display::fmt(self.syntax(), f)
5071 } 3605 }
5072} 3606}
5073impl std::fmt::Display for DynTraitType { 3607impl std::fmt::Display for Param {
5074 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3608 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5075 std::fmt::Display::fmt(self.syntax(), f) 3609 std::fmt::Display::fmt(self.syntax(), f)
5076 } 3610 }
5077} 3611}
5078impl std::fmt::Display for TupleExpr { 3612impl std::fmt::Display for TypeBoundList {
5079 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5080 std::fmt::Display::fmt(self.syntax(), f) 3614 std::fmt::Display::fmt(self.syntax(), f)
5081 } 3615 }
5082} 3616}
5083impl std::fmt::Display for ArrayExpr { 3617impl std::fmt::Display for RecordFieldList {
5084 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3618 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5085 std::fmt::Display::fmt(self.syntax(), f) 3619 std::fmt::Display::fmt(self.syntax(), f)
5086 } 3620 }
5087} 3621}
5088impl std::fmt::Display for ParenExpr { 3622impl std::fmt::Display for TupleFieldList {
5089 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3623 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5090 std::fmt::Display::fmt(self.syntax(), f) 3624 std::fmt::Display::fmt(self.syntax(), f)
5091 } 3625 }
5092} 3626}
5093impl std::fmt::Display for PathExpr { 3627impl std::fmt::Display for RecordField {
5094 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3628 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5095 std::fmt::Display::fmt(self.syntax(), f) 3629 std::fmt::Display::fmt(self.syntax(), f)
5096 } 3630 }
5097} 3631}
5098impl std::fmt::Display for LambdaExpr { 3632impl std::fmt::Display for TupleField {
5099 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3633 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5100 std::fmt::Display::fmt(self.syntax(), f) 3634 std::fmt::Display::fmt(self.syntax(), f)
5101 } 3635 }
5102} 3636}
5103impl std::fmt::Display for IfExpr { 3637impl std::fmt::Display for VariantList {
5104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3638 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5105 std::fmt::Display::fmt(self.syntax(), f) 3639 std::fmt::Display::fmt(self.syntax(), f)
5106 } 3640 }
5107} 3641}
5108impl std::fmt::Display for LoopExpr { 3642impl std::fmt::Display for Variant {
5109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3643 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5110 std::fmt::Display::fmt(self.syntax(), f) 3644 std::fmt::Display::fmt(self.syntax(), f)
5111 } 3645 }
5112} 3646}
5113impl std::fmt::Display for EffectExpr { 3647impl std::fmt::Display for AssocItemList {
5114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3648 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5115 std::fmt::Display::fmt(self.syntax(), f) 3649 std::fmt::Display::fmt(self.syntax(), f)
5116 } 3650 }
5117} 3651}
5118impl std::fmt::Display for ForExpr { 3652impl std::fmt::Display for ExternItemList {
5119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3653 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5120 std::fmt::Display::fmt(self.syntax(), f) 3654 std::fmt::Display::fmt(self.syntax(), f)
5121 } 3655 }
5122} 3656}
5123impl std::fmt::Display for WhileExpr { 3657impl std::fmt::Display for LifetimeParam {
5124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3658 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5125 std::fmt::Display::fmt(self.syntax(), f) 3659 std::fmt::Display::fmt(self.syntax(), f)
5126 } 3660 }
5127} 3661}
5128impl std::fmt::Display for ContinueExpr { 3662impl std::fmt::Display for TypeParam {
5129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3663 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5130 std::fmt::Display::fmt(self.syntax(), f) 3664 std::fmt::Display::fmt(self.syntax(), f)
5131 } 3665 }
5132} 3666}
5133impl std::fmt::Display for BreakExpr { 3667impl std::fmt::Display for ConstParam {
5134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5135 std::fmt::Display::fmt(self.syntax(), f) 3669 std::fmt::Display::fmt(self.syntax(), f)
5136 } 3670 }
5137} 3671}
5138impl std::fmt::Display for Label { 3672impl std::fmt::Display for Literal {
5139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3673 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5140 std::fmt::Display::fmt(self.syntax(), f) 3674 std::fmt::Display::fmt(self.syntax(), f)
5141 } 3675 }
5142} 3676}
5143impl std::fmt::Display for BlockExpr { 3677impl std::fmt::Display for TokenTree {
5144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3678 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5145 std::fmt::Display::fmt(self.syntax(), f) 3679 std::fmt::Display::fmt(self.syntax(), f)
5146 } 3680 }
5147} 3681}
5148impl std::fmt::Display for ReturnExpr { 3682impl std::fmt::Display for ParenType {
5149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3683 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5150 std::fmt::Display::fmt(self.syntax(), f) 3684 std::fmt::Display::fmt(self.syntax(), f)
5151 } 3685 }
5152} 3686}
5153impl std::fmt::Display for CallExpr { 3687impl std::fmt::Display for TupleType {
5154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3688 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5155 std::fmt::Display::fmt(self.syntax(), f) 3689 std::fmt::Display::fmt(self.syntax(), f)
5156 } 3690 }
5157} 3691}
5158impl std::fmt::Display for MethodCallExpr { 3692impl std::fmt::Display for NeverType {
5159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3693 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5160 std::fmt::Display::fmt(self.syntax(), f) 3694 std::fmt::Display::fmt(self.syntax(), f)
5161 } 3695 }
5162} 3696}
5163impl std::fmt::Display for IndexExpr { 3697impl std::fmt::Display for PathType {
5164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3698 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5165 std::fmt::Display::fmt(self.syntax(), f) 3699 std::fmt::Display::fmt(self.syntax(), f)
5166 } 3700 }
5167} 3701}
5168impl std::fmt::Display for FieldExpr { 3702impl std::fmt::Display for PointerType {
5169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3703 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5170 std::fmt::Display::fmt(self.syntax(), f) 3704 std::fmt::Display::fmt(self.syntax(), f)
5171 } 3705 }
5172} 3706}
5173impl std::fmt::Display for AwaitExpr { 3707impl std::fmt::Display for ArrayType {
5174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3708 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5175 std::fmt::Display::fmt(self.syntax(), f) 3709 std::fmt::Display::fmt(self.syntax(), f)
5176 } 3710 }
5177} 3711}
5178impl std::fmt::Display for TryExpr { 3712impl std::fmt::Display for SliceType {
5179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3713 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5180 std::fmt::Display::fmt(self.syntax(), f) 3714 std::fmt::Display::fmt(self.syntax(), f)
5181 } 3715 }
5182} 3716}
5183impl std::fmt::Display for CastExpr { 3717impl std::fmt::Display for ReferenceType {
5184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3718 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5185 std::fmt::Display::fmt(self.syntax(), f) 3719 std::fmt::Display::fmt(self.syntax(), f)
5186 } 3720 }
5187} 3721}
5188impl std::fmt::Display for RefExpr { 3722impl std::fmt::Display for PlaceholderType {
5189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3723 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5190 std::fmt::Display::fmt(self.syntax(), f) 3724 std::fmt::Display::fmt(self.syntax(), f)
5191 } 3725 }
5192} 3726}
5193impl std::fmt::Display for PrefixExpr { 3727impl std::fmt::Display for FnPointerType {
5194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3728 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5195 std::fmt::Display::fmt(self.syntax(), f) 3729 std::fmt::Display::fmt(self.syntax(), f)
5196 } 3730 }
5197} 3731}
5198impl std::fmt::Display for BoxExpr { 3732impl std::fmt::Display for ForType {
5199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3733 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5200 std::fmt::Display::fmt(self.syntax(), f) 3734 std::fmt::Display::fmt(self.syntax(), f)
5201 } 3735 }
5202} 3736}
5203impl std::fmt::Display for RangeExpr { 3737impl std::fmt::Display for ImplTraitType {
5204 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3738 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5205 std::fmt::Display::fmt(self.syntax(), f) 3739 std::fmt::Display::fmt(self.syntax(), f)
5206 } 3740 }
5207} 3741}
5208impl std::fmt::Display for BinExpr { 3742impl std::fmt::Display for DynTraitType {
5209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3743 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5210 std::fmt::Display::fmt(self.syntax(), f) 3744 std::fmt::Display::fmt(self.syntax(), f)
5211 } 3745 }
5212} 3746}
5213impl std::fmt::Display for Literal { 3747impl std::fmt::Display for TupleExpr {
5214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3748 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5215 std::fmt::Display::fmt(self.syntax(), f) 3749 std::fmt::Display::fmt(self.syntax(), f)
5216 } 3750 }
5217} 3751}
5218impl std::fmt::Display for MatchExpr { 3752impl std::fmt::Display for ArrayExpr {
5219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3753 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5220 std::fmt::Display::fmt(self.syntax(), f) 3754 std::fmt::Display::fmt(self.syntax(), f)
5221 } 3755 }
5222} 3756}
5223impl std::fmt::Display for MatchArmList { 3757impl std::fmt::Display for ParenExpr {
5224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3758 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5225 std::fmt::Display::fmt(self.syntax(), f) 3759 std::fmt::Display::fmt(self.syntax(), f)
5226 } 3760 }
5227} 3761}
5228impl std::fmt::Display for MatchArm { 3762impl std::fmt::Display for PathExpr {
5229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3763 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5230 std::fmt::Display::fmt(self.syntax(), f) 3764 std::fmt::Display::fmt(self.syntax(), f)
5231 } 3765 }
5232} 3766}
5233impl std::fmt::Display for MatchGuard { 3767impl std::fmt::Display for LambdaExpr {
5234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3768 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5235 std::fmt::Display::fmt(self.syntax(), f) 3769 std::fmt::Display::fmt(self.syntax(), f)
5236 } 3770 }
5237} 3771}
5238impl std::fmt::Display for RecordLit { 3772impl std::fmt::Display for IfExpr {
5239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3773 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5240 std::fmt::Display::fmt(self.syntax(), f) 3774 std::fmt::Display::fmt(self.syntax(), f)
5241 } 3775 }
5242} 3776}
5243impl std::fmt::Display for RecordFieldList { 3777impl std::fmt::Display for Condition {
5244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3778 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5245 std::fmt::Display::fmt(self.syntax(), f) 3779 std::fmt::Display::fmt(self.syntax(), f)
5246 } 3780 }
5247} 3781}
5248impl std::fmt::Display for RecordField { 3782impl std::fmt::Display for EffectExpr {
5249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3783 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5250 std::fmt::Display::fmt(self.syntax(), f) 3784 std::fmt::Display::fmt(self.syntax(), f)
5251 } 3785 }
5252} 3786}
5253impl std::fmt::Display for OrPat { 3787impl std::fmt::Display for Label {
5254 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3788 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5255 std::fmt::Display::fmt(self.syntax(), f) 3789 std::fmt::Display::fmt(self.syntax(), f)
5256 } 3790 }
5257} 3791}
5258impl std::fmt::Display for ParenPat { 3792impl std::fmt::Display for LoopExpr {
5259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3793 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5260 std::fmt::Display::fmt(self.syntax(), f) 3794 std::fmt::Display::fmt(self.syntax(), f)
5261 } 3795 }
5262} 3796}
5263impl std::fmt::Display for RefPat { 3797impl std::fmt::Display for ForExpr {
5264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3798 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5265 std::fmt::Display::fmt(self.syntax(), f) 3799 std::fmt::Display::fmt(self.syntax(), f)
5266 } 3800 }
5267} 3801}
5268impl std::fmt::Display for BoxPat { 3802impl std::fmt::Display for WhileExpr {
5269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3803 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5270 std::fmt::Display::fmt(self.syntax(), f) 3804 std::fmt::Display::fmt(self.syntax(), f)
5271 } 3805 }
5272} 3806}
5273impl std::fmt::Display for BindPat { 3807impl std::fmt::Display for ContinueExpr {
5274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3808 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5275 std::fmt::Display::fmt(self.syntax(), f) 3809 std::fmt::Display::fmt(self.syntax(), f)
5276 } 3810 }
5277} 3811}
5278impl std::fmt::Display for PlaceholderPat { 3812impl std::fmt::Display for BreakExpr {
5279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3813 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5280 std::fmt::Display::fmt(self.syntax(), f) 3814 std::fmt::Display::fmt(self.syntax(), f)
5281 } 3815 }
5282} 3816}
5283impl std::fmt::Display for DotDotPat { 3817impl std::fmt::Display for ReturnExpr {
5284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3818 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5285 std::fmt::Display::fmt(self.syntax(), f) 3819 std::fmt::Display::fmt(self.syntax(), f)
5286 } 3820 }
5287} 3821}
5288impl std::fmt::Display for PathPat { 3822impl std::fmt::Display for CallExpr {
5289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3823 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5290 std::fmt::Display::fmt(self.syntax(), f) 3824 std::fmt::Display::fmt(self.syntax(), f)
5291 } 3825 }
5292} 3826}
5293impl std::fmt::Display for SlicePat { 3827impl std::fmt::Display for ArgList {
5294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3828 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5295 std::fmt::Display::fmt(self.syntax(), f) 3829 std::fmt::Display::fmt(self.syntax(), f)
5296 } 3830 }
5297} 3831}
5298impl std::fmt::Display for RangePat { 3832impl std::fmt::Display for MethodCallExpr {
5299 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3833 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5300 std::fmt::Display::fmt(self.syntax(), f) 3834 std::fmt::Display::fmt(self.syntax(), f)
5301 } 3835 }
5302} 3836}
5303impl std::fmt::Display for LiteralPat { 3837impl std::fmt::Display for TypeArgList {
5304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3838 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5305 std::fmt::Display::fmt(self.syntax(), f) 3839 std::fmt::Display::fmt(self.syntax(), f)
5306 } 3840 }
5307} 3841}
5308impl std::fmt::Display for MacroPat { 3842impl std::fmt::Display for FieldExpr {
5309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3843 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5310 std::fmt::Display::fmt(self.syntax(), f) 3844 std::fmt::Display::fmt(self.syntax(), f)
5311 } 3845 }
5312} 3846}
5313impl std::fmt::Display for RecordPat { 3847impl std::fmt::Display for IndexExpr {
5314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3848 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5315 std::fmt::Display::fmt(self.syntax(), f) 3849 std::fmt::Display::fmt(self.syntax(), f)
5316 } 3850 }
5317} 3851}
5318impl std::fmt::Display for RecordFieldPatList { 3852impl std::fmt::Display for AwaitExpr {
5319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3853 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5320 std::fmt::Display::fmt(self.syntax(), f) 3854 std::fmt::Display::fmt(self.syntax(), f)
5321 } 3855 }
5322} 3856}
5323impl std::fmt::Display for RecordFieldPat { 3857impl std::fmt::Display for TryExpr {
5324 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3858 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5325 std::fmt::Display::fmt(self.syntax(), f) 3859 std::fmt::Display::fmt(self.syntax(), f)
5326 } 3860 }
5327} 3861}
5328impl std::fmt::Display for TupleStructPat { 3862impl std::fmt::Display for CastExpr {
5329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3863 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5330 std::fmt::Display::fmt(self.syntax(), f) 3864 std::fmt::Display::fmt(self.syntax(), f)
5331 } 3865 }
5332} 3866}
5333impl std::fmt::Display for TuplePat { 3867impl std::fmt::Display for RefExpr {
5334 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3868 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5335 std::fmt::Display::fmt(self.syntax(), f) 3869 std::fmt::Display::fmt(self.syntax(), f)
5336 } 3870 }
5337} 3871}
5338impl std::fmt::Display for Visibility { 3872impl std::fmt::Display for PrefixExpr {
5339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3873 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5340 std::fmt::Display::fmt(self.syntax(), f) 3874 std::fmt::Display::fmt(self.syntax(), f)
5341 } 3875 }
5342} 3876}
5343impl std::fmt::Display for Name { 3877impl std::fmt::Display for BoxExpr {
5344 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3878 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5345 std::fmt::Display::fmt(self.syntax(), f) 3879 std::fmt::Display::fmt(self.syntax(), f)
5346 } 3880 }
5347} 3881}
5348impl std::fmt::Display for NameRef { 3882impl std::fmt::Display for RangeExpr {
5349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3883 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5350 std::fmt::Display::fmt(self.syntax(), f) 3884 std::fmt::Display::fmt(self.syntax(), f)
5351 } 3885 }
5352} 3886}
5353impl std::fmt::Display for MacroCall { 3887impl std::fmt::Display for BinExpr {
5354 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5355 std::fmt::Display::fmt(self.syntax(), f) 3889 std::fmt::Display::fmt(self.syntax(), f)
5356 } 3890 }
5357} 3891}
5358impl std::fmt::Display for Attr { 3892impl std::fmt::Display for MatchExpr {
5359 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3893 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5360 std::fmt::Display::fmt(self.syntax(), f) 3894 std::fmt::Display::fmt(self.syntax(), f)
5361 } 3895 }
5362} 3896}
5363impl std::fmt::Display for TokenTree { 3897impl std::fmt::Display for MatchArmList {
5364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3898 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5365 std::fmt::Display::fmt(self.syntax(), f) 3899 std::fmt::Display::fmt(self.syntax(), f)
5366 } 3900 }
5367} 3901}
5368impl std::fmt::Display for TypeParamList { 3902impl std::fmt::Display for MatchArm {
5369 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3903 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5370 std::fmt::Display::fmt(self.syntax(), f) 3904 std::fmt::Display::fmt(self.syntax(), f)
5371 } 3905 }
5372} 3906}
5373impl std::fmt::Display for TypeParam { 3907impl std::fmt::Display for MatchGuard {
5374 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3908 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5375 std::fmt::Display::fmt(self.syntax(), f) 3909 std::fmt::Display::fmt(self.syntax(), f)
5376 } 3910 }
5377} 3911}
5378impl std::fmt::Display for ConstParam { 3912impl std::fmt::Display for RecordExpr {
5379 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3913 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5380 std::fmt::Display::fmt(self.syntax(), f) 3914 std::fmt::Display::fmt(self.syntax(), f)
5381 } 3915 }
5382} 3916}
5383impl std::fmt::Display for LifetimeParam { 3917impl std::fmt::Display for RecordExprFieldList {
5384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3918 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5385 std::fmt::Display::fmt(self.syntax(), f) 3919 std::fmt::Display::fmt(self.syntax(), f)
5386 } 3920 }
5387} 3921}
5388impl std::fmt::Display for TypeBound { 3922impl std::fmt::Display for RecordExprField {
5389 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3923 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5390 std::fmt::Display::fmt(self.syntax(), f) 3924 std::fmt::Display::fmt(self.syntax(), f)
5391 } 3925 }
5392} 3926}
5393impl std::fmt::Display for TypeBoundList { 3927impl std::fmt::Display for OrPat {
5394 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3928 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5395 std::fmt::Display::fmt(self.syntax(), f) 3929 std::fmt::Display::fmt(self.syntax(), f)
5396 } 3930 }
5397} 3931}
5398impl std::fmt::Display for WherePred { 3932impl std::fmt::Display for ParenPat {
5399 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3933 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5400 std::fmt::Display::fmt(self.syntax(), f) 3934 std::fmt::Display::fmt(self.syntax(), f)
5401 } 3935 }
5402} 3936}
5403impl std::fmt::Display for WhereClause { 3937impl std::fmt::Display for RefPat {
5404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3938 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5405 std::fmt::Display::fmt(self.syntax(), f) 3939 std::fmt::Display::fmt(self.syntax(), f)
5406 } 3940 }
5407} 3941}
5408impl std::fmt::Display for Abi { 3942impl std::fmt::Display for BoxPat {
5409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3943 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5410 std::fmt::Display::fmt(self.syntax(), f) 3944 std::fmt::Display::fmt(self.syntax(), f)
5411 } 3945 }
5412} 3946}
5413impl std::fmt::Display for ExprStmt { 3947impl std::fmt::Display for BindPat {
5414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3948 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5415 std::fmt::Display::fmt(self.syntax(), f) 3949 std::fmt::Display::fmt(self.syntax(), f)
5416 } 3950 }
5417} 3951}
5418impl std::fmt::Display for LetStmt { 3952impl std::fmt::Display for PlaceholderPat {
5419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3953 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5420 std::fmt::Display::fmt(self.syntax(), f) 3954 std::fmt::Display::fmt(self.syntax(), f)
5421 } 3955 }
5422} 3956}
5423impl std::fmt::Display for Condition { 3957impl std::fmt::Display for DotDotPat {
5424 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3958 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5425 std::fmt::Display::fmt(self.syntax(), f) 3959 std::fmt::Display::fmt(self.syntax(), f)
5426 } 3960 }
5427} 3961}
5428impl std::fmt::Display for ParamList { 3962impl std::fmt::Display for PathPat {
5429 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3963 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5430 std::fmt::Display::fmt(self.syntax(), f) 3964 std::fmt::Display::fmt(self.syntax(), f)
5431 } 3965 }
5432} 3966}
5433impl std::fmt::Display for SelfParam { 3967impl std::fmt::Display for SlicePat {
5434 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3968 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5435 std::fmt::Display::fmt(self.syntax(), f) 3969 std::fmt::Display::fmt(self.syntax(), f)
5436 } 3970 }
5437} 3971}
5438impl std::fmt::Display for Param { 3972impl std::fmt::Display for RangePat {
5439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3973 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5440 std::fmt::Display::fmt(self.syntax(), f) 3974 std::fmt::Display::fmt(self.syntax(), f)
5441 } 3975 }
5442} 3976}
5443impl std::fmt::Display for UseItem { 3977impl std::fmt::Display for LiteralPat {
5444 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3978 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5445 std::fmt::Display::fmt(self.syntax(), f) 3979 std::fmt::Display::fmt(self.syntax(), f)
5446 } 3980 }
5447} 3981}
5448impl std::fmt::Display for UseTree { 3982impl std::fmt::Display for MacroPat {
5449 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3983 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5450 std::fmt::Display::fmt(self.syntax(), f) 3984 std::fmt::Display::fmt(self.syntax(), f)
5451 } 3985 }
5452} 3986}
5453impl std::fmt::Display for Alias { 3987impl std::fmt::Display for RecordPat {
5454 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3988 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5455 std::fmt::Display::fmt(self.syntax(), f) 3989 std::fmt::Display::fmt(self.syntax(), f)
5456 } 3990 }
5457} 3991}
5458impl std::fmt::Display for UseTreeList { 3992impl std::fmt::Display for RecordFieldPatList {
5459 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3993 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5460 std::fmt::Display::fmt(self.syntax(), f) 3994 std::fmt::Display::fmt(self.syntax(), f)
5461 } 3995 }
5462} 3996}
5463impl std::fmt::Display for ExternCrateItem { 3997impl std::fmt::Display for RecordFieldPat {
5464 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3998 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5465 std::fmt::Display::fmt(self.syntax(), f) 3999 std::fmt::Display::fmt(self.syntax(), f)
5466 } 4000 }
5467} 4001}
5468impl std::fmt::Display for ArgList { 4002impl std::fmt::Display for TupleStructPat {
5469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4003 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5470 std::fmt::Display::fmt(self.syntax(), f) 4004 std::fmt::Display::fmt(self.syntax(), f)
5471 } 4005 }
5472} 4006}
5473impl std::fmt::Display for Path { 4007impl std::fmt::Display for TuplePat {
5474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4008 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5475 std::fmt::Display::fmt(self.syntax(), f) 4009 std::fmt::Display::fmt(self.syntax(), f)
5476 } 4010 }
5477} 4011}
5478impl std::fmt::Display for PathSegment { 4012impl std::fmt::Display for MacroDef {
5479 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4013 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5480 std::fmt::Display::fmt(self.syntax(), f) 4014 std::fmt::Display::fmt(self.syntax(), f)
5481 } 4015 }
5482} 4016}
5483impl std::fmt::Display for TypeArgList { 4017impl std::fmt::Display for MacroItems {
5484 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4018 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5485 std::fmt::Display::fmt(self.syntax(), f) 4019 std::fmt::Display::fmt(self.syntax(), f)
5486 } 4020 }
5487} 4021}
5488impl std::fmt::Display for TypeArg { 4022impl std::fmt::Display for MacroStmts {
5489 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4023 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5490 std::fmt::Display::fmt(self.syntax(), f) 4024 std::fmt::Display::fmt(self.syntax(), f)
5491 } 4025 }
5492} 4026}
5493impl std::fmt::Display for AssocTypeArg { 4027impl std::fmt::Display for TypeBound {
5494 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4028 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5495 std::fmt::Display::fmt(self.syntax(), f) 4029 std::fmt::Display::fmt(self.syntax(), f)
5496 } 4030 }
5497} 4031}
5498impl std::fmt::Display for LifetimeArg { 4032impl std::fmt::Display for WherePred {
5499 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4033 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5500 std::fmt::Display::fmt(self.syntax(), f) 4034 std::fmt::Display::fmt(self.syntax(), f)
5501 } 4035 }
5502} 4036}
5503impl std::fmt::Display for ConstArg { 4037impl std::fmt::Display for ExprStmt {
5504 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4038 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5505 std::fmt::Display::fmt(self.syntax(), f) 4039 std::fmt::Display::fmt(self.syntax(), f)
5506 } 4040 }
5507} 4041}
5508impl std::fmt::Display for MacroItems { 4042impl std::fmt::Display for LetStmt {
5509 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4043 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5510 std::fmt::Display::fmt(self.syntax(), f) 4044 std::fmt::Display::fmt(self.syntax(), f)
5511 } 4045 }
5512} 4046}
5513impl std::fmt::Display for MacroStmts { 4047impl std::fmt::Display for PathSegment {
5514 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4048 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5515 std::fmt::Display::fmt(self.syntax(), f) 4049 std::fmt::Display::fmt(self.syntax(), f)
5516 } 4050 }
5517} 4051}
5518impl std::fmt::Display for ExternItemList { 4052impl std::fmt::Display for TypeArg {
5519 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4053 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5520 std::fmt::Display::fmt(self.syntax(), f) 4054 std::fmt::Display::fmt(self.syntax(), f)
5521 } 4055 }
5522} 4056}
5523impl std::fmt::Display for ExternBlock { 4057impl std::fmt::Display for LifetimeArg {
5524 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4058 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5525 std::fmt::Display::fmt(self.syntax(), f) 4059 std::fmt::Display::fmt(self.syntax(), f)
5526 } 4060 }
5527} 4061}
5528impl std::fmt::Display for MetaItem { 4062impl std::fmt::Display for AssocTypeArg {
5529 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4063 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5530 std::fmt::Display::fmt(self.syntax(), f) 4064 std::fmt::Display::fmt(self.syntax(), f)
5531 } 4065 }
5532} 4066}
5533impl std::fmt::Display for MacroDef { 4067impl std::fmt::Display for ConstArg {
5534 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 4068 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5535 std::fmt::Display::fmt(self.syntax(), f) 4069 std::fmt::Display::fmt(self.syntax(), f)
5536 } 4070 }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 192c610f1..509e8ae7a 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -37,7 +37,7 @@ fn path_from_text(text: &str) -> ast::Path {
37pub fn use_tree( 37pub fn use_tree(
38 path: ast::Path, 38 path: ast::Path,
39 use_tree_list: Option<ast::UseTreeList>, 39 use_tree_list: Option<ast::UseTreeList>,
40 alias: Option<ast::Alias>, 40 alias: Option<ast::Rename>,
41 add_star: bool, 41 add_star: bool,
42) -> ast::UseTree { 42) -> ast::UseTree {
43 let mut buf = "use ".to_string(); 43 let mut buf = "use ".to_string();
@@ -60,22 +60,22 @@ pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::
60 ast_from_text(&format!("use {{{}}};", use_trees)) 60 ast_from_text(&format!("use {{{}}};", use_trees))
61} 61}
62 62
63pub fn use_item(use_tree: ast::UseTree) -> ast::UseItem { 63pub fn use_item(use_tree: ast::UseTree) -> ast::Use {
64 ast_from_text(&format!("use {};", use_tree)) 64 ast_from_text(&format!("use {};", use_tree))
65} 65}
66 66
67pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { 67pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
68 return match expr { 68 return match expr {
69 Some(expr) => from_text(&format!("{}: {}", name, expr)), 69 Some(expr) => from_text(&format!("{}: {}", name, expr)),
70 None => from_text(&name.to_string()), 70 None => from_text(&name.to_string()),
71 }; 71 };
72 72
73 fn from_text(text: &str) -> ast::RecordField { 73 fn from_text(text: &str) -> ast::RecordExprField {
74 ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text)) 74 ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
75 } 75 }
76} 76}
77 77
78pub fn record_field_def(name: ast::NameRef, ty: ast::TypeRef) -> ast::RecordFieldDef { 78pub fn record_field_def(name: ast::NameRef, ty: ast::TypeRef) -> ast::RecordField {
79 ast_from_text(&format!("struct S {{ {}: {}, }}", name, ty)) 79 ast_from_text(&format!("struct S {{ {}: {}, }}", name, ty))
80} 80}
81 81
@@ -291,10 +291,10 @@ pub fn visibility_pub_crate() -> ast::Visibility {
291pub fn fn_def( 291pub fn fn_def(
292 visibility: Option<ast::Visibility>, 292 visibility: Option<ast::Visibility>,
293 fn_name: ast::Name, 293 fn_name: ast::Name,
294 type_params: Option<ast::TypeParamList>, 294 type_params: Option<ast::GenericParamList>,
295 params: ast::ParamList, 295 params: ast::ParamList,
296 body: ast::BlockExpr, 296 body: ast::BlockExpr,
297) -> ast::FnDef { 297) -> ast::Fn {
298 let type_params = 298 let type_params =
299 if let Some(type_params) = type_params { format!("<{}>", type_params) } else { "".into() }; 299 if let Some(type_params) = type_params { format!("<{}>", type_params) } else { "".into() };
300 let visibility = match visibility { 300 let visibility = match visibility {
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/node_ext.rs
index 662c6f73e..bba7310ad 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/node_ext.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
7use ra_parser::SyntaxKind; 7use ra_parser::SyntaxKind;
8 8
9use crate::{ 9use crate::{
10 ast::{self, support, AstNode, AttrInput, NameOwner, SyntaxNode}, 10 ast::{self, support, AstNode, NameOwner, SyntaxNode},
11 SmolStr, SyntaxElement, SyntaxToken, T, 11 SmolStr, SyntaxElement, SyntaxToken, T,
12}; 12};
13 13
@@ -39,29 +39,23 @@ pub enum AttrKind {
39 39
40impl ast::Attr { 40impl ast::Attr {
41 pub fn as_simple_atom(&self) -> Option<SmolStr> { 41 pub fn as_simple_atom(&self) -> Option<SmolStr> {
42 match self.input() { 42 if self.eq_token().is_some() || self.token_tree().is_some() {
43 None => self.simple_name(), 43 return None;
44 Some(_) => None,
45 } 44 }
45 self.simple_name()
46 } 46 }
47 47
48 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { 48 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
49 match self.input() { 49 let tt = self.token_tree()?;
50 Some(AttrInput::TokenTree(tt)) => Some((self.simple_name()?, tt)), 50 Some((self.simple_name()?, tt))
51 _ => None,
52 }
53 } 51 }
54 52
55 pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> { 53 pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> {
56 match self.input() { 54 let lit = self.literal()?;
57 Some(AttrInput::Literal(lit)) => { 55 let key = self.simple_name()?;
58 let key = self.simple_name()?; 56 // FIXME: escape? raw string?
59 // FIXME: escape? raw string? 57 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
60 let value = lit.syntax().first_token()?.text().trim_matches('"').into(); 58 Some((key, value))
61 Some((key, value))
62 }
63 _ => None,
64 }
65 } 59 }
66 60
67 pub fn simple_name(&self) -> Option<SmolStr> { 61 pub fn simple_name(&self) -> Option<SmolStr> {
@@ -141,7 +135,7 @@ impl ast::UseTreeList {
141 } 135 }
142} 136}
143 137
144impl ast::ImplDef { 138impl ast::Impl {
145 pub fn target_type(&self) -> Option<ast::TypeRef> { 139 pub fn target_type(&self) -> Option<ast::TypeRef> {
146 match self.target() { 140 match self.target() {
147 (Some(t), None) | (_, Some(t)) => Some(t), 141 (Some(t), None) | (_, Some(t)) => Some(t),
@@ -166,16 +160,16 @@ impl ast::ImplDef {
166 160
167#[derive(Debug, Clone, PartialEq, Eq)] 161#[derive(Debug, Clone, PartialEq, Eq)]
168pub enum StructKind { 162pub enum StructKind {
169 Record(ast::RecordFieldDefList), 163 Record(ast::RecordFieldList),
170 Tuple(ast::TupleFieldDefList), 164 Tuple(ast::TupleFieldList),
171 Unit, 165 Unit,
172} 166}
173 167
174impl StructKind { 168impl StructKind {
175 fn from_node<N: AstNode>(node: &N) -> StructKind { 169 fn from_node<N: AstNode>(node: &N) -> StructKind {
176 if let Some(nfdl) = support::child::<ast::RecordFieldDefList>(node.syntax()) { 170 if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
177 StructKind::Record(nfdl) 171 StructKind::Record(nfdl)
178 } else if let Some(pfl) = support::child::<ast::TupleFieldDefList>(node.syntax()) { 172 } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
179 StructKind::Tuple(pfl) 173 StructKind::Tuple(pfl)
180 } else { 174 } else {
181 StructKind::Unit 175 StructKind::Unit
@@ -183,17 +177,17 @@ impl StructKind {
183 } 177 }
184} 178}
185 179
186impl ast::StructDef { 180impl ast::Struct {
187 pub fn kind(&self) -> StructKind { 181 pub fn kind(&self) -> StructKind {
188 StructKind::from_node(self) 182 StructKind::from_node(self)
189 } 183 }
190} 184}
191 185
192impl ast::RecordField { 186impl ast::RecordExprField {
193 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordField> { 187 pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
194 let candidate = 188 let candidate =
195 field_name.syntax().parent().and_then(ast::RecordField::cast).or_else(|| { 189 field_name.syntax().parent().and_then(ast::RecordExprField::cast).or_else(|| {
196 field_name.syntax().ancestors().nth(4).and_then(ast::RecordField::cast) 190 field_name.syntax().ancestors().nth(4).and_then(ast::RecordExprField::cast)
197 })?; 191 })?;
198 if candidate.field_name().as_ref() == Some(field_name) { 192 if candidate.field_name().as_ref() == Some(field_name) {
199 Some(candidate) 193 Some(candidate)
@@ -247,12 +241,12 @@ impl ast::RecordFieldPat {
247 } 241 }
248} 242}
249 243
250impl ast::EnumVariant { 244impl ast::Variant {
251 pub fn parent_enum(&self) -> ast::EnumDef { 245 pub fn parent_enum(&self) -> ast::Enum {
252 self.syntax() 246 self.syntax()
253 .parent() 247 .parent()
254 .and_then(|it| it.parent()) 248 .and_then(|it| it.parent())
255 .and_then(ast::EnumDef::cast) 249 .and_then(ast::Enum::cast)
256 .expect("EnumVariants are always nested in Enums") 250 .expect("EnumVariants are always nested in Enums")
257 } 251 }
258 pub fn kind(&self) -> StructKind { 252 pub fn kind(&self) -> StructKind {
@@ -472,3 +466,40 @@ impl ast::TokenTree {
472 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']'])) 466 .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
473 } 467 }
474} 468}
469
470impl ast::GenericParamList {
471 pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
472 self.generic_params().filter_map(|param| match param {
473 ast::GenericParam::LifetimeParam(it) => Some(it),
474 ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
475 })
476 }
477 pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
478 self.generic_params().filter_map(|param| match param {
479 ast::GenericParam::TypeParam(it) => Some(it),
480 ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
481 })
482 }
483 pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
484 self.generic_params().filter_map(|param| match param {
485 ast::GenericParam::ConstParam(it) => Some(it),
486 ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
487 })
488 }
489}
490
491impl ast::DocCommentsOwner for ast::SourceFile {}
492impl ast::DocCommentsOwner for ast::Fn {}
493impl ast::DocCommentsOwner for ast::Struct {}
494impl ast::DocCommentsOwner for ast::Union {}
495impl ast::DocCommentsOwner for ast::RecordField {}
496impl ast::DocCommentsOwner for ast::TupleField {}
497impl ast::DocCommentsOwner for ast::Enum {}
498impl ast::DocCommentsOwner for ast::Variant {}
499impl ast::DocCommentsOwner for ast::Trait {}
500impl ast::DocCommentsOwner for ast::Module {}
501impl ast::DocCommentsOwner for ast::Static {}
502impl ast::DocCommentsOwner for ast::Const {}
503impl ast::DocCommentsOwner for ast::TypeAlias {}
504impl ast::DocCommentsOwner for ast::Impl {}
505impl ast::DocCommentsOwner for ast::MacroCall {}
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/token_ext.rs
index 2e72d4927..c5ef92733 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/token_ext.rs
@@ -1,12 +1,16 @@
1//! There are many AstNodes, but only a few tokens, so we hand-write them here. 1//! There are many AstNodes, but only a few tokens, so we hand-write them here.
2 2
3use std::convert::{TryFrom, TryInto}; 3use std::{
4 borrow::Cow,
5 convert::{TryFrom, TryInto},
6};
7
8use rustc_lexer::unescape::{unescape_literal, Mode};
4 9
5use crate::{ 10use crate::{
6 ast::{AstToken, Comment, RawString, String, Whitespace}, 11 ast::{AstToken, Comment, RawString, String, Whitespace},
7 TextRange, TextSize, 12 TextRange, TextSize,
8}; 13};
9use rustc_lexer::unescape::{unescape_literal, Mode};
10 14
11impl Comment { 15impl Comment {
12 pub fn kind(&self) -> CommentKind { 16 pub fn kind(&self) -> CommentKind {
@@ -138,11 +142,11 @@ impl HasQuotes for String {}
138impl HasQuotes for RawString {} 142impl HasQuotes for RawString {}
139 143
140pub trait HasStringValue: HasQuotes { 144pub trait HasStringValue: HasQuotes {
141 fn value(&self) -> Option<std::string::String>; 145 fn value(&self) -> Option<Cow<'_, str>>;
142} 146}
143 147
144impl HasStringValue for String { 148impl HasStringValue for String {
145 fn value(&self) -> Option<std::string::String> { 149 fn value(&self) -> Option<Cow<'_, str>> {
146 let text = self.text().as_str(); 150 let text = self.text().as_str();
147 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 151 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
148 152
@@ -156,15 +160,17 @@ impl HasStringValue for String {
156 if has_error { 160 if has_error {
157 return None; 161 return None;
158 } 162 }
159 Some(buf) 163 // FIXME: don't actually allocate for borrowed case
164 let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) };
165 Some(res)
160 } 166 }
161} 167}
162 168
163impl HasStringValue for RawString { 169impl HasStringValue for RawString {
164 fn value(&self) -> Option<std::string::String> { 170 fn value(&self) -> Option<Cow<'_, str>> {
165 let text = self.text().as_str(); 171 let text = self.text().as_str();
166 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 172 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
167 Some(text.to_string()) 173 Some(Cow::Borrowed(text))
168 } 174 }
169} 175}
170 176
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index a8f2454fd..3a56b1674 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -9,12 +9,6 @@ use crate::{
9 SyntaxToken, T, 9 SyntaxToken, T,
10}; 10};
11 11
12pub trait TypeAscriptionOwner: AstNode {
13 fn ascribed_type(&self) -> Option<ast::TypeRef> {
14 support::child(self.syntax())
15 }
16}
17
18pub trait NameOwner: AstNode { 12pub trait NameOwner: AstNode {
19 fn name(&self) -> Option<ast::Name> { 13 fn name(&self) -> Option<ast::Name> {
20 support::child(self.syntax()) 14 support::child(self.syntax())
@@ -44,13 +38,13 @@ pub trait ArgListOwner: AstNode {
44} 38}
45 39
46pub trait ModuleItemOwner: AstNode { 40pub trait ModuleItemOwner: AstNode {
47 fn items(&self) -> AstChildren<ast::ModuleItem> { 41 fn items(&self) -> AstChildren<ast::Item> {
48 support::children(self.syntax()) 42 support::children(self.syntax())
49 } 43 }
50} 44}
51 45
52pub trait TypeParamsOwner: AstNode { 46pub trait GenericParamsOwner: AstNode {
53 fn type_param_list(&self) -> Option<ast::TypeParamList> { 47 fn generic_param_list(&self) -> Option<ast::GenericParamList> {
54 support::child(self.syntax()) 48 support::child(self.syntax())
55 } 49 }
56 50
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 9b7664576..6203b6206 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -42,8 +42,6 @@ use std::{marker::PhantomData, sync::Arc};
42use ra_text_edit::Indel; 42use ra_text_edit::Indel;
43use stdx::format_to; 43use stdx::format_to;
44 44
45use crate::syntax_node::GreenNode;
46
47pub use crate::{ 45pub use crate::{
48 algo::InsertPosition, 46 algo::InsertPosition,
49 ast::{AstNode, AstToken}, 47 ast::{AstNode, AstToken},
@@ -51,7 +49,7 @@ pub use crate::{
51 ptr::{AstPtr, SyntaxNodePtr}, 49 ptr::{AstPtr, SyntaxNodePtr},
52 syntax_error::SyntaxError, 50 syntax_error::SyntaxError,
53 syntax_node::{ 51 syntax_node::{
54 Direction, NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode, 52 Direction, GreenNode, NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode,
55 SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder, 53 SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder,
56 }, 54 },
57}; 55};
@@ -189,7 +187,7 @@ impl ast::Expr {
189 } 187 }
190} 188}
191 189
192impl ast::ModuleItem { 190impl ast::Item {
193 /// Returns `text`, parsed as an item, but only if it has no errors. 191 /// Returns `text`, parsed as an item, but only if it has no errors.
194 pub fn parse(text: &str) -> Result<Self, ()> { 192 pub fn parse(text: &str) -> Result<Self, ()> {
195 parsing::parse_text_fragment(text, ra_parser::FragmentKind::Item) 193 parsing::parse_text_fragment(text, ra_parser::FragmentKind::Item)
@@ -257,11 +255,11 @@ fn api_walkthrough() {
257 let mut func = None; 255 let mut func = None;
258 for item in file.items() { 256 for item in file.items() {
259 match item { 257 match item {
260 ast::ModuleItem::FnDef(f) => func = Some(f), 258 ast::Item::Fn(f) => func = Some(f),
261 _ => unreachable!(), 259 _ => unreachable!(),
262 } 260 }
263 } 261 }
264 let func: ast::FnDef = func.unwrap(); 262 let func: ast::Fn = func.unwrap();
265 263
266 // Each AST node has a bunch of getters for children. All getters return 264 // Each AST node has a bunch of getters for children. All getters return
267 // `Option`s though, to account for incomplete code. Some getters are common 265 // `Option`s though, to account for incomplete code. Some getters are common
@@ -318,7 +316,7 @@ fn api_walkthrough() {
318 ); 316 );
319 317
320 // As well as some iterator helpers: 318 // As well as some iterator helpers:
321 let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); 319 let f = expr_syntax.ancestors().find_map(ast::Fn::cast);
322 assert_eq!(f, Some(func)); 320 assert_eq!(f, Some(func));
323 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}'])); 321 assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
324 assert_eq!( 322 assert_eq!(
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index 22aed1db1..6d1828d20 100644
--- a/crates/ra_syntax/src/parsing/text_tree_sink.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -146,8 +146,8 @@ fn n_attached_trivias<'a>(
146 trivias: impl Iterator<Item = (SyntaxKind, &'a str)>, 146 trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
147) -> usize { 147) -> usize {
148 match kind { 148 match kind {
149 MACRO_CALL | CONST_DEF | TYPE_ALIAS_DEF | STRUCT_DEF | ENUM_DEF | ENUM_VARIANT | FN_DEF 149 MACRO_CALL | CONST | TYPE_ALIAS | STRUCT | ENUM | VARIANT | FN | TRAIT | MODULE
150 | TRAIT_DEF | MODULE | RECORD_FIELD_DEF | STATIC_DEF => { 150 | RECORD_FIELD | STATIC => {
151 let mut res = 0; 151 let mut res = 0;
152 let mut trivias = trivias.enumerate().peekable(); 152 let mut trivias = trivias.enumerate().peekable();
153 153
@@ -160,7 +160,10 @@ fn n_attached_trivias<'a>(
160 if let Some((peek_kind, peek_text)) = 160 if let Some((peek_kind, peek_text)) =
161 trivias.peek().map(|(_, pair)| pair) 161 trivias.peek().map(|(_, pair)| pair)
162 { 162 {
163 if *peek_kind == COMMENT && peek_text.starts_with("///") { 163 if *peek_kind == COMMENT
164 && peek_text.starts_with("///")
165 && !peek_text.starts_with("////")
166 {
164 continue; 167 continue;
165 } 168 }
166 } 169 }
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index 62f03e93d..ca7957747 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -98,7 +98,7 @@ fn test_local_syntax_ptr() {
98 use crate::{ast, AstNode, SourceFile}; 98 use crate::{ast, AstNode, SourceFile};
99 99
100 let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap(); 100 let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
101 let field = file.syntax().descendants().find_map(ast::RecordFieldDef::cast).unwrap(); 101 let field = file.syntax().descendants().find_map(ast::RecordField::cast).unwrap();
102 let ptr = SyntaxNodePtr::new(field.syntax()); 102 let ptr = SyntaxNodePtr::new(field.syntax());
103 let field_syntax = ptr.to_node(file.syntax()); 103 let field_syntax = ptr.to_node(file.syntax());
104 assert_eq!(field.syntax(), &field_syntax); 104 assert_eq!(field.syntax(), &field_syntax);
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 9650b8781..a7dbdba7b 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -10,7 +10,9 @@ use rowan::{GreenNodeBuilder, Language};
10 10
11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize}; 11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextSize};
12 12
13pub(crate) use rowan::{GreenNode, GreenToken}; 13pub use rowan::GreenNode;
14
15pub(crate) use rowan::GreenToken;
14 16
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum RustLanguage {} 18pub enum RustLanguage {}
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index 959967b79..68cee8914 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -1,9 +1,12 @@
1use std::{ 1use std::{
2 fmt::Write, 2 fmt::Write,
3 path::{Component, Path, PathBuf}, 3 fs,
4 path::{Path, PathBuf},
4}; 5};
5 6
6use test_utils::{collect_rust_files, dir_tests, project_dir, read_text}; 7use expect::expect_file;
8use rayon::prelude::*;
9use test_utils::project_dir;
7 10
8use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token}; 11use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token};
9 12
@@ -86,7 +89,7 @@ fn item_parser_tests() {
86 fragment_parser_dir_test( 89 fragment_parser_dir_test(
87 &["parser/fragments/item/ok"], 90 &["parser/fragments/item/ok"],
88 &["parser/fragments/item/err"], 91 &["parser/fragments/item/err"],
89 crate::ast::ModuleItem::parse, 92 crate::ast::Item::parse,
90 ); 93 );
91} 94}
92 95
@@ -119,33 +122,43 @@ fn reparse_fuzz_tests() {
119/// FIXME: Use this as a benchmark 122/// FIXME: Use this as a benchmark
120#[test] 123#[test]
121fn self_hosting_parsing() { 124fn self_hosting_parsing() {
122 use std::ffi::OsStr;
123 let dir = project_dir().join("crates"); 125 let dir = project_dir().join("crates");
124 let mut count = 0; 126 let files = walkdir::WalkDir::new(dir)
125 for entry in walkdir::WalkDir::new(dir)
126 .into_iter() 127 .into_iter()
127 .filter_entry(|entry| { 128 .filter_entry(|entry| {
128 !entry.path().components().any(|component| { 129 // Get all files which are not in the crates/ra_syntax/test_data folder
129 // Get all files which are not in the crates/ra_syntax/test_data folder 130 !entry.path().components().any(|component| component.as_os_str() == "test_data")
130 component == Component::Normal(OsStr::new("test_data"))
131 })
132 }) 131 })
133 .map(|e| e.unwrap()) 132 .map(|e| e.unwrap())
134 .filter(|entry| { 133 .filter(|entry| {
135 // Get all `.rs ` files 134 // Get all `.rs ` files
136 !entry.path().is_dir() && (entry.path().extension() == Some(OsStr::new("rs"))) 135 !entry.path().is_dir() && (entry.path().extension().unwrap_or_default() == "rs")
137 }) 136 })
138 { 137 .map(|entry| entry.into_path())
139 count += 1; 138 .collect::<Vec<_>>();
140 let text = read_text(entry.path());
141 if let Err(errors) = SourceFile::parse(&text).ok() {
142 panic!("Parsing errors:\n{:?}\n{}\n", errors, entry.path().display());
143 }
144 }
145 assert!( 139 assert!(
146 count > 30, 140 files.len() > 100,
147 "self_hosting_parsing found too few files - is it running in the right directory?" 141 "self_hosting_parsing found too few files - is it running in the right directory?"
148 ) 142 );
143
144 let errors = files
145 .into_par_iter()
146 .filter_map(|file| {
147 let text = read_text(&file);
148 match SourceFile::parse(&text).ok() {
149 Ok(_) => None,
150 Err(err) => Some((file, err)),
151 }
152 })
153 .collect::<Vec<_>>();
154
155 if !errors.is_empty() {
156 let errors = errors
157 .into_iter()
158 .map(|(path, err)| format!("{}: {:?}\n", path.display(), err))
159 .collect::<String>();
160 panic!("Parsing errors:\n{}\n", errors);
161 }
149} 162}
150 163
151fn test_data_dir() -> PathBuf { 164fn test_data_dir() -> PathBuf {
@@ -200,3 +213,68 @@ where
200 } 213 }
201 }); 214 });
202} 215}
216
217/// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir`
218/// subdirectories defined by `paths`.
219///
220/// If the content of the matching output file differs from the output of `f()`
221/// the test will fail.
222///
223/// If there is no matching output file it will be created and filled with the
224/// output of `f()`, but the test will fail.
225fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F)
226where
227 F: Fn(&str, &Path) -> String,
228{
229 for (path, input_code) in collect_rust_files(test_data_dir, paths) {
230 let actual = f(&input_code, &path);
231 let path = path.with_extension(outfile_extension);
232 expect_file![path].assert_eq(&actual)
233 }
234}
235
236/// Collects all `.rs` files from `dir` subdirectories defined by `paths`.
237fn collect_rust_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
238 paths
239 .iter()
240 .flat_map(|path| {
241 let path = root_dir.to_owned().join(path);
242 rust_files_in_dir(&path).into_iter()
243 })
244 .map(|path| {
245 let text = read_text(&path);
246 (path, text)
247 })
248 .collect()
249}
250
251/// Collects paths to all `.rs` files from `dir` in a sorted `Vec<PathBuf>`.
252fn rust_files_in_dir(dir: &Path) -> Vec<PathBuf> {
253 let mut acc = Vec::new();
254 for file in fs::read_dir(&dir).unwrap() {
255 let file = file.unwrap();
256 let path = file.path();
257 if path.extension().unwrap_or_default() == "rs" {
258 acc.push(path);
259 }
260 }
261 acc.sort();
262 acc
263}
264
265/// Read file and normalize newlines.
266///
267/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
268///
269/// ```
270/// let s = "
271/// ";
272/// assert_eq!(s.as_bytes(), &[10]);
273/// ```
274///
275/// so this should always be correct.
276fn read_text(path: &Path) -> String {
277 fs::read_to_string(path)
278 .unwrap_or_else(|_| panic!("File at {:?} should be valid", path))
279 .replace("\r\n", "\n")
280}
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index fdec48fb0..0325ab0b4 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -4,7 +4,7 @@ mod block;
4 4
5use crate::{ 5use crate::{
6 ast, match_ast, AstNode, SyntaxError, 6 ast, match_ast, AstNode, SyntaxError,
7 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, 7 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS},
8 SyntaxNode, SyntaxToken, TextSize, T, 8 SyntaxNode, SyntaxToken, TextSize, T,
9}; 9};
10use rustc_lexer::unescape::{ 10use rustc_lexer::unescape::{
@@ -91,7 +91,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
91 ast::Literal(it) => validate_literal(it, &mut errors), 91 ast::Literal(it) => validate_literal(it, &mut errors),
92 ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors), 92 ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
93 ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors), 93 ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
94 ast::RecordField(it) => validate_numeric_name(it.name_ref(), &mut errors), 94 ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
95 ast::Visibility(it) => validate_visibility(it, &mut errors), 95 ast::Visibility(it) => validate_visibility(it, &mut errors),
96 ast::RangeExpr(it) => validate_range_expr(it, &mut errors), 96 ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
97 ast::PathSegment(it) => validate_path_keywords(it, &mut errors), 97 ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
@@ -200,11 +200,11 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
200 None => return, 200 None => return,
201 }; 201 };
202 match parent.kind() { 202 match parent.kind() {
203 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (), 203 FN | CONST | TYPE_ALIAS => (),
204 _ => return, 204 _ => return,
205 } 205 }
206 206
207 let impl_def = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplDef::cast) { 207 let impl_def = match parent.parent().and_then(|it| it.parent()).and_then(ast::Impl::cast) {
208 Some(it) => it, 208 Some(it) => it,
209 None => return, 209 None => return,
210 }; 210 };
diff --git a/crates/ra_syntax/src/validation/block.rs b/crates/ra_syntax/src/validation/block.rs
index 2c08f7e6e..ad9901468 100644
--- a/crates/ra_syntax/src/validation/block.rs
+++ b/crates/ra_syntax/src/validation/block.rs
@@ -9,7 +9,7 @@ use crate::{
9pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) { 9pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
10 if let Some(parent) = block.syntax().parent() { 10 if let Some(parent) = block.syntax().parent() {
11 match parent.kind() { 11 match parent.kind() {
12 FN_DEF | EXPR_STMT | BLOCK_EXPR => return, 12 FN | EXPR_STMT | BLOCK_EXPR => return,
13 _ => {} 13 _ => {}
14 } 14 }
15 } 15 }
diff --git a/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast b/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast
index 81f0f575c..bbbf496c8 100644
--- a/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast
+++ b/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..34 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..21 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "a" 13 [email protected] "a"
14 [email protected] ":" 14 [email protected] ":"
@@ -19,7 +19,7 @@ [email protected]
19 [email protected] 19 [email protected]
20 [email protected] "u32" 20 [email protected] "u32"
21 [email protected] "\n " 21 [email protected] "\n "
22 RECORD_FIELD_DEF@26..32 22 [email protected]
23 [email protected] 23 [email protected]
24 [email protected] "b" 24 [email protected] "b"
25 [email protected] ":" 25 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast b/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast
index 97d0fe910..6dc73bfdb 100644
--- a/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast
+++ b/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast
@@ -5,13 +5,13 @@ [email protected]
5 [email protected] 5 [email protected]
6 [email protected] "match" 6 [email protected] "match"
7 [email protected] "\n\n" 7 [email protected] "\n\n"
8 STRUCT_DEF@10..21 8 [email protected]
9 [email protected] "struct" 9 [email protected] "struct"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 [email protected]
12 [email protected] "S" 12 [email protected] "S"
13 [email protected] " " 13 [email protected] " "
14 RECORD_FIELD_DEF_[email protected] 14 [email protected]
15 [email protected] "{" 15 [email protected] "{"
16 [email protected] "}" 16 [email protected] "}"
17error 0..0: expected an item 17error 0..0: expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
index 6717995e9..4cfd1bce4 100644
--- a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast
@@ -6,7 +6,7 @@ [email protected]
6 [email protected] "!" 6 [email protected] "!"
7 [email protected] 7 [email protected]
8 [email protected] "/" 8 [email protected] "/"
9 USE_ITEM@24..28 9 [email protected]
10 [email protected] "use" 10 [email protected] "use"
11 [email protected] 11 [email protected]
12 [email protected] "/" 12 [email protected] "/"
diff --git a/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast b/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast
index 21c255698..7763fad84 100644
--- a/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast
+++ b/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..39 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..21 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "a" 13 [email protected] "a"
14 [email protected] ":" 14 [email protected] ":"
@@ -20,7 +20,7 @@ [email protected]
20 [email protected] "i32" 20 [email protected] "i32"
21 [email protected] "," 21 [email protected] ","
22 [email protected] "\n " 22 [email protected] "\n "
23 RECORD_FIELD_DEF@27..36 23 [email protected]
24 [email protected] 24 [email protected]
25 [email protected] "b" 25 [email protected] "b"
26 [email protected] ":" 26 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
index b3bcf472a..9a0f4665e 100644
--- a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
+++ b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..12 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast b/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast
index 375ed45e0..4845a6563 100644
--- a/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast
+++ b/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..31 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast b/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast
index 2d6364998..5f85c3943 100644
--- a/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast
+++ b/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..73 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..21 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "f" 13 [email protected] "f"
14 [email protected] ":" 14 [email protected] ":"
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] 35 [email protected]
36 [email protected] "*" 36 [email protected] "*"
37 [email protected] "\n " 37 [email protected] "\n "
38 RECORD_FIELD_DEF@48..58 38 [email protected]
39 [email protected] 39 [email protected]
40 [email protected] "pub" 40 [email protected] "pub"
41 [email protected] " " 41 [email protected] " "
@@ -50,7 +50,7 @@ [email protected]
50 [email protected] "u32" 50 [email protected] "u32"
51 [email protected] "," 51 [email protected] ","
52 [email protected] "\n " 52 [email protected] "\n "
53 RECORD_FIELD_DEF@64..70 53 [email protected]
54 [email protected] 54 [email protected]
55 [email protected] "z" 55 [email protected] "z"
56 [email protected] ":" 56 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast b/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast
index b72c92c33..560bfd751 100644
--- a/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast
+++ b/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast
@@ -2,7 +2,7 @@ [email protected]
2 [email protected] 2 [email protected]
3 [email protected] "}" 3 [email protected] "}"
4 [email protected] "\n\n" 4 [email protected] "\n\n"
5 STRUCT_DEF@3..12 5 [email protected]
6 [email protected] "struct" 6 [email protected] "struct"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n\n" 14 [email protected] "\n\n"
15 FN_DEF@17..27 15 [email protected]
16 [email protected] "fn" 16 [email protected] "fn"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast b/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast
index 33953d8d7..1e9637c26 100644
--- a/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast
+++ b/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..12 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -58,7 +58,7 @@ [email protected]
58 [email protected] "\n" 58 [email protected] "\n"
59 [email protected] "}" 59 [email protected] "}"
60 [email protected] "\n\n" 60 [email protected] "\n\n"
61 FN_DEF@82..94 61 [email protected]
62 [email protected] "fn" 62 [email protected] "fn"
63 [email protected] " " 63 [email protected] " "
64 [email protected] 64 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast b/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast
index aca02ece4..dacf71aa1 100644
--- a/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast
+++ b/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..11 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] "90" 10 [email protected] "90"
@@ -38,7 +38,7 @@ [email protected]
38 [email protected] "\n" 38 [email protected] "\n"
39 [email protected] "}" 39 [email protected] "}"
40 [email protected] "\n\n" 40 [email protected] "\n\n"
41 STRUCT_DEF@33..42 41 [email protected]
42 [email protected] "struct" 42 [email protected] "struct"
43 [email protected] " " 43 [email protected] " "
44 [email protected] 44 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
index 3bf57eacc..1c3e0f65b 100644
--- a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
+++ b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..41 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast b/crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast
index 87c54c32c..b02d390af 100644
--- a/crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast
+++ b/crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast
@@ -3,7 +3,7 @@ [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "extern" 4 [email protected] "extern"
5 [email protected] " " 5 [email protected] " "
6 STRUCT_DEF@7..18 6 [email protected]
7 [email protected] "struct" 7 [email protected] "struct"
8 [email protected] " " 8 [email protected] " "
9 [email protected] 9 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast b/crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast
index e1e782f5f..d62906b99 100644
--- a/crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast
+++ b/crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..389 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] 4 [email protected]
5 [email protected] 5 [email protected]
@@ -10,7 +10,7 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "process" 12 [email protected] "process"
13 TYP[email protected] 13 GENERIC[email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "'a" 16 [email protected] "'a"
diff --git a/crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast b/crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast
index 211e5fd46..3eef848fc 100644
--- a/crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast
+++ b/crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..72 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "pub" 4 [email protected] "pub"
5 [email protected] " " 5 [email protected] " "
@@ -7,10 +7,10 @@ [email protected]
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 [email protected]
9 [email protected] "Cache" 9 [email protected] "Cache"
10 TUPLE_FIELD_DEF_[email protected] 10 [email protected]
11 [email protected] "(" 11 [email protected] "("
12 [email protected] "\n " 12 [email protected] "\n "
13 TUPLE_FIELD_DEF@22..68 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
@@ -47,7 +47,7 @@ [email protected]
47 [email protected] 47 [email protected]
48 [email protected] "@" 48 [email protected] "@"
49 [email protected] " " 49 [email protected] " "
50 TUPLE_FIELD_DEF@69..72 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
53 [email protected] 53 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast b/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast
index 9323b7890..a1f39b22a 100644
--- a/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast
+++ b/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..22 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "foo" 6 [email protected] "foo"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast b/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast
index b18378cff..a3c25b450 100644
--- a/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast
+++ b/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..7 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast b/crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast
index 93434f34f..66157c3dc 100644
--- a/crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast
+++ b/crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..55 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast b/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast
index 628315c78..bb4a28f4e 100644
--- a/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast
+++ b/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..46 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast b/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast
index 31cc4e551..bc95b8512 100644
--- a/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast
+++ b/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..182 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "FnScopes" 9 [email protected] "FnScopes"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@20..161 14 [email protected]
15 [email protected] "fn" 15 [email protected] "fn"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -75,16 +75,16 @@ [email protected]
75 [email protected] "push" 75 [email protected] "push"
76 [email protected] 76 [email protected]
77 [email protected] "(" 77 [email protected] "("
78 RECORD_LIT@111..154 78 RECORD_EXPR@111..154
79 [email protected] 79 [email protected]
80 [email protected] 80 [email protected]
81 [email protected] 81 [email protected]
82 [email protected] "ScopeData" 82 [email protected] "ScopeData"
83 [email protected] " " 83 [email protected] " "
84 [email protected] 84 RECORD_EXPR_[email protected]
85 [email protected] "{" 85 [email protected] "{"
86 [email protected] " " 86 [email protected] " "
87 [email protected] 87 RECORD_EXPR_[email protected]
88 [email protected] 88 [email protected]
89 [email protected] "parent" 89 [email protected] "parent"
90 [email protected] ":" 90 [email protected] ":"
@@ -96,7 +96,7 @@ [email protected]
96 [email protected] "None" 96 [email protected] "None"
97 [email protected] "," 97 [email protected] ","
98 [email protected] " " 98 [email protected] " "
99 [email protected] 99 RECORD_EXPR_[email protected]
100 [email protected] 100 [email protected]
101 [email protected] "entries" 101 [email protected] "entries"
102 [email protected] ":" 102 [email protected] ":"
@@ -116,7 +116,7 @@ [email protected]
116 [email protected] "\n " 116 [email protected] "\n "
117 [email protected] "}" 117 [email protected] "}"
118 [email protected] "\n\n " 118 [email protected] "\n\n "
119 FN_DEF@167..180 119 [email protected]
120 [email protected] "fn" 120 [email protected] "fn"
121 [email protected] " " 121 [email protected] " "
122 [email protected] 122 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0019_let_recover.rast b/crates/ra_syntax/test_data/parser/err/0019_let_recover.rast
index 4ff27f5c8..f6fa964b7 100644
--- a/crates/ra_syntax/test_data/parser/err/0019_let_recover.rast
+++ b/crates/ra_syntax/test_data/parser/err/0019_let_recover.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..138 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast b/crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast
index 5f3a31473..6f6feba5a 100644
--- a/crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast
+++ b/crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast
@@ -1,8 +1,8 @@
1[email protected] 1[email protected]
2 FN_DEF@0..2 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] "\n\n" 4 [email protected] "\n\n"
5 FN_DEF@4..15 5 [email protected]
6 [email protected] "fn" 6 [email protected] "fn"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast b/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast
index 1746bd3c1..ba4ce4795 100644
--- a/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast
+++ b/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..21 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast b/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast
index 28146f44e..71fb19783 100644
--- a/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast
+++ b/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..33 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -28,7 +28,7 @@ [email protected]
28 [email protected] 28 [email protected]
29 [email protected] "," 29 [email protected] ","
30 [email protected] " " 30 [email protected] " "
31 STRUCT_DEF@19..26 31 [email protected]
32 [email protected] "struct" 32 [email protected] "struct"
33 [email protected] 33 [email protected]
34 [email protected] "," 34 [email protected] ","
@@ -40,7 +40,7 @@ [email protected]
40 [email protected] " " 40 [email protected] " "
41 [email protected] "}" 41 [email protected] "}"
42 [email protected] "\n" 42 [email protected] "\n"
43 FN_DEF@34..68 43 [email protected]
44 [email protected] "fn" 44 [email protected] "fn"
45 [email protected] " " 45 [email protected] " "
46 [email protected] 46 [email protected]
@@ -75,7 +75,7 @@ [email protected]
75 [email protected] 75 [email protected]
76 [email protected] "," 76 [email protected] ","
77 [email protected] " " 77 [email protected] " "
78 IMPL_DEF@56..60 78 [email protected]
79 [email protected] "impl" 79 [email protected] "impl"
80 [email protected] 80 [email protected]
81 [email protected] 81 [email protected]
@@ -88,7 +88,7 @@ [email protected]
88 [email protected] " " 88 [email protected] " "
89 [email protected] "}" 89 [email protected] "}"
90 [email protected] "\n" 90 [email protected] "\n"
91 FN_DEF@69..111 91 [email protected]
92 [email protected] "fn" 92 [email protected] "fn"
93 [email protected] " " 93 [email protected] " "
94 [email protected] 94 [email protected]
@@ -133,7 +133,7 @@ [email protected]
133 [email protected] 133 [email protected]
134 [email protected] "," 134 [email protected] ","
135 [email protected] " " 135 [email protected] " "
136 TRAIT_DEF@98..104 136 [email protected]
137 [email protected] "trait" 137 [email protected] "trait"
138 [email protected] 138 [email protected]
139 [email protected] "," 139 [email protected] ","
diff --git a/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast b/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast
index 9ea9d715e..5ffefd742 100644
--- a/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast
+++ b/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..55 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast
index 48610a5eb..4c2d1ad68 100644
--- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast
+++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..53 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "f" 6 [email protected] "f"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -39,7 +39,7 @@ [email protected]
39 [email protected] "(" 39 [email protected] "("
40 [email protected] 40 [email protected]
41 [email protected] "for" 41 [email protected] "for"
42 TYP[email protected] 42 GENERIC[email protected]
43 [email protected] "<" 43 [email protected] "<"
44 [email protected] 44 [email protected]
45 [email protected] "\'a" 45 [email protected] "\'a"
@@ -65,7 +65,7 @@ [email protected]
65 [email protected] "{" 65 [email protected] "{"
66 [email protected] "}" 66 [email protected] "}"
67 [email protected] "\n\n" 67 [email protected] "\n\n"
68 FN_DEF@55..239 68 [email protected]
69 [email protected] "fn" 69 [email protected] "fn"
70 [email protected] " " 70 [email protected] " "
71 [email protected] 71 [email protected]
@@ -122,7 +122,7 @@ [email protected]
122 [email protected] "(" 122 [email protected] "("
123 [email protected] 123 [email protected]
124 [email protected] "for" 124 [email protected] "for"
125 TYP[email protected] 125 GENERIC[email protected]
126 [email protected] "<" 126 [email protected] "<"
127 [email protected] 127 [email protected]
128 [email protected] "\'a" 128 [email protected] "\'a"
@@ -242,7 +242,7 @@ [email protected]
242 [email protected] "(" 242 [email protected] "("
243 [email protected] 243 [email protected]
244 [email protected] "for" 244 [email protected] "for"
245 TYP[email protected] 245 GENERIC[email protected]
246 [email protected] "<" 246 [email protected] "<"
247 [email protected] 247 [email protected]
248 [email protected] "\'a" 248 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/err/0025_nope.rast b/crates/ra_syntax/test_data/parser/err/0025_nope.rast
index 88b086daf..fca646557 100644
--- a/crates/ra_syntax/test_data/parser/err/0025_nope.rast
+++ b/crates/ra_syntax/test_data/parser/err/0025_nope.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..574 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,26 +11,26 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 ENUM_DEF@16..152 14 [email protected]
15 [email protected] "enum" 15 [email protected] "enum"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
18 [email protected] "Test" 18 [email protected] "Test"
19 [email protected] " " 19 [email protected] " "
20 ENUM_[email protected] 20 [email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] "\n " 22 [email protected] "\n "
23 ENUM_[email protected] 23 [email protected]
24 [email protected] 24 [email protected]
25 [email protected] "Var1" 25 [email protected] "Var1"
26 [email protected] "," 26 [email protected] ","
27 [email protected] "\n " 27 [email protected] "\n "
28 ENUM_[email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "Var2" 30 [email protected] "Var2"
31 TUPLE_FIELD_DEF_[email protected] 31 [email protected]
32 [email protected] "(" 32 [email protected] "("
33 TUPLE_FIELD_DEF@55..61 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] 35 [email protected]
36 [email protected] 36 [email protected]
@@ -39,14 +39,14 @@ [email protected]
39 [email protected] ")" 39 [email protected] ")"
40 [email protected] "," 40 [email protected] ","
41 [email protected] "\n " 41 [email protected] "\n "
42 ENUM_[email protected] 42 [email protected]
43 [email protected] 43 [email protected]
44 [email protected] "Var3" 44 [email protected] "Var3"
45 [email protected] " " 45 [email protected] " "
46 RECORD_FIELD_DEF_[email protected] 46 [email protected]
47 [email protected] "{" 47 [email protected] "{"
48 [email protected] "\n " 48 [email protected] "\n "
49 RECORD_FIELD_DEF@91..95 49 [email protected]
50 [email protected] 50 [email protected]
51 [email protected] "abc" 51 [email protected] "abc"
52 [email protected] ":" 52 [email protected] ":"
@@ -79,39 +79,39 @@ [email protected]
79 [email protected] "1" 79 [email protected] "1"
80 [email protected] ";" 80 [email protected] ";"
81 [email protected] "\n " 81 [email protected] "\n "
82 ENUM_DEF@191..223 82 [email protected]
83 [email protected] "enum" 83 [email protected] "enum"
84 [email protected] " " 84 [email protected] " "
85 [email protected] 85 [email protected]
86 [email protected] "Test2" 86 [email protected] "Test2"
87 [email protected] " " 87 [email protected] " "
88 ENUM_[email protected] 88 [email protected]
89 [email protected] "{" 89 [email protected] "{"
90 [email protected] "\n " 90 [email protected] "\n "
91 ENUM_[email protected] 91 [email protected]
92 [email protected] 92 [email protected]
93 [email protected] "Fine" 93 [email protected] "Fine"
94 [email protected] "," 94 [email protected] ","
95 [email protected] "\n " 95 [email protected] "\n "
96 [email protected] "}" 96 [email protected] "}"
97 [email protected] "\n\n " 97 [email protected] "\n\n "
98 ENUM_DEF@229..300 98 [email protected]
99 [email protected] "enum" 99 [email protected] "enum"
100 [email protected] " " 100 [email protected] " "
101 [email protected] 101 [email protected]
102 [email protected] "Test3" 102 [email protected] "Test3"
103 [email protected] " " 103 [email protected] " "
104 ENUM_[email protected] 104 [email protected]
105 [email protected] "{" 105 [email protected] "{"
106 [email protected] "\n " 106 [email protected] "\n "
107 ENUM_[email protected] 107 [email protected]
108 [email protected] 108 [email protected]
109 [email protected] "StillFine" 109 [email protected] "StillFine"
110 [email protected] " " 110 [email protected] " "
111 RECORD_FIELD_DEF_[email protected] 111 [email protected]
112 [email protected] "{" 112 [email protected] "{"
113 [email protected] "\n " 113 [email protected] "\n "
114 RECORD_FIELD_DEF@274..282 114 [email protected]
115 [email protected] 115 [email protected]
116 [email protected] "def" 116 [email protected] "def"
117 [email protected] ":" 117 [email protected] ":"
@@ -132,7 +132,7 @@ [email protected]
132 [email protected] 132 [email protected]
133 [email protected] "{" 133 [email protected] "{"
134 [email protected] "\n " 134 [email protected] "\n "
135 ENUM_DEF@316..453 135 [email protected]
136 [email protected] "// fail again" 136 [email protected] "// fail again"
137 [email protected] "\n " 137 [email protected] "\n "
138 [email protected] "enum" 138 [email protected] "enum"
@@ -140,15 +140,15 @@ [email protected]
140 [email protected] 140 [email protected]
141 [email protected] "Test4" 141 [email protected] "Test4"
142 [email protected] " " 142 [email protected] " "
143 ENUM_[email protected] 143 [email protected]
144 [email protected] "{" 144 [email protected] "{"
145 [email protected] "\n " 145 [email protected] "\n "
146 ENUM_[email protected] 146 [email protected]
147 [email protected] 147 [email protected]
148 [email protected] "Nope" 148 [email protected] "Nope"
149 TUPLE_FIELD_DEF_[email protected] 149 [email protected]
150 [email protected] "(" 150 [email protected] "("
151 TUPLE_FIELD_DEF@368..371 151 [email protected]
152 [email protected] 152 [email protected]
153 [email protected] 153 [email protected]
154 [email protected] 154 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast b/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast
index bf07409fb..7e4b11c27 100644
--- a/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast
+++ b/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast
@@ -1,7 +1,7 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..14 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 TYP[email protected] 4 GENERIC[email protected]
5 [email protected] "<" 5 [email protected] "<"
6 [email protected] 6 [email protected]
7 [email protected] 7 [email protected]
@@ -17,9 +17,9 @@ [email protected]
17 [email protected] "Clone" 17 [email protected] "Clone"
18 [email protected] ">" 18 [email protected] ">"
19 [email protected] "\n" 19 [email protected] "\n"
20 IMPL_DEF@15..37 20 [email protected]
21 [email protected] "impl" 21 [email protected] "impl"
22 TYP[email protected] 22 GENERIC[email protected]
23 [email protected] "<" 23 [email protected] "<"
24 [email protected] 24 [email protected]
25 [email protected] 25 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "T" 41 [email protected] "T"
42 [email protected] ">" 42 [email protected] ">"
43 [email protected] " " 43 [email protected] " "
44 [email protected] 44 ASSOC_[email protected]
45 [email protected] "{" 45 [email protected] "{"
46 [email protected] "}" 46 [email protected] "}"
47 [email protected] "\n" 47 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast
index 4d6461d1e..a8e42e6ea 100644
--- a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast
+++ b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..29 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -13,7 +13,7 @@ [email protected]
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
15 [email protected] "for" 15 [email protected] "for"
16 TYP[email protected] 16 GENERIC[email protected]
17 [email protected] "<" 17 [email protected] "<"
18 [email protected] 18 [email protected]
19 [email protected] "\'a" 19 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/err/0029_field_completion.rast b/crates/ra_syntax/test_data/parser/err/0029_field_completion.rast
index 0da8f59f0..bfcd0149e 100644
--- a/crates/ra_syntax/test_data/parser/err/0029_field_completion.rast
+++ b/crates/ra_syntax/test_data/parser/err/0029_field_completion.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..23 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast b/crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast
index 515819e42..55ff3943f 100644
--- a/crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..349 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast b/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
index c6859eca8..ec9f556aa 100644
--- a/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..292 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast b/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
index 53e445459..063532e02 100644
--- a/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..88 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast
index 1b2ac5011..303a49576 100644
--- a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast
+++ b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..89 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
index 9588cf3b3..2f03709eb 100644
--- a/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
+++ b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..13 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -14,10 +14,10 @@ [email protected]
14 [email protected] "bar" 14 [email protected] "bar"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 USE_ITEM@14..17 17 [email protected]
18 [email protected] "use" 18 [email protected] "use"
19 [email protected] "\n" 19 [email protected] "\n"
20 USE_ITEM@18..33 20 [email protected]
21 [email protected] "use" 21 [email protected] "use"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 [email protected]
@@ -31,10 +31,10 @@ [email protected]
31 [email protected] "baz" 31 [email protected] "baz"
32 [email protected] ";" 32 [email protected] ";"
33 [email protected] "\n" 33 [email protected] "\n"
34 USE_ITEM@34..37 34 [email protected]
35 [email protected] "use" 35 [email protected] "use"
36 [email protected] "\n" 36 [email protected] "\n"
37 FN_DEF@38..47 37 [email protected]
38 [email protected] "fn" 38 [email protected] "fn"
39 [email protected] " " 39 [email protected] " "
40 [email protected] 40 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
index f926b67d2..ef6172f8a 100644
--- a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
+++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..36 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast
index e3cda7c43..faf87d6e5 100644
--- a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast
+++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..117 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -14,10 +14,10 @@ [email protected]
14 [email protected] "(" 14 [email protected] "("
15 [email protected] ")" 15 [email protected] ")"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 ASSOC_[email protected]
18 [email protected] "{" 18 [email protected] "{"
19 [email protected] "\n " 19 [email protected] "\n "
20 FN_DEF@20..31 20 [email protected]
21 [email protected] "fn" 21 [email protected] "fn"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 [email protected]
@@ -30,7 +30,7 @@ [email protected]
30 [email protected] "{" 30 [email protected] "{"
31 [email protected] "}" 31 [email protected] "}"
32 [email protected] "\n " 32 [email protected] "\n "
33 FN_DEF@36..51 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "pub" 35 [email protected] "pub"
36 [email protected] " " 36 [email protected] " "
@@ -46,7 +46,7 @@ [email protected]
46 [email protected] "{" 46 [email protected] "{"
47 [email protected] "}" 47 [email protected] "}"
48 [email protected] "\n " 48 [email protected] "\n "
49 TYPE_ALIAS_DEF@56..81 49 [email protected]
50 [email protected] 50 [email protected]
51 [email protected] "pub" 51 [email protected] "pub"
52 [email protected] "(" 52 [email protected] "("
@@ -65,7 +65,7 @@ [email protected]
65 [email protected] ")" 65 [email protected] ")"
66 [email protected] ";" 66 [email protected] ";"
67 [email protected] "\n " 67 [email protected] "\n "
68 CONST_DEF@86..115 68 [email protected]
69 [email protected] 69 [email protected]
70 [email protected] "pub" 70 [email protected] "pub"
71 [email protected] "(" 71 [email protected] "("
diff --git a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast
index 21db9ee85..bed7ad6c3 100644
--- a/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast
+++ b/crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..32 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast
index ec950381b..a98c31b0c 100644
--- a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..82 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
index d2a549273..284c8715b 100644
--- a/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0040_illegal_crate_kw_location.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..12 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] "crate" 9 [email protected] "crate"
10 [email protected] ";" 10 [email protected] ";"
11 [email protected] "\n" 11 [email protected] "\n"
12 USE_ITEM@13..54 12 [email protected]
13 [email protected] "use" 13 [email protected] "use"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 [email protected]
@@ -52,7 +52,7 @@ [email protected]
52 [email protected] "}" 52 [email protected] "}"
53 [email protected] ";" 53 [email protected] ";"
54 [email protected] "\n" 54 [email protected] "\n"
55 USE_ITEM@55..72 55 [email protected]
56 [email protected] "use" 56 [email protected] "use"
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 [email protected]
@@ -66,7 +66,7 @@ [email protected]
66 [email protected] "crate" 66 [email protected] "crate"
67 [email protected] ";" 67 [email protected] ";"
68 [email protected] "\n" 68 [email protected] "\n"
69 USE_ITEM@73..97 69 [email protected]
70 [email protected] "use" 70 [email protected] "use"
71 [email protected] " " 71 [email protected] " "
72 [email protected] 72 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
index d0360c467..2049a9d72 100644
--- a/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0041_illegal_super_keyword_location.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..12 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] "super" 9 [email protected] "super"
10 [email protected] ";" 10 [email protected] ";"
11 [email protected] "\n" 11 [email protected] "\n"
12 USE_ITEM@13..26 12 [email protected]
13 [email protected] "use" 13 [email protected] "use"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 [email protected]
@@ -23,7 +23,7 @@ [email protected]
23 [email protected] "super" 23 [email protected] "super"
24 [email protected] ";" 24 [email protected] ";"
25 [email protected] "\n" 25 [email protected] "\n"
26 USE_ITEM@27..47 26 [email protected]
27 [email protected] "use" 27 [email protected] "use"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "super" 41 [email protected] "super"
42 [email protected] ";" 42 [email protected] ";"
43 [email protected] "\n" 43 [email protected] "\n"
44 USE_ITEM@48..66 44 [email protected]
45 [email protected] "use" 45 [email protected] "use"
46 [email protected] " " 46 [email protected] " "
47 [email protected] 47 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
index 4f382b06c..deadf56b4 100644
--- a/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
+++ b/crates/ra_syntax/test_data/parser/err/0042_illegal_self_keyword_location.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..11 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] "self" 9 [email protected] "self"
10 [email protected] ";" 10 [email protected] ";"
11 [email protected] "\n" 11 [email protected] "\n"
12 USE_ITEM@12..24 12 [email protected]
13 [email protected] "use" 13 [email protected] "use"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast
index 8eb583ef8..51ad2a846 100644
--- a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast
+++ b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast
@@ -1,11 +1,11 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..38 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "T" 6 [email protected] "T"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 ASSOC_[email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 [email protected] 11 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] 14 [email protected]
15 [email protected] "default" 15 [email protected] "default"
16 [email protected] " " 16 [email protected] " "
17 CONST_DEF@20..36 17 [email protected]
18 [email protected] "const" 18 [email protected] "const"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast
index cb90f28bc..082625c13 100644
--- a/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast
+++ b/crates/ra_syntax/test_data/parser/err/0044_unexpected_for_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..30 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 [email protected]
11 [email protected] "for" 11 [email protected] "for"
12 TYP[email protected] 12 GENERIC[email protected]
13 [email protected] "<" 13 [email protected] "<"
14 [email protected] 14 [email protected]
15 [email protected] "\'a" 15 [email protected] "\'a"
@@ -26,7 +26,7 @@ [email protected]
26 [email protected] "u32" 26 [email protected] "u32"
27 [email protected] ";" 27 [email protected] ";"
28 [email protected] "\n" 28 [email protected] "\n"
29 TYPE_ALIAS_DEF@31..64 29 [email protected]
30 [email protected] "type" 30 [email protected] "type"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
@@ -36,7 +36,7 @@ [email protected]
36 [email protected] " " 36 [email protected] " "
37 [email protected] 37 [email protected]
38 [email protected] "for" 38 [email protected] "for"
39 TYP[email protected] 39 GENERIC[email protected]
40 [email protected] "<" 40 [email protected] "<"
41 [email protected] 41 [email protected]
42 [email protected] "\'a" 42 [email protected] "\'a"
@@ -57,7 +57,7 @@ [email protected]
57 [email protected] ")" 57 [email protected] ")"
58 [email protected] ";" 58 [email protected] ";"
59 [email protected] "\n" 59 [email protected] "\n"
60 TYPE_ALIAS_DEF@65..95 60 [email protected]
61 [email protected] "type" 61 [email protected] "type"
62 [email protected] " " 62 [email protected] " "
63 [email protected] 63 [email protected]
@@ -67,7 +67,7 @@ [email protected]
67 [email protected] " " 67 [email protected] " "
68 [email protected] 68 [email protected]
69 [email protected] "for" 69 [email protected] "for"
70 TYP[email protected] 70 GENERIC[email protected]
71 [email protected] "<" 71 [email protected] "<"
72 [email protected] 72 [email protected]
73 [email protected] "\'a" 73 [email protected] "\'a"
@@ -83,7 +83,7 @@ [email protected]
83 [email protected] "]" 83 [email protected] "]"
84 [email protected] ";" 84 [email protected] ";"
85 [email protected] "\n" 85 [email protected] "\n"
86 TYPE_ALIAS_DEF@96..149 86 [email protected]
87 [email protected] "type" 87 [email protected] "type"
88 [email protected] " " 88 [email protected] " "
89 [email protected] 89 [email protected]
@@ -93,7 +93,7 @@ [email protected]
93 [email protected] " " 93 [email protected] " "
94 [email protected] 94 [email protected]
95 [email protected] "for" 95 [email protected] "for"
96 TYP[email protected] 96 GENERIC[email protected]
97 [email protected] "<" 97 [email protected] "<"
98 [email protected] 98 [email protected]
99 [email protected] "\'a" 99 [email protected] "\'a"
@@ -101,7 +101,7 @@ [email protected]
101 [email protected] " " 101 [email protected] " "
102 [email protected] 102 [email protected]
103 [email protected] "for" 103 [email protected] "for"
104 TYP[email protected] 104 GENERIC[email protected]
105 [email protected] "<" 105 [email protected] "<"
106 [email protected] 106 [email protected]
107 [email protected] "\'b" 107 [email protected] "\'b"
@@ -136,12 +136,12 @@ [email protected]
136 [email protected] ")" 136 [email protected] ")"
137 [email protected] ";" 137 [email protected] ";"
138 [email protected] "\n" 138 [email protected] "\n"
139 FN_DEF@150..238 139 [email protected]
140 [email protected] "fn" 140 [email protected] "fn"
141 [email protected] " " 141 [email protected] " "
142 [email protected] 142 [email protected]
143 [email protected] "for_for_for" 143 [email protected] "for_for_for"
144 TYP[email protected] 144 GENERIC[email protected]
145 [email protected] "<" 145 [email protected] "<"
146 [email protected] 146 [email protected]
147 [email protected] 147 [email protected]
@@ -156,7 +156,7 @@ [email protected]
156 [email protected] "\n " 156 [email protected] "\n "
157 [email protected] 157 [email protected]
158 [email protected] "for" 158 [email protected] "for"
159 TYP[email protected] 159 GENERIC[email protected]
160 [email protected] "<" 160 [email protected] "<"
161 [email protected] 161 [email protected]
162 [email protected] "\'a" 162 [email protected] "\'a"
@@ -164,7 +164,7 @@ [email protected]
164 [email protected] " " 164 [email protected] " "
165 [email protected] 165 [email protected]
166 [email protected] "for" 166 [email protected] "for"
167 TYP[email protected] 167 GENERIC[email protected]
168 [email protected] "<" 168 [email protected] "<"
169 [email protected] 169 [email protected]
170 [email protected] "\'b" 170 [email protected] "\'b"
@@ -172,7 +172,7 @@ [email protected]
172 [email protected] " " 172 [email protected] " "
173 [email protected] 173 [email protected]
174 [email protected] "for" 174 [email protected] "for"
175 TYP[email protected] 175 GENERIC[email protected]
176 [email protected] "<" 176 [email protected] "<"
177 [email protected] 177 [email protected]
178 [email protected] "\'c" 178 [email protected] "\'c"
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
index e46456384..df29017e7 100644
--- a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
+++ b/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..82 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast b/crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast
index f1e78f388..93c429e12 100644
--- a/crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast
+++ b/crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast
@@ -1,4 +1,4 @@
1FN_DEF@0..11 1[email protected]
2 [email protected] "fn" 2 [email protected] "fn"
3 [email protected] " " 3 [email protected] " "
4 [email protected] 4 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/fuzz-failures/0000.rs b/crates/ra_syntax/test_data/parser/fuzz-failures/0000.rs
index 0e6e0ccc3..f1d0dc343 100644
--- a/crates/ra_syntax/test_data/parser/fuzz-failures/0000.rs
+++ b/crates/ra_syntax/test_data/parser/fuzz-failures/0000.rs
@@ -86,7 +86,7 @@ fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(Syntax
86 fn reparser(node: SyntaxNodeRef) -> Option<fn(&mut Parser)> { 86 fn reparser(node: SyntaxNodeRef) -> Option<fn(&mut Parser)> {
87 let res = match node.kind() { 87 let res = match node.kind() {
88 BLOCK => grammar::block, 88 BLOCK => grammar::block,
89 RECORD_FIELD_DEF_LIST => grammar::record_field_def_list, 89 RECORD_FIELD_LIST => grammar::record_field_list,
90 _ => return None, 90 _ => return None,
91 }; 91 };
92 Some(res) 92 Some(res)
@@ -138,7 +138,7 @@ fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(Syntax
138 let res = match node.kind() { 138 let res = match node.kind() {
139 ; 139 ;
140 let end = u32::from(range.end()) as usize; 140 let end = u32::from(range.end()) as usize;
141 text.replaT => grammar::record_field_def_list, 141 text.replaT => grammar::record_field_list,
142 _ => return None, 142 _ => return None,
143 }; 143 };
144 Some(res) 144 Some(res)
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast b/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast
index bf70ebca4..0b9bbec07 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..12 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast b/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
index 75668c818..a4271fc87 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..29 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] "\'loop" 17 [email protected] "\'loop"
18 [email protected] ":" 18 [email protected] ":"
19 [email protected] " " 19 [email protected] " "
20 IMPL_DEF@23..27 20 [email protected]
21 [email protected] "impl" 21 [email protected] "impl"
22 [email protected] "\n" 22 [email protected] "\n"
23 [email protected] "}" 23 [email protected] "}"
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast b/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast
index 95bcc3c0a..2409eefe7 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..13 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast b/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast
index fd939be8d..29d6b3974 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..12 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,11 +8,11 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "Type" 9 [email protected] "Type"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
15 IMPL_DEF@13..33 15 [email protected]
16 [email protected] "impl" 16 [email protected] "impl"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
@@ -29,14 +29,14 @@ [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "T" 30 [email protected] "T"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 ASSOC_[email protected]
33 [email protected] "{" 33 [email protected] "{"
34 [email protected] "}" 34 [email protected] "}"
35 [email protected] "\n" 35 [email protected] "\n"
36 IMPL_DEF@34..38 36 [email protected]
37 [email protected] "impl" 37 [email protected] "impl"
38 [email protected] " " 38 [email protected] " "
39 IMPL_DEF@39..54 39 [email protected]
40 [email protected] "impl" 40 [email protected] "impl"
41 [email protected] " " 41 [email protected] " "
42 [email protected] 42 [email protected]
@@ -45,11 +45,11 @@ [email protected]
45 [email protected] 45 [email protected]
46 [email protected] "NotType" 46 [email protected] "NotType"
47 [email protected] " " 47 [email protected] " "
48 [email protected] 48 ASSOC_[email protected]
49 [email protected] "{" 49 [email protected] "{"
50 [email protected] "}" 50 [email protected] "}"
51 [email protected] "\n" 51 [email protected] "\n"
52 IMPL_DEF@55..70 52 [email protected]
53 [email protected] "impl" 53 [email protected] "impl"
54 [email protected] " " 54 [email protected] " "
55 [email protected] 55 [email protected]
@@ -60,7 +60,7 @@ [email protected]
60 [email protected] " " 60 [email protected] " "
61 [email protected] "for" 61 [email protected] "for"
62 [email protected] " " 62 [email protected] " "
63 IMPL_DEF@71..86 63 [email protected]
64 [email protected] "impl" 64 [email protected] "impl"
65 [email protected] " " 65 [email protected] " "
66 [email protected] 66 [email protected]
@@ -69,7 +69,7 @@ [email protected]
69 [email protected] 69 [email protected]
70 [email protected] "NotType" 70 [email protected] "NotType"
71 [email protected] " " 71 [email protected] " "
72 [email protected] 72 ASSOC_[email protected]
73 [email protected] "{" 73 [email protected] "{"
74 [email protected] "}" 74 [email protected] "}"
75 [email protected] "\n" 75 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast b/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast
index 90202d764..776022fd9 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..15 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast b/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast
index c789e8d82..cc0f8bcaf 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..10 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -19,7 +19,7 @@ [email protected]
19 [email protected] " " 19 [email protected] " "
20 [email protected] "}" 20 [email protected] "}"
21 [email protected] " " 21 [email protected] " "
22 FN_DEF@22..32 22 [email protected]
23 [email protected] "fn" 23 [email protected] "fn"
24 [email protected] " " 24 [email protected] " "
25 [email protected] 25 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast b/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast
index cd24313d4..3f3a7f1b9 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..29 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast b/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast
index c5fa7a404..63a10127d 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..20 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
index 4e3fa704e..8fd8d5e59 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..47 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast
index e1abc5633..fa14e1e6d 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..46 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast
index 53f7ebaf9..a6e6552a9 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast
@@ -2,7 +2,7 @@ [email protected]
2 [email protected] 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 FN_DEF@7..24 5 [email protected]
6 [email protected] "async" 6 [email protected] "async"
7 [email protected] " " 7 [email protected] " "
8 [email protected] "fn" 8 [email protected] "fn"
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] "{" 17 [email protected] "{"
18 [email protected] "}" 18 [email protected] "}"
19 [email protected] "\n" 19 [email protected] "\n"
20 CONST_DEF@25..46 20 [email protected]
21 [email protected] "unsafe" 21 [email protected] "unsafe"
22 [email protected] " " 22 [email protected] " "
23 [email protected] "const" 23 [email protected] "const"
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast b/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast
index ebcc26e0d..8d761b907 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 STATIC_DEF@0..18 2 [email protected]
3 [email protected] "static" 3 [email protected] "static"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast
index b8cd0587d..acd72094b 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast
@@ -1,11 +1,11 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..61 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "T" 6 [email protected] "T"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 ASSOC_[email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 [email protected] 11 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] 14 [email protected]
15 [email protected] "default" 15 [email protected] "default"
16 [email protected] " " 16 [email protected] " "
17 TYPE_ALIAS_DEF@22..35 17 [email protected]
18 [email protected] "type" 18 [email protected] "type"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] 35 [email protected]
36 [email protected] "default" 36 [email protected] "default"
37 [email protected] " " 37 [email protected] " "
38 FN_DEF@48..59 38 [email protected]
39 [email protected] "fn" 39 [email protected] "fn"
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
index a9de44b57..a81c442c0 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..44 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,16 +11,16 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 RECORD_LIT@16..42 14 RECORD_EXPR@16..42
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "S" 18 [email protected] "S"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 RECORD_EXPR_[email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 RECORD_EXPR_[email protected]
24 [email protected] 24 [email protected]
25 [email protected] "field" 25 [email protected] "field"
26 [email protected] " " 26 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast b/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
index da8505607..2f59d0606 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
+++ b/crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..12 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast
index a38b4f573..c7289e400 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..82 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "F" 9 [email protected] "F"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 TYPE_ALIAS_DEF@13..27 14 [email protected]
15 [email protected] "type" 15 [email protected] "type"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -27,7 +27,7 @@ [email protected]
27 [email protected] "Clone" 27 [email protected] "Clone"
28 [email protected] ";" 28 [email protected] ";"
29 [email protected] "\n " 29 [email protected] "\n "
30 CONST_DEF@32..45 30 [email protected]
31 [email protected] "const" 31 [email protected] "const"
32 [email protected] " " 32 [email protected] " "
33 [email protected] 33 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "i32" 41 [email protected] "i32"
42 [email protected] ";" 42 [email protected] ";"
43 [email protected] "\n " 43 [email protected] "\n "
44 FN_DEF@50..61 44 [email protected]
45 [email protected] "fn" 45 [email protected] "fn"
46 [email protected] " " 46 [email protected] " "
47 [email protected] 47 [email protected]
@@ -54,7 +54,7 @@ [email protected]
54 [email protected] "{" 54 [email protected] "{"
55 [email protected] "}" 55 [email protected] "}"
56 [email protected] "\n " 56 [email protected] "\n "
57 FN_DEF@66..80 57 [email protected]
58 [email protected] "fn" 58 [email protected] "fn"
59 [email protected] " " 59 [email protected] " "
60 [email protected] 60 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
index cf3a90400..1e80dd7e2 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..58 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -51,7 +51,7 @@ [email protected]
51 [email protected] " " 51 [email protected] " "
52 [email protected] "// Rust 2018 (with a ..." 52 [email protected] "// Rust 2018 (with a ..."
53 [email protected] "\n" 53 [email protected] "\n"
54 USE_ITEM@98..121 54 [email protected]
55 [email protected] "use" 55 [email protected] "use"
56 [email protected] " " 56 [email protected] " "
57 [email protected] 57 [email protected]
@@ -77,7 +77,7 @@ [email protected]
77 [email protected] " " 77 [email protected] " "
78 [email protected] "// Rust 2015" 78 [email protected] "// Rust 2015"
79 [email protected] "\n" 79 [email protected] "\n"
80 USE_ITEM@135..166 80 [email protected]
81 [email protected] "use" 81 [email protected] "use"
82 [email protected] " " 82 [email protected] " "
83 [email protected] 83 [email protected]
@@ -104,7 +104,7 @@ [email protected]
104 [email protected] " " 104 [email protected] " "
105 [email protected] "// Rust 2015" 105 [email protected] "// Rust 2015"
106 [email protected] "\n" 106 [email protected] "\n"
107 USE_ITEM@180..205 107 [email protected]
108 [email protected] "use" 108 [email protected] "use"
109 [email protected] " " 109 [email protected] " "
110 [email protected] 110 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
index cd0892451..b0f2b5888 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..53 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "for_trait" 6 [email protected] "for_trait"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -19,7 +19,7 @@ [email protected]
19 [email protected] "\n " 19 [email protected] "\n "
20 [email protected] 20 [email protected]
21 [email protected] "for" 21 [email protected] "for"
22 TYP[email protected] 22 GENERIC[email protected]
23 [email protected] "<" 23 [email protected] "<"
24 [email protected] 24 [email protected]
25 [email protected] "\'a" 25 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast
index 20eba09f5..ace8ad050 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..38 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast b/crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast
index 6c8c1e24b..8e0252ce7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..27 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "foo" 6 [email protected] "foo"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast b/crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast
index 9f4a9e69b..ae61cbad8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..127 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "S" 9 [email protected] "S"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@13..26 14 [email protected]
15 [email protected] "fn" 15 [email protected] "fn"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -26,7 +26,7 @@ [email protected]
26 [email protected] "{" 26 [email protected] "{"
27 [email protected] "}" 27 [email protected] "}"
28 [email protected] "\n " 28 [email protected] "\n "
29 FN_DEF@31..46 29 [email protected]
30 [email protected] "fn" 30 [email protected] "fn"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
@@ -43,7 +43,7 @@ [email protected]
43 [email protected] "{" 43 [email protected] "{"
44 [email protected] "}" 44 [email protected] "}"
45 [email protected] "\n " 45 [email protected] "\n "
46 FN_DEF@51..69 46 [email protected]
47 [email protected] "fn" 47 [email protected] "fn"
48 [email protected] " " 48 [email protected] " "
49 [email protected] 49 [email protected]
@@ -62,7 +62,7 @@ [email protected]
62 [email protected] "{" 62 [email protected] "{"
63 [email protected] "}" 63 [email protected] "}"
64 [email protected] "\n " 64 [email protected] "\n "
65 FN_DEF@74..103 65 [email protected]
66 [email protected] "fn" 66 [email protected] "fn"
67 [email protected] " " 67 [email protected] " "
68 [email protected] 68 [email protected]
@@ -95,7 +95,7 @@ [email protected]
95 [email protected] "{" 95 [email protected] "{"
96 [email protected] "}" 96 [email protected] "}"
97 [email protected] "\n " 97 [email protected] "\n "
98 FN_DEF@108..125 98 [email protected]
99 [email protected] "fn" 99 [email protected] "fn"
100 [email protected] " " 100 [email protected] " "
101 [email protected] 101 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast b/crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
index 7cb9e1d55..e95688f56 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..34 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast b/crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast
index 10eb31d68..3ce2acfae 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..102 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast
index 425e5196c..f62826fd5 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..25 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast
index d823c08fc..66a609346 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..47 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast b/crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast
index 283442a8b..28c94bfd6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..30 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast b/crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast
index e2e871dda..845b32e6d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..17 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] ")" 16 [email protected] ")"
17 [email protected] ";" 17 [email protected] ";"
18 [email protected] "\n" 18 [email protected] "\n"
19 TYPE_ALIAS_DEF@18..35 19 [email protected]
20 [email protected] "type" 20 [email protected] "type"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast
index a60940fcf..b1d5106ce 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..15 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast
index 422912e3c..104e153ce 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..68 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast
index d59c6006d..625ab4c2d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..17 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "trait" 5 [email protected] "trait"
@@ -7,7 +7,7 @@ [email protected]
7 [email protected] 7 [email protected]
8 [email protected] "T" 8 [email protected] "T"
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 ASSOC_[email protected]
11 [email protected] "{" 11 [email protected] "{"
12 [email protected] "}" 12 [email protected] "}"
13 [email protected] "\n" 13 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast
index 61a0b22f4..c131df1c9 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..18 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast b/crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast
index 15da6fdd6..20b2b6c19 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..68 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "S" 9 [email protected] "S"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@13..33 14 [email protected]
15 [email protected] "fn" 15 [email protected] "fn"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] "{" 35 [email protected] "{"
36 [email protected] "}" 36 [email protected] "}"
37 [email protected] "\n " 37 [email protected] "\n "
38 FN_DEF@38..66 38 [email protected]
39 [email protected] "fn" 39 [email protected] "fn"
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast
index 10d6b2fde..7db38ea4d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..43 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast b/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
index 9e898b7b9..b3623c445 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast
@@ -1,12 +1,12 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..6 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "*" 6 [email protected] "*"
7 [email protected] ";" 7 [email protected] ";"
8 [email protected] "\n" 8 [email protected] "\n"
9 USE_ITEM@7..15 9 [email protected]
10 [email protected] "use" 10 [email protected] "use"
11 [email protected] " " 11 [email protected] " "
12 [email protected] 12 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] "*" 14 [email protected] "*"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 USE_ITEM@16..36 17 [email protected]
18 [email protected] "use" 18 [email protected] "use"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] "}" 35 [email protected] "}"
36 [email protected] ";" 36 [email protected] ";"
37 [email protected] "\n" 37 [email protected] "\n"
38 USE_ITEM@37..59 38 [email protected]
39 [email protected] "use" 39 [email protected] "use"
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast
index c204aeb63..ca0702aba 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..88 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "F" 9 [email protected] "F"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 TYPE_ALIAS_DEF@13..26 14 [email protected]
15 [email protected] "type" 15 [email protected] "type"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -26,7 +26,7 @@ [email protected]
26 [email protected] "i32" 26 [email protected] "i32"
27 [email protected] ";" 27 [email protected] ";"
28 [email protected] "\n " 28 [email protected] "\n "
29 CONST_DEF@31..49 29 [email protected]
30 [email protected] "const" 30 [email protected] "const"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
@@ -45,7 +45,7 @@ [email protected]
45 [email protected] "92" 45 [email protected] "92"
46 [email protected] ";" 46 [email protected] ";"
47 [email protected] "\n " 47 [email protected] "\n "
48 FN_DEF@54..65 48 [email protected]
49 [email protected] "fn" 49 [email protected] "fn"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 [email protected]
@@ -58,7 +58,7 @@ [email protected]
58 [email protected] "{" 58 [email protected] "{"
59 [email protected] "}" 59 [email protected] "}"
60 [email protected] "\n " 60 [email protected] "\n "
61 FN_DEF@70..86 61 [email protected]
62 [email protected] "fn" 62 [email protected] "fn"
63 [email protected] " " 63 [email protected] " "
64 [email protected] 64 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast b/crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast
index 1b810607e..50742cbcf 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..20 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "pub" 4 [email protected] "pub"
5 [email protected] "(" 5 [email protected] "("
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] "S" 12 [email protected] "S"
13 [email protected] ";" 13 [email protected] ";"
14 [email protected] "\n" 14 [email protected] "\n"
15 STRUCT_DEF@21..40 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "pub" 17 [email protected] "pub"
18 [email protected] "(" 18 [email protected] "("
@@ -25,7 +25,7 @@ [email protected]
25 [email protected] "S" 25 [email protected] "S"
26 [email protected] ";" 26 [email protected] ";"
27 [email protected] "\n" 27 [email protected] "\n"
28 STRUCT_DEF@41..60 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "pub" 30 [email protected] "pub"
31 [email protected] "(" 31 [email protected] "("
@@ -38,7 +38,7 @@ [email protected]
38 [email protected] "S" 38 [email protected] "S"
39 [email protected] ";" 39 [email protected] ";"
40 [email protected] "\n" 40 [email protected] "\n"
41 STRUCT_DEF@61..80 41 [email protected]
42 [email protected] 42 [email protected]
43 [email protected] "pub" 43 [email protected] "pub"
44 [email protected] "(" 44 [email protected] "("
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast
index 17687617b..57008e5fe 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..21 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast
index 7eb27d5e1..dea0c73f7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..38 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast
index 0a6d77f45..fd819ea37 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..14 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast b/crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
index b4598768e..e5f550347 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..96 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast
index b824c10a8..9e76d881e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..51 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
index 93f5c738c..f45f3cab8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..42 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast
index fabb09937..e096b3a1f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..88 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast b/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast
index 3aed26732..381284dc5 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..37 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] " " 41 [email protected] " "
42 [email protected] "}" 42 [email protected] "}"
43 [email protected] "\n" 43 [email protected] "\n"
44 FN_DEF@38..196 44 [email protected]
45 [email protected] "fn" 45 [email protected] "fn"
46 [email protected] " " 46 [email protected] " "
47 [email protected] 47 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast
index 899b63aac..ffe1a3a01 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..92 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast
index 72705e148..79a5ee339 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..14 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] ")" 14 [email protected] ")"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 TYPE_ALIAS_DEF@15..36 17 [email protected]
18 [email protected] "type" 18 [email protected] "type"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -31,7 +31,7 @@ [email protected]
31 [email protected] ")" 31 [email protected] ")"
32 [email protected] ";" 32 [email protected] ";"
33 [email protected] "\n" 33 [email protected] "\n"
34 TYPE_ALIAS_DEF@37..69 34 [email protected]
35 [email protected] "type" 35 [email protected] "type"
36 [email protected] " " 36 [email protected] " "
37 [email protected] 37 [email protected]
@@ -53,7 +53,7 @@ [email protected]
53 [email protected] ")" 53 [email protected] ")"
54 [email protected] ";" 54 [email protected] ";"
55 [email protected] "\n" 55 [email protected] "\n"
56 TYPE_ALIAS_DEF@70..112 56 [email protected]
57 [email protected] "type" 57 [email protected] "type"
58 [email protected] " " 58 [email protected] " "
59 [email protected] 59 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast b/crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast
index 784fbb592..c522f76cf 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..13 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] ")" 14 [email protected] ")"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 TYPE_ALIAS_DEF@14..35 17 [email protected]
18 [email protected] "type" 18 [email protected] "type"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -31,7 +31,7 @@ [email protected]
31 [email protected] ")" 31 [email protected] ")"
32 [email protected] ";" 32 [email protected] ";"
33 [email protected] "\n" 33 [email protected] "\n"
34 TYPE_ALIAS_DEF@36..53 34 [email protected]
35 [email protected] "type" 35 [email protected] "type"
36 [email protected] " " 36 [email protected] " "
37 [email protected] 37 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast
index e064aafaf..f905def6f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..101 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast
index cf5825593..293b1d64c 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..29 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast b/crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast
index fbd90bc0f..b6379e62f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..26 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] "Output" 32 [email protected] "Output"
33 [email protected] ";" 33 [email protected] ";"
34 [email protected] "\n" 34 [email protected] "\n"
35 FN_DEF@27..70 35 [email protected]
36 [email protected] "fn" 36 [email protected] "fn"
37 [email protected] " " 37 [email protected] " "
38 [email protected] 38 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast
index a767f145d..64e705fb3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..20 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast
index e92ea2bf2..2185d3c91 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..45 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast b/crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
index aa582516a..db5bd2849 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..19 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "crate" 4 [email protected] "crate"
5 [email protected] " " 5 [email protected] " "
@@ -16,16 +16,16 @@ [email protected]
16 [email protected] " " 16 [email protected] " "
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
19 STRUCT_DEF@20..49 19 [email protected]
20 [email protected] "struct" 20 [email protected] "struct"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
23 [email protected] "S" 23 [email protected] "S"
24 [email protected] " " 24 [email protected] " "
25 RECORD_FIELD_DEF_[email protected] 25 [email protected]
26 [email protected] "{" 26 [email protected] "{"
27 [email protected] " " 27 [email protected] " "
28 RECORD_FIELD_DEF@31..47 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "crate" 30 [email protected] "crate"
31 [email protected] " " 31 [email protected] " "
@@ -41,14 +41,14 @@ [email protected]
41 [email protected] " " 41 [email protected] " "
42 [email protected] "}" 42 [email protected] "}"
43 [email protected] "\n" 43 [email protected] "\n"
44 STRUCT_DEF@50..70 44 [email protected]
45 [email protected] "struct" 45 [email protected] "struct"
46 [email protected] " " 46 [email protected] " "
47 [email protected] 47 [email protected]
48 [email protected] "T" 48 [email protected] "T"
49 TUPLE_FIELD_DEF_[email protected] 49 [email protected]
50 [email protected] "(" 50 [email protected] "("
51 TUPLE_FIELD_DEF@59..68 51 [email protected]
52 [email protected] 52 [email protected]
53 [email protected] "crate" 53 [email protected] "crate"
54 [email protected] " " 54 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast
index 1ae791361..3638462f8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..41 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "T" 6 [email protected] "T"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -48,16 +48,16 @@ [email protected]
48 [email protected] 48 [email protected]
49 [email protected] "Copy" 49 [email protected] "Copy"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 ASSOC_[email protected]
52 [email protected] "{" 52 [email protected] "{"
53 [email protected] "}" 53 [email protected] "}"
54 [email protected] "\n" 54 [email protected] "\n"
55 TRAIT_DEF@42..100 55 [email protected]
56 [email protected] "trait" 56 [email protected] "trait"
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 [email protected]
59 [email protected] "X" 59 [email protected] "X"
60 TYP[email protected] 60 GENERIC[email protected]
61 [email protected] "<" 61 [email protected] "<"
62 [email protected] 62 [email protected]
63 [email protected] 63 [email protected]
@@ -119,7 +119,7 @@ [email protected]
119 [email protected] 119 [email protected]
120 [email protected] "Copy" 120 [email protected] "Copy"
121 [email protected] " " 121 [email protected] " "
122 [email protected] 122 ASSOC_[email protected]
123 [email protected] "{" 123 [email protected] "{"
124 [email protected] "}" 124 [email protected] "}"
125 [email protected] "\n" 125 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast
index 0c1c6e877..40875ae1e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..117 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast b/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
index f0e09d40d..60b517230 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..28 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -13,14 +13,14 @@ [email protected]
13 [email protected] 13 [email protected]
14 [email protected] "path" 14 [email protected] "path"
15 [email protected] " " 15 [email protected] " "
16 ALIAS@15..27 16 RENAME@15..27
17 [email protected] "as" 17 [email protected] "as"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 [email protected]
20 [email protected] "some_name" 20 [email protected] "some_name"
21 [email protected] ";" 21 [email protected] ";"
22 [email protected] "\n" 22 [email protected] "\n"
23 USE_ITEM@29..181 23 [email protected]
24 [email protected] "use" 24 [email protected] "use"
25 [email protected] " " 25 [email protected] " "
26 [email protected] 26 [email protected]
@@ -43,7 +43,7 @@ [email protected]
43 [email protected] 43 [email protected]
44 [email protected] "path" 44 [email protected] "path"
45 [email protected] " " 45 [email protected] " "
46 ALIAS@54..72 46 RENAME@54..72
47 [email protected] "as" 47 [email protected] "as"
48 [email protected] " " 48 [email protected] " "
49 [email protected] 49 [email protected]
@@ -61,7 +61,7 @@ [email protected]
61 [email protected] 61 [email protected]
62 [email protected] "path" 62 [email protected] "path"
63 [email protected] " " 63 [email protected] " "
64 ALIAS@91..108 64 RENAME@91..108
65 [email protected] "as" 65 [email protected] "as"
66 [email protected] " " 66 [email protected] " "
67 [email protected] 67 [email protected]
@@ -121,7 +121,7 @@ [email protected]
121 [email protected] "}" 121 [email protected] "}"
122 [email protected] ";" 122 [email protected] ";"
123 [email protected] "\n" 123 [email protected] "\n"
124 USE_ITEM@182..197 124 [email protected]
125 [email protected] "use" 125 [email protected] "use"
126 [email protected] " " 126 [email protected] " "
127 [email protected] 127 [email protected]
@@ -130,7 +130,7 @@ [email protected]
130 [email protected] 130 [email protected]
131 [email protected] "Trait" 131 [email protected] "Trait"
132 [email protected] " " 132 [email protected] " "
133 ALIAS@192..196 133 RENAME@192..196
134 [email protected] "as" 134 [email protected] "as"
135 [email protected] " " 135 [email protected] " "
136 [email protected] "_" 136 [email protected] "_"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast b/crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast
index c23b3b67c..1fd3cd0e7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..20 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,7 +11,7 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] " " 13 [email protected] " "
14 FN_DEF@9..18 14 [email protected]
15 [email protected] "fn" 15 [email protected] "fn"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast b/crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
index 9ca2165ba..d4235a8b1 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..34 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "foo" 6 [email protected] "foo"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast
index c28dc9d61..e89284c14 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..16 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast
index 52de6023b..d6dfa83b7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..26 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "default" 5 [email protected] "default"
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "Foo" 13 [email protected] "Foo"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 ASSOC_[email protected]
16 [email protected] "{" 16 [email protected] "{"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast b/crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
index b209f67f8..37757ccd4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..26 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -38,7 +38,7 @@ [email protected]
38 [email protected] "{" 38 [email protected] "{"
39 [email protected] "}" 39 [email protected] "}"
40 [email protected] "\n" 40 [email protected] "\n"
41 FN_DEF@27..57 41 [email protected]
42 [email protected] "fn" 42 [email protected] "fn"
43 [email protected] " " 43 [email protected] " "
44 [email protected] 44 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast
index 8bf62cda9..a5bf55131 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..21 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "T" 6 [email protected] "T"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 ASSOC_[email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] " " 10 [email protected] " "
11 FN_DEF@10..19 11 [email protected]
12 [email protected] "fn" 12 [email protected] "fn"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast
index 798ef2a48..6330dbf9e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..12 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast
index 0d2f5ff56..9bc36bea7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..13 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] "Foo" 14 [email protected] "Foo"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 TYPE_ALIAS_DEF@14..29 17 [email protected]
18 [email protected] "type" 18 [email protected] "type"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -30,7 +30,7 @@ [email protected]
30 [email protected] "Foo" 30 [email protected] "Foo"
31 [email protected] ";" 31 [email protected] ";"
32 [email protected] "\n" 32 [email protected] "\n"
33 TYPE_ALIAS_DEF@30..49 33 [email protected]
34 [email protected] "type" 34 [email protected] "type"
35 [email protected] " " 35 [email protected] " "
36 [email protected] 36 [email protected]
@@ -49,7 +49,7 @@ [email protected]
49 [email protected] "Foo" 49 [email protected] "Foo"
50 [email protected] ";" 50 [email protected] ";"
51 [email protected] "\n" 51 [email protected] "\n"
52 TYPE_ALIAS_DEF@50..70 52 [email protected]
53 [email protected] "type" 53 [email protected] "type"
54 [email protected] " " 54 [email protected] " "
55 [email protected] 55 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast
index 70232a3b2..2bfb52453 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..90 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast b/crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
index 6362aa02d..9ae271817 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..63 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..60 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "#" 13 [email protected] "#"
14 [email protected] "[" 14 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast b/crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
index 03c52525e..68bb43852 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..112 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast b/crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast
index 24f89b83f..28129c50c 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..115 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast
index bb43d1eaf..97548a5ee 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..17 2 [email protected]
3 [email protected] "const" 3 [email protected] "const"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast
index 8bd94a868..3e72f9671 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..111 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast b/crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast
index 9210f155c..fa659c19b 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..82 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast b/crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast
index d06fc0be5..25e1777d1 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 EXTERN_CRATE_ITEM@0..17 2 [email protected]
3 [email protected] "extern" 3 [email protected] "extern"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "crate" 5 [email protected] "crate"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
index 850465d82..a9ae1aa59 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..111 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,28 +12,28 @@ [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 [email protected] 14 [email protected]
15 RECORD_LIT@15..19 15 RECORD_EXPR@15..19
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] "S" 19 [email protected] "S"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 RECORD_EXPR_[email protected]
22 [email protected] "{" 22 [email protected] "{"
23 [email protected] "}" 23 [email protected] "}"
24 [email protected] ";" 24 [email protected] ";"
25 [email protected] "\n " 25 [email protected] "\n "
26 [email protected] 26 [email protected]
27 RECORD_LIT@25..40 27 RECORD_EXPR@25..40
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "S" 31 [email protected] "S"
32 [email protected] " " 32 [email protected] " "
33 [email protected] 33 RECORD_EXPR_[email protected]
34 [email protected] "{" 34 [email protected] "{"
35 [email protected] " " 35 [email protected] " "
36 [email protected] 36 RECORD_EXPR_[email protected]
37 [email protected] 37 [email protected]
38 [email protected] 38 [email protected]
39 [email protected] 39 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "x" 41 [email protected] "x"
42 [email protected] "," 42 [email protected] ","
43 [email protected] " " 43 [email protected] " "
44 [email protected] 44 RECORD_EXPR_[email protected]
45 [email protected] 45 [email protected]
46 [email protected] "y" 46 [email protected] "y"
47 [email protected] ":" 47 [email protected] ":"
@@ -54,16 +54,16 @@ [email protected]
54 [email protected] ";" 54 [email protected] ";"
55 [email protected] "\n " 55 [email protected] "\n "
56 [email protected] 56 [email protected]
57 RECORD_LIT@46..82 57 RECORD_EXPR@46..82
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
60 [email protected] 60 [email protected]
61 [email protected] "S" 61 [email protected] "S"
62 [email protected] " " 62 [email protected] " "
63 [email protected] 63 RECORD_EXPR_[email protected]
64 [email protected] "{" 64 [email protected] "{"
65 [email protected] " " 65 [email protected] " "
66 [email protected] 66 RECORD_EXPR_[email protected]
67 [email protected] 67 [email protected]
68 [email protected] 68 [email protected]
69 [email protected] 69 [email protected]
@@ -71,7 +71,7 @@ [email protected]
71 [email protected] "x" 71 [email protected] "x"
72 [email protected] "," 72 [email protected] ","
73 [email protected] " " 73 [email protected] " "
74 [email protected] 74 RECORD_EXPR_[email protected]
75 [email protected] 75 [email protected]
76 [email protected] "y" 76 [email protected] "y"
77 [email protected] ":" 77 [email protected] ":"
@@ -100,16 +100,16 @@ [email protected]
100 [email protected] ";" 100 [email protected] ";"
101 [email protected] "\n " 101 [email protected] "\n "
102 [email protected] 102 [email protected]
103 RECORD_LIT@88..108 103 RECORD_EXPR@88..108
104 [email protected] 104 [email protected]
105 [email protected] 105 [email protected]
106 [email protected] 106 [email protected]
107 [email protected] "TupleStruct" 107 [email protected] "TupleStruct"
108 [email protected] " " 108 [email protected] " "
109 [email protected] 109 RECORD_EXPR_[email protected]
110 [email protected] "{" 110 [email protected] "{"
111 [email protected] " " 111 [email protected] " "
112 [email protected] 112 RECORD_EXPR_[email protected]
113 [email protected] 113 [email protected]
114 [email protected] "0" 114 [email protected] "0"
115 [email protected] ":" 115 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast b/crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast
index 02656df31..de8217064 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..11 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -57,7 +57,7 @@ [email protected]
57 [email protected] "{" 57 [email protected] "{"
58 [email protected] "}" 58 [email protected] "}"
59 [email protected] "\n" 59 [email protected] "\n"
60 STRUCT_DEF@60..69 60 [email protected]
61 [email protected] "struct" 61 [email protected] "struct"
62 [email protected] " " 62 [email protected] " "
63 [email protected] 63 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast b/crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast
index 24b9a1f46..4368930cc 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..19 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "!" 5 [email protected] "!"
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "X" 18 [email protected] "X"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 ASSOC_[email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] "}" 22 [email protected] "}"
23 [email protected] "\n" 23 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast
index 445d8d309..587160003 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..136 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
index 8e10f3673..629fea99d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..41 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast
index 177bb5514..37ca478e6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..166 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -49,14 +49,14 @@ [email protected]
49 [email protected] " " 49 [email protected] " "
50 [email protected] ">" 50 [email protected] ">"
51 [email protected] " " 51 [email protected] " "
52 RECORD_LIT@63..77 52 RECORD_EXPR@63..77
53 [email protected] 53 [email protected]
54 [email protected] 54 [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "Test" 56 [email protected] "Test"
57 [email protected] 57 RECORD_EXPR_[email protected]
58 [email protected] "{" 58 [email protected] "{"
59 [email protected] 59 RECORD_EXPR_[email protected]
60 [email protected] 60 [email protected]
61 [email protected] "field" 61 [email protected] "field"
62 [email protected] ":" 62 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
index caa76fe8a..702f2e0b0 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..15 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast b/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast
index ec2496072..6589e4795 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast
@@ -1,24 +1,24 @@
1[email protected] 1[email protected]
2 UNION_DEF@0..12 2 [email protected]
3 [email protected] "union" 3 [email protected] "union"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Foo" 6 [email protected] "Foo"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "}" 10 [email protected] "}"
11 [email protected] "\n" 11 [email protected] "\n"
12 UNION_DEF@13..50 12 [email protected]
13 [email protected] "union" 13 [email protected] "union"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 [email protected]
16 [email protected] "Foo" 16 [email protected] "Foo"
17 [email protected] " " 17 [email protected] " "
18 RECORD_FIELD_DEF_[email protected] 18 [email protected]
19 [email protected] "{" 19 [email protected] "{"
20 [email protected] "\n " 20 [email protected] "\n "
21 RECORD_FIELD_DEF@29..35 21 [email protected]
22 [email protected] 22 [email protected]
23 [email protected] "a" 23 [email protected] "a"
24 [email protected] ":" 24 [email protected] ":"
@@ -30,7 +30,7 @@ [email protected]
30 [email protected] "i32" 30 [email protected] "i32"
31 [email protected] "," 31 [email protected] ","
32 [email protected] "\n " 32 [email protected] "\n "
33 RECORD_FIELD_DEF@41..47 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "b" 35 [email protected] "b"
36 [email protected] ":" 36 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
index 18cd5271f..c4c5bc51e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..18 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] ";" 18 [email protected] ";"
19 [email protected] "\n" 19 [email protected] "\n"
20 USE_ITEM@19..36 20 [email protected]
21 [email protected] "use" 21 [email protected] "use"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast b/crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast
index f8ff7079b..4c1165dc8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..45 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast
index 07b3d1435..673d396ee 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..96 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -72,13 +72,13 @@ [email protected]
72 [email protected] 72 [email protected]
73 [email protected] "{" 73 [email protected] "{"
74 [email protected] " " 74 [email protected] " "
75 RECORD_LIT@84..88 75 RECORD_EXPR@84..88
76 [email protected] 76 [email protected]
77 [email protected] 77 [email protected]
78 [email protected] 78 [email protected]
79 [email protected] "S" 79 [email protected] "S"
80 [email protected] " " 80 [email protected] " "
81 [email protected] 81 RECORD_EXPR_[email protected]
82 [email protected] "{" 82 [email protected] "{"
83 [email protected] "}" 83 [email protected] "}"
84 [email protected] " " 84 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast
index 665f716a8..437d7ac04 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..39 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast b/crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast
index cc871ac0c..00cce69e6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..20 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Result" 6 [email protected] "Result"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast b/crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast
index 3fd3a4391..3ca70f021 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..83 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast
index 97c6e6a9d..5cefc5076 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..9 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
15 FN_DEF@10..31 15 [email protected]
16 [email protected] "fn" 16 [email protected] "fn"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
@@ -38,7 +38,7 @@ [email protected]
38 [email protected] " " 38 [email protected] " "
39 [email protected] "}" 39 [email protected] "}"
40 [email protected] "\n" 40 [email protected] "\n"
41 FN_DEF@32..48 41 [email protected]
42 [email protected] "fn" 42 [email protected] "fn"
43 [email protected] " " 43 [email protected] " "
44 [email protected] 44 [email protected]
@@ -62,7 +62,7 @@ [email protected]
62 [email protected] " " 62 [email protected] " "
63 [email protected] "}" 63 [email protected] "}"
64 [email protected] "\n" 64 [email protected] "\n"
65 FN_DEF@49..64 65 [email protected]
66 [email protected] "fn" 66 [email protected] "fn"
67 [email protected] " " 67 [email protected] " "
68 [email protected] 68 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast b/crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast
index e2c1a507d..96217a7fd 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..28 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "foo" 6 [email protected] "foo"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast
index 4f3a8ed24..33e6fb93f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..20 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast
index a08e16fab..2befc8388 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..15 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast b/crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast
index a00ab40f9..209711fc4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..11 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "Foo" 9 [email protected] "Foo"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast
index 462d1a8bb..3c80846db 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..88 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast
index b26ac2d36..e7629ac03 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..28 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 [email protected]
11 [email protected] "for" 11 [email protected] "for"
12 TYP[email protected] 12 GENERIC[email protected]
13 [email protected] "<" 13 [email protected] "<"
14 [email protected] 14 [email protected]
15 [email protected] "\'a" 15 [email protected] "\'a"
@@ -29,7 +29,7 @@ [email protected]
29 [email protected] ")" 29 [email protected] ")"
30 [email protected] ";" 30 [email protected] ";"
31 [email protected] "\n" 31 [email protected] "\n"
32 TYPE_ALIAS_DEF@29..81 32 [email protected]
33 [email protected] "type" 33 [email protected] "type"
34 [email protected] " " 34 [email protected] " "
35 [email protected] 35 [email protected]
@@ -39,7 +39,7 @@ [email protected]
39 [email protected] " " 39 [email protected] " "
40 [email protected] 40 [email protected]
41 [email protected] "for" 41 [email protected] "for"
42 TYP[email protected] 42 GENERIC[email protected]
43 [email protected] "<" 43 [email protected] "<"
44 [email protected] 44 [email protected]
45 [email protected] "\'a" 45 [email protected] "\'a"
@@ -74,7 +74,7 @@ [email protected]
74 [email protected] ")" 74 [email protected] ")"
75 [email protected] ";" 75 [email protected] ";"
76 [email protected] "\n" 76 [email protected] "\n"
77 TYPE_ALIAS_DEF@82..120 77 [email protected]
78 [email protected] "type" 78 [email protected] "type"
79 [email protected] " " 79 [email protected] " "
80 [email protected] 80 [email protected]
@@ -84,7 +84,7 @@ [email protected]
84 [email protected] " " 84 [email protected] " "
85 [email protected] 85 [email protected]
86 [email protected] "for" 86 [email protected] "for"
87 TYP[email protected] 87 GENERIC[email protected]
88 [email protected] "<" 88 [email protected] "<"
89 [email protected] 89 [email protected]
90 [email protected] "\'a" 90 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast
index 58bdf7e34..1563b1988 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..199 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast b/crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast
index 217b07e59..cdbc40fe0 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast
@@ -1,39 +1,39 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..11 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Foo" 6 [email protected] "Foo"
7 [email protected] ";" 7 [email protected] ";"
8 [email protected] "\n" 8 [email protected] "\n"
9 STRUCT_DEF@12..25 9 [email protected]
10 [email protected] "struct" 10 [email protected] "struct"
11 [email protected] " " 11 [email protected] " "
12 [email protected] 12 [email protected]
13 [email protected] "Foo" 13 [email protected] "Foo"
14 [email protected] " " 14 [email protected] " "
15 RECORD_FIELD_DEF_[email protected] 15 [email protected]
16 [email protected] "{" 16 [email protected] "{"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
19 STRUCT_DEF@26..39 19 [email protected]
20 [email protected] "struct" 20 [email protected] "struct"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
23 [email protected] "Foo" 23 [email protected] "Foo"
24 TUPLE_FIELD_DEF_[email protected] 24 [email protected]
25 [email protected] "(" 25 [email protected] "("
26 [email protected] ")" 26 [email protected] ")"
27 [email protected] ";" 27 [email protected] ";"
28 [email protected] "\n" 28 [email protected] "\n"
29 STRUCT_DEF@40..66 29 [email protected]
30 [email protected] "struct" 30 [email protected] "struct"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
33 [email protected] "Foo" 33 [email protected] "Foo"
34 TUPLE_FIELD_DEF_[email protected] 34 [email protected]
35 [email protected] "(" 35 [email protected] "("
36 TUPLE_FIELD_DEF@51..57 36 [email protected]
37 [email protected] 37 [email protected]
38 [email protected] 38 [email protected]
39 [email protected] 39 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "String" 41 [email protected] "String"
42 [email protected] "," 42 [email protected] ","
43 [email protected] " " 43 [email protected] " "
44 TUPLE_FIELD_DEF@59..64 44 [email protected]
45 [email protected] 45 [email protected]
46 [email protected] 46 [email protected]
47 [email protected] 47 [email protected]
@@ -50,16 +50,16 @@ [email protected]
50 [email protected] ")" 50 [email protected] ")"
51 [email protected] ";" 51 [email protected] ";"
52 [email protected] "\n" 52 [email protected] "\n"
53 STRUCT_DEF@67..105 53 [email protected]
54 [email protected] "struct" 54 [email protected] "struct"
55 [email protected] " " 55 [email protected] " "
56 [email protected] 56 [email protected]
57 [email protected] "Foo" 57 [email protected] "Foo"
58 [email protected] " " 58 [email protected] " "
59 RECORD_FIELD_DEF_[email protected] 59 [email protected]
60 [email protected] "{" 60 [email protected] "{"
61 [email protected] "\n " 61 [email protected] "\n "
62 RECORD_FIELD_DEF@84..90 62 [email protected]
63 [email protected] 63 [email protected]
64 [email protected] "a" 64 [email protected] "a"
65 [email protected] ":" 65 [email protected] ":"
@@ -71,7 +71,7 @@ [email protected]
71 [email protected] "i32" 71 [email protected] "i32"
72 [email protected] "," 72 [email protected] ","
73 [email protected] "\n " 73 [email protected] "\n "
74 RECORD_FIELD_DEF@96..102 74 [email protected]
75 [email protected] 75 [email protected]
76 [email protected] "b" 76 [email protected] "b"
77 [email protected] ":" 77 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast
index 9cd8910d4..ee8894966 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..15 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast b/crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast
index 9fcb7899e..ded36949a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..188 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast
index a42abc189..70e05a859 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..11 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
15 FN_DEF@12..29 15 [email protected]
16 [email protected] "fn" 16 [email protected] "fn"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast
index 01ed3afca..43c09affe 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..18 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "impl" 5 [email protected] "impl"
@@ -10,7 +10,7 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "Foo" 11 [email protected] "Foo"
12 [email protected] " " 12 [email protected] " "
13 [email protected] 13 ASSOC_[email protected]
14 [email protected] "{" 14 [email protected] "{"
15 [email protected] "}" 15 [email protected] "}"
16 [email protected] "\n" 16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast b/crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast
index 7e71d7373..34f520994 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..87 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast
index 48aaf1004..405b6a259 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..18 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "extern" 4 [email protected] "extern"
5 [email protected] " " 5 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast b/crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast
index cee2bc906..2ef026e37 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..18 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast
index 800412cef..0cac9ac43 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..15 2 [email protected]
3 [email protected] "auto" 3 [email protected] "auto"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "trait" 5 [email protected] "trait"
@@ -7,7 +7,7 @@ [email protected]
7 [email protected] 7 [email protected]
8 [email protected] "T" 8 [email protected] "T"
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 ASSOC_[email protected]
11 [email protected] "{" 11 [email protected] "{"
12 [email protected] "}" 12 [email protected] "}"
13 [email protected] "\n" 13 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast b/crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast
index 1e2d7db7c..95686977f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..20 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast
index aed81f9b0..82f03f9c1 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..25 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast
index 9370f6ae7..0ef11c682 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..22 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "auto" 5 [email protected] "auto"
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] 9 [email protected]
10 [email protected] "T" 10 [email protected] "T"
11 [email protected] " " 11 [email protected] " "
12 [email protected] 12 ASSOC_[email protected]
13 [email protected] "{" 13 [email protected] "{"
14 [email protected] "}" 14 [email protected] "}"
15 [email protected] "\n" 15 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast
index 67d9595d3..25706d2a4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..25 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
index 031e74652..cb5316a0d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..166 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast
index 80bda4ba7..0a1b21d6e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..19 2 [email protected]
3 [email protected] "default" 3 [email protected] "default"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "impl" 5 [email protected] "impl"
@@ -10,7 +10,7 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "Foo" 11 [email protected] "Foo"
12 [email protected] " " 12 [email protected] " "
13 [email protected] 13 ASSOC_[email protected]
14 [email protected] "{" 14 [email protected] "{"
15 [email protected] "}" 15 [email protected] "}"
16 [email protected] "\n" 16 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast
index 816e49310..32a77ba49 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..24 2 [email protected]
3 [email protected] "const" 3 [email protected] "const"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "unsafe" 5 [email protected] "unsafe"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast
index d48ef865c..1627556c8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..9 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
15 FN_DEF@10..25 15 [email protected]
16 [email protected] "fn" 16 [email protected] "fn"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
@@ -36,7 +36,7 @@ [email protected]
36 [email protected] "{" 36 [email protected] "{"
37 [email protected] "}" 37 [email protected] "}"
38 [email protected] "\n" 38 [email protected] "\n"
39 FN_DEF@26..43 39 [email protected]
40 [email protected] "fn" 40 [email protected] "fn"
41 [email protected] " " 41 [email protected] " "
42 [email protected] 42 [email protected]
@@ -62,7 +62,7 @@ [email protected]
62 [email protected] "{" 62 [email protected] "{"
63 [email protected] "}" 63 [email protected] "}"
64 [email protected] "\n" 64 [email protected] "\n"
65 FN_DEF@44..66 65 [email protected]
66 [email protected] "fn" 66 [email protected] "fn"
67 [email protected] " " 67 [email protected] " "
68 [email protected] 68 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast
index e4455cd3e..766de4efe 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..32 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast
index 8a8743060..73c94e5d4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..18 2 [email protected]
3 [email protected] "unsafe" 3 [email protected] "unsafe"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast b/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
index 9f966ff8a..fe1c290c3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..118 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast
index 9b3bef04e..c4c0a0568 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..54 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast
index e3c4cfeb3..3f53d60c0 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..28 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast
index e64717152..51a6c5170 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..133 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast
index 98963dc62..b2961b0ff 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..48 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast
index ea603e2c9..ca7e4a5c3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..39 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast b/crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast
index 30ff96a7c..a6a169f1b 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..73 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
index 015a7a7d2..82028096f 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..17 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] " " 12 [email protected] " "
13 [email protected] "// Rust 2018 - All fl ..." 13 [email protected] "// Rust 2018 - All fl ..."
14 [email protected] "\n" 14 [email protected] "\n"
15 USE_ITEM@46..61 15 [email protected]
16 [email protected] "use" 16 [email protected] "use"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
@@ -24,7 +24,7 @@ [email protected]
24 [email protected] " " 24 [email protected] " "
25 [email protected] "// Rust 2018 - Anchor ..." 25 [email protected] "// Rust 2018 - Anchor ..."
26 [email protected] "\n" 26 [email protected] "\n"
27 USE_ITEM@92..124 27 [email protected]
28 [email protected] "use" 28 [email protected] "use"
29 [email protected] " " 29 [email protected] " "
30 [email protected] 30 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast
index b58f40ac1..432318da0 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..93 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast
index b67714c17..3cd554d45 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..145 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast
index 5de480da9..d761c1c68 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..49 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast b/crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast
index 01d717d6b..0e1594dc4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast
@@ -1,18 +1,18 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..33 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Test" 6 [email protected] "Test"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "T" 11 [email protected] "T"
12 [email protected] ">" 12 [email protected] ">"
13 TUPLE_FIELD_DEF_[email protected] 13 [email protected]
14 [email protected] "(" 14 [email protected] "("
15 TUPLE_FIELD_DEF@15..16 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
@@ -40,20 +40,20 @@ [email protected]
40 [email protected] "Clone" 40 [email protected] "Clone"
41 [email protected] ";" 41 [email protected] ";"
42 [email protected] "\n" 42 [email protected] "\n"
43 STRUCT_DEF@34..52 43 [email protected]
44 [email protected] "struct" 44 [email protected] "struct"
45 [email protected] " " 45 [email protected] " "
46 [email protected] 46 [email protected]
47 [email protected] "Test" 47 [email protected] "Test"
48 TYP[email protected] 48 GENERIC[email protected]
49 [email protected] "<" 49 [email protected] "<"
50 [email protected] 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] "T" 52 [email protected] "T"
53 [email protected] ">" 53 [email protected] ">"
54 TUPLE_FIELD_DEF_[email protected] 54 [email protected]
55 [email protected] "(" 55 [email protected] "("
56 TUPLE_FIELD_DEF@49..50 56 [email protected]
57 [email protected] 57 [email protected]
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast b/crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
index 3c0ef9005..4d09c9f50 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..59 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 TUPLE_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "(" 9 [email protected] "("
10 [email protected] "\n " 10 [email protected] "\n "
11 TUPLE_FIELD_DEF@15..55 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "#" 13 [email protected] "#"
14 [email protected] "[" 14 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
index ddfcf974e..f3d4ad72c 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..16 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -18,7 +18,7 @@ [email protected]
18 [email protected] ")" 18 [email protected] ")"
19 [email protected] ";" 19 [email protected] ";"
20 [email protected] "\n" 20 [email protected] "\n"
21 TYPE_ALIAS_DEF@17..40 21 [email protected]
22 [email protected] "type" 22 [email protected] "type"
23 [email protected] " " 23 [email protected] " "
24 [email protected] 24 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast b/crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
index a65a5c85f..141a7b203 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 ENUM_DEF@0..8 2 [email protected]
3 [email protected] "enum" 3 [email protected] "enum"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "F" 6 [email protected] "F"
7 ENUM_[email protected] 7 [email protected]
8 [email protected] "{" 8 [email protected] "{"
9 [email protected] "}" 9 [email protected] "}"
10 [email protected] "\n" 10 [email protected] "\n"
11 IMPL_DEF@9..93 11 [email protected]
12 [email protected] "impl" 12 [email protected] "impl"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "F" 18 [email protected] "F"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 ASSOC_[email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] "\n " 22 [email protected] "\n "
23 [email protected] "//! This is a doc com ..." 23 [email protected] "//! This is a doc com ..."
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast b/crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast
index e152c6b6c..aaaf803b7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..57 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast b/crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
index b283ab804..4b5f9cdc9 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..138 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast b/crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
index 9d5470914..54cc3be3a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..258 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast b/crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
index ada2fc54e..edac8d5d9 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..63 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "foo" 6 [email protected] "foo"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast b/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast
index b3a33c14d..f155743cf 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] " " 10 [email protected] " "
11 FN_DEF@13..54 11 [email protected]
12 [email protected] "fn" 12 [email protected] "fn"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast
index 6178dfe59..a7df188bd 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..17 2 [email protected]
3 [email protected] "async" 3 [email protected] "async"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast
index ced59b7c1..aa4d7a784 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..26 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
index 97611f7f3..54ea2c7c6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..45 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,16 +11,16 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 RECORD_LIT@16..43 14 RECORD_EXPR@16..43
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "S" 18 [email protected] "S"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 RECORD_EXPR_[email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 RECORD_EXPR_[email protected]
24 [email protected] 24 [email protected]
25 [email protected] "#" 25 [email protected] "#"
26 [email protected] "[" 26 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
index 09221fc54..0342e64f3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..81 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
index 93cc41533..3b46e5b47 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..46 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast
index 0901f2348..98a20f36d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..24 2 [email protected]
3 [email protected] "async" 3 [email protected] "async"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "unsafe" 5 [email protected] "unsafe"
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] "{" 16 [email protected] "{"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
19 FN_DEF@25..49 19 [email protected]
20 [email protected] "const" 20 [email protected] "const"
21 [email protected] " " 21 [email protected] " "
22 [email protected] "unsafe" 22 [email protected] "unsafe"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast
index 28291afc2..e283966ca 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..32 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast b/crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast
index bb94a05c6..931e81f27 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..134 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast
index 8f2f144c7..0fe3bf582 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..32 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast
index 4a1c2b3a4..d47071a91 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..36 2 [email protected]
3 [email protected] "existential" 3 [email protected] "existential"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "type" 5 [email protected] "type"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast
index 87ac42748..48f483813 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..105 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast
index 00ce5ecf0..b8d26a53a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..68 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -16,10 +16,10 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "Foo" 17 [email protected] "Foo"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 ASSOC_[email protected]
20 [email protected] "{" 20 [email protected] "{"
21 [email protected] "\n " 21 [email protected] "\n "
22 TYPE_ALIAS_DEF@21..42 22 [email protected]
23 [email protected] "default" 23 [email protected] "default"
24 [email protected] " " 24 [email protected] " "
25 [email protected] "type" 25 [email protected] "type"
@@ -36,7 +36,7 @@ [email protected]
36 [email protected] "Bar" 36 [email protected] "Bar"
37 [email protected] ";" 37 [email protected] ";"
38 [email protected] "\n " 38 [email protected] "\n "
39 FN_DEF@47..66 39 [email protected]
40 [email protected] "default" 40 [email protected] "default"
41 [email protected] " " 41 [email protected] " "
42 [email protected] "fn" 42 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast
index b330a0932..429a0506e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..110 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,21 +11,21 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 ENUM_DEF@27..75 14 [email protected]
15 [email protected] "enum" 15 [email protected] "enum"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
18 [email protected] "LocalEnum" 18 [email protected] "LocalEnum"
19 [email protected] " " 19 [email protected] " "
20 ENUM_[email protected] 20 [email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] "\n " 22 [email protected] "\n "
23 ENUM_[email protected] 23 [email protected]
24 [email protected] 24 [email protected]
25 [email protected] "One" 25 [email protected] "One"
26 [email protected] "," 26 [email protected] ","
27 [email protected] "\n " 27 [email protected] "\n "
28 ENUM_[email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "Two" 30 [email protected] "Two"
31 [email protected] "," 31 [email protected] ","
@@ -33,7 +33,7 @@ [email protected]
33 [email protected] "}" 33 [email protected] "}"
34 [email protected] ";" 34 [email protected] ";"
35 [email protected] "\n " 35 [email protected] "\n "
36 FN_DEF@81..90 36 [email protected]
37 [email protected] "fn" 37 [email protected] "fn"
38 [email protected] " " 38 [email protected] " "
39 [email protected] 39 [email protected]
@@ -47,13 +47,13 @@ [email protected]
47 [email protected] "}" 47 [email protected] "}"
48 [email protected] ";" 48 [email protected] ";"
49 [email protected] "\n " 49 [email protected] "\n "
50 STRUCT_DEF@96..107 50 [email protected]
51 [email protected] "struct" 51 [email protected] "struct"
52 [email protected] " " 52 [email protected] " "
53 [email protected] 53 [email protected]
54 [email protected] "S" 54 [email protected] "S"
55 [email protected] " " 55 [email protected] " "
56 RECORD_FIELD_DEF_[email protected] 56 [email protected]
57 [email protected] "{" 57 [email protected] "{"
58 [email protected] "}" 58 [email protected] "}"
59 [email protected] ";" 59 [email protected] ";"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast
index 8e8d9e992..923effe38 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..66 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
index c457851c9..157513565 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..58 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "print_all" 6 [email protected] "print_all"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast
index ea325831e..a7f87c020 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..51 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -22,14 +22,14 @@ [email protected]
22 [email protected] " " 22 [email protected] " "
23 [email protected] "=" 23 [email protected] "="
24 [email protected] " " 24 [email protected] " "
25 RECORD_LIT@26..33 25 RECORD_EXPR@26..33
26 [email protected] 26 [email protected]
27 [email protected] 27 [email protected]
28 [email protected] 28 [email protected]
29 [email protected] "F" 29 [email protected] "F"
30 [email protected] 30 RECORD_EXPR_[email protected]
31 [email protected] "{" 31 [email protected] "{"
32 [email protected] 32 RECORD_EXPR_[email protected]
33 [email protected] 33 [email protected]
34 [email protected] "x" 34 [email protected] "x"
35 [email protected] ":" 35 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
index 9135de9df..6403ff8d5 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..25 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
index 14610a0a2..36fd2997b 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..27 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast b/crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast
index e6be8b7e4..d11019076 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..50 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
index 57fba5fd5..09fd9e9b8 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..117 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast
index 8d8b9597b..8d0f1ead5 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..554 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
index 7c092d518..b41ef4098 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..62 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast
index 8382a4f96..2d0c83458 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..42 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast
index 4b9b8e0ab..9312eab65 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..23 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] "const" 10 [email protected] "const"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast b/crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast
index 3c00a2647..0c35bf2b7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 CONST_DEF@0..39 2 [email protected]
3 [email protected] "const" 3 [email protected] "const"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast
index e70c3b710..8f197a19d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast
@@ -1,7 +1,7 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..28 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 TYP[email protected] 4 GENERIC[email protected]
5 [email protected] "<" 5 [email protected] "<"
6 [email protected] 6 [email protected]
7 [email protected] "const" 7 [email protected] "const"
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] "N" 32 [email protected] "N"
33 [email protected] ">" 33 [email protected] ">"
34 [email protected] " " 34 [email protected] " "
35 [email protected] 35 ASSOC_[email protected]
36 [email protected] "{" 36 [email protected] "{"
37 [email protected] "}" 37 [email protected] "}"
38 [email protected] "\n" 38 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast b/crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast
index 48d73a4e7..cc220e534 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..18 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Z" 6 [email protected] "Z"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -31,12 +31,12 @@ [email protected]
31 [email protected] ">" 31 [email protected] ">"
32 [email protected] ";" 32 [email protected] ";"
33 [email protected] "\n" 33 [email protected] "\n"
34 TRAIT_DEF@19..51 34 [email protected]
35 [email protected] "trait" 35 [email protected] "trait"
36 [email protected] " " 36 [email protected] " "
37 [email protected] 37 [email protected]
38 [email protected] "Z" 38 [email protected] "Z"
39 TYP[email protected] 39 GENERIC[email protected]
40 [email protected] "<" 40 [email protected] "<"
41 [email protected] 41 [email protected]
42 [email protected] 42 [email protected]
@@ -82,12 +82,12 @@ [email protected]
82 [email protected] "Copy" 82 [email protected] "Copy"
83 [email protected] ";" 83 [email protected] ";"
84 [email protected] "\n" 84 [email protected] "\n"
85 TRAIT_DEF@52..82 85 [email protected]
86 [email protected] "trait" 86 [email protected] "trait"
87 [email protected] " " 87 [email protected] " "
88 [email protected] 88 [email protected]
89 [email protected] "Z" 89 [email protected] "Z"
90 TYP[email protected] 90 GENERIC[email protected]
91 [email protected] "<" 91 [email protected] "<"
92 [email protected] 92 [email protected]
93 [email protected] 93 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast b/crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
index f43dfbe63..2905c5f1a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..33 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast
index 861065362..69b4d73d7 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..24 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -25,7 +25,7 @@ [email protected]
25 [email protected] ")" 25 [email protected] ")"
26 [email protected] ";" 26 [email protected] ";"
27 [email protected] "\n" 27 [email protected] "\n"
28 TYPE_ALIAS_DEF@25..54 28 [email protected]
29 [email protected] "type" 29 [email protected] "type"
30 [email protected] " " 30 [email protected] " "
31 [email protected] 31 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast
index ecac05950..c63a55a56 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..62 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast
index 092833417..3b8dfefc6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..29 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast
index 88d512f1a..4d4c41f1a 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..129 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast b/crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast
index fad9df007..ccca045b6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..22 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast b/crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast
index e8a0e9ddd..a2e05eb2e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast
@@ -1,19 +1,19 @@
1[email protected] 1[email protected]
2 ENUM_DEF@0..22 2 [email protected]
3 [email protected] "enum" 3 [email protected] "enum"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "E" 6 [email protected] "E"
7 [email protected] " " 7 [email protected] " "
8 ENUM_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] " " 10 [email protected] " "
11 ENUM_[email protected] 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "X" 13 [email protected] "X"
14 TUPLE_FIELD_DEF_[email protected] 14 [email protected]
15 [email protected] "(" 15 [email protected] "("
16 TUPLE_FIELD_DEF@11..14 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast b/crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast
index bd9e8d40f..8ae24b9c1 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..27 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast
index 08333a325..9c071ec2e 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..33 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast
index 5f09e4f4a..fb46d4ce4 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0159_try_macro_fallback.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..26 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0161_labeled_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0161_labeled_block.rast
index 9efebd8b8..9e9a5f9c5 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0161_labeled_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0161_labeled_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..22 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0162_unsafe_block.rast b/crates/ra_syntax/test_data/parser/inline/ok/0162_unsafe_block.rast
index 4991f2c36..ca9a1183d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0162_unsafe_block.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0162_unsafe_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..21 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
index adb6159f4..1269621dc 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..49 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -16,10 +16,10 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "Foo" 17 [email protected] "Foo"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 ASSOC_[email protected]
20 [email protected] "{" 20 [email protected] "{"
21 [email protected] "\n " 21 [email protected] "\n "
22 FN_DEF@21..47 22 [email protected]
23 [email protected] "default" 23 [email protected] "default"
24 [email protected] " " 24 [email protected] " "
25 [email protected] "unsafe" 25 [email protected] "unsafe"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast
index a9eda5668..6bfe925af 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..26 2 [email protected]
3 [email protected] "default" 3 [email protected] "default"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "unsafe" 5 [email protected] "unsafe"
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "Foo" 13 [email protected] "Foo"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 ASSOC_[email protected]
16 [email protected] "{" 16 [email protected] "{"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast
index 868899275..f5e20b93d 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_type_path_in_pattern.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..32 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast b/crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast
index 705f7e001..a171fe7a8 100644
--- a/crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..31 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -20,10 +20,10 @@ [email protected]
20 [email protected] "Copy" 20 [email protected] "Copy"
21 [email protected] ">" 21 [email protected] ">"
22 [email protected] " " 22 [email protected] " "
23 RECORD_FIELD_DEF_[email protected] 23 [email protected]
24 [email protected] "{" 24 [email protected] "{"
25 [email protected] "\n " 25 [email protected] "\n "
26 RECORD_FIELD_DEF@24..28 26 [email protected]
27 [email protected] 27 [email protected]
28 [email protected] "f" 28 [email protected] "f"
29 [email protected] ":" 29 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast b/crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast
index a1d546491..362892b91 100644
--- a/crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..25 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..23 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "foo" 13 [email protected] "foo"
14 [email protected] ":" 14 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast b/crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast
index 0ec237f8e..a7a2b11a7 100644
--- a/crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..12 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast b/crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast
index b5bdf0aa9..594c2f8f2 100644
--- a/crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 EXTERN_CRATE_ITEM@0..17 2 [email protected]
3 [email protected] "extern" 3 [email protected] "extern"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "crate" 5 [email protected] "crate"
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] "foo" 8 [email protected] "foo"
9 [email protected] ";" 9 [email protected] ";"
10 [email protected] "\n" 10 [email protected] "\n"
11 EXTERN_CRATE_ITEM@18..42 11 [email protected]
12 [email protected] "extern" 12 [email protected] "extern"
13 [email protected] " " 13 [email protected] " "
14 [email protected] "crate" 14 [email protected] "crate"
@@ -16,22 +16,21 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "foo" 17 [email protected] "foo"
18 [email protected] " " 18 [email protected] " "
19 ALIAS@35..41 19 RENAME@35..41
20 [email protected] "as" 20 [email protected] "as"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
23 [email protected] "bar" 23 [email protected] "bar"
24 [email protected] ";" 24 [email protected] ";"
25 [email protected] "\n" 25 [email protected] "\n"
26 EXTERN_CRATE_ITEM@43..68 26 [email protected]
27 [email protected] "extern" 27 [email protected] "extern"
28 [email protected] " " 28 [email protected] " "
29 [email protected] "crate" 29 [email protected] "crate"
30 [email protected] " " 30 [email protected] " "
31 [email protected] 31 [email protected] "self"
32 [email protected] "self"
33 [email protected] " " 32 [email protected] " "
34 ALIAS@61..67 33 RENAME@61..67
35 [email protected] "as" 34 [email protected] "as"
36 [email protected] " " 35 [email protected] " "
37 [email protected] 36 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast b/crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast
index 37b452ec4..b2c1d791f 100644
--- a/crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast
@@ -26,7 +26,7 @@ [email protected]
26 [email protected] 26 [email protected]
27 [email protected] "{" 27 [email protected] "{"
28 [email protected] "\n " 28 [email protected] "\n "
29 FN_DEF@31..47 29 [email protected]
30 [email protected] "fn" 30 [email protected] "fn"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
@@ -40,13 +40,13 @@ [email protected]
40 [email protected] "\n " 40 [email protected] "\n "
41 [email protected] "}" 41 [email protected] "}"
42 [email protected] "\n " 42 [email protected] "\n "
43 STRUCT_DEF@52..63 43 [email protected]
44 [email protected] "struct" 44 [email protected] "struct"
45 [email protected] " " 45 [email protected] " "
46 [email protected] 46 [email protected]
47 [email protected] "S" 47 [email protected] "S"
48 [email protected] " " 48 [email protected] " "
49 RECORD_FIELD_DEF_[email protected] 49 [email protected]
50 [email protected] "{" 50 [email protected] "{"
51 [email protected] "}" 51 [email protected] "}"
52 [email protected] "\n" 52 [email protected] "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast b/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
index 96b8a94fc..6be1cf9fc 100644
--- a/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0009_use_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..8 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] "foo" 9 [email protected] "foo"
10 [email protected] ";" 10 [email protected] ";"
11 [email protected] "\n" 11 [email protected] "\n"
12 USE_ITEM@9..19 12 [email protected]
13 [email protected] "use" 13 [email protected] "use"
14 [email protected] " " 14 [email protected] " "
15 [email protected] 15 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast b/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
index 07272dc3c..4d49e7933 100644
--- a/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..20 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -20,7 +20,7 @@ [email protected]
20 [email protected] "baz" 20 [email protected] "baz"
21 [email protected] ";" 21 [email protected] ";"
22 [email protected] "\n" 22 [email protected] "\n"
23 USE_ITEM@21..39 23 [email protected]
24 [email protected] "use" 24 [email protected] "use"
25 [email protected] " " 25 [email protected] " "
26 [email protected] 26 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast
index 0b9bc58e8..478fdba75 100644
--- a/crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..34 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/ok/0012_visibility.rast b/crates/ra_syntax/test_data/parser/ok/0012_visibility.rast
index 980b34049..83a93b5a9 100644
--- a/crates/ra_syntax/test_data/parser/ok/0012_visibility.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0012_visibility.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..9 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "}" 13 [email protected] "}"
14 [email protected] "\n" 14 [email protected] "\n"
15 FN_DEF@10..23 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "pub" 17 [email protected] "pub"
18 [email protected] " " 18 [email protected] " "
@@ -28,7 +28,7 @@ [email protected]
28 [email protected] "{" 28 [email protected] "{"
29 [email protected] "}" 29 [email protected] "}"
30 [email protected] "\n" 30 [email protected] "\n"
31 FN_DEF@24..44 31 [email protected]
32 [email protected] 32 [email protected]
33 [email protected] "pub" 33 [email protected] "pub"
34 [email protected] "(" 34 [email protected] "("
@@ -47,7 +47,7 @@ [email protected]
47 [email protected] "{" 47 [email protected] "{"
48 [email protected] "}" 48 [email protected] "}"
49 [email protected] "\n" 49 [email protected] "\n"
50 FN_DEF@45..65 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] "pub" 52 [email protected] "pub"
53 [email protected] "(" 53 [email protected] "("
@@ -66,7 +66,7 @@ [email protected]
66 [email protected] "{" 66 [email protected] "{"
67 [email protected] "}" 67 [email protected] "}"
68 [email protected] "\n" 68 [email protected] "\n"
69 FN_DEF@66..97 69 [email protected]
70 [email protected] 70 [email protected]
71 [email protected] "pub" 71 [email protected] "pub"
72 [email protected] "(" 72 [email protected] "("
diff --git a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
index 05d9c05ad..66ab13660 100644
--- a/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..14 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -13,7 +13,7 @@ [email protected]
13 [email protected] "foo" 13 [email protected] "foo"
14 [email protected] ";" 14 [email protected] ";"
15 [email protected] "\n" 15 [email protected] "\n"
16 USE_ITEM@15..37 16 [email protected]
17 [email protected] "use" 17 [email protected] "use"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast b/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
index 3642c107b..4389d2d4b 100644
--- a/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast
@@ -1,12 +1,12 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..6 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "*" 6 [email protected] "*"
7 [email protected] ";" 7 [email protected] ";"
8 [email protected] "\n" 8 [email protected] "\n"
9 USE_ITEM@7..15 9 [email protected]
10 [email protected] "use" 10 [email protected] "use"
11 [email protected] " " 11 [email protected] " "
12 [email protected] 12 [email protected]
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] "*" 14 [email protected] "*"
15 [email protected] ";" 15 [email protected] ";"
16 [email protected] "\n" 16 [email protected] "\n"
17 USE_ITEM@16..25 17 [email protected]
18 [email protected] "use" 18 [email protected] "use"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 [email protected]
@@ -24,7 +24,7 @@ [email protected]
24 [email protected] "}" 24 [email protected] "}"
25 [email protected] ";" 25 [email protected] ";"
26 [email protected] "\n" 26 [email protected] "\n"
27 USE_ITEM@26..33 27 [email protected]
28 [email protected] "use" 28 [email protected] "use"
29 [email protected] " " 29 [email protected] " "
30 [email protected] 30 [email protected]
@@ -33,7 +33,7 @@ [email protected]
33 [email protected] "}" 33 [email protected] "}"
34 [email protected] ";" 34 [email protected] ";"
35 [email protected] "\n" 35 [email protected] "\n"
36 USE_ITEM@34..45 36 [email protected]
37 [email protected] "use" 37 [email protected] "use"
38 [email protected] " " 38 [email protected] " "
39 [email protected] 39 [email protected]
@@ -45,7 +45,7 @@ [email protected]
45 [email protected] "*" 45 [email protected] "*"
46 [email protected] ";" 46 [email protected] ";"
47 [email protected] "\n" 47 [email protected] "\n"
48 USE_ITEM@46..58 48 [email protected]
49 [email protected] "use" 49 [email protected] "use"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 [email protected]
@@ -59,7 +59,7 @@ [email protected]
59 [email protected] "}" 59 [email protected] "}"
60 [email protected] ";" 60 [email protected] ";"
61 [email protected] "\n" 61 [email protected] "\n"
62 USE_ITEM@59..80 62 [email protected]
63 [email protected] "use" 63 [email protected] "use"
64 [email protected] " " 64 [email protected] " "
65 [email protected] 65 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast b/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
index 09e0050f0..d7e93f7eb 100644
--- a/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 USE_ITEM@0..15 2 [email protected]
3 [email protected] "use" 3 [email protected] "use"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,14 +8,14 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "foo" 9 [email protected] "foo"
10 [email protected] " " 10 [email protected] " "
11 ALIAS@8..14 11 RENAME@8..14
12 [email protected] "as" 12 [email protected] "as"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
15 [email protected] "bar" 15 [email protected] "bar"
16 [email protected] ";" 16 [email protected] ";"
17 [email protected] "\n" 17 [email protected] "\n"
18 USE_ITEM@16..54 18 [email protected]
19 [email protected] "use" 19 [email protected] "use"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 [email protected]
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] 32 [email protected]
33 [email protected] "a" 33 [email protected] "a"
34 [email protected] " " 34 [email protected] " "
35 ALIAS@28..32 35 RENAME@28..32
36 [email protected] "as" 36 [email protected] "as"
37 [email protected] " " 37 [email protected] " "
38 [email protected] 38 [email protected]
@@ -55,7 +55,7 @@ [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "foo" 56 [email protected] "foo"
57 [email protected] " " 57 [email protected] " "
58 ALIAS@48..52 58 RENAME@48..52
59 [email protected] "as" 59 [email protected] "as"
60 [email protected] " " 60 [email protected] " "
61 [email protected] 61 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast b/crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast
index 95656d19b..b15f41dd7 100644
--- a/crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast
@@ -1,41 +1,41 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..9 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "A" 6 [email protected] "A"
7 [email protected] ";" 7 [email protected] ";"
8 [email protected] "\n" 8 [email protected] "\n"
9 STRUCT_DEF@10..21 9 [email protected]
10 [email protected] "struct" 10 [email protected] "struct"
11 [email protected] " " 11 [email protected] " "
12 [email protected] 12 [email protected]
13 [email protected] "B" 13 [email protected] "B"
14 [email protected] " " 14 [email protected] " "
15 RECORD_FIELD_DEF_[email protected] 15 [email protected]
16 [email protected] "{" 16 [email protected] "{"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n" 18 [email protected] "\n"
19 STRUCT_DEF@22..33 19 [email protected]
20 [email protected] "struct" 20 [email protected] "struct"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
23 [email protected] "C" 23 [email protected] "C"
24 TUPLE_FIELD_DEF_[email protected] 24 [email protected]
25 [email protected] "(" 25 [email protected] "("
26 [email protected] ")" 26 [email protected] ")"
27 [email protected] ";" 27 [email protected] ";"
28 [email protected] "\n\n" 28 [email protected] "\n\n"
29 STRUCT_DEF@35..74 29 [email protected]
30 [email protected] "struct" 30 [email protected] "struct"
31 [email protected] " " 31 [email protected] " "
32 [email protected] 32 [email protected]
33 [email protected] "D" 33 [email protected] "D"
34 [email protected] " " 34 [email protected] " "
35 RECORD_FIELD_DEF_[email protected] 35 [email protected]
36 [email protected] "{" 36 [email protected] "{"
37 [email protected] "\n " 37 [email protected] "\n "
38 RECORD_FIELD_DEF@50..56 38 [email protected]
39 [email protected] 39 [email protected]
40 [email protected] "a" 40 [email protected] "a"
41 [email protected] ":" 41 [email protected] ":"
@@ -47,7 +47,7 @@ [email protected]
47 [email protected] "u32" 47 [email protected] "u32"
48 [email protected] "," 48 [email protected] ","
49 [email protected] "\n " 49 [email protected] "\n "
50 RECORD_FIELD_DEF@62..72 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] "pub" 52 [email protected] "pub"
53 [email protected] " " 53 [email protected] " "
@@ -63,14 +63,14 @@ [email protected]
63 [email protected] "\n" 63 [email protected] "\n"
64 [email protected] "}" 64 [email protected] "}"
65 [email protected] "\n\n" 65 [email protected] "\n\n"
66 STRUCT_DEF@76..96 66 [email protected]
67 [email protected] "struct" 67 [email protected] "struct"
68 [email protected] " " 68 [email protected] " "
69 [email protected] 69 [email protected]
70 [email protected] "E" 70 [email protected] "E"
71 TUPLE_FIELD_DEF_[email protected] 71 [email protected]
72 [email protected] "(" 72 [email protected] "("
73 TUPLE_FIELD_DEF@85..90 73 [email protected]
74 [email protected] 74 [email protected]
75 [email protected] "pub" 75 [email protected] "pub"
76 [email protected] " " 76 [email protected] " "
@@ -81,7 +81,7 @@ [email protected]
81 [email protected] "x" 81 [email protected] "x"
82 [email protected] "," 82 [email protected] ","
83 [email protected] " " 83 [email protected] " "
84 TUPLE_FIELD_DEF@92..93 84 [email protected]
85 [email protected] 85 [email protected]
86 [email protected] 86 [email protected]
87 [email protected] 87 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast b/crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
index 964cbf5dd..a3e091ad3 100644
--- a/crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..22 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast b/crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast
index 451634e3f..630aa0708 100644
--- a/crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..13 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S1" 6 [email protected] "S1"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -12,20 +12,20 @@ [email protected]
12 [email protected] ">" 12 [email protected] ">"
13 [email protected] ";" 13 [email protected] ";"
14 [email protected] "\n" 14 [email protected] "\n"
15 STRUCT_DEF@14..32 15 [email protected]
16 [email protected] "struct" 16 [email protected] "struct"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
19 [email protected] "S2" 19 [email protected] "S2"
20 TYP[email protected] 20 GENERIC[email protected]
21 [email protected] "<" 21 [email protected] "<"
22 [email protected] 22 [email protected]
23 [email protected] 23 [email protected]
24 [email protected] "T" 24 [email protected] "T"
25 [email protected] ">" 25 [email protected] ">"
26 TUPLE_FIELD_DEF_[email protected] 26 [email protected]
27 [email protected] "(" 27 [email protected] "("
28 TUPLE_FIELD_DEF@27..30 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] 31 [email protected]
@@ -34,22 +34,22 @@ [email protected]
34 [email protected] ")" 34 [email protected] ")"
35 [email protected] ";" 35 [email protected] ";"
36 [email protected] "\n" 36 [email protected] "\n"
37 STRUCT_DEF@33..56 37 [email protected]
38 [email protected] "struct" 38 [email protected] "struct"
39 [email protected] " " 39 [email protected] " "
40 [email protected] 40 [email protected]
41 [email protected] "S3" 41 [email protected] "S3"
42 TYP[email protected] 42 GENERIC[email protected]
43 [email protected] "<" 43 [email protected] "<"
44 [email protected] 44 [email protected]
45 [email protected] 45 [email protected]
46 [email protected] "T" 46 [email protected] "T"
47 [email protected] ">" 47 [email protected] ">"
48 [email protected] " " 48 [email protected] " "
49 RECORD_FIELD_DEF_[email protected] 49 [email protected]
50 [email protected] "{" 50 [email protected] "{"
51 [email protected] " " 51 [email protected] " "
52 RECORD_FIELD_DEF@48..54 52 [email protected]
53 [email protected] 53 [email protected]
54 [email protected] "u" 54 [email protected] "u"
55 [email protected] ":" 55 [email protected] ":"
@@ -62,34 +62,34 @@ [email protected]
62 [email protected] " " 62 [email protected] " "
63 [email protected] "}" 63 [email protected] "}"
64 [email protected] "\n\n" 64 [email protected] "\n\n"
65 STRUCT_DEF@58..70 65 [email protected]
66 [email protected] "struct" 66 [email protected] "struct"
67 [email protected] " " 67 [email protected] " "
68 [email protected] 68 [email protected]
69 [email protected] "S4" 69 [email protected] "S4"
70 TYP[email protected] 70 GENERIC[email protected]
71 [email protected] "<" 71 [email protected] "<"
72 [email protected] ">" 72 [email protected] ">"
73 [email protected] ";" 73 [email protected] ";"
74 [email protected] "\n" 74 [email protected] "\n"
75 STRUCT_DEF@71..85 75 [email protected]
76 [email protected] "struct" 76 [email protected] "struct"
77 [email protected] " " 77 [email protected] " "
78 [email protected] 78 [email protected]
79 [email protected] "S5" 79 [email protected] "S5"
80 TYP[email protected] 80 GENERIC[email protected]
81 [email protected] "<" 81 [email protected] "<"
82 [email protected] 82 [email protected]
83 [email protected] "\'a" 83 [email protected] "\'a"
84 [email protected] ">" 84 [email protected] ">"
85 [email protected] ";" 85 [email protected] ";"
86 [email protected] "\n" 86 [email protected] "\n"
87 STRUCT_DEF@86..101 87 [email protected]
88 [email protected] "struct" 88 [email protected] "struct"
89 [email protected] " " 89 [email protected] " "
90 [email protected] 90 [email protected]
91 [email protected] "S6" 91 [email protected] "S6"
92 TYP[email protected] 92 GENERIC[email protected]
93 [email protected] "<" 93 [email protected] "<"
94 [email protected] 94 [email protected]
95 [email protected] "\'a" 95 [email protected] "\'a"
@@ -97,12 +97,12 @@ [email protected]
97 [email protected] ">" 97 [email protected] ">"
98 [email protected] ";" 98 [email protected] ";"
99 [email protected] "\n" 99 [email protected] "\n"
100 STRUCT_DEF@102..120 100 [email protected]
101 [email protected] "struct" 101 [email protected] "struct"
102 [email protected] " " 102 [email protected] " "
103 [email protected] 103 [email protected]
104 [email protected] "S7" 104 [email protected] "S7"
105 TYP[email protected] 105 GENERIC[email protected]
106 [email protected] "<" 106 [email protected] "<"
107 [email protected] 107 [email protected]
108 [email protected] "\'a" 108 [email protected] "\'a"
@@ -112,12 +112,12 @@ [email protected]
112 [email protected] ">" 112 [email protected] ">"
113 [email protected] ";" 113 [email protected] ";"
114 [email protected] "\n" 114 [email protected] "\n"
115 STRUCT_DEF@121..142 115 [email protected]
116 [email protected] "struct" 116 [email protected] "struct"
117 [email protected] " " 117 [email protected] " "
118 [email protected] 118 [email protected]
119 [email protected] "S8" 119 [email protected] "S8"
120 TYP[email protected] 120 GENERIC[email protected]
121 [email protected] "<" 121 [email protected] "<"
122 [email protected] 122 [email protected]
123 [email protected] "\'a" 123 [email protected] "\'a"
@@ -130,12 +130,12 @@ [email protected]
130 [email protected] ">" 130 [email protected] ">"
131 [email protected] ";" 131 [email protected] ";"
132 [email protected] "\n" 132 [email protected] "\n"
133 STRUCT_DEF@143..166 133 [email protected]
134 [email protected] "struct" 134 [email protected] "struct"
135 [email protected] " " 135 [email protected] " "
136 [email protected] 136 [email protected]
137 [email protected] "S9" 137 [email protected] "S9"
138 TYP[email protected] 138 GENERIC[email protected]
139 [email protected] "<" 139 [email protected] "<"
140 [email protected] 140 [email protected]
141 [email protected] "\'a" 141 [email protected] "\'a"
@@ -149,12 +149,12 @@ [email protected]
149 [email protected] ">" 149 [email protected] ">"
150 [email protected] ";" 150 [email protected] ";"
151 [email protected] "\n" 151 [email protected] "\n"
152 STRUCT_DEF@167..183 152 [email protected]
153 [email protected] "struct" 153 [email protected] "struct"
154 [email protected] " " 154 [email protected] " "
155 [email protected] 155 [email protected]
156 [email protected] "S10" 156 [email protected] "S10"
157 TYP[email protected] 157 GENERIC[email protected]
158 [email protected] "<" 158 [email protected] "<"
159 [email protected] 159 [email protected]
160 [email protected] "\'a" 160 [email protected] "\'a"
@@ -162,12 +162,12 @@ [email protected]
162 [email protected] ">" 162 [email protected] ">"
163 [email protected] ";" 163 [email protected] ";"
164 [email protected] "\n" 164 [email protected] "\n"
165 STRUCT_DEF@184..203 165 [email protected]
166 [email protected] "struct" 166 [email protected] "struct"
167 [email protected] " " 167 [email protected] " "
168 [email protected] 168 [email protected]
169 [email protected] "S11" 169 [email protected] "S11"
170 TYP[email protected] 170 GENERIC[email protected]
171 [email protected] "<" 171 [email protected] "<"
172 [email protected] 172 [email protected]
173 [email protected] "\'a" 173 [email protected] "\'a"
@@ -178,12 +178,12 @@ [email protected]
178 [email protected] ">" 178 [email protected] ">"
179 [email protected] ";" 179 [email protected] ";"
180 [email protected] "\n" 180 [email protected] "\n"
181 STRUCT_DEF@204..233 181 [email protected]
182 [email protected] "struct" 182 [email protected] "struct"
183 [email protected] " " 183 [email protected] " "
184 [email protected] 184 [email protected]
185 [email protected] "S12" 185 [email protected] "S12"
186 TYP[email protected] 186 GENERIC[email protected]
187 [email protected] "<" 187 [email protected] "<"
188 [email protected] 188 [email protected]
189 [email protected] "\'a" 189 [email protected] "\'a"
@@ -202,12 +202,12 @@ [email protected]
202 [email protected] ">" 202 [email protected] ">"
203 [email protected] ";" 203 [email protected] ";"
204 [email protected] "\n\n" 204 [email protected] "\n\n"
205 STRUCT_DEF@235..249 205 [email protected]
206 [email protected] "struct" 206 [email protected] "struct"
207 [email protected] " " 207 [email protected] " "
208 [email protected] 208 [email protected]
209 [email protected] "S13" 209 [email protected] "S13"
210 TYP[email protected] 210 GENERIC[email protected]
211 [email protected] "<" 211 [email protected] "<"
212 [email protected] 212 [email protected]
213 [email protected] 213 [email protected]
@@ -215,12 +215,12 @@ [email protected]
215 [email protected] ">" 215 [email protected] ">"
216 [email protected] ";" 216 [email protected] ";"
217 [email protected] "\n" 217 [email protected] "\n"
218 STRUCT_DEF@250..267 218 [email protected]
219 [email protected] "struct" 219 [email protected] "struct"
220 [email protected] " " 220 [email protected] " "
221 [email protected] 221 [email protected]
222 [email protected] "S14" 222 [email protected] "S14"
223 TYP[email protected] 223 GENERIC[email protected]
224 [email protected] "<" 224 [email protected] "<"
225 [email protected] 225 [email protected]
226 [email protected] 226 [email protected]
@@ -233,12 +233,12 @@ [email protected]
233 [email protected] ">" 233 [email protected] ">"
234 [email protected] ";" 234 [email protected] ";"
235 [email protected] "\n" 235 [email protected] "\n"
236 STRUCT_DEF@268..289 236 [email protected]
237 [email protected] "struct" 237 [email protected] "struct"
238 [email protected] " " 238 [email protected] " "
239 [email protected] 239 [email protected]
240 [email protected] "S15" 240 [email protected] "S15"
241 TYP[email protected] 241 GENERIC[email protected]
242 [email protected] "<" 242 [email protected] "<"
243 [email protected] 243 [email protected]
244 [email protected] "\'a" 244 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/ok/0019_enums.rast b/crates/ra_syntax/test_data/parser/ok/0019_enums.rast
index f767e9e19..c3df00814 100644
--- a/crates/ra_syntax/test_data/parser/ok/0019_enums.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0019_enums.rast
@@ -1,78 +1,78 @@
1[email protected] 1[email protected]
2 ENUM_DEF@0..11 2 [email protected]
3 [email protected] "enum" 3 [email protected] "enum"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "E1" 6 [email protected] "E1"
7 [email protected] " " 7 [email protected] " "
8 ENUM_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n" 10 [email protected] "\n"
11 [email protected] "}" 11 [email protected] "}"
12 [email protected] "\n\n" 12 [email protected] "\n\n"
13 ENUM_DEF@13..27 13 [email protected]
14 [email protected] "enum" 14 [email protected] "enum"
15 [email protected] " " 15 [email protected] " "
16 [email protected] 16 [email protected]
17 [email protected] "E2" 17 [email protected] "E2"
18 TYP[email protected] 18 GENERIC[email protected]
19 [email protected] "<" 19 [email protected] "<"
20 [email protected] 20 [email protected]
21 [email protected] 21 [email protected]
22 [email protected] "T" 22 [email protected] "T"
23 [email protected] ">" 23 [email protected] ">"
24 [email protected] " " 24 [email protected] " "
25 ENUM_[email protected] 25 [email protected]
26 [email protected] "{" 26 [email protected] "{"
27 [email protected] "\n" 27 [email protected] "\n"
28 [email protected] "}" 28 [email protected] "}"
29 [email protected] "\n\n" 29 [email protected] "\n\n"
30 ENUM_DEF@29..46 30 [email protected]
31 [email protected] "enum" 31 [email protected] "enum"
32 [email protected] " " 32 [email protected] " "
33 [email protected] 33 [email protected]
34 [email protected] "E3" 34 [email protected] "E3"
35 [email protected] " " 35 [email protected] " "
36 ENUM_[email protected] 36 [email protected]
37 [email protected] "{" 37 [email protected] "{"
38 [email protected] "\n " 38 [email protected] "\n "
39 ENUM_[email protected] 39 [email protected]
40 [email protected] 40 [email protected]
41 [email protected] "X" 41 [email protected] "X"
42 [email protected] "\n" 42 [email protected] "\n"
43 [email protected] "}" 43 [email protected] "}"
44 [email protected] "\n\n" 44 [email protected] "\n\n"
45 ENUM_DEF@48..66 45 [email protected]
46 [email protected] "enum" 46 [email protected] "enum"
47 [email protected] " " 47 [email protected] " "
48 [email protected] 48 [email protected]
49 [email protected] "E4" 49 [email protected] "E4"
50 [email protected] " " 50 [email protected] " "
51 ENUM_[email protected] 51 [email protected]
52 [email protected] "{" 52 [email protected] "{"
53 [email protected] "\n " 53 [email protected] "\n "
54 ENUM_[email protected] 54 [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "X" 56 [email protected] "X"
57 [email protected] "," 57 [email protected] ","
58 [email protected] "\n" 58 [email protected] "\n"
59 [email protected] "}" 59 [email protected] "}"
60 [email protected] "\n\n" 60 [email protected] "\n\n"
61 ENUM_DEF@68..181 61 [email protected]
62 [email protected] "enum" 62 [email protected] "enum"
63 [email protected] " " 63 [email protected] " "
64 [email protected] 64 [email protected]
65 [email protected] "E5" 65 [email protected] "E5"
66 [email protected] " " 66 [email protected] " "
67 ENUM_[email protected] 67 [email protected]
68 [email protected] "{" 68 [email protected] "{"
69 [email protected] "\n " 69 [email protected] "\n "
70 ENUM_[email protected] 70 [email protected]
71 [email protected] 71 [email protected]
72 [email protected] "A" 72 [email protected] "A"
73 [email protected] "," 73 [email protected] ","
74 [email protected] "\n " 74 [email protected] "\n "
75 ENUM_[email protected] 75 [email protected]
76 [email protected] 76 [email protected]
77 [email protected] "B" 77 [email protected] "B"
78 [email protected] " " 78 [email protected] " "
@@ -82,14 +82,14 @@ [email protected]
82 [email protected] "92" 82 [email protected] "92"
83 [email protected] "," 83 [email protected] ","
84 [email protected] "\n " 84 [email protected] "\n "
85 ENUM_[email protected] 85 [email protected]
86 [email protected] 86 [email protected]
87 [email protected] "C" 87 [email protected] "C"
88 [email protected] " " 88 [email protected] " "
89 RECORD_FIELD_DEF_[email protected] 89 [email protected]
90 [email protected] "{" 90 [email protected] "{"
91 [email protected] "\n " 91 [email protected] "\n "
92 RECORD_FIELD_DEF@113..119 92 [email protected]
93 [email protected] 93 [email protected]
94 [email protected] "a" 94 [email protected] "a"
95 [email protected] ":" 95 [email protected] ":"
@@ -101,7 +101,7 @@ [email protected]
101 [email protected] "u32" 101 [email protected] "u32"
102 [email protected] "," 102 [email protected] ","
103 [email protected] "\n " 103 [email protected] "\n "
104 RECORD_FIELD_DEF@129..139 104 [email protected]
105 [email protected] 105 [email protected]
106 [email protected] "pub" 106 [email protected] "pub"
107 [email protected] " " 107 [email protected] " "
@@ -119,21 +119,21 @@ [email protected]
119 [email protected] "}" 119 [email protected] "}"
120 [email protected] "," 120 [email protected] ","
121 [email protected] "\n " 121 [email protected] "\n "
122 ENUM_[email protected] 122 [email protected]
123 [email protected] 123 [email protected]
124 [email protected] "F" 124 [email protected] "F"
125 [email protected] " " 125 [email protected] " "
126 RECORD_FIELD_DEF_[email protected] 126 [email protected]
127 [email protected] "{" 127 [email protected] "{"
128 [email protected] "}" 128 [email protected] "}"
129 [email protected] "," 129 [email protected] ","
130 [email protected] "\n " 130 [email protected] "\n "
131 ENUM_[email protected] 131 [email protected]
132 [email protected] 132 [email protected]
133 [email protected] "D" 133 [email protected] "D"
134 TUPLE_FIELD_DEF_[email protected] 134 [email protected]
135 [email protected] "(" 135 [email protected] "("
136 TUPLE_FIELD_DEF@164..167 136 [email protected]
137 [email protected] 137 [email protected]
138 [email protected] 138 [email protected]
139 [email protected] 139 [email protected]
@@ -143,10 +143,10 @@ [email protected]
143 [email protected] ")" 143 [email protected] ")"
144 [email protected] "," 144 [email protected] ","
145 [email protected] "\n " 145 [email protected] "\n "
146 ENUM_[email protected] 146 [email protected]
147 [email protected] 147 [email protected]
148 [email protected] "E" 148 [email protected] "E"
149 TUPLE_FIELD_DEF_[email protected] 149 [email protected]
150 [email protected] "(" 150 [email protected] "("
151 [email protected] ")" 151 [email protected] ")"
152 [email protected] "," 152 [email protected] ","
diff --git a/crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast b/crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast
index 4fb4baf56..9bdc50e1e 100644
--- a/crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..12 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "A" 6 [email protected] "A"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -12,12 +12,12 @@ [email protected]
12 [email protected] ">" 12 [email protected] ">"
13 [email protected] ";" 13 [email protected] ";"
14 [email protected] "\n" 14 [email protected] "\n"
15 STRUCT_DEF@13..26 15 [email protected]
16 [email protected] "struct" 16 [email protected] "struct"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
19 [email protected] "B" 19 [email protected] "B"
20 TYP[email protected] 20 GENERIC[email protected]
21 [email protected] "<" 21 [email protected] "<"
22 [email protected] 22 [email protected]
23 [email protected] 23 [email protected]
@@ -27,12 +27,12 @@ [email protected]
27 [email protected] ">" 27 [email protected] ">"
28 [email protected] ";" 28 [email protected] ";"
29 [email protected] "\n" 29 [email protected] "\n"
30 STRUCT_DEF@27..43 30 [email protected]
31 [email protected] "struct" 31 [email protected] "struct"
32 [email protected] " " 32 [email protected] " "
33 [email protected] 33 [email protected]
34 [email protected] "C" 34 [email protected] "C"
35 TYP[email protected] 35 GENERIC[email protected]
36 [email protected] "<" 36 [email protected] "<"
37 [email protected] 37 [email protected]
38 [email protected] 38 [email protected]
@@ -45,12 +45,12 @@ [email protected]
45 [email protected] ">" 45 [email protected] ">"
46 [email protected] ";" 46 [email protected] ";"
47 [email protected] "\n" 47 [email protected] "\n"
48 STRUCT_DEF@44..63 48 [email protected]
49 [email protected] "struct" 49 [email protected] "struct"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 [email protected]
52 [email protected] "D" 52 [email protected] "D"
53 TYP[email protected] 53 GENERIC[email protected]
54 [email protected] "<" 54 [email protected] "<"
55 [email protected] 55 [email protected]
56 [email protected] 56 [email protected]
@@ -66,12 +66,12 @@ [email protected]
66 [email protected] ">" 66 [email protected] ">"
67 [email protected] ";" 67 [email protected] ";"
68 [email protected] "\n" 68 [email protected] "\n"
69 STRUCT_DEF@64..86 69 [email protected]
70 [email protected] "struct" 70 [email protected] "struct"
71 [email protected] " " 71 [email protected] " "
72 [email protected] 72 [email protected]
73 [email protected] "E" 73 [email protected] "E"
74 TYP[email protected] 74 GENERIC[email protected]
75 [email protected] "<" 75 [email protected] "<"
76 [email protected] 76 [email protected]
77 [email protected] 77 [email protected]
@@ -90,12 +90,12 @@ [email protected]
90 [email protected] ">" 90 [email protected] ">"
91 [email protected] ";" 91 [email protected] ";"
92 [email protected] "\n" 92 [email protected] "\n"
93 STRUCT_DEF@87..116 93 [email protected]
94 [email protected] "struct" 94 [email protected] "struct"
95 [email protected] " " 95 [email protected] " "
96 [email protected] 96 [email protected]
97 [email protected] "F" 97 [email protected] "F"
98 TYP[email protected] 98 GENERIC[email protected]
99 [email protected] "<" 99 [email protected] "<"
100 [email protected] 100 [email protected]
101 [email protected] 101 [email protected]
@@ -122,12 +122,12 @@ [email protected]
122 [email protected] ">" 122 [email protected] ">"
123 [email protected] ";" 123 [email protected] ";"
124 [email protected] "\n" 124 [email protected] "\n"
125 STRUCT_DEF@117..143 125 [email protected]
126 [email protected] "struct" 126 [email protected] "struct"
127 [email protected] " " 127 [email protected] " "
128 [email protected] 128 [email protected]
129 [email protected] "G" 129 [email protected] "G"
130 TYP[email protected] 130 GENERIC[email protected]
131 [email protected] "<" 131 [email protected] "<"
132 [email protected] 132 [email protected]
133 [email protected] 133 [email protected]
@@ -153,12 +153,12 @@ [email protected]
153 [email protected] ">" 153 [email protected] ">"
154 [email protected] ";" 154 [email protected] ";"
155 [email protected] "\n" 155 [email protected] "\n"
156 STRUCT_DEF@144..180 156 [email protected]
157 [email protected] "struct" 157 [email protected] "struct"
158 [email protected] " " 158 [email protected] " "
159 [email protected] 159 [email protected]
160 [email protected] "H" 160 [email protected] "H"
161 TYP[email protected] 161 GENERIC[email protected]
162 [email protected] "<" 162 [email protected] "<"
163 [email protected] 163 [email protected]
164 [email protected] 164 [email protected]
@@ -194,12 +194,12 @@ [email protected]
194 [email protected] ">" 194 [email protected] ">"
195 [email protected] ";" 195 [email protected] ";"
196 [email protected] "\n" 196 [email protected] "\n"
197 STRUCT_DEF@181..199 197 [email protected]
198 [email protected] "struct" 198 [email protected] "struct"
199 [email protected] " " 199 [email protected] " "
200 [email protected] 200 [email protected]
201 [email protected] "I" 201 [email protected] "I"
202 TYP[email protected] 202 GENERIC[email protected]
203 [email protected] "<" 203 [email protected] "<"
204 [email protected] 204 [email protected]
205 [email protected] 205 [email protected]
@@ -217,12 +217,12 @@ [email protected]
217 [email protected] ">" 217 [email protected] ">"
218 [email protected] ";" 218 [email protected] ";"
219 [email protected] "\n" 219 [email protected] "\n"
220 STRUCT_DEF@200..250 220 [email protected]
221 [email protected] "struct" 221 [email protected] "struct"
222 [email protected] " " 222 [email protected] " "
223 [email protected] 223 [email protected]
224 [email protected] "K" 224 [email protected] "K"
225 TYP[email protected] 225 GENERIC[email protected]
226 [email protected] "<" 226 [email protected] "<"
227 [email protected] 227 [email protected]
228 [email protected] "\'a" 228 [email protected] "\'a"
diff --git a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast
index 873791f50..5524efaaf 100644
--- a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..19 2 [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "extern" 4 [email protected] "extern"
5 [email protected] " " 5 [email protected] " "
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] "\n" 16 [email protected] "\n"
17 [email protected] "}" 17 [email protected] "}"
18 [email protected] "\n\n" 18 [email protected] "\n\n"
19 FN_DEF@21..44 19 [email protected]
20 [email protected] 20 [email protected]
21 [email protected] "extern" 21 [email protected] "extern"
22 [email protected] " " 22 [email protected] " "
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] "\n" 35 [email protected] "\n"
36 [email protected] "}" 36 [email protected] "}"
37 [email protected] "\n\n" 37 [email protected] "\n\n"
38 FN_DEF@46..70 38 [email protected]
39 [email protected] 39 [email protected]
40 [email protected] "extern" 40 [email protected] "extern"
41 [email protected] " " 41 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/ok/0023_static_items.rast b/crates/ra_syntax/test_data/parser/ok/0023_static_items.rast
index 97d90dc75..9374cf5e9 100644
--- a/crates/ra_syntax/test_data/parser/ok/0023_static_items.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0023_static_items.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 STATIC_DEF@0..20 2 [email protected]
3 [email protected] "static" 3 [email protected] "static"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -18,7 +18,7 @@ [email protected]
18 [email protected] "1" 18 [email protected] "1"
19 [email protected] ";" 19 [email protected] ";"
20 [email protected] "\n" 20 [email protected] "\n"
21 STATIC_DEF@21..46 21 [email protected]
22 [email protected] "static" 22 [email protected] "static"
23 [email protected] " " 23 [email protected] " "
24 [email protected] "mut" 24 [email protected] "mut"
diff --git a/crates/ra_syntax/test_data/parser/ok/0024_const_item.rast b/crates/ra_syntax/test_data/parser/ok/0024_const_item.rast
index d241f034c..dd1b9c9a0 100644
--- a/crates/ra_syntax/test_data/parser/ok/0024_const_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0024_const_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 CONST_DEF@0..17 2 [email protected]
3 [email protected] "const" 3 [email protected] "const"
4 [email protected] " " 4 [email protected] " "
5 [email protected] "_" 5 [email protected] "_"
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] "0" 17 [email protected] "0"
18 [email protected] ";" 18 [email protected] ";"
19 [email protected] "\n" 19 [email protected] "\n"
20 CONST_DEF@18..38 20 [email protected]
21 [email protected] "const" 21 [email protected] "const"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 [email protected]
@@ -36,7 +36,7 @@ [email protected]
36 [email protected] "92" 36 [email protected] "92"
37 [email protected] ";" 37 [email protected] ";"
38 [email protected] "\n" 38 [email protected] "\n"
39 CONST_DEF@39..63 39 [email protected]
40 [email protected] "const" 40 [email protected] "const"
41 [email protected] " " 41 [email protected] " "
42 [email protected] "mut" 42 [email protected] "mut"
diff --git a/crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast b/crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast
index 5701f566e..bb6527b48 100644
--- a/crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..34 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,7 +11,7 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@16..32 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "extern" 16 [email protected] "extern"
17 [email protected] " " 17 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast b/crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast
index b029d8692..5bcf54deb 100644
--- a/crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..33 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,7 +11,7 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@16..31 14 [email protected]
15 [email protected] "const" 15 [email protected] "const"
16 [email protected] " " 16 [email protected] " "
17 [email protected] "fn" 17 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast b/crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast
index 299bbd136..a7cc12295 100644
--- a/crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..52 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -11,7 +11,7 @@ [email protected]
11 [email protected] 11 [email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@16..32 14 [email protected]
15 [email protected] "unsafe" 15 [email protected] "unsafe"
16 [email protected] " " 16 [email protected] " "
17 [email protected] "fn" 17 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast b/crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast
index de3c4b786..efe018484 100644
--- a/crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..247 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast b/crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast
index dc47d68a6..47e46f009 100644
--- a/crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..152 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast b/crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast
index 86c3b46c4..93f766149 100644
--- a/crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..111 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0030_traits.rast b/crates/ra_syntax/test_data/parser/ok/0030_traits.rast
index 0aadc11a4..280d4cb82 100644
--- a/crates/ra_syntax/test_data/parser/ok/0030_traits.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0030_traits.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..36 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "Runnable" 6 [email protected] "Runnable"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 ASSOC_[email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 FN_DEF@21..34 11 [email protected]
12 [email protected] "fn" 12 [email protected] "fn"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
@@ -20,16 +20,16 @@ [email protected]
20 [email protected] "\n" 20 [email protected] "\n"
21 [email protected] "}" 21 [email protected] "}"
22 [email protected] "\n\n" 22 [email protected] "\n\n"
23 TRAIT_DEF@38..95 23 [email protected]
24 [email protected] "trait" 24 [email protected] "trait"
25 [email protected] " " 25 [email protected] " "
26 [email protected] 26 [email protected]
27 [email protected] "TraitWithExpr" 27 [email protected] "TraitWithExpr"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 ASSOC_[email protected]
30 [email protected] "{" 30 [email protected] "{"
31 [email protected] "\n " 31 [email protected] "\n "
32 FN_DEF@64..93 32 [email protected]
33 [email protected] "fn" 33 [email protected] "fn"
34 [email protected] " " 34 [email protected] " "
35 [email protected] 35 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0031_extern.rast b/crates/ra_syntax/test_data/parser/ok/0031_extern.rast
index ea285f52f..0509f7504 100644
--- a/crates/ra_syntax/test_data/parser/ok/0031_extern.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0031_extern.rast
@@ -6,7 +6,7 @@ [email protected]
6 [email protected] 6 [email protected]
7 [email protected] "{" 7 [email protected] "{"
8 [email protected] "\n " 8 [email protected] "\n "
9 FN_DEF@13..87 9 [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "pub" 11 [email protected] "pub"
12 [email protected] " " 12 [email protected] " "
@@ -69,7 +69,7 @@ [email protected]
69 [email protected] "c_int" 69 [email protected] "c_int"
70 [email protected] ";" 70 [email protected] ";"
71 [email protected] "\n " 71 [email protected] "\n "
72 FN_DEF@92..167 72 [email protected]
73 [email protected] 73 [email protected]
74 [email protected] "pub" 74 [email protected] "pub"
75 [email protected] " " 75 [email protected] " "
@@ -134,7 +134,7 @@ [email protected]
134 [email protected] "c_int" 134 [email protected] "c_int"
135 [email protected] ";" 135 [email protected] ";"
136 [email protected] "\n " 136 [email protected] "\n "
137 FN_DEF@172..276 137 [email protected]
138 [email protected] 138 [email protected]
139 [email protected] "pub" 139 [email protected] "pub"
140 [email protected] " " 140 [email protected] " "
@@ -199,7 +199,7 @@ [email protected]
199 [email protected] "c_int" 199 [email protected] "c_int"
200 [email protected] ";" 200 [email protected] ";"
201 [email protected] "\n " 201 [email protected] "\n "
202 FN_DEF@281..341 202 [email protected]
203 [email protected] 203 [email protected]
204 [email protected] "pub" 204 [email protected] "pub"
205 [email protected] " " 205 [email protected] " "
@@ -248,7 +248,7 @@ [email protected]
248 [email protected] "c_int" 248 [email protected] "c_int"
249 [email protected] ";" 249 [email protected] ";"
250 [email protected] "\n " 250 [email protected] "\n "
251 FN_DEF@346..469 251 [email protected]
252 [email protected] 252 [email protected]
253 [email protected] "pub" 253 [email protected] "pub"
254 [email protected] " " 254 [email protected] " "
@@ -317,7 +317,7 @@ [email protected]
317 [email protected] "c_int" 317 [email protected] "c_int"
318 [email protected] ";" 318 [email protected] ";"
319 [email protected] "\n " 319 [email protected] "\n "
320 FN_DEF@474..691 320 [email protected]
321 [email protected] 321 [email protected]
322 [email protected] "pub" 322 [email protected] "pub"
323 [email protected] " " 323 [email protected] " "
@@ -416,7 +416,7 @@ [email protected]
416 [email protected] "c_int" 416 [email protected] "c_int"
417 [email protected] ";" 417 [email protected] ";"
418 [email protected] "\n " 418 [email protected] "\n "
419 FN_DEF@696..864 419 [email protected]
420 [email protected] 420 [email protected]
421 [email protected] "pub" 421 [email protected] "pub"
422 [email protected] " " 422 [email protected] " "
@@ -510,7 +510,7 @@ [email protected]
510 [email protected] "c_int" 510 [email protected] "c_int"
511 [email protected] ";" 511 [email protected] ";"
512 [email protected] "\n " 512 [email protected] "\n "
513 FN_DEF@869..992 513 [email protected]
514 [email protected] 514 [email protected]
515 [email protected] "pub" 515 [email protected] "pub"
516 [email protected] " " 516 [email protected] " "
@@ -579,7 +579,7 @@ [email protected]
579 [email protected] "c_int" 579 [email protected] "c_int"
580 [email protected] ";" 580 [email protected] ";"
581 [email protected] "\n " 581 [email protected] "\n "
582 FN_DEF@997..1173 582 [email protected]
583 [email protected] 583 [email protected]
584 [email protected] "pub" 584 [email protected] "pub"
585 [email protected] " " 585 [email protected] " "
@@ -690,7 +690,7 @@ [email protected]
690 [email protected] "ssize_t" 690 [email protected] "ssize_t"
691 [email protected] ";" 691 [email protected] ";"
692 [email protected] "\n " 692 [email protected] "\n "
693 FN_DEF@1178..1289 693 [email protected]
694 [email protected] 694 [email protected]
695 [email protected] "pub" 695 [email protected] "pub"
696 [email protected] " " 696 [email protected] " "
@@ -771,7 +771,7 @@ [email protected]
771 [email protected] "ssize_t" 771 [email protected] "ssize_t"
772 [email protected] ";" 772 [email protected] ";"
773 [email protected] "\n " 773 [email protected] "\n "
774 FN_DEF@1294..1481 774 [email protected]
775 [email protected] 775 [email protected]
776 [email protected] "pub" 776 [email protected] "pub"
777 [email protected] " " 777 [email protected] " "
@@ -888,7 +888,7 @@ [email protected]
888 [email protected] "ssize_t" 888 [email protected] "ssize_t"
889 [email protected] ";" 889 [email protected] ";"
890 [email protected] "\n " 890 [email protected] "\n "
891 FN_DEF@1486..1595 891 [email protected]
892 [email protected] 892 [email protected]
893 [email protected] "pub" 893 [email protected] "pub"
894 [email protected] " " 894 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/ok/0032_where_for.rast b/crates/ra_syntax/test_data/parser/ok/0032_where_for.rast
index 8d76c4e0b..10da87c71 100644
--- a/crates/ra_syntax/test_data/parser/ok/0032_where_for.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0032_where_for.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..115 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "test_serialization" 6 [email protected] "test_serialization"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -38,7 +38,7 @@ [email protected]
38 [email protected] 38 [email protected]
39 [email protected] 39 [email protected]
40 [email protected] "for" 40 [email protected] "for"
41 TYP[email protected] 41 GENERIC[email protected]
42 [email protected] "<" 42 [email protected] "<"
43 [email protected] 43 [email protected]
44 [email protected] "\'de" 44 [email protected] "\'de"
diff --git a/crates/ra_syntax/test_data/parser/ok/0033_label_break.rast b/crates/ra_syntax/test_data/parser/ok/0033_label_break.rast
index 13b730ded..b3f29638c 100644
--- a/crates/ra_syntax/test_data/parser/ok/0033_label_break.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0033_label_break.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..505 2 [email protected]
3 [email protected] "// format with label ..." 3 [email protected] "// format with label ..."
4 [email protected] "\n" 4 [email protected] "\n"
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast b/crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast
index 21874ae3a..5ad8c570d 100644
--- a/crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..61 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
index eb59d6e17..b04a505ea 100644
--- a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast
@@ -78,7 +78,7 @@ [email protected]
78 [email protected] "\"128\"" 78 [email protected] "\"128\""
79 [email protected] "]" 79 [email protected] "]"
80 [email protected] "\n\n" 80 [email protected] "\n\n"
81 USE_ITEM@407..427 81 [email protected]
82 [email protected] "use" 82 [email protected] "use"
83 [email protected] " " 83 [email protected] " "
84 [email protected] 84 [email protected]
@@ -98,7 +98,7 @@ [email protected]
98 [email protected] "Cell" 98 [email protected] "Cell"
99 [email protected] ";" 99 [email protected] ";"
100 [email protected] "\n" 100 [email protected] "\n"
101 USE_ITEM@428..447 101 [email protected]
102 [email protected] "use" 102 [email protected] "use"
103 [email protected] " " 103 [email protected] " "
104 [email protected] 104 [email protected]
@@ -120,7 +120,7 @@ [email protected]
120 [email protected] "\n\n" 120 [email protected] "\n\n"
121 [email protected] "// Just a grab bag of ..." 121 [email protected] "// Just a grab bag of ..."
122 [email protected] "\n\n" 122 [email protected] "\n\n"
123 FN_DEF@520..572 123 [email protected]
124 [email protected] "fn" 124 [email protected] "fn"
125 [email protected] " " 125 [email protected] " "
126 [email protected] 126 [email protected]
@@ -166,7 +166,7 @@ [email protected]
166 [email protected] " " 166 [email protected] " "
167 [email protected] "}" 167 [email protected] "}"
168 [email protected] "\n\n" 168 [email protected] "\n\n"
169 FN_DEF@574..624 169 [email protected]
170 [email protected] "fn" 170 [email protected] "fn"
171 [email protected] " " 171 [email protected] " "
172 [email protected] 172 [email protected]
@@ -178,7 +178,7 @@ [email protected]
178 [email protected] 178 [email protected]
179 [email protected] "{" 179 [email protected] "{"
180 [email protected] "\n " 180 [email protected] "\n "
181 FN_DEF@591..607 181 [email protected]
182 [email protected] "fn" 182 [email protected] "fn"
183 [email protected] " " 183 [email protected] " "
184 [email protected] 184 [email protected]
@@ -217,7 +217,7 @@ [email protected]
217 [email protected] "\n" 217 [email protected] "\n"
218 [email protected] "}" 218 [email protected] "}"
219 [email protected] "\n\n" 219 [email protected] "\n\n"
220 FN_DEF@626..816 220 [email protected]
221 [email protected] "fn" 221 [email protected] "fn"
222 [email protected] " " 222 [email protected] " "
223 [email protected] 223 [email protected]
@@ -229,7 +229,7 @@ [email protected]
229 [email protected] 229 [email protected]
230 [email protected] "{" 230 [email protected] "{"
231 [email protected] "\n " 231 [email protected] "\n "
232 FN_DEF@642..720 232 [email protected]
233 [email protected] "fn" 233 [email protected] "fn"
234 [email protected] " " 234 [email protected] " "
235 [email protected] 235 [email protected]
@@ -407,7 +407,7 @@ [email protected]
407 [email protected] "\n" 407 [email protected] "\n"
408 [email protected] "}" 408 [email protected] "}"
409 [email protected] "\n\n" 409 [email protected] "\n\n"
410 FN_DEF@818..1322 410 [email protected]
411 [email protected] "fn" 411 [email protected] "fn"
412 [email protected] " " 412 [email protected] " "
413 [email protected] 413 [email protected]
@@ -572,7 +572,7 @@ [email protected]
572 [email protected] "\n" 572 [email protected] "\n"
573 [email protected] "}" 573 [email protected] "}"
574 [email protected] "\n\n" 574 [email protected] "\n\n"
575 FN_DEF@1324..1539 575 [email protected]
576 [email protected] "fn" 576 [email protected] "fn"
577 [email protected] " " 577 [email protected] " "
578 [email protected] 578 [email protected]
@@ -809,7 +809,7 @@ [email protected]
809 [email protected] "\n" 809 [email protected] "\n"
810 [email protected] "}" 810 [email protected] "}"
811 [email protected] "\n\n" 811 [email protected] "\n\n"
812 FN_DEF@1541..1741 812 [email protected]
813 [email protected] "fn" 813 [email protected] "fn"
814 [email protected] " " 814 [email protected] " "
815 [email protected] 815 [email protected]
@@ -830,7 +830,7 @@ [email protected]
830 [email protected] 830 [email protected]
831 [email protected] "{" 831 [email protected] "{"
832 [email protected] "\n " 832 [email protected] "\n "
833 FN_DEF@1575..1598 833 [email protected]
834 [email protected] "fn" 834 [email protected] "fn"
835 [email protected] " " 835 [email protected] " "
836 [email protected] 836 [email protected]
@@ -988,7 +988,7 @@ [email protected]
988 [email protected] "\n" 988 [email protected] "\n"
989 [email protected] "}" 989 [email protected] "}"
990 [email protected] "\n\n" 990 [email protected] "\n\n"
991 FN_DEF@1743..1904 991 [email protected]
992 [email protected] "fn" 992 [email protected] "fn"
993 [email protected] " " 993 [email protected] " "
994 [email protected] 994 [email protected]
@@ -1131,7 +1131,7 @@ [email protected]
1131 [email protected] "\n" 1131 [email protected] "\n"
1132 [email protected] "}" 1132 [email protected] "}"
1133 [email protected] "\n\n" 1133 [email protected] "\n\n"
1134 FN_DEF@1906..1960 1134 [email protected]
1135 [email protected] "fn" 1135 [email protected] "fn"
1136 [email protected] " " 1136 [email protected] " "
1137 [email protected] 1137 [email protected]
@@ -1166,7 +1166,7 @@ [email protected]
1166 [email protected] " " 1166 [email protected] " "
1167 [email protected] "}" 1167 [email protected] "}"
1168 [email protected] "\n\n" 1168 [email protected] "\n\n"
1169 FN_DEF@1962..2198 1169 [email protected]
1170 [email protected] "fn" 1170 [email protected] "fn"
1171 [email protected] " " 1171 [email protected] " "
1172 [email protected] 1172 [email protected]
@@ -1284,7 +1284,7 @@ [email protected]
1284 [email protected] "\n" 1284 [email protected] "\n"
1285 [email protected] "}" 1285 [email protected] "}"
1286 [email protected] "\n\n" 1286 [email protected] "\n\n"
1287 FN_DEF@2200..2693 1287 [email protected]
1288 [email protected] "fn" 1288 [email protected] "fn"
1289 [email protected] " " 1289 [email protected] " "
1290 [email protected] 1290 [email protected]
@@ -1468,7 +1468,7 @@ [email protected]
1468 [email protected] "\n" 1468 [email protected] "\n"
1469 [email protected] "}" 1469 [email protected] "}"
1470 [email protected] "\n\n" 1470 [email protected] "\n\n"
1471 FN_DEF@2695..2832 1471 [email protected]
1472 [email protected] "fn" 1472 [email protected] "fn"
1473 [email protected] " " 1473 [email protected] " "
1474 [email protected] 1474 [email protected]
@@ -1548,7 +1548,7 @@ [email protected]
1548 [email protected] "\n" 1548 [email protected] "\n"
1549 [email protected] "}" 1549 [email protected] "}"
1550 [email protected] "\n\n" 1550 [email protected] "\n\n"
1551 FN_DEF@2834..2906 1551 [email protected]
1552 [email protected] "fn" 1552 [email protected] "fn"
1553 [email protected] " " 1553 [email protected] " "
1554 [email protected] 1554 [email protected]
@@ -1560,21 +1560,21 @@ [email protected]
1560 [email protected] 1560 [email protected]
1561 [email protected] "{" 1561 [email protected] "{"
1562 [email protected] "\n " 1562 [email protected] "\n "
1563 UNION_DEF@2851..2904 1563 [email protected]
1564 [email protected] "union" 1564 [email protected] "union"
1565 [email protected] " " 1565 [email protected] " "
1566 [email protected] 1566 [email protected]
1567 [email protected] "union" 1567 [email protected] "union"
1568 TYP[email protected] 1568 GENERIC[email protected]
1569 [email protected] "<" 1569 [email protected] "<"
1570 [email protected] 1570 [email protected]
1571 [email protected] "\'union" 1571 [email protected] "\'union"
1572 [email protected] ">" 1572 [email protected] ">"
1573 [email protected] " " 1573 [email protected] " "
1574 RECORD_FIELD_DEF_[email protected] 1574 [email protected]
1575 [email protected] "{" 1575 [email protected] "{"
1576 [email protected] " " 1576 [email protected] " "
1577 RECORD_FIELD_DEF@2873..2901 1577 [email protected]
1578 [email protected] 1578 [email protected]
1579 [email protected] "union" 1579 [email protected] "union"
1580 [email protected] ":" 1580 [email protected] ":"
@@ -1599,7 +1599,7 @@ [email protected]
1599 [email protected] "\n" 1599 [email protected] "\n"
1600 [email protected] "}" 1600 [email protected] "}"
1601 [email protected] "\n\n" 1601 [email protected] "\n\n"
1602 FN_DEF@2908..3042 1602 [email protected]
1603 [email protected] "fn" 1603 [email protected] "fn"
1604 [email protected] " " 1604 [email protected] " "
1605 [email protected] 1605 [email protected]
@@ -1722,7 +1722,7 @@ [email protected]
1722 [email protected] "\n" 1722 [email protected] "\n"
1723 [email protected] "}" 1723 [email protected] "}"
1724 [email protected] "\n\n" 1724 [email protected] "\n\n"
1725 FN_DEF@3044..3514 1725 [email protected]
1726 [email protected] "fn" 1726 [email protected] "fn"
1727 [email protected] " " 1727 [email protected] " "
1728 [email protected] 1728 [email protected]
@@ -2056,7 +2056,7 @@ [email protected]
2056 [email protected] "\n" 2056 [email protected] "\n"
2057 [email protected] "}" 2057 [email protected] "}"
2058 [email protected] "\n\n" 2058 [email protected] "\n\n"
2059 FN_DEF@3516..3552 2059 [email protected]
2060 [email protected] "fn" 2060 [email protected] "fn"
2061 [email protected] " " 2061 [email protected] " "
2062 [email protected] 2062 [email protected]
@@ -2090,7 +2090,7 @@ [email protected]
2090 [email protected] "\n" 2090 [email protected] "\n"
2091 [email protected] "}" 2091 [email protected] "}"
2092 [email protected] "\n\n" 2092 [email protected] "\n\n"
2093 FN_DEF@3554..3812 2093 [email protected]
2094 [email protected] 2094 [email protected]
2095 [email protected] "pub" 2095 [email protected] "pub"
2096 [email protected] " " 2096 [email protected] " "
diff --git a/crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast b/crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast
index a64a82e94..c4da317b9 100644
--- a/crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast
@@ -1,7 +1,7 @@
1[email protected] 1[email protected]
2 [email protected] "// https://github.com ..." 2 [email protected] "// https://github.com ..."
3 [email protected] "\n\n" 3 [email protected] "\n\n"
4 FN_DEF@62..156 4 [email protected]
5 [email protected] 5 [email protected]
6 [email protected] "pub" 6 [email protected] "pub"
7 [email protected] " " 7 [email protected] " "
@@ -9,7 +9,7 @@ [email protected]
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 [email protected]
11 [email protected] "foo" 11 [email protected] "foo"
12 TYP[email protected] 12 GENERIC[email protected]
13 [email protected] "<" 13 [email protected] "<"
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast b/crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast
index 7fd414090..22168eaf1 100644
--- a/crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..34 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast b/crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast
index 17be2c238..68a366354 100644
--- a/crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..14 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast b/crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast
index 5640bae0a..8cfc14f49 100644
--- a/crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 STRUCT_DEF@0..27 2 [email protected]
3 [email protected] "struct" 3 [email protected] "struct"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "S" 6 [email protected] "S"
7 [email protected] " " 7 [email protected] " "
8 RECORD_FIELD_DEF_[email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 RECORD_FIELD_DEF@15..25 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "r#foo" 13 [email protected] "r#foo"
14 [email protected] ":" 14 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast b/crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast
index acf32a852..92ede8ccb 100644
--- a/crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..59 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast b/crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast
index 468982b74..ed29b0812 100644
--- a/crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 [email protected] "// https://github.com ..." 2 [email protected] "// https://github.com ..."
3 [email protected] "\n\n" 3 [email protected] "\n\n"
4 STRUCT_DEF@62..73 4 [email protected]
5 [email protected] "struct" 5 [email protected] "struct"
6 [email protected] " " 6 [email protected] " "
7 [email protected] 7 [email protected]
8 [email protected] "Foo" 8 [email protected] "Foo"
9 [email protected] ";" 9 [email protected] ";"
10 [email protected] "\n\n" 10 [email protected] "\n\n"
11 IMPL_DEF@75..141 11 [email protected]
12 [email protected] "impl" 12 [email protected] "impl"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
@@ -17,10 +17,10 @@ [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "Foo" 18 [email protected] "Foo"
19 [email protected] " " 19 [email protected] " "
20 [email protected] 20 ASSOC_[email protected]
21 [email protected] "{" 21 [email protected] "{"
22 [email protected] "\n " 22 [email protected] "\n "
23 FN_DEF@90..139 23 [email protected]
24 [email protected] "fn" 24 [email protected] "fn"
25 [email protected] " " 25 [email protected] " "
26 [email protected] 26 [email protected]
@@ -55,7 +55,7 @@ [email protected]
55 [email protected] "\n" 55 [email protected] "\n"
56 [email protected] "}" 56 [email protected] "}"
57 [email protected] "\n\n" 57 [email protected] "\n\n"
58 FN_DEF@143..161 58 [email protected]
59 [email protected] "fn" 59 [email protected] "fn"
60 [email protected] " " 60 [email protected] " "
61 [email protected] 61 [email protected]
@@ -78,7 +78,7 @@ [email protected]
78 [email protected] "{" 78 [email protected] "{"
79 [email protected] "}" 79 [email protected] "}"
80 [email protected] "\n\n" 80 [email protected] "\n\n"
81 FN_DEF@163..198 81 [email protected]
82 [email protected] "fn" 82 [email protected] "fn"
83 [email protected] " " 83 [email protected] " "
84 [email protected] 84 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast b/crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast
index 900eeb445..adc4a22e9 100644
--- a/crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast
@@ -1,16 +1,16 @@
1[email protected] 1[email protected]
2 [email protected] "// https://github.com ..." 2 [email protected] "// https://github.com ..."
3 [email protected] "\n\n" 3 [email protected] "\n\n"
4 STRUCT_DEF@62..90 4 [email protected]
5 [email protected] "struct" 5 [email protected] "struct"
6 [email protected] " " 6 [email protected] " "
7 [email protected] 7 [email protected]
8 [email protected] "Repr" 8 [email protected] "Repr"
9 [email protected] " " 9 [email protected] " "
10 RECORD_FIELD_DEF_[email protected] 10 [email protected]
11 [email protected] "{" 11 [email protected] "{"
12 [email protected] " " 12 [email protected] " "
13 RECORD_FIELD_DEF@76..88 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] "raw" 15 [email protected] "raw"
16 [email protected] ":" 16 [email protected] ":"
@@ -30,7 +30,7 @@ [email protected]
30 [email protected] " " 30 [email protected] " "
31 [email protected] "}" 31 [email protected] "}"
32 [email protected] "\n\n" 32 [email protected] "\n\n"
33 FN_DEF@92..159 33 [email protected]
34 [email protected] "fn" 34 [email protected] "fn"
35 [email protected] " " 35 [email protected] " "
36 [email protected] 36 [email protected]
@@ -46,16 +46,16 @@ [email protected]
46 [email protected] 46 [email protected]
47 [email protected] 47 [email protected]
48 [email protected] 48 [email protected]
49 RECORD_LIT@107..124 49 RECORD_EXPR@107..124
50 [email protected] 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
53 [email protected] "Repr" 53 [email protected] "Repr"
54 [email protected] " " 54 [email protected] " "
55 [email protected] 55 RECORD_EXPR_[email protected]
56 [email protected] "{" 56 [email protected] "{"
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 RECORD_EXPR_[email protected]
59 [email protected] 59 [email protected]
60 [email protected] "raw" 60 [email protected] "raw"
61 [email protected] ":" 61 [email protected] ":"
@@ -83,14 +83,14 @@ [email protected]
83 [email protected] "\n " 83 [email protected] "\n "
84 [email protected] 84 [email protected]
85 [email protected] 85 [email protected]
86 RECORD_LIT@141..154 86 RECORD_EXPR@141..154
87 [email protected] 87 [email protected]
88 [email protected] 88 [email protected]
89 [email protected] 89 [email protected]
90 [email protected] "Repr" 90 [email protected] "Repr"
91 [email protected] 91 RECORD_EXPR_[email protected]
92 [email protected] "{" 92 [email protected] "{"
93 [email protected] 93 RECORD_EXPR_[email protected]
94 [email protected] 94 [email protected]
95 [email protected] "raw" 95 [email protected] "raw"
96 [email protected] ":" 96 [email protected] ":"
diff --git a/crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast b/crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast
index 6d941487b..c9e6d88eb 100644
--- a/crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..165 2 [email protected]
3 [email protected] "// https://github.com ..." 3 [email protected] "// https://github.com ..."
4 [email protected] "\n" 4 [email protected] "\n"
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast b/crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast
index e8b095251..139ce9046 100644
--- a/crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..461 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -89,7 +89,7 @@ [email protected]
89 [email protected] "\n\n" 89 [email protected] "\n\n"
90 [email protected] "// https://github.com ..." 90 [email protected] "// https://github.com ..."
91 [email protected] "\n" 91 [email protected] "\n"
92 IMPL_DEF@524..685 92 [email protected]
93 [email protected] "impl" 93 [email protected] "impl"
94 [email protected] " " 94 [email protected] " "
95 [email protected] 95 [email protected]
@@ -98,10 +98,10 @@ [email protected]
98 [email protected] 98 [email protected]
99 [email protected] "Whatever" 99 [email protected] "Whatever"
100 [email protected] " " 100 [email protected] " "
101 [email protected] 101 ASSOC_[email protected]
102 [email protected] "{" 102 [email protected] "{"
103 [email protected] "\n " 103 [email protected] "\n "
104 FN_DEF@544..683 104 [email protected]
105 [email protected] "fn" 105 [email protected] "fn"
106 [email protected] " " 106 [email protected] " "
107 [email protected] 107 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast b/crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast
index 38e44e48a..7a54fa113 100644
--- a/crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast
@@ -1,7 +1,7 @@
1[email protected] 1[email protected]
2 [email protected] "// https://github.com ..." 2 [email protected] "// https://github.com ..."
3 [email protected] "\n\n" 3 [email protected] "\n\n"
4 FN_DEF@62..341 4 [email protected]
5 [email protected] "fn" 5 [email protected] "fn"
6 [email protected] " " 6 [email protected] " "
7 [email protected] 7 [email protected]
@@ -256,21 +256,21 @@ [email protected]
256 [email protected] "\n" 256 [email protected] "\n"
257 [email protected] "}" 257 [email protected] "}"
258 [email protected] "\n\n" 258 [email protected] "\n\n"
259 ENUM_DEF@343..367 259 [email protected]
260 [email protected] "enum" 260 [email protected] "enum"
261 [email protected] " " 261 [email protected] " "
262 [email protected] 262 [email protected]
263 [email protected] "A" 263 [email protected] "A"
264 [email protected] " " 264 [email protected] " "
265 ENUM_[email protected] 265 [email protected]
266 [email protected] "{" 266 [email protected] "{"
267 [email protected] "\n " 267 [email protected] "\n "
268 ENUM_[email protected] 268 [email protected]
269 [email protected] 269 [email protected]
270 [email protected] "B" 270 [email protected] "B"
271 TUPLE_FIELD_DEF_[email protected] 271 [email protected]
272 [email protected] "(" 272 [email protected] "("
273 TUPLE_FIELD_DEF@358..360 273 [email protected]
274 [email protected] 274 [email protected]
275 [email protected] 275 [email protected]
276 [email protected] 276 [email protected]
@@ -278,7 +278,7 @@ [email protected]
278 [email protected] "i8" 278 [email protected] "i8"
279 [email protected] "," 279 [email protected] ","
280 [email protected] " " 280 [email protected] " "
281 TUPLE_FIELD_DEF@362..364 281 [email protected]
282 [email protected] 282 [email protected]
283 [email protected] 283 [email protected]
284 [email protected] 284 [email protected]
@@ -288,7 +288,7 @@ [email protected]
288 [email protected] "\n" 288 [email protected] "\n"
289 [email protected] "}" 289 [email protected] "}"
290 [email protected] "\n\n" 290 [email protected] "\n\n"
291 FN_DEF@369..394 291 [email protected]
292 [email protected] "fn" 292 [email protected] "fn"
293 [email protected] " " 293 [email protected] " "
294 [email protected] 294 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast b/crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast
index 28233c5d0..662576e5f 100644
--- a/crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast
@@ -1,7 +1,7 @@
1[email protected] 1[email protected]
2 [email protected] "// https://github.com ..." 2 [email protected] "// https://github.com ..."
3 [email protected] "\n\n" 3 [email protected] "\n\n"
4 FN_DEF@60..256 4 [email protected]
5 [email protected] "fn" 5 [email protected] "fn"
6 [email protected] " " 6 [email protected] " "
7 [email protected] 7 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0049_async_block.rast b/crates/ra_syntax/test_data/parser/ok/0049_async_block.rast
index 0569488f8..57ecad3cf 100644
--- a/crates/ra_syntax/test_data/parser/ok/0049_async_block.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0049_async_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..45 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast b/crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast
index 7847da085..798e81ca6 100644
--- a/crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..52 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -52,7 +52,7 @@ [email protected]
52 [email protected] "{" 52 [email protected] "{"
53 [email protected] "}" 53 [email protected] "}"
54 [email protected] "\n\n" 54 [email protected] "\n\n"
55 FN_DEF@54..94 55 [email protected]
56 [email protected] "fn" 56 [email protected] "fn"
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast
index 816740a7c..2cc849784 100644
--- a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..37 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -41,7 +41,7 @@ [email protected]
41 [email protected] "{" 41 [email protected] "{"
42 [email protected] "}" 42 [email protected] "}"
43 [email protected] "\n" 43 [email protected] "\n"
44 FN_DEF@38..62 44 [email protected]
45 [email protected] "fn" 45 [email protected] "fn"
46 [email protected] " " 46 [email protected] " "
47 [email protected] 47 [email protected]
@@ -83,7 +83,7 @@ [email protected]
83 [email protected] 83 [email protected]
84 [email protected] "{" 84 [email protected] "{"
85 [email protected] " " 85 [email protected] " "
86 FN_DEF@77..126 86 [email protected]
87 [email protected] "fn" 87 [email protected] "fn"
88 [email protected] " " 88 [email protected] " "
89 [email protected] 89 [email protected]
@@ -132,12 +132,12 @@ [email protected]
132 [email protected] " " 132 [email protected] " "
133 [email protected] "}" 133 [email protected] "}"
134 [email protected] "\n\n" 134 [email protected] "\n\n"
135 FN_DEF@130..172 135 [email protected]
136 [email protected] "fn" 136 [email protected] "fn"
137 [email protected] " " 137 [email protected] " "
138 [email protected] 138 [email protected]
139 [email protected] "foo" 139 [email protected] "foo"
140 TYP[email protected] 140 GENERIC[email protected]
141 [email protected] "<" 141 [email protected] "<"
142 [email protected] 142 [email protected]
143 [email protected] 143 [email protected]
@@ -186,16 +186,16 @@ [email protected]
186 [email protected] "{" 186 [email protected] "{"
187 [email protected] "}" 187 [email protected] "}"
188 [email protected] "\n\n" 188 [email protected] "\n\n"
189 TRAIT_DEF@174..236 189 [email protected]
190 [email protected] "trait" 190 [email protected] "trait"
191 [email protected] " " 191 [email protected] " "
192 [email protected] 192 [email protected]
193 [email protected] "Foo" 193 [email protected] "Foo"
194 [email protected] " " 194 [email protected] " "
195 [email protected] 195 ASSOC_[email protected]
196 [email protected] "{" 196 [email protected] "{"
197 [email protected] "\n " 197 [email protected] "\n "
198 FN_DEF@190..234 198 [email protected]
199 [email protected] "fn" 199 [email protected] "fn"
200 [email protected] " " 200 [email protected] " "
201 [email protected] 201 [email protected]
@@ -251,7 +251,7 @@ [email protected]
251 [email protected] "\n" 251 [email protected] "\n"
252 [email protected] "}" 252 [email protected] "}"
253 [email protected] "\n\n" 253 [email protected] "\n\n"
254 IMPL_DEF@238..519 254 [email protected]
255 [email protected] "impl" 255 [email protected] "impl"
256 [email protected] " " 256 [email protected] " "
257 [email protected] 257 [email protected]
@@ -260,10 +260,10 @@ [email protected]
260 [email protected] 260 [email protected]
261 [email protected] "S" 261 [email protected] "S"
262 [email protected] " " 262 [email protected] " "
263 [email protected] 263 ASSOC_[email protected]
264 [email protected] "{" 264 [email protected] "{"
265 [email protected] "\n " 265 [email protected] "\n "
266 FN_DEF@252..277 266 [email protected]
267 [email protected] "fn" 267 [email protected] "fn"
268 [email protected] " " 268 [email protected] " "
269 [email protected] 269 [email protected]
@@ -287,7 +287,7 @@ [email protected]
287 [email protected] "{" 287 [email protected] "{"
288 [email protected] "}" 288 [email protected] "}"
289 [email protected] "\n " 289 [email protected] "\n "
290 FN_DEF@283..305 290 [email protected]
291 [email protected] "fn" 291 [email protected] "fn"
292 [email protected] " " 292 [email protected] " "
293 [email protected] 293 [email protected]
@@ -311,7 +311,7 @@ [email protected]
311 [email protected] "{" 311 [email protected] "{"
312 [email protected] "}" 312 [email protected] "}"
313 [email protected] "\n " 313 [email protected] "\n "
314 FN_DEF@311..334 314 [email protected]
315 [email protected] "fn" 315 [email protected] "fn"
316 [email protected] " " 316 [email protected] " "
317 [email protected] 317 [email protected]
@@ -336,12 +336,12 @@ [email protected]
336 [email protected] "{" 336 [email protected] "{"
337 [email protected] "}" 337 [email protected] "}"
338 [email protected] "\n " 338 [email protected] "\n "
339 FN_DEF@340..371 339 [email protected]
340 [email protected] "fn" 340 [email protected] "fn"
341 [email protected] " " 341 [email protected] " "
342 [email protected] 342 [email protected]
343 [email protected] "g3" 343 [email protected] "g3"
344 TYP[email protected] 344 GENERIC[email protected]
345 [email protected] "<" 345 [email protected] "<"
346 [email protected] 346 [email protected]
347 [email protected] "\'a" 347 [email protected] "\'a"
@@ -368,12 +368,12 @@ [email protected]
368 [email protected] "{" 368 [email protected] "{"
369 [email protected] "}" 369 [email protected] "}"
370 [email protected] "\n " 370 [email protected] "\n "
371 FN_DEF@377..407 371 [email protected]
372 [email protected] "fn" 372 [email protected] "fn"
373 [email protected] " " 373 [email protected] " "
374 [email protected] 374 [email protected]
375 [email protected] "g4" 375 [email protected] "g4"
376 TYP[email protected] 376 GENERIC[email protected]
377 [email protected] "<" 377 [email protected] "<"
378 [email protected] 378 [email protected]
379 [email protected] "\'a" 379 [email protected] "\'a"
@@ -400,12 +400,12 @@ [email protected]
400 [email protected] "{" 400 [email protected] "{"
401 [email protected] "}" 401 [email protected] "}"
402 [email protected] "\n " 402 [email protected] "\n "
403 FN_DEF@413..447 403 [email protected]
404 [email protected] "fn" 404 [email protected] "fn"
405 [email protected] " " 405 [email protected] " "
406 [email protected] 406 [email protected]
407 [email protected] "g5" 407 [email protected] "g5"
408 TYP[email protected] 408 GENERIC[email protected]
409 [email protected] "<" 409 [email protected] "<"
410 [email protected] 410 [email protected]
411 [email protected] "\'a" 411 [email protected] "\'a"
@@ -434,7 +434,7 @@ [email protected]
434 [email protected] "{" 434 [email protected] "{"
435 [email protected] "}" 435 [email protected] "}"
436 [email protected] "\n " 436 [email protected] "\n "
437 FN_DEF@453..480 437 [email protected]
438 [email protected] "fn" 438 [email protected] "fn"
439 [email protected] " " 439 [email protected] " "
440 [email protected] 440 [email protected]
@@ -465,7 +465,7 @@ [email protected]
465 [email protected] "{" 465 [email protected] "{"
466 [email protected] "}" 466 [email protected] "}"
467 [email protected] "\n " 467 [email protected] "\n "
468 FN_DEF@486..517 468 [email protected]
469 [email protected] "fn" 469 [email protected] "fn"
470 [email protected] " " 470 [email protected] " "
471 [email protected] 471 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast b/crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast
index 65cfa7bc5..a30000398 100644
--- a/crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..79 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast
index d6aec7ab9..e3997ac5b 100644
--- a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..26 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -35,7 +35,7 @@ [email protected]
35 [email protected] "{" 35 [email protected] "{"
36 [email protected] "}" 36 [email protected] "}"
37 [email protected] "\n\n" 37 [email protected] "\n\n"
38 FN_DEF@28..56 38 [email protected]
39 [email protected] "fn" 39 [email protected] "fn"
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
@@ -77,7 +77,7 @@ [email protected]
77 [email protected] "{" 77 [email protected] "{"
78 [email protected] "}" 78 [email protected] "}"
79 [email protected] "\n\n" 79 [email protected] "\n\n"
80 FN_DEF@58..87 80 [email protected]
81 [email protected] "fn" 81 [email protected] "fn"
82 [email protected] " " 82 [email protected] " "
83 [email protected] 83 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast
index 9e0cec35f..7447d516e 100644
--- a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 TYPE_ALIAS_DEF@0..12 2 [email protected]
3 [email protected] "type" 3 [email protected] "type"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -12,7 +12,7 @@ [email protected]
12 [email protected] ")" 12 [email protected] ")"
13 [email protected] ";" 13 [email protected] ";"
14 [email protected] "\n\n" 14 [email protected] "\n\n"
15 FN_DEF@14..48 15 [email protected]
16 [email protected] "fn" 16 [email protected] "fn"
17 [email protected] " " 17 [email protected] " "
18 [email protected] 18 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast b/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast
index 7fa3033ac..3ef916e55 100644
--- a/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..70 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast
index d93968016..53410a1ee 100644
--- a/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..17 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -23,7 +23,7 @@ [email protected]
23 [email protected] "{" 23 [email protected] "{"
24 [email protected] "}" 24 [email protected] "}"
25 [email protected] "\n\n" 25 [email protected] "\n\n"
26 FN_DEF@19..50 26 [email protected]
27 [email protected] "fn" 27 [email protected] "fn"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast
index b5c72ee36..a1dfd58f2 100644
--- a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..78 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast
index ddcb139c1..767b516a2 100644
--- a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..104 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0060_as_range.rast b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rast
index 098152fc3..1fd1a2888 100644
--- a/crates/ra_syntax/test_data/parser/ok/0060_as_range.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0060_as_range.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..55 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast
index c6e982976..ba49c115b 100644
--- a/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..34 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast
index bf791ee2b..0c22c31a4 100644
--- a/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast
@@ -51,7 +51,7 @@ [email protected]
51 [email protected] "\n" 51 [email protected] "\n"
52 [email protected] "}" 52 [email protected] "}"
53 [email protected] "\n\n" 53 [email protected] "\n\n"
54 FN_DEF@95..348 54 [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "#" 56 [email protected] "#"
57 [email protected] "[" 57 [email protected] "["
diff --git a/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
index 886b211d0..facce8167 100644
--- a/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast
@@ -1,14 +1,14 @@
1[email protected] 1[email protected]
2 TRAIT_DEF@0..169 2 [email protected]
3 [email protected] "trait" 3 [email protected] "trait"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "T" 6 [email protected] "T"
7 [email protected] " " 7 [email protected] " "
8 [email protected] 8 ASSOC_[email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 FN_DEF@14..46 11 [email protected]
12 [email protected] "fn" 12 [email protected] "fn"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
@@ -50,7 +50,7 @@ [email protected]
50 [email protected] "{" 50 [email protected] "{"
51 [email protected] "}" 51 [email protected] "}"
52 [email protected] "\n " 52 [email protected] "\n "
53 FN_DEF@51..74 53 [email protected]
54 [email protected] "fn" 54 [email protected] "fn"
55 [email protected] " " 55 [email protected] " "
56 [email protected] 56 [email protected]
@@ -92,7 +92,7 @@ [email protected]
92 [email protected] "{" 92 [email protected] "{"
93 [email protected] "}" 93 [email protected] "}"
94 [email protected] "\n " 94 [email protected] "\n "
95 FN_DEF@79..108 95 [email protected]
96 [email protected] "fn" 96 [email protected] "fn"
97 [email protected] " " 97 [email protected] " "
98 [email protected] 98 [email protected]
@@ -123,7 +123,7 @@ [email protected]
123 [email protected] "{" 123 [email protected] "{"
124 [email protected] "}" 124 [email protected] "}"
125 [email protected] "\n " 125 [email protected] "\n "
126 FN_DEF@113..135 126 [email protected]
127 [email protected] "fn" 127 [email protected] "fn"
128 [email protected] " " 128 [email protected] " "
129 [email protected] 129 [email protected]
@@ -155,7 +155,7 @@ [email protected]
155 [email protected] "{" 155 [email protected] "{"
156 [email protected] "}" 156 [email protected] "}"
157 [email protected] "\n " 157 [email protected] "\n "
158 FN_DEF@140..167 158 [email protected]
159 [email protected] "fn" 159 [email protected] "fn"
160 [email protected] " " 160 [email protected] " "
161 [email protected] 161 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast
index 5a9f07c89..7adedb02e 100644
--- a/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "{" 9 [email protected] "{"
10 [email protected] "\n " 10 [email protected] "\n "
11 FN_DEF@17..40 11 [email protected]
12 [email protected] "fn" 12 [email protected] "fn"
13 [email protected] " " 13 [email protected] " "
14 [email protected] 14 [email protected]
@@ -37,7 +37,7 @@ [email protected]
37 [email protected] ")" 37 [email protected] ")"
38 [email protected] ";" 38 [email protected] ";"
39 [email protected] "\n " 39 [email protected] "\n "
40 FN_DEF@45..70 40 [email protected]
41 [email protected] "fn" 41 [email protected] "fn"
42 [email protected] " " 42 [email protected] " "
43 [email protected] 43 [email protected]
@@ -69,7 +69,7 @@ [email protected]
69 [email protected] ")" 69 [email protected] ")"
70 [email protected] ";" 70 [email protected] ";"
71 [email protected] "\n " 71 [email protected] "\n "
72 FN_DEF@75..123 72 [email protected]
73 [email protected] "fn" 73 [email protected] "fn"
74 [email protected] " " 74 [email protected] " "
75 [email protected] 75 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
index a0423806c..453757c3c 100644
--- a/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..136 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,10 +8,10 @@ [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "U" 9 [email protected] "U"
10 [email protected] " " 10 [email protected] " "
11 [email protected] 11 ASSOC_[email protected]
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 FN_DEF@13..45 14 [email protected]
15 [email protected] "fn" 15 [email protected] "fn"
16 [email protected] " " 16 [email protected] " "
17 [email protected] 17 [email protected]
@@ -53,7 +53,7 @@ [email protected]
53 [email protected] "{" 53 [email protected] "{"
54 [email protected] "}" 54 [email protected] "}"
55 [email protected] "\n " 55 [email protected] "\n "
56 FN_DEF@50..73 56 [email protected]
57 [email protected] "fn" 57 [email protected] "fn"
58 [email protected] " " 58 [email protected] " "
59 [email protected] 59 [email protected]
@@ -95,7 +95,7 @@ [email protected]
95 [email protected] "{" 95 [email protected] "{"
96 [email protected] "}" 96 [email protected] "}"
97 [email protected] "\n " 97 [email protected] "\n "
98 FN_DEF@78..107 98 [email protected]
99 [email protected] "fn" 99 [email protected] "fn"
100 [email protected] " " 100 [email protected] " "
101 [email protected] 101 [email protected]
@@ -126,7 +126,7 @@ [email protected]
126 [email protected] "{" 126 [email protected] "{"
127 [email protected] "}" 127 [email protected] "}"
128 [email protected] "\n " 128 [email protected] "\n "
129 FN_DEF@112..134 129 [email protected]
130 [email protected] "fn" 130 [email protected] "fn"
131 [email protected] " " 131 [email protected] " "
132 [email protected] 132 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast
index d1fffdd63..29bd38c05 100644
--- a/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 FN_DEF@0..25 2 [email protected]
3 [email protected] "/// Example" 3 [email protected] "/// Example"
4 [email protected] "\n\n" 4 [email protected] "\n\n"
5 [email protected] "fn" 5 [email protected] "fn"
diff --git a/crates/ra_syntax/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/crates/ra_syntax/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast
index eb2f8eb3c..2c699ffcb 100644
--- a/crates/ra_syntax/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..39 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "f" 6 [email protected] "f"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast
index dab0247ee..6246a31a6 100644
--- a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast
@@ -1,5 +1,5 @@
1[email protected] 1[email protected]
2 IMPL_DEF@0..45 2 [email protected]
3 [email protected] "impl" 3 [email protected] "impl"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -16,10 +16,10 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "Foo" 17 [email protected] "Foo"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 ASSOC_[email protected]
20 [email protected] "{" 20 [email protected] "{"
21 [email protected] "\n " 21 [email protected] "\n "
22 CONST_DEF@19..43 22 [email protected]
23 [email protected] "default" 23 [email protected] "default"
24 [email protected] " " 24 [email protected] " "
25 [email protected] "const" 25 [email protected] "const"
diff --git a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast
index 503585103..a368ac1e8 100644
--- a/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast
+++ b/crates/ra_syntax/test_data/parser/ok/0067_where_for_pred.rast
@@ -1,10 +1,10 @@
1[email protected] 1[email protected]
2 FN_DEF@0..55 2 [email protected]
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
6 [email protected] "for_trait" 6 [email protected] "for_trait"
7 TYP[email protected] 7 GENERIC[email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
@@ -19,7 +19,7 @@ [email protected]
19 [email protected] "\n " 19 [email protected] "\n "
20 [email protected] 20 [email protected]
21 [email protected] "for" 21 [email protected] "for"
22 TYP[email protected] 22 GENERIC[email protected]
23 [email protected] "<" 23 [email protected] "<"
24 [email protected] 24 [email protected]
25 [email protected] "\'a" 25 [email protected] "\'a"
@@ -59,12 +59,12 @@ [email protected]
59 [email protected] "\n" 59 [email protected] "\n"
60 [email protected] "}" 60 [email protected] "}"
61 [email protected] "\n" 61 [email protected] "\n"
62 FN_DEF@56..107 62 [email protected]
63 [email protected] "fn" 63 [email protected] "fn"
64 [email protected] " " 64 [email protected] " "
65 [email protected] 65 [email protected]
66 [email protected] "for_ref" 66 [email protected] "for_ref"
67 TYP[email protected] 67 GENERIC[email protected]
68 [email protected] "<" 68 [email protected] "<"
69 [email protected] 69 [email protected]
70 [email protected] 70 [email protected]
@@ -79,7 +79,7 @@ [email protected]
79 [email protected] "\n " 79 [email protected] "\n "
80 [email protected] 80 [email protected]
81 [email protected] "for" 81 [email protected] "for"
82 TYP[email protected] 82 GENERIC[email protected]
83 [email protected] "<" 83 [email protected] "<"
84 [email protected] 84 [email protected]
85 [email protected] "\'a" 85 [email protected] "\'a"
@@ -110,12 +110,12 @@ [email protected]
110 [email protected] "\n" 110 [email protected] "\n"
111 [email protected] "}" 111 [email protected] "}"
112 [email protected] "\n" 112 [email protected] "\n"
113 FN_DEF@108..170 113 [email protected]
114 [email protected] "fn" 114 [email protected] "fn"
115 [email protected] " " 115 [email protected] " "
116 [email protected] 116 [email protected]
117 [email protected] "for_parens" 117 [email protected] "for_parens"
118 TYP[email protected] 118 GENERIC[email protected]
119 [email protected] "<" 119 [email protected] "<"
120 [email protected] 120 [email protected]
121 [email protected] 121 [email protected]
@@ -130,7 +130,7 @@ [email protected]
130 [email protected] "\n " 130 [email protected] "\n "
131 [email protected] 131 [email protected]
132 [email protected] "for" 132 [email protected] "for"
133 TYP[email protected] 133 GENERIC[email protected]
134 [email protected] "<" 134 [email protected] "<"
135 [email protected] 135 [email protected]
136 [email protected] "\'a" 136 [email protected] "\'a"
@@ -177,12 +177,12 @@ [email protected]
177 [email protected] "\n" 177 [email protected] "\n"
178 [email protected] "}" 178 [email protected] "}"
179 [email protected] "\n" 179 [email protected] "\n"
180 FN_DEF@171..223 180 [email protected]
181 [email protected] "fn" 181 [email protected] "fn"
182 [email protected] " " 182 [email protected] " "
183 [email protected] 183 [email protected]
184 [email protected] "for_slice" 184 [email protected] "for_slice"
185 TYP[email protected] 185 GENERIC[email protected]
186 [email protected] "<" 186 [email protected] "<"
187 [email protected] 187 [email protected]
188 [email protected] 188 [email protected]
@@ -197,7 +197,7 @@ [email protected]
197 [email protected] "\n " 197 [email protected] "\n "
198 [email protected] 198 [email protected]
199 [email protected] "for" 199 [email protected] "for"
200 TYP[email protected] 200 GENERIC[email protected]
201 [email protected] "<" 201 [email protected] "<"
202 [email protected] 202 [email protected]
203 [email protected] "\'a" 203 [email protected] "\'a"
@@ -231,12 +231,12 @@ [email protected]
231 [email protected] "\n" 231 [email protected] "\n"
232 [email protected] "}" 232 [email protected] "}"
233 [email protected] "\n" 233 [email protected] "\n"
234 FN_DEF@224..300 234 [email protected]
235 [email protected] "fn" 235 [email protected] "fn"
236 [email protected] " " 236 [email protected] " "
237 [email protected] 237 [email protected]
238 [email protected] "for_qpath" 238 [email protected] "for_qpath"
239 TYP[email protected] 239 GENERIC[email protected]
240 [email protected] "<" 240 [email protected] "<"
241 [email protected] 241 [email protected]
242 [email protected] 242 [email protected]
@@ -264,7 +264,7 @@ [email protected]
264 [email protected] "\n " 264 [email protected] "\n "
265 [email protected] 265 [email protected]
266 [email protected] "for" 266 [email protected] "for"
267 TYP[email protected] 267 GENERIC[email protected]
268 [email protected] "<" 268 [email protected] "<"
269 [email protected] 269 [email protected]
270 [email protected] "\'a" 270 [email protected] "\'a"
@@ -313,12 +313,12 @@ [email protected]
313 [email protected] "\n" 313 [email protected] "\n"
314 [email protected] "}" 314 [email protected] "}"
315 [email protected] "\n" 315 [email protected] "\n"
316 FN_DEF@301..373 316 [email protected]
317 [email protected] "fn" 317 [email protected] "fn"
318 [email protected] " " 318 [email protected] " "
319 [email protected] 319 [email protected]
320 [email protected] "for_for_fn" 320 [email protected] "for_for_fn"
321 TYP[email protected] 321 GENERIC[email protected]
322 [email protected] "<" 322 [email protected] "<"
323 [email protected] 323 [email protected]
324 [email protected] 324 [email protected]
@@ -333,7 +333,7 @@ [email protected]
333 [email protected] "\n " 333 [email protected] "\n "
334 [email protected] 334 [email protected]
335 [email protected] "for" 335 [email protected] "for"
336 TYP[email protected] 336 GENERIC[email protected]
337 [email protected] "<" 337 [email protected] "<"
338 [email protected] 338 [email protected]
339 [email protected] "\'a" 339 [email protected] "\'a"
@@ -341,7 +341,7 @@ [email protected]
341 [email protected] " " 341 [email protected] " "
342 [email protected] 342 [email protected]
343 [email protected] "for" 343 [email protected] "for"
344 TYP[email protected] 344 GENERIC[email protected]
345 [email protected] "<" 345 [email protected] "<"
346 [email protected] 346 [email protected]
347 [email protected] "\'b" 347 [email protected] "\'b"
diff --git a/crates/ra_text_edit/Cargo.toml b/crates/ra_text_edit/Cargo.toml
index 46a2ab68f..dbb223350 100644
--- a/crates/ra_text_edit/Cargo.toml
+++ b/crates/ra_text_edit/Cargo.toml
@@ -4,6 +4,7 @@ name = "ra_text_edit"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/ra_toolchain/Cargo.toml b/crates/ra_toolchain/Cargo.toml
index 1873fbe16..84b748c0a 100644
--- a/crates/ra_toolchain/Cargo.toml
+++ b/crates/ra_toolchain/Cargo.toml
@@ -3,6 +3,10 @@ edition = "2018"
3name = "ra_toolchain" 3name = "ra_toolchain"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
7
8[lib]
9doctest = false
6 10
7[dependencies] 11[dependencies]
8home = "0.5.3" 12home = "0.5.3"
diff --git a/crates/ra_tt/Cargo.toml b/crates/ra_tt/Cargo.toml
index f7230a9ca..3c45248c3 100644
--- a/crates/ra_tt/Cargo.toml
+++ b/crates/ra_tt/Cargo.toml
@@ -3,11 +3,13 @@ edition = "2018"
3name = "ra_tt" 3name = "ra_tt"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
9 10
10[dependencies] 11[dependencies]
12stdx = { path = "../stdx" }
11# ideally, `serde` should be enabled by `rust-analyzer`, but we enable it here 13# ideally, `serde` should be enabled by `rust-analyzer`, but we enable it here
12# to reduce number of compilations 14# to reduce number of compilations
13smol_str = { version = "0.1.15", features = ["serde"] } 15smol_str = { version = "0.1.15", features = ["serde"] }
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 342ddbe32..8faf1cc67 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -1,24 +1,13 @@
1//! `tt` crate defines a `TokenTree` data structure: this is the interface (both 1//! `tt` crate defines a `TokenTree` data structure: this is the interface (both
2//! input and output) of macros. It closely mirrors `proc_macro` crate's 2//! input and output) of macros. It closely mirrors `proc_macro` crate's
3//! `TokenTree`. 3//! `TokenTree`.
4
5macro_rules! impl_froms {
6 ($e:ident: $($v:ident), *) => {
7 $(
8 impl From<$v> for $e {
9 fn from(it: $v) -> $e {
10 $e::$v(it)
11 }
12 }
13 )*
14 }
15}
16
17use std::{ 4use std::{
18 fmt::{self, Debug}, 5 fmt::{self, Debug},
19 panic::RefUnwindSafe, 6 panic::RefUnwindSafe,
20}; 7};
21 8
9use stdx::impl_from;
10
22pub use smol_str::SmolStr; 11pub use smol_str::SmolStr;
23 12
24/// Represents identity of the token. 13/// Represents identity of the token.
@@ -41,7 +30,7 @@ pub enum TokenTree {
41 Leaf(Leaf), 30 Leaf(Leaf),
42 Subtree(Subtree), 31 Subtree(Subtree),
43} 32}
44impl_froms!(TokenTree: Leaf, Subtree); 33impl_from!(Leaf, Subtree for TokenTree);
45 34
46impl TokenTree { 35impl TokenTree {
47 pub fn empty() -> Self { 36 pub fn empty() -> Self {
@@ -55,7 +44,7 @@ pub enum Leaf {
55 Punct(Punct), 44 Punct(Punct),
56 Ident(Ident), 45 Ident(Ident),
57} 46}
58impl_froms!(Leaf: Literal, Punct, Ident); 47impl_from!(Literal, Punct, Ident for Leaf);
59 48
60#[derive(Clone, PartialEq, Eq, Hash, Default)] 49#[derive(Clone, PartialEq, Eq, Hash, Default)]
61pub struct Subtree { 50pub struct Subtree {
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 803755106..02c1371ac 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -4,6 +4,7 @@ name = "rust-analyzer"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6autobins = false 6autobins = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
@@ -16,18 +17,19 @@ path = "src/bin/main.rs"
16anyhow = "1.0.26" 17anyhow = "1.0.26"
17crossbeam-channel = "0.4.0" 18crossbeam-channel = "0.4.0"
18env_logger = { version = "0.7.1", default-features = false } 19env_logger = { version = "0.7.1", default-features = false }
19globset = "0.4.4"
20itertools = "0.9.0" 20itertools = "0.9.0"
21jod-thread = "0.1.0" 21jod-thread = "0.1.0"
22log = "0.4.8" 22log = "0.4.8"
23lsp-types = { version = "0.74.0", features = ["proposed"] } 23lsp-types = { version = "0.79.0", features = ["proposed"] }
24parking_lot = "0.11.0" 24parking_lot = "0.11.0"
25pico-args = "0.3.1" 25pico-args = "0.3.1"
26rand = { version = "0.7.3", features = ["small_rng"] } 26oorandom = "11.1.2"
27rustc-hash = "1.1.0" 27rustc-hash = "1.1.0"
28serde = { version = "1.0.106", features = ["derive"] } 28serde = { version = "1.0.106", features = ["derive"] }
29serde_json = "1.0.48" 29serde_json = "1.0.48"
30threadpool = "1.7.1" 30threadpool = "1.7.1"
31rayon = "1.3.1"
32mimalloc = { version = "0.1.19", default-features = false, optional = true }
31 33
32stdx = { path = "../stdx" } 34stdx = { path = "../stdx" }
33 35
@@ -40,7 +42,7 @@ ra_syntax = { path = "../ra_syntax" }
40ra_text_edit = { path = "../ra_text_edit" } 42ra_text_edit = { path = "../ra_text_edit" }
41vfs = { path = "../vfs" } 43vfs = { path = "../vfs" }
42vfs-notify = { path = "../vfs-notify" } 44vfs-notify = { path = "../vfs-notify" }
43ra_cfg = { path = "../ra_cfg"} 45ra_cfg = { path = "../ra_cfg" }
44ra_toolchain = { path = "../ra_toolchain" } 46ra_toolchain = { path = "../ra_toolchain" }
45 47
46# This should only be used in CLI 48# This should only be used in CLI
@@ -56,11 +58,7 @@ ra_proc_macro_srv = { path = "../ra_proc_macro_srv" }
56winapi = "0.3.8" 58winapi = "0.3.8"
57 59
58[dev-dependencies] 60[dev-dependencies]
59tempfile = "3.1.0" 61expect = { path = "../expect" }
60insta = "0.16.0"
61test_utils = { path = "../test_utils" } 62test_utils = { path = "../test_utils" }
62mbe = { path = "../ra_mbe", package = "ra_mbe" } 63mbe = { path = "../ra_mbe", package = "ra_mbe" }
63tt = { path = "../ra_tt", package = "ra_tt" } 64tt = { path = "../ra_tt", package = "ra_tt" }
64
65[features]
66jemalloc = [ "ra_prof/jemalloc" ]
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 3f0bb3865..f16e35d86 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -3,12 +3,13 @@
3//! If run started args, we run the LSP server loop. With a subcommand, we do a 3//! If run started args, we run the LSP server loop. With a subcommand, we do a
4//! one-time batch processing. 4//! one-time batch processing.
5 5
6use std::{env, fmt::Write, path::PathBuf};
7
6use anyhow::{bail, Result}; 8use anyhow::{bail, Result};
7use pico_args::Arguments; 9use pico_args::Arguments;
8use ra_ssr::SsrRule; 10use ra_ssr::{SsrPattern, SsrRule};
9use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 11use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
10 12use vfs::AbsPathBuf;
11use std::{fmt::Write, path::PathBuf};
12 13
13pub(crate) struct Args { 14pub(crate) struct Args {
14 pub(crate) verbosity: Verbosity, 15 pub(crate) verbosity: Verbosity,
@@ -23,21 +24,8 @@ pub(crate) enum Command {
23 Highlight { 24 Highlight {
24 rainbow: bool, 25 rainbow: bool,
25 }, 26 },
26 Stats { 27 AnalysisStats(AnalysisStatsCmd),
27 randomize: bool, 28 Bench(BenchCmd),
28 memory_usage: bool,
29 only: Option<String>,
30 with_deps: bool,
31 path: PathBuf,
32 load_output_dirs: bool,
33 with_proc_macro: bool,
34 },
35 Bench {
36 path: PathBuf,
37 what: BenchWhat,
38 load_output_dirs: bool,
39 with_proc_macro: bool,
40 },
41 Diagnostics { 29 Diagnostics {
42 path: PathBuf, 30 path: PathBuf,
43 load_output_dirs: bool, 31 load_output_dirs: bool,
@@ -49,6 +37,10 @@ pub(crate) enum Command {
49 Ssr { 37 Ssr {
50 rules: Vec<SsrRule>, 38 rules: Vec<SsrRule>,
51 }, 39 },
40 StructuredSearch {
41 debug_snippet: Option<String>,
42 patterns: Vec<SsrPattern>,
43 },
52 ProcMacro, 44 ProcMacro,
53 RunServer, 45 RunServer,
54 Version, 46 Version,
@@ -98,7 +90,7 @@ USAGE:
98 rust-analyzer parse [FLAGS] 90 rust-analyzer parse [FLAGS]
99 91
100FLAGS: 92FLAGS:
101 -h, --help Prints help inforamtion 93 -h, --help Prints help information
102 --no-dump" 94 --no-dump"
103 ); 95 );
104 return Ok(Err(HelpPrinted)); 96 return Ok(Err(HelpPrinted));
@@ -157,10 +149,14 @@ USAGE:
157 rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH] 149 rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH]
158 150
159FLAGS: 151FLAGS:
152 -o, --only Only analyze items matching this path
160 -h, --help Prints help information 153 -h, --help Prints help information
161 --memory-usage 154 --memory-usage Collect memory usage statistics
155 --randomize Randomize order in which crates, modules, and items are processed
156 --parallel Run type inference in parallel
162 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 157 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
163 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding 158 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
159 --with-deps Also analyze all dependencies
164 -v, --verbose 160 -v, --verbose
165 -q, --quiet 161 -q, --quiet
166 162
@@ -174,6 +170,7 @@ ARGS:
174 } 170 }
175 171
176 let randomize = matches.contains("--randomize"); 172 let randomize = matches.contains("--randomize");
173 let parallel = matches.contains("--parallel");
177 let memory_usage = matches.contains("--memory-usage"); 174 let memory_usage = matches.contains("--memory-usage");
178 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; 175 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
179 let with_deps: bool = matches.contains("--with-deps"); 176 let with_deps: bool = matches.contains("--with-deps");
@@ -187,15 +184,16 @@ ARGS:
187 trailing.pop().unwrap().into() 184 trailing.pop().unwrap().into()
188 }; 185 };
189 186
190 Command::Stats { 187 Command::AnalysisStats(AnalysisStatsCmd {
191 randomize, 188 randomize,
189 parallel,
192 memory_usage, 190 memory_usage,
193 only, 191 only,
194 with_deps, 192 with_deps,
195 path, 193 path,
196 load_output_dirs, 194 load_output_dirs,
197 with_proc_macro, 195 with_proc_macro,
198 } 196 })
199 } 197 }
200 "analysis-bench" => { 198 "analysis-bench" => {
201 if matches.contains(["-h", "--help"]) { 199 if matches.contains(["-h", "--help"]) {
@@ -208,8 +206,9 @@ USAGE:
208 206
209FLAGS: 207FLAGS:
210 -h, --help Prints help information 208 -h, --help Prints help information
209 --memory-usage Collect memory usage statistics
211 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 210 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
212 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding 211 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
213 -v, --verbose 212 -v, --verbose
214 213
215OPTIONS: 214OPTIONS:
@@ -229,16 +228,26 @@ ARGS:
229 let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?; 228 let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
230 let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?; 229 let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
231 let what = match (highlight_path, complete_path, goto_def_path) { 230 let what = match (highlight_path, complete_path, goto_def_path) {
232 (Some(path), None, None) => BenchWhat::Highlight { path: path.into() }, 231 (Some(path), None, None) => {
232 let path = env::current_dir().unwrap().join(path);
233 BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
234 }
233 (None, Some(position), None) => BenchWhat::Complete(position), 235 (None, Some(position), None) => BenchWhat::Complete(position),
234 (None, None, Some(position)) => BenchWhat::GotoDef(position), 236 (None, None, Some(position)) => BenchWhat::GotoDef(position),
235 _ => panic!( 237 _ => panic!(
236 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" 238 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
237 ), 239 ),
238 }; 240 };
241 let memory_usage = matches.contains("--memory-usage");
239 let load_output_dirs = matches.contains("--load-output-dirs"); 242 let load_output_dirs = matches.contains("--load-output-dirs");
240 let with_proc_macro = matches.contains("--with-proc-macro"); 243 let with_proc_macro = matches.contains("--with-proc-macro");
241 Command::Bench { path, what, load_output_dirs, with_proc_macro } 244 Command::Bench(BenchCmd {
245 memory_usage,
246 path,
247 what,
248 load_output_dirs,
249 with_proc_macro,
250 })
242 } 251 }
243 "diagnostics" => { 252 "diagnostics" => {
244 if matches.contains(["-h", "--help"]) { 253 if matches.contains(["-h", "--help"]) {
@@ -287,6 +296,7 @@ EXAMPLE:
287 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)' 296 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
288 297
289FLAGS: 298FLAGS:
299 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
290 -h, --help Prints help information 300 -h, --help Prints help information
291 301
292ARGS: 302ARGS:
@@ -300,6 +310,34 @@ ARGS:
300 } 310 }
301 Command::Ssr { rules } 311 Command::Ssr { rules }
302 } 312 }
313 "search" => {
314 if matches.contains(["-h", "--help"]) {
315 eprintln!(
316 "\
317rust-analyzer search
318
319USAGE:
320 rust-analyzer search [FLAGS] [PATTERN...]
321
322EXAMPLE:
323 rust-analyzer search '$a.foo($b)'
324
325FLAGS:
326 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
327 -h, --help Prints help information
328
329ARGS:
330 <PATTERN> A structured search pattern"
331 );
332 return Ok(Err(HelpPrinted));
333 }
334 let debug_snippet = matches.opt_value_from_str("--debug")?;
335 let mut patterns = Vec::new();
336 while let Some(rule) = matches.free_from_str()? {
337 patterns.push(rule);
338 }
339 Command::StructuredSearch { patterns, debug_snippet }
340 }
303 _ => { 341 _ => {
304 print_subcommands(); 342 print_subcommands();
305 return Ok(Err(HelpPrinted)); 343 return Ok(Err(HelpPrinted));
@@ -327,6 +365,7 @@ SUBCOMMANDS:
327 diagnostics 365 diagnostics
328 proc-macro 366 proc-macro
329 parse 367 parse
368 search
330 ssr 369 ssr
331 symbols" 370 symbols"
332 ) 371 )
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 16882fc13..ff8234495 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -6,17 +6,20 @@ mod args;
6use std::convert::TryFrom; 6use std::convert::TryFrom;
7 7
8use lsp_server::Connection; 8use lsp_server::Connection;
9use ra_project_model::ProjectManifest;
9use rust_analyzer::{ 10use rust_analyzer::{
10 cli, 11 cli,
11 config::{Config, LinkedProject}, 12 config::{Config, LinkedProject},
12 from_json, Result, 13 from_json, Result,
13}; 14};
14 15use vfs::AbsPathBuf;
15use ra_db::AbsPathBuf;
16use ra_project_model::ProjectManifest;
17 16
18use crate::args::HelpPrinted; 17use crate::args::HelpPrinted;
19 18
19#[cfg(all(feature = "mimalloc"))]
20#[global_allocator]
21static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
22
20fn main() -> Result<()> { 23fn main() -> Result<()> {
21 setup_logging()?; 24 setup_logging()?;
22 let args = match args::Args::parse()? { 25 let args = match args::Args::parse()? {
@@ -30,39 +33,17 @@ fn main() -> Result<()> {
30 args::Command::Parse { no_dump } => cli::parse(no_dump)?, 33 args::Command::Parse { no_dump } => cli::parse(no_dump)?,
31 args::Command::Symbols => cli::symbols()?, 34 args::Command::Symbols => cli::symbols()?,
32 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, 35 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
33 args::Command::Stats { 36 args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?,
34 randomize, 37 args::Command::Bench(cmd) => cmd.run(args.verbosity)?,
35 memory_usage,
36 only,
37 with_deps,
38 path,
39 load_output_dirs,
40 with_proc_macro,
41 } => cli::analysis_stats(
42 args.verbosity,
43 memory_usage,
44 path.as_ref(),
45 only.as_ref().map(String::as_ref),
46 with_deps,
47 randomize,
48 load_output_dirs,
49 with_proc_macro,
50 )?,
51 args::Command::Bench { path, what, load_output_dirs, with_proc_macro } => {
52 cli::analysis_bench(
53 args.verbosity,
54 path.as_ref(),
55 what,
56 load_output_dirs,
57 with_proc_macro,
58 )?
59 }
60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 38 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 39 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
62 } 40 }
63 args::Command::Ssr { rules } => { 41 args::Command::Ssr { rules } => {
64 cli::apply_ssr_rules(rules)?; 42 cli::apply_ssr_rules(rules)?;
65 } 43 }
44 args::Command::StructuredSearch { patterns, debug_snippet } => {
45 cli::search_for_patterns(patterns, debug_snippet)?;
46 }
66 args::Command::Version => println!("rust-analyzer {}", env!("REV")), 47 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
67 } 48 }
68 Ok(()) 49 Ok(())
@@ -116,8 +97,8 @@ fn run_server() -> Result<()> {
116 }; 97 };
117 98
118 let mut config = Config::new(root_path); 99 let mut config = Config::new(root_path);
119 if let Some(value) = &initialize_params.initialization_options { 100 if let Some(json) = initialize_params.initialization_options {
120 config.update(value); 101 config.update(json);
121 } 102 }
122 config.update_caps(&initialize_params.capabilities); 103 config.update_caps(&initialize_params.capabilities);
123 104
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 673795e78..37d695448 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -2,9 +2,9 @@
2use std::env; 2use std::env;
3 3
4use lsp_types::{ 4use lsp_types::{
5 CallHierarchyServerCapability, ClientCapabilities, CodeActionOptions, 5 CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
6 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, 6 CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
7 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, 7 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, HoverProviderCapability,
8 ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions, 8 ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions,
9 SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend, 9 SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend,
10 SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, 10 SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability,
@@ -28,9 +28,9 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
28 }), 28 }),
29 will_save: None, 29 will_save: None,
30 will_save_wait_until: None, 30 will_save_wait_until: None,
31 save: Some(SaveOptions::default()), 31 save: Some(SaveOptions::default().into()),
32 })), 32 })),
33 hover_provider: Some(true), 33 hover_provider: Some(HoverProviderCapability::Simple(true)),
34 completion_provider: Some(CompletionOptions { 34 completion_provider: Some(CompletionOptions {
35 resolve_provider: None, 35 resolve_provider: None,
36 trigger_characters: Some(vec![":".to_string(), ".".to_string()]), 36 trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
@@ -106,14 +106,12 @@ fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProvi
106 // Ideally we would base this off of the client capabilities 106 // Ideally we would base this off of the client capabilities
107 // but the client is supposed to fall back gracefully for unknown values. 107 // but the client is supposed to fall back gracefully for unknown values.
108 code_action_kinds: Some(vec![ 108 code_action_kinds: Some(vec![
109 lsp_types::code_action_kind::EMPTY.to_string(), 109 CodeActionKind::EMPTY,
110 lsp_types::code_action_kind::QUICKFIX.to_string(), 110 CodeActionKind::QUICKFIX,
111 lsp_types::code_action_kind::REFACTOR.to_string(), 111 CodeActionKind::REFACTOR,
112 lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(), 112 CodeActionKind::REFACTOR_EXTRACT,
113 lsp_types::code_action_kind::REFACTOR_INLINE.to_string(), 113 CodeActionKind::REFACTOR_INLINE,
114 lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(), 114 CodeActionKind::REFACTOR_REWRITE,
115 lsp_types::code_action_kind::SOURCE.to_string(),
116 lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(),
117 ]), 115 ]),
118 work_done_progress_options: Default::default(), 116 work_done_progress_options: Default::default(),
119 }) 117 })
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index e4dd5d92d..03c41263a 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -1,9 +1,9 @@
1//! See `CargoTargetSpec` 1//! See `CargoTargetSpec`
2 2
3use ra_cfg::CfgExpr; 3use ra_cfg::CfgExpr;
4use ra_db::AbsPathBuf;
5use ra_ide::{FileId, RunnableKind, TestId}; 4use ra_ide::{FileId, RunnableKind, TestId};
6use ra_project_model::{self, TargetKind}; 5use ra_project_model::{self, TargetKind};
6use vfs::AbsPathBuf;
7 7
8use crate::{global_state::GlobalStateSnapshot, Result}; 8use crate::{global_state::GlobalStateSnapshot, Result};
9 9
@@ -21,6 +21,7 @@ pub(crate) struct CargoTargetSpec {
21 21
22impl CargoTargetSpec { 22impl CargoTargetSpec {
23 pub(crate) fn runnable_args( 23 pub(crate) fn runnable_args(
24 snap: &GlobalStateSnapshot,
24 spec: Option<CargoTargetSpec>, 25 spec: Option<CargoTargetSpec>,
25 kind: &RunnableKind, 26 kind: &RunnableKind,
26 cfgs: &[CfgExpr], 27 cfgs: &[CfgExpr],
@@ -78,13 +79,21 @@ impl CargoTargetSpec {
78 } 79 }
79 } 80 }
80 81
81 let mut features = Vec::new(); 82 if snap.config.cargo.all_features {
82 for cfg in cfgs { 83 args.push("--all-features".to_string());
83 required_features(cfg, &mut features); 84 } else {
84 } 85 let mut features = Vec::new();
85 for feature in features { 86 for cfg in cfgs {
86 args.push("--features".to_string()); 87 required_features(cfg, &mut features);
87 args.push(feature); 88 }
89 for feature in &snap.config.cargo.features {
90 features.push(feature.clone());
91 }
92 features.dedup();
93 for feature in features {
94 args.push("--features".to_string());
95 args.push(feature);
96 }
88 } 97 }
89 98
90 Ok((args, extra_args)) 99 Ok((args, extra_args))
@@ -168,49 +177,35 @@ fn required_features(cfg_expr: &CfgExpr, features: &mut Vec<String>) {
168mod tests { 177mod tests {
169 use super::*; 178 use super::*;
170 179
171 use mbe::{ast_to_token_tree, TokenMap}; 180 use mbe::ast_to_token_tree;
172 use ra_cfg::parse_cfg; 181 use ra_cfg::CfgExpr;
173 use ra_syntax::{ 182 use ra_syntax::{
174 ast::{self, AstNode}, 183 ast::{self, AstNode},
175 SmolStr, 184 SmolStr,
176 }; 185 };
177 186
178 fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { 187 fn check(cfg: &str, expected_features: &[&str]) {
179 let source_file = ast::SourceFile::parse(input).ok().unwrap(); 188 let cfg_expr = {
180 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 189 let source_file = ast::SourceFile::parse(cfg).ok().unwrap();
181 ast_to_token_tree(&tt).unwrap() 190 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
182 } 191 let (tt, _) = ast_to_token_tree(&tt).unwrap();
183 192 CfgExpr::parse(&tt)
184 #[test] 193 };
185 fn test_cfg_expr_minimal_features_needed() {
186 let (subtree, _) = get_token_tree_generated(r#"#![cfg(feature = "baz")]"#);
187 let cfg_expr = parse_cfg(&subtree);
188 let mut min_features = vec![];
189 required_features(&cfg_expr, &mut min_features);
190
191 assert_eq!(min_features, vec![SmolStr::new("baz")]);
192
193 let (subtree, _) =
194 get_token_tree_generated(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#);
195 let cfg_expr = parse_cfg(&subtree);
196
197 let mut min_features = vec![];
198 required_features(&cfg_expr, &mut min_features);
199 assert_eq!(min_features, vec![SmolStr::new("baz"), SmolStr::new("foo")]);
200 194
201 let (subtree, _) = 195 let mut features = vec![];
202 get_token_tree_generated(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#); 196 required_features(&cfg_expr, &mut features);
203 let cfg_expr = parse_cfg(&subtree);
204 197
205 let mut min_features = vec![]; 198 let expected_features =
206 required_features(&cfg_expr, &mut min_features); 199 expected_features.iter().map(|&it| SmolStr::new(it)).collect::<Vec<_>>();
207 assert_eq!(min_features, vec![SmolStr::new("baz")]);
208 200
209 let (subtree, _) = get_token_tree_generated(r#"#![cfg(foo)]"#); 201 assert_eq!(features, expected_features);
210 let cfg_expr = parse_cfg(&subtree); 202 }
211 203
212 let mut min_features = vec![]; 204 #[test]
213 required_features(&cfg_expr, &mut min_features); 205 fn test_cfg_expr_minimal_features_needed() {
214 assert!(min_features.is_empty()); 206 check(r#"#![cfg(feature = "baz")]"#, &["baz"]);
207 check(r#"#![cfg(all(feature = "baz", feature = "foo"))]"#, &["baz", "foo"]);
208 check(r#"#![cfg(any(feature = "baz", feature = "foo", unix))]"#, &["baz"]);
209 check(r#"#![cfg(foo)]"#, &[]);
215 } 210 }
216} 211}
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index 13e3d75be..1034d11bd 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -10,15 +10,15 @@ mod ssr;
10use std::io::Read; 10use std::io::Read;
11 11
12use anyhow::Result; 12use anyhow::Result;
13use ra_ide::{file_structure, Analysis}; 13use ra_ide::Analysis;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{AstNode, SourceFile}; 15use ra_syntax::{AstNode, SourceFile};
16 16
17pub use analysis_bench::{analysis_bench, BenchWhat, Position}; 17pub use analysis_bench::{BenchCmd, BenchWhat, Position};
18pub use analysis_stats::analysis_stats; 18pub use analysis_stats::AnalysisStatsCmd;
19pub use diagnostics::diagnostics; 19pub use diagnostics::diagnostics;
20pub use load_cargo::load_cargo; 20pub use load_cargo::load_cargo;
21pub use ssr::apply_ssr_rules; 21pub use ssr::{apply_ssr_rules, search_for_patterns};
22 22
23#[derive(Clone, Copy)] 23#[derive(Clone, Copy)]
24pub enum Verbosity { 24pub enum Verbosity {
@@ -48,8 +48,10 @@ pub fn parse(no_dump: bool) -> Result<()> {
48} 48}
49 49
50pub fn symbols() -> Result<()> { 50pub fn symbols() -> Result<()> {
51 let file = file()?; 51 let text = read_stdin()?;
52 for s in file_structure(&file) { 52 let (analysis, file_id) = Analysis::from_single_file(text);
53 let structure = analysis.file_structure(file_id).unwrap();
54 for s in structure {
53 println!("{:?}", s); 55 println!("{:?}", s);
54 } 56 }
55 Ok(()) 57 Ok(())
@@ -72,3 +74,10 @@ fn read_stdin() -> Result<String> {
72 std::io::stdin().read_to_string(&mut buff)?; 74 std::io::stdin().read_to_string(&mut buff)?;
73 Ok(buff) 75 Ok(buff)
74} 76}
77
78fn report_metric(metric: &str, value: u64, unit: &str) {
79 if std::env::var("RA_METRICS").is_err() {
80 return;
81 }
82 println!("METRIC:{}:{}:{}", metric, value, unit)
83}
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 930375d3e..c54ee5f4d 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -1,30 +1,36 @@
1//! Benchmark operations like highlighting or goto definition. 1//! Benchmark operations like highlighting or goto definition.
2 2
3use std::{ 3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
4 convert::TryFrom,
5 path::{Path, PathBuf},
6 str::FromStr,
7 sync::Arc,
8 time::Instant,
9};
10 4
11use anyhow::{format_err, Result}; 5use anyhow::{bail, format_err, Result};
12use ra_db::{ 6use ra_db::{
13 salsa::{Database, Durability}, 7 salsa::{Database, Durability},
14 AbsPathBuf, FileId, 8 FileId,
15}; 9};
16use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionConfig, FilePosition, LineCol}; 10use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionConfig, FilePosition, LineCol};
11use vfs::AbsPathBuf;
12
13use crate::{
14 cli::{load_cargo::load_cargo, Verbosity},
15 print_memory_usage,
16};
17 17
18use crate::cli::{load_cargo::load_cargo, Verbosity}; 18pub struct BenchCmd {
19 pub path: PathBuf,
20 pub what: BenchWhat,
21 pub memory_usage: bool,
22 pub load_output_dirs: bool,
23 pub with_proc_macro: bool,
24}
19 25
20pub enum BenchWhat { 26pub enum BenchWhat {
21 Highlight { path: PathBuf }, 27 Highlight { path: AbsPathBuf },
22 Complete(Position), 28 Complete(Position),
23 GotoDef(Position), 29 GotoDef(Position),
24} 30}
25 31
26pub struct Position { 32pub struct Position {
27 pub path: PathBuf, 33 pub path: AbsPathBuf,
28 pub line: u32, 34 pub line: u32,
29 pub column: u32, 35 pub column: u32,
30} 36}
@@ -32,78 +38,80 @@ pub struct Position {
32impl FromStr for Position { 38impl FromStr for Position {
33 type Err = anyhow::Error; 39 type Err = anyhow::Error;
34 fn from_str(s: &str) -> Result<Self> { 40 fn from_str(s: &str) -> Result<Self> {
35 let (path_line, column) = rsplit_at_char(s, ':')?; 41 let mut split = s.rsplitn(3, ':');
36 let (path, line) = rsplit_at_char(path_line, ':')?; 42 match (split.next(), split.next(), split.next()) {
37 Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? }) 43 (Some(column), Some(line), Some(path)) => {
44 let path = env::current_dir().unwrap().join(path);
45 let path = AbsPathBuf::assert(path);
46 Ok(Position { path, line: line.parse()?, column: column.parse()? })
47 }
48 _ => bail!("position should be in file:line:column format: {:?}", s),
49 }
38 } 50 }
39} 51}
40 52
41fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { 53impl BenchCmd {
42 let idx = s.rfind(c).ok_or_else(|| format_err!("no `{}` in {}", c, s))?; 54 pub fn run(self, verbosity: Verbosity) -> Result<()> {
43 Ok((&s[..idx], &s[idx + 1..])) 55 ra_prof::init();
44}
45 56
46pub fn analysis_bench( 57 let start = Instant::now();
47 verbosity: Verbosity, 58 eprint!("loading: ");
48 path: &Path, 59 let (mut host, vfs) = load_cargo(&self.path, self.load_output_dirs, self.with_proc_macro)?;
49 what: BenchWhat, 60 eprintln!("{:?}\n", start.elapsed());
50 load_output_dirs: bool,
51 with_proc_macro: bool,
52) -> Result<()> {
53 ra_prof::init();
54
55 let start = Instant::now();
56 eprint!("loading: ");
57 let (mut host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
58 eprintln!("{:?}\n", start.elapsed());
59
60 let file_id = {
61 let path = match &what {
62 BenchWhat::Highlight { path } => path,
63 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path,
64 };
65 let path = AbsPathBuf::try_from(path.clone()).unwrap();
66 let path = path.into();
67 vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))?
68 };
69
70 match &what {
71 BenchWhat::Highlight { .. } => {
72 let res = do_work(&mut host, file_id, |analysis| {
73 analysis.diagnostics(file_id).unwrap();
74 analysis.highlight_as_html(file_id, false).unwrap()
75 });
76 if verbosity.is_verbose() {
77 println!("\n{}", res);
78 }
79 }
80 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
81 let is_completion = matches!(what, BenchWhat::Complete(..));
82 61
83 let offset = host 62 let file_id = {
84 .analysis() 63 let path = match &self.what {
85 .file_line_index(file_id)? 64 BenchWhat::Highlight { path } => path,
86 .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); 65 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path,
87 let file_position = FilePosition { file_id, offset }; 66 };
67 let path = path.clone().into();
68 vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))?
69 };
88 70
89 if is_completion { 71 match &self.what {
90 let options = CompletionConfig::default(); 72 BenchWhat::Highlight { .. } => {
91 let res = do_work(&mut host, file_id, |analysis| { 73 let res = do_work(&mut host, file_id, |analysis| {
92 analysis.completions(&options, file_position) 74 analysis.diagnostics(file_id, true).unwrap();
75 analysis.highlight_as_html(file_id, false).unwrap()
93 }); 76 });
94 if verbosity.is_verbose() { 77 if verbosity.is_verbose() {
95 println!("\n{:#?}", res); 78 println!("\n{}", res);
96 } 79 }
97 } else { 80 }
98 let res = 81 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
99 do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_position)); 82 let is_completion = matches!(self.what, BenchWhat::Complete(..));
100 if verbosity.is_verbose() { 83
101 println!("\n{:#?}", res); 84 let offset = host
85 .analysis()
86 .file_line_index(file_id)?
87 .offset(LineCol { line: pos.line - 1, col_utf16: pos.column });
88 let file_position = FilePosition { file_id, offset };
89
90 if is_completion {
91 let options = CompletionConfig::default();
92 let res = do_work(&mut host, file_id, |analysis| {
93 analysis.completions(&options, file_position)
94 });
95 if verbosity.is_verbose() {
96 println!("\n{:#?}", res);
97 }
98 } else {
99 let res = do_work(&mut host, file_id, |analysis| {
100 analysis.goto_definition(file_position)
101 });
102 if verbosity.is_verbose() {
103 println!("\n{:#?}", res);
104 }
102 } 105 }
103 } 106 }
104 } 107 }
108
109 if self.memory_usage {
110 print_memory_usage(host, vfs);
111 }
112
113 Ok(())
105 } 114 }
106 Ok(())
107} 115}
108 116
109fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T { 117fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T {
@@ -141,6 +149,19 @@ fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, w
141 } 149 }
142 { 150 {
143 let start = Instant::now(); 151 let start = Instant::now();
152 eprint!("item change: ");
153 {
154 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
155 text.push_str("\npub fn _dummy() {}\n");
156 let mut change = AnalysisChange::new();
157 change.change_file(file_id, Some(Arc::new(text)));
158 host.apply_change(change);
159 }
160 work(&host.analysis());
161 eprintln!("{:?}", start.elapsed());
162 }
163 {
164 let start = Instant::now();
144 eprint!("const change: "); 165 eprint!("const change: ");
145 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH); 166 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH);
146 let res = work(&host.analysis()); 167 let res = work(&host.analysis());
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9d09501cd..721d41a58 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -1,11 +1,10 @@
1//! Fully type-check project and print various stats, like the number of type 1//! Fully type-check project and print various stats, like the number of type
2//! errors. 2//! errors.
3 3
4use std::{path::Path, time::Instant}; 4use std::{
5 5 path::PathBuf,
6use itertools::Itertools; 6 time::{SystemTime, UNIX_EPOCH},
7use rand::{seq::SliceRandom, thread_rng}; 7};
8use rustc_hash::FxHashSet;
9 8
10use hir::{ 9use hir::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 10 db::{AstDatabase, DefDatabase, HirDatabase},
@@ -13,246 +12,317 @@ use hir::{
13}; 12};
14use hir_def::FunctionId; 13use hir_def::FunctionId;
15use hir_ty::{Ty, TypeWalk}; 14use hir_ty::{Ty, TypeWalk};
16use ra_db::SourceDatabaseExt; 15use itertools::Itertools;
16use oorandom::Rand32;
17use ra_db::{
18 salsa::{self, ParallelDatabase},
19 SourceDatabaseExt,
20};
17use ra_syntax::AstNode; 21use ra_syntax::AstNode;
22use rayon::prelude::*;
23use rustc_hash::FxHashSet;
18use stdx::format_to; 24use stdx::format_to;
19 25
20use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; 26use crate::{
21 27 cli::{
22pub fn analysis_stats( 28 load_cargo::load_cargo, progress_report::ProgressReport, report_metric, Result, Verbosity,
23 verbosity: Verbosity, 29 },
24 memory_usage: bool, 30 print_memory_usage,
25 path: &Path, 31};
26 only: Option<&str>, 32use ra_prof::StopWatch;
27 with_deps: bool,
28 randomize: bool,
29 load_output_dirs: bool,
30 with_proc_macro: bool,
31) -> Result<()> {
32 let db_load_time = Instant::now();
33 let (mut host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
34 let db = host.raw_database();
35 println!("Database loaded {:?}", db_load_time.elapsed());
36 let analysis_time = Instant::now();
37 let mut num_crates = 0;
38 let mut visited_modules = FxHashSet::default();
39 let mut visit_queue = Vec::new();
40 33
41 let mut krates = Crate::all(db); 34/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
42 if randomize { 35struct Snap<DB>(DB);
43 krates.shuffle(&mut thread_rng()); 36impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
44 } 37 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
45 for krate in krates { 38 Snap(self.0.snapshot())
46 let module = krate.root_module(db).expect("crate without root module");
47 let file_id = module.definition_source(db).file_id;
48 let file_id = file_id.original_file(db);
49 let source_root = db.file_source_root(file_id);
50 let source_root = db.source_root(source_root);
51 if !source_root.is_library || with_deps {
52 num_crates += 1;
53 visit_queue.push(module);
54 }
55 } 39 }
40}
56 41
57 if randomize { 42pub struct AnalysisStatsCmd {
58 visit_queue.shuffle(&mut thread_rng()); 43 pub randomize: bool,
59 } 44 pub parallel: bool,
45 pub memory_usage: bool,
46 pub only: Option<String>,
47 pub with_deps: bool,
48 pub path: PathBuf,
49 pub load_output_dirs: bool,
50 pub with_proc_macro: bool,
51}
60 52
61 println!("Crates in this dir: {}", num_crates); 53impl AnalysisStatsCmd {
62 let mut num_decls = 0; 54 pub fn run(self, verbosity: Verbosity) -> Result<()> {
63 let mut funcs = Vec::new(); 55 let mut rng = {
64 while let Some(module) = visit_queue.pop() { 56 let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
65 if visited_modules.insert(module) { 57 Rand32::new(seed)
66 visit_queue.extend(module.children(db)); 58 };
67 59
68 for decl in module.declarations(db) { 60 let mut db_load_sw = self.stop_watch();
69 num_decls += 1; 61 let (host, vfs) = load_cargo(&self.path, self.load_output_dirs, self.with_proc_macro)?;
70 if let ModuleDef::Function(f) = decl { 62 let db = host.raw_database();
71 funcs.push(f); 63 eprintln!("Database loaded {}", db_load_sw.elapsed());
72 } 64
65 let mut analysis_sw = self.stop_watch();
66 let mut num_crates = 0;
67 let mut visited_modules = FxHashSet::default();
68 let mut visit_queue = Vec::new();
69
70 let mut krates = Crate::all(db);
71 if self.randomize {
72 shuffle(&mut rng, &mut krates);
73 }
74 for krate in krates {
75 let module = krate.root_module(db).expect("crate without root module");
76 let file_id = module.definition_source(db).file_id;
77 let file_id = file_id.original_file(db);
78 let source_root = db.file_source_root(file_id);
79 let source_root = db.source_root(source_root);
80 if !source_root.is_library || self.with_deps {
81 num_crates += 1;
82 visit_queue.push(module);
73 } 83 }
84 }
85
86 if self.randomize {
87 shuffle(&mut rng, &mut visit_queue);
88 }
74 89
75 for impl_def in module.impl_defs(db) { 90 eprintln!("Crates in this dir: {}", num_crates);
76 for item in impl_def.items(db) { 91 let mut num_decls = 0;
92 let mut funcs = Vec::new();
93 while let Some(module) = visit_queue.pop() {
94 if visited_modules.insert(module) {
95 visit_queue.extend(module.children(db));
96
97 for decl in module.declarations(db) {
77 num_decls += 1; 98 num_decls += 1;
78 if let AssocItem::Function(f) = item { 99 if let ModuleDef::Function(f) = decl {
79 funcs.push(f); 100 funcs.push(f);
80 } 101 }
81 } 102 }
103
104 for impl_def in module.impl_defs(db) {
105 for item in impl_def.items(db) {
106 num_decls += 1;
107 if let AssocItem::Function(f) = item {
108 funcs.push(f);
109 }
110 }
111 }
82 } 112 }
83 } 113 }
84 } 114 eprintln!("Total modules found: {}", visited_modules.len());
85 println!("Total modules found: {}", visited_modules.len()); 115 eprintln!("Total declarations: {}", num_decls);
86 println!("Total declarations: {}", num_decls); 116 eprintln!("Total functions: {}", funcs.len());
87 println!("Total functions: {}", funcs.len()); 117 eprintln!("Item Collection: {}", analysis_sw.elapsed());
88 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());
89 118
90 if randomize { 119 if self.randomize {
91 funcs.shuffle(&mut thread_rng()); 120 shuffle(&mut rng, &mut funcs);
92 } 121 }
93 122
94 let inference_time = Instant::now(); 123 let mut bar = match verbosity {
95 let mut bar = match verbosity { 124 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
96 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), 125 _ if self.parallel => ProgressReport::hidden(),
97 _ => ProgressReport::new(funcs.len() as u64), 126 _ => ProgressReport::new(funcs.len() as u64),
98 }; 127 };
99 128
100 bar.tick(); 129 if self.parallel {
101 let mut num_exprs = 0; 130 let mut inference_sw = self.stop_watch();
102 let mut num_exprs_unknown = 0; 131 let snap = Snap(db.snapshot());
103 let mut num_exprs_partially_unknown = 0; 132 funcs
104 let mut num_type_mismatches = 0; 133 .par_iter()
105 for f in funcs { 134 .map_with(snap, |snap, &f| {
106 let name = f.name(db); 135 let f_id = FunctionId::from(f);
107 let full_name = f 136 snap.0.body(f_id.into());
108 .module(db) 137 snap.0.infer(f_id.into());
109 .path_to_root(db) 138 })
110 .into_iter() 139 .count();
111 .rev() 140 eprintln!("Parallel Inference: {}", inference_sw.elapsed());
112 .filter_map(|it| it.name(db))
113 .chain(Some(f.name(db)))
114 .join("::");
115 if let Some(only_name) = only {
116 if name.to_string() != only_name && full_name != only_name {
117 continue;
118 }
119 }
120 let mut msg = format!("processing: {}", full_name);
121 if verbosity.is_verbose() {
122 let src = f.source(db);
123 let original_file = src.file_id.original_file(db);
124 let path = vfs.file_path(original_file);
125 let syntax_range = src.value.syntax().text_range();
126 format_to!(msg, " ({} {:?})", path, syntax_range);
127 } 141 }
128 if verbosity.is_spammy() { 142
129 bar.println(msg.to_string()); 143 let mut inference_sw = self.stop_watch();
130 } 144 bar.tick();
131 bar.set_message(&msg); 145 let mut num_exprs = 0;
132 let f_id = FunctionId::from(f); 146 let mut num_exprs_unknown = 0;
133 let body = db.body(f_id.into()); 147 let mut num_exprs_partially_unknown = 0;
134 let inference_result = db.infer(f_id.into()); 148 let mut num_type_mismatches = 0;
135 let (previous_exprs, previous_unknown, previous_partially_unknown) = 149 for f in funcs {
136 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown); 150 let name = f.name(db);
137 for (expr_id, _) in body.exprs.iter() { 151 let full_name = f
138 let ty = &inference_result[expr_id]; 152 .module(db)
139 num_exprs += 1; 153 .path_to_root(db)
140 if let Ty::Unknown = ty { 154 .into_iter()
141 num_exprs_unknown += 1; 155 .rev()
142 } else { 156 .filter_map(|it| it.name(db))
143 let mut is_partially_unknown = false; 157 .chain(Some(f.name(db)))
144 ty.walk(&mut |ty| { 158 .join("::");
145 if let Ty::Unknown = ty { 159 if let Some(only_name) = self.only.as_deref() {
146 is_partially_unknown = true; 160 if name.to_string() != only_name && full_name != only_name {
147 } 161 continue;
148 });
149 if is_partially_unknown {
150 num_exprs_partially_unknown += 1;
151 } 162 }
152 } 163 }
153 if only.is_some() && verbosity.is_spammy() { 164 let mut msg = format!("processing: {}", full_name);
154 // in super-verbose mode for just one function, we print every single expression 165 if verbosity.is_verbose() {
155 let (_, sm) = db.body_with_source_map(f_id.into()); 166 let src = f.source(db);
156 let src = sm.expr_syntax(expr_id); 167 let original_file = src.file_id.original_file(db);
157 if let Ok(src) = src { 168 let path = vfs.file_path(original_file);
158 let node = { 169 let syntax_range = src.value.syntax().text_range();
159 let root = db.parse_or_expand(src.file_id).unwrap(); 170 format_to!(msg, " ({} {:?})", path, syntax_range);
160 src.value.to_node(&root) 171 }
161 }; 172 if verbosity.is_spammy() {
162 let original_file = src.file_id.original_file(db); 173 bar.println(msg.to_string());
163 let line_index = host.analysis().file_line_index(original_file).unwrap(); 174 }
164 let text_range = node.syntax().text_range(); 175 bar.set_message(&msg);
165 let (start, end) = ( 176 let f_id = FunctionId::from(f);
166 line_index.line_col(text_range.start()), 177 let body = db.body(f_id.into());
167 line_index.line_col(text_range.end()), 178 let inference_result = db.infer(f_id.into());
168 ); 179 let (previous_exprs, previous_unknown, previous_partially_unknown) =
169 bar.println(format!( 180 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
170 "{}:{}-{}:{}: {}", 181 for (expr_id, _) in body.exprs.iter() {
171 start.line + 1, 182 let ty = &inference_result[expr_id];
172 start.col_utf16, 183 num_exprs += 1;
173 end.line + 1, 184 if let Ty::Unknown = ty {
174 end.col_utf16, 185 num_exprs_unknown += 1;
175 ty.display(db)
176 ));
177 } else { 186 } else {
178 bar.println(format!("unknown location: {}", ty.display(db))); 187 let mut is_partially_unknown = false;
188 ty.walk(&mut |ty| {
189 if let Ty::Unknown = ty {
190 is_partially_unknown = true;
191 }
192 });
193 if is_partially_unknown {
194 num_exprs_partially_unknown += 1;
195 }
179 } 196 }
180 } 197 if self.only.is_some() && verbosity.is_spammy() {
181 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 198 // in super-verbose mode for just one function, we print every single expression
182 num_type_mismatches += 1;
183 if verbosity.is_verbose() {
184 let (_, sm) = db.body_with_source_map(f_id.into()); 199 let (_, sm) = db.body_with_source_map(f_id.into());
185 let src = sm.expr_syntax(expr_id); 200 let src = sm.expr_syntax(expr_id);
186 if let Ok(src) = src { 201 if let Ok(src) = src {
187 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly 202 let node = {
188 // But also, we should just turn the type mismatches into diagnostics and provide these 203 let root = db.parse_or_expand(src.file_id).unwrap();
189 let root = db.parse_or_expand(src.file_id).unwrap(); 204 src.value.to_node(&root)
190 let node = src.map(|e| e.to_node(&root).syntax().clone()); 205 };
191 let original_range = original_range(db, node.as_ref()); 206 let original_file = src.file_id.original_file(db);
192 let path = vfs.file_path(original_range.file_id); 207 let line_index = host.analysis().file_line_index(original_file).unwrap();
193 let line_index = 208 let text_range = node.syntax().text_range();
194 host.analysis().file_line_index(original_range.file_id).unwrap();
195 let text_range = original_range.range;
196 let (start, end) = ( 209 let (start, end) = (
197 line_index.line_col(text_range.start()), 210 line_index.line_col(text_range.start()),
198 line_index.line_col(text_range.end()), 211 line_index.line_col(text_range.end()),
199 ); 212 );
200 bar.println(format!( 213 bar.println(format!(
201 "{} {}:{}-{}:{}: Expected {}, got {}", 214 "{}:{}-{}:{}: {}",
202 path,
203 start.line + 1, 215 start.line + 1,
204 start.col_utf16, 216 start.col_utf16,
205 end.line + 1, 217 end.line + 1,
206 end.col_utf16, 218 end.col_utf16,
207 mismatch.expected.display(db), 219 ty.display(db)
208 mismatch.actual.display(db)
209 )); 220 ));
210 } else { 221 } else {
211 bar.println(format!( 222 bar.println(format!("unknown location: {}", ty.display(db)));
212 "{}: Expected {}, got {}",
213 name,
214 mismatch.expected.display(db),
215 mismatch.actual.display(db)
216 ));
217 } 223 }
218 } 224 }
225 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
226 num_type_mismatches += 1;
227 if verbosity.is_verbose() {
228 let (_, sm) = db.body_with_source_map(f_id.into());
229 let src = sm.expr_syntax(expr_id);
230 if let Ok(src) = src {
231 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
232 // But also, we should just turn the type mismatches into diagnostics and provide these
233 let root = db.parse_or_expand(src.file_id).unwrap();
234 let node = src.map(|e| e.to_node(&root).syntax().clone());
235 let original_range = original_range(db, node.as_ref());
236 let path = vfs.file_path(original_range.file_id);
237 let line_index =
238 host.analysis().file_line_index(original_range.file_id).unwrap();
239 let text_range = original_range.range;
240 let (start, end) = (
241 line_index.line_col(text_range.start()),
242 line_index.line_col(text_range.end()),
243 );
244 bar.println(format!(
245 "{} {}:{}-{}:{}: Expected {}, got {}",
246 path,
247 start.line + 1,
248 start.col_utf16,
249 end.line + 1,
250 end.col_utf16,
251 mismatch.expected.display(db),
252 mismatch.actual.display(db)
253 ));
254 } else {
255 bar.println(format!(
256 "{}: Expected {}, got {}",
257 name,
258 mismatch.expected.display(db),
259 mismatch.actual.display(db)
260 ));
261 }
262 }
263 }
264 }
265 if verbosity.is_spammy() {
266 bar.println(format!(
267 "In {}: {} exprs, {} unknown, {} partial",
268 full_name,
269 num_exprs - previous_exprs,
270 num_exprs_unknown - previous_unknown,
271 num_exprs_partially_unknown - previous_partially_unknown
272 ));
219 } 273 }
274 bar.inc(1);
220 } 275 }
221 if verbosity.is_spammy() { 276 bar.finish_and_clear();
222 bar.println(format!( 277 eprintln!("Total expressions: {}", num_exprs);
223 "In {}: {} exprs, {} unknown, {} partial", 278 eprintln!(
224 full_name, 279 "Expressions of unknown type: {} ({}%)",
225 num_exprs - previous_exprs, 280 num_exprs_unknown,
226 num_exprs_unknown - previous_unknown, 281 if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 }
227 num_exprs_partially_unknown - previous_partially_unknown 282 );
228 )); 283 report_metric("unknown type", num_exprs_unknown, "#");
284
285 eprintln!(
286 "Expressions of partially unknown type: {} ({}%)",
287 num_exprs_partially_unknown,
288 if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 }
289 );
290
291 eprintln!("Type mismatches: {}", num_type_mismatches);
292 report_metric("type mismatches", num_type_mismatches, "#");
293
294 eprintln!("Inference: {}", inference_sw.elapsed());
295
296 let total_span = analysis_sw.elapsed();
297 eprintln!("Total: {}", total_span);
298 report_metric("total time", total_span.time.as_millis() as u64, "ms");
299 if let Some(instructions) = total_span.instructions {
300 report_metric("total instructions", instructions, "#instr");
301 }
302 if let Some(memory) = total_span.memory {
303 report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
229 } 304 }
230 bar.inc(1);
231 }
232 bar.finish_and_clear();
233 println!("Total expressions: {}", num_exprs);
234 println!(
235 "Expressions of unknown type: {} ({}%)",
236 num_exprs_unknown,
237 if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 }
238 );
239 println!(
240 "Expressions of partially unknown type: {} ({}%)",
241 num_exprs_partially_unknown,
242 if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 }
243 );
244 println!("Type mismatches: {}", num_type_mismatches);
245 println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
246 println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());
247 305
248 if memory_usage { 306 if self.memory_usage {
249 for (name, bytes) in host.per_query_memory_usage() { 307 print_memory_usage(host, vfs);
250 println!("{:>8} {}", bytes, name)
251 } 308 }
252 let before = ra_prof::memory_usage(); 309
253 drop(host); 310 Ok(())
254 println!("leftover: {}", before.allocated - ra_prof::memory_usage().allocated)
255 } 311 }
256 312
257 Ok(()) 313 fn stop_watch(&self) -> StopWatch {
314 StopWatch::start().memory(self.memory_usage)
315 }
316}
317
318fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
319 for i in 0..slice.len() {
320 randomize_first(rng, &mut slice[i..]);
321 }
322
323 fn randomize_first<T>(rng: &mut Rand32, slice: &mut [T]) {
324 assert!(!slice.is_empty());
325 let idx = rng.rand_range(0..slice.len() as u32) as usize;
326 slice.swap(0, idx);
327 }
258} 328}
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 6f3c1c1f9..4ac8c8772 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -47,7 +47,7 @@ pub fn diagnostics(
47 String::from("unknown") 47 String::from("unknown")
48 }; 48 };
49 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); 49 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id));
50 for diagnostic in analysis.diagnostics(file_id).unwrap() { 50 for diagnostic in analysis.diagnostics(file_id, true).unwrap() {
51 if matches!(diagnostic.severity, Severity::Error) { 51 if matches!(diagnostic.severity, Severity::Error) {
52 found_error = true; 52 found_error = true;
53 } 53 }
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index d8677c231..a43bf2244 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -4,10 +4,10 @@ use std::{path::Path, sync::Arc};
4 4
5use anyhow::Result; 5use anyhow::Result;
6use crossbeam_channel::{unbounded, Receiver}; 6use crossbeam_channel::{unbounded, Receiver};
7use ra_db::{AbsPathBuf, CrateGraph}; 7use ra_db::CrateGraph;
8use ra_ide::{AnalysisChange, AnalysisHost}; 8use ra_ide::{AnalysisChange, AnalysisHost};
9use ra_project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace}; 9use ra_project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
10use vfs::{loader::Handle, AbsPath}; 10use vfs::{loader::Handle, AbsPath, AbsPathBuf};
11 11
12use crate::reload::{ProjectFolders, SourceRootConfig}; 12use crate::reload::{ProjectFolders, SourceRootConfig};
13 13
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
index a5265ac15..194bec008 100644
--- a/crates/rust-analyzer/src/cli/ssr.rs
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -1,27 +1,17 @@
1//! Applies structured search replace rules from the command line. 1//! Applies structured search replace rules from the command line.
2 2
3use crate::cli::{load_cargo::load_cargo, Result}; 3use crate::cli::{load_cargo::load_cargo, Result};
4use ra_ide::SourceFileEdit; 4use ra_ssr::{MatchFinder, SsrPattern, SsrRule};
5use ra_ssr::{MatchFinder, SsrRule};
6 5
7pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { 6pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
8 use ra_db::SourceDatabaseExt; 7 use ra_db::SourceDatabaseExt;
9 use ra_ide_db::symbol_index::SymbolsDatabase;
10 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?; 8 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
11 let db = host.raw_database(); 9 let db = host.raw_database();
12 let mut match_finder = MatchFinder::new(db); 10 let mut match_finder = MatchFinder::at_first_file(db)?;
13 for rule in rules { 11 for rule in rules {
14 match_finder.add_rule(rule); 12 match_finder.add_rule(rule)?;
15 }
16 let mut edits = Vec::new();
17 for &root in db.local_roots().iter() {
18 let sr = db.source_root(root);
19 for file_id in sr.iter() {
20 if let Some(edit) = match_finder.edits_for_file(file_id) {
21 edits.push(SourceFileEdit { file_id, edit });
22 }
23 }
24 } 13 }
14 let edits = match_finder.edits();
25 for edit in edits { 15 for edit in edits {
26 if let Some(path) = vfs.file_path(edit.file_id).as_path() { 16 if let Some(path) = vfs.file_path(edit.file_id).as_path() {
27 let mut contents = db.file_text(edit.file_id).to_string(); 17 let mut contents = db.file_text(edit.file_id).to_string();
@@ -31,3 +21,34 @@ pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
31 } 21 }
32 Ok(()) 22 Ok(())
33} 23}
24
25/// Searches for `patterns`, printing debug information for any nodes whose text exactly matches
26/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
27/// for much else.
28pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
29 use ra_db::SourceDatabaseExt;
30 use ra_ide_db::symbol_index::SymbolsDatabase;
31 let (host, _vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
32 let db = host.raw_database();
33 let mut match_finder = MatchFinder::at_first_file(db)?;
34 for pattern in patterns {
35 match_finder.add_search_pattern(pattern)?;
36 }
37 if let Some(debug_snippet) = &debug_snippet {
38 for &root in db.local_roots().iter() {
39 let sr = db.source_root(root);
40 for file_id in sr.iter() {
41 for debug_info in match_finder.debug_where_text_equal(file_id, debug_snippet) {
42 println!("{:#?}", debug_info);
43 }
44 }
45 }
46 } else {
47 for m in match_finder.matches().flattened().matches {
48 // We could possibly at some point do something more useful than just printing
49 // the matched text. For now though, that's the easiest thing to do.
50 println!("{}", m.matched_text());
51 }
52 }
53 Ok(())
54}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 6b17ce18b..70b4512d0 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -9,25 +9,28 @@
9 9
10use std::{ffi::OsString, path::PathBuf}; 10use std::{ffi::OsString, path::PathBuf};
11 11
12use crate::diagnostics::DiagnosticsConfig;
13use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
14use lsp_types::ClientCapabilities; 13use lsp_types::ClientCapabilities;
15use ra_db::AbsPathBuf;
16use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; 14use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
17use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; 15use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
18use serde::Deserialize; 16use serde::Deserialize;
17use vfs::AbsPathBuf;
18
19use crate::diagnostics::DiagnosticsConfig;
19 20
20#[derive(Debug, Clone)] 21#[derive(Debug, Clone)]
21pub struct Config { 22pub struct Config {
22 pub client_caps: ClientCapsConfig, 23 pub client_caps: ClientCapsConfig,
23 24
24 pub publish_diagnostics: bool, 25 pub publish_diagnostics: bool,
26 pub experimental_diagnostics: bool,
25 pub diagnostics: DiagnosticsConfig, 27 pub diagnostics: DiagnosticsConfig,
26 pub lru_capacity: Option<usize>, 28 pub lru_capacity: Option<usize>,
27 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, 29 pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
28 pub files: FilesConfig, 30 pub files: FilesConfig,
29 pub notifications: NotificationsConfig, 31 pub notifications: NotificationsConfig,
30 32
33 pub cargo_autoreload: bool,
31 pub cargo: CargoConfig, 34 pub cargo: CargoConfig,
32 pub rustfmt: RustfmtConfig, 35 pub rustfmt: RustfmtConfig,
33 pub flycheck: Option<FlycheckConfig>, 36 pub flycheck: Option<FlycheckConfig>,
@@ -44,7 +47,7 @@ pub struct Config {
44 pub root_path: AbsPathBuf, 47 pub root_path: AbsPathBuf,
45} 48}
46 49
47#[derive(Debug, Clone)] 50#[derive(Debug, Clone, Eq, PartialEq)]
48pub enum LinkedProject { 51pub enum LinkedProject {
49 ProjectManifest(ProjectManifest), 52 ProjectManifest(ProjectManifest),
50 InlineJsonProject(ProjectJson), 53 InlineJsonProject(ProjectJson),
@@ -66,20 +69,20 @@ impl From<ProjectJson> for LinkedProject {
66pub struct LensConfig { 69pub struct LensConfig {
67 pub run: bool, 70 pub run: bool,
68 pub debug: bool, 71 pub debug: bool,
69 pub impementations: bool, 72 pub implementations: bool,
70} 73}
71 74
72impl Default for LensConfig { 75impl Default for LensConfig {
73 fn default() -> Self { 76 fn default() -> Self {
74 Self { run: true, debug: true, impementations: true } 77 Self { run: true, debug: true, implementations: true }
75 } 78 }
76} 79}
77 80
78impl LensConfig { 81impl LensConfig {
79 pub const NO_LENS: LensConfig = Self { run: false, debug: false, impementations: false }; 82 pub const NO_LENS: LensConfig = Self { run: false, debug: false, implementations: false };
80 83
81 pub fn any(&self) -> bool { 84 pub fn any(&self) -> bool {
82 self.impementations || self.runnable() 85 self.implementations || self.runnable()
83 } 86 }
84 87
85 pub fn none(&self) -> bool { 88 pub fn none(&self) -> bool {
@@ -110,14 +113,8 @@ pub struct NotificationsConfig {
110 113
111#[derive(Debug, Clone)] 114#[derive(Debug, Clone)]
112pub enum RustfmtConfig { 115pub enum RustfmtConfig {
113 Rustfmt { 116 Rustfmt { extra_args: Vec<String> },
114 extra_args: Vec<String>, 117 CustomCommand { command: String, args: Vec<String> },
115 },
116 #[allow(unused)]
117 CustomCommand {
118 command: String,
119 args: Vec<String>,
120 },
121} 118}
122 119
123#[derive(Debug, Clone, Default)] 120#[derive(Debug, Clone, Default)]
@@ -130,6 +127,8 @@ pub struct ClientCapsConfig {
130 pub code_action_group: bool, 127 pub code_action_group: bool,
131 pub resolve_code_action: bool, 128 pub resolve_code_action: bool,
132 pub hover_actions: bool, 129 pub hover_actions: bool,
130 pub status_notification: bool,
131 pub signature_help_label_offsets: bool,
133} 132}
134 133
135impl Config { 134impl Config {
@@ -139,16 +138,20 @@ impl Config {
139 138
140 with_sysroot: true, 139 with_sysroot: true,
141 publish_diagnostics: true, 140 publish_diagnostics: true,
141 experimental_diagnostics: true,
142 diagnostics: DiagnosticsConfig::default(), 142 diagnostics: DiagnosticsConfig::default(),
143 lru_capacity: None, 143 lru_capacity: None,
144 proc_macro_srv: None, 144 proc_macro_srv: None,
145 files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, 145 files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
146 notifications: NotificationsConfig { cargo_toml_not_found: true }, 146 notifications: NotificationsConfig { cargo_toml_not_found: true },
147 147
148 cargo_autoreload: true,
148 cargo: CargoConfig::default(), 149 cargo: CargoConfig::default(),
149 rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, 150 rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
150 flycheck: Some(FlycheckConfig::CargoCommand { 151 flycheck: Some(FlycheckConfig::CargoCommand {
151 command: "check".to_string(), 152 command: "check".to_string(),
153 target_triple: None,
154 no_default_features: false,
152 all_targets: true, 155 all_targets: true,
153 all_features: false, 156 all_features: false,
154 extra_args: Vec::new(), 157 extra_args: Vec::new(),
@@ -176,144 +179,121 @@ impl Config {
176 } 179 }
177 } 180 }
178 181
179 #[rustfmt::skip] 182 pub fn update(&mut self, json: serde_json::Value) {
180 pub fn update(&mut self, value: &serde_json::Value) { 183 log::info!("Config::update({:#})", json);
181 log::info!("Config::update({:#})", value); 184
182 185 if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
183 let client_caps = self.client_caps.clone(); 186 return;
184 *self = Config::new(self.root_path.clone());
185 self.client_caps = client_caps;
186
187 set(value, "/withSysroot", &mut self.with_sysroot);
188 set(value, "/diagnostics/enable", &mut self.publish_diagnostics);
189 set(value, "/diagnostics/warningsAsInfo", &mut self.diagnostics.warnings_as_info);
190 set(value, "/diagnostics/warningsAsHint", &mut self.diagnostics.warnings_as_hint);
191 set(value, "/lruCapacity", &mut self.lru_capacity);
192 self.files.watcher = match get(value, "/files/watcher") {
193 Some("client") => FilesWatcher::Client,
194 Some("notify") | _ => FilesWatcher::Notify
195 };
196 set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);
197
198 set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
199 set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
200 set(value, "/cargo/features", &mut self.cargo.features);
201 set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
202 set(value, "/cargo/target", &mut self.cargo.target);
203
204 match get(value, "/procMacro/enable") {
205 Some(true) => {
206 if let Ok(path) = std::env::current_exe() {
207 self.proc_macro_srv = Some((path, vec!["proc-macro".into()]));
208 }
209 }
210 _ => self.proc_macro_srv = None,
211 } 187 }
212 188
213 match get::<Vec<String>>(value, "/rustfmt/overrideCommand") { 189 let data = ConfigData::from_json(json);
190
191 self.with_sysroot = data.withSysroot;
192 self.publish_diagnostics = data.diagnostics_enable;
193 self.experimental_diagnostics = data.diagnostics_enableExperimental;
194 self.diagnostics = DiagnosticsConfig {
195 warnings_as_info: data.diagnostics_warningsAsInfo,
196 warnings_as_hint: data.diagnostics_warningsAsHint,
197 };
198 self.lru_capacity = data.lruCapacity;
199 self.files.watcher = match data.files_watcher.as_str() {
200 "notify" => FilesWatcher::Notify,
201 "client" | _ => FilesWatcher::Client,
202 };
203 self.notifications =
204 NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound };
205 self.cargo_autoreload = data.cargo_autoreload;
206 self.cargo = CargoConfig {
207 no_default_features: data.cargo_noDefaultFeatures,
208 all_features: data.cargo_allFeatures,
209 features: data.cargo_features.clone(),
210 load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck,
211 target: data.cargo_target.clone(),
212 };
213
214 self.proc_macro_srv = if data.procMacro_enable {
215 std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()]))
216 } else {
217 None
218 };
219
220 self.rustfmt = match data.rustfmt_overrideCommand {
214 Some(mut args) if !args.is_empty() => { 221 Some(mut args) if !args.is_empty() => {
215 let command = args.remove(0); 222 let command = args.remove(0);
216 self.rustfmt = RustfmtConfig::CustomCommand { 223 RustfmtConfig::CustomCommand { command, args }
217 command,
218 args,
219 }
220 }
221 _ => {
222 if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
223 set(value, "/rustfmt/extraArgs", extra_args);
224 }
225 } 224 }
225 Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs },
226 }; 226 };
227 227
228 if let Some(false) = get(value, "/checkOnSave/enable") { 228 self.flycheck = if data.checkOnSave_enable {
229 // check is disabled 229 let flycheck_config = match data.checkOnSave_overrideCommand {
230 self.flycheck = None;
231 } else {
232 // check is enabled
233 match get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
234 // first see if the user has completely overridden the command
235 Some(mut args) if !args.is_empty() => { 230 Some(mut args) if !args.is_empty() => {
236 let command = args.remove(0); 231 let command = args.remove(0);
237 self.flycheck = Some(FlycheckConfig::CustomCommand { 232 FlycheckConfig::CustomCommand { command, args }
238 command,
239 args,
240 });
241 }
242 // otherwise configure command customizations
243 _ => {
244 if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features, features })
245 = &mut self.flycheck
246 {
247 set(value, "/checkOnSave/extraArgs", extra_args);
248 set(value, "/checkOnSave/command", command);
249 set(value, "/checkOnSave/allTargets", all_targets);
250 *all_features = get(value, "/checkOnSave/allFeatures").unwrap_or(self.cargo.all_features);
251 *features = get(value, "/checkOnSave/features").unwrap_or(self.cargo.features.clone());
252 }
253 } 233 }
234 Some(_) | None => FlycheckConfig::CargoCommand {
235 command: data.checkOnSave_command,
236 target_triple: data.checkOnSave_target.or(data.cargo_target),
237 all_targets: data.checkOnSave_allTargets,
238 no_default_features: data
239 .checkOnSave_noDefaultFeatures
240 .unwrap_or(data.cargo_noDefaultFeatures),
241 all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures),
242 features: data.checkOnSave_features.unwrap_or(data.cargo_features),
243 extra_args: data.checkOnSave_extraArgs,
244 },
254 }; 245 };
255 } 246 Some(flycheck_config)
256
257 set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
258 set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
259 set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
260 set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
261 set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
262 set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
263 set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
264 set(value, "/callInfo/full", &mut self.call_info_full);
265
266 let mut lens_enabled = true;
267 set(value, "/lens/enable", &mut lens_enabled);
268 if lens_enabled {
269 set(value, "/lens/run", &mut self.lens.run);
270 set(value, "/lens/debug", &mut self.lens.debug);
271 set(value, "/lens/implementations", &mut self.lens.impementations);
272 } else { 247 } else {
273 self.lens = LensConfig::NO_LENS; 248 None
274 } 249 };
275 250
276 if let Some(linked_projects) = get::<Vec<ManifestOrProjectJson>>(value, "/linkedProjects") { 251 self.inlay_hints = InlayHintsConfig {
277 if !linked_projects.is_empty() { 252 type_hints: data.inlayHints_typeHints,
278 self.linked_projects.clear(); 253 parameter_hints: data.inlayHints_parameterHints,
279 for linked_project in linked_projects { 254 chaining_hints: data.inlayHints_chainingHints,
280 let linked_project = match linked_project { 255 max_length: data.inlayHints_maxLength,
281 ManifestOrProjectJson::Manifest(it) => { 256 };
282 let path = self.root_path.join(it);
283 match ProjectManifest::from_manifest_file(path) {
284 Ok(it) => it.into(),
285 Err(_) => continue,
286 }
287 }
288 ManifestOrProjectJson::ProjectJson(it) => ProjectJson::new(&self.root_path, it).into(),
289 };
290 self.linked_projects.push(linked_project);
291 }
292 }
293 }
294 257
295 let mut use_hover_actions = false; 258 self.completion.enable_postfix_completions = data.completion_postfix_enable;
296 set(value, "/hoverActions/enable", &mut use_hover_actions); 259 self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
297 if use_hover_actions { 260 self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;
298 set(value, "/hoverActions/implementations", &mut self.hover.implementations);
299 set(value, "/hoverActions/run", &mut self.hover.run);
300 set(value, "/hoverActions/debug", &mut self.hover.debug);
301 set(value, "/hoverActions/gotoTypeDef", &mut self.hover.goto_type_def);
302 } else {
303 self.hover = HoverConfig::NO_ACTIONS;
304 }
305 261
306 log::info!("Config::update() = {:#?}", self); 262 self.call_info_full = data.callInfo_full;
307 263
308 fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { 264 self.lens = LensConfig {
309 value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) 265 run: data.lens_enable && data.lens_run,
310 } 266 debug: data.lens_enable && data.lens_debug,
267 implementations: data.lens_enable && data.lens_implementations,
268 };
311 269
312 fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { 270 if !data.linkedProjects.is_empty() {
313 if let Some(new_value) = get(value, pointer) { 271 self.linked_projects.clear();
314 *slot = new_value 272 for linked_project in data.linkedProjects {
273 let linked_project = match linked_project {
274 ManifestOrProjectJson::Manifest(it) => {
275 let path = self.root_path.join(it);
276 match ProjectManifest::from_manifest_file(path) {
277 Ok(it) => it.into(),
278 Err(_) => continue,
279 }
280 }
281 ManifestOrProjectJson::ProjectJson(it) => {
282 ProjectJson::new(&self.root_path, it).into()
283 }
284 };
285 self.linked_projects.push(linked_project);
315 } 286 }
316 } 287 }
288
289 self.hover = HoverConfig {
290 implementations: data.hoverActions_enable && data.hoverActions_implementations,
291 run: data.hoverActions_enable && data.hoverActions_run,
292 debug: data.hoverActions_enable && data.hoverActions_debug,
293 goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef,
294 };
295
296 log::info!("Config::update() = {:#?}", self);
317 } 297 }
318 298
319 pub fn update_caps(&mut self, caps: &ClientCapabilities) { 299 pub fn update_caps(&mut self, caps: &ClientCapabilities) {
@@ -337,6 +317,15 @@ impl Config {
337 { 317 {
338 self.client_caps.code_action_literals = value; 318 self.client_caps.code_action_literals = value;
339 } 319 }
320 if let Some(value) = doc_caps
321 .signature_help
322 .as_ref()
323 .and_then(|it| it.signature_information.as_ref())
324 .and_then(|it| it.parameter_information.as_ref())
325 .and_then(|it| it.label_offset_support)
326 {
327 self.client_caps.signature_help_label_offsets = value;
328 }
340 329
341 self.completion.allow_snippets(false); 330 self.completion.allow_snippets(false);
342 if let Some(completion) = &doc_caps.completion { 331 if let Some(completion) = &doc_caps.completion {
@@ -365,6 +354,7 @@ impl Config {
365 self.client_caps.code_action_group = get_bool("codeActionGroup"); 354 self.client_caps.code_action_group = get_bool("codeActionGroup");
366 self.client_caps.resolve_code_action = get_bool("resolveCodeAction"); 355 self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
367 self.client_caps.hover_actions = get_bool("hoverActions"); 356 self.client_caps.hover_actions = get_bool("hoverActions");
357 self.client_caps.status_notification = get_bool("statusNotification");
368 } 358 }
369 } 359 }
370} 360}
@@ -375,3 +365,84 @@ enum ManifestOrProjectJson {
375 Manifest(PathBuf), 365 Manifest(PathBuf),
376 ProjectJson(ProjectJsonData), 366 ProjectJson(ProjectJsonData),
377} 367}
368
369macro_rules! config_data {
370 (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => {
371 #[allow(non_snake_case)]
372 struct $name { $($field: $ty,)* }
373 impl $name {
374 fn from_json(mut json: serde_json::Value) -> $name {
375 $name {$(
376 $field: {
377 let pointer = stringify!($field).replace('_', "/");
378 let pointer = format!("/{}", pointer);
379 json.pointer_mut(&pointer)
380 .and_then(|it| serde_json::from_value(it.take()).ok())
381 .unwrap_or($default)
382 },
383 )*}
384 }
385 }
386
387 };
388}
389
390config_data! {
391 struct ConfigData {
392 callInfo_full: bool = true,
393
394 cargo_autoreload: bool = true,
395 cargo_allFeatures: bool = false,
396 cargo_features: Vec<String> = Vec::new(),
397 cargo_loadOutDirsFromCheck: bool = false,
398 cargo_noDefaultFeatures: bool = false,
399 cargo_target: Option<String> = None,
400
401 checkOnSave_enable: bool = false,
402 checkOnSave_allFeatures: Option<bool> = None,
403 checkOnSave_allTargets: bool = true,
404 checkOnSave_command: String = "check".into(),
405 checkOnSave_noDefaultFeatures: Option<bool> = None,
406 checkOnSave_target: Option<String> = None,
407 checkOnSave_extraArgs: Vec<String> = Vec::new(),
408 checkOnSave_features: Option<Vec<String>> = None,
409 checkOnSave_overrideCommand: Option<Vec<String>> = None,
410
411 completion_addCallArgumentSnippets: bool = true,
412 completion_addCallParenthesis: bool = true,
413 completion_postfix_enable: bool = true,
414
415 diagnostics_enable: bool = true,
416 diagnostics_enableExperimental: bool = true,
417 diagnostics_warningsAsHint: Vec<String> = Vec::new(),
418 diagnostics_warningsAsInfo: Vec<String> = Vec::new(),
419
420 files_watcher: String = "client".into(),
421
422 hoverActions_debug: bool = true,
423 hoverActions_enable: bool = true,
424 hoverActions_gotoTypeDef: bool = true,
425 hoverActions_implementations: bool = true,
426 hoverActions_run: bool = true,
427
428 inlayHints_chainingHints: bool = true,
429 inlayHints_maxLength: Option<usize> = None,
430 inlayHints_parameterHints: bool = true,
431 inlayHints_typeHints: bool = true,
432
433 lens_debug: bool = true,
434 lens_enable: bool = true,
435 lens_implementations: bool = true,
436 lens_run: bool = true,
437
438 linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(),
439 lruCapacity: Option<usize> = None,
440 notifications_cargoTomlNotFound: bool = true,
441 procMacro_enable: bool = false,
442
443 rustfmt_extraArgs: Vec<String> = Vec::new(),
444 rustfmt_overrideCommand: Option<Vec<String>> = None,
445
446 withSysroot: bool = true,
447 }
448}
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index b46281c98..d24c55cee 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -18,7 +18,9 @@ pub struct DiagnosticsConfig {
18 18
19#[derive(Debug, Default, Clone)] 19#[derive(Debug, Default, Clone)]
20pub(crate) struct DiagnosticCollection { 20pub(crate) struct DiagnosticCollection {
21 // FIXME: should be FxHashMap<FileId, Vec<ra_id::Diagnostic>>
21 pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>, 22 pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
23 // FIXME: should be Vec<flycheck::Diagnostic>
22 pub(crate) check: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>, 24 pub(crate) check: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
23 pub(crate) check_fixes: CheckFixes, 25 pub(crate) check_fixes: CheckFixes,
24 changes: FxHashSet<FileId>, 26 changes: FxHashSet<FileId>,
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 3eed118a9..97f331352 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -2,11 +2,7 @@
2//! `cargo check` json format to the LSP diagnostic format. 2//! `cargo check` json format to the LSP diagnostic format.
3use std::{collections::HashMap, path::Path}; 3use std::{collections::HashMap, path::Path};
4 4
5use flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion}; 5use flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan};
6use lsp_types::{
7 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location,
8 NumberOrString, Position, Range, TextEdit, Url,
9};
10use stdx::format_to; 6use stdx::format_to;
11 7
12use crate::{lsp_ext, to_proto::url_from_abs_path}; 8use crate::{lsp_ext, to_proto::url_from_abs_path};
@@ -14,22 +10,25 @@ use crate::{lsp_ext, to_proto::url_from_abs_path};
14use super::DiagnosticsConfig; 10use super::DiagnosticsConfig;
15 11
16/// Determines the LSP severity from a diagnostic 12/// Determines the LSP severity from a diagnostic
17fn map_diagnostic_to_severity( 13fn diagnostic_severity(
18 config: &DiagnosticsConfig, 14 config: &DiagnosticsConfig,
19 val: &flycheck::Diagnostic, 15 level: flycheck::DiagnosticLevel,
20) -> Option<DiagnosticSeverity> { 16 code: Option<flycheck::DiagnosticCode>,
21 let res = match val.level { 17) -> Option<lsp_types::DiagnosticSeverity> {
22 DiagnosticLevel::Ice => DiagnosticSeverity::Error, 18 let res = match level {
23 DiagnosticLevel::Error => DiagnosticSeverity::Error, 19 DiagnosticLevel::Ice => lsp_types::DiagnosticSeverity::Error,
24 DiagnosticLevel::Warning => match &val.code { 20 DiagnosticLevel::Error => lsp_types::DiagnosticSeverity::Error,
25 Some(code) if config.warnings_as_hint.contains(&code.code) => DiagnosticSeverity::Hint, 21 DiagnosticLevel::Warning => match &code {
22 Some(code) if config.warnings_as_hint.contains(&code.code) => {
23 lsp_types::DiagnosticSeverity::Hint
24 }
26 Some(code) if config.warnings_as_info.contains(&code.code) => { 25 Some(code) if config.warnings_as_info.contains(&code.code) => {
27 DiagnosticSeverity::Information 26 lsp_types::DiagnosticSeverity::Information
28 } 27 }
29 _ => DiagnosticSeverity::Warning, 28 _ => lsp_types::DiagnosticSeverity::Warning,
30 }, 29 },
31 DiagnosticLevel::Note => DiagnosticSeverity::Information, 30 DiagnosticLevel::Note => lsp_types::DiagnosticSeverity::Information,
32 DiagnosticLevel::Help => DiagnosticSeverity::Hint, 31 DiagnosticLevel::Help => lsp_types::DiagnosticSeverity::Hint,
33 DiagnosticLevel::Unknown => return None, 32 DiagnosticLevel::Unknown => return None,
34 }; 33 };
35 Some(res) 34 Some(res)
@@ -40,90 +39,50 @@ fn is_from_macro(file_name: &str) -> bool {
40 file_name.starts_with('<') && file_name.ends_with('>') 39 file_name.starts_with('<') && file_name.ends_with('>')
41} 40}
42 41
43/// Converts a Rust macro span to a LSP location recursively
44fn map_macro_span_to_location(
45 span_macro: &DiagnosticSpanMacroExpansion,
46 workspace_root: &Path,
47) -> Option<Location> {
48 if !is_from_macro(&span_macro.span.file_name) {
49 return Some(map_span_to_location(&span_macro.span, workspace_root));
50 }
51
52 if let Some(expansion) = &span_macro.span.expansion {
53 return map_macro_span_to_location(&expansion, workspace_root);
54 }
55
56 None
57}
58
59/// Converts a Rust span to a LSP location, resolving macro expansion site if neccesary 42/// Converts a Rust span to a LSP location, resolving macro expansion site if neccesary
60fn map_span_to_location(span: &DiagnosticSpan, workspace_root: &Path) -> Location { 43fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
61 if span.expansion.is_some() { 44 let mut span = span.clone();
62 let expansion = span.expansion.as_ref().unwrap(); 45 while let Some(expansion) = span.expansion {
63 if let Some(macro_range) = map_macro_span_to_location(&expansion, workspace_root) { 46 span = expansion.span;
64 return macro_range;
65 }
66 } 47 }
67 48 return location_naive(workspace_root, &span);
68 map_span_to_location_naive(span, workspace_root)
69} 49}
70 50
71/// Converts a Rust span to a LSP location 51/// Converts a Rust span to a LSP location
72fn map_span_to_location_naive(span: &DiagnosticSpan, workspace_root: &Path) -> Location { 52fn location_naive(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
73 let mut file_name = workspace_root.to_path_buf(); 53 let file_name = workspace_root.join(&span.file_name);
74 file_name.push(&span.file_name);
75 let uri = url_from_abs_path(&file_name); 54 let uri = url_from_abs_path(&file_name);
76 55
77 // FIXME: this doesn't handle UTF16 offsets correctly 56 // FIXME: this doesn't handle UTF16 offsets correctly
78 let range = Range::new( 57 let range = lsp_types::Range::new(
79 Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1), 58 lsp_types::Position::new(span.line_start as u64 - 1, span.column_start as u64 - 1),
80 Position::new(span.line_end as u64 - 1, span.column_end as u64 - 1), 59 lsp_types::Position::new(span.line_end as u64 - 1, span.column_end as u64 - 1),
81 ); 60 );
82 61
83 Location { uri, range } 62 lsp_types::Location { uri, range }
84} 63}
85 64
86/// Converts a secondary Rust span to a LSP related information 65/// Converts a secondary Rust span to a LSP related inflocation(ormation
87/// 66///
88/// If the span is unlabelled this will return `None`. 67/// If the span is unlabelled this will return `None`.
89fn map_secondary_span_to_related( 68fn diagnostic_related_information(
90 span: &DiagnosticSpan,
91 workspace_root: &Path, 69 workspace_root: &Path,
92) -> Option<DiagnosticRelatedInformation> { 70 span: &DiagnosticSpan,
71) -> Option<lsp_types::DiagnosticRelatedInformation> {
93 let message = span.label.clone()?; 72 let message = span.label.clone()?;
94 let location = map_span_to_location(span, workspace_root); 73 let location = location(workspace_root, span);
95 Some(DiagnosticRelatedInformation { location, message }) 74 Some(lsp_types::DiagnosticRelatedInformation { location, message })
96}
97
98/// Determines if diagnostic is related to unused code
99fn is_unused_or_unnecessary(rd: &flycheck::Diagnostic) -> bool {
100 match &rd.code {
101 Some(code) => match code.code.as_str() {
102 "dead_code" | "unknown_lints" | "unreachable_code" | "unused_attributes"
103 | "unused_imports" | "unused_macros" | "unused_variables" => true,
104 _ => false,
105 },
106 None => false,
107 }
108}
109
110/// Determines if diagnostic is related to deprecated code
111fn is_deprecated(rd: &flycheck::Diagnostic) -> bool {
112 match &rd.code {
113 Some(code) => code.code.as_str() == "deprecated",
114 None => false,
115 }
116} 75}
117 76
118enum MappedRustChildDiagnostic { 77enum MappedRustChildDiagnostic {
119 Related(DiagnosticRelatedInformation), 78 Related(lsp_types::DiagnosticRelatedInformation),
120 SuggestedFix(lsp_ext::CodeAction), 79 SuggestedFix(lsp_ext::CodeAction),
121 MessageLine(String), 80 MessageLine(String),
122} 81}
123 82
124fn map_rust_child_diagnostic( 83fn map_rust_child_diagnostic(
125 rd: &flycheck::Diagnostic,
126 workspace_root: &Path, 84 workspace_root: &Path,
85 rd: &flycheck::Diagnostic,
127) -> MappedRustChildDiagnostic { 86) -> MappedRustChildDiagnostic {
128 let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); 87 let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect();
129 if spans.is_empty() { 88 if spans.is_empty() {
@@ -132,21 +91,20 @@ fn map_rust_child_diagnostic(
132 return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); 91 return MappedRustChildDiagnostic::MessageLine(rd.message.clone());
133 } 92 }
134 93
135 let mut edit_map: HashMap<Url, Vec<TextEdit>> = HashMap::new(); 94 let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new();
136 for &span in &spans { 95 for &span in &spans {
137 match (&span.suggestion_applicability, &span.suggested_replacement) { 96 if let (Some(Applicability::MachineApplicable), Some(suggested_replacement)) =
138 (Some(Applicability::MachineApplicable), Some(suggested_replacement)) => { 97 (&span.suggestion_applicability, &span.suggested_replacement)
139 let location = map_span_to_location(span, workspace_root); 98 {
140 let edit = TextEdit::new(location.range, suggested_replacement.clone()); 99 let location = location(workspace_root, span);
141 edit_map.entry(location.uri).or_default().push(edit); 100 let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone());
142 } 101 edit_map.entry(location.uri).or_default().push(edit);
143 _ => {}
144 } 102 }
145 } 103 }
146 104
147 if edit_map.is_empty() { 105 if edit_map.is_empty() {
148 MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { 106 MappedRustChildDiagnostic::Related(lsp_types::DiagnosticRelatedInformation {
149 location: map_span_to_location(spans[0], workspace_root), 107 location: location(workspace_root, spans[0]),
150 message: rd.message.clone(), 108 message: rd.message.clone(),
151 }) 109 })
152 } else { 110 } else {
@@ -154,21 +112,21 @@ fn map_rust_child_diagnostic(
154 title: rd.message.clone(), 112 title: rd.message.clone(),
155 id: None, 113 id: None,
156 group: None, 114 group: None,
157 kind: Some("quickfix".to_string()), 115 kind: Some(lsp_types::CodeActionKind::QUICKFIX),
158 edit: Some(lsp_ext::SnippetWorkspaceEdit { 116 edit: Some(lsp_ext::SnippetWorkspaceEdit {
159 // FIXME: there's no good reason to use edit_map here.... 117 // FIXME: there's no good reason to use edit_map here....
160 changes: Some(edit_map), 118 changes: Some(edit_map),
161 document_changes: None, 119 document_changes: None,
162 }), 120 }),
163 command: None, 121 is_preferred: Some(true),
164 }) 122 })
165 } 123 }
166} 124}
167 125
168#[derive(Debug)] 126#[derive(Debug)]
169pub(crate) struct MappedRustDiagnostic { 127pub(crate) struct MappedRustDiagnostic {
170 pub(crate) location: Location, 128 pub(crate) url: lsp_types::Url,
171 pub(crate) diagnostic: Diagnostic, 129 pub(crate) diagnostic: lsp_types::Diagnostic,
172 pub(crate) fixes: Vec<lsp_ext::CodeAction>, 130 pub(crate) fixes: Vec<lsp_ext::CodeAction>,
173} 131}
174 132
@@ -192,7 +150,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
192 return Vec::new(); 150 return Vec::new();
193 } 151 }
194 152
195 let severity = map_diagnostic_to_severity(config, rd); 153 let severity = diagnostic_severity(config, rd.level.clone(), rd.code.clone());
196 154
197 let mut source = String::from("rustc"); 155 let mut source = String::from("rustc");
198 let mut code = rd.code.as_ref().map(|c| c.code.clone()); 156 let mut code = rd.code.as_ref().map(|c| c.code.clone());
@@ -210,7 +168,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
210 let mut tags = Vec::new(); 168 let mut tags = Vec::new();
211 169
212 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { 170 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
213 let related = map_secondary_span_to_related(secondary_span, workspace_root); 171 let related = diagnostic_related_information(workspace_root, secondary_span);
214 if let Some(related) = related { 172 if let Some(related) = related {
215 related_information.push(related); 173 related_information.push(related);
216 } 174 }
@@ -219,7 +177,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
219 let mut fixes = Vec::new(); 177 let mut fixes = Vec::new();
220 let mut message = rd.message.clone(); 178 let mut message = rd.message.clone();
221 for child in &rd.children { 179 for child in &rd.children {
222 let child = map_rust_child_diagnostic(&child, workspace_root); 180 let child = map_rust_child_diagnostic(workspace_root, &child);
223 match child { 181 match child {
224 MappedRustChildDiagnostic::Related(related) => related_information.push(related), 182 MappedRustChildDiagnostic::Related(related) => related_information.push(related),
225 MappedRustChildDiagnostic::SuggestedFix(code_action) => fixes.push(code_action), 183 MappedRustChildDiagnostic::SuggestedFix(code_action) => fixes.push(code_action),
@@ -233,18 +191,30 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
233 } 191 }
234 } 192 }
235 193
236 if is_unused_or_unnecessary(rd) { 194 if let Some(code) = &rd.code {
237 tags.push(DiagnosticTag::Unnecessary); 195 let code = code.code.as_str();
238 } 196 if matches!(
197 code,
198 "dead_code"
199 | "unknown_lints"
200 | "unreachable_code"
201 | "unused_attributes"
202 | "unused_imports"
203 | "unused_macros"
204 | "unused_variables"
205 ) {
206 tags.push(lsp_types::DiagnosticTag::Unnecessary);
207 }
239 208
240 if is_deprecated(rd) { 209 if matches!(code, "deprecated") {
241 tags.push(DiagnosticTag::Deprecated); 210 tags.push(lsp_types::DiagnosticTag::Deprecated);
211 }
242 } 212 }
243 213
244 primary_spans 214 primary_spans
245 .iter() 215 .iter()
246 .map(|primary_span| { 216 .map(|primary_span| {
247 let location = map_span_to_location(&primary_span, workspace_root); 217 let location = location(workspace_root, &primary_span);
248 218
249 let mut message = message.clone(); 219 let mut message = message.clone();
250 if needs_primary_span_label { 220 if needs_primary_span_label {
@@ -256,17 +226,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
256 // If error occurs from macro expansion, add related info pointing to 226 // If error occurs from macro expansion, add related info pointing to
257 // where the error originated 227 // where the error originated
258 if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { 228 if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() {
259 let def_loc = map_span_to_location_naive(&primary_span, workspace_root); 229 related_information.push(lsp_types::DiagnosticRelatedInformation {
260 related_information.push(DiagnosticRelatedInformation { 230 location: location_naive(workspace_root, &primary_span),
261 location: def_loc,
262 message: "Error originated from macro here".to_string(), 231 message: "Error originated from macro here".to_string(),
263 }); 232 });
264 } 233 }
265 234
266 let diagnostic = Diagnostic { 235 let diagnostic = lsp_types::Diagnostic {
267 range: location.range, 236 range: location.range,
268 severity, 237 severity,
269 code: code.clone().map(NumberOrString::String), 238 code: code.clone().map(lsp_types::NumberOrString::String),
270 source: Some(source.clone()), 239 source: Some(source.clone()),
271 message, 240 message,
272 related_information: if related_information.is_empty() { 241 related_information: if related_information.is_empty() {
@@ -277,7 +246,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
277 tags: if tags.is_empty() { None } else { Some(tags.clone()) }, 246 tags: if tags.is_empty() { None } else { Some(tags.clone()) },
278 }; 247 };
279 248
280 MappedRustDiagnostic { location, diagnostic, fixes: fixes.clone() } 249 MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() }
281 }) 250 })
282 .collect() 251 .collect()
283} 252}
@@ -287,13 +256,22 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
287mod tests { 256mod tests {
288 use super::*; 257 use super::*;
289 258
290 fn parse_diagnostic(val: &str) -> flycheck::Diagnostic { 259 use expect::{expect_file, ExpectFile};
291 serde_json::from_str::<flycheck::Diagnostic>(val).unwrap() 260
261 fn check(diagnostics_json: &str, expect: ExpectFile) {
262 check_with_config(DiagnosticsConfig::default(), diagnostics_json, expect)
263 }
264
265 fn check_with_config(config: DiagnosticsConfig, diagnostics_json: &str, expect: ExpectFile) {
266 let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap();
267 let workspace_root = Path::new("/test/");
268 let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root);
269 expect.assert_debug_eq(&actual)
292 } 270 }
293 271
294 #[test] 272 #[test]
295 fn snap_rustc_incompatible_type_for_trait() { 273 fn rustc_incompatible_type_for_trait() {
296 let diag = parse_diagnostic( 274 check(
297 r##"{ 275 r##"{
298 "message": "method `next` has an incompatible type for trait", 276 "message": "method `next` has an incompatible type for trait",
299 "code": { 277 "code": {
@@ -337,16 +315,13 @@ mod tests {
337 "rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref<M>> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`\n\n" 315 "rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref<M>> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`\n\n"
338 } 316 }
339 "##, 317 "##,
318 expect_file!["crates/rust-analyzer/test_data/rustc_incompatible_type_for_trait.txt"],
340 ); 319 );
341
342 let workspace_root = Path::new("/test/");
343 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
344 insta::assert_debug_snapshot!(diag);
345 } 320 }
346 321
347 #[test] 322 #[test]
348 fn snap_rustc_unused_variable() { 323 fn rustc_unused_variable() {
349 let diag = parse_diagnostic( 324 check(
350 r##"{ 325 r##"{
351 "message": "unused variable: `foo`", 326 "message": "unused variable: `foo`",
352 "code": { 327 "code": {
@@ -419,17 +394,18 @@ mod tests {
419 ], 394 ],
420 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" 395 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
421 }"##, 396 }"##,
397 expect_file!["crates/rust-analyzer/test_data/rustc_unused_variable.txt"],
422 ); 398 );
423
424 let workspace_root = Path::new("/test/");
425 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
426 insta::assert_debug_snapshot!(diag);
427 } 399 }
428 400
429 #[test] 401 #[test]
430 #[cfg(not(windows))] 402 #[cfg(not(windows))]
431 fn snap_rustc_unused_variable_as_info() { 403 fn rustc_unused_variable_as_info() {
432 let diag = parse_diagnostic( 404 check_with_config(
405 DiagnosticsConfig {
406 warnings_as_info: vec!["unused_variables".to_string()],
407 ..DiagnosticsConfig::default()
408 },
433 r##"{ 409 r##"{
434 "message": "unused variable: `foo`", 410 "message": "unused variable: `foo`",
435 "code": { 411 "code": {
@@ -502,22 +478,18 @@ mod tests {
502 ], 478 ],
503 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" 479 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
504 }"##, 480 }"##,
481 expect_file!["crates/rust-analyzer/test_data/rustc_unused_variable_as_info.txt"],
505 ); 482 );
506
507 let config = DiagnosticsConfig {
508 warnings_as_info: vec!["unused_variables".to_string()],
509 ..DiagnosticsConfig::default()
510 };
511
512 let workspace_root = Path::new("/test/");
513 let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
514 insta::assert_debug_snapshot!(diag);
515 } 483 }
516 484
517 #[test] 485 #[test]
518 #[cfg(not(windows))] 486 #[cfg(not(windows))]
519 fn snap_rustc_unused_variable_as_hint() { 487 fn rustc_unused_variable_as_hint() {
520 let diag = parse_diagnostic( 488 check_with_config(
489 DiagnosticsConfig {
490 warnings_as_hint: vec!["unused_variables".to_string()],
491 ..DiagnosticsConfig::default()
492 },
521 r##"{ 493 r##"{
522 "message": "unused variable: `foo`", 494 "message": "unused variable: `foo`",
523 "code": { 495 "code": {
@@ -590,21 +562,13 @@ mod tests {
590 ], 562 ],
591 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n" 563 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
592 }"##, 564 }"##,
565 expect_file!["crates/rust-analyzer/test_data/rustc_unused_variable_as_hint.txt"],
593 ); 566 );
594
595 let config = DiagnosticsConfig {
596 warnings_as_hint: vec!["unused_variables".to_string()],
597 ..DiagnosticsConfig::default()
598 };
599
600 let workspace_root = Path::new("/test/");
601 let diag = map_rust_diagnostic_to_lsp(&config, &diag, workspace_root);
602 insta::assert_debug_snapshot!(diag);
603 } 567 }
604 568
605 #[test] 569 #[test]
606 fn snap_rustc_wrong_number_of_parameters() { 570 fn rustc_wrong_number_of_parameters() {
607 let diag = parse_diagnostic( 571 check(
608 r##"{ 572 r##"{
609 "message": "this function takes 2 parameters but 3 parameters were supplied", 573 "message": "this function takes 2 parameters but 3 parameters were supplied",
610 "code": { 574 "code": {
@@ -719,16 +683,13 @@ mod tests {
719 "children": [], 683 "children": [],
720 "rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref<ty::Poly>,\n222 | | evidence_poly: &ty::Ref<ty::Poly>,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n" 684 "rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref<ty::Poly>,\n222 | | evidence_poly: &ty::Ref<ty::Poly>,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n"
721 }"##, 685 }"##,
686 expect_file!["crates/rust-analyzer/test_data/rustc_wrong_number_of_parameters.txt"],
722 ); 687 );
723
724 let workspace_root = Path::new("/test/");
725 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
726 insta::assert_debug_snapshot!(diag);
727 } 688 }
728 689
729 #[test] 690 #[test]
730 fn snap_clippy_pass_by_ref() { 691 fn clippy_pass_by_ref() {
731 let diag = parse_diagnostic( 692 check(
732 r##"{ 693 r##"{
733 "message": "this argument is passed by reference, but would be more efficient if passed by value", 694 "message": "this argument is passed by reference, but would be more efficient if passed by value",
734 "code": { 695 "code": {
@@ -839,16 +800,13 @@ mod tests {
839 ], 800 ],
840 "rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n" 801 "rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n"
841 }"##, 802 }"##,
803 expect_file!["crates/rust-analyzer/test_data/clippy_pass_by_ref.txt"],
842 ); 804 );
843
844 let workspace_root = Path::new("/test/");
845 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
846 insta::assert_debug_snapshot!(diag);
847 } 805 }
848 806
849 #[test] 807 #[test]
850 fn snap_rustc_mismatched_type() { 808 fn rustc_mismatched_type() {
851 let diag = parse_diagnostic( 809 check(
852 r##"{ 810 r##"{
853 "message": "mismatched types", 811 "message": "mismatched types",
854 "code": { 812 "code": {
@@ -882,16 +840,13 @@ mod tests {
882 "children": [], 840 "children": [],
883 "rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n" 841 "rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n"
884 }"##, 842 }"##,
843 expect_file!["crates/rust-analyzer/test_data/rustc_mismatched_type.txt"],
885 ); 844 );
886
887 let workspace_root = Path::new("/test/");
888 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
889 insta::assert_debug_snapshot!(diag);
890 } 845 }
891 846
892 #[test] 847 #[test]
893 fn snap_handles_macro_location() { 848 fn handles_macro_location() {
894 let diag = parse_diagnostic( 849 check(
895 r##"{ 850 r##"{
896 "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n", 851 "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n",
897 "children": [ 852 "children": [
@@ -1153,16 +1108,13 @@ mod tests {
1153 } 1108 }
1154 ] 1109 ]
1155 }"##, 1110 }"##,
1111 expect_file!["crates/rust-analyzer/test_data/handles_macro_location.txt"],
1156 ); 1112 );
1157
1158 let workspace_root = Path::new("/test/");
1159 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
1160 insta::assert_debug_snapshot!(diag);
1161 } 1113 }
1162 1114
1163 #[test] 1115 #[test]
1164 fn snap_macro_compiler_error() { 1116 fn macro_compiler_error() {
1165 let diag = parse_diagnostic( 1117 check(
1166 r##"{ 1118 r##"{
1167 "rendered": "error: Please register your known path in the path module\n --> crates/ra_hir_def/src/path.rs:265:9\n |\n265 | compile_error!(\"Please register your known path in the path module\")\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n | \n ::: crates/ra_hir_def/src/data.rs:80:16\n |\n80 | let path = path![std::future::Future];\n | -------------------------- in this macro invocation\n\n", 1119 "rendered": "error: Please register your known path in the path module\n --> crates/ra_hir_def/src/path.rs:265:9\n |\n265 | compile_error!(\"Please register your known path in the path module\")\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n | \n ::: crates/ra_hir_def/src/data.rs:80:16\n |\n80 | let path = path![std::future::Future];\n | -------------------------- in this macro invocation\n\n",
1168 "children": [], 1120 "children": [],
@@ -1382,16 +1334,13 @@ mod tests {
1382 ] 1334 ]
1383 } 1335 }
1384 "##, 1336 "##,
1337 expect_file!["crates/rust-analyzer/test_data/macro_compiler_error.txt"],
1385 ); 1338 );
1386
1387 let workspace_root = Path::new("/test/");
1388 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
1389 insta::assert_debug_snapshot!(diag);
1390 } 1339 }
1391 1340
1392 #[test] 1341 #[test]
1393 fn snap_multi_line_fix() { 1342 fn snap_multi_line_fix() {
1394 let diag = parse_diagnostic( 1343 check(
1395 r##"{ 1344 r##"{
1396 "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n", 1345 "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n",
1397 "children": [ 1346 "children": [
@@ -1515,10 +1464,7 @@ mod tests {
1515 ] 1464 ]
1516 } 1465 }
1517 "##, 1466 "##,
1467 expect_file!["crates/rust-analyzer/test_data/snap_multi_line_fix.txt"],
1518 ); 1468 );
1519
1520 let workspace_root = Path::new("/test/");
1521 let diag = map_rust_diagnostic_to_lsp(&DiagnosticsConfig::default(), &diag, workspace_root);
1522 insta::assert_debug_snapshot!(diag);
1523 } 1469 }
1524} 1470}
diff --git a/crates/rust-analyzer/src/document.rs b/crates/rust-analyzer/src/document.rs
new file mode 100644
index 000000000..43219e633
--- /dev/null
+++ b/crates/rust-analyzer/src/document.rs
@@ -0,0 +1,16 @@
1//! In-memory document information.
2
3/// Information about a document that the Language Client
4// knows about.
5// Its lifetime is driven by the textDocument/didOpen and textDocument/didClose
6// client notifications.
7#[derive(Debug, Clone)]
8pub(crate) struct DocumentData {
9 pub version: Option<i64>,
10}
11
12impl DocumentData {
13 pub fn new(version: i64) -> Self {
14 DocumentData { version: Some(version) }
15 }
16}
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index 15b281103..9f8ce3b99 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -2,7 +2,7 @@
2use std::convert::TryFrom; 2use std::convert::TryFrom;
3 3
4use ra_db::{FileId, FilePosition, FileRange}; 4use ra_db::{FileId, FilePosition, FileRange};
5use ra_ide::{LineCol, LineIndex}; 5use ra_ide::{AssistKind, LineCol, LineIndex};
6use ra_syntax::{TextRange, TextSize}; 6use ra_syntax::{TextRange, TextSize};
7use vfs::AbsPathBuf; 7use vfs::AbsPathBuf;
8 8
@@ -52,3 +52,17 @@ pub(crate) fn file_range(
52 let range = text_range(&line_index, range); 52 let range = text_range(&line_index, range);
53 Ok(FileRange { file_id, range }) 53 Ok(FileRange { file_id, range })
54} 54}
55
56pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
57 let assist_kind = match &kind {
58 k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
59 k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
60 k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
61 k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
62 k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
63 k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
64 _ => return None,
65 };
66
67 Some(assist_kind)
68}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index b8aa1e5b5..b2d65a6d1 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -12,11 +12,12 @@ use parking_lot::RwLock;
12use ra_db::{CrateId, VfsPath}; 12use ra_db::{CrateId, VfsPath};
13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; 13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId};
14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
16 16
17use crate::{ 17use crate::{
18 config::Config, 18 config::Config,
19 diagnostics::{CheckFixes, DiagnosticCollection}, 19 diagnostics::{CheckFixes, DiagnosticCollection},
20 document::DocumentData,
20 from_proto, 21 from_proto,
21 line_endings::LineEndings, 22 line_endings::LineEndings,
22 main_loop::Task, 23 main_loop::Task,
@@ -26,11 +27,14 @@ use crate::{
26 to_proto::url_from_abs_path, 27 to_proto::url_from_abs_path,
27 Result, 28 Result,
28}; 29};
30use ra_prof::profile;
29 31
30#[derive(Eq, PartialEq)] 32#[derive(Eq, PartialEq, Copy, Clone)]
31pub(crate) enum Status { 33pub(crate) enum Status {
32 Loading, 34 Loading,
33 Ready, 35 Ready,
36 Invalid,
37 NeedsReload,
34} 38}
35 39
36impl Default for Status { 40impl Default for Status {
@@ -60,11 +64,13 @@ pub(crate) struct GlobalState {
60 req_queue: ReqQueue, 64 req_queue: ReqQueue,
61 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, 65 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
62 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, 66 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
63 pub(crate) flycheck: Option<Handle<FlycheckHandle, Receiver<flycheck::Message>>>, 67 pub(crate) flycheck: Option<FlycheckHandle>,
68 pub(crate) flycheck_sender: Sender<flycheck::Message>,
69 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
64 pub(crate) config: Config, 70 pub(crate) config: Config,
65 pub(crate) analysis_host: AnalysisHost, 71 pub(crate) analysis_host: AnalysisHost,
66 pub(crate) diagnostics: DiagnosticCollection, 72 pub(crate) diagnostics: DiagnosticCollection,
67 pub(crate) mem_docs: FxHashSet<VfsPath>, 73 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
68 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, 74 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
69 pub(crate) status: Status, 75 pub(crate) status: Status,
70 pub(crate) source_root_config: SourceRootConfig, 76 pub(crate) source_root_config: SourceRootConfig,
@@ -79,6 +85,7 @@ pub(crate) struct GlobalStateSnapshot {
79 pub(crate) analysis: Analysis, 85 pub(crate) analysis: Analysis,
80 pub(crate) check_fixes: CheckFixes, 86 pub(crate) check_fixes: CheckFixes,
81 pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, 87 pub(crate) latest_requests: Arc<RwLock<LatestRequests>>,
88 mem_docs: FxHashMap<VfsPath, DocumentData>,
82 vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, 89 vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
83 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 90 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
84} 91}
@@ -100,16 +107,19 @@ impl GlobalState {
100 }; 107 };
101 108
102 let analysis_host = AnalysisHost::new(config.lru_capacity); 109 let analysis_host = AnalysisHost::new(config.lru_capacity);
110 let (flycheck_sender, flycheck_receiver) = unbounded();
103 GlobalState { 111 GlobalState {
104 sender, 112 sender,
105 req_queue: ReqQueue::default(), 113 req_queue: ReqQueue::default(),
106 task_pool, 114 task_pool,
107 loader, 115 loader,
108 flycheck: None, 116 flycheck: None,
117 flycheck_sender,
118 flycheck_receiver,
109 config, 119 config,
110 analysis_host, 120 analysis_host,
111 diagnostics: Default::default(), 121 diagnostics: Default::default(),
112 mem_docs: FxHashSet::default(), 122 mem_docs: FxHashMap::default(),
113 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), 123 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
114 status: Status::default(), 124 status: Status::default(),
115 source_root_config: SourceRootConfig::default(), 125 source_root_config: SourceRootConfig::default(),
@@ -120,6 +130,10 @@ impl GlobalState {
120 } 130 }
121 131
122 pub(crate) fn process_changes(&mut self) -> bool { 132 pub(crate) fn process_changes(&mut self) -> bool {
133 let _p = profile("GlobalState::process_changes");
134 let mut fs_changes = Vec::new();
135 let mut has_fs_changes = false;
136
123 let change = { 137 let change = {
124 let mut change = AnalysisChange::new(); 138 let mut change = AnalysisChange::new();
125 let (vfs, line_endings_map) = &mut *self.vfs.write(); 139 let (vfs, line_endings_map) = &mut *self.vfs.write();
@@ -128,13 +142,14 @@ impl GlobalState {
128 return false; 142 return false;
129 } 143 }
130 144
131 let fs_op = changed_files.iter().any(|it| it.is_created_or_deleted());
132 if fs_op {
133 let roots = self.source_root_config.partition(&vfs);
134 change.set_roots(roots)
135 }
136
137 for file in changed_files { 145 for file in changed_files {
146 if file.is_created_or_deleted() {
147 if let Some(path) = vfs.file_path(file.file_id).as_path() {
148 fs_changes.push((path.to_path_buf(), file.change_kind));
149 has_fs_changes = true;
150 }
151 }
152
138 let text = if file.exists() { 153 let text = if file.exists() {
139 let bytes = vfs.file_contents(file.file_id).to_vec(); 154 let bytes = vfs.file_contents(file.file_id).to_vec();
140 match String::from_utf8(bytes).ok() { 155 match String::from_utf8(bytes).ok() {
@@ -150,10 +165,15 @@ impl GlobalState {
150 }; 165 };
151 change.change_file(file.file_id, text); 166 change.change_file(file.file_id, text);
152 } 167 }
168 if has_fs_changes {
169 let roots = self.source_root_config.partition(&vfs);
170 change.set_roots(roots);
171 }
153 change 172 change
154 }; 173 };
155 174
156 self.analysis_host.apply_change(change); 175 self.analysis_host.apply_change(change);
176 self.maybe_refresh(&fs_changes);
157 true 177 true
158 } 178 }
159 179
@@ -165,6 +185,7 @@ impl GlobalState {
165 vfs: Arc::clone(&self.vfs), 185 vfs: Arc::clone(&self.vfs),
166 latest_requests: Arc::clone(&self.latest_requests), 186 latest_requests: Arc::clone(&self.latest_requests),
167 check_fixes: Arc::clone(&self.diagnostics.check_fixes), 187 check_fixes: Arc::clone(&self.diagnostics.check_fixes),
188 mem_docs: self.mem_docs.clone(),
168 } 189 }
169 } 190 }
170 191
@@ -202,8 +223,7 @@ impl GlobalState {
202 if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) { 223 if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
203 let duration = start.elapsed(); 224 let duration = start.elapsed();
204 log::info!("handled req#{} in {:?}", response.id, duration); 225 log::info!("handled req#{} in {:?}", response.id, duration);
205 let metrics = 226 let metrics = RequestMetrics { id: response.id.clone(), method, duration };
206 RequestMetrics { id: response.id.clone(), method: method.to_string(), duration };
207 self.latest_requests.write().record(metrics); 227 self.latest_requests.write().record(metrics);
208 self.send(response.into()); 228 self.send(response.into());
209 } 229 }
@@ -238,6 +258,11 @@ impl GlobalStateSnapshot {
238 self.vfs.read().1[&id] 258 self.vfs.read().1[&id]
239 } 259 }
240 260
261 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i64> {
262 let path = from_proto::vfs_path(&url).ok()?;
263 self.mem_docs.get(&path)?.version
264 }
265
241 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { 266 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url {
242 let mut base = self.vfs.read().0.file_path(file_id); 267 let mut base = self.vfs.read().0.file_path(file_id);
243 base.pop(); 268 base.pop();
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index e35a5e846..e73b3a211 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -11,11 +11,11 @@ use lsp_server::ErrorCode;
11use lsp_types::{ 11use lsp_types::{
12 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, 12 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
13 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, 13 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
14 CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams, DocumentHighlight, 14 CodeActionKind, CodeLens, Command, CompletionItem, Diagnostic, DocumentFormattingParams,
15 DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, MarkupContent, 15 DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location,
16 MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, 16 Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams,
17 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, 17 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
18 TextDocumentIdentifier, Url, WorkspaceEdit, 18 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
19}; 19};
20use ra_ide::{ 20use ra_ide::{
21 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, 21 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
@@ -23,16 +23,16 @@ use ra_ide::{
23}; 23};
24use ra_prof::profile; 24use ra_prof::profile;
25use ra_project_model::TargetKind; 25use ra_project_model::TargetKind;
26use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; 26use ra_syntax::{algo, ast, AstNode, SyntaxKind, TextRange, TextSize};
27use serde::{Deserialize, Serialize}; 27use serde::{Deserialize, Serialize};
28use serde_json::to_value; 28use serde_json::to_value;
29use stdx::{format_to, split_delim}; 29use stdx::{format_to, split_once};
30 30
31use crate::{ 31use crate::{
32 cargo_target_spec::CargoTargetSpec, 32 cargo_target_spec::CargoTargetSpec,
33 config::RustfmtConfig, 33 config::RustfmtConfig,
34 from_json, from_proto, 34 from_json, from_proto,
35 global_state::GlobalStateSnapshot, 35 global_state::{GlobalState, GlobalStateSnapshot},
36 lsp_ext::{self, InlayHint, InlayHintsParams}, 36 lsp_ext::{self, InlayHint, InlayHintsParams},
37 to_proto, LspError, Result, 37 to_proto, LspError, Result,
38}; 38};
@@ -62,6 +62,17 @@ pub(crate) fn handle_analyzer_status(snap: GlobalStateSnapshot, _: ()) -> Result
62 Ok(buf) 62 Ok(buf)
63} 63}
64 64
65pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> {
66 let _p = profile("handle_memory_usage");
67 let mem = state.analysis_host.per_query_memory_usage();
68
69 let mut out = String::new();
70 for (name, bytes) in mem {
71 format_to!(out, "{:>8} {}\n", bytes, name);
72 }
73 Ok(out)
74}
75
65pub(crate) fn handle_syntax_tree( 76pub(crate) fn handle_syntax_tree(
66 snap: GlobalStateSnapshot, 77 snap: GlobalStateSnapshot,
67 params: lsp_ext::SyntaxTreeParams, 78 params: lsp_ext::SyntaxTreeParams,
@@ -242,10 +253,17 @@ pub(crate) fn handle_document_symbol(
242 let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); 253 let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new();
243 254
244 for symbol in snap.analysis.file_structure(file_id)? { 255 for symbol in snap.analysis.file_structure(file_id)? {
256 let mut tags = Vec::new();
257 if symbol.deprecated {
258 tags.push(SymbolTag::Deprecated)
259 };
260
261 #[allow(deprecated)]
245 let doc_symbol = DocumentSymbol { 262 let doc_symbol = DocumentSymbol {
246 name: symbol.label, 263 name: symbol.label,
247 detail: symbol.detail, 264 detail: symbol.detail,
248 kind: to_proto::symbol_kind(symbol.kind), 265 kind: to_proto::symbol_kind(symbol.kind),
266 tags: Some(tags),
249 deprecated: Some(symbol.deprecated), 267 deprecated: Some(symbol.deprecated),
250 range: to_proto::range(&line_index, symbol.node_range), 268 range: to_proto::range(&line_index, symbol.node_range),
251 selection_range: to_proto::range(&line_index, symbol.navigation_range), 269 selection_range: to_proto::range(&line_index, symbol.navigation_range),
@@ -285,9 +303,19 @@ pub(crate) fn handle_document_symbol(
285 url: &Url, 303 url: &Url,
286 res: &mut Vec<SymbolInformation>, 304 res: &mut Vec<SymbolInformation>,
287 ) { 305 ) {
306 let mut tags = Vec::new();
307
308 #[allow(deprecated)]
309 match symbol.deprecated {
310 Some(true) => tags.push(SymbolTag::Deprecated),
311 _ => {}
312 }
313
314 #[allow(deprecated)]
288 res.push(SymbolInformation { 315 res.push(SymbolInformation {
289 name: symbol.name.clone(), 316 name: symbol.name.clone(),
290 kind: symbol.kind, 317 kind: symbol.kind,
318 tags: Some(tags),
291 deprecated: symbol.deprecated, 319 deprecated: symbol.deprecated,
292 location: Location::new(url.clone(), symbol.range), 320 location: Location::new(url.clone(), symbol.range),
293 container_name, 321 container_name,
@@ -330,11 +358,15 @@ pub(crate) fn handle_workspace_symbol(
330 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { 358 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
331 let mut res = Vec::new(); 359 let mut res = Vec::new();
332 for nav in snap.analysis.symbol_search(query)? { 360 for nav in snap.analysis.symbol_search(query)? {
361 let container_name = nav.container_name.as_ref().map(|v| v.to_string());
362
363 #[allow(deprecated)]
333 let info = SymbolInformation { 364 let info = SymbolInformation {
334 name: nav.name().to_string(), 365 name: nav.name.to_string(),
335 kind: to_proto::symbol_kind(nav.kind()), 366 kind: to_proto::symbol_kind(nav.kind),
336 location: to_proto::location(snap, nav.file_range())?, 367 tags: None,
337 container_name: nav.container_name().map(|v| v.to_string()), 368 location: to_proto::location_from_nav(snap, nav)?,
369 container_name,
338 deprecated: None, 370 deprecated: None,
339 }; 371 };
340 res.push(info); 372 res.push(info);
@@ -407,27 +439,42 @@ pub(crate) fn handle_runnables(
407 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 439 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
408 let line_index = snap.analysis.file_line_index(file_id)?; 440 let line_index = snap.analysis.file_line_index(file_id)?;
409 let offset = params.position.map(|it| from_proto::offset(&line_index, it)); 441 let offset = params.position.map(|it| from_proto::offset(&line_index, it));
410 let mut res = Vec::new();
411 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; 442 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
443
444 let expect_test = match offset {
445 Some(offset) => {
446 let source_file = snap.analysis.parse(file_id)?;
447 algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
448 .and_then(|it| it.path()?.segment()?.name_ref())
449 .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
450 }
451 None => false,
452 };
453
454 let mut res = Vec::new();
412 for runnable in snap.analysis.runnables(file_id)? { 455 for runnable in snap.analysis.runnables(file_id)? {
413 if let Some(offset) = offset { 456 if let Some(offset) = offset {
414 if !runnable.nav.full_range().contains_inclusive(offset) { 457 if !runnable.nav.full_range.contains_inclusive(offset) {
415 continue; 458 continue;
416 } 459 }
417 } 460 }
418 if should_skip_target(&runnable, cargo_spec.as_ref()) { 461 if should_skip_target(&runnable, cargo_spec.as_ref()) {
419 continue; 462 continue;
420 } 463 }
421 464 let mut runnable = to_proto::runnable(&snap, file_id, runnable)?;
422 res.push(to_proto::runnable(&snap, file_id, runnable)?); 465 if expect_test {
466 runnable.label = format!("{} + expect", runnable.label);
467 runnable.args.expect_test = Some(true);
468 }
469 res.push(runnable);
423 } 470 }
424 471
425 // Add `cargo check` and `cargo test` for the whole package 472 // Add `cargo check` and `cargo test` for all targets of the whole package
426 match cargo_spec { 473 match cargo_spec {
427 Some(spec) => { 474 Some(spec) => {
428 for &cmd in ["check", "test"].iter() { 475 for &cmd in ["check", "test"].iter() {
429 res.push(lsp_ext::Runnable { 476 res.push(lsp_ext::Runnable {
430 label: format!("cargo {} -p {}", cmd, spec.package), 477 label: format!("cargo {} -p {} --all-targets", cmd, spec.package),
431 location: None, 478 location: None,
432 kind: lsp_ext::RunnableKind::Cargo, 479 kind: lsp_ext::RunnableKind::Cargo,
433 args: lsp_ext::CargoRunnable { 480 args: lsp_ext::CargoRunnable {
@@ -436,8 +483,10 @@ pub(crate) fn handle_runnables(
436 cmd.to_string(), 483 cmd.to_string(),
437 "--package".to_string(), 484 "--package".to_string(),
438 spec.package.clone(), 485 spec.package.clone(),
486 "--all-targets".to_string(),
439 ], 487 ],
440 executable_args: Vec::new(), 488 executable_args: Vec::new(),
489 expect_test: None,
441 }, 490 },
442 }) 491 })
443 } 492 }
@@ -451,6 +500,7 @@ pub(crate) fn handle_runnables(
451 workspace_root: None, 500 workspace_root: None,
452 cargo_args: vec!["check".to_string(), "--workspace".to_string()], 501 cargo_args: vec!["check".to_string(), "--workspace".to_string()],
453 executable_args: Vec::new(), 502 executable_args: Vec::new(),
503 expect_test: None,
454 }, 504 },
455 }); 505 });
456 } 506 }
@@ -524,21 +574,16 @@ pub(crate) fn handle_signature_help(
524 let _p = profile("handle_signature_help"); 574 let _p = profile("handle_signature_help");
525 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 575 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
526 let call_info = match snap.analysis.call_info(position)? { 576 let call_info = match snap.analysis.call_info(position)? {
527 None => return Ok(None),
528 Some(it) => it, 577 Some(it) => it,
578 None => return Ok(None),
529 }; 579 };
530 let concise = !snap.config.call_info_full; 580 let concise = !snap.config.call_info_full;
531 let mut active_parameter = call_info.active_parameter.map(|it| it as i64); 581 let res = to_proto::signature_help(
532 if concise && call_info.signature.has_self_param { 582 call_info,
533 active_parameter = active_parameter.map(|it| it.saturating_sub(1)); 583 concise,
534 } 584 snap.config.client_caps.signature_help_label_offsets,
535 let sig_info = to_proto::signature_information(call_info.signature, concise); 585 );
536 586 Ok(Some(res))
537 Ok(Some(lsp_types::SignatureHelp {
538 signatures: vec![sig_info],
539 active_signature: Some(0),
540 active_parameter,
541 }))
542} 587}
543 588
544pub(crate) fn handle_hover( 589pub(crate) fn handle_hover(
@@ -555,13 +600,10 @@ pub(crate) fn handle_hover(
555 let range = to_proto::range(&line_index, info.range); 600 let range = to_proto::range(&line_index, info.range);
556 let hover = lsp_ext::Hover { 601 let hover = lsp_ext::Hover {
557 hover: lsp_types::Hover { 602 hover: lsp_types::Hover {
558 contents: HoverContents::Markup(MarkupContent { 603 contents: HoverContents::Markup(to_proto::markup_content(info.info.markup)),
559 kind: MarkupKind::Markdown,
560 value: crate::markdown::format_docs(&info.info.to_markup()),
561 }),
562 range: Some(range), 604 range: Some(range),
563 }, 605 },
564 actions: prepare_hover_actions(&snap, position.file_id, info.info.actions()), 606 actions: prepare_hover_actions(&snap, position.file_id, &info.info.actions),
565 }; 607 };
566 608
567 Ok(Some(hover)) 609 Ok(Some(hover))
@@ -720,7 +762,20 @@ fn handle_fixes(
720 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 762 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
721 let line_index = snap.analysis.file_line_index(file_id)?; 763 let line_index = snap.analysis.file_line_index(file_id)?;
722 let range = from_proto::text_range(&line_index, params.range); 764 let range = from_proto::text_range(&line_index, params.range);
723 let diagnostics = snap.analysis.diagnostics(file_id)?; 765
766 match &params.context.only {
767 Some(v) => {
768 if !v.iter().any(|it| {
769 it == &lsp_types::CodeActionKind::EMPTY
770 || it == &lsp_types::CodeActionKind::QUICKFIX
771 }) {
772 return Ok(());
773 }
774 }
775 None => {}
776 };
777
778 let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?;
724 779
725 let fixes_from_diagnostics = diagnostics 780 let fixes_from_diagnostics = diagnostics
726 .into_iter() 781 .into_iter()
@@ -734,9 +789,9 @@ fn handle_fixes(
734 title, 789 title,
735 id: None, 790 id: None,
736 group: None, 791 group: None,
737 kind: Some(lsp_types::code_action_kind::QUICKFIX.into()), 792 kind: Some(CodeActionKind::QUICKFIX),
738 edit: Some(edit), 793 edit: Some(edit),
739 command: None, 794 is_preferred: Some(false),
740 }; 795 };
741 res.push(action); 796 res.push(action);
742 } 797 }
@@ -752,7 +807,7 @@ fn handle_fixes(
752} 807}
753 808
754pub(crate) fn handle_code_action( 809pub(crate) fn handle_code_action(
755 snap: GlobalStateSnapshot, 810 mut snap: GlobalStateSnapshot,
756 params: lsp_types::CodeActionParams, 811 params: lsp_types::CodeActionParams,
757) -> Result<Option<Vec<lsp_ext::CodeAction>>> { 812) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
758 let _p = profile("handle_code_action"); 813 let _p = profile("handle_code_action");
@@ -767,6 +822,13 @@ pub(crate) fn handle_code_action(
767 let line_index = snap.analysis.file_line_index(file_id)?; 822 let line_index = snap.analysis.file_line_index(file_id)?;
768 let range = from_proto::text_range(&line_index, params.range); 823 let range = from_proto::text_range(&line_index, params.range);
769 let frange = FileRange { file_id, range }; 824 let frange = FileRange { file_id, range };
825
826 snap.config.assist.allowed = params
827 .clone()
828 .context
829 .only
830 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
831
770 let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); 832 let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
771 833
772 handle_fixes(&snap, &params, &mut res)?; 834 handle_fixes(&snap, &params, &mut res)?;
@@ -787,7 +849,7 @@ pub(crate) fn handle_code_action(
787} 849}
788 850
789pub(crate) fn handle_resolve_code_action( 851pub(crate) fn handle_resolve_code_action(
790 snap: GlobalStateSnapshot, 852 mut snap: GlobalStateSnapshot,
791 params: lsp_ext::ResolveCodeActionParams, 853 params: lsp_ext::ResolveCodeActionParams,
792) -> Result<Option<lsp_ext::SnippetWorkspaceEdit>> { 854) -> Result<Option<lsp_ext::SnippetWorkspaceEdit>> {
793 let _p = profile("handle_resolve_code_action"); 855 let _p = profile("handle_resolve_code_action");
@@ -796,8 +858,14 @@ pub(crate) fn handle_resolve_code_action(
796 let range = from_proto::text_range(&line_index, params.code_action_params.range); 858 let range = from_proto::text_range(&line_index, params.code_action_params.range);
797 let frange = FileRange { file_id, range }; 859 let frange = FileRange { file_id, range };
798 860
861 snap.config.assist.allowed = params
862 .code_action_params
863 .context
864 .only
865 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
866
799 let assists = snap.analysis.resolved_assists(&snap.config.assist, frange)?; 867 let assists = snap.analysis.resolved_assists(&snap.config.assist, frange)?;
800 let (id_string, index) = split_delim(&params.id, ':').unwrap(); 868 let (id_string, index) = split_once(&params.id, ':').unwrap();
801 let index = index.parse::<usize>().unwrap(); 869 let index = index.parse::<usize>().unwrap();
802 let assist = &assists[index]; 870 let assist = &assists[index];
803 assert!(assist.assist.id.0 == id_string); 871 assert!(assist.assist.id.0 == id_string);
@@ -828,7 +896,7 @@ pub(crate) fn handle_code_lens(
828 } 896 }
829 897
830 let action = runnable.action(); 898 let action = runnable.action();
831 let range = to_proto::range(&line_index, runnable.nav.range()); 899 let range = to_proto::range(&line_index, runnable.nav.focus_or_full_range());
832 let r = to_proto::runnable(&snap, file_id, runnable)?; 900 let r = to_proto::runnable(&snap, file_id, runnable)?;
833 if snap.config.lens.run { 901 if snap.config.lens.run {
834 let lens = CodeLens { 902 let lens = CodeLens {
@@ -847,15 +915,20 @@ pub(crate) fn handle_code_lens(
847 } 915 }
848 } 916 }
849 917
850 if snap.config.lens.impementations { 918 if snap.config.lens.implementations {
851 // Handle impls 919 // Handle impls
852 lenses.extend( 920 lenses.extend(
853 snap.analysis 921 snap.analysis
854 .file_structure(file_id)? 922 .file_structure(file_id)?
855 .into_iter() 923 .into_iter()
856 .filter(|it| match it.kind { 924 .filter(|it| {
857 SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true, 925 matches!(
858 _ => false, 926 it.kind,
927 SyntaxKind::TRAIT
928 | SyntaxKind::STRUCT
929 | SyntaxKind::ENUM
930 | SyntaxKind::UNION
931 )
859 }) 932 })
860 .map(|it| { 933 .map(|it| {
861 let range = to_proto::range(&line_index, it.node_range); 934 let range = to_proto::range(&line_index, it.node_range);
@@ -954,8 +1027,18 @@ pub(crate) fn handle_ssr(
954 params: lsp_ext::SsrParams, 1027 params: lsp_ext::SsrParams,
955) -> Result<lsp_types::WorkspaceEdit> { 1028) -> Result<lsp_types::WorkspaceEdit> {
956 let _p = profile("handle_ssr"); 1029 let _p = profile("handle_ssr");
957 let source_change = 1030 let selections = params
958 snap.analysis.structural_search_replace(&params.query, params.parse_only)??; 1031 .selections
1032 .iter()
1033 .map(|range| from_proto::file_range(&snap, params.position.text_document.clone(), *range))
1034 .collect::<Result<Vec<_>, _>>()?;
1035 let position = from_proto::file_position(&snap, params.position)?;
1036 let source_change = snap.analysis.structural_search_replace(
1037 &params.query,
1038 params.parse_only,
1039 position,
1040 selections,
1041 )??;
959 to_proto::workspace_edit(&snap, source_change) 1042 to_proto::workspace_edit(&snap, source_change)
960} 1043}
961 1044
@@ -967,7 +1050,7 @@ pub(crate) fn publish_diagnostics(
967 let line_index = snap.analysis.file_line_index(file_id)?; 1050 let line_index = snap.analysis.file_line_index(file_id)?;
968 let diagnostics: Vec<Diagnostic> = snap 1051 let diagnostics: Vec<Diagnostic> = snap
969 .analysis 1052 .analysis
970 .diagnostics(file_id)? 1053 .diagnostics(file_id, snap.config.experimental_diagnostics)?
971 .into_iter() 1054 .into_iter()
972 .map(|d| Diagnostic { 1055 .map(|d| Diagnostic {
973 range: to_proto::range(&line_index, d.range), 1056 range: to_proto::range(&line_index, d.range),
@@ -1012,7 +1095,7 @@ pub(crate) fn handle_call_hierarchy_prepare(
1012 let RangeInfo { range: _, info: navs } = nav_info; 1095 let RangeInfo { range: _, info: navs } = nav_info;
1013 let res = navs 1096 let res = navs
1014 .into_iter() 1097 .into_iter()
1015 .filter(|it| it.kind() == SyntaxKind::FN_DEF) 1098 .filter(|it| it.kind == SyntaxKind::FN)
1016 .map(|it| to_proto::call_hierarchy_item(&snap, it)) 1099 .map(|it| to_proto::call_hierarchy_item(&snap, it))
1017 .collect::<Result<Vec<_>>>()?; 1100 .collect::<Result<Vec<_>>>()?;
1018 1101
@@ -1027,7 +1110,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
1027 let item = params.item; 1110 let item = params.item;
1028 1111
1029 let doc = TextDocumentIdentifier::new(item.uri); 1112 let doc = TextDocumentIdentifier::new(item.uri);
1030 let frange = from_proto::file_range(&snap, doc, item.range)?; 1113 let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
1031 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 1114 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
1032 1115
1033 let call_items = match snap.analysis.incoming_calls(fpos)? { 1116 let call_items = match snap.analysis.incoming_calls(fpos)? {
@@ -1038,7 +1121,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
1038 let mut res = vec![]; 1121 let mut res = vec![];
1039 1122
1040 for call_item in call_items.into_iter() { 1123 for call_item in call_items.into_iter() {
1041 let file_id = call_item.target.file_id(); 1124 let file_id = call_item.target.file_id;
1042 let line_index = snap.analysis.file_line_index(file_id)?; 1125 let line_index = snap.analysis.file_line_index(file_id)?;
1043 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; 1126 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
1044 res.push(CallHierarchyIncomingCall { 1127 res.push(CallHierarchyIncomingCall {
@@ -1062,7 +1145,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
1062 let item = params.item; 1145 let item = params.item;
1063 1146
1064 let doc = TextDocumentIdentifier::new(item.uri); 1147 let doc = TextDocumentIdentifier::new(item.uri);
1065 let frange = from_proto::file_range(&snap, doc, item.range)?; 1148 let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
1066 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 1149 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
1067 1150
1068 let call_items = match snap.analysis.outgoing_calls(fpos)? { 1151 let call_items = match snap.analysis.outgoing_calls(fpos)? {
@@ -1073,7 +1156,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
1073 let mut res = vec![]; 1156 let mut res = vec![];
1074 1157
1075 for call_item in call_items.into_iter() { 1158 for call_item in call_items.into_iter() {
1076 let file_id = call_item.target.file_id(); 1159 let file_id = call_item.target.file_id;
1077 let line_index = snap.analysis.file_line_index(file_id)?; 1160 let line_index = snap.analysis.file_line_index(file_id)?;
1078 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; 1161 let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
1079 res.push(CallHierarchyOutgoingCall { 1162 res.push(CallHierarchyOutgoingCall {
@@ -1169,13 +1252,13 @@ fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) ->
1169 let link = to_proto::location_link(snap, None, nav.clone()).ok()?; 1252 let link = to_proto::location_link(snap, None, nav.clone()).ok()?;
1170 to_value(link).ok()? 1253 to_value(link).ok()?
1171 } else { 1254 } else {
1172 let range = FileRange { file_id: nav.file_id(), range: nav.range() }; 1255 let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() };
1173 let location = to_proto::location(snap, range).ok()?; 1256 let location = to_proto::location(snap, range).ok()?;
1174 to_value(location).ok()? 1257 to_value(location).ok()?
1175 }; 1258 };
1176 1259
1177 Some(Command { 1260 Some(Command {
1178 title: nav.name().to_string(), 1261 title: nav.name.to_string(),
1179 command: "rust-analyzer.gotoLocation".into(), 1262 command: "rust-analyzer.gotoLocation".into(),
1180 arguments: Some(vec![value]), 1263 arguments: Some(vec![value]),
1181 }) 1264 })
@@ -1196,8 +1279,8 @@ fn show_impl_command_link(
1196 let position = to_proto::position(&line_index, position.offset); 1279 let position = to_proto::position(&line_index, position.offset);
1197 let locations: Vec<_> = nav_data 1280 let locations: Vec<_> = nav_data
1198 .info 1281 .info
1199 .iter() 1282 .into_iter()
1200 .filter_map(|it| to_proto::location(snap, it.file_range()).ok()) 1283 .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
1201 .collect(); 1284 .collect();
1202 let title = implementation_title(locations.len()); 1285 let title = implementation_title(locations.len());
1203 let command = show_references_command(title, &uri, position, locations); 1286 let command = show_references_command(title, &uri, position, locations);
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 407944d85..ed37992cd 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -33,6 +33,7 @@ mod line_endings;
33mod request_metrics; 33mod request_metrics;
34mod lsp_utils; 34mod lsp_utils;
35mod thread_pool; 35mod thread_pool;
36mod document;
36pub mod lsp_ext; 37pub mod lsp_ext;
37pub mod config; 38pub mod config;
38 39
@@ -40,7 +41,9 @@ use serde::de::DeserializeOwned;
40 41
41pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>; 42pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>;
42pub use crate::{caps::server_capabilities, main_loop::main_loop}; 43pub use crate::{caps::server_capabilities, main_loop::main_loop};
44use ra_ide::AnalysisHost;
43use std::fmt; 45use std::fmt;
46use vfs::Vfs;
44 47
45pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { 48pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
46 let res = T::deserialize(&json) 49 let res = T::deserialize(&json)
@@ -67,3 +70,22 @@ impl fmt::Display for LspError {
67} 70}
68 71
69impl std::error::Error for LspError {} 72impl std::error::Error for LspError {}
73
74fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) {
75 let mut mem = host.per_query_memory_usage();
76
77 let before = ra_prof::memory_usage();
78 drop(vfs);
79 let vfs = before.allocated - ra_prof::memory_usage().allocated;
80 mem.push(("VFS".into(), vfs));
81
82 let before = ra_prof::memory_usage();
83 drop(host);
84 mem.push(("Unaccounted".into(), before.allocated - ra_prof::memory_usage().allocated));
85
86 mem.push(("Remaining".into(), ra_prof::memory_usage().allocated));
87
88 for (name, bytes) in mem {
89 eprintln!("{:>8} {}", bytes, name);
90 }
91}
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 1371f6cb4..3976b6529 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -3,7 +3,9 @@
3use std::{collections::HashMap, path::PathBuf}; 3use std::{collections::HashMap, path::PathBuf};
4 4
5use lsp_types::request::Request; 5use lsp_types::request::Request;
6use lsp_types::{Position, Range, TextDocumentIdentifier}; 6use lsp_types::{
7 notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier,
8};
7use serde::{Deserialize, Serialize}; 9use serde::{Deserialize, Serialize};
8 10
9pub enum AnalyzerStatus {} 11pub enum AnalyzerStatus {}
@@ -14,12 +16,20 @@ impl Request for AnalyzerStatus {
14 const METHOD: &'static str = "rust-analyzer/analyzerStatus"; 16 const METHOD: &'static str = "rust-analyzer/analyzerStatus";
15} 17}
16 18
17pub enum CollectGarbage {} 19pub enum MemoryUsage {}
18 20
19impl Request for CollectGarbage { 21impl Request for MemoryUsage {
22 type Params = ();
23 type Result = String;
24 const METHOD: &'static str = "rust-analyzer/memoryUsage";
25}
26
27pub enum ReloadWorkspace {}
28
29impl Request for ReloadWorkspace {
20 type Params = (); 30 type Params = ();
21 type Result = (); 31 type Result = ();
22 const METHOD: &'static str = "rust-analyzer/collectGarbage"; 32 const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
23} 33}
24 34
25pub enum SyntaxTree {} 35pub enum SyntaxTree {}
@@ -161,6 +171,8 @@ pub struct CargoRunnable {
161 pub cargo_args: Vec<String>, 171 pub cargo_args: Vec<String>,
162 // stuff after -- 172 // stuff after --
163 pub executable_args: Vec<String>, 173 pub executable_args: Vec<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub expect_test: Option<bool>,
164} 176}
165 177
166pub enum InlayHints {} 178pub enum InlayHints {}
@@ -204,6 +216,30 @@ impl Request for Ssr {
204pub struct SsrParams { 216pub struct SsrParams {
205 pub query: String, 217 pub query: String,
206 pub parse_only: bool, 218 pub parse_only: bool,
219
220 /// File position where SSR was invoked. Paths in `query` will be resolved relative to this
221 /// position.
222 #[serde(flatten)]
223 pub position: lsp_types::TextDocumentPositionParams,
224
225 /// Current selections. Search/replace will be restricted to these if non-empty.
226 pub selections: Vec<lsp_types::Range>,
227}
228
229pub enum StatusNotification {}
230
231#[serde(rename_all = "camelCase")]
232#[derive(Serialize, Deserialize)]
233pub enum Status {
234 Loading,
235 Ready,
236 NeedsReload,
237 Invalid,
238}
239
240impl Notification for StatusNotification {
241 type Params = Status;
242 const METHOD: &'static str = "rust-analyzer/status";
207} 243}
208 244
209pub enum CodeActionRequest {} 245pub enum CodeActionRequest {}
@@ -215,6 +251,7 @@ impl Request for CodeActionRequest {
215} 251}
216 252
217#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] 253#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
254#[serde(rename_all = "camelCase")]
218pub struct CodeAction { 255pub struct CodeAction {
219 pub title: String, 256 pub title: String,
220 #[serde(skip_serializing_if = "Option::is_none")] 257 #[serde(skip_serializing_if = "Option::is_none")]
@@ -222,11 +259,14 @@ pub struct CodeAction {
222 #[serde(skip_serializing_if = "Option::is_none")] 259 #[serde(skip_serializing_if = "Option::is_none")]
223 pub group: Option<String>, 260 pub group: Option<String>,
224 #[serde(skip_serializing_if = "Option::is_none")] 261 #[serde(skip_serializing_if = "Option::is_none")]
225 pub kind: Option<String>, 262 pub kind: Option<CodeActionKind>,
226 #[serde(skip_serializing_if = "Option::is_none")] 263 // We don't handle commands on the client-side
227 pub command: Option<lsp_types::Command>, 264 // #[serde(skip_serializing_if = "Option::is_none")]
265 // pub command: Option<lsp_types::Command>,
228 #[serde(skip_serializing_if = "Option::is_none")] 266 #[serde(skip_serializing_if = "Option::is_none")]
229 pub edit: Option<SnippetWorkspaceEdit>, 267 pub edit: Option<SnippetWorkspaceEdit>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub is_preferred: Option<bool>,
230} 270}
231 271
232#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] 272#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 0bc3ff115..d4cc9dd04 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,5 +1,5 @@
1//! Utilities for LSP-related boilerplate code. 1//! Utilities for LSP-related boilerplate code.
2use std::{error::Error, ops::Range}; 2use std::{borrow::Cow, error::Error, ops::Range};
3 3
4use lsp_server::Notification; 4use lsp_server::Notification;
5use ra_db::Canceled; 5use ra_db::Canceled;
@@ -84,8 +84,8 @@ impl GlobalState {
84pub(crate) fn apply_document_changes( 84pub(crate) fn apply_document_changes(
85 old_text: &mut String, 85 old_text: &mut String,
86 content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>, 86 content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
87 mut line_index: Cow<'_, LineIndex>,
87) { 88) {
88 let mut line_index = LineIndex::new(old_text);
89 // The changes we got must be applied sequentially, but can cross lines so we 89 // The changes we got must be applied sequentially, but can cross lines so we
90 // have to keep our line index updated. 90 // have to keep our line index updated.
91 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we 91 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
@@ -110,7 +110,7 @@ pub(crate) fn apply_document_changes(
110 match change.range { 110 match change.range {
111 Some(range) => { 111 Some(range) => {
112 if !index_valid.covers(range.end.line) { 112 if !index_valid.covers(range.end.line) {
113 line_index = LineIndex::new(&old_text); 113 line_index = Cow::Owned(LineIndex::new(old_text));
114 } 114 }
115 index_valid = IndexValid::UpToLineExclusive(range.start.line); 115 index_valid = IndexValid::UpToLineExclusive(range.start.line);
116 let range = from_proto::text_range(&line_index, range); 116 let range = from_proto::text_range(&line_index, range);
@@ -145,10 +145,15 @@ mod tests {
145 }; 145 };
146 } 146 }
147 147
148 fn run(text: &mut String, changes: Vec<TextDocumentContentChangeEvent>) {
149 let line_index = Cow::Owned(LineIndex::new(&text));
150 super::apply_document_changes(text, changes, line_index);
151 }
152
148 let mut text = String::new(); 153 let mut text = String::new();
149 apply_document_changes(&mut text, vec![]); 154 run(&mut text, vec![]);
150 assert_eq!(text, ""); 155 assert_eq!(text, "");
151 apply_document_changes( 156 run(
152 &mut text, 157 &mut text,
153 vec![TextDocumentContentChangeEvent { 158 vec![TextDocumentContentChangeEvent {
154 range: None, 159 range: None,
@@ -157,39 +162,36 @@ mod tests {
157 }], 162 }],
158 ); 163 );
159 assert_eq!(text, "the"); 164 assert_eq!(text, "the");
160 apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); 165 run(&mut text, c![0, 3; 0, 3 => " quick"]);
161 assert_eq!(text, "the quick"); 166 assert_eq!(text, "the quick");
162 apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); 167 run(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
163 assert_eq!(text, "quick foxes"); 168 assert_eq!(text, "quick foxes");
164 apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); 169 run(&mut text, c![0, 11; 0, 11 => "\ndream"]);
165 assert_eq!(text, "quick foxes\ndream"); 170 assert_eq!(text, "quick foxes\ndream");
166 apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); 171 run(&mut text, c![1, 0; 1, 0 => "have "]);
167 assert_eq!(text, "quick foxes\nhave dream"); 172 assert_eq!(text, "quick foxes\nhave dream");
168 apply_document_changes( 173 run(&mut text, c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"]);
169 &mut text,
170 c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
171 );
172 assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); 174 assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
173 apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); 175 run(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
174 assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); 176 assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
175 apply_document_changes( 177 run(
176 &mut text, 178 &mut text,
177 c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], 179 c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
178 ); 180 );
179 assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); 181 assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
180 apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); 182 run(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
181 assert_eq!(text, "the quick \nthey have quiet dreams\n"); 183 assert_eq!(text, "the quick \nthey have quiet dreams\n");
182 184
183 text = String::from("❤️"); 185 text = String::from("❤️");
184 apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); 186 run(&mut text, c![0, 0; 0, 0 => "a"]);
185 assert_eq!(text, "a❤️"); 187 assert_eq!(text, "a❤️");
186 188
187 text = String::from("a\nb"); 189 text = String::from("a\nb");
188 apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); 190 run(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
189 assert_eq!(text, "adcb"); 191 assert_eq!(text, "adcb");
190 192
191 text = String::from("a\nb"); 193 text = String::from("a\nb");
192 apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); 194 run(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
193 assert_eq!(text, "ațc\ncb"); 195 assert_eq!(text, "ațc\ncb");
194 } 196 }
195} 197}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 9fd16ef3b..0ace4cb45 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -1,13 +1,14 @@
1//! The main loop of `rust-analyzer` responsible for dispatching LSP 1//! The main loop of `rust-analyzer` responsible for dispatching LSP
2//! requests/replies and notifications back to the client. 2//! requests/replies and notifications back to the client.
3use std::{ 3use std::{
4 borrow::Cow,
4 env, fmt, panic, 5 env, fmt, panic,
5 time::{Duration, Instant}, 6 time::{Duration, Instant},
6}; 7};
7 8
8use crossbeam_channel::{never, select, Receiver}; 9use crossbeam_channel::{select, Receiver};
9use lsp_server::{Connection, Notification, Request, Response}; 10use lsp_server::{Connection, Notification, Request, Response};
10use lsp_types::notification::Notification as _; 11use lsp_types::{notification::Notification as _, DidChangeTextDocumentParams};
11use ra_db::VfsPath; 12use ra_db::VfsPath;
12use ra_ide::{Canceled, FileId}; 13use ra_ide::{Canceled, FileId};
13use ra_prof::profile; 14use ra_prof::profile;
@@ -15,12 +16,15 @@ use ra_prof::profile;
15use crate::{ 16use crate::{
16 config::Config, 17 config::Config,
17 dispatch::{NotificationDispatcher, RequestDispatcher}, 18 dispatch::{NotificationDispatcher, RequestDispatcher},
19 document::DocumentData,
18 from_proto, 20 from_proto,
19 global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, 21 global_state::{file_id_to_url, url_to_file_id, GlobalState, Status},
20 handlers, lsp_ext, 22 handlers, lsp_ext,
21 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, 23 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
22 Result, 24 Result,
23}; 25};
26use ra_project_model::ProjectWorkspace;
27use vfs::ChangeKind;
24 28
25pub fn main_loop(config: Config, connection: Connection) -> Result<()> { 29pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
26 log::info!("initial config: {:#?}", config); 30 log::info!("initial config: {:#?}", config);
@@ -58,6 +62,7 @@ enum Event {
58pub(crate) enum Task { 62pub(crate) enum Task {
59 Response(Response), 63 Response(Response),
60 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), 64 Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
65 Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
61 Unit, 66 Unit,
62} 67}
63 68
@@ -94,24 +99,49 @@ impl fmt::Debug for Event {
94} 99}
95 100
96impl GlobalState { 101impl GlobalState {
97 fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> { 102 fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
98 select! { 103 if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found
99 recv(inbox) -> msg => 104 {
100 msg.ok().map(Event::Lsp), 105 self.show_message(
101 106 lsp_types::MessageType::Error,
102 recv(self.task_pool.receiver) -> task => 107 "rust-analyzer failed to discover workspace".to_string(),
103 Some(Event::Task(task.unwrap())), 108 );
109 };
104 110
105 recv(self.loader.receiver) -> task => 111 let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions {
106 Some(Event::Vfs(task.unwrap())), 112 include_text: Some(false),
113 text_document_registration_options: lsp_types::TextDocumentRegistrationOptions {
114 document_selector: Some(vec![
115 lsp_types::DocumentFilter {
116 language: None,
117 scheme: None,
118 pattern: Some("**/*.rs".into()),
119 },
120 lsp_types::DocumentFilter {
121 language: None,
122 scheme: None,
123 pattern: Some("**/Cargo.toml".into()),
124 },
125 lsp_types::DocumentFilter {
126 language: None,
127 scheme: None,
128 pattern: Some("**/Cargo.lock".into()),
129 },
130 ]),
131 },
132 };
107 133
108 recv(self.flycheck.as_ref().map_or(&never(), |it| &it.receiver)) -> task => 134 let registration = lsp_types::Registration {
109 Some(Event::Flycheck(task.unwrap())), 135 id: "textDocument/didSave".to_string(),
110 } 136 method: "textDocument/didSave".to_string(),
111 } 137 register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
138 };
139 self.send_request::<lsp_types::request::RegisterCapability>(
140 lsp_types::RegistrationParams { registrations: vec![registration] },
141 |_, _| (),
142 );
112 143
113 fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { 144 self.fetch_workspaces();
114 self.reload();
115 145
116 while let Some(event) = self.next_event(&inbox) { 146 while let Some(event) = self.next_event(&inbox) {
117 if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { 147 if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
@@ -125,6 +155,22 @@ impl GlobalState {
125 Err("client exited without proper shutdown sequence")? 155 Err("client exited without proper shutdown sequence")?
126 } 156 }
127 157
158 fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> {
159 select! {
160 recv(inbox) -> msg =>
161 msg.ok().map(Event::Lsp),
162
163 recv(self.task_pool.receiver) -> task =>
164 Some(Event::Task(task.unwrap())),
165
166 recv(self.loader.receiver) -> task =>
167 Some(Event::Vfs(task.unwrap())),
168
169 recv(self.flycheck_receiver) -> task =>
170 Some(Event::Flycheck(task.unwrap())),
171 }
172 }
173
128 fn handle_event(&mut self, event: Event) -> Result<()> { 174 fn handle_event(&mut self, event: Event) -> Result<()> {
129 let loop_start = Instant::now(); 175 let loop_start = Instant::now();
130 // NOTE: don't count blocking select! call as a loop-turn time 176 // NOTE: don't count blocking select! call as a loop-turn time
@@ -136,7 +182,7 @@ impl GlobalState {
136 log::info!("queued count = {}", queue_count); 182 log::info!("queued count = {}", queue_count);
137 } 183 }
138 184
139 let mut became_ready = false; 185 let prev_status = self.status;
140 match event { 186 match event {
141 Event::Lsp(msg) => match msg { 187 Event::Lsp(msg) => match msg {
142 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, 188 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -153,39 +199,54 @@ impl GlobalState {
153 self.diagnostics.set_native_diagnostics(file_id, diagnostics) 199 self.diagnostics.set_native_diagnostics(file_id, diagnostics)
154 } 200 }
155 } 201 }
202 Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
156 Task::Unit => (), 203 Task::Unit => (),
157 } 204 }
158 self.analysis_host.maybe_collect_garbage(); 205 self.analysis_host.maybe_collect_garbage();
159 } 206 }
160 Event::Vfs(task) => match task { 207 Event::Vfs(mut task) => {
161 vfs::loader::Message::Loaded { files } => { 208 let _p = profile("GlobalState::handle_event/vfs");
162 let vfs = &mut self.vfs.write().0; 209 loop {
163 for (path, contents) in files { 210 match task {
164 let path = VfsPath::from(path); 211 vfs::loader::Message::Loaded { files } => {
165 if !self.mem_docs.contains(&path) { 212 let vfs = &mut self.vfs.write().0;
166 vfs.set_file_contents(path, contents) 213 for (path, contents) in files {
214 let path = VfsPath::from(path);
215 if !self.mem_docs.contains_key(&path) {
216 vfs.set_file_contents(path, contents)
217 }
218 }
219 }
220 vfs::loader::Message::Progress { n_total, n_done } => {
221 if n_total == 0 {
222 self.transition(Status::Invalid);
223 } else {
224 let state = if n_done == 0 {
225 self.transition(Status::Loading);
226 Progress::Begin
227 } else if n_done < n_total {
228 Progress::Report
229 } else {
230 assert_eq!(n_done, n_total);
231 self.transition(Status::Ready);
232 Progress::End
233 };
234 self.report_progress(
235 "roots scanned",
236 state,
237 Some(format!("{}/{}", n_done, n_total)),
238 Some(Progress::percentage(n_done, n_total)),
239 )
240 }
167 } 241 }
168 } 242 }
243 // Coalesce many VFS event into a single loop turn
244 task = match self.loader.receiver.try_recv() {
245 Ok(task) => task,
246 Err(_) => break,
247 }
169 } 248 }
170 vfs::loader::Message::Progress { n_total, n_done } => { 249 }
171 let state = if n_done == 0 {
172 Progress::Begin
173 } else if n_done < n_total {
174 Progress::Report
175 } else {
176 assert_eq!(n_done, n_total);
177 self.status = Status::Ready;
178 became_ready = true;
179 Progress::End
180 };
181 self.report_progress(
182 "roots scanned",
183 state,
184 Some(format!("{}/{}", n_done, n_total)),
185 Some(Progress::percentage(n_done, n_total)),
186 )
187 }
188 },
189 Event::Flycheck(task) => match task { 250 Event::Flycheck(task) => match task {
190 flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { 251 flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => {
191 let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( 252 let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
@@ -194,7 +255,7 @@ impl GlobalState {
194 &workspace_root, 255 &workspace_root,
195 ); 256 );
196 for diag in diagnostics { 257 for diag in diagnostics {
197 match url_to_file_id(&self.vfs.read().0, &diag.location.uri) { 258 match url_to_file_id(&self.vfs.read().0, &diag.url) {
198 Ok(file_id) => self.diagnostics.add_check_diagnostic( 259 Ok(file_id) => self.diagnostics.add_check_diagnostic(
199 file_id, 260 file_id,
200 diag.diagnostic, 261 diag.diagnostic,
@@ -231,16 +292,16 @@ impl GlobalState {
231 } 292 }
232 293
233 let state_changed = self.process_changes(); 294 let state_changed = self.process_changes();
234 if became_ready { 295 if prev_status == Status::Loading && self.status == Status::Ready {
235 if let Some(flycheck) = &self.flycheck { 296 if let Some(flycheck) = &self.flycheck {
236 flycheck.handle.update(); 297 flycheck.update();
237 } 298 }
238 } 299 }
239 300
240 if self.status == Status::Ready && (state_changed || became_ready) { 301 if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) {
241 let subscriptions = self 302 let subscriptions = self
242 .mem_docs 303 .mem_docs
243 .iter() 304 .keys()
244 .map(|path| self.vfs.read().0.file_id(&path).unwrap()) 305 .map(|path| self.vfs.read().0.file_id(&path).unwrap())
245 .collect::<Vec<_>>(); 306 .collect::<Vec<_>>();
246 307
@@ -251,8 +312,12 @@ impl GlobalState {
251 for file_id in diagnostic_changes { 312 for file_id in diagnostic_changes {
252 let url = file_id_to_url(&self.vfs.read().0, file_id); 313 let url = file_id_to_url(&self.vfs.read().0, file_id);
253 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); 314 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect();
315 let version = from_proto::vfs_path(&url)
316 .map(|path| self.mem_docs.get(&path)?.version)
317 .unwrap_or_default();
318
254 self.send_notification::<lsp_types::notification::PublishDiagnostics>( 319 self.send_notification::<lsp_types::notification::PublishDiagnostics>(
255 lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }, 320 lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version },
256 ); 321 );
257 } 322 }
258 } 323 }
@@ -274,7 +339,7 @@ impl GlobalState {
274 self.register_request(&req, request_received); 339 self.register_request(&req, request_received);
275 340
276 RequestDispatcher { req: Some(req), global_state: self } 341 RequestDispatcher { req: Some(req), global_state: self }
277 .on_sync::<lsp_ext::CollectGarbage>(|s, ()| Ok(s.analysis_host.collect_garbage()))? 342 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))?
278 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 343 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
279 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 344 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
280 .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))? 345 .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))?
@@ -284,6 +349,7 @@ impl GlobalState {
284 .on_sync::<lsp_ext::MatchingBrace>(|s, p| { 349 .on_sync::<lsp_ext::MatchingBrace>(|s, p| {
285 handlers::handle_matching_brace(s.snapshot(), p) 350 handlers::handle_matching_brace(s.snapshot(), p)
286 })? 351 })?
352 .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
287 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)? 353 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)?
288 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)? 354 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)?
289 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)? 355 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)?
@@ -340,7 +406,11 @@ impl GlobalState {
340 })? 406 })?
341 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { 407 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| {
342 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 408 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
343 if !this.mem_docs.insert(path.clone()) { 409 if this
410 .mem_docs
411 .insert(path.clone(), DocumentData::new(params.text_document.version))
412 .is_some()
413 {
344 log::error!("duplicate DidOpenTextDocument: {}", path) 414 log::error!("duplicate DidOpenTextDocument: {}", path)
345 } 415 }
346 this.vfs 416 this.vfs
@@ -352,36 +422,56 @@ impl GlobalState {
352 })? 422 })?
353 .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { 423 .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| {
354 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 424 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
355 assert!(this.mem_docs.contains(&path)); 425 let DidChangeTextDocumentParams { text_document, content_changes } = params;
356 let vfs = &mut this.vfs.write().0; 426 let vfs = &mut this.vfs.write().0;
427 let world = this.snapshot();
357 let file_id = vfs.file_id(&path).unwrap(); 428 let file_id = vfs.file_id(&path).unwrap();
429
430 // let file_id = vfs.file_id(&path).unwrap();
358 let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); 431 let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap();
359 apply_document_changes(&mut text, params.content_changes); 432 let line_index = world.analysis.file_line_index(file_id)?;
360 vfs.set_file_contents(path, Some(text.into_bytes())) 433 apply_document_changes(&mut text, content_changes, Cow::Borrowed(&line_index));
434
435 // The version passed in DidChangeTextDocument is the version after all edits are applied
436 // so we should apply it before the vfs is notified.
437 let doc = this.mem_docs.get_mut(&path).unwrap();
438 doc.version = text_document.version;
439
440 vfs.set_file_contents(path.clone(), Some(text.into_bytes()));
361 } 441 }
362 Ok(()) 442 Ok(())
363 })? 443 })?
364 .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| { 444 .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| {
445 let mut version = None;
365 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 446 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
366 if !this.mem_docs.remove(&path) { 447 match this.mem_docs.remove(&path) {
367 log::error!("orphan DidCloseTextDocument: {}", path) 448 Some(doc) => version = doc.version,
449 None => log::error!("orphan DidCloseTextDocument: {}", path),
368 } 450 }
451
369 if let Some(path) = path.as_path() { 452 if let Some(path) = path.as_path() {
370 this.loader.handle.invalidate(path.to_path_buf()); 453 this.loader.handle.invalidate(path.to_path_buf());
371 } 454 }
372 } 455 }
456
457 // Clear the diagnostics for the previously known version of the file.
458 // This prevents stale "cargo check" diagnostics if the file is
459 // closed, "cargo check" is run and then the file is reopened.
373 this.send_notification::<lsp_types::notification::PublishDiagnostics>( 460 this.send_notification::<lsp_types::notification::PublishDiagnostics>(
374 lsp_types::PublishDiagnosticsParams { 461 lsp_types::PublishDiagnosticsParams {
375 uri: params.text_document.uri, 462 uri: params.text_document.uri,
376 diagnostics: Vec::new(), 463 diagnostics: Vec::new(),
377 version: None, 464 version,
378 }, 465 },
379 ); 466 );
380 Ok(()) 467 Ok(())
381 })? 468 })?
382 .on::<lsp_types::notification::DidSaveTextDocument>(|this, _params| { 469 .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
383 if let Some(flycheck) = &this.flycheck { 470 if let Some(flycheck) = &this.flycheck {
384 flycheck.handle.update(); 471 flycheck.update();
472 }
473 if let Ok(abs_path) = from_proto::abs_path(&params.text_document.uri) {
474 this.maybe_refresh(&[(abs_path, ChangeKind::Modify)]);
385 } 475 }
386 Ok(()) 476 Ok(())
387 })? 477 })?
@@ -403,10 +493,12 @@ impl GlobalState {
403 (Some(err), _) => { 493 (Some(err), _) => {
404 log::error!("failed to fetch the server settings: {:?}", err) 494 log::error!("failed to fetch the server settings: {:?}", err)
405 } 495 }
406 (None, Some(configs)) => { 496 (None, Some(mut configs)) => {
407 if let Some(new_config) = configs.get(0) { 497 if let Some(json) = configs.get_mut(0) {
498 // Note that json can be null according to the spec if the client can't
499 // provide a configuration. This is handled in Config::update below.
408 let mut config = this.config.clone(); 500 let mut config = this.config.clone();
409 config.update(&new_config); 501 config.update(json.take());
410 this.update_configuration(config); 502 this.update_configuration(config);
411 } 503 }
412 } 504 }
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index ec71f8b29..1907f2f13 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -1,81 +1,163 @@
1//! Project loading & configuration updates 1//! Project loading & configuration updates
2use std::{mem, sync::Arc}; 2use std::{mem, sync::Arc};
3 3
4use crossbeam_channel::unbounded;
5use flycheck::FlycheckHandle; 4use flycheck::FlycheckHandle;
6use ra_db::{CrateGraph, SourceRoot, VfsPath}; 5use ra_db::{CrateGraph, SourceRoot, VfsPath};
7use ra_ide::AnalysisChange; 6use ra_ide::AnalysisChange;
8use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace}; 7use ra_prof::profile;
9use vfs::{file_set::FileSetConfig, AbsPath}; 8use ra_project_model::{ProcMacroClient, ProjectWorkspace};
9use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
10 10
11use crate::{ 11use crate::{
12 config::{Config, FilesWatcher, LinkedProject}, 12 config::{Config, FilesWatcher, LinkedProject},
13 global_state::{GlobalState, Handle}, 13 global_state::{GlobalState, Status},
14 lsp_ext,
15 main_loop::Task,
14}; 16};
15 17
16impl GlobalState { 18impl GlobalState {
17 pub(crate) fn update_configuration(&mut self, config: Config) { 19 pub(crate) fn update_configuration(&mut self, config: Config) {
20 let _p = profile("GlobalState::update_configuration");
18 let old_config = mem::replace(&mut self.config, config); 21 let old_config = mem::replace(&mut self.config, config);
19 if self.config.lru_capacity != old_config.lru_capacity { 22 if self.config.lru_capacity != old_config.lru_capacity {
20 self.analysis_host.update_lru_capacity(old_config.lru_capacity); 23 self.analysis_host.update_lru_capacity(old_config.lru_capacity);
21 } 24 }
22 if self.config.flycheck != old_config.flycheck { 25 if self.config.linked_projects != old_config.linked_projects {
26 self.fetch_workspaces()
27 } else if self.config.flycheck != old_config.flycheck {
23 self.reload_flycheck(); 28 self.reload_flycheck();
24 } 29 }
25 } 30 }
26 pub(crate) fn reload(&mut self) { 31 pub(crate) fn maybe_refresh(&mut self, changes: &[(AbsPathBuf, ChangeKind)]) {
27 let workspaces = { 32 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
28 if self.config.linked_projects.is_empty() 33 return;
29 && self.config.notifications.cargo_toml_not_found 34 }
30 { 35 match self.status {
31 self.show_message( 36 Status::Loading | Status::NeedsReload => return,
32 lsp_types::MessageType::Error, 37 Status::Ready | Status::Invalid => (),
33 "rust-analyzer failed to discover workspace".to_string(), 38 }
34 ); 39 if self.config.cargo_autoreload {
40 self.fetch_workspaces();
41 } else {
42 self.transition(Status::NeedsReload);
43 }
44
45 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
46 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
47 const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
48
49 if path.ends_with("Cargo.toml") || path.ends_with("Cargo.lock") {
50 return true;
51 }
52 if change_kind == ChangeKind::Modify {
53 return false;
54 }
55 if path.extension().unwrap_or_default() != "rs" {
56 return false;
57 }
58 if IMPLICIT_TARGET_FILES.iter().any(|it| path.ends_with(it)) {
59 return true;
60 }
61 let parent = match path.parent() {
62 Some(it) => it,
63 None => return false,
64 };
65 if IMPLICIT_TARGET_DIRS.iter().any(|it| parent.ends_with(it)) {
66 return true;
67 }
68 if path.ends_with("main.rs") {
69 let grand_parent = match parent.parent() {
70 Some(it) => it,
71 None => return false,
72 };
73 if IMPLICIT_TARGET_DIRS.iter().any(|it| grand_parent.ends_with(it)) {
74 return true;
75 }
76 }
77 false
78 }
79 }
80 pub(crate) fn transition(&mut self, new_status: Status) {
81 self.status = new_status;
82 if self.config.client_caps.status_notification {
83 let lsp_status = match new_status {
84 Status::Loading => lsp_ext::Status::Loading,
85 Status::Ready => lsp_ext::Status::Ready,
86 Status::Invalid => lsp_ext::Status::Invalid,
87 Status::NeedsReload => lsp_ext::Status::NeedsReload,
35 }; 88 };
89 self.send_notification::<lsp_ext::StatusNotification>(lsp_status);
90 }
91 }
92 pub(crate) fn fetch_workspaces(&mut self) {
93 self.task_pool.handle.spawn({
94 let linked_projects = self.config.linked_projects.clone();
95 let cargo_config = self.config.cargo.clone();
96 let with_sysroot = self.config.with_sysroot.clone();
97 move || {
98 let workspaces = linked_projects
99 .iter()
100 .map(|project| match project {
101 LinkedProject::ProjectManifest(manifest) => {
102 ra_project_model::ProjectWorkspace::load(
103 manifest.clone(),
104 &cargo_config,
105 with_sysroot,
106 )
107 }
108 LinkedProject::InlineJsonProject(it) => {
109 Ok(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
110 }
111 })
112 .collect::<Vec<_>>();
113 Task::Workspaces(workspaces)
114 }
115 });
116 }
117 pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
118 let _p = profile("GlobalState::switch_workspaces");
119 log::info!("reloading projects: {:?}", self.config.linked_projects);
36 120
37 self.config 121 let mut has_errors = false;
38 .linked_projects 122 let workspaces = workspaces
39 .iter() 123 .into_iter()
40 .map(|project| match project { 124 .filter_map(|res| {
41 LinkedProject::ProjectManifest(manifest) => { 125 res.map_err(|err| {
42 ra_project_model::ProjectWorkspace::load( 126 has_errors = true;
43 manifest.clone(), 127 log::error!("failed to load workspace: {:#}", err);
44 &self.config.cargo, 128 if self.workspaces.is_empty() {
45 self.config.with_sysroot,
46 )
47 }
48 LinkedProject::InlineJsonProject(it) => {
49 Ok(ra_project_model::ProjectWorkspace::Json { project: it.clone() })
50 }
51 })
52 .collect::<Vec<_>>()
53 .into_iter()
54 .filter_map(|res| {
55 res.map_err(|err| {
56 log::error!("failed to load workspace: {:#}", err);
57 self.show_message( 129 self.show_message(
58 lsp_types::MessageType::Error, 130 lsp_types::MessageType::Error,
59 format!("rust-analyzer failed to load workspace: {:#}", err), 131 format!("rust-analyzer failed to load workspace: {:#}", err),
60 ); 132 );
61 }) 133 }
62 .ok()
63 }) 134 })
64 .collect::<Vec<_>>() 135 .ok()
65 }; 136 })
137 .collect::<Vec<_>>();
138
139 if &*self.workspaces == &workspaces {
140 return;
141 }
142
143 if !self.workspaces.is_empty() && has_errors {
144 return;
145 }
66 146
67 if let FilesWatcher::Client = self.config.files.watcher { 147 if let FilesWatcher::Client = self.config.files.watcher {
68 let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { 148 let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions {
69 watchers: workspaces 149 watchers: workspaces
70 .iter() 150 .iter()
71 .flat_map(ProjectWorkspace::to_roots) 151 .flat_map(ProjectWorkspace::to_roots)
72 .filter(PackageRoot::is_member) 152 .filter(|it| it.is_member)
73 .map(|root| format!("{}/**/*.rs", root.path().display())) 153 .flat_map(|root| {
154 root.include.into_iter().map(|it| format!("{}/**/*.rs", it.display()))
155 })
74 .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) 156 .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None })
75 .collect(), 157 .collect(),
76 }; 158 };
77 let registration = lsp_types::Registration { 159 let registration = lsp_types::Registration {
78 id: "file-watcher".to_string(), 160 id: "workspace/didChangeWatchedFiles".to_string(),
79 method: "workspace/didChangeWatchedFiles".to_string(), 161 method: "workspace/didChangeWatchedFiles".to_string(),
80 register_options: Some(serde_json::to_value(registration_options).unwrap()), 162 register_options: Some(serde_json::to_value(registration_options).unwrap()),
81 }; 163 };
@@ -103,6 +185,7 @@ impl GlobalState {
103 } 185 }
104 }, 186 },
105 }; 187 };
188
106 let watch = match self.config.files.watcher { 189 let watch = match self.config.files.watcher {
107 FilesWatcher::Client => vec![], 190 FilesWatcher::Client => vec![],
108 FilesWatcher::Notify => project_folders.watch, 191 FilesWatcher::Notify => project_folders.watch,
@@ -149,21 +232,20 @@ impl GlobalState {
149 } 232 }
150 }; 233 };
151 234
152 // FIXME: Figure out the multi-workspace situation 235 let sender = self.flycheck_sender.clone();
153 self.flycheck = self.workspaces.iter().find_map(move |w| match w { 236 let sender = Box::new(move |msg| sender.send(msg).unwrap());
154 ProjectWorkspace::Cargo { cargo, .. } => { 237 self.flycheck = self
155 let (sender, receiver) = unbounded(); 238 .workspaces
156 let sender = Box::new(move |msg| sender.send(msg).unwrap()); 239 .iter()
240 // FIXME: Figure out the multi-workspace situation
241 .find_map(|w| match w {
242 ProjectWorkspace::Cargo { cargo, sysroot: _ } => Some(cargo),
243 ProjectWorkspace::Json { .. } => None,
244 })
245 .map(move |cargo| {
157 let cargo_project_root = cargo.workspace_root().to_path_buf(); 246 let cargo_project_root = cargo.workspace_root().to_path_buf();
158 let handle = 247 FlycheckHandle::spawn(sender, config, cargo_project_root.into())
159 FlycheckHandle::spawn(sender, config.clone(), cargo_project_root.into()); 248 })
160 Some(Handle { handle, receiver })
161 }
162 ProjectWorkspace::Json { .. } => {
163 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
164 None
165 }
166 })
167 } 249 }
168} 250}
169 251
@@ -181,31 +263,23 @@ impl ProjectFolders {
181 let mut local_filesets = vec![]; 263 let mut local_filesets = vec![];
182 264
183 for root in workspaces.iter().flat_map(|it| it.to_roots()) { 265 for root in workspaces.iter().flat_map(|it| it.to_roots()) {
184 let path = root.path().to_owned(); 266 let file_set_roots: Vec<VfsPath> =
267 root.include.iter().cloned().map(VfsPath::from).collect();
185 268
186 let mut file_set_roots: Vec<VfsPath> = vec![]; 269 let entry = {
187 270 let mut dirs = vfs::loader::Directories::default();
188 let entry = if root.is_member() { 271 dirs.extensions.push("rs".into());
189 vfs::loader::Entry::local_cargo_package(path.to_path_buf()) 272 dirs.include.extend(root.include);
190 } else { 273 dirs.exclude.extend(root.exclude);
191 vfs::loader::Entry::cargo_package_dependency(path.to_path_buf()) 274 vfs::loader::Entry::Directories(dirs)
192 }; 275 };
193 res.load.push(entry);
194 if root.is_member() {
195 res.watch.push(res.load.len() - 1);
196 }
197 276
198 if let Some(out_dir) = root.out_dir() { 277 if root.is_member {
199 let out_dir = out_dir.to_path_buf(); 278 res.watch.push(res.load.len());
200 res.load.push(vfs::loader::Entry::rs_files_recursively(out_dir.clone()));
201 if root.is_member() {
202 res.watch.push(res.load.len() - 1);
203 }
204 file_set_roots.push(out_dir.into());
205 } 279 }
206 file_set_roots.push(path.to_path_buf().into()); 280 res.load.push(entry);
207 281
208 if root.is_member() { 282 if root.is_member {
209 local_filesets.push(fsc.len()); 283 local_filesets.push(fsc.len());
210 } 284 }
211 fsc.add_file_set(file_set_roots) 285 fsc.add_file_set(file_set_roots)
@@ -226,6 +300,7 @@ pub(crate) struct SourceRootConfig {
226 300
227impl SourceRootConfig { 301impl SourceRootConfig {
228 pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> { 302 pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec<SourceRoot> {
303 let _p = profile("SourceRootConfig::partition");
229 self.fsc 304 self.fsc
230 .partition(vfs) 305 .partition(vfs)
231 .into_iter() 306 .into_iter()
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 10fe40cb5..576bd8adc 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -43,6 +43,7 @@ define_semantic_token_types![
43 (FORMAT_SPECIFIER, "formatSpecifier"), 43 (FORMAT_SPECIFIER, "formatSpecifier"),
44 (GENERIC, "generic"), 44 (GENERIC, "generic"),
45 (LIFETIME, "lifetime"), 45 (LIFETIME, "lifetime"),
46 (PUNCTUATION, "punctuation"),
46 (SELF_KEYWORD, "selfKeyword"), 47 (SELF_KEYWORD, "selfKeyword"),
47 (TYPE_ALIAS, "typeAlias"), 48 (TYPE_ALIAS, "typeAlias"),
48 (UNION, "union"), 49 (UNION, "union"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index f6cb8e4bb..fadcc5853 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -4,10 +4,10 @@ use std::path::{self, Path};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::{FileId, FileRange}; 5use ra_db::{FileId, FileRange};
6use ra_ide::{ 6use ra_ide::{
7 Assist, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, FoldKind, 7 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
8 FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, Indel, 8 FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
9 InlayHint, InlayKind, InsertTextFormat, LineIndex, NavigationTarget, ReferenceAccess, 9 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
10 ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, 10 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
11}; 11};
12use ra_syntax::{SyntaxKind, TextRange, TextSize}; 12use ra_syntax::{SyntaxKind, TextRange, TextSize};
13 13
@@ -31,18 +31,18 @@ pub(crate) fn range(line_index: &LineIndex, range: TextRange) -> lsp_types::Rang
31 31
32pub(crate) fn symbol_kind(syntax_kind: SyntaxKind) -> lsp_types::SymbolKind { 32pub(crate) fn symbol_kind(syntax_kind: SyntaxKind) -> lsp_types::SymbolKind {
33 match syntax_kind { 33 match syntax_kind {
34 SyntaxKind::FN_DEF => lsp_types::SymbolKind::Function, 34 SyntaxKind::FN => lsp_types::SymbolKind::Function,
35 SyntaxKind::STRUCT_DEF => lsp_types::SymbolKind::Struct, 35 SyntaxKind::STRUCT => lsp_types::SymbolKind::Struct,
36 SyntaxKind::ENUM_DEF => lsp_types::SymbolKind::Enum, 36 SyntaxKind::ENUM => lsp_types::SymbolKind::Enum,
37 SyntaxKind::ENUM_VARIANT => lsp_types::SymbolKind::EnumMember, 37 SyntaxKind::VARIANT => lsp_types::SymbolKind::EnumMember,
38 SyntaxKind::TRAIT_DEF => lsp_types::SymbolKind::Interface, 38 SyntaxKind::TRAIT => lsp_types::SymbolKind::Interface,
39 SyntaxKind::MACRO_CALL => lsp_types::SymbolKind::Function, 39 SyntaxKind::MACRO_CALL => lsp_types::SymbolKind::Function,
40 SyntaxKind::MODULE => lsp_types::SymbolKind::Module, 40 SyntaxKind::MODULE => lsp_types::SymbolKind::Module,
41 SyntaxKind::TYPE_ALIAS_DEF => lsp_types::SymbolKind::TypeParameter, 41 SyntaxKind::TYPE_ALIAS => lsp_types::SymbolKind::TypeParameter,
42 SyntaxKind::RECORD_FIELD_DEF => lsp_types::SymbolKind::Field, 42 SyntaxKind::RECORD_FIELD => lsp_types::SymbolKind::Field,
43 SyntaxKind::STATIC_DEF => lsp_types::SymbolKind::Constant, 43 SyntaxKind::STATIC => lsp_types::SymbolKind::Constant,
44 SyntaxKind::CONST_DEF => lsp_types::SymbolKind::Constant, 44 SyntaxKind::CONST => lsp_types::SymbolKind::Constant,
45 SyntaxKind::IMPL_DEF => lsp_types::SymbolKind::Object, 45 SyntaxKind::IMPL => lsp_types::SymbolKind::Object,
46 _ => lsp_types::SymbolKind::Variable, 46 _ => lsp_types::SymbolKind::Variable,
47 } 47 }
48} 48}
@@ -100,6 +100,7 @@ pub(crate) fn completion_item_kind(
100 CompletionItemKind::TypeParam => lsp_types::CompletionItemKind::TypeParameter, 100 CompletionItemKind::TypeParam => lsp_types::CompletionItemKind::TypeParameter,
101 CompletionItemKind::Macro => lsp_types::CompletionItemKind::Method, 101 CompletionItemKind::Macro => lsp_types::CompletionItemKind::Method,
102 CompletionItemKind::Attribute => lsp_types::CompletionItemKind::EnumMember, 102 CompletionItemKind::Attribute => lsp_types::CompletionItemKind::EnumMember,
103 CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::Reference,
103 } 104 }
104} 105}
105 106
@@ -218,29 +219,76 @@ pub(crate) fn completion_item(
218 res 219 res
219} 220}
220 221
221pub(crate) fn signature_information( 222pub(crate) fn signature_help(
222 signature: FunctionSignature, 223 call_info: CallInfo,
223 concise: bool, 224 concise: bool,
224) -> lsp_types::SignatureInformation { 225 label_offsets: bool,
225 let (label, documentation, params) = if concise { 226) -> lsp_types::SignatureHelp {
226 let mut params = signature.parameters; 227 let (label, parameters) = match (concise, label_offsets) {
227 if signature.has_self_param { 228 (_, false) => {
228 params.remove(0); 229 let params = call_info
230 .parameter_labels()
231 .map(|label| lsp_types::ParameterInformation {
232 label: lsp_types::ParameterLabel::Simple(label.to_string()),
233 documentation: None,
234 })
235 .collect::<Vec<_>>();
236 let label =
237 if concise { call_info.parameter_labels().join(", ") } else { call_info.signature };
238 (label, params)
239 }
240 (false, true) => {
241 let params = call_info
242 .parameter_ranges()
243 .iter()
244 .map(|it| [u32::from(it.start()).into(), u32::from(it.end()).into()])
245 .map(|label_offsets| lsp_types::ParameterInformation {
246 label: lsp_types::ParameterLabel::LabelOffsets(label_offsets),
247 documentation: None,
248 })
249 .collect::<Vec<_>>();
250 (call_info.signature, params)
251 }
252 (true, true) => {
253 let mut params = Vec::new();
254 let mut label = String::new();
255 let mut first = true;
256 for param in call_info.parameter_labels() {
257 if !first {
258 label.push_str(", ");
259 }
260 first = false;
261 let start = label.len() as u64;
262 label.push_str(param);
263 let end = label.len() as u64;
264 params.push(lsp_types::ParameterInformation {
265 label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
266 documentation: None,
267 });
268 }
269
270 (label, params)
229 } 271 }
230 (params.join(", "), None, params)
231 } else {
232 (signature.to_string(), signature.doc.map(documentation), signature.parameters)
233 }; 272 };
234 273
235 let parameters: Vec<lsp_types::ParameterInformation> = params 274 let documentation = if concise {
236 .into_iter() 275 None
237 .map(|param| lsp_types::ParameterInformation { 276 } else {
238 label: lsp_types::ParameterLabel::Simple(param), 277 call_info.doc.map(|doc| {
239 documentation: None, 278 lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent {
279 kind: lsp_types::MarkupKind::Markdown,
280 value: doc,
281 })
240 }) 282 })
241 .collect(); 283 };
242 284
243 lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) } 285 let signature =
286 lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) };
287 lsp_types::SignatureHelp {
288 signatures: vec![signature],
289 active_signature: None,
290 active_parameter: call_info.active_parameter.map(|it| it as i64),
291 }
244} 292}
245 293
246pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { 294pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint {
@@ -308,6 +356,7 @@ fn semantic_token_type_and_modifiers(
308 } 356 }
309 HighlightTag::EnumVariant => semantic_tokens::ENUM_MEMBER, 357 HighlightTag::EnumVariant => semantic_tokens::ENUM_MEMBER,
310 HighlightTag::Macro => lsp_types::SemanticTokenType::MACRO, 358 HighlightTag::Macro => lsp_types::SemanticTokenType::MACRO,
359 HighlightTag::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
311 HighlightTag::Local => lsp_types::SemanticTokenType::VARIABLE, 360 HighlightTag::Local => lsp_types::SemanticTokenType::VARIABLE,
312 HighlightTag::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, 361 HighlightTag::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
313 HighlightTag::Lifetime => semantic_tokens::LIFETIME, 362 HighlightTag::Lifetime => semantic_tokens::LIFETIME,
@@ -325,6 +374,7 @@ fn semantic_token_type_and_modifiers(
325 HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 374 HighlightTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
326 HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 375 HighlightTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
327 HighlightTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, 376 HighlightTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
377 HighlightTag::Punctuation => semantic_tokens::PUNCTUATION,
328 }; 378 };
329 379
330 for modifier in highlight.modifiers.iter() { 380 for modifier in highlight.modifiers.iter() {
@@ -352,7 +402,7 @@ pub(crate) fn folding_range(
352 let kind = match fold.kind { 402 let kind = match fold.kind {
353 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 403 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
354 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 404 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
355 FoldKind::Mods | FoldKind::Block => None, 405 FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None,
356 }; 406 };
357 407
358 let range = range(line_index, fold.range); 408 let range = range(line_index, fold.range);
@@ -430,9 +480,10 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url {
430pub(crate) fn versioned_text_document_identifier( 480pub(crate) fn versioned_text_document_identifier(
431 snap: &GlobalStateSnapshot, 481 snap: &GlobalStateSnapshot,
432 file_id: FileId, 482 file_id: FileId,
433 version: Option<i64>,
434) -> lsp_types::VersionedTextDocumentIdentifier { 483) -> lsp_types::VersionedTextDocumentIdentifier {
435 lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id), version } 484 let url = url(snap, file_id);
485 let version = snap.url_file_version(&url);
486 lsp_types::VersionedTextDocumentIdentifier { uri: url, version }
436} 487}
437 488
438pub(crate) fn location( 489pub(crate) fn location(
@@ -446,6 +497,18 @@ pub(crate) fn location(
446 Ok(loc) 497 Ok(loc)
447} 498}
448 499
500/// Perefer using `location_link`, if the client has the cap.
501pub(crate) fn location_from_nav(
502 snap: &GlobalStateSnapshot,
503 nav: NavigationTarget,
504) -> Result<lsp_types::Location> {
505 let url = url(snap, nav.file_id);
506 let line_index = snap.analysis.file_line_index(nav.file_id)?;
507 let range = range(&line_index, nav.full_range);
508 let loc = lsp_types::Location::new(url, range);
509 Ok(loc)
510}
511
449pub(crate) fn location_link( 512pub(crate) fn location_link(
450 snap: &GlobalStateSnapshot, 513 snap: &GlobalStateSnapshot,
451 src: Option<FileRange>, 514 src: Option<FileRange>,
@@ -473,12 +536,12 @@ fn location_info(
473 snap: &GlobalStateSnapshot, 536 snap: &GlobalStateSnapshot,
474 target: NavigationTarget, 537 target: NavigationTarget,
475) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { 538) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> {
476 let line_index = snap.analysis.file_line_index(target.file_id())?; 539 let line_index = snap.analysis.file_line_index(target.file_id)?;
477 540
478 let target_uri = url(snap, target.file_id()); 541 let target_uri = url(snap, target.file_id);
479 let target_range = range(&line_index, target.full_range()); 542 let target_range = range(&line_index, target.full_range);
480 let target_selection_range = 543 let target_selection_range =
481 target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); 544 target.focus_range.map(|it| range(&line_index, it)).unwrap_or(target_range);
482 Ok((target_uri, target_range, target_selection_range)) 545 Ok((target_uri, target_range, target_selection_range))
483} 546}
484 547
@@ -497,13 +560,7 @@ pub(crate) fn goto_definition_response(
497 let locations = targets 560 let locations = targets
498 .into_iter() 561 .into_iter()
499 .map(|nav| { 562 .map(|nav| {
500 location( 563 location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
501 snap,
502 FileRange {
503 file_id: nav.file_id(),
504 range: nav.focus_range().unwrap_or(nav.range()),
505 },
506 )
507 }) 564 })
508 .collect::<Result<Vec<_>>>()?; 565 .collect::<Result<Vec<_>>>()?;
509 Ok(locations.into()) 566 Ok(locations.into())
@@ -515,7 +572,7 @@ pub(crate) fn snippet_text_document_edit(
515 is_snippet: bool, 572 is_snippet: bool,
516 source_file_edit: SourceFileEdit, 573 source_file_edit: SourceFileEdit,
517) -> Result<lsp_ext::SnippetTextDocumentEdit> { 574) -> Result<lsp_ext::SnippetTextDocumentEdit> {
518 let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None); 575 let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id);
519 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?; 576 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?;
520 let line_endings = snap.file_line_endings(source_file_edit.file_id); 577 let line_endings = snap.file_line_endings(source_file_edit.file_id);
521 let edits = source_file_edit 578 let edits = source_file_edit
@@ -608,13 +665,24 @@ pub(crate) fn call_hierarchy_item(
608 snap: &GlobalStateSnapshot, 665 snap: &GlobalStateSnapshot,
609 target: NavigationTarget, 666 target: NavigationTarget,
610) -> Result<lsp_types::CallHierarchyItem> { 667) -> Result<lsp_types::CallHierarchyItem> {
611 let name = target.name().to_string(); 668 let name = target.name.to_string();
612 let detail = target.description().map(|it| it.to_string()); 669 let detail = target.description.clone();
613 let kind = symbol_kind(target.kind()); 670 let kind = symbol_kind(target.kind);
614 let (uri, range, selection_range) = location_info(snap, target)?; 671 let (uri, range, selection_range) = location_info(snap, target)?;
615 Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) 672 Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range })
616} 673}
617 674
675pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
676 match kind {
677 AssistKind::None | AssistKind::Generate => lsp_types::CodeActionKind::EMPTY,
678 AssistKind::QuickFix => lsp_types::CodeActionKind::QUICKFIX,
679 AssistKind::Refactor => lsp_types::CodeActionKind::REFACTOR,
680 AssistKind::RefactorExtract => lsp_types::CodeActionKind::REFACTOR_EXTRACT,
681 AssistKind::RefactorInline => lsp_types::CodeActionKind::REFACTOR_INLINE,
682 AssistKind::RefactorRewrite => lsp_types::CodeActionKind::REFACTOR_REWRITE,
683 }
684}
685
618pub(crate) fn unresolved_code_action( 686pub(crate) fn unresolved_code_action(
619 snap: &GlobalStateSnapshot, 687 snap: &GlobalStateSnapshot,
620 assist: Assist, 688 assist: Assist,
@@ -624,9 +692,9 @@ pub(crate) fn unresolved_code_action(
624 title: assist.label, 692 title: assist.label,
625 id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())), 693 id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())),
626 group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), 694 group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0),
627 kind: Some(String::new()), 695 kind: Some(code_action_kind(assist.id.1)),
628 edit: None, 696 edit: None,
629 command: None, 697 is_preferred: None,
630 }; 698 };
631 Ok(res) 699 Ok(res)
632} 700}
@@ -654,7 +722,7 @@ pub(crate) fn runnable(
654 let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); 722 let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone());
655 let target = spec.as_ref().map(|s| s.target.clone()); 723 let target = spec.as_ref().map(|s| s.target.clone());
656 let (cargo_args, executable_args) = 724 let (cargo_args, executable_args) =
657 CargoTargetSpec::runnable_args(spec, &runnable.kind, &runnable.cfg_exprs)?; 725 CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg_exprs)?;
658 let label = runnable.label(target); 726 let label = runnable.label(target);
659 let location = location_link(snap, None, runnable.nav)?; 727 let location = location_link(snap, None, runnable.nav)?;
660 728
@@ -666,38 +734,38 @@ pub(crate) fn runnable(
666 workspace_root: workspace_root.map(|it| it.into()), 734 workspace_root: workspace_root.map(|it| it.into()),
667 cargo_args, 735 cargo_args,
668 executable_args, 736 executable_args,
737 expect_test: None,
669 }, 738 },
670 }) 739 })
671} 740}
672 741
742pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent {
743 lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value: markup.into() }
744}
745
673#[cfg(test)] 746#[cfg(test)]
674mod tests { 747mod tests {
675 use test_utils::extract_ranges; 748 use ra_ide::Analysis;
676 749
677 use super::*; 750 use super::*;
678 751
679 #[test] 752 #[test]
680 fn conv_fold_line_folding_only_fixup() { 753 fn conv_fold_line_folding_only_fixup() {
681 let text = r#"<fold>mod a; 754 let text = r#"mod a;
682mod b; 755mod b;
683mod c;</fold> 756mod c;
684 757
685fn main() <fold>{ 758fn main() {
686 if cond <fold>{ 759 if cond {
687 a::do_a(); 760 a::do_a();
688 }</fold> else <fold>{ 761 } else {
689 b::do_b(); 762 b::do_b();
690 }</fold> 763 }
691}</fold>"#; 764}"#;
692 765
693 let (ranges, text) = extract_ranges(text, "fold"); 766 let (analysis, file_id) = Analysis::from_single_file(text.to_string());
694 assert_eq!(ranges.len(), 4); 767 let folds = analysis.folding_ranges(file_id).unwrap();
695 let folds = vec![ 768 assert_eq!(folds.len(), 4);
696 Fold { range: ranges[0], kind: FoldKind::Mods },
697 Fold { range: ranges[1], kind: FoldKind::Block },
698 Fold { range: ranges[2], kind: FoldKind::Block },
699 Fold { range: ranges[3], kind: FoldKind::Block },
700 ];
701 769
702 let line_index = LineIndex::new(&text); 770 let line_index = LineIndex::new(&text);
703 let converted: Vec<lsp_types::FoldingRange> = 771 let converted: Vec<lsp_types::FoldingRange> =
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_clippy_pass_by_ref.snap b/crates/rust-analyzer/test_data/clippy_pass_by_ref.txt
index d7f9ec049..d06517126 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_clippy_pass_by_ref.snap
+++ b/crates/rust-analyzer/test_data/clippy_pass_by_ref.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/compiler/mir/tagset.rs",
8 uri: "file:///test/compiler/mir/tagset.rs",
9 range: Range {
10 start: Position {
11 line: 41,
12 character: 23,
13 },
14 end: Position {
15 line: 41,
16 character: 28,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_handles_macro_location.snap b/crates/rust-analyzer/test_data/handles_macro_location.txt
index a59faf254..f5de2f07f 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_handles_macro_location.snap
+++ b/crates/rust-analyzer/test_data/handles_macro_location.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/src/main.rs",
8 uri: "file:///test/src/main.rs",
9 range: Range {
10 start: Position {
11 line: 1,
12 character: 4,
13 },
14 end: Position {
15 line: 1,
16 character: 26,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_macro_compiler_error.snap b/crates/rust-analyzer/test_data/macro_compiler_error.txt
index 3c78e7f36..f695db73c 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_macro_compiler_error.snap
+++ b/crates/rust-analyzer/test_data/macro_compiler_error.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/crates/ra_hir_def/src/data.rs",
8 uri: "file:///test/crates/ra_hir_def/src/data.rs",
9 range: Range {
10 start: Position {
11 line: 79,
12 character: 15,
13 },
14 end: Position {
15 line: 79,
16 character: 41,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_incompatible_type_for_trait.snap b/crates/rust-analyzer/test_data/rustc_incompatible_type_for_trait.txt
index 46d0c56d2..fc54440be 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_incompatible_type_for_trait.snap
+++ b/crates/rust-analyzer/test_data/rustc_incompatible_type_for_trait.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/compiler/ty/list_iter.rs",
8 uri: "file:///test/compiler/ty/list_iter.rs",
9 range: Range {
10 start: Position {
11 line: 51,
12 character: 4,
13 },
14 end: Position {
15 line: 51,
16 character: 47,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_mismatched_type.snap b/crates/rust-analyzer/test_data/rustc_mismatched_type.txt
index 4182929ba..c269af218 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_mismatched_type.snap
+++ b/crates/rust-analyzer/test_data/rustc_mismatched_type.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/runtime/compiler_support.rs",
8 uri: "file:///test/runtime/compiler_support.rs",
9 range: Range {
10 start: Position {
11 line: 47,
12 character: 64,
13 },
14 end: Position {
15 line: 47,
16 character: 69,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap b/crates/rust-analyzer/test_data/rustc_unused_variable.txt
index 9a7972ff5..74d91bc77 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable.snap
+++ b/crates/rust-analyzer/test_data/rustc_unused_variable.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/driver/subcommand/repl.rs",
8 uri: "file:///test/driver/subcommand/repl.rs",
9 range: Range {
10 start: Position {
11 line: 290,
12 character: 8,
13 },
14 end: Position {
15 line: 290,
16 character: 11,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
@@ -53,9 +37,10 @@ expression: diag
53 id: None, 37 id: None,
54 group: None, 38 group: None,
55 kind: Some( 39 kind: Some(
56 "quickfix", 40 CodeActionKind(
41 "quickfix",
42 ),
57 ), 43 ),
58 command: None,
59 edit: Some( 44 edit: Some(
60 SnippetWorkspaceEdit { 45 SnippetWorkspaceEdit {
61 changes: Some( 46 changes: Some(
@@ -80,6 +65,9 @@ expression: diag
80 document_changes: None, 65 document_changes: None,
81 }, 66 },
82 ), 67 ),
68 is_preferred: Some(
69 true,
70 ),
83 }, 71 },
84 ], 72 ],
85 }, 73 },
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap b/crates/rust-analyzer/test_data/rustc_unused_variable_as_hint.txt
index f0273315e..8a420c949 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_hint.snap
+++ b/crates/rust-analyzer/test_data/rustc_unused_variable_as_hint.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/driver/subcommand/repl.rs",
8 uri: "file:///test/driver/subcommand/repl.rs",
9 range: Range {
10 start: Position {
11 line: 290,
12 character: 8,
13 },
14 end: Position {
15 line: 290,
16 character: 11,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
@@ -53,9 +37,10 @@ expression: diag
53 id: None, 37 id: None,
54 group: None, 38 group: None,
55 kind: Some( 39 kind: Some(
56 "quickfix", 40 CodeActionKind(
41 "quickfix",
42 ),
57 ), 43 ),
58 command: None,
59 edit: Some( 44 edit: Some(
60 SnippetWorkspaceEdit { 45 SnippetWorkspaceEdit {
61 changes: Some( 46 changes: Some(
@@ -80,6 +65,9 @@ expression: diag
80 document_changes: None, 65 document_changes: None,
81 }, 66 },
82 ), 67 ),
68 is_preferred: Some(
69 true,
70 ),
83 }, 71 },
84 ], 72 ],
85 }, 73 },
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap b/crates/rust-analyzer/test_data/rustc_unused_variable_as_info.txt
index 85fd050fd..79910660b 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_unused_variable_as_info.snap
+++ b/crates/rust-analyzer/test_data/rustc_unused_variable_as_info.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/driver/subcommand/repl.rs",
8 uri: "file:///test/driver/subcommand/repl.rs",
9 range: Range {
10 start: Position {
11 line: 290,
12 character: 8,
13 },
14 end: Position {
15 line: 290,
16 character: 11,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
@@ -53,9 +37,10 @@ expression: diag
53 id: None, 37 id: None,
54 group: None, 38 group: None,
55 kind: Some( 39 kind: Some(
56 "quickfix", 40 CodeActionKind(
41 "quickfix",
42 ),
57 ), 43 ),
58 command: None,
59 edit: Some( 44 edit: Some(
60 SnippetWorkspaceEdit { 45 SnippetWorkspaceEdit {
61 changes: Some( 46 changes: Some(
@@ -80,6 +65,9 @@ expression: diag
80 document_changes: None, 65 document_changes: None,
81 }, 66 },
82 ), 67 ),
68 is_preferred: Some(
69 true,
70 ),
83 }, 71 },
84 ], 72 ],
85 }, 73 },
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_wrong_number_of_parameters.snap b/crates/rust-analyzer/test_data/rustc_wrong_number_of_parameters.txt
index f6ab05004..efe37261d 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_rustc_wrong_number_of_parameters.snap
+++ b/crates/rust-analyzer/test_data/rustc_wrong_number_of_parameters.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/compiler/ty/select.rs",
8 uri: "file:///test/compiler/ty/select.rs",
9 range: Range {
10 start: Position {
11 line: 103,
12 character: 17,
13 },
14 end: Position {
15 line: 103,
16 character: 29,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
diff --git a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap b/crates/rust-analyzer/test_data/snap_multi_line_fix.txt
index 272057b47..4f811ab64 100644
--- a/crates/rust-analyzer/src/diagnostics/snapshots/rust_analyzer__diagnostics__to_proto__tests__snap_multi_line_fix.snap
+++ b/crates/rust-analyzer/test_data/snap_multi_line_fix.txt
@@ -1,22 +1,6 @@
1---
2source: crates/rust-analyzer/src/diagnostics/to_proto.rs
3expression: diag
4---
5[ 1[
6 MappedRustDiagnostic { 2 MappedRustDiagnostic {
7 location: Location { 3 url: "file:///test/src/main.rs",
8 uri: "file:///test/src/main.rs",
9 range: Range {
10 start: Position {
11 line: 3,
12 character: 4,
13 },
14 end: Position {
15 line: 3,
16 character: 5,
17 },
18 },
19 },
20 diagnostic: Diagnostic { 4 diagnostic: Diagnostic {
21 range: Range { 5 range: Range {
22 start: Position { 6 start: Position {
@@ -68,9 +52,10 @@ expression: diag
68 id: None, 52 id: None,
69 group: None, 53 group: None,
70 kind: Some( 54 kind: Some(
71 "quickfix", 55 CodeActionKind(
56 "quickfix",
57 ),
72 ), 58 ),
73 command: None,
74 edit: Some( 59 edit: Some(
75 SnippetWorkspaceEdit { 60 SnippetWorkspaceEdit {
76 changes: Some( 61 changes: Some(
@@ -108,6 +93,9 @@ expression: diag
108 document_changes: None, 93 document_changes: None,
109 }, 94 },
110 ), 95 ),
96 is_preferred: Some(
97 true,
98 ),
111 }, 99 },
112 ], 100 ],
113 }, 101 },
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index ea80705aa..91ce04731 100644
--- a/crates/rust-analyzer/tests/heavy_tests/main.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/main.rs
@@ -1,3 +1,4 @@
1mod testdir;
1mod support; 2mod support;
2 3
3use std::{collections::HashMap, path::PathBuf, time::Instant}; 4use std::{collections::HashMap, path::PathBuf, time::Instant};
@@ -12,10 +13,12 @@ use lsp_types::{
12}; 13};
13use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams}; 14use rust_analyzer::lsp_ext::{OnEnter, Runnables, RunnablesParams};
14use serde_json::json; 15use serde_json::json;
15use tempfile::TempDir;
16use test_utils::skip_slow_tests; 16use test_utils::skip_slow_tests;
17 17
18use crate::support::{project, Project}; 18use crate::{
19 support::{project, Project},
20 testdir::TestDir,
21};
19 22
20const PROFILE: &str = ""; 23const PROFILE: &str = "";
21// const PROFILE: &'static str = "*@3>100"; 24// const PROFILE: &'static str = "*@3>100";
@@ -112,21 +115,21 @@ fn main() {}
112 }, 115 },
113 { 116 {
114 "args": { 117 "args": {
115 "cargoArgs": ["check", "--package", "foo"], 118 "cargoArgs": ["check", "--package", "foo", "--all-targets"],
116 "executableArgs": [], 119 "executableArgs": [],
117 "workspaceRoot": server.path().join("foo") 120 "workspaceRoot": server.path().join("foo")
118 }, 121 },
119 "kind": "cargo", 122 "kind": "cargo",
120 "label": "cargo check -p foo" 123 "label": "cargo check -p foo --all-targets"
121 }, 124 },
122 { 125 {
123 "args": { 126 "args": {
124 "cargoArgs": ["test", "--package", "foo"], 127 "cargoArgs": ["test", "--package", "foo", "--all-targets"],
125 "executableArgs": [], 128 "executableArgs": [],
126 "workspaceRoot": server.path().join("foo") 129 "workspaceRoot": server.path().join("foo")
127 }, 130 },
128 "kind": "cargo", 131 "kind": "cargo",
129 "label": "cargo test -p foo" 132 "label": "cargo test -p foo --all-targets"
130 } 133 }
131 ]), 134 ]),
132 ); 135 );
@@ -284,6 +287,7 @@ fn main() {}
284 } 287 }
285 ] 288 ]
286 }, 289 },
290 "isPreferred": false,
287 "kind": "quickfix", 291 "kind": "quickfix",
288 "title": "Create module" 292 "title": "Create module"
289 }]), 293 }]),
@@ -307,7 +311,7 @@ fn test_missing_module_code_action_in_json_project() {
307 return; 311 return;
308 } 312 }
309 313
310 let tmp_dir = TempDir::new().unwrap(); 314 let tmp_dir = TestDir::new();
311 315
312 let path = tmp_dir.path(); 316 let path = tmp_dir.path();
313 317
@@ -317,7 +321,7 @@ fn test_missing_module_code_action_in_json_project() {
317 "root_module": path.join("src/lib.rs"), 321 "root_module": path.join("src/lib.rs"),
318 "deps": [], 322 "deps": [],
319 "edition": "2015", 323 "edition": "2015",
320 "cfg": [ "cfg_atom_1", "feature=cfg_1"], 324 "cfg": [ "cfg_atom_1", "feature=\"cfg_1\""],
321 } ] 325 } ]
322 }); 326 });
323 327
@@ -355,6 +359,7 @@ fn main() {{}}
355 } 359 }
356 ] 360 ]
357 }, 361 },
362 "isPreferred": false,
358 "kind": "quickfix", 363 "kind": "quickfix",
359 "title": "Create module" 364 "title": "Create module"
360 }]), 365 }]),
@@ -447,6 +452,7 @@ version = \"0.0.0\"
447", 452",
448 ) 453 )
449 .server(); 454 .server();
455 server.wait_until_workspace_is_loaded();
450 456
451 server.request::<OnEnter>( 457 server.request::<OnEnter>(
452 TextDocumentPositionParams { 458 TextDocumentPositionParams {
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 49f194f7e..f242c8165 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -12,22 +12,22 @@ use lsp_types::{
12 notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress, 12 notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress,
13}; 13};
14use lsp_types::{ProgressParams, ProgressParamsValue}; 14use lsp_types::{ProgressParams, ProgressParamsValue};
15use serde::Serialize;
16use serde_json::{to_string_pretty, Value};
17use tempfile::TempDir;
18use test_utils::{find_mismatch, Fixture};
19
20use ra_db::AbsPathBuf;
21use ra_project_model::ProjectManifest; 15use ra_project_model::ProjectManifest;
22use rust_analyzer::{ 16use rust_analyzer::{
23 config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject}, 17 config::{ClientCapsConfig, Config, FilesConfig, FilesWatcher, LinkedProject},
24 main_loop, 18 main_loop,
25}; 19};
20use serde::Serialize;
21use serde_json::{to_string_pretty, Value};
22use test_utils::{find_mismatch, Fixture};
23use vfs::AbsPathBuf;
24
25use crate::testdir::TestDir;
26 26
27pub struct Project<'a> { 27pub struct Project<'a> {
28 fixture: &'a str, 28 fixture: &'a str,
29 with_sysroot: bool, 29 with_sysroot: bool,
30 tmp_dir: Option<TempDir>, 30 tmp_dir: Option<TestDir>,
31 roots: Vec<PathBuf>, 31 roots: Vec<PathBuf>,
32 config: Option<Box<dyn Fn(&mut Config)>>, 32 config: Option<Box<dyn Fn(&mut Config)>>,
33} 33}
@@ -37,7 +37,7 @@ impl<'a> Project<'a> {
37 Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None } 37 Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None }
38 } 38 }
39 39
40 pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> { 40 pub fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> {
41 self.tmp_dir = Some(tmp_dir); 41 self.tmp_dir = Some(tmp_dir);
42 self 42 self
43 } 43 }
@@ -58,7 +58,7 @@ impl<'a> Project<'a> {
58 } 58 }
59 59
60 pub fn server(self) -> Server { 60 pub fn server(self) -> Server {
61 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap()); 61 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TestDir::new());
62 static INIT: Once = Once::new(); 62 static INIT: Once = Once::new();
63 INIT.call_once(|| { 63 INIT.call_once(|| {
64 env_logger::builder().is_test(true).try_init().unwrap(); 64 env_logger::builder().is_test(true).try_init().unwrap();
@@ -113,11 +113,11 @@ pub struct Server {
113 _thread: jod_thread::JoinHandle<()>, 113 _thread: jod_thread::JoinHandle<()>,
114 client: Connection, 114 client: Connection,
115 /// XXX: remove the tempdir last 115 /// XXX: remove the tempdir last
116 dir: TempDir, 116 dir: TestDir,
117} 117}
118 118
119impl Server { 119impl Server {
120 fn new(dir: TempDir, config: Config) -> Server { 120 fn new(dir: TestDir, config: Config) -> Server {
121 let (connection, client) = Connection::memory(); 121 let (connection, client) = Connection::memory();
122 122
123 let _thread = jod_thread::Builder::new() 123 let _thread = jod_thread::Builder::new()
@@ -176,12 +176,19 @@ impl Server {
176 while let Some(msg) = self.recv() { 176 while let Some(msg) = self.recv() {
177 match msg { 177 match msg {
178 Message::Request(req) => { 178 Message::Request(req) => {
179 if req.method != "window/workDoneProgress/create" 179 if req.method == "window/workDoneProgress/create" {
180 && !(req.method == "client/registerCapability" 180 continue;
181 && req.params.to_string().contains("workspace/didChangeWatchedFiles")) 181 }
182 { 182 if req.method == "client/registerCapability" {
183 panic!("unexpected request: {:?}", req) 183 let params = req.params.to_string();
184 if ["workspace/didChangeWatchedFiles", "textDocument/didSave"]
185 .iter()
186 .any(|&it| params.contains(it))
187 {
188 continue;
189 }
184 } 190 }
191 panic!("unexpected request: {:?}", req)
185 } 192 }
186 Message::Notification(_) => (), 193 Message::Notification(_) => (),
187 Message::Response(res) => { 194 Message::Response(res) => {
@@ -246,7 +253,8 @@ impl Drop for Server {
246} 253}
247 254
248fn recv_timeout(receiver: &Receiver<Message>) -> Option<Message> { 255fn recv_timeout(receiver: &Receiver<Message>) -> Option<Message> {
249 let timeout = Duration::from_secs(120); 256 let timeout =
257 if cfg!(target_os = "macos") { Duration::from_secs(300) } else { Duration::from_secs(120) };
250 select! { 258 select! {
251 recv(receiver) -> msg => msg.ok(), 259 recv(receiver) -> msg => msg.ok(),
252 recv(after(timeout)) -> _ => panic!("timed out"), 260 recv(after(timeout)) -> _ => panic!("timed out"),
diff --git a/crates/rust-analyzer/tests/heavy_tests/testdir.rs b/crates/rust-analyzer/tests/heavy_tests/testdir.rs
new file mode 100644
index 000000000..7487e7429
--- /dev/null
+++ b/crates/rust-analyzer/tests/heavy_tests/testdir.rs
@@ -0,0 +1,62 @@
1use std::{
2 fs, io,
3 path::{Path, PathBuf},
4 sync::atomic::{AtomicUsize, Ordering},
5};
6
7pub struct TestDir {
8 path: PathBuf,
9 keep: bool,
10}
11
12impl TestDir {
13 pub fn new() -> TestDir {
14 let base = std::env::temp_dir().join("testdir");
15 let pid = std::process::id();
16
17 static CNT: AtomicUsize = AtomicUsize::new(0);
18 for _ in 0..100 {
19 let cnt = CNT.fetch_add(1, Ordering::Relaxed);
20 let path = base.join(format!("{}_{}", pid, cnt));
21 if path.is_dir() {
22 continue;
23 }
24 fs::create_dir_all(&path).unwrap();
25 return TestDir { path, keep: false };
26 }
27 panic!("Failed to create a temporary directory")
28 }
29 #[allow(unused)]
30 pub fn keep(mut self) -> TestDir {
31 self.keep = true;
32 self
33 }
34 pub fn path(&self) -> &Path {
35 &self.path
36 }
37}
38
39impl Drop for TestDir {
40 fn drop(&mut self) {
41 if self.keep {
42 return;
43 }
44 remove_dir_all(&self.path).unwrap()
45 }
46}
47
48#[cfg(not(windows))]
49fn remove_dir_all(path: &Path) -> io::Result<()> {
50 fs::remove_dir_all(path)
51}
52
53#[cfg(windows)]
54fn remove_dir_all(path: &Path) -> io::Result<()> {
55 for _ in 0..99 {
56 if fs::remove_dir_all(path).is_ok() {
57 return Ok(());
58 }
59 std::thread::sleep(std::time::Duration::from_millis(10))
60 }
61 fs::remove_dir_all(path)
62}
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index f9e380c10..4c0b85861 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -3,6 +3,7 @@ name = "stdx"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["rust-analyzer developers"] 4authors = ["rust-analyzer developers"]
5edition = "2018" 5edition = "2018"
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 08ac6f70f..b65875c96 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,30 +1,13 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2use std::{cell::Cell, fmt, time::Instant}; 2use std::{cell::Cell, fmt, time::Instant};
3 3
4mod macros;
5
4#[inline(always)] 6#[inline(always)]
5pub fn is_ci() -> bool { 7pub fn is_ci() -> bool {
6 option_env!("CI").is_some() 8 option_env!("CI").is_some()
7} 9}
8 10
9#[macro_export]
10macro_rules! eprintln {
11 ($($tt:tt)*) => {{
12 if $crate::is_ci() {
13 panic!("Forgot to remove debug-print?")
14 }
15 std::eprintln!($($tt)*)
16 }}
17}
18
19/// Appends formatted string to a `String`.
20#[macro_export]
21macro_rules! format_to {
22 ($buf:expr) => ();
23 ($buf:expr, $lit:literal $($arg:tt)*) => {
24 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
25 };
26}
27
28pub trait SepBy: Sized { 11pub trait SepBy: Sized {
29 /// Returns an `impl fmt::Display`, which joins elements via a separator. 12 /// Returns an `impl fmt::Display`, which joins elements via a separator.
30 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>; 13 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>;
@@ -87,6 +70,8 @@ where
87 Ok(()) 70 Ok(())
88 } 71 }
89} 72}
73
74#[must_use]
90pub fn timeit(label: &'static str) -> impl Drop { 75pub fn timeit(label: &'static str) -> impl Drop {
91 struct Guard { 76 struct Guard {
92 label: &'static str, 77 label: &'static str,
@@ -124,9 +109,18 @@ pub fn replace(buf: &mut String, from: char, to: &str) {
124 *buf = buf.replace(from, to) 109 *buf = buf.replace(from, to)
125} 110}
126 111
127pub fn split_delim(haystack: &str, delim: char) -> Option<(&str, &str)> { 112// https://github.com/rust-lang/rust/issues/74773
128 let idx = haystack.find(delim)?; 113pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
129 Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) 114 let mut split = haystack.splitn(2, delim);
115 let prefix = split.next()?;
116 let suffix = split.next()?;
117 Some((prefix, suffix))
118}
119pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
120 let mut split = haystack.rsplitn(2, delim);
121 let suffix = split.next()?;
122 let prefix = split.next()?;
123 Some((prefix, suffix))
130} 124}
131 125
132pub fn trim_indent(mut text: &str) -> String { 126pub fn trim_indent(mut text: &str) -> String {
@@ -173,6 +167,36 @@ impl<'a> Iterator for LinesWithEnds<'a> {
173 } 167 }
174} 168}
175 169
170// https://github.com/rust-lang/rust/issues/73831
171pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize
172where
173 P: FnMut(&T) -> bool,
174{
175 let mut left = 0;
176 let mut right = slice.len();
177
178 while left != right {
179 let mid = left + (right - left) / 2;
180 // SAFETY:
181 // When left < right, left <= mid < right.
182 // Therefore left always increases and right always decreases,
183 // and either of them is selected.
184 // In both cases left <= right is satisfied.
185 // Therefore if left < right in a step,
186 // left <= right is satisfied in the next step.
187 // Therefore as long as left != right, 0 <= left < right <= len is satisfied
188 // and if this case 0 <= mid < len is satisfied too.
189 let value = unsafe { slice.get_unchecked(mid) };
190 if pred(value) {
191 left = mid + 1;
192 } else {
193 right = mid;
194 }
195 }
196
197 left
198}
199
176#[cfg(test)] 200#[cfg(test)]
177mod tests { 201mod tests {
178 use super::*; 202 use super::*;
diff --git a/crates/stdx/src/macros.rs b/crates/stdx/src/macros.rs
new file mode 100644
index 000000000..bf298460f
--- /dev/null
+++ b/crates/stdx/src/macros.rs
@@ -0,0 +1,40 @@
1//! Convenience macros.
2#[macro_export]
3macro_rules! eprintln {
4 ($($tt:tt)*) => {{
5 if $crate::is_ci() {
6 panic!("Forgot to remove debug-print?")
7 }
8 std::eprintln!($($tt)*)
9 }}
10}
11
12/// Appends formatted string to a `String`.
13#[macro_export]
14macro_rules! format_to {
15 ($buf:expr) => ();
16 ($buf:expr, $lit:literal $($arg:tt)*) => {
17 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
18 };
19}
20
21// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums
22#[macro_export]
23macro_rules! impl_from {
24 ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => {
25 $(
26 impl From<$variant> for $enum {
27 fn from(it: $variant) -> $enum {
28 $enum::$variant(it)
29 }
30 }
31 $($(
32 impl From<$sub_variant> for $enum {
33 fn from(it: $sub_variant) -> $enum {
34 $enum::$variant($variant::$sub_variant(it))
35 }
36 }
37 )*)?
38 )*
39 }
40}
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 6821db1e8..e719f4f7c 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "test_utils" 3name = "test_utils"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index fad8f7e2c..e40b61a94 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -2,7 +2,7 @@
2//! rust-analyzer database from a single string. 2//! rust-analyzer database from a single string.
3 3
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5use stdx::{lines_with_ends, split_delim, trim_indent}; 5use stdx::{lines_with_ends, split_once, trim_indent};
6 6
7#[derive(Debug, Eq, PartialEq)] 7#[derive(Debug, Eq, PartialEq)]
8pub struct Fixture { 8pub struct Fixture {
@@ -62,7 +62,7 @@ impl Fixture {
62 let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); 62 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
63 63
64 let path = components[0].to_string(); 64 let path = components[0].to_string();
65 assert!(path.starts_with("/")); 65 assert!(path.starts_with('/'));
66 66
67 let mut krate = None; 67 let mut krate = None;
68 let mut deps = Vec::new(); 68 let mut deps = Vec::new();
@@ -71,14 +71,14 @@ impl Fixture {
71 let mut cfg_key_values = Vec::new(); 71 let mut cfg_key_values = Vec::new();
72 let mut env = FxHashMap::default(); 72 let mut env = FxHashMap::default();
73 for component in components[1..].iter() { 73 for component in components[1..].iter() {
74 let (key, value) = split_delim(component, ':').unwrap(); 74 let (key, value) = split_once(component, ':').unwrap();
75 match key { 75 match key {
76 "crate" => krate = Some(value.to_string()), 76 "crate" => krate = Some(value.to_string()),
77 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), 77 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
78 "edition" => edition = Some(value.to_string()), 78 "edition" => edition = Some(value.to_string()),
79 "cfg" => { 79 "cfg" => {
80 for entry in value.split(',') { 80 for entry in value.split(',') {
81 match split_delim(entry, '=') { 81 match split_once(entry, '=') {
82 Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())), 82 Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())),
83 None => cfg_atoms.push(entry.to_string()), 83 None => cfg_atoms.push(entry.to_string()),
84 } 84 }
@@ -86,7 +86,7 @@ impl Fixture {
86 } 86 }
87 "env" => { 87 "env" => {
88 for key in value.split(',') { 88 for key in value.split(',') {
89 if let Some((k, v)) = split_delim(key, '=') { 89 if let Some((k, v)) = split_once(key, '=') {
90 env.insert(k.into(), v.into()); 90 env.insert(k.into(), v.into());
91 } 91 }
92 } 92 }
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index caf847273..ad586c882 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -11,8 +11,9 @@ pub mod mark;
11mod fixture; 11mod fixture;
12 12
13use std::{ 13use std::{
14 convert::{TryFrom, TryInto},
14 env, fs, 15 env, fs,
15 path::{Path, PathBuf}, 16 path::PathBuf,
16}; 17};
17 18
18use serde_json::Value; 19use serde_json::Value;
@@ -117,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
117} 118}
118 119
119/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text` 120/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
120pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) { 121pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String>)>, String) {
121 let open = format!("<{}>", tag); 122 let open = format!("<{}", tag);
122 let close = format!("</{}>", tag); 123 let close = format!("</{}>", tag);
123 let mut ranges = Vec::new(); 124 let mut ranges = Vec::new();
124 let mut res = String::new(); 125 let mut res = String::new();
@@ -133,22 +134,35 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
133 res.push_str(&text[..i]); 134 res.push_str(&text[..i]);
134 text = &text[i..]; 135 text = &text[i..];
135 if text.starts_with(&open) { 136 if text.starts_with(&open) {
136 text = &text[open.len()..]; 137 let close_open = text.find('>').unwrap();
138 let attr = text[open.len()..close_open].trim();
139 let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
140 text = &text[close_open + '>'.len_utf8()..];
137 let from = TextSize::of(&res); 141 let from = TextSize::of(&res);
138 stack.push(from); 142 stack.push((from, attr));
139 } else if text.starts_with(&close) { 143 } else if text.starts_with(&close) {
140 text = &text[close.len()..]; 144 text = &text[close.len()..];
141 let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag)); 145 let (from, attr) =
146 stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
142 let to = TextSize::of(&res); 147 let to = TextSize::of(&res);
143 ranges.push(TextRange::new(from, to)); 148 ranges.push((TextRange::new(from, to), attr));
149 } else {
150 res.push('<');
151 text = &text['<'.len_utf8()..];
144 } 152 }
145 } 153 }
146 } 154 }
147 } 155 }
148 assert!(stack.is_empty(), "unmatched <{}>", tag); 156 assert!(stack.is_empty(), "unmatched <{}>", tag);
149 ranges.sort_by_key(|r| (r.start(), r.end())); 157 ranges.sort_by_key(|r| (r.0.start(), r.0.end()));
150 (ranges, res) 158 (ranges, res)
151} 159}
160#[test]
161fn test_extract_tags() {
162 let (tags, text) = extract_tags(r#"<tag fn>fn <tag>main</tag>() {}</tag>"#, "tag");
163 let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::<Vec<_>>();
164 assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]);
165}
152 166
153/// Inserts `<|>` marker into the `text` at `offset`. 167/// Inserts `<|>` marker into the `text` at `offset`.
154pub fn add_cursor(text: &str, offset: TextSize) -> String { 168pub fn add_cursor(text: &str, offset: TextSize) -> String {
@@ -165,15 +179,80 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
165 let mut res = Vec::new(); 179 let mut res = Vec::new();
166 let mut prev_line_start: Option<TextSize> = None; 180 let mut prev_line_start: Option<TextSize> = None;
167 let mut line_start: TextSize = 0.into(); 181 let mut line_start: TextSize = 0.into();
182 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
168 for line in lines_with_ends(text) { 183 for line in lines_with_ends(text) {
169 if let Some(idx) = line.find("//^") { 184 let mut this_line_annotations = Vec::new();
170 let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); 185 if let Some(idx) = line.find("//") {
171 let data = line[idx + "//^".len()..].trim().to_string(); 186 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
172 res.push((TextRange::at(offset, 1.into()), data)) 187 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
188 match annotation {
189 LineAnnotation::Annotation { mut range, content } => {
190 range += annotation_offset;
191 this_line_annotations.push((range.end(), res.len()));
192 res.push((range + prev_line_start.unwrap(), content))
193 }
194 LineAnnotation::Continuation { mut offset, content } => {
195 offset += annotation_offset;
196 let &(_, idx) = prev_line_annotations
197 .iter()
198 .find(|&&(off, _idx)| off == offset)
199 .unwrap();
200 res[idx].1.push('\n');
201 res[idx].1.push_str(&content);
202 res[idx].1.push('\n');
203 }
204 }
205 }
173 } 206 }
207
174 prev_line_start = Some(line_start); 208 prev_line_start = Some(line_start);
175 line_start += TextSize::of(line); 209 line_start += TextSize::of(line);
210
211 prev_line_annotations = this_line_annotations;
212 }
213 res
214}
215
216enum LineAnnotation {
217 Annotation { range: TextRange, content: String },
218 Continuation { offset: TextSize, content: String },
219}
220
221fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
222 let mut res = Vec::new();
223 let mut offset: TextSize = 0.into();
224 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' };
225 loop {
226 match line.find(marker) {
227 Some(idx) => {
228 offset += TextSize::try_from(idx).unwrap();
229 line = &line[idx..];
230 }
231 None => break,
232 };
233
234 let mut len = line.chars().take_while(|&it| it == '^').count();
235 let mut continuation = false;
236 if len == 0 {
237 assert!(line.starts_with('|'));
238 continuation = true;
239 len = 1;
240 }
241 let range = TextRange::at(offset, len.try_into().unwrap());
242 let next = line[len..].find(marker).map_or(line.len(), |it| it + len);
243 let content = line[len..][..next - len].trim().to_string();
244
245 let annotation = if continuation {
246 LineAnnotation::Continuation { offset: range.end(), content }
247 } else {
248 LineAnnotation::Annotation { range, content }
249 };
250 res.push(annotation);
251
252 line = &line[next..];
253 offset += TextSize::try_from(next).unwrap();
176 } 254 }
255
177 res 256 res
178} 257}
179 258
@@ -182,17 +261,21 @@ fn test_extract_annotations() {
182 let text = stdx::trim_indent( 261 let text = stdx::trim_indent(
183 r#" 262 r#"
184fn main() { 263fn main() {
185 let x = 92; 264 let (x, y) = (9, 2);
186 //^ def 265 //^ def ^ def
187 z + 1 266 zoo + 1
188} //^ i32 267} //^^^ type:
268 // | i32
189 "#, 269 "#,
190 ); 270 );
191 let res = extract_annotations(&text) 271 let res = extract_annotations(&text)
192 .into_iter() 272 .into_iter()
193 .map(|(range, ann)| (&text[range], ann)) 273 .map(|(range, ann)| (&text[range], ann))
194 .collect::<Vec<_>>(); 274 .collect::<Vec<_>>();
195 assert_eq!(res, vec![("x", "def".into()), ("z", "i32".into()),]); 275 assert_eq!(
276 res,
277 vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),]
278 );
196} 279}
197 280
198// Comparison functionality borrowed from cargo: 281// Comparison functionality borrowed from cargo:
@@ -282,85 +365,6 @@ pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a
282 } 365 }
283} 366}
284 367
285/// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir`
286/// subdirectories defined by `paths`.
287///
288/// If the content of the matching output file differs from the output of `f()`
289/// the test will fail.
290///
291/// If there is no matching output file it will be created and filled with the
292/// output of `f()`, but the test will fail.
293pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F)
294where
295 F: Fn(&str, &Path) -> String,
296{
297 for (path, input_code) in collect_rust_files(test_data_dir, paths) {
298 let actual = f(&input_code, &path);
299 let path = path.with_extension(outfile_extension);
300 if !path.exists() {
301 println!("\nfile: {}", path.display());
302 println!("No .txt file with expected result, creating...\n");
303 println!("{}\n{}", input_code, actual);
304 fs::write(&path, &actual).unwrap();
305 panic!("No expected result");
306 }
307 let expected = read_text(&path);
308 assert_equal_text(&expected, &actual, &path);
309 }
310}
311
312/// Collects all `.rs` files from `dir` subdirectories defined by `paths`.
313pub fn collect_rust_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
314 paths
315 .iter()
316 .flat_map(|path| {
317 let path = root_dir.to_owned().join(path);
318 rust_files_in_dir(&path).into_iter()
319 })
320 .map(|path| {
321 let text = read_text(&path);
322 (path, text)
323 })
324 .collect()
325}
326
327/// Collects paths to all `.rs` files from `dir` in a sorted `Vec<PathBuf>`.
328fn rust_files_in_dir(dir: &Path) -> Vec<PathBuf> {
329 let mut acc = Vec::new();
330 for file in fs::read_dir(&dir).unwrap() {
331 let file = file.unwrap();
332 let path = file.path();
333 if path.extension().unwrap_or_default() == "rs" {
334 acc.push(path);
335 }
336 }
337 acc.sort();
338 acc
339}
340
341/// Returns the path to the root directory of `rust-analyzer` project.
342pub fn project_dir() -> PathBuf {
343 let dir = env!("CARGO_MANIFEST_DIR");
344 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
345}
346
347/// Read file and normalize newlines.
348///
349/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
350///
351/// ```
352/// let s = "
353/// ";
354/// assert_eq!(s.as_bytes(), &[10]);
355/// ```
356///
357/// so this should always be correct.
358pub fn read_text(path: &Path) -> String {
359 fs::read_to_string(path)
360 .unwrap_or_else(|_| panic!("File at {:?} should be valid", path))
361 .replace("\r\n", "\n")
362}
363
364/// Returns `false` if slow tests should not run, otherwise returns `true` and 368/// Returns `false` if slow tests should not run, otherwise returns `true` and
365/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag 369/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
366/// that slow tests did run. 370/// that slow tests did run.
@@ -375,25 +379,8 @@ pub fn skip_slow_tests() -> bool {
375 should_skip 379 should_skip
376} 380}
377 381
378/// Asserts that `expected` and `actual` strings are equal. If they differ only 382/// Returns the path to the root directory of `rust-analyzer` project.
379/// in trailing or leading whitespace the test won't fail and 383pub fn project_dir() -> PathBuf {
380/// the contents of `actual` will be written to the file located at `path`. 384 let dir = env!("CARGO_MANIFEST_DIR");
381fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 385 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
382 if expected == actual {
383 return;
384 }
385 let dir = project_dir();
386 let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
387 if expected.trim() == actual.trim() {
388 println!("whitespace difference, rewriting");
389 println!("file: {}\n", pretty_path.display());
390 fs::write(path, actual).unwrap();
391 return;
392 }
393 if env::var("UPDATE_EXPECTATIONS").is_ok() {
394 println!("rewriting {}", pretty_path.display());
395 fs::write(path, actual).unwrap();
396 return;
397 }
398 assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
399} 386}
diff --git a/crates/test_utils/src/mark.rs b/crates/test_utils/src/mark.rs
index 7c309a894..97f5a93ad 100644
--- a/crates/test_utils/src/mark.rs
+++ b/crates/test_utils/src/mark.rs
@@ -62,7 +62,7 @@ pub struct MarkChecker {
62 62
63impl MarkChecker { 63impl MarkChecker {
64 pub fn new(mark: &'static AtomicUsize) -> MarkChecker { 64 pub fn new(mark: &'static AtomicUsize) -> MarkChecker {
65 let value_on_entry = mark.load(Ordering::SeqCst); 65 let value_on_entry = mark.load(Ordering::Relaxed);
66 MarkChecker { mark, value_on_entry } 66 MarkChecker { mark, value_on_entry }
67 } 67 }
68} 68}
@@ -72,7 +72,7 @@ impl Drop for MarkChecker {
72 if std::thread::panicking() { 72 if std::thread::panicking() {
73 return; 73 return;
74 } 74 }
75 let value_on_exit = self.mark.load(Ordering::SeqCst); 75 let value_on_exit = self.mark.load(Ordering::Relaxed);
76 assert!(value_on_exit > self.value_on_entry, "mark was not hit") 76 assert!(value_on_exit > self.value_on_entry, "mark was not hit")
77 } 77 }
78} 78}
diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml
index 4737a52a7..fce7bae3a 100644
--- a/crates/vfs-notify/Cargo.toml
+++ b/crates/vfs-notify/Cargo.toml
@@ -3,13 +3,16 @@ name = "vfs-notify"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["rust-analyzer developers"] 4authors = ["rust-analyzer developers"]
5edition = "2018" 5edition = "2018"
6license = "MIT OR Apache-2.0"
7
8[lib]
9doctest = false
6 10
7[dependencies] 11[dependencies]
8log = "0.4.8" 12log = "0.4.8"
9rustc-hash = "1.0" 13rustc-hash = "1.0"
10jod-thread = "0.1.0" 14jod-thread = "0.1.0"
11walkdir = "2.3.1" 15walkdir = "2.3.1"
12globset = "0.4.5"
13crossbeam-channel = "0.4.0" 16crossbeam-channel = "0.4.0"
14notify = "5.0.0-pre.3" 17notify = "5.0.0-pre.3"
15 18
diff --git a/crates/vfs-notify/src/include.rs b/crates/vfs-notify/src/include.rs
deleted file mode 100644
index 7378766f5..000000000
--- a/crates/vfs-notify/src/include.rs
+++ /dev/null
@@ -1,43 +0,0 @@
1//! See `Include`.
2
3use std::convert::TryFrom;
4
5use globset::{Glob, GlobSet, GlobSetBuilder};
6use paths::{RelPath, RelPathBuf};
7
8/// `Include` is the opposite of .gitignore.
9///
10/// It describes the set of files inside some directory.
11///
12/// The current implementation is very limited, it allows white-listing file
13/// globs and black-listing directories.
14#[derive(Debug, Clone)]
15pub(crate) struct Include {
16 include_files: GlobSet,
17 exclude_dirs: Vec<RelPathBuf>,
18}
19
20impl Include {
21 pub(crate) fn new(include: Vec<String>) -> Include {
22 let mut include_files = GlobSetBuilder::new();
23 let mut exclude_dirs = Vec::new();
24
25 for glob in include {
26 if glob.starts_with("!/") {
27 if let Ok(path) = RelPathBuf::try_from(&glob["!/".len()..]) {
28 exclude_dirs.push(path)
29 }
30 } else {
31 include_files.add(Glob::new(&glob).unwrap());
32 }
33 }
34 let include_files = include_files.build().unwrap();
35 Include { include_files, exclude_dirs }
36 }
37 pub(crate) fn include_file(&self, path: &RelPath) -> bool {
38 self.include_files.is_match(path)
39 }
40 pub(crate) fn exclude_dir(&self, path: &RelPath) -> bool {
41 self.exclude_dirs.iter().any(|excluded| path.starts_with(excluded))
42 }
43}
diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs
index b1ea298ae..e1e36612a 100644
--- a/crates/vfs-notify/src/lib.rs
+++ b/crates/vfs-notify/src/lib.rs
@@ -6,19 +6,14 @@
6//! 6//!
7//! Hopefully, one day a reliable file watching/walking crate appears on 7//! Hopefully, one day a reliable file watching/walking crate appears on
8//! crates.io, and we can reduce this to trivial glue code. 8//! crates.io, and we can reduce this to trivial glue code.
9mod include; 9use std::convert::TryFrom;
10 10
11use std::convert::{TryFrom, TryInto}; 11use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
12
13use crossbeam_channel::{select, unbounded, Receiver, Sender};
14use notify::{RecommendedWatcher, RecursiveMode, Watcher}; 12use notify::{RecommendedWatcher, RecursiveMode, Watcher};
15use paths::{AbsPath, AbsPathBuf}; 13use paths::{AbsPath, AbsPathBuf};
16use rustc_hash::FxHashSet;
17use vfs::loader; 14use vfs::loader;
18use walkdir::WalkDir; 15use walkdir::WalkDir;
19 16
20use crate::include::Include;
21
22#[derive(Debug)] 17#[derive(Debug)]
23pub struct NotifyHandle { 18pub struct NotifyHandle {
24 // Relative order of fields below is significant. 19 // Relative order of fields below is significant.
@@ -54,11 +49,9 @@ type NotifyEvent = notify::Result<notify::Event>;
54 49
55struct NotifyActor { 50struct NotifyActor {
56 sender: loader::Sender, 51 sender: loader::Sender,
57 config: Vec<(AbsPathBuf, Include, bool)>, 52 watched_entries: Vec<loader::Entry>,
58 watched_paths: FxHashSet<AbsPathBuf>, 53 // Drop order is significant.
59 // Drop order of fields bellow is significant, 54 watcher: Option<(RecommendedWatcher, Receiver<NotifyEvent>)>,
60 watcher: Option<RecommendedWatcher>,
61 watcher_receiver: Receiver<NotifyEvent>,
62} 55}
63 56
64#[derive(Debug)] 57#[derive(Debug)]
@@ -69,23 +62,13 @@ enum Event {
69 62
70impl NotifyActor { 63impl NotifyActor {
71 fn new(sender: loader::Sender) -> NotifyActor { 64 fn new(sender: loader::Sender) -> NotifyActor {
72 let (watcher_sender, watcher_receiver) = unbounded(); 65 NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
73 let watcher = log_notify_error(Watcher::new_immediate(move |event| {
74 watcher_sender.send(event).unwrap()
75 }));
76
77 NotifyActor {
78 sender,
79 config: Vec::new(),
80 watched_paths: FxHashSet::default(),
81 watcher,
82 watcher_receiver,
83 }
84 } 66 }
85 fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> { 67 fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
68 let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
86 select! { 69 select! {
87 recv(receiver) -> it => it.ok().map(Event::Message), 70 recv(receiver) -> it => it.ok().map(Event::Message),
88 recv(&self.watcher_receiver) -> it => Some(Event::NotifyEvent(it.unwrap())), 71 recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())),
89 } 72 }
90 } 73 }
91 fn run(mut self, inbox: Receiver<Message>) { 74 fn run(mut self, inbox: Receiver<Message>) {
@@ -94,19 +77,29 @@ impl NotifyActor {
94 match event { 77 match event {
95 Event::Message(msg) => match msg { 78 Event::Message(msg) => match msg {
96 Message::Config(config) => { 79 Message::Config(config) => {
80 self.watcher = None;
81 if !config.watch.is_empty() {
82 let (watcher_sender, watcher_receiver) = unbounded();
83 let watcher = log_notify_error(Watcher::new_immediate(move |event| {
84 watcher_sender.send(event).unwrap()
85 }));
86 self.watcher = watcher.map(|it| (it, watcher_receiver));
87 }
88
97 let n_total = config.load.len(); 89 let n_total = config.load.len();
98 self.send(loader::Message::Progress { n_total, n_done: 0 }); 90 self.send(loader::Message::Progress { n_total, n_done: 0 });
99 91
100 self.unwatch_all(); 92 self.watched_entries.clear();
101 self.config.clear();
102 93
103 for (i, entry) in config.load.into_iter().enumerate() { 94 for (i, entry) in config.load.into_iter().enumerate() {
104 let watch = config.watch.contains(&i); 95 let watch = config.watch.contains(&i);
96 if watch {
97 self.watched_entries.push(entry.clone())
98 }
105 let files = self.load_entry(entry, watch); 99 let files = self.load_entry(entry, watch);
106 self.send(loader::Message::Loaded { files }); 100 self.send(loader::Message::Loaded { files });
107 self.send(loader::Message::Progress { n_total, n_done: i + 1 }); 101 self.send(loader::Message::Progress { n_total, n_done: i + 1 });
108 } 102 }
109 self.config.sort_by(|x, y| x.0.cmp(&y.0));
110 } 103 }
111 Message::Invalidate(path) => { 104 Message::Invalidate(path) => {
112 let contents = read(path.as_path()); 105 let contents = read(path.as_path());
@@ -121,34 +114,27 @@ impl NotifyActor {
121 .into_iter() 114 .into_iter()
122 .map(|path| AbsPathBuf::try_from(path).unwrap()) 115 .map(|path| AbsPathBuf::try_from(path).unwrap())
123 .filter_map(|path| { 116 .filter_map(|path| {
124 let is_dir = path.is_dir(); 117 if path.is_dir()
125 let is_file = path.is_file(); 118 && self
126 119 .watched_entries
127 let config_idx = 120 .iter()
128 match self.config.binary_search_by(|it| it.0.cmp(&path)) { 121 .any(|entry| entry.contains_dir(&path))
129 Ok(it) => it, 122 {
130 Err(it) => it.saturating_sub(1), 123 self.watch(path);
131 }; 124 return None;
132 let include = self.config.get(config_idx).and_then(|it| {
133 let rel_path = path.strip_prefix(&it.0)?;
134 Some((rel_path, &it.1))
135 });
136
137 if let Some((rel_path, include)) = include {
138 if is_dir && include.exclude_dir(&rel_path)
139 || is_file && !include.include_file(&rel_path)
140 {
141 return None;
142 }
143 } 125 }
144 126
145 if is_dir { 127 if !path.is_file() {
146 self.watch(path);
147 return None; 128 return None;
148 } 129 }
149 if !is_file { 130 if !self
131 .watched_entries
132 .iter()
133 .any(|entry| entry.contains_file(&path))
134 {
150 return None; 135 return None;
151 } 136 }
137
152 let contents = read(&path); 138 let contents = read(&path);
153 Some((path, contents)) 139 Some((path, contents))
154 }) 140 })
@@ -175,58 +161,49 @@ impl NotifyActor {
175 (file, contents) 161 (file, contents)
176 }) 162 })
177 .collect::<Vec<_>>(), 163 .collect::<Vec<_>>(),
178 loader::Entry::Directory { path, include } => { 164 loader::Entry::Directories(dirs) => {
179 let include = Include::new(include); 165 let mut res = Vec::new();
180 self.config.push((path.clone(), include.clone(), watch)); 166
181 167 for root in dirs.include.iter() {
182 let files = WalkDir::new(&path) 168 let walkdir = WalkDir::new(root).into_iter().filter_entry(|entry| {
183 .into_iter() 169 if !entry.file_type().is_dir() {
184 .filter_entry(|entry| { 170 return true;
185 let abs_path: &AbsPath = entry.path().try_into().unwrap();
186 match abs_path.strip_prefix(&path) {
187 Some(rel_path) => {
188 !(entry.file_type().is_dir() && include.exclude_dir(rel_path))
189 }
190 None => false,
191 } 171 }
192 }) 172 let path = AbsPath::assert(entry.path());
193 .filter_map(|entry| entry.ok()) 173 root == path
194 .filter_map(|entry| { 174 || dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
175 });
176
177 let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| {
195 let is_dir = entry.file_type().is_dir(); 178 let is_dir = entry.file_type().is_dir();
196 let is_file = entry.file_type().is_file(); 179 let is_file = entry.file_type().is_file();
197 let abs_path = AbsPathBuf::try_from(entry.into_path()).unwrap(); 180 let abs_path = AbsPathBuf::assert(entry.into_path());
198 if is_dir && watch { 181 if is_dir && watch {
199 self.watch(abs_path.clone()); 182 self.watch(abs_path.clone());
200 } 183 }
201 let rel_path = abs_path.strip_prefix(&path)?; 184 if !is_file {
202 if is_file && include.include_file(&rel_path) { 185 return None;
203 Some(abs_path) 186 }
204 } else { 187 let ext = abs_path.extension().unwrap_or_default();
205 None 188 if dirs.extensions.iter().all(|it| it.as_str() != ext) {
189 return None;
206 } 190 }
191 Some(abs_path)
207 }); 192 });
208 193
209 files 194 res.extend(files.map(|file| {
210 .map(|file| {
211 let contents = read(file.as_path()); 195 let contents = read(file.as_path());
212 (file, contents) 196 (file, contents)
213 }) 197 }));
214 .collect() 198 }
199 res
215 } 200 }
216 } 201 }
217 } 202 }
218 203
219 fn watch(&mut self, path: AbsPathBuf) { 204 fn watch(&mut self, path: AbsPathBuf) {
220 if let Some(watcher) = &mut self.watcher { 205 if let Some((watcher, _)) = &mut self.watcher {
221 log_notify_error(watcher.watch(&path, RecursiveMode::NonRecursive)); 206 log_notify_error(watcher.watch(&path, RecursiveMode::NonRecursive));
222 self.watched_paths.insert(path);
223 }
224 }
225 fn unwatch_all(&mut self) {
226 if let Some(watcher) = &mut self.watcher {
227 for path in self.watched_paths.drain() {
228 log_notify_error(watcher.unwatch(path));
229 }
230 } 207 }
231 } 208 }
232 fn send(&mut self, msg: loader::Message) { 209 fn send(&mut self, msg: loader::Message) {
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index 263069002..b74cdb7ff 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -3,8 +3,13 @@ name = "vfs"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["rust-analyzer developers"] 4authors = ["rust-analyzer developers"]
5edition = "2018" 5edition = "2018"
6license = "MIT OR Apache-2.0"
7
8[lib]
9doctest = false
6 10
7[dependencies] 11[dependencies]
8rustc-hash = "1.0" 12rustc-hash = "1.0"
13fst = "0.4"
9 14
10paths = { path = "../paths" } 15paths = { path = "../paths" }
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
index d0ddeafe7..e9196fcd2 100644
--- a/crates/vfs/src/file_set.rs
+++ b/crates/vfs/src/file_set.rs
@@ -2,8 +2,9 @@
2//! 2//!
3//! Files which do not belong to any explicitly configured `FileSet` belong to 3//! Files which do not belong to any explicitly configured `FileSet` belong to
4//! the default `FileSet`. 4//! the default `FileSet`.
5use std::{fmt, iter}; 5use std::fmt;
6 6
7use fst::{IntoStreamer, Streamer};
7use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
8 9
9use crate::{FileId, Vfs, VfsPath}; 10use crate::{FileId, Vfs, VfsPath};
@@ -15,6 +16,9 @@ pub struct FileSet {
15} 16}
16 17
17impl FileSet { 18impl FileSet {
19 pub fn len(&self) -> usize {
20 self.files.len()
21 }
18 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 22 pub fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
19 let mut base = self.paths[&anchor].clone(); 23 let mut base = self.paths[&anchor].clone();
20 base.pop(); 24 base.pop();
@@ -40,7 +44,7 @@ impl fmt::Debug for FileSet {
40#[derive(Debug)] 44#[derive(Debug)]
41pub struct FileSetConfig { 45pub struct FileSetConfig {
42 n_file_sets: usize, 46 n_file_sets: usize,
43 roots: Vec<(VfsPath, usize)>, 47 map: fst::Map<Vec<u8>>,
44} 48}
45 49
46impl Default for FileSetConfig { 50impl Default for FileSetConfig {
@@ -54,26 +58,27 @@ impl FileSetConfig {
54 FileSetConfigBuilder::default() 58 FileSetConfigBuilder::default()
55 } 59 }
56 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> { 60 pub fn partition(&self, vfs: &Vfs) -> Vec<FileSet> {
61 let mut scratch_space = Vec::new();
57 let mut res = vec![FileSet::default(); self.len()]; 62 let mut res = vec![FileSet::default(); self.len()];
58 for (file_id, path) in vfs.iter() { 63 for (file_id, path) in vfs.iter() {
59 let root = self.classify(&path); 64 let root = self.classify(&path, &mut scratch_space);
60 res[root].insert(file_id, path) 65 res[root].insert(file_id, path.clone())
61 } 66 }
62 res 67 res
63 } 68 }
64 fn len(&self) -> usize { 69 fn len(&self) -> usize {
65 self.n_file_sets 70 self.n_file_sets
66 } 71 }
67 fn classify(&self, path: &VfsPath) -> usize { 72 fn classify(&self, path: &VfsPath, scratch_space: &mut Vec<u8>) -> usize {
68 let idx = match self.roots.binary_search_by(|(p, _)| p.cmp(path)) { 73 scratch_space.clear();
69 Ok(it) => it, 74 path.encode(scratch_space);
70 Err(it) => it.saturating_sub(1), 75 let automaton = PrefixOf::new(scratch_space.as_slice());
71 }; 76 let mut longest_prefix = self.len() - 1;
72 if path.starts_with(&self.roots[idx].0) { 77 let mut stream = self.map.search(automaton).into_stream();
73 self.roots[idx].1 78 while let Some((_, v)) = stream.next() {
74 } else { 79 longest_prefix = v as usize;
75 self.len() - 1
76 } 80 }
81 longest_prefix
77 } 82 }
78} 83}
79 84
@@ -96,13 +101,101 @@ impl FileSetConfigBuilder {
96 } 101 }
97 pub fn build(self) -> FileSetConfig { 102 pub fn build(self) -> FileSetConfig {
98 let n_file_sets = self.roots.len() + 1; 103 let n_file_sets = self.roots.len() + 1;
99 let mut roots: Vec<(VfsPath, usize)> = self 104 let map = {
100 .roots 105 let mut entries = Vec::new();
101 .into_iter() 106 for (i, paths) in self.roots.into_iter().enumerate() {
102 .enumerate() 107 for p in paths {
103 .flat_map(|(i, paths)| paths.into_iter().zip(iter::repeat(i))) 108 let mut buf = Vec::new();
104 .collect(); 109 p.encode(&mut buf);
105 roots.sort(); 110 entries.push((buf, i as u64));
106 FileSetConfig { n_file_sets, roots } 111 }
112 }
113 entries.sort();
114 entries.dedup_by(|(a, _), (b, _)| a == b);
115 fst::Map::from_iter(entries).unwrap()
116 };
117 FileSetConfig { n_file_sets, map }
118 }
119}
120
121struct PrefixOf<'a> {
122 prefix_of: &'a [u8],
123}
124
125impl<'a> PrefixOf<'a> {
126 fn new(prefix_of: &'a [u8]) -> Self {
127 Self { prefix_of }
128 }
129}
130
131impl fst::Automaton for PrefixOf<'_> {
132 type State = usize;
133 fn start(&self) -> usize {
134 0
135 }
136 fn is_match(&self, &state: &usize) -> bool {
137 state != !0
138 }
139 fn can_match(&self, &state: &usize) -> bool {
140 state != !0
141 }
142 fn accept(&self, &state: &usize, byte: u8) -> usize {
143 if self.prefix_of.get(state) == Some(&byte) {
144 state + 1
145 } else {
146 !0
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn path_prefix() {
157 let mut file_set = FileSetConfig::builder();
158 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
159 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo/bar/baz".into())]);
160 let file_set = file_set.build();
161
162 let mut vfs = Vfs::default();
163 vfs.set_file_contents(
164 VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
165 Some(Vec::new()),
166 );
167 vfs.set_file_contents(
168 VfsPath::new_virtual_path("/foo/src/bar/baz/lib.rs".into()),
169 Some(Vec::new()),
170 );
171 vfs.set_file_contents(
172 VfsPath::new_virtual_path("/foo/bar/baz/lib.rs".into()),
173 Some(Vec::new()),
174 );
175 vfs.set_file_contents(VfsPath::new_virtual_path("/quux/lib.rs".into()), Some(Vec::new()));
176
177 let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
178 assert_eq!(partition, vec![2, 1, 1]);
179 }
180
181 #[test]
182 fn name_prefix() {
183 let mut file_set = FileSetConfig::builder();
184 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo".into())]);
185 file_set.add_file_set(vec![VfsPath::new_virtual_path("/foo-things".into())]);
186 let file_set = file_set.build();
187
188 let mut vfs = Vfs::default();
189 vfs.set_file_contents(
190 VfsPath::new_virtual_path("/foo/src/lib.rs".into()),
191 Some(Vec::new()),
192 );
193 vfs.set_file_contents(
194 VfsPath::new_virtual_path("/foo-things/src/lib.rs".into()),
195 Some(Vec::new()),
196 );
197
198 let partition = file_set.partition(&vfs).into_iter().map(|it| it.len()).collect::<Vec<_>>();
199 assert_eq!(partition, vec![1, 1, 0]);
107 } 200 }
108} 201}
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index 024e58018..cdf6f1fd0 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -70,7 +70,7 @@ impl ChangedFile {
70 } 70 }
71} 71}
72 72
73#[derive(Eq, PartialEq)] 73#[derive(Eq, PartialEq, Copy, Clone, Debug)]
74pub enum ChangeKind { 74pub enum ChangeKind {
75 Create, 75 Create,
76 Modify, 76 Modify,
@@ -90,12 +90,12 @@ impl Vfs {
90 pub fn file_contents(&self, file_id: FileId) -> &[u8] { 90 pub fn file_contents(&self, file_id: FileId) -> &[u8] {
91 self.get(file_id).as_deref().unwrap() 91 self.get(file_id).as_deref().unwrap()
92 } 92 }
93 pub fn iter(&self) -> impl Iterator<Item = (FileId, VfsPath)> + '_ { 93 pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
94 (0..self.data.len()) 94 (0..self.data.len())
95 .map(|it| FileId(it as u32)) 95 .map(|it| FileId(it as u32))
96 .filter(move |&file_id| self.get(file_id).is_some()) 96 .filter(move |&file_id| self.get(file_id).is_some())
97 .map(move |file_id| { 97 .map(move |file_id| {
98 let path = self.interner.lookup(file_id).clone(); 98 let path = self.interner.lookup(file_id);
99 (file_id, path) 99 (file_id, path)
100 }) 100 })
101 } 101 }
diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs
index 6de2e5b3f..40cf96020 100644
--- a/crates/vfs/src/loader.rs
+++ b/crates/vfs/src/loader.rs
@@ -3,10 +3,25 @@ use std::fmt;
3 3
4use paths::{AbsPath, AbsPathBuf}; 4use paths::{AbsPath, AbsPathBuf};
5 5
6#[derive(Debug)] 6#[derive(Debug, Clone)]
7pub enum Entry { 7pub enum Entry {
8 Files(Vec<AbsPathBuf>), 8 Files(Vec<AbsPathBuf>),
9 Directory { path: AbsPathBuf, include: Vec<String> }, 9 Directories(Directories),
10}
11
12/// Specifies a set of files on the file system.
13///
14/// A file is included if:
15/// * it has included extension
16/// * it is under an `include` path
17/// * it is not under `exclude` path
18///
19/// If many include/exclude paths match, the longest one wins.
20#[derive(Debug, Clone, Default)]
21pub struct Directories {
22 pub extensions: Vec<String>,
23 pub include: Vec<AbsPathBuf>,
24 pub exclude: Vec<AbsPathBuf>,
10} 25}
11 26
12#[derive(Debug)] 27#[derive(Debug)]
@@ -33,21 +48,66 @@ pub trait Handle: fmt::Debug {
33 48
34impl Entry { 49impl Entry {
35 pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { 50 pub fn rs_files_recursively(base: AbsPathBuf) -> Entry {
36 Entry::Directory { path: base, include: globs(&["*.rs", "!/.git/"]) } 51 Entry::Directories(dirs(base, &[".git"]))
37 } 52 }
38 pub fn local_cargo_package(base: AbsPathBuf) -> Entry { 53 pub fn local_cargo_package(base: AbsPathBuf) -> Entry {
39 Entry::Directory { path: base, include: globs(&["*.rs", "!/target/", "!/.git/"]) } 54 Entry::Directories(dirs(base, &[".git", "target"]))
40 } 55 }
41 pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { 56 pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry {
42 Entry::Directory { 57 Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"]))
43 path: base, 58 }
44 include: globs(&["*.rs", "!/tests/", "!/examples/", "!/benches/", "!/.git/"]), 59
60 pub fn contains_file(&self, path: &AbsPath) -> bool {
61 match self {
62 Entry::Files(files) => files.iter().any(|it| it == path),
63 Entry::Directories(dirs) => dirs.contains_file(path),
64 }
65 }
66 pub fn contains_dir(&self, path: &AbsPath) -> bool {
67 match self {
68 Entry::Files(_) => false,
69 Entry::Directories(dirs) => dirs.contains_dir(path),
70 }
71 }
72}
73
74impl Directories {
75 pub fn contains_file(&self, path: &AbsPath) -> bool {
76 let ext = path.extension().unwrap_or_default();
77 if self.extensions.iter().all(|it| it.as_str() != ext) {
78 return false;
79 }
80 self.includes_path(path)
81 }
82 pub fn contains_dir(&self, path: &AbsPath) -> bool {
83 self.includes_path(path)
84 }
85 fn includes_path(&self, path: &AbsPath) -> bool {
86 let mut include: Option<&AbsPathBuf> = None;
87 for incl in &self.include {
88 if path.starts_with(incl) {
89 include = Some(match include {
90 Some(prev) if prev.starts_with(incl) => prev,
91 _ => incl,
92 })
93 }
94 }
95 let include = match include {
96 Some(it) => it,
97 None => return false,
98 };
99 for excl in &self.exclude {
100 if path.starts_with(excl) && excl.starts_with(include) {
101 return false;
102 }
45 } 103 }
104 true
46 } 105 }
47} 106}
48 107
49fn globs(globs: &[&str]) -> Vec<String> { 108fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories {
50 globs.iter().map(|it| it.to_string()).collect() 109 let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>();
110 Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude }
51} 111}
52 112
53impl fmt::Debug for Message { 113impl fmt::Debug for Message {
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs
index dc3031ada..04a42264e 100644
--- a/crates/vfs/src/vfs_path.rs
+++ b/crates/vfs/src/vfs_path.rs
@@ -48,6 +48,37 @@ impl VfsPath {
48 (VfsPathRepr::VirtualPath(_), _) => false, 48 (VfsPathRepr::VirtualPath(_), _) => false,
49 } 49 }
50 } 50 }
51
52 // Don't make this `pub`
53 pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
54 let tag = match &self.0 {
55 VfsPathRepr::PathBuf(_) => 0,
56 VfsPathRepr::VirtualPath(_) => 1,
57 };
58 buf.push(tag);
59 match &self.0 {
60 VfsPathRepr::PathBuf(it) => {
61 let path: &std::ffi::OsStr = it.as_os_str();
62 #[cfg(windows)]
63 {
64 use std::os::windows::ffi::OsStrExt;
65 for wchar in path.encode_wide() {
66 buf.extend(wchar.to_le_bytes().iter().copied());
67 }
68 }
69 #[cfg(unix)]
70 {
71 use std::os::unix::ffi::OsStrExt;
72 buf.extend(path.as_bytes());
73 }
74 #[cfg(not(any(windows, unix)))]
75 {
76 buf.extend(path.to_string_lossy().as_bytes());
77 }
78 }
79 VfsPathRepr::VirtualPath(VirtualPath(s)) => buf.extend(s.as_bytes()),
80 }
81 }
51} 82}
52 83
53#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] 84#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 6b6824ded..417352c9d 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -177,6 +177,9 @@ There are many benefits to this:
177* less stuff printed during printf-debugging 177* less stuff printed during printf-debugging
178* less time to run test 178* less time to run test
179 179
180It also makes sense to format snippets more compactly (for example, by placing enum defitions like `enum E { Foo, Bar }` on a single line),
181as long as they are still readable.
182
180## Order of Imports 183## Order of Imports
181 184
182We separate import groups with blank lines 185We separate import groups with blank lines
@@ -311,7 +314,7 @@ We don't have specific rules around git history hygiene.
311Maintaining clean git history is encouraged, but not enforced. 314Maintaining clean git history is encouraged, but not enforced.
312We use rebase workflow, it's OK to rewrite history during PR review process. 315We use rebase workflow, it's OK to rewrite history during PR review process.
313 316
314Avoid @mentioning people in commit messages, as such messages create a lot of duplicate notification traffic during rebases. 317Avoid @mentioning people in commit messages and pull request descriptions (they are added to commit message by bors), as such messages create a lot of duplicate notification traffic during rebases.
315 318
316# Architecture Invariants 319# Architecture Invariants
317 320
@@ -358,14 +361,24 @@ There are two kinds of tests:
358The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. 361The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for.
359If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. 362If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test.
360 363
361To update test data, run with `UPDATE_EXPECTATIONS` variable: 364To update test data, run with `UPDATE_EXPECT` variable:
362 365
363```bash 366```bash
364env UPDATE_EXPECTATIONS=1 cargo qt 367env UPDATE_EXPECT=1 cargo qt
365``` 368```
366 369
367After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above. 370After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above.
368 371
372## TypeScript Tests
373
374If you change files under `editors/code` and would like to run the tests and linter, install npm and run:
375
376```bash
377cd editors/code
378npm ci
379npm run lint
380```
381
369# Logging 382# Logging
370 383
371Logging is done by both rust-analyzer and VS Code, so it might be tricky to 384Logging is done by both rust-analyzer and VS Code, so it might be tricky to
@@ -394,13 +407,7 @@ To log all communication between the server and the client, there are two choice
394 407
395There are also two VS Code commands which might be of interest: 408There are also two VS Code commands which might be of interest:
396 409
397* `Rust Analyzer: Status` shows some memory-usage statistics. To take full 410* `Rust Analyzer: Status` shows some memory-usage statistics.
398 advantage of it, you need to compile rust-analyzer with jemalloc support:
399 ```
400 $ cargo install --path crates/rust-analyzer --force --features jemalloc
401 ```
402
403 There's an alias for this: `cargo xtask install --server --jemalloc`.
404 411
405* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. 412* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
406 413
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index cee916c09..d0c6eea61 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -170,8 +170,7 @@ The innermost and most elaborate boundary is `hir`. It has a much richer
170vocabulary of types than `ide`, but the basic testing setup is the same: we 170vocabulary of types than `ide`, but the basic testing setup is the same: we
171create a database, run some queries, assert result. 171create a database, run some queries, assert result.
172 172
173For comparisons, we use [insta](https://github.com/mitsuhiko/insta/) library for 173For comparisons, we use the `expect` crate for snapshot testing.
174snapshot testing.
175 174
176To test various analysis corner cases and avoid forgetting about old tests, we 175To test various analysis corner cases and avoid forgetting about old tests, we
177use so-called marks. See the `marks` module in the `test_utils` crate for more. 176use so-called marks. See the `marks` module in the `test_utils` crate for more.
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a0847dad3..1be01fd88 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -11,11 +11,13 @@ If you want to be notified about the changes to this document, subscribe to [#46
11 11
12## `initializationOptions` 12## `initializationOptions`
13 13
14As `initializationOptions`, `rust-analyzer` expects `"rust-analyzer"` section of the configuration. 14For `initializationOptions`, `rust-analyzer` expects `"rust-analyzer"` section of the configuration.
15That is, `rust-analyzer` usually sends `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload. 15That is, `rust-analyzer` usually sends `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload.
16`initializationOptions` should contain the same data that would be in the first item of the result. 16`initializationOptions` should contain the same data that would be in the first item of the result.
17It's OK to not send anything, then all the settings would take their default values. 17If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following:
18However, some settings can not be changed after startup at the moment. 18 * Not sending `initializationOptions`
19 * Send `"initializationOptions": null`
20 * Send `"initializationOptions": {}`
19 21
20## Snippet `TextEdit` 22## Snippet `TextEdit`
21 23
@@ -272,6 +274,11 @@ interface SsrParams {
272 query: string, 274 query: string,
273 /// If true, only check the syntax of the query and don't compute the actual edit. 275 /// If true, only check the syntax of the query and don't compute the actual edit.
274 parseOnly: bool, 276 parseOnly: bool,
277 /// The current text document. This and `position` will be used to determine in what scope
278 /// paths in `query` should be resolved.
279 textDocument: lc.TextDocumentIdentifier;
280 /// Position where SSR was invoked.
281 position: lc.Position;
275} 282}
276``` 283```
277 284
@@ -283,7 +290,7 @@ WorkspaceEdit
283 290
284### Example 291### Example
285 292
286SSR with query `foo($a:expr, $b:expr) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`. 293SSR with query `foo($a, $b) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`.
287 294
288### Unresolved Question 295### Unresolved Question
289 296
@@ -389,15 +396,27 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look
389 396
390Returns internal status message, mostly for debugging purposes. 397Returns internal status message, mostly for debugging purposes.
391 398
392## Collect Garbage 399## Reload Workspace
393 400
394**Method:** `rust-analyzer/collectGarbage` 401**Method:** `rust-analyzer/reloadWorkspace`
395 402
396**Request:** `null` 403**Request:** `null`
397 404
398**Response:** `null` 405**Response:** `null`
399 406
400Frees some caches. For internal use, and is mostly broken at the moment. 407Reloads project information (that is, re-executes `cargo metadata`).
408
409## Status Notification
410
411**Client Capability:** `{ "statusNotification": boolean }`
412
413**Method:** `rust-analyzer/status`
414
415**Notification:** `"loading" | "ready" | "invalid" | "needsReload"`
416
417This notification is sent from server to client.
418The client can use it to display persistent status to the user (in modline).
419For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request.
401 420
402## Syntax Tree 421## Syntax Tree
403 422
@@ -504,4 +523,4 @@ Such actions on the client side are appended to a hover bottom as command links:
504 | TITLE _Action1_ | _Action2_ | <- second group 523 | TITLE _Action1_ | _Action2_ | <- second group
505 +-----------------------------+ 524 +-----------------------------+
506 ... 525 ...
507``` \ No newline at end of file 526```
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
index c2864bbbc..d4bc4b07c 100644
--- a/docs/dev/syntax.md
+++ b/docs/dev/syntax.md
@@ -82,7 +82,7 @@ Points of note:
82An input like `fn f() { 90 + 2 }` might be parsed as 82An input like `fn f() { 90 + 2 }` might be parsed as
83 83
84``` 84```
85FN_DEF@0..17 85[email protected]
86 [email protected] "fn" 86 [email protected] "fn"
87 [email protected] " " 87 [email protected] " "
88 [email protected] 88 [email protected]
@@ -342,7 +342,7 @@ pub struct FnDef {
342impl AstNode for FnDef { 342impl AstNode for FnDef {
343 fn cast(syntax: SyntaxNode) -> Option<Self> { 343 fn cast(syntax: SyntaxNode) -> Option<Self> {
344 match kind { 344 match kind {
345 FN_DEF => Some(FnDef { syntax }), 345 FN => Some(FnDef { syntax }),
346 _ => None, 346 _ => None,
347 } 347 }
348 } 348 }
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index b763958fe..cfc0ad81c 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -13,8 +13,12 @@ This manual focuses on a specific usage of the library -- running it as part of
13https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP). 13https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP).
14The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process. 14The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process.
15 15
16To improve this document, send a pull request against 16[TIP]
17https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc[this file]. 17====
18[.lead]
19To improve this document, send a pull request: +
20https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc]
21====
18 22
19If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum. 23If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum.
20 24
@@ -106,20 +110,8 @@ Here are some useful self-diagnostic commands:
106* **Rust Analyzer: Show RA Version** shows the version of `rust-analyzer` binary 110* **Rust Analyzer: Show RA Version** shows the version of `rust-analyzer` binary
107* **Rust Analyzer: Status** prints some statistics about the server, like the few latest LSP requests 111* **Rust Analyzer: Status** prints some statistics about the server, like the few latest LSP requests
108* To enable server-side logging, run with `env RA_LOG=info` and see `Output > Rust Analyzer Language Server` in VS Code's panel. 112* To enable server-side logging, run with `env RA_LOG=info` and see `Output > Rust Analyzer Language Server` in VS Code's panel.
109* To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. 113* To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Rust Analyzer Language Server Trace` in the panel.
110* To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. 114* To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open `Output > Rust Analyzer Client` in the panel.
111
112==== Special `when` clause context for keybindings.
113You may use `inRustProject` context to configure keybindings for rust projects only. For example:
114[source,json]
115----
116{
117 "key": "ctrl+i",
118 "command": "rust-analyzer.toggleInlayHints",
119 "when": "inRustProject"
120}
121----
122More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here].
123 115
124=== rust-analyzer Language Server Binary 116=== rust-analyzer Language Server Binary
125 117
@@ -281,9 +273,6 @@ However, if you use some other build system, you'll have to describe the structu
281[source,TypeScript] 273[source,TypeScript]
282---- 274----
283interface JsonProject { 275interface JsonProject {
284 /// The set of paths containing the crates for this project.
285 /// Any `Crate` must be nested inside some `root`.
286 roots: string[];
287 /// The set of crates comprising the current project. 276 /// The set of crates comprising the current project.
288 /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such). 277 /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such).
289 crates: Crate[]; 278 crates: Crate[];
@@ -296,11 +285,37 @@ interface Crate {
296 edition: "2015" | "2018"; 285 edition: "2015" | "2018";
297 /// Dependencies 286 /// Dependencies
298 deps: Dep[]; 287 deps: Dep[];
288 /// Should this crate be treated as a member of current "workspace".
289 ///
290 /// By default, inferred from the `root_module` (members are the crates which reside
291 /// inside the directory opened in the editor).
292 ///
293 /// Set this to `false` for things like standard library and 3rd party crates to
294 /// enable performance optimizations (rust-analyzer assumes that non-member crates
295 /// don't change).
296 is_workspace_member?: boolean;
297 /// Optionally specify the (super)set of `.rs` files comprising this crate.
298 ///
299 /// By default, rust-analyzer assumes that only files under `root_module.parent` can belong to a crate.
300 /// `include_dirs` are included recursively, unless a subdirectory is in `exclude_dirs`.
301 ///
302 /// Different crates can share the same `source`.
303 ///
304 /// If two crates share an `.rs` file in common, they *must* have the same `source`.
305 /// rust-analyzer assumes that files from one source can't refer to files in another source.
306 source?: {
307 include_dirs: string[],
308 exclude_dirs: string[],
309 },
299 /// The set of cfgs activated for a given crate, like `["unix", "feature=foo", "feature=bar"]`. 310 /// The set of cfgs activated for a given crate, like `["unix", "feature=foo", "feature=bar"]`.
300 cfg: string[]; 311 cfg: string[];
312 /// Target triple for this Crate.
313 ///
314 /// Used when running `rustc --print cfg` to get target-specific cfgs.
315 target?: string;
316 /// Environment variables, used for the `env!` macro
317 env: : { [key: string]: string; },
301 318
302 /// value of the OUT_DIR env variable.
303 out_dir?: string;
304 /// For proc-macro crates, path to compiles proc-macro (.so file). 319 /// For proc-macro crates, path to compiles proc-macro (.so file).
305 proc_macro_dylib_path?: string; 320 proc_macro_dylib_path?: string;
306} 321}
@@ -337,3 +352,66 @@ They are usually triggered by a shortcut or by clicking a light bulb icon in the
337Cursor position or selection is signified by `┃` character. 352Cursor position or selection is signified by `┃` character.
338 353
339include::./generated_assists.adoc[] 354include::./generated_assists.adoc[]
355
356== Editor Features
357=== VS Code
358==== Special `when` clause context for keybindings.
359You may use `inRustProject` context to configure keybindings for rust projects only. For example:
360[source,json]
361----
362{
363 "key": "ctrl+i",
364 "command": "rust-analyzer.toggleInlayHints",
365 "when": "inRustProject"
366}
367----
368More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here].
369
370==== Setting runnable environment variables
371You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables.
372The simplest way for all runnables in a bunch:
373```jsonc
374"rust-analyzer.runnableEnv": {
375 "RUN_SLOW_TESTS": "1"
376}
377```
378
379Or it is possible to specify vars more granularly:
380```jsonc
381"rust-analyzer.runnableEnv": [
382 {
383 // "mask": null, // null mask means that this rule will be applied for all runnables
384 env: {
385 "APP_ID": "1",
386 "APP_DATA": "asdf"
387 }
388 },
389 {
390 "mask": "test_name",
391 "env": {
392 "APP_ID": "2", // overwrites only APP_ID
393 }
394 }
395]
396```
397
398You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively.
399
400==== Compiler feedback from external commands
401
402Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output.
403
404To do this you need to create a new https://code.visualstudio.com/docs/editor/tasks[VS Code Task] and set `rust-analyzer.checkOnSave.enable: false` in preferences.
405
406For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watch`] instead, you might add the following to `.vscode/tasks.json`:
407
408```json
409{
410 "label": "Watch",
411 "group": "build",
412 "type": "shell",
413 "command": "cargo watch",
414 "problemMatcher": "$rustc-watch",
415 "isBackground": true
416}
417```
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 3b4a31682..b0f24b10a 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -5,35 +5,35 @@
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
7 "@babel/code-frame": { 7 "@babel/code-frame": {
8 "version": "7.8.3", 8 "version": "7.10.3",
9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", 9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.3.tgz",
10 "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", 10 "integrity": "sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==",
11 "dev": true, 11 "dev": true,
12 "requires": { 12 "requires": {
13 "@babel/highlight": "^7.8.3" 13 "@babel/highlight": "^7.10.3"
14 } 14 }
15 }, 15 },
16 "@babel/helper-validator-identifier": { 16 "@babel/helper-validator-identifier": {
17 "version": "7.9.5", 17 "version": "7.10.3",
18 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", 18 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz",
19 "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", 19 "integrity": "sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==",
20 "dev": true 20 "dev": true
21 }, 21 },
22 "@babel/highlight": { 22 "@babel/highlight": {
23 "version": "7.9.0", 23 "version": "7.10.3",
24 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", 24 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.3.tgz",
25 "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", 25 "integrity": "sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==",
26 "dev": true, 26 "dev": true,
27 "requires": { 27 "requires": {
28 "@babel/helper-validator-identifier": "^7.9.0", 28 "@babel/helper-validator-identifier": "^7.10.3",
29 "chalk": "^2.0.0", 29 "chalk": "^2.0.0",
30 "js-tokens": "^4.0.0" 30 "js-tokens": "^4.0.0"
31 } 31 }
32 }, 32 },
33 "@rollup/plugin-commonjs": { 33 "@rollup/plugin-commonjs": {
34 "version": "12.0.0", 34 "version": "13.0.0",
35 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-12.0.0.tgz", 35 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-13.0.0.tgz",
36 "integrity": "sha512-8+mDQt1QUmN+4Y9D3yCG8AJNewuTSLYPJVzKKUZ+lGeQrI+bV12Tc5HCyt2WdlnG6ihIL/DPbKRJlB40DX40mw==", 36 "integrity": "sha512-Anxc3qgkAi7peAyesTqGYidG5GRim9jtg8xhmykNaZkImtvjA7Wsqep08D2mYsqw1IF7rA3lYfciLgzUSgRoqw==",
37 "dev": true, 37 "dev": true,
38 "requires": { 38 "requires": {
39 "@rollup/pluginutils": "^3.0.8", 39 "@rollup/pluginutils": "^3.0.8",
@@ -46,9 +46,9 @@
46 } 46 }
47 }, 47 },
48 "@rollup/plugin-node-resolve": { 48 "@rollup/plugin-node-resolve": {
49 "version": "8.0.0", 49 "version": "8.1.0",
50 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.0.tgz", 50 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.1.0.tgz",
51 "integrity": "sha512-5poJCChrkVggXXND/sQ7yNqwjUNT4fP31gpRWCnSNnlXuUXTCMHT33xZrTGxgjm5Rl18MHj7iEzlCT8rYWwQSA==", 51 "integrity": "sha512-ovq7ZM3JJYUUmEjjO+H8tnUdmQmdQudJB7xruX8LFZ1W2q8jXdPUS6SsIYip8ByOApu4RR7729Am9WhCeCMiHA==",
52 "dev": true, 52 "dev": true,
53 "requires": { 53 "requires": {
54 "@rollup/pluginutils": "^3.0.8", 54 "@rollup/pluginutils": "^3.0.8",
@@ -89,19 +89,12 @@
89 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", 89 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
90 "dev": true 90 "dev": true
91 }, 91 },
92 "@types/events": {
93 "version": "3.0.0",
94 "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
95 "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
96 "dev": true
97 },
98 "@types/glob": { 92 "@types/glob": {
99 "version": "7.1.1", 93 "version": "7.1.2",
100 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 94 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz",
101 "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", 95 "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==",
102 "dev": true, 96 "dev": true,
103 "requires": { 97 "requires": {
104 "@types/events": "*",
105 "@types/minimatch": "*", 98 "@types/minimatch": "*",
106 "@types/node": "*" 99 "@types/node": "*"
107 } 100 }
@@ -125,9 +118,9 @@
125 "dev": true 118 "dev": true
126 }, 119 },
127 "@types/node": { 120 "@types/node": {
128 "version": "14.0.5", 121 "version": "12.7.12",
129 "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", 122 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz",
130 "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", 123 "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==",
131 "dev": true 124 "dev": true
132 }, 125 },
133 "@types/node-fetch": { 126 "@types/node-fetch": {
@@ -156,18 +149,46 @@
156 "dev": true 149 "dev": true
157 }, 150 },
158 "@typescript-eslint/eslint-plugin": { 151 "@typescript-eslint/eslint-plugin": {
159 "version": "3.0.0", 152 "version": "3.4.0",
160 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.0.0.tgz", 153 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz",
161 "integrity": "sha512-lcZ0M6jD4cqGccYOERKdMtg+VWpoq3NSnWVxpc/AwAy0zhkUYVioOUZmfNqiNH8/eBNGhCn6HXd6mKIGRgNc1Q==", 154 "integrity": "sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ==",
162 "dev": true, 155 "dev": true,
163 "requires": { 156 "requires": {
164 "@typescript-eslint/experimental-utils": "3.0.0", 157 "@typescript-eslint/experimental-utils": "3.4.0",
158 "debug": "^4.1.1",
165 "functional-red-black-tree": "^1.0.1", 159 "functional-red-black-tree": "^1.0.1",
166 "regexpp": "^3.0.0", 160 "regexpp": "^3.0.0",
167 "semver": "^7.3.2", 161 "semver": "^7.3.2",
168 "tsutils": "^3.17.1" 162 "tsutils": "^3.17.1"
169 }, 163 },
170 "dependencies": { 164 "dependencies": {
165 "@typescript-eslint/experimental-utils": {
166 "version": "3.4.0",
167 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz",
168 "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==",
169 "dev": true,
170 "requires": {
171 "@types/json-schema": "^7.0.3",
172 "@typescript-eslint/typescript-estree": "3.4.0",
173 "eslint-scope": "^5.0.0",
174 "eslint-utils": "^2.0.0"
175 }
176 },
177 "@typescript-eslint/typescript-estree": {
178 "version": "3.4.0",
179 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz",
180 "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==",
181 "dev": true,
182 "requires": {
183 "debug": "^4.1.1",
184 "eslint-visitor-keys": "^1.1.0",
185 "glob": "^7.1.6",
186 "is-glob": "^4.0.1",
187 "lodash": "^4.17.15",
188 "semver": "^7.3.2",
189 "tsutils": "^3.17.1"
190 }
191 },
171 "semver": { 192 "semver": {
172 "version": "7.3.2", 193 "version": "7.3.2",
173 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", 194 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
@@ -177,33 +198,33 @@
177 } 198 }
178 }, 199 },
179 "@typescript-eslint/experimental-utils": { 200 "@typescript-eslint/experimental-utils": {
180 "version": "3.0.0", 201 "version": "3.4.0",
181 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.0.0.tgz", 202 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz",
182 "integrity": "sha512-BN0vmr9N79M9s2ctITtChRuP1+Dls0x/wlg0RXW1yQ7WJKPurg6X3Xirv61J2sjPif4F8SLsFMs5Nzte0WYoTQ==", 203 "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==",
183 "dev": true, 204 "dev": true,
184 "requires": { 205 "requires": {
185 "@types/json-schema": "^7.0.3", 206 "@types/json-schema": "^7.0.3",
186 "@typescript-eslint/typescript-estree": "3.0.0", 207 "@typescript-eslint/typescript-estree": "3.4.0",
187 "eslint-scope": "^5.0.0", 208 "eslint-scope": "^5.0.0",
188 "eslint-utils": "^2.0.0" 209 "eslint-utils": "^2.0.0"
189 } 210 }
190 }, 211 },
191 "@typescript-eslint/parser": { 212 "@typescript-eslint/parser": {
192 "version": "3.0.0", 213 "version": "3.4.0",
193 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.0.0.tgz", 214 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.4.0.tgz",
194 "integrity": "sha512-8RRCA9KLxoFNO0mQlrLZA0reGPd/MsobxZS/yPFj+0/XgMdS8+mO8mF3BDj2ZYQj03rkayhSJtF1HAohQ3iylw==", 215 "integrity": "sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA==",
195 "dev": true, 216 "dev": true,
196 "requires": { 217 "requires": {
197 "@types/eslint-visitor-keys": "^1.0.0", 218 "@types/eslint-visitor-keys": "^1.0.0",
198 "@typescript-eslint/experimental-utils": "3.0.0", 219 "@typescript-eslint/experimental-utils": "3.4.0",
199 "@typescript-eslint/typescript-estree": "3.0.0", 220 "@typescript-eslint/typescript-estree": "3.4.0",
200 "eslint-visitor-keys": "^1.1.0" 221 "eslint-visitor-keys": "^1.1.0"
201 } 222 }
202 }, 223 },
203 "@typescript-eslint/typescript-estree": { 224 "@typescript-eslint/typescript-estree": {
204 "version": "3.0.0", 225 "version": "3.4.0",
205 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.0.tgz", 226 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz",
206 "integrity": "sha512-nevQvHyNghsfLrrByzVIH4ZG3NROgJ8LZlfh3ddwPPH4CH7W4GAiSx5qu+xHuX5pWsq6q/eqMc1io840ZhAnUg==", 227 "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==",
207 "dev": true, 228 "dev": true,
208 "requires": { 229 "requires": {
209 "debug": "^4.1.1", 230 "debug": "^4.1.1",
@@ -224,9 +245,9 @@
224 } 245 }
225 }, 246 },
226 "acorn": { 247 "acorn": {
227 "version": "7.2.0", 248 "version": "7.3.1",
228 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", 249 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
229 "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", 250 "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==",
230 "dev": true 251 "dev": true
231 }, 252 },
232 "acorn-jsx": { 253 "acorn-jsx": {
@@ -262,23 +283,6 @@
262 "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", 283 "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
263 "dev": true 284 "dev": true
264 }, 285 },
265 "ansi-escapes": {
266 "version": "4.3.1",
267 "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
268 "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
269 "dev": true,
270 "requires": {
271 "type-fest": "^0.11.0"
272 },
273 "dependencies": {
274 "type-fest": {
275 "version": "0.11.0",
276 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
277 "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
278 "dev": true
279 }
280 }
281 },
282 "ansi-regex": { 286 "ansi-regex": {
283 "version": "5.0.0", 287 "version": "5.0.0",
284 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 288 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
@@ -313,6 +317,18 @@
313 "sprintf-js": "~1.0.2" 317 "sprintf-js": "~1.0.2"
314 } 318 }
315 }, 319 },
320 "array.prototype.map": {
321 "version": "1.0.2",
322 "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz",
323 "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==",
324 "dev": true,
325 "requires": {
326 "define-properties": "^1.1.3",
327 "es-abstract": "^1.17.0-next.1",
328 "es-array-method-boxes-properly": "^1.0.0",
329 "is-string": "^1.0.4"
330 }
331 },
316 "astral-regex": { 332 "astral-regex": {
317 "version": "1.0.0", 333 "version": "1.0.0",
318 "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 334 "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -344,9 +360,9 @@
344 "dev": true 360 "dev": true
345 }, 361 },
346 "binary-extensions": { 362 "binary-extensions": {
347 "version": "2.0.0", 363 "version": "2.1.0",
348 "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 364 "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
349 "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 365 "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
350 "dev": true 366 "dev": true
351 }, 367 },
352 "boolbase": { 368 "boolbase": {
@@ -415,12 +431,6 @@
415 "supports-color": "^5.3.0" 431 "supports-color": "^5.3.0"
416 } 432 }
417 }, 433 },
418 "chardet": {
419 "version": "0.7.0",
420 "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
421 "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
422 "dev": true
423 },
424 "cheerio": { 434 "cheerio": {
425 "version": "1.0.0-rc.3", 435 "version": "1.0.0-rc.3",
426 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", 436 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
@@ -436,36 +446,21 @@
436 } 446 }
437 }, 447 },
438 "chokidar": { 448 "chokidar": {
439 "version": "3.3.0", 449 "version": "3.3.1",
440 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", 450 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
441 "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", 451 "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
442 "dev": true, 452 "dev": true,
443 "requires": { 453 "requires": {
444 "anymatch": "~3.1.1", 454 "anymatch": "~3.1.1",
445 "braces": "~3.0.2", 455 "braces": "~3.0.2",
446 "fsevents": "~2.1.1", 456 "fsevents": "~2.1.2",
447 "glob-parent": "~5.1.0", 457 "glob-parent": "~5.1.0",
448 "is-binary-path": "~2.1.0", 458 "is-binary-path": "~2.1.0",
449 "is-glob": "~4.0.1", 459 "is-glob": "~4.0.1",
450 "normalize-path": "~3.0.0", 460 "normalize-path": "~3.0.0",
451 "readdirp": "~3.2.0" 461 "readdirp": "~3.3.0"
452 } 462 }
453 }, 463 },
454 "cli-cursor": {
455 "version": "3.1.0",
456 "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
457 "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
458 "dev": true,
459 "requires": {
460 "restore-cursor": "^3.1.0"
461 }
462 },
463 "cli-width": {
464 "version": "2.2.1",
465 "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
466 "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
467 "dev": true
468 },
469 "cliui": { 464 "cliui": {
470 "version": "5.0.0", 465 "version": "5.0.0",
471 "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 466 "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -483,29 +478,6 @@
483 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 478 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
484 "dev": true 479 "dev": true
485 }, 480 },
486 "emoji-regex": {
487 "version": "7.0.3",
488 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
489 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
490 "dev": true
491 },
492 "is-fullwidth-code-point": {
493 "version": "2.0.0",
494 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
495 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
496 "dev": true
497 },
498 "string-width": {
499 "version": "3.1.0",
500 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
501 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
502 "dev": true,
503 "requires": {
504 "emoji-regex": "^7.0.1",
505 "is-fullwidth-code-point": "^2.0.0",
506 "strip-ansi": "^5.1.0"
507 }
508 },
509 "strip-ansi": { 481 "strip-ansi": {
510 "version": "5.2.0", 482 "version": "5.2.0",
511 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 483 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -566,9 +538,9 @@
566 "dev": true 538 "dev": true
567 }, 539 },
568 "cross-spawn": { 540 "cross-spawn": {
569 "version": "7.0.2", 541 "version": "7.0.3",
570 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", 542 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
571 "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", 543 "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
572 "dev": true, 544 "dev": true,
573 "requires": { 545 "requires": {
574 "path-key": "^3.1.0", 546 "path-key": "^3.1.0",
@@ -649,9 +621,9 @@
649 "dev": true 621 "dev": true
650 }, 622 },
651 "diff": { 623 "diff": {
652 "version": "3.5.0", 624 "version": "4.0.2",
653 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 625 "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
654 "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 626 "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
655 "dev": true 627 "dev": true
656 }, 628 },
657 "doctrine": { 629 "doctrine": {
@@ -719,11 +691,20 @@
719 } 691 }
720 }, 692 },
721 "emoji-regex": { 693 "emoji-regex": {
722 "version": "8.0.0", 694 "version": "7.0.3",
723 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 695 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
724 "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 696 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
725 "dev": true 697 "dev": true
726 }, 698 },
699 "enquirer": {
700 "version": "2.3.5",
701 "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz",
702 "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==",
703 "dev": true,
704 "requires": {
705 "ansi-colors": "^3.2.1"
706 }
707 },
727 "entities": { 708 "entities": {
728 "version": "1.1.2", 709 "version": "1.1.2",
729 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", 710 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
@@ -731,22 +712,43 @@
731 "dev": true 712 "dev": true
732 }, 713 },
733 "es-abstract": { 714 "es-abstract": {
734 "version": "1.17.5", 715 "version": "1.17.6",
735 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", 716 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
736 "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", 717 "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
737 "dev": true, 718 "dev": true,
738 "requires": { 719 "requires": {
739 "es-to-primitive": "^1.2.1", 720 "es-to-primitive": "^1.2.1",
740 "function-bind": "^1.1.1", 721 "function-bind": "^1.1.1",
741 "has": "^1.0.3", 722 "has": "^1.0.3",
742 "has-symbols": "^1.0.1", 723 "has-symbols": "^1.0.1",
743 "is-callable": "^1.1.5", 724 "is-callable": "^1.2.0",
744 "is-regex": "^1.0.5", 725 "is-regex": "^1.1.0",
745 "object-inspect": "^1.7.0", 726 "object-inspect": "^1.7.0",
746 "object-keys": "^1.1.1", 727 "object-keys": "^1.1.1",
747 "object.assign": "^4.1.0", 728 "object.assign": "^4.1.0",
748 "string.prototype.trimleft": "^2.1.1", 729 "string.prototype.trimend": "^1.0.1",
749 "string.prototype.trimright": "^2.1.1" 730 "string.prototype.trimstart": "^1.0.1"
731 }
732 },
733 "es-array-method-boxes-properly": {
734 "version": "1.0.0",
735 "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
736 "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
737 "dev": true
738 },
739 "es-get-iterator": {
740 "version": "1.1.0",
741 "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz",
742 "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==",
743 "dev": true,
744 "requires": {
745 "es-abstract": "^1.17.4",
746 "has-symbols": "^1.0.1",
747 "is-arguments": "^1.0.4",
748 "is-map": "^2.0.1",
749 "is-set": "^2.0.1",
750 "is-string": "^1.0.5",
751 "isarray": "^2.0.5"
750 } 752 }
751 }, 753 },
752 "es-to-primitive": { 754 "es-to-primitive": {
@@ -782,9 +784,9 @@
782 "dev": true 784 "dev": true
783 }, 785 },
784 "eslint": { 786 "eslint": {
785 "version": "7.1.0", 787 "version": "7.3.1",
786 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz", 788 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.1.tgz",
787 "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==", 789 "integrity": "sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA==",
788 "dev": true, 790 "dev": true,
789 "requires": { 791 "requires": {
790 "@babel/code-frame": "^7.0.0", 792 "@babel/code-frame": "^7.0.0",
@@ -793,10 +795,11 @@
793 "cross-spawn": "^7.0.2", 795 "cross-spawn": "^7.0.2",
794 "debug": "^4.0.1", 796 "debug": "^4.0.1",
795 "doctrine": "^3.0.0", 797 "doctrine": "^3.0.0",
796 "eslint-scope": "^5.0.0", 798 "enquirer": "^2.3.5",
799 "eslint-scope": "^5.1.0",
797 "eslint-utils": "^2.0.0", 800 "eslint-utils": "^2.0.0",
798 "eslint-visitor-keys": "^1.1.0", 801 "eslint-visitor-keys": "^1.2.0",
799 "espree": "^7.0.0", 802 "espree": "^7.1.0",
800 "esquery": "^1.2.0", 803 "esquery": "^1.2.0",
801 "esutils": "^2.0.2", 804 "esutils": "^2.0.2",
802 "file-entry-cache": "^5.0.1", 805 "file-entry-cache": "^5.0.1",
@@ -806,7 +809,6 @@
806 "ignore": "^4.0.6", 809 "ignore": "^4.0.6",
807 "import-fresh": "^3.0.0", 810 "import-fresh": "^3.0.0",
808 "imurmurhash": "^0.1.4", 811 "imurmurhash": "^0.1.4",
809 "inquirer": "^7.0.0",
810 "is-glob": "^4.0.0", 812 "is-glob": "^4.0.0",
811 "js-yaml": "^3.13.1", 813 "js-yaml": "^3.13.1",
812 "json-stable-stringify-without-jsonify": "^1.0.1", 814 "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -836,9 +838,9 @@
836 } 838 }
837 }, 839 },
838 "chalk": { 840 "chalk": {
839 "version": "4.0.0", 841 "version": "4.1.0",
840 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", 842 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
841 "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", 843 "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
842 "dev": true, 844 "dev": true,
843 "requires": { 845 "requires": {
844 "ansi-styles": "^4.1.0", 846 "ansi-styles": "^4.1.0",
@@ -860,6 +862,22 @@
860 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 862 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
861 "dev": true 863 "dev": true
862 }, 864 },
865 "eslint-scope": {
866 "version": "5.1.0",
867 "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
868 "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
869 "dev": true,
870 "requires": {
871 "esrecurse": "^4.1.0",
872 "estraverse": "^4.1.1"
873 }
874 },
875 "eslint-visitor-keys": {
876 "version": "1.3.0",
877 "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
878 "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
879 "dev": true
880 },
863 "has-flag": { 881 "has-flag": {
864 "version": "4.0.0", 882 "version": "4.0.0",
865 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 883 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -909,14 +927,22 @@
909 "dev": true 927 "dev": true
910 }, 928 },
911 "espree": { 929 "espree": {
912 "version": "7.0.0", 930 "version": "7.1.0",
913 "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", 931 "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz",
914 "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", 932 "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==",
915 "dev": true, 933 "dev": true,
916 "requires": { 934 "requires": {
917 "acorn": "^7.1.1", 935 "acorn": "^7.2.0",
918 "acorn-jsx": "^5.2.0", 936 "acorn-jsx": "^5.2.0",
919 "eslint-visitor-keys": "^1.1.0" 937 "eslint-visitor-keys": "^1.2.0"
938 },
939 "dependencies": {
940 "eslint-visitor-keys": {
941 "version": "1.3.0",
942 "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
943 "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
944 "dev": true
945 }
920 } 946 }
921 }, 947 },
922 "esprima": { 948 "esprima": {
@@ -969,21 +995,10 @@
969 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 995 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
970 "dev": true 996 "dev": true
971 }, 997 },
972 "external-editor": {
973 "version": "3.1.0",
974 "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
975 "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
976 "dev": true,
977 "requires": {
978 "chardet": "^0.7.0",
979 "iconv-lite": "^0.4.24",
980 "tmp": "^0.0.33"
981 }
982 },
983 "fast-deep-equal": { 998 "fast-deep-equal": {
984 "version": "3.1.1", 999 "version": "3.1.3",
985 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", 1000 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
986 "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", 1001 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
987 "dev": true 1002 "dev": true
988 }, 1003 },
989 "fast-json-stable-stringify": { 1004 "fast-json-stable-stringify": {
@@ -1007,15 +1022,6 @@
1007 "pend": "~1.2.0" 1022 "pend": "~1.2.0"
1008 } 1023 }
1009 }, 1024 },
1010 "figures": {
1011 "version": "3.2.0",
1012 "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
1013 "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
1014 "dev": true,
1015 "requires": {
1016 "escape-string-regexp": "^1.0.5"
1017 }
1018 },
1019 "file-entry-cache": { 1025 "file-entry-cache": {
1020 "version": "5.0.1", 1026 "version": "5.0.1",
1021 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 1027 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
@@ -1035,12 +1041,13 @@
1035 } 1041 }
1036 }, 1042 },
1037 "find-up": { 1043 "find-up": {
1038 "version": "3.0.0", 1044 "version": "4.1.0",
1039 "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 1045 "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
1040 "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 1046 "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
1041 "dev": true, 1047 "dev": true,
1042 "requires": { 1048 "requires": {
1043 "locate-path": "^3.0.0" 1049 "locate-path": "^5.0.0",
1050 "path-exists": "^4.0.0"
1044 } 1051 }
1045 }, 1052 },
1046 "flat": { 1053 "flat": {
@@ -1238,15 +1245,6 @@
1238 } 1245 }
1239 } 1246 }
1240 }, 1247 },
1241 "iconv-lite": {
1242 "version": "0.4.24",
1243 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1244 "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1245 "dev": true,
1246 "requires": {
1247 "safer-buffer": ">= 2.1.2 < 3"
1248 }
1249 },
1250 "ignore": { 1248 "ignore": {
1251 "version": "4.0.6", 1249 "version": "4.0.6",
1252 "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 1250 "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -1285,78 +1283,11 @@
1285 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1283 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1286 "dev": true 1284 "dev": true
1287 }, 1285 },
1288 "inquirer": { 1286 "is-arguments": {
1289 "version": "7.1.0", 1287 "version": "1.0.4",
1290 "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", 1288 "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
1291 "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", 1289 "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
1292 "dev": true, 1290 "dev": true
1293 "requires": {
1294 "ansi-escapes": "^4.2.1",
1295 "chalk": "^3.0.0",
1296 "cli-cursor": "^3.1.0",
1297 "cli-width": "^2.0.0",
1298 "external-editor": "^3.0.3",
1299 "figures": "^3.0.0",
1300 "lodash": "^4.17.15",
1301 "mute-stream": "0.0.8",
1302 "run-async": "^2.4.0",
1303 "rxjs": "^6.5.3",
1304 "string-width": "^4.1.0",
1305 "strip-ansi": "^6.0.0",
1306 "through": "^2.3.6"
1307 },
1308 "dependencies": {
1309 "ansi-styles": {
1310 "version": "4.2.1",
1311 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
1312 "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
1313 "dev": true,
1314 "requires": {
1315 "@types/color-name": "^1.1.1",
1316 "color-convert": "^2.0.1"
1317 }
1318 },
1319 "chalk": {
1320 "version": "3.0.0",
1321 "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
1322 "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
1323 "dev": true,
1324 "requires": {
1325 "ansi-styles": "^4.1.0",
1326 "supports-color": "^7.1.0"
1327 }
1328 },
1329 "color-convert": {
1330 "version": "2.0.1",
1331 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1332 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1333 "dev": true,
1334 "requires": {
1335 "color-name": "~1.1.4"
1336 }
1337 },
1338 "color-name": {
1339 "version": "1.1.4",
1340 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1341 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1342 "dev": true
1343 },
1344 "has-flag": {
1345 "version": "4.0.0",
1346 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1347 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1348 "dev": true
1349 },
1350 "supports-color": {
1351 "version": "7.1.0",
1352 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
1353 "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
1354 "dev": true,
1355 "requires": {
1356 "has-flag": "^4.0.0"
1357 }
1358 }
1359 }
1360 }, 1291 },
1361 "is-binary-path": { 1292 "is-binary-path": {
1362 "version": "2.1.0", 1293 "version": "2.1.0",
@@ -1374,9 +1305,9 @@
1374 "dev": true 1305 "dev": true
1375 }, 1306 },
1376 "is-callable": { 1307 "is-callable": {
1377 "version": "1.1.5", 1308 "version": "1.2.0",
1378 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 1309 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
1379 "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", 1310 "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==",
1380 "dev": true 1311 "dev": true
1381 }, 1312 },
1382 "is-date-object": { 1313 "is-date-object": {
@@ -1392,9 +1323,9 @@
1392 "dev": true 1323 "dev": true
1393 }, 1324 },
1394 "is-fullwidth-code-point": { 1325 "is-fullwidth-code-point": {
1395 "version": "3.0.0", 1326 "version": "2.0.0",
1396 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1327 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
1397 "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1328 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
1398 "dev": true 1329 "dev": true
1399 }, 1330 },
1400 "is-glob": { 1331 "is-glob": {
@@ -1406,6 +1337,12 @@
1406 "is-extglob": "^2.1.1" 1337 "is-extglob": "^2.1.1"
1407 } 1338 }
1408 }, 1339 },
1340 "is-map": {
1341 "version": "2.0.1",
1342 "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz",
1343 "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==",
1344 "dev": true
1345 },
1409 "is-module": { 1346 "is-module": {
1410 "version": "1.0.0", 1347 "version": "1.0.0",
1411 "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", 1348 "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@@ -1419,23 +1356,35 @@
1419 "dev": true 1356 "dev": true
1420 }, 1357 },
1421 "is-reference": { 1358 "is-reference": {
1422 "version": "1.1.4", 1359 "version": "1.2.1",
1423 "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", 1360 "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
1424 "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", 1361 "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
1425 "dev": true, 1362 "dev": true,
1426 "requires": { 1363 "requires": {
1427 "@types/estree": "0.0.39" 1364 "@types/estree": "*"
1428 } 1365 }
1429 }, 1366 },
1430 "is-regex": { 1367 "is-regex": {
1431 "version": "1.0.5", 1368 "version": "1.1.0",
1432 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 1369 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz",
1433 "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 1370 "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==",
1434 "dev": true, 1371 "dev": true,
1435 "requires": { 1372 "requires": {
1436 "has": "^1.0.3" 1373 "has-symbols": "^1.0.1"
1437 } 1374 }
1438 }, 1375 },
1376 "is-set": {
1377 "version": "2.0.1",
1378 "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz",
1379 "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==",
1380 "dev": true
1381 },
1382 "is-string": {
1383 "version": "1.0.5",
1384 "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
1385 "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
1386 "dev": true
1387 },
1439 "is-symbol": { 1388 "is-symbol": {
1440 "version": "1.0.3", 1389 "version": "1.0.3",
1441 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 1390 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
@@ -1445,12 +1394,34 @@
1445 "has-symbols": "^1.0.1" 1394 "has-symbols": "^1.0.1"
1446 } 1395 }
1447 }, 1396 },
1397 "isarray": {
1398 "version": "2.0.5",
1399 "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
1400 "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
1401 "dev": true
1402 },
1448 "isexe": { 1403 "isexe": {
1449 "version": "2.0.0", 1404 "version": "2.0.0",
1450 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1405 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1451 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1406 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1452 "dev": true 1407 "dev": true
1453 }, 1408 },
1409 "iterate-iterator": {
1410 "version": "1.0.1",
1411 "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz",
1412 "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==",
1413 "dev": true
1414 },
1415 "iterate-value": {
1416 "version": "1.0.2",
1417 "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
1418 "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
1419 "dev": true,
1420 "requires": {
1421 "es-get-iterator": "^1.0.2",
1422 "iterate-iterator": "^1.0.1"
1423 }
1424 },
1454 "js-tokens": { 1425 "js-tokens": {
1455 "version": "4.0.0", 1426 "version": "4.0.0",
1456 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1427 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -1505,19 +1476,18 @@
1505 } 1476 }
1506 }, 1477 },
1507 "locate-path": { 1478 "locate-path": {
1508 "version": "3.0.0", 1479 "version": "5.0.0",
1509 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 1480 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1510 "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 1481 "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1511 "dev": true, 1482 "dev": true,
1512 "requires": { 1483 "requires": {
1513 "p-locate": "^3.0.0", 1484 "p-locate": "^4.1.0"
1514 "path-exists": "^3.0.0"
1515 } 1485 }
1516 }, 1486 },
1517 "lodash": { 1487 "lodash": {
1518 "version": "4.17.15", 1488 "version": "4.17.19",
1519 "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 1489 "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
1520 "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 1490 "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
1521 "dev": true 1491 "dev": true
1522 }, 1492 },
1523 "log-symbols": { 1493 "log-symbols": {
@@ -1596,12 +1566,6 @@
1596 "mime-db": "1.44.0" 1566 "mime-db": "1.44.0"
1597 } 1567 }
1598 }, 1568 },
1599 "mimic-fn": {
1600 "version": "2.1.0",
1601 "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
1602 "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
1603 "dev": true
1604 },
1605 "minimatch": { 1569 "minimatch": {
1606 "version": "3.0.4", 1570 "version": "3.0.4",
1607 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1571 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1627,37 +1591,44 @@
1627 } 1591 }
1628 }, 1592 },
1629 "mocha": { 1593 "mocha": {
1630 "version": "7.2.0", 1594 "version": "8.0.1",
1631 "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", 1595 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz",
1632 "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", 1596 "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==",
1633 "dev": true, 1597 "dev": true,
1634 "requires": { 1598 "requires": {
1635 "ansi-colors": "3.2.3", 1599 "ansi-colors": "4.1.1",
1636 "browser-stdout": "1.3.1", 1600 "browser-stdout": "1.3.1",
1637 "chokidar": "3.3.0", 1601 "chokidar": "3.3.1",
1638 "debug": "3.2.6", 1602 "debug": "3.2.6",
1639 "diff": "3.5.0", 1603 "diff": "4.0.2",
1640 "escape-string-regexp": "1.0.5", 1604 "escape-string-regexp": "1.0.5",
1641 "find-up": "3.0.0", 1605 "find-up": "4.1.0",
1642 "glob": "7.1.3", 1606 "glob": "7.1.6",
1643 "growl": "1.10.5", 1607 "growl": "1.10.5",
1644 "he": "1.2.0", 1608 "he": "1.2.0",
1645 "js-yaml": "3.13.1", 1609 "js-yaml": "3.13.1",
1646 "log-symbols": "3.0.0", 1610 "log-symbols": "3.0.0",
1647 "minimatch": "3.0.4", 1611 "minimatch": "3.0.4",
1648 "mkdirp": "0.5.5", 1612 "ms": "2.1.2",
1649 "ms": "2.1.1",
1650 "node-environment-flags": "1.0.6",
1651 "object.assign": "4.1.0", 1613 "object.assign": "4.1.0",
1652 "strip-json-comments": "2.0.1", 1614 "promise.allsettled": "1.0.2",
1653 "supports-color": "6.0.0", 1615 "serialize-javascript": "3.0.0",
1654 "which": "1.3.1", 1616 "strip-json-comments": "3.0.1",
1617 "supports-color": "7.1.0",
1618 "which": "2.0.2",
1655 "wide-align": "1.1.3", 1619 "wide-align": "1.1.3",
1620 "workerpool": "6.0.0",
1656 "yargs": "13.3.2", 1621 "yargs": "13.3.2",
1657 "yargs-parser": "13.1.2", 1622 "yargs-parser": "13.1.2",
1658 "yargs-unparser": "1.6.0" 1623 "yargs-unparser": "1.6.0"
1659 }, 1624 },
1660 "dependencies": { 1625 "dependencies": {
1626 "ansi-colors": {
1627 "version": "4.1.1",
1628 "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
1629 "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
1630 "dev": true
1631 },
1661 "debug": { 1632 "debug": {
1662 "version": "3.2.6", 1633 "version": "3.2.6",
1663 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1634 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -1667,19 +1638,11 @@
1667 "ms": "^2.1.1" 1638 "ms": "^2.1.1"
1668 } 1639 }
1669 }, 1640 },
1670 "glob": { 1641 "has-flag": {
1671 "version": "7.1.3", 1642 "version": "4.0.0",
1672 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 1643 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1673 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 1644 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1674 "dev": true, 1645 "dev": true
1675 "requires": {
1676 "fs.realpath": "^1.0.0",
1677 "inflight": "^1.0.4",
1678 "inherits": "2",
1679 "minimatch": "^3.0.4",
1680 "once": "^1.3.0",
1681 "path-is-absolute": "^1.0.0"
1682 }
1683 }, 1646 },
1684 "js-yaml": { 1647 "js-yaml": {
1685 "version": "3.13.1", 1648 "version": "3.13.1",
@@ -1691,34 +1654,19 @@
1691 "esprima": "^4.0.0" 1654 "esprima": "^4.0.0"
1692 } 1655 }
1693 }, 1656 },
1694 "ms": {
1695 "version": "2.1.1",
1696 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
1697 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
1698 "dev": true
1699 },
1700 "strip-json-comments": { 1657 "strip-json-comments": {
1701 "version": "2.0.1", 1658 "version": "3.0.1",
1702 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1659 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
1703 "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1660 "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
1704 "dev": true 1661 "dev": true
1705 }, 1662 },
1706 "supports-color": { 1663 "supports-color": {
1707 "version": "6.0.0", 1664 "version": "7.1.0",
1708 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", 1665 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
1709 "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", 1666 "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
1710 "dev": true,
1711 "requires": {
1712 "has-flag": "^3.0.0"
1713 }
1714 },
1715 "which": {
1716 "version": "1.3.1",
1717 "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1718 "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1719 "dev": true, 1667 "dev": true,
1720 "requires": { 1668 "requires": {
1721 "isexe": "^2.0.0" 1669 "has-flag": "^4.0.0"
1722 } 1670 }
1723 } 1671 }
1724 } 1672 }
@@ -1741,24 +1689,6 @@
1741 "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1689 "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
1742 "dev": true 1690 "dev": true
1743 }, 1691 },
1744 "node-environment-flags": {
1745 "version": "1.0.6",
1746 "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
1747 "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
1748 "dev": true,
1749 "requires": {
1750 "object.getownpropertydescriptors": "^2.0.3",
1751 "semver": "^5.7.0"
1752 },
1753 "dependencies": {
1754 "semver": {
1755 "version": "5.7.1",
1756 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1757 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1758 "dev": true
1759 }
1760 }
1761 },
1762 "node-fetch": { 1692 "node-fetch": {
1763 "version": "2.6.0", 1693 "version": "2.6.0",
1764 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 1694 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
@@ -1780,9 +1710,9 @@
1780 } 1710 }
1781 }, 1711 },
1782 "object-inspect": { 1712 "object-inspect": {
1783 "version": "1.7.0", 1713 "version": "1.8.0",
1784 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 1714 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
1785 "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", 1715 "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
1786 "dev": true 1716 "dev": true
1787 }, 1717 },
1788 "object-keys": { 1718 "object-keys": {
@@ -1803,16 +1733,6 @@
1803 "object-keys": "^1.0.11" 1733 "object-keys": "^1.0.11"
1804 } 1734 }
1805 }, 1735 },
1806 "object.getownpropertydescriptors": {
1807 "version": "2.1.0",
1808 "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
1809 "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
1810 "dev": true,
1811 "requires": {
1812 "define-properties": "^1.1.3",
1813 "es-abstract": "^1.17.0-next.1"
1814 }
1815 },
1816 "once": { 1736 "once": {
1817 "version": "1.4.0", 1737 "version": "1.4.0",
1818 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1738 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1822,15 +1742,6 @@
1822 "wrappy": "1" 1742 "wrappy": "1"
1823 } 1743 }
1824 }, 1744 },
1825 "onetime": {
1826 "version": "5.1.0",
1827 "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
1828 "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
1829 "dev": true,
1830 "requires": {
1831 "mimic-fn": "^2.1.0"
1832 }
1833 },
1834 "optionator": { 1745 "optionator": {
1835 "version": "0.9.1", 1746 "version": "0.9.1",
1836 "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 1747 "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -1883,12 +1794,12 @@
1883 } 1794 }
1884 }, 1795 },
1885 "p-locate": { 1796 "p-locate": {
1886 "version": "3.0.0", 1797 "version": "4.1.0",
1887 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 1798 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1888 "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 1799 "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1889 "dev": true, 1800 "dev": true,
1890 "requires": { 1801 "requires": {
1891 "p-limit": "^2.0.0" 1802 "p-limit": "^2.2.0"
1892 } 1803 }
1893 }, 1804 },
1894 "p-try": { 1805 "p-try": {
@@ -1933,9 +1844,9 @@
1933 } 1844 }
1934 }, 1845 },
1935 "path-exists": { 1846 "path-exists": {
1936 "version": "3.0.0", 1847 "version": "4.0.0",
1937 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1848 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1938 "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1849 "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1939 "dev": true 1850 "dev": true
1940 }, 1851 },
1941 "path-is-absolute": { 1852 "path-is-absolute": {
@@ -1980,6 +1891,19 @@
1980 "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1891 "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
1981 "dev": true 1892 "dev": true
1982 }, 1893 },
1894 "promise.allsettled": {
1895 "version": "1.0.2",
1896 "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz",
1897 "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==",
1898 "dev": true,
1899 "requires": {
1900 "array.prototype.map": "^1.0.1",
1901 "define-properties": "^1.1.3",
1902 "es-abstract": "^1.17.0-next.1",
1903 "function-bind": "^1.1.1",
1904 "iterate-value": "^1.0.0"
1905 }
1906 },
1983 "pseudomap": { 1907 "pseudomap": {
1984 "version": "1.0.2", 1908 "version": "1.0.2",
1985 "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1909 "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@@ -2013,12 +1937,12 @@
2013 } 1937 }
2014 }, 1938 },
2015 "readdirp": { 1939 "readdirp": {
2016 "version": "3.2.0", 1940 "version": "3.3.0",
2017 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", 1941 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
2018 "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", 1942 "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
2019 "dev": true, 1943 "dev": true,
2020 "requires": { 1944 "requires": {
2021 "picomatch": "^2.0.4" 1945 "picomatch": "^2.0.7"
2022 } 1946 }
2023 }, 1947 },
2024 "regexpp": { 1948 "regexpp": {
@@ -2054,16 +1978,6 @@
2054 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1978 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
2055 "dev": true 1979 "dev": true
2056 }, 1980 },
2057 "restore-cursor": {
2058 "version": "3.1.0",
2059 "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
2060 "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
2061 "dev": true,
2062 "requires": {
2063 "onetime": "^5.1.0",
2064 "signal-exit": "^3.0.2"
2065 }
2066 },
2067 "rimraf": { 1981 "rimraf": {
2068 "version": "2.6.3", 1982 "version": "2.6.3",
2069 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1983 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
@@ -2074,54 +1988,31 @@
2074 } 1988 }
2075 }, 1989 },
2076 "rollup": { 1990 "rollup": {
2077 "version": "2.10.9", 1991 "version": "2.18.1",
2078 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.9.tgz", 1992 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.18.1.tgz",
2079 "integrity": "sha512-dY/EbjiWC17ZCUSyk14hkxATAMAShkMsD43XmZGWjLrgFj15M3Dw2kEkA9ns64BiLFm9PKN6vTQw8neHwK74eg==", 1993 "integrity": "sha512-w4X77ADA+WTGlapC8Z6yggdJtODw3SBl6R2LSkA7ZW5MtdkgcB7sfaSD1UWyx8diXbMcGIb0eI9gCx/dyqOgNQ==",
2080 "dev": true, 1994 "dev": true,
2081 "requires": { 1995 "requires": {
2082 "fsevents": "~2.1.2" 1996 "fsevents": "~2.1.2"
2083 } 1997 }
2084 }, 1998 },
2085 "run-async": {
2086 "version": "2.4.1",
2087 "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
2088 "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
2089 "dev": true
2090 },
2091 "rxjs": {
2092 "version": "6.5.5",
2093 "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz",
2094 "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==",
2095 "dev": true,
2096 "requires": {
2097 "tslib": "^1.9.0"
2098 },
2099 "dependencies": {
2100 "tslib": {
2101 "version": "1.13.0",
2102 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
2103 "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
2104 "dev": true
2105 }
2106 }
2107 },
2108 "safe-buffer": { 1999 "safe-buffer": {
2109 "version": "5.2.0", 2000 "version": "5.2.0",
2110 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 2001 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
2111 "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", 2002 "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
2112 "dev": true 2003 "dev": true
2113 }, 2004 },
2114 "safer-buffer": {
2115 "version": "2.1.2",
2116 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
2117 "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
2118 "dev": true
2119 },
2120 "semver": { 2005 "semver": {
2121 "version": "6.3.0", 2006 "version": "6.3.0",
2122 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2007 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
2123 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 2008 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
2124 }, 2009 },
2010 "serialize-javascript": {
2011 "version": "3.0.0",
2012 "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz",
2013 "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==",
2014 "dev": true
2015 },
2125 "set-blocking": { 2016 "set-blocking": {
2126 "version": "2.0.0", 2017 "version": "2.0.0",
2127 "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 2018 "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -2149,12 +2040,6 @@
2149 "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 2040 "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
2150 "dev": true 2041 "dev": true
2151 }, 2042 },
2152 "signal-exit": {
2153 "version": "3.0.3",
2154 "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
2155 "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
2156 "dev": true
2157 },
2158 "slice-ansi": { 2043 "slice-ansi": {
2159 "version": "2.1.0", 2044 "version": "2.1.0",
2160 "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 2045 "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
@@ -2164,14 +2049,6 @@
2164 "ansi-styles": "^3.2.0", 2049 "ansi-styles": "^3.2.0",
2165 "astral-regex": "^1.0.0", 2050 "astral-regex": "^1.0.0",
2166 "is-fullwidth-code-point": "^2.0.0" 2051 "is-fullwidth-code-point": "^2.0.0"
2167 },
2168 "dependencies": {
2169 "is-fullwidth-code-point": {
2170 "version": "2.0.0",
2171 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2172 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2173 "dev": true
2174 }
2175 } 2052 }
2176 }, 2053 },
2177 "sourcemap-codec": { 2054 "sourcemap-codec": {
@@ -2187,14 +2064,31 @@
2187 "dev": true 2064 "dev": true
2188 }, 2065 },
2189 "string-width": { 2066 "string-width": {
2190 "version": "4.2.0", 2067 "version": "3.1.0",
2191 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2068 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2192 "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2069 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2193 "dev": true, 2070 "dev": true,
2194 "requires": { 2071 "requires": {
2195 "emoji-regex": "^8.0.0", 2072 "emoji-regex": "^7.0.1",
2196 "is-fullwidth-code-point": "^3.0.0", 2073 "is-fullwidth-code-point": "^2.0.0",
2197 "strip-ansi": "^6.0.0" 2074 "strip-ansi": "^5.1.0"
2075 },
2076 "dependencies": {
2077 "ansi-regex": {
2078 "version": "4.1.0",
2079 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
2080 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2081 "dev": true
2082 },
2083 "strip-ansi": {
2084 "version": "5.2.0",
2085 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
2086 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
2087 "dev": true,
2088 "requires": {
2089 "ansi-regex": "^4.1.0"
2090 }
2091 }
2198 } 2092 }
2199 }, 2093 },
2200 "string.prototype.trimend": { 2094 "string.prototype.trimend": {
@@ -2207,28 +2101,6 @@
2207 "es-abstract": "^1.17.5" 2101 "es-abstract": "^1.17.5"
2208 } 2102 }
2209 }, 2103 },
2210 "string.prototype.trimleft": {
2211 "version": "2.1.2",
2212 "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
2213 "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
2214 "dev": true,
2215 "requires": {
2216 "define-properties": "^1.1.3",
2217 "es-abstract": "^1.17.5",
2218 "string.prototype.trimstart": "^1.0.0"
2219 }
2220 },
2221 "string.prototype.trimright": {
2222 "version": "2.1.2",
2223 "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
2224 "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
2225 "dev": true,
2226 "requires": {
2227 "define-properties": "^1.1.3",
2228 "es-abstract": "^1.17.5",
2229 "string.prototype.trimend": "^1.0.0"
2230 }
2231 },
2232 "string.prototype.trimstart": { 2104 "string.prototype.trimstart": {
2233 "version": "1.0.1", 2105 "version": "1.0.1",
2234 "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 2106 "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
@@ -2282,46 +2154,6 @@
2282 "lodash": "^4.17.14", 2154 "lodash": "^4.17.14",
2283 "slice-ansi": "^2.1.0", 2155 "slice-ansi": "^2.1.0",
2284 "string-width": "^3.0.0" 2156 "string-width": "^3.0.0"
2285 },
2286 "dependencies": {
2287 "ansi-regex": {
2288 "version": "4.1.0",
2289 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
2290 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2291 "dev": true
2292 },
2293 "emoji-regex": {
2294 "version": "7.0.3",
2295 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2296 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2297 "dev": true
2298 },
2299 "is-fullwidth-code-point": {
2300 "version": "2.0.0",
2301 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2302 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2303 "dev": true
2304 },
2305 "string-width": {
2306 "version": "3.1.0",
2307 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2308 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2309 "dev": true,
2310 "requires": {
2311 "emoji-regex": "^7.0.1",
2312 "is-fullwidth-code-point": "^2.0.0",
2313 "strip-ansi": "^5.1.0"
2314 }
2315 },
2316 "strip-ansi": {
2317 "version": "5.2.0",
2318 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
2319 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
2320 "dev": true,
2321 "requires": {
2322 "ansi-regex": "^4.1.0"
2323 }
2324 }
2325 } 2157 }
2326 }, 2158 },
2327 "text-table": { 2159 "text-table": {
@@ -2330,21 +2162,6 @@
2330 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 2162 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
2331 "dev": true 2163 "dev": true
2332 }, 2164 },
2333 "through": {
2334 "version": "2.3.8",
2335 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
2336 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
2337 "dev": true
2338 },
2339 "tmp": {
2340 "version": "0.0.33",
2341 "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
2342 "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
2343 "dev": true,
2344 "requires": {
2345 "os-tmpdir": "~1.0.2"
2346 }
2347 },
2348 "to-regex-range": { 2165 "to-regex-range": {
2349 "version": "5.0.1", 2166 "version": "5.0.1",
2350 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2167 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2409,9 +2226,9 @@
2409 } 2226 }
2410 }, 2227 },
2411 "typescript": { 2228 "typescript": {
2412 "version": "3.9.3", 2229 "version": "3.9.5",
2413 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", 2230 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
2414 "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", 2231 "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
2415 "dev": true 2232 "dev": true
2416 }, 2233 },
2417 "typescript-formatter": { 2234 "typescript-formatter": {
@@ -2458,9 +2275,9 @@
2458 "dev": true 2275 "dev": true
2459 }, 2276 },
2460 "v8-compile-cache": { 2277 "v8-compile-cache": {
2461 "version": "2.1.0", 2278 "version": "2.1.1",
2462 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", 2279 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
2463 "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", 2280 "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
2464 "dev": true 2281 "dev": true
2465 }, 2282 },
2466 "vsce": { 2283 "vsce": {
@@ -2537,9 +2354,9 @@
2537 "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg==" 2354 "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg=="
2538 }, 2355 },
2539 "vscode-test": { 2356 "vscode-test": {
2540 "version": "1.3.0", 2357 "version": "1.4.0",
2541 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", 2358 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz",
2542 "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", 2359 "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==",
2543 "dev": true, 2360 "dev": true,
2544 "requires": { 2361 "requires": {
2545 "http-proxy-agent": "^2.1.0", 2362 "http-proxy-agent": "^2.1.0",
@@ -2577,12 +2394,6 @@
2577 "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 2394 "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
2578 "dev": true 2395 "dev": true
2579 }, 2396 },
2580 "is-fullwidth-code-point": {
2581 "version": "2.0.0",
2582 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2583 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2584 "dev": true
2585 },
2586 "string-width": { 2397 "string-width": {
2587 "version": "2.1.1", 2398 "version": "2.1.1",
2588 "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 2399 "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@@ -2610,6 +2421,12 @@
2610 "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 2421 "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
2611 "dev": true 2422 "dev": true
2612 }, 2423 },
2424 "workerpool": {
2425 "version": "6.0.0",
2426 "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz",
2427 "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==",
2428 "dev": true
2429 },
2613 "wrap-ansi": { 2430 "wrap-ansi": {
2614 "version": "5.1.0", 2431 "version": "5.1.0",
2615 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 2432 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
@@ -2627,29 +2444,6 @@
2627 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 2444 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2628 "dev": true 2445 "dev": true
2629 }, 2446 },
2630 "emoji-regex": {
2631 "version": "7.0.3",
2632 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2633 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2634 "dev": true
2635 },
2636 "is-fullwidth-code-point": {
2637 "version": "2.0.0",
2638 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2639 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2640 "dev": true
2641 },
2642 "string-width": {
2643 "version": "3.1.0",
2644 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2645 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2646 "dev": true,
2647 "requires": {
2648 "emoji-regex": "^7.0.1",
2649 "is-fullwidth-code-point": "^2.0.0",
2650 "strip-ansi": "^5.1.0"
2651 }
2652 },
2653 "strip-ansi": { 2447 "strip-ansi": {
2654 "version": "5.2.0", 2448 "version": "5.2.0",
2655 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 2449 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -2706,43 +2500,39 @@
2706 "yargs-parser": "^13.1.2" 2500 "yargs-parser": "^13.1.2"
2707 }, 2501 },
2708 "dependencies": { 2502 "dependencies": {
2709 "ansi-regex": { 2503 "find-up": {
2710 "version": "4.1.0", 2504 "version": "3.0.0",
2711 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 2505 "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
2712 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 2506 "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
2713 "dev": true 2507 "dev": true,
2714 }, 2508 "requires": {
2715 "emoji-regex": { 2509 "locate-path": "^3.0.0"
2716 "version": "7.0.3", 2510 }
2717 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2718 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2719 "dev": true
2720 },
2721 "is-fullwidth-code-point": {
2722 "version": "2.0.0",
2723 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2724 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2725 "dev": true
2726 }, 2511 },
2727 "string-width": { 2512 "locate-path": {
2728 "version": "3.1.0", 2513 "version": "3.0.0",
2729 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 2514 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
2730 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 2515 "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
2731 "dev": true, 2516 "dev": true,
2732 "requires": { 2517 "requires": {
2733 "emoji-regex": "^7.0.1", 2518 "p-locate": "^3.0.0",
2734 "is-fullwidth-code-point": "^2.0.0", 2519 "path-exists": "^3.0.0"
2735 "strip-ansi": "^5.1.0"
2736 } 2520 }
2737 }, 2521 },
2738 "strip-ansi": { 2522 "p-locate": {
2739 "version": "5.2.0", 2523 "version": "3.0.0",
2740 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 2524 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
2741 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 2525 "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
2742 "dev": true, 2526 "dev": true,
2743 "requires": { 2527 "requires": {
2744 "ansi-regex": "^4.1.0" 2528 "p-limit": "^2.0.0"
2745 } 2529 }
2530 },
2531 "path-exists": {
2532 "version": "3.0.0",
2533 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
2534 "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
2535 "dev": true
2746 } 2536 }
2747 } 2537 }
2748 }, 2538 },
diff --git a/editors/code/package.json b/editors/code/package.json
index f542a490a..1adf055d0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -39,29 +39,30 @@
39 "vscode-languageclient": "7.0.0-next.1" 39 "vscode-languageclient": "7.0.0-next.1"
40 }, 40 },
41 "devDependencies": { 41 "devDependencies": {
42 "@rollup/plugin-commonjs": "^12.0.0", 42 "@rollup/plugin-commonjs": "^13.0.0",
43 "@rollup/plugin-node-resolve": "^8.0.0", 43 "@rollup/plugin-node-resolve": "^8.1.0",
44 "@types/glob": "^7.1.1", 44 "@types/glob": "^7.1.2",
45 "@types/mocha": "^7.0.2", 45 "@types/mocha": "^7.0.2",
46 "@types/node": "^14.0.5", 46 "@types/node": "~12.7.0",
47 "@types/node-fetch": "^2.5.7", 47 "@types/node-fetch": "^2.5.7",
48 "@types/vscode": "^1.44.1", 48 "@types/vscode": "^1.44.1",
49 "@typescript-eslint/eslint-plugin": "^3.0.0", 49 "@typescript-eslint/eslint-plugin": "^3.4.0",
50 "@typescript-eslint/parser": "^3.0.0", 50 "@typescript-eslint/parser": "^3.4.0",
51 "eslint": "^7.0.0", 51 "eslint": "^7.3.1",
52 "glob": "^7.1.6", 52 "glob": "^7.1.6",
53 "mocha": "^7.1.2", 53 "mocha": "^8.0.1",
54 "rollup": "^2.10.7", 54 "rollup": "^2.18.1",
55 "tslib": "^2.0.0", 55 "tslib": "^2.0.0",
56 "typescript": "^3.9.3", 56 "typescript": "^3.9.5",
57 "typescript-formatter": "^7.2.2", 57 "typescript-formatter": "^7.2.2",
58 "vsce": "^1.75.0", 58 "vsce": "^1.75.0",
59 "vscode-test": "^1.3.0" 59 "vscode-test": "^1.4.0"
60 }, 60 },
61 "activationEvents": [ 61 "activationEvents": [
62 "onLanguage:rust", 62 "onLanguage:rust",
63 "onCommand:rust-analyzer.analyzerStatus", 63 "onCommand:rust-analyzer.analyzerStatus",
64 "onCommand:rust-analyzer.collectGarbage", 64 "onCommand:rust-analyzer.memoryUsage",
65 "onCommand:rust-analyzer.reloadWorkspace",
65 "workspaceContains:**/Cargo.toml" 66 "workspaceContains:**/Cargo.toml"
66 ], 67 ],
67 "main": "./out/src/main", 68 "main": "./out/src/main",
@@ -143,8 +144,13 @@
143 "category": "Rust Analyzer" 144 "category": "Rust Analyzer"
144 }, 145 },
145 { 146 {
146 "command": "rust-analyzer.collectGarbage", 147 "command": "rust-analyzer.memoryUsage",
147 "title": "Run garbage collection", 148 "title": "Memory Usage (Clears Database)",
149 "category": "Rust Analyzer"
150 },
151 {
152 "command": "rust-analyzer.reloadWorkspace",
153 "title": "Reload workspace",
148 "category": "Rust Analyzer" 154 "category": "Rust Analyzer"
149 }, 155 },
150 { 156 {
@@ -194,11 +200,6 @@
194 "type": "object", 200 "type": "object",
195 "title": "Rust Analyzer", 201 "title": "Rust Analyzer",
196 "properties": { 202 "properties": {
197 "rust-analyzer.diagnostics.enable": {
198 "type": "boolean",
199 "default": true,
200 "markdownDescription": "Whether to show native rust-analyzer diagnostics."
201 },
202 "rust-analyzer.lruCapacity": { 203 "rust-analyzer.lruCapacity": {
203 "type": [ 204 "type": [
204 "null", 205 "null",
@@ -231,6 +232,11 @@
231 "default": true, 232 "default": true,
232 "markdownDescription": "Whether to show `can't find Cargo.toml` error message" 233 "markdownDescription": "Whether to show `can't find Cargo.toml` error message"
233 }, 234 },
235 "rust-analyzer.cargo.autoreload": {
236 "type": "boolean",
237 "default": true,
238 "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes"
239 },
234 "rust-analyzer.cargo.noDefaultFeatures": { 240 "rust-analyzer.cargo.noDefaultFeatures": {
235 "type": "boolean", 241 "type": "boolean",
236 "default": false, 242 "default": false,
@@ -317,6 +323,14 @@
317 "default": true, 323 "default": true,
318 "markdownDescription": "Check all targets and tests (will be passed as `--all-targets`)" 324 "markdownDescription": "Check all targets and tests (will be passed as `--all-targets`)"
319 }, 325 },
326 "rust-analyzer.checkOnSave.noDefaultFeatures": {
327 "type": [
328 "null",
329 "boolean"
330 ],
331 "default": null,
332 "markdownDescription": "Do not activate the `default` feature"
333 },
320 "rust-analyzer.checkOnSave.allFeatures": { 334 "rust-analyzer.checkOnSave.allFeatures": {
321 "type": [ 335 "type": [
322 "null", 336 "null",
@@ -344,6 +358,35 @@
344 "default": null, 358 "default": null,
345 "description": "Custom cargo runner extension ID." 359 "description": "Custom cargo runner extension ID."
346 }, 360 },
361 "rust-analyzer.runnableEnv": {
362 "anyOf": [
363 {
364 "type": "null"
365 },
366 {
367 "type": "array",
368 "items": {
369 "type": "object",
370 "properties": {
371 "mask": {
372 "type": "string",
373 "description": "Runnable name mask"
374 },
375 "env": {
376 "type": "object",
377 "description": "Variables in form of { \"key\": \"value\"}"
378 }
379 }
380 }
381 },
382 {
383 "type": "object",
384 "description": "Variables in form of { \"key\": \"value\"}"
385 }
386 ],
387 "default": null,
388 "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command."
389 },
347 "rust-analyzer.inlayHints.enable": { 390 "rust-analyzer.inlayHints.enable": {
348 "type": "boolean", 391 "type": "boolean",
349 "default": true, 392 "default": true,
@@ -539,6 +582,16 @@
539 "type": "boolean", 582 "type": "boolean",
540 "default": true 583 "default": true
541 }, 584 },
585 "rust-analyzer.diagnostics.enable": {
586 "type": "boolean",
587 "default": true,
588 "markdownDescription": "Whether to show native rust-analyzer diagnostics."
589 },
590 "rust-analyzer.diagnostics.enableExperimental": {
591 "type": "boolean",
592 "default": true,
593 "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual."
594 },
542 "rust-analyzer.diagnostics.warningsAsInfo": { 595 "rust-analyzer.diagnostics.warningsAsInfo": {
543 "type": "array", 596 "type": "array",
544 "uniqueItems": true, 597 "uniqueItems": true,
@@ -554,7 +607,7 @@
554 "items": { 607 "items": {
555 "type": "string" 608 "type": "string"
556 }, 609 },
557 "description": "List of warnings warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in te problems panel.", 610 "description": "List of warnings warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.",
558 "default": [] 611 "default": []
559 } 612 }
560 } 613 }
@@ -615,24 +668,30 @@
615 "problemMatchers": [ 668 "problemMatchers": [
616 { 669 {
617 "name": "rustc", 670 "name": "rustc",
671 "owner": "rustc",
672 "source": "rustc",
618 "fileLocation": [ 673 "fileLocation": [
619 "relative", 674 "autoDetect",
620 "${workspaceRoot}" 675 "${workspaceRoot}"
621 ], 676 ],
622 "pattern": "$rustc" 677 "pattern": "$rustc"
623 }, 678 },
624 { 679 {
625 "name": "rustc-json", 680 "name": "rustc-json",
681 "owner": "rustc",
682 "source": "rustc",
626 "fileLocation": [ 683 "fileLocation": [
627 "relative", 684 "autoDetect",
628 "${workspaceRoot}" 685 "${workspaceRoot}"
629 ], 686 ],
630 "pattern": "$rustc-json" 687 "pattern": "$rustc-json"
631 }, 688 },
632 { 689 {
633 "name": "rustc-watch", 690 "name": "rustc-watch",
691 "owner": "rustc",
692 "source": "rustc",
634 "fileLocation": [ 693 "fileLocation": [
635 "relative", 694 "autoDetect",
636 "${workspaceRoot}" 695 "${workspaceRoot}"
637 ], 696 ],
638 "background": { 697 "background": {
@@ -815,7 +874,11 @@
815 "when": "inRustProject" 874 "when": "inRustProject"
816 }, 875 },
817 { 876 {
818 "command": "rust-analyzer.collectGarbage", 877 "command": "rust-analyzer.memoryUsage",
878 "when": "inRustProject"
879 },
880 {
881 "command": "rust-analyzer.reloadWorkspace",
819 "when": "inRustProject" 882 "when": "inRustProject"
820 }, 883 },
821 { 884 {
diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js
index 4b4c47f4a..27abf75ac 100644
--- a/editors/code/rollup.config.js
+++ b/editors/code/rollup.config.js
@@ -16,7 +16,6 @@ export default {
16 external: [...nodeBuiltins, 'vscode'], 16 external: [...nodeBuiltins, 'vscode'],
17 output: { 17 output: {
18 file: './out/src/main.js', 18 file: './out/src/main.js',
19 format: 'cjs', 19 format: 'cjs'
20 exports: 'named'
21 } 20 }
22}; 21};
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json
index ab87cd39f..0be2583db 100644
--- a/editors/code/rust.tmGrammar.json
+++ b/editors/code/rust.tmGrammar.json
@@ -268,7 +268,7 @@
268 "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!" 268 "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!"
269 }, 269 },
270 { 270 {
271 "comment": "Invokation of a macro", 271 "comment": "Invocation of a macro",
272 "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]", 272 "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]",
273 "captures": { 273 "captures": {
274 "1": { 274 "1": {
@@ -683,4 +683,4 @@
683 ] 683 ]
684 } 684 }
685 } 685 }
686} \ No newline at end of file 686}
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 65ad573d8..18948cb3c 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -41,6 +41,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
41 const clientOptions: lc.LanguageClientOptions = { 41 const clientOptions: lc.LanguageClientOptions = {
42 documentSelector: [{ scheme: 'file', language: 'rust' }], 42 documentSelector: [{ scheme: 'file', language: 'rust' }],
43 initializationOptions: vscode.workspace.getConfiguration("rust-analyzer"), 43 initializationOptions: vscode.workspace.getConfiguration("rust-analyzer"),
44 diagnosticCollectionName: "rustc",
44 traceOutputChannel, 45 traceOutputChannel,
45 middleware: { 46 middleware: {
46 // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 47 // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576
@@ -66,7 +67,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
66 return Promise.resolve(null); 67 return Promise.resolve(null);
67 }); 68 });
68 }, 69 },
69 // Using custom handling of CodeActions where each code action is resloved lazily 70 // Using custom handling of CodeActions where each code action is resolved lazily
70 // That's why we are not waiting for any command or edits 71 // That's why we are not waiting for any command or edits
71 async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) { 72 async provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken, _next: lc.ProvideCodeActionsSignature) {
72 const params: lc.CodeActionParams = { 73 const params: lc.CodeActionParams = {
@@ -87,7 +88,8 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
87 continue; 88 continue;
88 } 89 }
89 assert(isCodeActionWithoutEditsAndCommands(item), "We don't expect edits or commands here"); 90 assert(isCodeActionWithoutEditsAndCommands(item), "We don't expect edits or commands here");
90 const action = new vscode.CodeAction(item.title); 91 const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind);
92 const action = new vscode.CodeAction(item.title, kind);
91 const group = (item as any).group; 93 const group = (item as any).group;
92 const id = (item as any).id; 94 const id = (item as any).id;
93 const resolveParams: ra.ResolveCodeActionParams = { 95 const resolveParams: ra.ResolveCodeActionParams = {
@@ -116,6 +118,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient
116 result[index] = items[0]; 118 result[index] = items[0];
117 } else { 119 } else {
118 const action = new vscode.CodeAction(group); 120 const action = new vscode.CodeAction(group);
121 action.kind = items[0].kind;
119 action.command = { 122 action.command = {
120 command: "rust-analyzer.applyActionGroup", 123 command: "rust-analyzer.applyActionGroup",
121 title: "", 124 title: "",
@@ -161,6 +164,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
161 caps.codeActionGroup = true; 164 caps.codeActionGroup = true;
162 caps.resolveCodeAction = true; 165 caps.resolveCodeAction = true;
163 caps.hoverActions = true; 166 caps.hoverActions = true;
167 caps.statusNotification = true;
164 capabilities.experimental = caps; 168 capabilities.experimental = caps;
165 } 169 }
166 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void { 170 initialize(_capabilities: lc.ServerCapabilities<any>, _documentSelector: lc.DocumentSelector | undefined): void {
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 0e78f5101..d0faf4745 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -55,6 +55,38 @@ export function analyzerStatus(ctx: Ctx): Cmd {
55 }; 55 };
56} 56}
57 57
58export function memoryUsage(ctx: Ctx): Cmd {
59 const tdcp = new class implements vscode.TextDocumentContentProvider {
60 readonly uri = vscode.Uri.parse('rust-analyzer-memory://memory');
61 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
62
63 provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
64 if (!vscode.window.activeTextEditor) return '';
65
66 return ctx.client.sendRequest(ra.memoryUsage, null).then((mem) => {
67 return 'Per-query memory usage:\n' + mem + '\n(note: database has been cleared)';
68 });
69 }
70
71 get onDidChange(): vscode.Event<vscode.Uri> {
72 return this.eventEmitter.event;
73 }
74 }();
75
76 ctx.pushCleanup(
77 vscode.workspace.registerTextDocumentContentProvider(
78 'rust-analyzer-memory',
79 tdcp,
80 ),
81 );
82
83 return async () => {
84 tdcp.eventEmitter.fire(tdcp.uri);
85 const document = await vscode.workspace.openTextDocument(tdcp.uri);
86 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true);
87 };
88}
89
58export function matchingBrace(ctx: Ctx): Cmd { 90export function matchingBrace(ctx: Ctx): Cmd {
59 return async () => { 91 return async () => {
60 const editor = ctx.activeRustEditor; 92 const editor = ctx.activeRustEditor;
@@ -153,15 +185,22 @@ export function parentModule(ctx: Ctx): Cmd {
153 185
154export function ssr(ctx: Ctx): Cmd { 186export function ssr(ctx: Ctx): Cmd {
155 return async () => { 187 return async () => {
188 const editor = vscode.window.activeTextEditor;
156 const client = ctx.client; 189 const client = ctx.client;
157 if (!client) return; 190 if (!editor || !client) return;
191
192 const position = editor.selection.active;
193 const selections = editor.selections;
194 const textDocument = { uri: editor.document.uri.toString() };
158 195
159 const options: vscode.InputBoxOptions = { 196 const options: vscode.InputBoxOptions = {
160 value: "() ==>> ()", 197 value: "() ==>> ()",
161 prompt: "Enter request, for example 'Foo($a) ==> Foo::new($a)' ", 198 prompt: "Enter request, for example 'Foo($a) ==> Foo::new($a)' ",
162 validateInput: async (x: string) => { 199 validateInput: async (x: string) => {
163 try { 200 try {
164 await client.sendRequest(ra.ssr, { query: x, parseOnly: true }); 201 await client.sendRequest(ra.ssr, {
202 query: x, parseOnly: true, textDocument, position, selections,
203 });
165 } catch (e) { 204 } catch (e) {
166 return e.toString(); 205 return e.toString();
167 } 206 }
@@ -176,7 +215,9 @@ export function ssr(ctx: Ctx): Cmd {
176 title: "Structured search replace in progress...", 215 title: "Structured search replace in progress...",
177 cancellable: false, 216 cancellable: false,
178 }, async (_progress, _token) => { 217 }, async (_progress, _token) => {
179 const edit = await client.sendRequest(ra.ssr, { query: request, parseOnly: false }); 218 const edit = await client.sendRequest(ra.ssr, {
219 query: request, parseOnly: false, textDocument, position, selections,
220 });
180 221
181 await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit)); 222 await vscode.workspace.applyEdit(client.protocol2CodeConverter.asWorkspaceEdit(edit));
182 }); 223 });
@@ -330,8 +371,8 @@ export function expandMacro(ctx: Ctx): Cmd {
330 }; 371 };
331} 372}
332 373
333export function collectGarbage(ctx: Ctx): Cmd { 374export function reloadWorkspace(ctx: Ctx): Cmd {
334 return async () => ctx.client.sendRequest(ra.collectGarbage, null); 375 return async () => ctx.client.sendRequest(ra.reloadWorkspace, null);
335} 376}
336 377
337export function showReferences(ctx: Ctx): Cmd { 378export function showReferences(ctx: Ctx): Cmd {
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index fc95a7de6..033b04b60 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -5,6 +5,8 @@ export type UpdatesChannel = "stable" | "nightly";
5 5
6export const NIGHTLY_TAG = "nightly"; 6export const NIGHTLY_TAG = "nightly";
7 7
8export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[];
9
8export class Config { 10export class Config {
9 readonly extensionId = "matklad.rust-analyzer"; 11 readonly extensionId = "matklad.rust-analyzer";
10 12
@@ -37,10 +39,10 @@ export class Config {
37 39
38 private refreshLogging() { 40 private refreshLogging() {
39 log.setEnabled(this.traceExtension); 41 log.setEnabled(this.traceExtension);
40 log.debug( 42 log.info("Extension version:", this.package.version);
41 "Extension version:", this.package.version, 43
42 "using configuration:", this.cfg 44 const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function));
43 ); 45 log.info("Using configuration", Object.fromEntries(cfg));
44 } 46 }
45 47
46 private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { 48 private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) {
@@ -114,6 +116,10 @@ export class Config {
114 return this.get<string | undefined>("cargoRunner"); 116 return this.get<string | undefined>("cargoRunner");
115 } 117 }
116 118
119 get runnableEnv() {
120 return this.get<RunnableEnvCfg>("runnableEnv");
121 }
122
117 get debug() { 123 get debug() {
118 // "/rustc/<id>" used by suggestions only. 124 // "/rustc/<id>" used by suggestions only.
119 const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap"); 125 const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap");
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 41df11991..6e767babf 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -1,9 +1,11 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import * as ra from './lsp_ext';
3 4
4import { Config } from './config'; 5import { Config } from './config';
5import { createClient } from './client'; 6import { createClient } from './client';
6import { isRustEditor, RustEditor } from './util'; 7import { isRustEditor, RustEditor } from './util';
8import { Status } from './lsp_ext';
7 9
8export class Ctx { 10export class Ctx {
9 private constructor( 11 private constructor(
@@ -11,6 +13,7 @@ export class Ctx {
11 private readonly extCtx: vscode.ExtensionContext, 13 private readonly extCtx: vscode.ExtensionContext,
12 readonly client: lc.LanguageClient, 14 readonly client: lc.LanguageClient,
13 readonly serverPath: string, 15 readonly serverPath: string,
16 readonly statusBar: vscode.StatusBarItem,
14 ) { 17 ) {
15 18
16 } 19 }
@@ -22,9 +25,18 @@ export class Ctx {
22 cwd: string, 25 cwd: string,
23 ): Promise<Ctx> { 26 ): Promise<Ctx> {
24 const client = createClient(serverPath, cwd); 27 const client = createClient(serverPath, cwd);
25 const res = new Ctx(config, extCtx, client, serverPath); 28
29 const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
30 extCtx.subscriptions.push(statusBar);
31 statusBar.text = "rust-analyzer";
32 statusBar.tooltip = "ready";
33 statusBar.show();
34
35 const res = new Ctx(config, extCtx, client, serverPath, statusBar);
36
26 res.pushCleanup(client.start()); 37 res.pushCleanup(client.start());
27 await client.onReady(); 38 await client.onReady();
39 client.onNotification(ra.status, (status) => res.setStatus(status));
28 return res; 40 return res;
29 } 41 }
30 42
@@ -54,6 +66,35 @@ export class Ctx {
54 return this.extCtx.subscriptions; 66 return this.extCtx.subscriptions;
55 } 67 }
56 68
69 setStatus(status: Status) {
70 switch (status) {
71 case "loading":
72 this.statusBar.text = "$(sync~spin) rust-analyzer";
73 this.statusBar.tooltip = "Loading the project";
74 this.statusBar.command = undefined;
75 this.statusBar.color = undefined;
76 break;
77 case "ready":
78 this.statusBar.text = "rust-analyzer";
79 this.statusBar.tooltip = "Ready";
80 this.statusBar.command = undefined;
81 this.statusBar.color = undefined;
82 break;
83 case "invalid":
84 this.statusBar.text = "$(error) rust-analyzer";
85 this.statusBar.tooltip = "Failed to load the project";
86 this.statusBar.command = undefined;
87 this.statusBar.color = new vscode.ThemeColor("notificationsErrorIcon.foreground");
88 break;
89 case "needsReload":
90 this.statusBar.text = "$(warning) rust-analyzer";
91 this.statusBar.tooltip = "Click to reload";
92 this.statusBar.command = "rust-analyzer.reloadWorkspace";
93 this.statusBar.color = new vscode.ThemeColor("notificationsWarningIcon.foreground");
94 break;
95 }
96 }
97
57 pushCleanup(d: Disposable) { 98 pushCleanup(d: Disposable) {
58 this.extCtx.subscriptions.push(d); 99 this.extCtx.subscriptions.push(d);
59 } 100 }
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index 61c12dbe0..bd92c5b6d 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -5,9 +5,10 @@ import * as ra from './lsp_ext';
5 5
6import { Cargo } from './toolchain'; 6import { Cargo } from './toolchain';
7import { Ctx } from "./ctx"; 7import { Ctx } from "./ctx";
8import { prepareEnv } from "./run";
8 9
9const debugOutput = vscode.window.createOutputChannel("Debug"); 10const debugOutput = vscode.window.createOutputChannel("Debug");
10type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration; 11type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration;
11 12
12export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> { 13export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise<void> {
13 const scope = ctx.activeRustEditor?.document.uri; 14 const scope = ctx.activeRustEditor?.document.uri;
@@ -92,7 +93,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise<v
92 } 93 }
93 94
94 const executable = await getDebugExecutable(runnable); 95 const executable = await getDebugExecutable(runnable);
95 const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), debugOptions.sourceFileMap); 96 const env = prepareEnv(runnable, ctx.config.runnableEnv);
97 const debugConfig = knownEngines[debugEngine.id](runnable, simplifyPath(executable), env, debugOptions.sourceFileMap);
96 if (debugConfig.type in debugOptions.engineSettings) { 98 if (debugConfig.type in debugOptions.engineSettings) {
97 const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; 99 const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
98 for (var key in settingsMap) { 100 for (var key in settingsMap) {
@@ -121,7 +123,7 @@ async function getDebugExecutable(runnable: ra.Runnable): Promise<string> {
121 return executable; 123 return executable;
122} 124}
123 125
124function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 126function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
125 return { 127 return {
126 type: "lldb", 128 type: "lldb",
127 request: "launch", 129 request: "launch",
@@ -130,11 +132,12 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil
130 args: runnable.args.executableArgs, 132 args: runnable.args.executableArgs,
131 cwd: runnable.args.workspaceRoot, 133 cwd: runnable.args.workspaceRoot,
132 sourceMap: sourceFileMap, 134 sourceMap: sourceFileMap,
133 sourceLanguages: ["rust"] 135 sourceLanguages: ["rust"],
136 env
134 }; 137 };
135} 138}
136 139
137function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration { 140function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, env: Record<string, string>, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
138 return { 141 return {
139 type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", 142 type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg",
140 request: "launch", 143 request: "launch",
@@ -142,6 +145,7 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi
142 program: executable, 145 program: executable,
143 args: runnable.args.executableArgs, 146 args: runnable.args.executableArgs,
144 cwd: runnable.args.workspaceRoot, 147 cwd: runnable.args.workspaceRoot,
145 sourceFileMap: sourceFileMap, 148 sourceFileMap,
149 env,
146 }; 150 };
147} 151}
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index e16ea799c..494d51c83 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -5,8 +5,12 @@
5import * as lc from "vscode-languageclient"; 5import * as lc from "vscode-languageclient";
6 6
7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); 7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
8export const memoryUsage = new lc.RequestType<null, string, void>("rust-analyzer/memoryUsage");
8 9
9export const collectGarbage = new lc.RequestType<null, null, void>("rust-analyzer/collectGarbage"); 10export type Status = "loading" | "ready" | "invalid" | "needsReload";
11export const status = new lc.NotificationType<Status>("rust-analyzer/status");
12
13export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
10 14
11export interface SyntaxTreeParams { 15export interface SyntaxTreeParams {
12 textDocument: lc.TextDocumentIdentifier; 16 textDocument: lc.TextDocumentIdentifier;
@@ -60,6 +64,7 @@ export interface Runnable {
60 workspaceRoot?: string; 64 workspaceRoot?: string;
61 cargoArgs: string[]; 65 cargoArgs: string[];
62 executableArgs: string[]; 66 executableArgs: string[];
67 expectTest?: boolean;
63 }; 68 };
64} 69}
65export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("experimental/runnables"); 70export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("experimental/runnables");
@@ -88,6 +93,9 @@ export const inlayHints = new lc.RequestType<InlayHintsParams, InlayHint[], void
88export interface SsrParams { 93export interface SsrParams {
89 query: string; 94 query: string;
90 parseOnly: boolean; 95 parseOnly: boolean;
96 textDocument: lc.TextDocumentIdentifier;
97 position: lc.Position;
98 selections: lc.Range[];
91} 99}
92export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>('experimental/ssr'); 100export const ssr = new lc.RequestType<SsrParams, lc.WorkspaceEdit, void>('experimental/ssr');
93 101
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 5ceab8b44..bd99d696a 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -19,6 +19,16 @@ let ctx: Ctx | undefined;
19const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; 19const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
20 20
21export async function activate(context: vscode.ExtensionContext) { 21export async function activate(context: vscode.ExtensionContext) {
22 // For some reason vscode not always shows pop-up error notifications
23 // when an extension fails to activate, so we do it explicitly by ourselves.
24 // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242
25 await tryActivate(context).catch(err => {
26 void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
27 throw err;
28 });
29}
30
31async function tryActivate(context: vscode.ExtensionContext) {
22 // Register a "dumb" onEnter command for the case where server fails to 32 // Register a "dumb" onEnter command for the case where server fails to
23 // start. 33 // start.
24 // 34 //
@@ -44,13 +54,13 @@ export async function activate(context: vscode.ExtensionContext) {
44 const serverPath = await bootstrap(config, state).catch(err => { 54 const serverPath = await bootstrap(config, state).catch(err => {
45 let message = "bootstrap error. "; 55 let message = "bootstrap error. ";
46 56
47 if (err.code === "EBUSY" || err.code === "ETXTBSY") { 57 if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") {
48 message += "Other vscode windows might be using rust-analyzer, "; 58 message += "Other vscode windows might be using rust-analyzer, ";
49 message += "you should close them and reload this window to retry. "; 59 message += "you should close them and reload this window to retry. ";
50 } 60 }
51 61
52 message += 'Open "Help > Toggle Developer Tools > Console" to see the logs '; 62 message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
53 message += '(enable verbose logs with "rust-analyzer.trace.extension")'; 63 message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
54 64
55 log.error("Bootstrap error", err); 65 log.error("Bootstrap error", err);
56 throw new Error(message); 66 throw new Error(message);
@@ -58,9 +68,7 @@ export async function activate(context: vscode.ExtensionContext) {
58 68
59 const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; 69 const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
60 if (workspaceFolder === undefined) { 70 if (workspaceFolder === undefined) {
61 const err = "Cannot activate rust-analyzer when no folder is opened"; 71 throw new Error("no folder is opened");
62 void vscode.window.showErrorMessage(err);
63 throw new Error(err);
64 } 72 }
65 73
66 // Note: we try to start the server before we activate type hints so that it 74 // Note: we try to start the server before we activate type hints so that it
@@ -88,7 +96,8 @@ export async function activate(context: vscode.ExtensionContext) {
88 }); 96 });
89 97
90 ctx.registerCommand('analyzerStatus', commands.analyzerStatus); 98 ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
91 ctx.registerCommand('collectGarbage', commands.collectGarbage); 99 ctx.registerCommand('memoryUsage', commands.memoryUsage);
100 ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace);
92 ctx.registerCommand('matchingBrace', commands.matchingBrace); 101 ctx.registerCommand('matchingBrace', commands.matchingBrace);
93 ctx.registerCommand('joinLines', commands.joinLines); 102 ctx.registerCommand('joinLines', commands.joinLines);
94 ctx.registerCommand('parentModule', commands.parentModule); 103 ctx.registerCommand('parentModule', commands.parentModule);
@@ -152,13 +161,17 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
152 return; 161 return;
153 }; 162 };
154 163
155 const lastCheck = state.lastCheck;
156 const now = Date.now(); 164 const now = Date.now();
165 if (config.package.releaseTag === NIGHTLY_TAG) {
166 // Check if we should poll github api for the new nightly version
167 // if we haven't done it during the past hour
168 const lastCheck = state.lastCheck;
157 169
158 const anHour = 60 * 60 * 1000; 170 const anHour = 60 * 60 * 1000;
159 const shouldDownloadNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour; 171 const shouldCheckForNewNightly = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour;
160 172
161 if (!shouldDownloadNightly) return; 173 if (!shouldCheckForNewNightly) return;
174 }
162 175
163 const release = await fetchRelease("nightly").catch((e) => { 176 const release = await fetchRelease("nightly").catch((e) => {
164 log.error(e); 177 log.error(e);
@@ -202,7 +215,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
202 ); 215 );
203 } 216 }
204 217
205 log.debug("Using server binary at", path); 218 log.info("Using server binary at", path);
206 219
207 if (!isValidExecutable(path)) { 220 if (!isValidExecutable(path)) {
208 throw new Error(`Failed to execute ${path} --version`); 221 throw new Error(`Failed to execute ${path} --version`);
@@ -261,13 +274,13 @@ async function getServer(config: Config, state: PersistentState): Promise<string
261 }; 274 };
262 if (config.package.releaseTag === null) return "rust-analyzer"; 275 if (config.package.releaseTag === null) return "rust-analyzer";
263 276
264 let binaryName: string | undefined = undefined; 277 let platform: string | undefined;
265 if (process.arch === "x64" || process.arch === "ia32") { 278 if (process.arch === "x64" || process.arch === "ia32") {
266 if (process.platform === "linux") binaryName = "rust-analyzer-linux"; 279 if (process.platform === "linux") platform = "linux";
267 if (process.platform === "darwin") binaryName = "rust-analyzer-mac"; 280 if (process.platform === "darwin") platform = "mac";
268 if (process.platform === "win32") binaryName = "rust-analyzer-windows.exe"; 281 if (process.platform === "win32") platform = "windows";
269 } 282 }
270 if (binaryName === undefined) { 283 if (platform === undefined) {
271 vscode.window.showErrorMessage( 284 vscode.window.showErrorMessage(
272 "Unfortunately we don't ship binaries for your platform yet. " + 285 "Unfortunately we don't ship binaries for your platform yet. " +
273 "You need to manually clone rust-analyzer repository and " + 286 "You need to manually clone rust-analyzer repository and " +
@@ -278,8 +291,8 @@ async function getServer(config: Config, state: PersistentState): Promise<string
278 ); 291 );
279 return undefined; 292 return undefined;
280 } 293 }
281 294 const ext = platform === "windows" ? ".exe" : "";
282 const dest = path.join(config.globalStoragePath, binaryName); 295 const dest = path.join(config.globalStoragePath, `rust-analyzer-${platform}${ext}`);
283 const exists = await fs.stat(dest).then(() => true, () => false); 296 const exists = await fs.stat(dest).then(() => true, () => false);
284 if (!exists) { 297 if (!exists) {
285 await state.updateServerVersion(undefined); 298 await state.updateServerVersion(undefined);
@@ -296,7 +309,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
296 } 309 }
297 310
298 const release = await fetchRelease(config.package.releaseTag); 311 const release = await fetchRelease(config.package.releaseTag);
299 const artifact = release.assets.find(artifact => artifact.name === binaryName); 312 const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`);
300 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); 313 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
301 314
302 // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error. 315 // Unlinking the exe file before moving new one on its place should prevent ETXTBSY error.
@@ -308,6 +321,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
308 url: artifact.browser_download_url, 321 url: artifact.browser_download_url,
309 dest, 322 dest,
310 progressTitle: "Downloading rust-analyzer server", 323 progressTitle: "Downloading rust-analyzer server",
324 gunzip: true,
311 mode: 0o755 325 mode: 0o755
312 }); 326 });
313 327
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index 866092882..681eaa9c9 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -1,8 +1,12 @@
1import fetch from "node-fetch"; 1// Replace with `import fetch from "node-fetch"` once this is fixed in rollup:
2// https://github.com/rollup/plugins/issues/491
3const fetch = require("node-fetch") as typeof import("node-fetch")["default"];
4
2import * as vscode from "vscode"; 5import * as vscode from "vscode";
3import * as stream from "stream"; 6import * as stream from "stream";
4import * as crypto from "crypto"; 7import * as crypto from "crypto";
5import * as fs from "fs"; 8import * as fs from "fs";
9import * as zlib from "zlib";
6import * as util from "util"; 10import * as util from "util";
7import * as path from "path"; 11import * as path from "path";
8import { log, assert } from "./util"; 12import { log, assert } from "./util";
@@ -65,6 +69,7 @@ interface DownloadOpts {
65 url: string; 69 url: string;
66 dest: string; 70 dest: string;
67 mode?: number; 71 mode?: number;
72 gunzip?: boolean;
68} 73}
69 74
70export async function download(opts: DownloadOpts) { 75export async function download(opts: DownloadOpts) {
@@ -82,7 +87,7 @@ export async function download(opts: DownloadOpts) {
82 }, 87 },
83 async (progress, _cancellationToken) => { 88 async (progress, _cancellationToken) => {
84 let lastPercentage = 0; 89 let lastPercentage = 0;
85 await downloadFile(opts.url, tempFile, opts.mode, (readBytes, totalBytes) => { 90 await downloadFile(opts.url, tempFile, opts.mode, !!opts.gunzip, (readBytes, totalBytes) => {
86 const newPercentage = (readBytes / totalBytes) * 100; 91 const newPercentage = (readBytes / totalBytes) * 100;
87 progress.report({ 92 progress.report({
88 message: newPercentage.toFixed(0) + "%", 93 message: newPercentage.toFixed(0) + "%",
@@ -97,16 +102,11 @@ export async function download(opts: DownloadOpts) {
97 await fs.promises.rename(tempFile, opts.dest); 102 await fs.promises.rename(tempFile, opts.dest);
98} 103}
99 104
100/**
101 * Downloads file from `url` and stores it at `destFilePath` with `mode` (unix permissions).
102 * `onProgress` callback is called on recieveing each chunk of bytes
103 * to track the progress of downloading, it gets the already read and total
104 * amount of bytes to read as its parameters.
105 */
106async function downloadFile( 105async function downloadFile(
107 url: string, 106 url: string,
108 destFilePath: fs.PathLike, 107 destFilePath: fs.PathLike,
109 mode: number | undefined, 108 mode: number | undefined,
109 gunzip: boolean,
110 onProgress: (readBytes: number, totalBytes: number) => void 110 onProgress: (readBytes: number, totalBytes: number) => void
111): Promise<void> { 111): Promise<void> {
112 const res = await fetch(url); 112 const res = await fetch(url);
@@ -130,7 +130,10 @@ async function downloadFile(
130 }); 130 });
131 131
132 const destFileStream = fs.createWriteStream(destFilePath, { mode }); 132 const destFileStream = fs.createWriteStream(destFilePath, { mode });
133 await pipeline(res.body, destFileStream); 133 const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
134
135 await pipeline(srcStream, destFileStream);
136
134 await new Promise<void>(resolve => { 137 await new Promise<void>(resolve => {
135 destFileStream.on("close", resolve); 138 destFileStream.on("close", resolve);
136 destFileStream.destroy(); 139 destFileStream.destroy();
diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts
index 138d11b89..5705eed81 100644
--- a/editors/code/src/persistent_state.ts
+++ b/editors/code/src/persistent_state.ts
@@ -4,7 +4,7 @@ import { log } from './util';
4export class PersistentState { 4export class PersistentState {
5 constructor(private readonly globalState: vscode.Memento) { 5 constructor(private readonly globalState: vscode.Memento) {
6 const { lastCheck, releaseId, serverVersion } = this; 6 const { lastCheck, releaseId, serverVersion } = this;
7 log.debug("PersistentState: ", { lastCheck, releaseId, serverVersion }); 7 log.info("PersistentState:", { lastCheck, releaseId, serverVersion });
8 } 8 }
9 9
10 /** 10 /**
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 766b05112..de68f27ae 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -5,7 +5,7 @@ import * as tasks from './tasks';
5 5
6import { Ctx } from './ctx'; 6import { Ctx } from './ctx';
7import { makeDebugConfig } from './debug'; 7import { makeDebugConfig } from './debug';
8import { Config } from './config'; 8import { Config, RunnableEnvCfg } from './config';
9 9
10const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; 10const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }];
11 11
@@ -96,6 +96,30 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
96 } 96 }
97} 97}
98 98
99export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg): Record<string, string> {
100 const env: Record<string, string> = { "RUST_BACKTRACE": "short" };
101
102 if (runnable.args.expectTest) {
103 env["UPDATE_EXPECT"] = "1";
104 }
105
106 Object.assign(env, process.env as { [key: string]: string });
107
108 if (runnableEnvCfg) {
109 if (Array.isArray(runnableEnvCfg)) {
110 for (const it of runnableEnvCfg) {
111 if (!it.mask || new RegExp(it.mask).test(runnable.label)) {
112 Object.assign(env, it.env);
113 }
114 }
115 } else {
116 Object.assign(env, runnableEnvCfg);
117 }
118 }
119
120 return env;
121}
122
99export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> { 123export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
100 if (runnable.kind !== "cargo") { 124 if (runnable.kind !== "cargo") {
101 // rust-analyzer supports only one kind, "cargo" 125 // rust-analyzer supports only one kind, "cargo"
@@ -108,12 +132,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
108 if (runnable.args.executableArgs.length > 0) { 132 if (runnable.args.executableArgs.length > 0) {
109 args.push('--', ...runnable.args.executableArgs); 133 args.push('--', ...runnable.args.executableArgs);
110 } 134 }
135
111 const definition: tasks.CargoTaskDefinition = { 136 const definition: tasks.CargoTaskDefinition = {
112 type: tasks.TASK_TYPE, 137 type: tasks.TASK_TYPE,
113 command: args[0], // run, test, etc... 138 command: args[0], // run, test, etc...
114 args: args.slice(1), 139 args: args.slice(1),
115 cwd: runnable.args.workspaceRoot, 140 cwd: runnable.args.workspaceRoot || ".",
116 env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), 141 env: prepareEnv(runnable, config.runnableEnv),
117 }; 142 };
118 143
119 const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() 144 const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts
index bcb3f2cc7..258b49982 100644
--- a/editors/code/src/snippets.ts
+++ b/editors/code/src/snippets.ts
@@ -6,6 +6,10 @@ export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
6 assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`); 6 assert(edit.entries().length === 1, `bad ws edit: ${JSON.stringify(edit)}`);
7 const [uri, edits] = edit.entries()[0]; 7 const [uri, edits] = edit.entries()[0];
8 8
9 if (vscode.window.activeTextEditor?.document.uri !== uri) {
10 // `vscode.window.visibleTextEditors` only contains editors whose contents are being displayed
11 await vscode.window.showTextDocument(uri, {});
12 }
9 const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString()); 13 const editor = vscode.window.visibleTextEditors.find((it) => it.document.uri.toString() === uri.toString());
10 if (!editor) return; 14 if (!editor) return;
11 await applySnippetTextEdits(editor, edits); 15 await applySnippetTextEdits(editor, edits);
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index fec4c3295..970fedb37 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -2,6 +2,7 @@ import * as lc from "vscode-languageclient";
2import * as vscode from "vscode"; 2import * as vscode from "vscode";
3import { strict as nativeAssert } from "assert"; 3import { strict as nativeAssert } from "assert";
4import { spawnSync } from "child_process"; 4import { spawnSync } from "child_process";
5import { inspect } from "util";
5 6
6export function assert(condition: boolean, explanation: string): asserts condition { 7export function assert(condition: boolean, explanation: string): asserts condition {
7 try { 8 try {
@@ -14,21 +15,46 @@ export function assert(condition: boolean, explanation: string): asserts conditi
14 15
15export const log = new class { 16export const log = new class {
16 private enabled = true; 17 private enabled = true;
18 private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
17 19
18 setEnabled(yes: boolean): void { 20 setEnabled(yes: boolean): void {
19 log.enabled = yes; 21 log.enabled = yes;
20 } 22 }
21 23
22 debug(message?: any, ...optionalParams: any[]): void { 24 // Hint: the type [T, ...T[]] means a non-empty array
25 debug(...msg: [unknown, ...unknown[]]): void {
23 if (!log.enabled) return; 26 if (!log.enabled) return;
24 // eslint-disable-next-line no-console 27 log.write("DEBUG", ...msg);
25 console.log(message, ...optionalParams); 28 log.output.toString();
26 } 29 }
27 30
28 error(message?: any, ...optionalParams: any[]): void { 31 info(...msg: [unknown, ...unknown[]]): void {
32 log.write("INFO", ...msg);
33 }
34
35 warn(...msg: [unknown, ...unknown[]]): void {
36 debugger;
37 log.write("WARN", ...msg);
38 }
39
40 error(...msg: [unknown, ...unknown[]]): void {
29 debugger; 41 debugger;
30 // eslint-disable-next-line no-console 42 log.write("ERROR", ...msg);
31 console.error(message, ...optionalParams); 43 log.output.show(true);
44 }
45
46 private write(label: string, ...messageParts: unknown[]): void {
47 const message = messageParts.map(log.stringify).join(" ");
48 const dateTime = new Date().toLocaleString();
49 log.output.appendLine(`${label} [${dateTime}]: ${message}`);
50 }
51
52 private stringify(val: unknown): string {
53 if (typeof val === "string") return val;
54 return inspect(val, {
55 colors: false,
56 depth: 6, // heuristic
57 });
32 } 58 }
33}; 59};
34 60
@@ -46,7 +72,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
46 ); 72 );
47 } catch (error) { 73 } catch (error) {
48 if (delay === null) { 74 if (delay === null) {
49 log.error("LSP request timed out", { method: reqType.method, param, error }); 75 log.warn("LSP request timed out", { method: reqType.method, param, error });
50 throw error; 76 throw error;
51 } 77 }
52 78
@@ -55,7 +81,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
55 } 81 }
56 82
57 if (error.code !== lc.ErrorCodes.ContentModified) { 83 if (error.code !== lc.ErrorCodes.ContentModified) {
58 log.error("LSP request failed", { method: reqType.method, param, error }); 84 log.warn("LSP request failed", { method: reqType.method, param, error });
59 throw error; 85 throw error;
60 } 86 }
61 87
@@ -89,7 +115,8 @@ export function isValidExecutable(path: string): boolean {
89 115
90 const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); 116 const res = spawnSync(path, ["--version"], { encoding: 'utf8' });
91 117
92 log.debug(res, "--version output:", res.output); 118 const printOutput = res.error && (res.error as any).code !== 'ENOENT' ? log.warn : log.debug;
119 printOutput(path, "--version:", res);
93 120
94 return res.status === 0; 121 return res.status === 0;
95} 122}
diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts
index 5165720b4..b7d8d2144 100644
--- a/editors/code/tests/unit/index.ts
+++ b/editors/code/tests/unit/index.ts
@@ -1,6 +1,6 @@
1import * as path from 'path'; 1import * as path from 'path';
2import Mocha from 'mocha'; 2import * as Mocha from 'mocha';
3import glob from 'glob'; 3import * as glob from 'glob';
4 4
5export function run(): Promise<void> { 5export function run(): Promise<void> {
6 // Create the mocha test 6 // Create the mocha test
diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts
new file mode 100644
index 000000000..f2f53e91a
--- /dev/null
+++ b/editors/code/tests/unit/runnable_env.test.ts
@@ -0,0 +1,118 @@
1import * as assert from 'assert';
2import { prepareEnv } from '../../src/run';
3import { RunnableEnvCfg } from '../../src/config';
4import * as ra from '../../src/lsp_ext';
5
6function makeRunnable(label: string): ra.Runnable {
7 return {
8 label,
9 kind: "cargo",
10 args: {
11 cargoArgs: [],
12 executableArgs: []
13 }
14 };
15}
16
17function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> {
18 const runnable = makeRunnable(runnableName);
19 return prepareEnv(runnable, config);
20}
21
22suite('Runnable env', () => {
23 test('Global config works', () => {
24 const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" });
25 assert.equal(binEnv["GLOBAL"], "g");
26
27 const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" });
28 assert.equal(testEnv["GLOBAL"], "g");
29 });
30
31 test('null mask works', () => {
32 const config = [
33 {
34 env: { DATA: "data" }
35 }
36 ];
37 const binEnv = fakePrepareEnv("run project_name", config);
38 assert.equal(binEnv["DATA"], "data");
39
40 const testEnv = fakePrepareEnv("test some::mod::test_name", config);
41 assert.equal(testEnv["DATA"], "data");
42 });
43
44 test('order works', () => {
45 const config = [
46 {
47 env: { DATA: "data" }
48 },
49 {
50 env: { DATA: "newdata" }
51 }
52 ];
53 const binEnv = fakePrepareEnv("run project_name", config);
54 assert.equal(binEnv["DATA"], "newdata");
55
56 const testEnv = fakePrepareEnv("test some::mod::test_name", config);
57 assert.equal(testEnv["DATA"], "newdata");
58 });
59
60 test('mask works', () => {
61 const config = [
62 {
63 env: { DATA: "data" }
64 },
65 {
66 mask: "^run",
67 env: { DATA: "rundata" }
68 },
69 {
70 mask: "special_test$",
71 env: { DATA: "special_test" }
72 }
73 ];
74 const binEnv = fakePrepareEnv("run project_name", config);
75 assert.equal(binEnv["DATA"], "rundata");
76
77 const testEnv = fakePrepareEnv("test some::mod::test_name", config);
78 assert.equal(testEnv["DATA"], "data");
79
80 const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config);
81 assert.equal(specialTestEnv["DATA"], "special_test");
82 });
83
84 test('exact test name works', () => {
85 const config = [
86 {
87 env: { DATA: "data" }
88 },
89 {
90 mask: "some::mod::test_name",
91 env: { DATA: "test special" }
92 }
93 ];
94 const testEnv = fakePrepareEnv("test some::mod::test_name", config);
95 assert.equal(testEnv["DATA"], "test special");
96
97 const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
98 assert.equal(specialTestEnv["DATA"], "data");
99 });
100
101 test('test mod name works', () => {
102 const config = [
103 {
104 env: { DATA: "data" }
105 },
106 {
107 mask: "some::mod",
108 env: { DATA: "mod special" }
109 }
110 ];
111 const testEnv = fakePrepareEnv("test some::mod::test_name", config);
112 assert.equal(testEnv["DATA"], "mod special");
113
114 const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
115 assert.equal(specialTestEnv["DATA"], "mod special");
116 });
117
118});
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index 32d1a865f..c9f348241 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -6,8 +6,6 @@
6 "lib": [ 6 "lib": [
7 "es2019" 7 "es2019"
8 ], 8 ],
9 "esModuleInterop": true,
10 "allowSyntheticDefaultImports": true,
11 "sourceMap": true, 9 "sourceMap": true,
12 "rootDir": ".", 10 "rootDir": ".",
13 "strict": true, 11 "strict": true,
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index a8b9b010d..8140da87f 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -4,13 +4,16 @@ name = "xtask"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
10 11
11[dependencies] 12[dependencies]
12walkdir = "2.3.1" 13anyhow = "1.0.26"
14flate2 = "1.0"
13pico-args = "0.3.1" 15pico-args = "0.3.1"
14quote = "1.0.2"
15proc-macro2 = "1.0.8" 16proc-macro2 = "1.0.8"
16anyhow = "1.0.26" 17quote = "1.0.2"
18ungrammar = "0.1.0"
19walkdir = "2.3.1"
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 392648d71..114898e38 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -93,19 +93,19 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
93 ], 93 ],
94 nodes: &[ 94 nodes: &[
95 "SOURCE_FILE", 95 "SOURCE_FILE",
96 "STRUCT_DEF", 96 "STRUCT",
97 "UNION_DEF", 97 "UNION",
98 "ENUM_DEF", 98 "ENUM",
99 "FN_DEF", 99 "FN",
100 "RET_TYPE", 100 "RET_TYPE",
101 "EXTERN_CRATE_ITEM", 101 "EXTERN_CRATE",
102 "MODULE", 102 "MODULE",
103 "USE_ITEM", 103 "USE",
104 "STATIC_DEF", 104 "STATIC",
105 "CONST_DEF", 105 "CONST",
106 "TRAIT_DEF", 106 "TRAIT",
107 "IMPL_DEF", 107 "IMPL",
108 "TYPE_ALIAS_DEF", 108 "TYPE_ALIAS",
109 "MACRO_CALL", 109 "MACRO_CALL",
110 "TOKEN_TREE", 110 "TOKEN_TREE",
111 "MACRO_DEF", 111 "MACRO_DEF",
@@ -159,9 +159,9 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
159 "MATCH_ARM_LIST", 159 "MATCH_ARM_LIST",
160 "MATCH_ARM", 160 "MATCH_ARM",
161 "MATCH_GUARD", 161 "MATCH_GUARD",
162 "RECORD_LIT", 162 "RECORD_EXPR",
163 "RECORD_FIELD_LIST", 163 "RECORD_EXPR_FIELD_LIST",
164 "RECORD_FIELD", 164 "RECORD_EXPR_FIELD",
165 "EFFECT_EXPR", 165 "EFFECT_EXPR",
166 "BOX_EXPR", 166 "BOX_EXPR",
167 // postfix 167 // postfix
@@ -179,13 +179,14 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
179 "BIN_EXPR", 179 "BIN_EXPR",
180 "EXTERN_BLOCK", 180 "EXTERN_BLOCK",
181 "EXTERN_ITEM_LIST", 181 "EXTERN_ITEM_LIST",
182 "ENUM_VARIANT", 182 "VARIANT",
183 "RECORD_FIELD_DEF_LIST", 183 "RECORD_FIELD_LIST",
184 "RECORD_FIELD_DEF", 184 "RECORD_FIELD",
185 "TUPLE_FIELD_DEF_LIST", 185 "TUPLE_FIELD_LIST",
186 "TUPLE_FIELD_DEF", 186 "TUPLE_FIELD",
187 "ENUM_VARIANT_LIST", 187 "VARIANT_LIST",
188 "ITEM_LIST", 188 "ITEM_LIST",
189 "ASSOC_ITEM_LIST",
189 "ATTR", 190 "ATTR",
190 "META_ITEM", // not an item actually 191 "META_ITEM", // not an item actually
191 "USE_TREE", 192 "USE_TREE",
@@ -193,7 +194,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
193 "PATH", 194 "PATH",
194 "PATH_SEGMENT", 195 "PATH_SEGMENT",
195 "LITERAL", 196 "LITERAL",
196 "ALIAS", 197 "RENAME",
197 "VISIBILITY", 198 "VISIBILITY",
198 "WHERE_CLAUSE", 199 "WHERE_CLAUSE",
199 "WHERE_PRED", 200 "WHERE_PRED",
@@ -202,7 +203,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
202 "NAME_REF", 203 "NAME_REF",
203 "LET_STMT", 204 "LET_STMT",
204 "EXPR_STMT", 205 "EXPR_STMT",
205 "TYPE_PARAM_LIST", 206 "GENERIC_PARAM_LIST",
207 "GENERIC_PARAM",
206 "LIFETIME_PARAM", 208 "LIFETIME_PARAM",
207 "TYPE_PARAM", 209 "TYPE_PARAM",
208 "CONST_PARAM", 210 "CONST_PARAM",
@@ -223,2021 +225,37 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
223 ], 225 ],
224}; 226};
225 227
226pub(crate) struct AstSrc<'a> { 228#[derive(Default, Debug)]
227 pub(crate) tokens: &'a [&'a str], 229pub(crate) struct AstSrc {
228 pub(crate) nodes: &'a [AstNodeSrc<'a>], 230 pub(crate) tokens: Vec<String>,
229 pub(crate) enums: &'a [AstEnumSrc<'a>], 231 pub(crate) nodes: Vec<AstNodeSrc>,
230} 232 pub(crate) enums: Vec<AstEnumSrc>,
231
232pub(crate) struct AstNodeSrc<'a> {
233 pub(crate) doc: &'a [&'a str],
234 pub(crate) name: &'a str,
235 pub(crate) traits: &'a [&'a str],
236 pub(crate) fields: &'a [Field<'a>],
237}
238
239pub(crate) enum Field<'a> {
240 Token(&'a str),
241 Node { name: &'a str, src: FieldSrc<'a> },
242}
243
244pub(crate) enum FieldSrc<'a> {
245 Shorthand,
246 Optional(&'a str),
247 Many(&'a str),
248} 233}
249 234
250pub(crate) struct AstEnumSrc<'a> { 235#[derive(Debug)]
251 pub(crate) doc: &'a [&'a str], 236pub(crate) struct AstNodeSrc {
252 pub(crate) name: &'a str, 237 pub(crate) doc: Vec<String>,
253 pub(crate) traits: &'a [&'a str], 238 pub(crate) name: String,
254 pub(crate) variants: &'a [&'a str], 239 pub(crate) traits: Vec<String>,
240 pub(crate) fields: Vec<Field>,
255} 241}
256 242
257macro_rules! ast_nodes { 243#[derive(Debug, Eq, PartialEq)]
258 ($( 244pub(crate) enum Field {
259 $(#[doc = $doc:expr])+ 245 Token(String),
260 struct $name:ident$(: $($trait:ident),*)? { 246 Node { name: String, ty: String, cardinality: Cardinality },
261 $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)?
262 }
263 )*) => {
264 [$(
265 AstNodeSrc {
266 doc: &[$($doc),*],
267 name: stringify!($name),
268 traits: &[$($(stringify!($trait)),*)?],
269 fields: &[
270 $(field!($(T![$token])? $field_name $($ty)?)),*
271 ],
272
273 }
274 ),*]
275 };
276} 247}
277 248
278macro_rules! field { 249#[derive(Debug, Eq, PartialEq)]
279 (T![$token:tt] T) => { 250pub(crate) enum Cardinality {
280 Field::Token(stringify!($token)) 251 Optional,
281 }; 252 Many,
282 ($field_name:ident) => {
283 Field::Node { name: stringify!($field_name), src: FieldSrc::Shorthand }
284 };
285 ($field_name:ident [$ty:ident]) => {
286 Field::Node { name: stringify!($field_name), src: FieldSrc::Many(stringify!($ty)) }
287 };
288 ($field_name:ident $ty:ident) => {
289 Field::Node { name: stringify!($field_name), src: FieldSrc::Optional(stringify!($ty)) }
290 };
291} 253}
292 254
293macro_rules! ast_enums { 255#[derive(Debug)]
294 ($( 256pub(crate) struct AstEnumSrc {
295 $(#[doc = $doc:expr])+ 257 pub(crate) doc: Vec<String>,
296 enum $name:ident $(: $($trait:ident),*)? { 258 pub(crate) name: String,
297 $($variant:ident),*$(,)? 259 pub(crate) traits: Vec<String>,
298 } 260 pub(crate) variants: Vec<String>,
299 )*) => {
300 [$(
301 AstEnumSrc {
302 doc: &[$($doc),*],
303 name: stringify!($name),
304 traits: &[$($(stringify!($trait)),*)?],
305 variants: &[$(stringify!($variant)),*],
306 }
307 ),*]
308 };
309} 261}
310
311pub(crate) const AST_SRC: AstSrc = AstSrc {
312 tokens: &["Whitespace", "Comment", "String", "RawString"],
313 nodes: &ast_nodes! {
314 /// The entire Rust source file. Includes all top-level inner attributes and module items.
315 ///
316 /// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
317 struct SourceFile: ModuleItemOwner, AttrsOwner, DocCommentsOwner {
318 modules: [Module],
319 }
320
321 /// Function definition either with body or not.
322 /// Includes all of its attributes and doc comments.
323 ///
324 /// ```
325 /// ❰
326 /// /// Docs
327 /// #[attr]
328 /// pub extern "C" fn foo<T>(#[attr] Patern {p}: Pattern) -> u32
329 /// where
330 /// T: Debug
331 /// {
332 /// 42
333 /// }
334 /// ❱
335 ///
336 /// extern "C" {
337 /// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱
338 /// }
339 /// ```
340 ///
341 /// - [Reference](https://doc.rust-lang.org/reference/items/functions.html)
342 /// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions)
343 struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner {
344 Abi,
345 T![const],
346 T![default],
347 T![async],
348 T![unsafe],
349 T![fn],
350 ParamList,
351 RetType,
352 body: BlockExpr,
353 T![;]
354 }
355
356 /// Return type annotation.
357 ///
358 /// ```
359 /// fn foo(a: u32) ❰ -> Option<u32> ❱ { Some(a) }
360 /// ```
361 ///
362 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
363 struct RetType { T![->], TypeRef }
364
365 /// Struct definition.
366 /// Includes all of its attributes and doc comments.
367 ///
368 /// ```
369 /// ❰
370 /// /// Docs
371 /// #[attr]
372 /// struct Foo<T> where T: Debug {
373 /// /// Docs
374 /// #[attr]
375 /// pub a: u32,
376 /// b: T,
377 /// }
378 /// ❱
379 ///
380 /// ❰ struct Foo; ❱
381 /// ❰ struct Foo<T>(#[attr] T) where T: Debug; ❱
382 /// ```
383 ///
384 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
385 struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
386 T![struct],
387 FieldDefList,
388 T![;]
389 }
390
391 /// Union definition.
392 /// Includes all of its attributes and doc comments.
393 ///
394 /// ```
395 /// ❰
396 /// /// Docs
397 /// #[attr]
398 /// pub union Foo<T> where T: Debug {
399 /// /// Docs
400 /// #[attr]
401 /// a: T,
402 /// b: u32,
403 /// }
404 /// ❱
405 /// ```
406 ///
407 /// [Reference](https://doc.rust-lang.org/reference/items/unions.html)
408 struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
409 T![union],
410 RecordFieldDefList,
411 }
412
413 /// Record field definition list including enclosing curly braces.
414 ///
415 /// ```
416 /// struct Foo // same for union
417 /// ❰
418 /// {
419 /// a: u32,
420 /// b: bool,
421 /// }
422 /// ❱
423 /// ```
424 ///
425 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
426 struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] }
427
428 /// Record field definition including its attributes and doc comments.
429 ///
430 /// ` ``
431 /// same for union
432 /// struct Foo {
433 /// ❰
434 /// /// Docs
435 /// #[attr]
436 /// pub a: u32
437 /// ❱
438 ///
439 /// ❰ b: bool ❱
440 /// }
441 /// ```
442 ///
443 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
444 struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { }
445
446 /// Tuple field definition list including enclosing parens.
447 ///
448 /// ```
449 /// struct Foo ❰ (u32, String, Vec<u32>) ❱;
450 /// ```
451 ///
452 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
453 struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] }
454
455 /// Tuple field definition including its attributes.
456 ///
457 /// ```
458 /// struct Foo(❰ #[attr] u32 ❱);
459 /// ```
460 ///
461 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
462 struct TupleFieldDef: VisibilityOwner, AttrsOwner {
463 TypeRef,
464 }
465
466 /// Enum definition.
467 /// Includes all of its attributes and doc comments.
468 ///
469 /// ```
470 /// ❰
471 /// /// Docs
472 /// #[attr]
473 /// pub enum Foo<T> where T: Debug {
474 /// /// Docs
475 /// #[attr]
476 /// Bar,
477 /// Baz(#[attr] u32),
478 /// Bruh {
479 /// a: u32,
480 /// /// Docs
481 /// #[attr]
482 /// b: T,
483 /// }
484 /// }
485 /// ❱
486 /// ```
487 ///
488 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
489 struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
490 T![enum],
491 variant_list: EnumVariantList,
492 }
493
494 /// Enum variant definition list including enclosing curly braces.
495 ///
496 /// ```
497 /// enum Foo
498 /// ❰
499 /// {
500 /// Bar,
501 /// Baz(u32),
502 /// Bruh {
503 /// a: u32
504 /// }
505 /// }
506 /// ❱
507 /// ```
508 ///
509 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
510 struct EnumVariantList {
511 T!['{'],
512 variants: [EnumVariant],
513 T!['}']
514 }
515
516 /// Enum variant definition including its attributes and discriminant value definition.
517 ///
518 /// ```
519 /// enum Foo {
520 /// ❰
521 /// /// Docs
522 /// #[attr]
523 /// Bar
524 /// ❱
525 ///
526 /// // same for tuple and record variants
527 /// }
528 /// ```
529 ///
530 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
531 struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner {
532 FieldDefList,
533 T![=],
534 Expr
535 }
536
537 /// Trait definition.
538 /// Includes all of its attributes and doc comments.
539 ///
540 /// ```
541 /// ❰
542 /// /// Docs
543 /// #[attr]
544 /// pub unsafe trait Foo<T>: Debug where T: Debug {
545 /// // ...
546 /// }
547 /// ❱
548 /// ```
549 ///
550 /// [Reference](https://doc.rust-lang.org/reference/items/traits.html)
551 struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner {
552 T![unsafe],
553 T![auto],
554 T![trait],
555 ItemList,
556 }
557
558 /// Module definition either with body or not.
559 /// Includes all of its inner and outer attributes, module items, doc comments.
560 ///
561 /// ```
562 /// ❰
563 /// /// Docs
564 /// #[attr]
565 /// pub mod foo;
566 /// ❱
567 ///
568 /// ❰
569 /// /// Docs
570 /// #[attr]
571 /// pub mod bar {
572 /// //! Inner docs
573 /// #![inner_attr]
574 /// }
575 /// ❱
576 /// ```
577 ///
578 /// [Reference](https://doc.rust-lang.org/reference/items/modules.html)
579 struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner {
580 T![mod],
581 ItemList,
582 T![;]
583 }
584
585 /// Item defintion list.
586 /// This is used for both top-level items and impl block items.
587 ///
588 /// ```
589 /// ❰
590 /// fn foo {}
591 /// struct Bar;
592 /// enum Baz;
593 /// trait Bruh;
594 /// const BRUUH: u32 = 42;
595 /// ❱
596 ///
597 /// impl Foo
598 /// ❰
599 /// {
600 /// fn bar() {}
601 /// const BAZ: u32 = 42;
602 /// }
603 /// ❱
604 /// ```
605 ///
606 /// [Reference](https://doc.rust-lang.org/reference/items.html)
607 struct ItemList: ModuleItemOwner {
608 T!['{'],
609 assoc_items: [AssocItem],
610 T!['}']
611 }
612
613 /// Constant variable definition.
614 /// Includes all of its attributes and doc comments.
615 ///
616 /// ```
617 /// ❰
618 /// /// Docs
619 /// #[attr]
620 /// pub const FOO: u32 = 42;
621 /// ❱
622 /// ```
623 ///
624 /// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html)
625 struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
626 T![default],
627 T![const],
628 T![=],
629 body: Expr,
630 T![;]
631 }
632
633
634 /// Static variable definition.
635 /// Includes all of its attributes and doc comments.
636 ///
637 /// ```
638 /// ❰
639 /// /// Docs
640 /// #[attr]
641 /// pub static mut FOO: u32 = 42;
642 /// ❱
643 /// ```
644 ///
645 /// [Reference](https://doc.rust-lang.org/reference/items/static-items.html)
646 struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
647 T![static],
648 T![mut],
649 T![=],
650 body: Expr,
651 T![;]
652 }
653
654 /// Type alias definition.
655 /// Includes associated type clauses with type bounds.
656 ///
657 /// ```
658 /// ❰
659 /// /// Docs
660 /// #[attr]
661 /// pub type Foo<T> where T: Debug = T;
662 /// ❱
663 ///
664 /// trait Bar {
665 /// ❰ type Baz: Debug; ❱
666 /// ❰ type Bruh = String; ❱
667 /// ❰ type Bruuh: Debug = u32; ❱
668 /// }
669 /// ```
670 ///
671 /// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html)
672 struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner {
673 T![default],
674 T![type],
675 T![=],
676 TypeRef,
677 T![;]
678 }
679
680 /// Inherent and trait impl definition.
681 /// Includes all of its inner and outer attributes.
682 ///
683 /// ```
684 /// ❰
685 /// #[attr]
686 /// unsafe impl<T> const !Foo for Bar where T: Debug {
687 /// #![inner_attr]
688 /// // ...
689 /// }
690 /// ❱
691 /// ```
692 ///
693 /// [Reference](https://doc.rust-lang.org/reference/items/implementations.html)
694 struct ImplDef: TypeParamsOwner, AttrsOwner, DocCommentsOwner {
695 T![default],
696 T![const],
697 T![unsafe],
698 T![impl],
699 T![!],
700 T![for],
701 ItemList,
702 }
703
704
705 /// Parenthesized type reference.
706 /// Note: parens are only used for grouping, this is not a tuple type.
707 ///
708 /// ```
709 /// // This is effectively just `u32`.
710 /// // Single-item tuple must be defined with a trailing comma: `(u32,)`
711 /// type Foo = ❰ (u32) ❱;
712 ///
713 /// let bar: &'static ❰ (dyn Debug) ❱ = "bruh";
714 /// ```
715 struct ParenType { T!['('], TypeRef, T![')'] }
716
717 /// Unnamed tuple type.
718 ///
719 /// ```
720 /// let foo: ❰ (u32, bool) ❱ = (42, true);
721 /// ```
722 ///
723 /// [Reference](https://doc.rust-lang.org/reference/types/tuple.html)
724 struct TupleType { T!['('], fields: [TypeRef], T![')'] }
725
726 /// The never type (i.e. the exclamation point).
727 ///
728 /// ```
729 /// type T = ❰ ! ❱;
730 ///
731 /// fn no_return() -> ❰ ! ❱ {
732 /// loop {}
733 /// }
734 /// ```
735 ///
736 /// [Reference](https://doc.rust-lang.org/reference/types/never.html)
737 struct NeverType { T![!] }
738
739 /// Path to a type.
740 /// Includes single identifier type names and elaborate paths with
741 /// generic parameters.
742 ///
743 /// ```
744 /// type Foo = ❰ String ❱;
745 /// type Bar = ❰ std::vec::Vec<T> ❱;
746 /// type Baz = ❰ ::bruh::<Bruuh as Iterator>::Item ❱;
747 /// ```
748 ///
749 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
750 struct PathType { Path }
751
752 /// Raw pointer type.
753 ///
754 /// ```
755 /// type Foo = ❰ *const u32 ❱;
756 /// type Bar = ❰ *mut u32 ❱;
757 /// ```
758 ///
759 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut)
760 struct PointerType { T![*], T![const], T![mut], TypeRef }
761
762 /// Array type.
763 ///
764 /// ```
765 /// type Foo = ❰ [u32; 24 - 3] ❱;
766 /// ```
767 ///
768 /// [Reference](https://doc.rust-lang.org/reference/types/array.html)
769 struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] }
770
771 /// Slice type.
772 ///
773 /// ```
774 /// type Foo = ❰ [u8] ❱;
775 /// ```
776 ///
777 /// [Reference](https://doc.rust-lang.org/reference/types/slice.html)
778 struct SliceType { T!['['], TypeRef, T![']'] }
779
780 /// Reference type.
781 ///
782 /// ```
783 /// type Foo = ❰ &'static str ❱;
784 /// ```
785 ///
786 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html)
787 struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef }
788
789 /// Placeholder type (i.e. the underscore).
790 ///
791 /// ```
792 /// let foo: ❰ _ ❱ = 42_u32;
793 /// ```
794 ///
795 /// [Reference](https://doc.rust-lang.org/reference/types/inferred.html)
796 struct PlaceholderType { T![_] }
797
798 /// Function pointer type (not to be confused with `Fn*` family of traits).
799 ///
800 /// ```
801 /// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱;
802 ///
803 /// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱;
804 /// ```
805 ///
806 /// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html)
807 struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType }
808
809 /// Higher order type.
810 ///
811 /// ```
812 /// type Foo = ❰ for<'a> fn(&'a str) ❱;
813 /// ```
814 ///
815 /// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html)
816 struct ForType { T![for], TypeParamList, TypeRef }
817
818 /// Opaque `impl Trait` type.
819 ///
820 /// ```
821 /// fn foo(bar: ❰ impl Debug + Eq ❱) {}
822 /// ```
823 ///
824 /// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html)
825 struct ImplTraitType: TypeBoundsOwner { T![impl] }
826
827 /// Trait object type.
828 ///
829 /// ```
830 /// type Foo = ❰ dyn Debug ❱;
831 /// ```
832 ///
833 /// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html)
834 struct DynTraitType: TypeBoundsOwner { T![dyn] }
835
836 /// Tuple literal.
837 ///
838 /// ```
839 /// ❰ (42, true) ❱;
840 /// ```
841 ///
842 /// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html)
843 struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] }
844
845 /// Array literal.
846 ///
847 /// ```
848 /// ❰ [#![inner_attr] true, false, true] ❱;
849 ///
850 /// ❰ ["baz"; 24] ❱;
851 /// ```
852 ///
853 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
854 struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] }
855
856 /// Parenthesized expression.
857 /// Note: parens are only used for grouping, this is not a tuple literal.
858 ///
859 /// ```
860 /// ❰ (#![inner_attr] 2 + 2) ❱ * 2;
861 /// ```
862 ///
863 /// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html)
864 struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] }
865
866 /// Path to a symbol in expression context.
867 /// Includes single identifier variable names and elaborate paths with
868 /// generic parameters.
869 ///
870 /// ```
871 /// ❰ Some::<i32> ❱;
872 /// ❰ foo ❱ + 42;
873 /// ❰ Vec::<i32>::push ❱;
874 /// ❰ <[i32]>::reverse ❱;
875 /// ❰ <String as std::borrow::Borrow<str>>::borrow ❱;
876 /// ```
877 ///
878 /// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html)
879 struct PathExpr { Path }
880
881 /// Anonymous callable object literal a.k.a. closure, lambda or functor.
882 ///
883 /// ```
884 /// ❰ || 42 ❱;
885 /// ❰ |a: u32| val + 1 ❱;
886 /// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱;
887 /// ❰ move || baz ❱;
888 /// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱
889 /// ```
890 ///
891 /// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html)
892 struct LambdaExpr: AttrsOwner {
893 T![static], // Note(@matklad): I belive this is (used to be?) syntax for generators
894 T![async],
895 T![move],
896 ParamList,
897 RetType,
898 body: Expr,
899 }
900
901 /// If expression. Includes both regular `if` and `if let` forms.
902 /// Beware that `else if` is a special case syntax sugar, because in general
903 /// there has to be block expression after `else`.
904 ///
905 /// ```
906 /// ❰ if bool_cond { 42 } ❱
907 /// ❰ if bool_cond { 42 } else { 24 } ❱
908 /// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱
909 ///
910 /// ❰
911 /// if let Pattern(foo) = bar {
912 /// foo
913 /// } else {
914 /// panic!();
915 /// }
916 /// ❱
917 /// ```
918 ///
919 /// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
920 struct IfExpr: AttrsOwner { T![if], Condition }
921
922 /// Unconditional loop expression.
923 ///
924 /// ```
925 /// ❰
926 /// loop {
927 /// // yeah, it's that simple...
928 /// }
929 /// ❱
930 /// ```
931 ///
932 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html)
933 struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] }
934
935 /// Block expression with an optional prefix (label, try ketword,
936 /// unsafe keyword, async keyword...).
937 ///
938 /// ```
939 /// ❰
940 /// 'label: try {
941 /// None?
942 /// }
943 /// ❱
944 /// ```
945 ///
946 /// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html)
947 /// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks)
948 /// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks)
949 struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr }
950
951
952 /// For loop expression.
953 /// Note: record struct literals are not valid as iterable expression
954 /// due to ambiguity.
955 ///
956 /// ```
957 /// ❰
958 /// for i in (0..4) {
959 /// dbg!(i);
960 /// }
961 /// ❱
962 /// ```
963 ///
964 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops)
965 struct ForExpr: AttrsOwner, LoopBodyOwner {
966 T![for],
967 Pat,
968 T![in],
969 iterable: Expr,
970 }
971
972 /// While loop expression. Includes both regular `while` and `while let` forms.
973 ///
974 /// ```
975 /// ❰
976 /// while bool_cond {
977 /// 42;
978 /// }
979 /// ❱
980 /// ❰
981 /// while let Pattern(foo) = bar {
982 /// bar += 1;
983 /// }
984 /// ❱
985 /// ```
986 ///
987 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
988 struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition }
989
990 /// Continue expression.
991 ///
992 /// ```
993 /// while bool_cond {
994 /// ❰ continue ❱;
995 /// }
996 ///
997 /// 'outer: loop {
998 /// loop {
999 /// ❰ continue 'outer ❱;
1000 /// }
1001 /// }
1002 ///
1003 /// ```
1004 ///
1005 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)
1006 struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] }
1007
1008 /// Break expression.
1009 ///
1010 /// ```
1011 /// while bool_cond {
1012 /// ❰ break ❱;
1013 /// }
1014 /// 'outer: loop {
1015 /// for foo in bar {
1016 /// ❰ break 'outer ❱;
1017 /// }
1018 /// }
1019 /// 'outer: loop {
1020 /// loop {
1021 /// ❰ break 'outer 42 ❱;
1022 /// }
1023 /// }
1024 /// ```
1025 ///
1026 /// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions)
1027 struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr }
1028
1029 /// Label.
1030 ///
1031 /// ```
1032 /// ❰ 'outer: ❱ loop {}
1033 ///
1034 /// let foo = ❰ 'bar: ❱ loop {}
1035 ///
1036 /// ❰ 'baz: ❱ {
1037 /// break 'baz;
1038 /// }
1039 /// ```
1040 ///
1041 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels)
1042 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1043 struct Label { T![lifetime] }
1044
1045 /// Block expression. Includes unsafe blocks and block labels.
1046 ///
1047 /// ```
1048 /// let foo = ❰
1049 /// {
1050 /// #![inner_attr]
1051 /// ❰ { } ❱
1052 ///
1053 /// ❰ 'label: { break 'label } ❱
1054 /// }
1055 /// ❱;
1056 /// ```
1057 ///
1058 /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html)
1059 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1060 struct BlockExpr: AttrsOwner, ModuleItemOwner {
1061 Label, T!['{'], statements: [Stmt], Expr, T!['}'],
1062 }
1063
1064 /// Return expression.
1065 ///
1066 /// ```
1067 /// || ❰ return 42 ❱;
1068 ///
1069 /// fn bar() {
1070 /// ❰ return ❱;
1071 /// }
1072 /// ```
1073 ///
1074 /// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html)
1075 struct ReturnExpr: AttrsOwner { Expr }
1076
1077 /// Call expression (not to be confused with method call expression, it is
1078 /// a separate ast node).
1079 ///
1080 /// ```
1081 /// ❰ foo() ❱;
1082 /// ❰ &str::len("bar") ❱;
1083 /// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱;
1084 /// ```
1085 ///
1086 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
1087 struct CallExpr: ArgListOwner { Expr }
1088
1089 /// Method call expression.
1090 ///
1091 /// ```
1092 /// ❰ receiver_expr.method() ❱;
1093 /// ❰ receiver_expr.method::<T>(42, true) ❱;
1094 ///
1095 /// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱;
1096 /// ```
1097 ///
1098 /// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html)
1099 struct MethodCallExpr: AttrsOwner, ArgListOwner {
1100 Expr, T![.], NameRef, TypeArgList,
1101 }
1102
1103 /// Index expression a.k.a. subscript operator call.
1104 ///
1105 /// ```
1106 /// ❰ foo[42] ❱;
1107 /// ```
1108 ///
1109 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
1110 struct IndexExpr: AttrsOwner { T!['['], T![']'] }
1111
1112 /// Field access expression.
1113 ///
1114 /// ```
1115 /// ❰ expr.bar ❱;
1116 ///
1117 /// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱;
1118 /// ```
1119 ///
1120 /// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html)
1121 struct FieldExpr: AttrsOwner { Expr, T![.], NameRef }
1122
1123 /// Await operator call expression.
1124 ///
1125 /// ```
1126 /// ❰ expr.await ❱;
1127 /// ```
1128 ///
1129 /// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html)
1130 struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] }
1131
1132 /// The question mark operator call.
1133 ///
1134 /// ```
1135 /// ❰ expr? ❱;
1136 /// ```
1137 ///
1138 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)
1139 struct TryExpr: AttrsOwner { Expr, T![?] }
1140
1141 /// Type cast expression.
1142 ///
1143 /// ```
1144 /// ❰ expr as T ❱;
1145 /// ```
1146 ///
1147 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
1148 struct CastExpr: AttrsOwner { Expr, T![as], TypeRef }
1149
1150
1151 /// Borrow operator call.
1152 ///
1153 /// ```
1154 /// ❰ &foo ❱;
1155 /// ❰ &mut bar ❱;
1156 /// ❰ &raw const bar ❱;
1157 /// ❰ &raw mut bar ❱;
1158 /// ```
1159 ///
1160 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators)
1161 struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr }
1162
1163 /// Prefix operator call. This is either `!` or `*` or `-`.
1164 ///
1165 /// ```
1166 /// ❰ !foo ❱;
1167 /// ❰ *bar ❱;
1168 /// ❰ -42 ❱;
1169 /// ```
1170 ///
1171 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html)
1172 struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr }
1173
1174 /// Box operator call.
1175 ///
1176 /// ```
1177 /// ❰ box 42 ❱;
1178 /// ```
1179 ///
1180 /// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md)
1181 struct BoxExpr: AttrsOwner { T![box], Expr }
1182
1183 /// Range operator call.
1184 ///
1185 /// ```
1186 /// ❰ 0..42 ❱;
1187 /// ❰ ..42 ❱;
1188 /// ❰ 0.. ❱;
1189 /// ❰ .. ❱;
1190 /// ❰ 0..=42 ❱;
1191 /// ❰ ..=42 ❱;
1192 /// ```
1193 ///
1194 /// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html)
1195 struct RangeExpr: AttrsOwner { /*RangeOp*/ }
1196
1197
1198 /// Binary operator call.
1199 /// Includes all arithmetic, logic, bitwise and assignment operators.
1200 ///
1201 /// ```
1202 /// ❰ 2 + ❰ 2 * 2 ❱ ❱;
1203 /// ❰ ❰ true && false ❱ || true ❱;
1204 /// ```
1205 ///
1206 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators)
1207 struct BinExpr: AttrsOwner { /*BinOp*/ }
1208
1209
1210 /// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal.
1211 ///
1212 /// ```
1213 /// ❰ "str" ❱;
1214 /// ❰ br##"raw byte str"## ❱;
1215 /// ❰ 'c' ❱;
1216 /// ❰ b'c' ❱;
1217 /// ❰ 42 ❱;
1218 /// ❰ 1e9 ❱;
1219 /// ❰ true ❱;
1220 /// ```
1221 ///
1222 /// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html)
1223 struct Literal { /*LiteralToken*/ }
1224
1225 /// Match expression.
1226 ///
1227 /// ```
1228 /// ❰
1229 /// match expr {
1230 /// Pat1 => {}
1231 /// Pat2(_) => 42,
1232 /// }
1233 /// ❱
1234 /// ```
1235 ///
1236 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1237 struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList }
1238
1239 /// Match arm list part of match expression. Includes its inner attributes.
1240 ///
1241 /// ```
1242 /// match expr
1243 /// ❰
1244 /// {
1245 /// #![inner_attr]
1246 /// Pat1 => {}
1247 /// Pat2(_) => 42,
1248 /// }
1249 /// ❱
1250 /// ```
1251 ///
1252 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1253 struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] }
1254
1255
1256 /// Match arm.
1257 /// Note: record struct literals are not valid as target match expression
1258 /// due to ambiguity.
1259 /// ```
1260 /// match expr {
1261 /// ❰ #[attr] Pattern(it) if bool_cond => it ❱,
1262 /// }
1263 /// ```
1264 ///
1265 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1266 struct MatchArm: AttrsOwner {
1267 pat: Pat,
1268 guard: MatchGuard,
1269 T![=>],
1270 Expr,
1271 }
1272
1273 /// Match guard.
1274 ///
1275 /// ```
1276 /// match expr {
1277 /// Pattern(it) ❰ if bool_cond ❱ => it,
1278 /// }
1279 /// ```
1280 ///
1281 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards)
1282 struct MatchGuard { T![if], Expr }
1283
1284 /// Record literal expression. The same syntax is used for structs,
1285 /// unions and record enum variants.
1286 ///
1287 /// ```
1288 /// ❰
1289 /// foo::Bar {
1290 /// #![inner_attr]
1291 /// baz: 42,
1292 /// bruh: true,
1293 /// ..spread
1294 /// }
1295 /// ❱
1296 /// ```
1297 ///
1298 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1299 struct RecordLit { Path, RecordFieldList}
1300
1301 /// Record field list including enclosing curly braces.
1302 ///
1303 /// foo::Bar ❰
1304 /// {
1305 /// baz: 42,
1306 /// ..spread
1307 /// }
1308 /// ❱
1309 ///
1310 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1311 struct RecordFieldList {
1312 T!['{'],
1313 fields: [RecordField],
1314 T![..],
1315 spread: Expr,
1316 T!['}']
1317 }
1318
1319 /// Record field.
1320 ///
1321 /// ```
1322 /// foo::Bar {
1323 /// ❰ #[attr] baz: 42 ❱
1324 /// }
1325 /// ```
1326 ///
1327 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1328 struct RecordField: AttrsOwner { NameRef, T![:], Expr }
1329
1330 /// Disjunction of patterns.
1331 ///
1332 /// ```
1333 /// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh;
1334 /// ```
1335 ///
1336 /// [Reference](https://doc.rust-lang.org/reference/patterns.html)
1337 struct OrPat { pats: [Pat] }
1338
1339 /// Parenthesized pattern.
1340 /// Note: parens are only used for grouping, this is not a tuple pattern.
1341 ///
1342 /// ```
1343 /// if let ❰ &(0..=42) ❱ = foo {}
1344 /// ```
1345 ///
1346 /// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns
1347 struct ParenPat { T!['('], Pat, T![')'] }
1348
1349 /// Reference pattern.
1350 /// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns.
1351 ///
1352 /// ```
1353 /// let ❰ &mut foo ❱ = bar;
1354 ///
1355 /// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz;
1356 /// ```
1357 ///
1358 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns)
1359 struct RefPat { T![&], T![mut], Pat }
1360
1361 /// Box pattern.
1362 ///
1363 /// ```
1364 /// let ❰ box foo ❱ = box 42;
1365 /// ```
1366 ///
1367 /// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html)
1368 struct BoxPat { T![box], Pat }
1369
1370 /// Bind pattern.
1371 ///
1372 /// ```
1373 /// match foo {
1374 /// Some(❰ ref mut bar ❱) => {}
1375 /// ❰ baz @ None ❱ => {}
1376 /// }
1377 /// ```
1378 ///
1379 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns)
1380 struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat }
1381
1382 /// Placeholder pattern a.k.a. the wildcard pattern or the underscore.
1383 ///
1384 /// ```
1385 /// let ❰ _ ❱ = foo;
1386 /// ```
1387 ///
1388 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern)
1389 struct PlaceholderPat { T![_] }
1390
1391 /// Rest-of-the record/tuple pattern.
1392 /// Note: this is not the unbonded range pattern (even more: it doesn't exist).
1393 ///
1394 /// ```
1395 /// let Foo { bar, ❰ .. ❱ } = baz;
1396 /// let (❰ .. ❱, bruh) = (42, 24, 42);
1397 /// let Bruuh(❰ .. ❱) = bruuuh;
1398 /// ```
1399 ///
1400 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1401 struct DotDotPat { T![..] }
1402
1403 /// Path pattern.
1404 /// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`).
1405 ///
1406 /// ```
1407 /// let ❰ foo::bar::Baz ❱ { .. } = bruh;
1408 /// if let ❰ CONST ❱ = 42 {}
1409 /// ```
1410 ///
1411 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns)
1412 struct PathPat { Path }
1413
1414 /// Slice pattern.
1415 ///
1416 /// ```
1417 /// let ❰ [foo, bar, baz] ❱ = [1, 2, 3];
1418 /// ```
1419 ///
1420 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns)
1421 struct SlicePat { T!['['], args: [Pat], T![']'] }
1422
1423 /// Range pattern.
1424 ///
1425 /// ```
1426 /// match foo {
1427 /// ❰ 0..42 ❱ => {}
1428 /// ❰ 0..=42 ❱ => {}
1429 /// }
1430 /// ```
1431 ///
1432 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns)
1433 struct RangePat { } // FIXME(@matklad): here should be T![..], T![..=] I think, if we don't already have an accessor in expresions_ext
1434
1435 /// Literal pattern.
1436 /// Includes only bool, number, char, and string literals.
1437 ///
1438 /// ```
1439 /// match foo {
1440 /// Number(❰ 42 ❱) => {}
1441 /// String(❰ "42" ❱) => {}
1442 /// Bool(❰ true ❱) => {}
1443 /// }
1444 /// ```
1445 ///
1446 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns)
1447 struct LiteralPat { Literal }
1448
1449 /// Macro invocation in pattern position.
1450 ///
1451 /// ```
1452 /// let ❰ foo!(my custom syntax) ❱ = baz;
1453 ///
1454 /// ```
1455 /// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation)
1456 struct MacroPat { MacroCall }
1457
1458 /// Record literal pattern.
1459 ///
1460 /// ```
1461 /// let ❰ foo::Bar { baz, .. } ❱ = bruh;
1462 /// ```
1463 ///
1464 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1465 struct RecordPat { RecordFieldPatList, Path }
1466
1467 /// Record literal's field patterns list including enclosing curly braces.
1468 ///
1469 /// ```
1470 /// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh;
1471 /// ``
1472 ///
1473 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1474 struct RecordFieldPatList {
1475 T!['{'],
1476 pats: [RecordInnerPat],
1477 record_field_pats: [RecordFieldPat],
1478 bind_pats: [BindPat],
1479 T![..],
1480 T!['}']
1481 }
1482
1483 /// Record literal's field pattern.
1484 /// Note: record literal can also match tuple structs.
1485 ///
1486 /// ```
1487 /// let Foo { ❰ bar: _ ❱ } = baz;
1488 /// let TupleStruct { ❰ 0: _ ❱ } = bruh;
1489 /// ```
1490 ///
1491 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1492 struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat }
1493
1494 /// Tuple struct literal pattern.
1495 ///
1496 /// ```
1497 /// let ❰ foo::Bar(baz, bruh) ❱ = bruuh;
1498 /// ```
1499 ///
1500 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns)
1501 struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] }
1502
1503 /// Tuple pattern.
1504 /// Note: this doesn't include tuple structs (see `TupleStructPat`)
1505 ///
1506 /// ```
1507 /// let ❰ (foo, bar, .., baz) ❱ = bruh;
1508 /// ```
1509 ///
1510 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns)
1511 struct TuplePat { T!['('], args: [Pat], T![')'] }
1512
1513 /// Visibility.
1514 ///
1515 /// ```
1516 /// ❰ pub mod ❱ foo;
1517 /// ❰ pub(crate) ❱ struct Bar;
1518 /// ❰ pub(self) ❱ enum Baz {}
1519 /// ❰ pub(super) ❱ fn bruh() {}
1520 /// ❰ pub(in bruuh::bruuuh) ❱ type T = u64;
1521 /// ```
1522 ///
1523 /// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html)
1524 struct Visibility { T![pub], T![super], T![self], T![crate] }
1525
1526 /// Single identifier.
1527 /// Note(@matklad): `Name` is for things that install a new name into the scope,
1528 /// `NameRef` is a usage of a name. Most of the time, this definition/reference
1529 /// distinction can be determined purely syntactically, ie in
1530 /// ```
1531 /// fn foo() { foo() }
1532 /// ```
1533 /// the first foo is `Name`, the second one is `NameRef`.
1534 /// The notable exception are patterns, where in
1535 /// ``
1536 /// let x = 92
1537 /// ```
1538 /// `x` can be semantically either a name or a name ref, depeding on
1539 /// wether there's an `x` constant in scope.
1540 /// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db).
1541 ///
1542 /// ```
1543 /// let ❰ foo ❱ = bar;
1544 /// struct ❰ Baz ❱;
1545 /// fn ❰ bruh ❱() {}
1546 /// ```
1547 ///
1548 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1549 struct Name { T![ident] }
1550
1551 /// Reference to a name.
1552 /// See the explanation on the difference between `Name` and `NameRef`
1553 /// in `Name` ast node docs.
1554 ///
1555 /// ```
1556 /// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱;
1557 /// ```
1558 ///
1559 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1560 struct NameRef { }
1561
1562 /// Macro call.
1563 /// Includes all of its attributes and doc comments.
1564 ///
1565 /// ```
1566 /// ❰
1567 /// /// Docs
1568 /// #[attr]
1569 /// macro_rules! foo { // macro rules is also a macro call
1570 /// ($bar: tt) => {}
1571 /// }
1572 /// ❱
1573 ///
1574 /// // semicolon is a part of `MacroCall` when it is used in item positions
1575 /// ❰ foo!(); ❱
1576 ///
1577 /// fn main() {
1578 /// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi
1579 /// }
1580 /// ```
1581 ///
1582 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
1583 struct MacroCall: NameOwner, AttrsOwner, DocCommentsOwner {
1584 Path, T![!], TokenTree, T![;]
1585 }
1586
1587 /// Attribute.
1588 ///
1589 /// ```
1590 /// ❰ #![inner_attr] ❱
1591 ///
1592 /// ❰ #[attr] ❱
1593 /// ❰ #[foo = "bar"] ❱
1594 /// ❰ #[baz(bruh::bruuh = "42")] ❱
1595 /// struct Foo;
1596 /// ```
1597 ///
1598 /// [Reference](https://doc.rust-lang.org/reference/attributes.html)
1599 struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] }
1600
1601 /// Stores a list of lexer tokens and other `TokenTree`s.
1602 /// It appears in attributes, macro_rules and macro call (foo!)
1603 ///
1604 /// ```
1605 /// macro_call! ❰ { my syntax here } ❱;
1606 /// ```
1607 ///
1608 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
1609 struct TokenTree {}
1610
1611 /// Generic lifetime, type and constants parameters list **declaration**.
1612 ///
1613 /// ```
1614 /// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {}
1615 ///
1616 /// struct Baz❰ <T> ❱(T);
1617 ///
1618 /// impl❰ <T> ❱ Bruh<T> {}
1619 ///
1620 /// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str;
1621 /// ```
1622 ///
1623 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1624 struct TypeParamList {
1625 T![<],
1626 generic_params: [GenericParam],
1627 type_params: [TypeParam],
1628 lifetime_params: [LifetimeParam],
1629 const_params: [ConstParam],
1630 T![>]
1631 }
1632
1633 /// Single type parameter **declaration**.
1634 ///
1635 /// ```
1636 /// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {}
1637 /// ```
1638 ///
1639 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1640 struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner {
1641 T![=],
1642 default_type: TypeRef,
1643 }
1644
1645 /// Const generic parameter **declaration**.
1646 /// ```
1647 /// fn foo<T, U, ❰ const BAR: usize ❱, ❰ const BAZ: bool ❱>() {}
1648 /// ```
1649 ///
1650 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
1651 struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner {
1652 T![=],
1653 default_val: Expr,
1654 }
1655
1656 /// Lifetime parameter **declaration**.
1657 ///
1658 /// ```
1659 /// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {}
1660 /// ```
1661 ///
1662 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1663 struct LifetimeParam: AttrsOwner { T![lifetime] }
1664
1665 /// Type bound declaration clause.
1666 ///
1667 /// ```
1668 /// fn foo<T: ❰ ?Sized ❱ + ❰ Debug ❱>() {}
1669 ///
1670 /// trait Bar<T>
1671 /// where
1672 /// T: ❰ Send ❱ + ❰ Sync ❱
1673 /// {
1674 /// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱;
1675 /// }
1676 /// ```
1677 ///
1678 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
1679 struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef }
1680
1681 /// Type bounds list.
1682 ///
1683 /// ```
1684 ///
1685 /// fn foo<T: ❰ ?Sized + Debug ❱>() {}
1686 ///
1687 /// trait Bar<T>
1688 /// where
1689 /// T: ❰ Send + Sync ❱
1690 /// {
1691 /// type Baz: ❰ !Sync + Debug ❱;
1692 /// }
1693 /// ```
1694 ///
1695 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
1696 struct TypeBoundList { bounds: [TypeBound] }
1697
1698 /// Single where predicate.
1699 ///
1700 /// ```
1701 /// trait Foo<'a, 'b, T>
1702 /// where
1703 /// ❰ 'a: 'b ❱,
1704 /// ❰ T: IntoIterator ❱,
1705 /// ❰ for<'c> <T as IntoIterator>::Item: Bar<'c> ❱
1706 /// {}
1707 /// ```
1708 ///
1709 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
1710 struct WherePred: TypeBoundsOwner { T![for], TypeParamList, T![lifetime], TypeRef }
1711
1712 /// Where clause.
1713 ///
1714 /// ```
1715 /// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {}
1716 ///
1717 /// ```
1718 ///
1719 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
1720 struct WhereClause { T![where], predicates: [WherePred] }
1721
1722 /// Abi declaration.
1723 /// Note: the abi string is optional.
1724 ///
1725 /// ```
1726 /// ❰ extern "C" ❱ {
1727 /// fn foo() {}
1728 /// }
1729 ///
1730 /// type Bar = ❰ extern ❱ fn() -> u32;
1731 ///
1732 /// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool;
1733 /// ```
1734 ///
1735 /// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
1736 /// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions)
1737 struct Abi { /*String*/ }
1738
1739 /// Expression statement.
1740 ///
1741 /// ```
1742 /// ❰ 42; ❱
1743 /// ❰ foo(); ❱
1744 /// ❰ (); ❱
1745 /// ❰ {}; ❱
1746 ///
1747 /// // constructions with trailing curly brace can omit the semicolon
1748 /// // but only when there are satements immediately after them (this is important!)
1749 /// ❰ if bool_cond { } ❱
1750 /// ❰ loop {} ❱
1751 /// ❰ somestatment; ❱
1752 /// ```
1753 ///
1754 /// [Reference](https://doc.rust-lang.org/reference/statements.html)
1755 struct ExprStmt: AttrsOwner { Expr, T![;] }
1756
1757 /// Let statement.
1758 ///
1759 /// ```
1760 /// ❰ #[attr] let foo; ❱
1761 /// ❰ let bar: u64; ❱
1762 /// ❰ let baz = 42; ❱
1763 /// ❰ let bruh: bool = true; ❱
1764 /// ```
1765 ///
1766 /// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements)
1767 struct LetStmt: AttrsOwner, TypeAscriptionOwner {
1768 T![let],
1769 Pat,
1770 T![=],
1771 initializer: Expr,
1772 T![;],
1773 }
1774
1775 /// Condition of `if` or `while` expression.
1776 ///
1777 /// ```
1778 /// if ❰ true ❱ {}
1779 /// if ❰ let Pat(foo) = bar ❱ {}
1780 ///
1781 /// while ❰ true ❱ {}
1782 /// while ❰ let Pat(baz) = bruh ❱ {}
1783 /// ```
1784 ///
1785 /// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
1786 /// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
1787 struct Condition { T![let], Pat, T![=], Expr }
1788
1789 /// Parameter list **declaration**.
1790 ///
1791 /// ```
1792 /// fn foo❰ (a: u32, b: bool) ❱ -> u32 {}
1793 /// let bar = ❰ |a, b| ❱ {};
1794 ///
1795 /// impl Baz {
1796 /// fn bruh❰ (&self, a: u32) ❱ {}
1797 /// }
1798 /// ```
1799 ///
1800 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script
1801 struct ParamList { // FIXME: this node is used by closure expressions too, but hey use pipes instead of parens...
1802 T!['('],
1803 SelfParam,
1804 params: [Param],
1805 T![')']
1806 }
1807
1808 /// Self parameter **declaration**.
1809 ///
1810 /// ```
1811 /// impl Bruh {
1812 /// fn foo(❰ self ❱) {}
1813 /// fn bar(❰ &self ❱) {}
1814 /// fn baz(❰ &mut self ❱) {}
1815 /// fn blah<'a>(❰ &'a self ❱) {}
1816 /// fn blin(❰ self: Box<Self> ❱) {}
1817 /// }
1818 /// ```
1819 ///
1820 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
1821 struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] }
1822
1823 /// Parameter **declaration**.
1824 ///
1825 /// ```
1826 /// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {}
1827 ///
1828 /// extern "C" {
1829 /// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32;
1830 /// }
1831 /// ```
1832 ///
1833 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
1834 struct Param: TypeAscriptionOwner, AttrsOwner {
1835 Pat,
1836 T![...]
1837 }
1838
1839 /// Use declaration.
1840 ///
1841 /// ```
1842 /// ❰ #[attr] pub use foo; ❱
1843 /// ❰ use bar as baz; ❱
1844 /// ❰ use bruh::{self, bruuh}; ❱
1845 /// ❰ use { blin::blen, blah::* };
1846 /// ```
1847 ///
1848 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1849 struct UseItem: AttrsOwner, VisibilityOwner {
1850 T![use],
1851 UseTree,
1852 }
1853
1854 /// Use tree.
1855 ///
1856 /// ```
1857 /// pub use ❰ foo::❰ * ❱ ❱;
1858 /// use ❰ bar as baz ❱;
1859 /// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱;
1860 /// use ❰ { ❰ blin::blen ❱ } ❱
1861 /// ```
1862 ///
1863 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1864 struct UseTree {
1865 Path, T![*], UseTreeList, Alias
1866 }
1867
1868 /// Item alias.
1869 /// Note: this is not the type alias.
1870 ///
1871 /// ```
1872 /// use foo ❰ as bar ❱;
1873 /// use baz::{bruh ❰ as _ ❱};
1874 /// extern crate bruuh ❰ as blin ❱;
1875 /// ```
1876 ///
1877 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1878 struct Alias: NameOwner { T![as] }
1879
1880 /// Sublist of use trees.
1881 ///
1882 /// ```
1883 /// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱;
1884 /// use ❰ { blin::blen::❰ {} ❱ } ❱
1885 /// ```
1886 ///
1887 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1888 struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] }
1889
1890 /// Extern crate item.
1891 ///
1892 /// ```
1893 /// ❰ #[attr] pub extern crate foo; ❱
1894 /// ❰ extern crate self as bar; ❱
1895 /// ```
1896 ///
1897 /// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html)
1898 struct ExternCrateItem: AttrsOwner, VisibilityOwner {
1899 T![extern], T![crate], NameRef, Alias,
1900 }
1901
1902 /// Call site arguments list.
1903 ///
1904 /// ```
1905 /// foo::<T, U>❰ (42, true) ❱;
1906 /// ```
1907 ///
1908 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
1909 struct ArgList {
1910 T!['('],
1911 args: [Expr],
1912 T![')']
1913 }
1914
1915 /// Path to a symbol. Includes single identifier names and elaborate paths with
1916 /// generic parameters.
1917 ///
1918 /// ```
1919 /// (0..10).❰ ❰ collect ❱ ::<Vec<_>> ❱();
1920 /// ❰ ❰ ❰ Vec ❱ ::<u8> ❱ ::with_capacity ❱(1024);
1921 /// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱();
1922 /// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱();
1923 /// ```
1924 ///
1925 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
1926 struct Path {
1927 segment: PathSegment,
1928 T![::],
1929 qualifier: Path,
1930 }
1931
1932 /// Segment of the path to a symbol.
1933 /// Only path segment of an absolute path holds the `::` token,
1934 /// all other `::` tokens that connect path segments reside under `Path` itself.`
1935 ///
1936 /// ```
1937 /// (0..10).❰ collect ❱ :: ❰ <Vec<_>> ❱();
1938 /// ❰ Vec ❱ :: ❰ <u8> ❱ :: ❰ with_capacity ❱(1024);
1939 /// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱();
1940 /// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱();
1941 ///
1942 /// // Note that only in this case `::` token is inlcuded:
1943 /// ❰ ::foo ❱;
1944 /// ```
1945 ///
1946 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
1947 struct PathSegment {
1948 T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
1949 }
1950
1951 /// List of type arguments that are passed at generic instantiation site.
1952 ///
1953 /// ```
1954 /// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar;
1955 ///
1956 /// Vec❰ ::<bool> ❱::();
1957 /// ```
1958 ///
1959 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1960 struct TypeArgList {
1961 T![::],
1962 T![<],
1963 generic_args: [GenericArg],
1964 type_args: [TypeArg],
1965 lifetime_args: [LifetimeArg],
1966 assoc_type_args: [AssocTypeArg],
1967 const_args: [ConstArg],
1968 T![>]
1969 }
1970
1971 /// Type argument that is passed at generic instantiation site.
1972 ///
1973 /// ```
1974 /// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz;
1975 /// ```
1976 ///
1977 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1978 struct TypeArg { TypeRef }
1979
1980 /// Associated type argument that is passed at generic instantiation site.
1981 /// ```
1982 /// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh;
1983 ///
1984 /// trait Bruh<T>: Iterator<❰ Item: Debug ❱> {}
1985 /// ```
1986 ///
1987 struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef }
1988
1989 /// Lifetime argument that is passed at generic instantiation site.
1990 ///
1991 /// ```
1992 /// fn foo<'a>(s: &'a str) {
1993 /// bar::<❰ 'a ❱>(s);
1994 /// }
1995 /// ```
1996 ///
1997 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1998 struct LifetimeArg { T![lifetime] }
1999
2000 /// Constant value argument that is passed at generic instantiation site.
2001 ///
2002 /// ```
2003 /// foo::<u32, ❰ { true } ❱>();
2004 ///
2005 /// bar::<❰ { 2 + 2} ❱>();
2006 /// ```
2007 ///
2008 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
2009 struct ConstArg { Literal, BlockExpr }
2010
2011
2012 /// FIXME: (@edwin0cheng) Remove it to use ItemList instead
2013 /// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243
2014 ///
2015 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
2016 struct MacroItems: ModuleItemOwner { }
2017
2018 /// FIXME: (@edwin0cheng) add some documentation here. As per the writing
2019 /// of this comment this ast node is not used.
2020 ///
2021 /// ```
2022 /// // FIXME: example here
2023 /// ```
2024 ///
2025 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
2026 struct MacroStmts {
2027 statements: [Stmt],
2028 Expr,
2029 }
2030
2031 /// List of items in an extern block.
2032 ///
2033 /// ```
2034 /// extern "C" ❰
2035 /// {
2036 /// fn foo();
2037 /// static var: u32;
2038 /// }
2039 /// ❱
2040 /// ```
2041 ///
2042 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2043 struct ExternItemList: ModuleItemOwner {
2044 T!['{'],
2045 extern_items: [ExternItem],
2046 T!['}']
2047 }
2048
2049 /// Extern block.
2050 ///
2051 /// ```
2052 /// ❰
2053 /// extern "C" {
2054 /// fn foo();
2055 /// }
2056 /// ❱
2057 ///
2058 /// ```
2059 ///
2060 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2061 struct ExternBlock {
2062 Abi,
2063 ExternItemList
2064 }
2065
2066 /// Meta item in an attribute.
2067 ///
2068 /// ```
2069 /// #[❰ bar::baz = "42" ❱]
2070 /// #[❰ bruh(bruuh("true")) ❱]
2071 /// struct Foo;
2072 /// ```
2073 ///
2074 /// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax)
2075 struct MetaItem {
2076 Path, T![=], AttrInput, nested_meta_items: [MetaItem]
2077 }
2078
2079 /// Macro 2.0 definition.
2080 /// Their syntax is still WIP by rustc team...
2081 /// ```
2082 /// ❰
2083 /// macro foo { }
2084 /// ❱
2085 /// ```
2086 ///
2087 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md)
2088 struct MacroDef {
2089 Name, TokenTree
2090 }
2091 },
2092 enums: &ast_enums! {
2093 /// Any kind of nominal type definition.
2094 enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
2095 StructDef, EnumDef, UnionDef,
2096 }
2097
2098 /// Any kind of **declared** generic parameter
2099 enum GenericParam {
2100 LifetimeParam,
2101 TypeParam,
2102 ConstParam
2103 }
2104
2105 /// Any kind of generic argument passed at instantiation site
2106 enum GenericArg {
2107 LifetimeArg,
2108 TypeArg,
2109 ConstArg,
2110 AssocTypeArg
2111 }
2112
2113 /// Any kind of construct valid in type context
2114 enum TypeRef {
2115 ParenType,
2116 TupleType,
2117 NeverType,
2118 PathType,
2119 PointerType,
2120 ArrayType,
2121 SliceType,
2122 ReferenceType,
2123 PlaceholderType,
2124 FnPointerType,
2125 ForType,
2126 ImplTraitType,
2127 DynTraitType,
2128 }
2129
2130 /// Any kind of top-level item that may appear in a module
2131 enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner {
2132 StructDef,
2133 UnionDef,
2134 EnumDef,
2135 FnDef,
2136 TraitDef,
2137 TypeAliasDef,
2138 ImplDef,
2139 UseItem,
2140 ExternCrateItem,
2141 ConstDef,
2142 StaticDef,
2143 Module,
2144 MacroCall,
2145 ExternBlock
2146 }
2147
2148
2149
2150 /// Any kind of item that may appear in an impl block
2151 ///
2152 /// // FIXME: impl blocks can also contain MacroCall
2153 enum AssocItem: NameOwner, AttrsOwner {
2154 FnDef, TypeAliasDef, ConstDef
2155 }
2156
2157 /// Any kind of item that may appear in an extern block
2158 ///
2159 /// // FIXME: extern blocks can also contain MacroCall
2160 enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner {
2161 FnDef, StaticDef
2162 }
2163
2164 /// Any kind of expression
2165 enum Expr: AttrsOwner {
2166 TupleExpr,
2167 ArrayExpr,
2168 ParenExpr,
2169 PathExpr,
2170 LambdaExpr,
2171 IfExpr,
2172 LoopExpr,
2173 ForExpr,
2174 WhileExpr,
2175 ContinueExpr,
2176 BreakExpr,
2177 Label,
2178 BlockExpr,
2179 ReturnExpr,
2180 MatchExpr,
2181 RecordLit,
2182 CallExpr,
2183 IndexExpr,
2184 MethodCallExpr,
2185 FieldExpr,
2186 AwaitExpr,
2187 TryExpr,
2188 EffectExpr,
2189 CastExpr,
2190 RefExpr,
2191 PrefixExpr,
2192 RangeExpr,
2193 BinExpr,
2194 Literal,
2195 MacroCall,
2196 BoxExpr,
2197 }
2198
2199 /// Any kind of pattern
2200 enum Pat {
2201 OrPat,
2202 ParenPat,
2203 RefPat,
2204 BoxPat,
2205 BindPat,
2206 PlaceholderPat,
2207 DotDotPat,
2208 PathPat,
2209 RecordPat,
2210 TupleStructPat,
2211 TuplePat,
2212 SlicePat,
2213 RangePat,
2214 LiteralPat,
2215 MacroPat,
2216 }
2217
2218 /// Any kind of pattern that appears directly inside of the curly
2219 /// braces of a record pattern
2220 enum RecordInnerPat {
2221 RecordFieldPat,
2222 BindPat
2223 }
2224
2225 /// Any kind of input to an attribute
2226 enum AttrInput { Literal, TokenTree }
2227
2228 /// Any kind of statement
2229 /// Note: there are no empty statements, these are just represented as
2230 /// bare semicolons without a dedicated statement ast node.
2231 enum Stmt {
2232 LetStmt,
2233 ExprStmt,
2234 // macro calls are parsed as expression statements
2235 }
2236
2237 /// Any kind of fields list (record or tuple field lists)
2238 enum FieldDefList {
2239 RecordFieldDefList,
2240 TupleFieldDefList,
2241 }
2242 },
2243};
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 745a25862..45b788bdb 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,34 +3,43 @@
3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype 3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. 4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
5 5
6use std::{collections::HashSet, fmt::Write}; 6use std::{
7 collections::{BTreeSet, HashSet},
8 fmt::Write,
9};
7 10
8use proc_macro2::{Punct, Spacing}; 11use proc_macro2::{Punct, Spacing};
9use quote::{format_ident, quote}; 12use quote::{format_ident, quote};
13use ungrammar::{Grammar, Rule};
10 14
11use crate::{ 15use crate::{
12 ast_src::{AstSrc, Field, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
13 codegen::{self, update, Mode}, 17 codegen::{self, update, Mode},
14 project_root, Result, 18 project_root, Result,
15}; 19};
16 20
17pub fn generate_syntax(mode: Mode) -> Result<()> { 21pub fn generate_syntax(mode: Mode) -> Result<()> {
22 let grammar = include_str!("rust.ungram")
23 .parse::<Grammar>()
24 .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err));
25 let ast = lower(&grammar);
26
18 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); 27 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
19 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 28 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
20 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 29 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
21 30
22 let ast_tokens_file = project_root().join(codegen::AST_TOKENS); 31 let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
23 let contents = generate_tokens(AST_SRC)?; 32 let contents = generate_tokens(&ast)?;
24 update(ast_tokens_file.as_path(), &contents, mode)?; 33 update(ast_tokens_file.as_path(), &contents, mode)?;
25 34
26 let ast_nodes_file = project_root().join(codegen::AST_NODES); 35 let ast_nodes_file = project_root().join(codegen::AST_NODES);
27 let contents = generate_nodes(KINDS_SRC, AST_SRC)?; 36 let contents = generate_nodes(KINDS_SRC, &ast)?;
28 update(ast_nodes_file.as_path(), &contents, mode)?; 37 update(ast_nodes_file.as_path(), &contents, mode)?;
29 38
30 Ok(()) 39 Ok(())
31} 40}
32 41
33fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { 42fn generate_tokens(grammar: &AstSrc) -> Result<String> {
34 let tokens = grammar.tokens.iter().map(|token| { 43 let tokens = grammar.tokens.iter().map(|token| {
35 let name = format_ident!("{}", token); 44 let name = format_ident!("{}", token);
36 let kind = format_ident!("{}", to_upper_snake_case(token)); 45 let kind = format_ident!("{}", to_upper_snake_case(token));
@@ -62,13 +71,13 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
62 Ok(pretty) 71 Ok(pretty)
63} 72}
64 73
65fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 74fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
66 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar 75 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
67 .nodes 76 .nodes
68 .iter() 77 .iter()
69 .map(|node| { 78 .map(|node| {
70 let name = format_ident!("{}", node.name); 79 let name = format_ident!("{}", node.name);
71 let kind = format_ident!("{}", to_upper_snake_case(node.name)); 80 let kind = format_ident!("{}", to_upper_snake_case(&node.name));
72 let traits = node.traits.iter().map(|trait_name| { 81 let traits = node.traits.iter().map(|trait_name| {
73 let trait_name = format_ident!("{}", trait_name); 82 let trait_name = format_ident!("{}", trait_name);
74 quote!(impl ast::#trait_name for #name {}) 83 quote!(impl ast::#trait_name for #name {})
@@ -192,8 +201,8 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
192 }) 201 })
193 .unzip(); 202 .unzip();
194 203
195 let enum_names = grammar.enums.iter().map(|it| it.name); 204 let enum_names = grammar.enums.iter().map(|it| &it.name);
196 let node_names = grammar.nodes.iter().map(|it| it.name); 205 let node_names = grammar.nodes.iter().map(|it| &it.name);
197 206
198 let display_impls = 207 let display_impls =
199 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { 208 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
@@ -212,9 +221,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
212 .nodes 221 .nodes
213 .iter() 222 .iter()
214 .map(|kind| to_pascal_case(kind)) 223 .map(|kind| to_pascal_case(kind))
215 .filter(|name| !defined_nodes.contains(name.as_str())) 224 .filter(|name| !defined_nodes.iter().any(|&it| it == name))
216 { 225 {
217 eprintln!("Warning: node {} not defined in ast source", node); 226 drop(node)
227 // TODO: restore this
228 // eprintln!("Warning: node {} not defined in ast source", node);
218 } 229 }
219 230
220 let ast = quote! { 231 let ast = quote! {
@@ -236,12 +247,12 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
236 let mut res = String::with_capacity(ast.len() * 2); 247 let mut res = String::with_capacity(ast.len() * 2);
237 248
238 let mut docs = 249 let mut docs =
239 grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc)); 250 grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
240 251
241 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") { 252 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
242 res.push_str(chunk); 253 res.push_str(chunk);
243 if let Some(doc) = docs.next() { 254 if let Some(doc) = docs.next() {
244 write_doc_comment(doc, &mut res); 255 write_doc_comment(&doc, &mut res);
245 } 256 }
246 } 257 }
247 258
@@ -249,7 +260,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
249 Ok(pretty) 260 Ok(pretty)
250} 261}
251 262
252fn write_doc_comment(contents: &[&str], dest: &mut String) { 263fn write_doc_comment(contents: &[String], dest: &mut String) {
253 for line in contents { 264 for line in contents {
254 writeln!(dest, "///{}", line).unwrap(); 265 writeln!(dest, "///{}", line).unwrap();
255 } 266 }
@@ -296,7 +307,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
296 307
297 let ast = quote! { 308 let ast = quote! {
298 #![allow(bad_style, missing_docs, unreachable_pub)] 309 #![allow(bad_style, missing_docs, unreachable_pub)]
299 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`. 310 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
300 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 311 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
301 #[repr(u16)] 312 #[repr(u16)]
302 pub enum SyntaxKind { 313 pub enum SyntaxKind {
@@ -363,6 +374,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
363 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)* 374 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
364 [lifetime] => { $crate::SyntaxKind::LIFETIME }; 375 [lifetime] => { $crate::SyntaxKind::LIFETIME };
365 [ident] => { $crate::SyntaxKind::IDENT }; 376 [ident] => { $crate::SyntaxKind::IDENT };
377 [shebang] => { $crate::SyntaxKind::SHEBANG };
366 } 378 }
367 }; 379 };
368 380
@@ -413,9 +425,13 @@ fn to_pascal_case(s: &str) -> String {
413 buf 425 buf
414} 426}
415 427
416impl Field<'_> { 428fn pluralize(s: &str) -> String {
429 format!("{}s", s)
430}
431
432impl Field {
417 fn is_many(&self) -> bool { 433 fn is_many(&self) -> bool {
418 matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) 434 matches!(self, Field::Node { cardinality: Cardinality::Many, .. })
419 } 435 }
420 fn token_kind(&self) -> Option<proc_macro2::TokenStream> { 436 fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
421 match self { 437 match self {
@@ -429,7 +445,7 @@ impl Field<'_> {
429 fn method_name(&self) -> proc_macro2::Ident { 445 fn method_name(&self) -> proc_macro2::Ident {
430 match self { 446 match self {
431 Field::Token(name) => { 447 Field::Token(name) => {
432 let name = match *name { 448 let name = match name.as_str() {
433 ";" => "semicolon", 449 ";" => "semicolon",
434 "->" => "thin_arrow", 450 "->" => "thin_arrow",
435 "'{'" => "l_curly", 451 "'{'" => "l_curly",
@@ -448,29 +464,251 @@ impl Field<'_> {
448 "." => "dot", 464 "." => "dot",
449 ".." => "dotdot", 465 ".." => "dotdot",
450 "..." => "dotdotdot", 466 "..." => "dotdotdot",
467 "..=" => "dotdoteq",
451 "=>" => "fat_arrow", 468 "=>" => "fat_arrow",
452 "@" => "at", 469 "@" => "at",
453 ":" => "colon", 470 ":" => "colon",
454 "::" => "coloncolon", 471 "::" => "coloncolon",
455 "#" => "pound", 472 "#" => "pound",
456 "?" => "question_mark", 473 "?" => "question_mark",
474 "," => "comma",
457 _ => name, 475 _ => name,
458 }; 476 };
459 format_ident!("{}_token", name) 477 format_ident!("{}_token", name)
460 } 478 }
461 Field::Node { name, src } => match src { 479 Field::Node { name, .. } => format_ident!("{}", name),
462 FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(name)),
463 _ => format_ident!("{}", name),
464 },
465 } 480 }
466 } 481 }
467 fn ty(&self) -> proc_macro2::Ident { 482 fn ty(&self) -> proc_macro2::Ident {
468 match self { 483 match self {
469 Field::Token(_) => format_ident!("SyntaxToken"), 484 Field::Token(_) => format_ident!("SyntaxToken"),
470 Field::Node { name, src } => match src { 485 Field::Node { ty, .. } => format_ident!("{}", ty),
471 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => format_ident!("{}", ty),
472 FieldSrc::Shorthand => format_ident!("{}", name),
473 },
474 } 486 }
475 } 487 }
476} 488}
489
490fn lower(grammar: &Grammar) -> AstSrc {
491 let mut res = AstSrc::default();
492 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()];
493
494 let nodes = grammar
495 .iter()
496 .filter(|&node| match grammar[node].rule {
497 Rule::Node(it) if it == node => false,
498 _ => true,
499 })
500 .collect::<Vec<_>>();
501
502 for &node in &nodes {
503 let name = grammar[node].name.clone();
504 let rule = &grammar[node].rule;
505 match lower_enum(grammar, rule) {
506 Some(variants) => {
507 let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
508 res.enums.push(enum_src);
509 }
510 None => {
511 let mut fields = Vec::new();
512 lower_rule(&mut fields, grammar, None, rule);
513 res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
514 }
515 }
516 }
517
518 deduplicate_fields(&mut res);
519 extract_enums(&mut res);
520 extract_struct_traits(&mut res);
521 extract_enum_traits(&mut res);
522 res
523}
524
525fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
526 let alternatives = match rule {
527 Rule::Alt(it) => it,
528 _ => return None,
529 };
530 let mut variants = Vec::new();
531 for alternative in alternatives {
532 match alternative {
533 Rule::Node(it) => variants.push(grammar[*it].name.clone()),
534 _ => return None,
535 }
536 }
537 Some(variants)
538}
539
540fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
541 if lower_comma_list(acc, grammar, label, rule) {
542 return;
543 }
544
545 match rule {
546 Rule::Node(node) => {
547 let ty = grammar[*node].name.clone();
548 let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
549 let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
550 acc.push(field);
551 }
552 Rule::Token(token) => {
553 assert!(label.is_none());
554 let mut name = grammar[*token].name.clone();
555 if name != "int_number" && name != "string" {
556 if "[]{}()".contains(&name) {
557 name = format!("'{}'", name);
558 }
559 let field = Field::Token(name);
560 acc.push(field);
561 }
562 }
563 Rule::Rep(inner) => {
564 if let Rule::Node(node) = &**inner {
565 let ty = grammar[*node].name.clone();
566 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
567 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
568 acc.push(field);
569 return;
570 }
571 todo!("{:?}", rule)
572 }
573 Rule::Labeled { label: l, rule } => {
574 assert!(label.is_none());
575 lower_rule(acc, grammar, Some(l), rule);
576 }
577 Rule::Seq(rules) | Rule::Alt(rules) => {
578 for rule in rules {
579 lower_rule(acc, grammar, label, rule)
580 }
581 }
582 Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
583 }
584}
585
586// (T (',' T)* ','?)
587fn lower_comma_list(
588 acc: &mut Vec<Field>,
589 grammar: &Grammar,
590 label: Option<&String>,
591 rule: &Rule,
592) -> bool {
593 let rule = match rule {
594 Rule::Seq(it) => it,
595 _ => return false,
596 };
597 let (node, repeat, trailing_comma) = match rule.as_slice() {
598 [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
599 (node, repeat, trailing_comma)
600 }
601 _ => return false,
602 };
603 let repeat = match &**repeat {
604 Rule::Seq(it) => it,
605 _ => return false,
606 };
607 match repeat.as_slice() {
608 [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
609 _ => return false,
610 }
611 let ty = grammar[*node].name.clone();
612 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
613 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
614 acc.push(field);
615 true
616}
617
618fn deduplicate_fields(ast: &mut AstSrc) {
619 for node in &mut ast.nodes {
620 let mut i = 0;
621 'outer: while i < node.fields.len() {
622 for j in 0..i {
623 let f1 = &node.fields[i];
624 let f2 = &node.fields[j];
625 if f1 == f2 {
626 node.fields.remove(i);
627 continue 'outer;
628 }
629 }
630 i += 1;
631 }
632 }
633}
634
635fn extract_enums(ast: &mut AstSrc) {
636 for node in &mut ast.nodes {
637 for enm in &ast.enums {
638 let mut to_remove = Vec::new();
639 for (i, field) in node.fields.iter().enumerate() {
640 let ty = field.ty().to_string();
641 if enm.variants.iter().any(|it| it == &ty) {
642 to_remove.push(i);
643 }
644 }
645 if to_remove.len() == enm.variants.len() {
646 node.remove_field(to_remove);
647 let ty = enm.name.clone();
648 let name = to_lower_snake_case(&ty);
649 node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
650 }
651 }
652 }
653}
654
655fn extract_struct_traits(ast: &mut AstSrc) {
656 let traits: &[(&str, &[&str])] = &[
657 ("AttrsOwner", &["attrs"]),
658 ("NameOwner", &["name"]),
659 ("VisibilityOwner", &["visibility"]),
660 ("GenericParamsOwner", &["generic_param_list", "where_clause"]),
661 ("TypeBoundsOwner", &["type_bound_list", "colon_token"]),
662 ("ModuleItemOwner", &["items"]),
663 ("LoopBodyOwner", &["label", "loop_body"]),
664 ("ArgListOwner", &["arg_list"]),
665 ];
666
667 for node in &mut ast.nodes {
668 for (name, methods) in traits {
669 extract_struct_trait(node, name, methods);
670 }
671 }
672}
673
674fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
675 let mut to_remove = Vec::new();
676 for (i, field) in node.fields.iter().enumerate() {
677 let method_name = field.method_name().to_string();
678 if methods.iter().any(|&it| it == &method_name) {
679 to_remove.push(i);
680 }
681 }
682 if to_remove.len() == methods.len() {
683 node.traits.push(trait_name.to_string());
684 node.remove_field(to_remove);
685 }
686}
687
688fn extract_enum_traits(ast: &mut AstSrc) {
689 for enm in &mut ast.enums {
690 let nodes = &ast.nodes;
691 let mut variant_traits = enm
692 .variants
693 .iter()
694 .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
695 .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
696
697 let mut enum_traits = match variant_traits.next() {
698 Some(it) => it,
699 None => continue,
700 };
701 for traits in variant_traits {
702 enum_traits = enum_traits.intersection(&traits).cloned().collect();
703 }
704 enm.traits = enum_traits.into_iter().collect();
705 }
706}
707
708impl AstNodeSrc {
709 fn remove_field(&mut self, to_remove: Vec<usize>) {
710 to_remove.into_iter().rev().for_each(|idx| {
711 self.fields.remove(idx);
712 });
713 }
714}
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
new file mode 100644
index 000000000..375df301f
--- /dev/null
+++ b/xtask/src/codegen/rust.ungram
@@ -0,0 +1,544 @@
1SourceFile =
2 'shebang'?
3 Attr*
4 Item*
5
6Item =
7 Const
8| Enum
9| ExternBlock
10| ExternCrate
11| Fn
12| Impl
13| MacroCall
14| Module
15| Static
16| Struct
17| Trait
18| TypeAlias
19| Union
20| Use
21
22Module =
23 Attr* Visibility? 'mod' Name
24 (ItemList | ';')
25
26ItemList =
27 '{' Attr* Item* '}'
28
29ExternCrate =
30 Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
31
32Rename =
33 'as' (Name | '_')
34
35Use =
36 Attr* Visibility? 'use' UseTree ';'
37
38UseTree =
39 (Path? '::')? ('*' | UseTreeList )
40| Path Rename?
41
42UseTreeList =
43 '{' (UseTree (',' UseTree)* ','?)? '}'
44
45Fn =
46 Attr* Visibility?
47 'default'? ('async' | 'const')? 'unsafe'? Abi?
48 'fn' Name GenericParamList? ParamList RetType?
49 WhereClause?
50 (body:BlockExpr | ';')
51
52Abi =
53 'extern' 'string'?
54
55ParamList =
56 '('(
57 SelfParam
58 | (SelfParam ',')? (Param (',' Param)* ','?)?
59 )')'
60
61SelfParam =
62 Attr* (
63 ('&' 'lifetime'?)? 'mut'? 'self'
64 | 'mut'? 'self' ':' ty:TypeRef
65 )
66
67Param =
68 Attr* (
69 Pat (':' ty:TypeRef)
70 | ty:TypeRef
71 | '...'
72 )
73
74RetType =
75 '->' ty:TypeRef
76
77TypeAlias =
78 Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
79 '=' ty:TypeRef ';'
80
81Struct =
82 Attr* Visibility? 'struct' Name GenericParamList? (
83 WhereClause? (RecordFieldList | ';')
84 | TupleFieldList WhereClause? ';'
85 )
86
87RecordFieldList =
88 '{' fields:(RecordField (',' RecordField)* ','?)? '}'
89
90RecordField =
91 Attr* Visibility? Name ':' ty:TypeRef
92
93TupleFieldList =
94 '(' fields:(TupleField (',' TupleField)* ','?)? ')'
95
96TupleField =
97 Attr* Visibility? ty:TypeRef
98
99FieldList =
100 RecordFieldList
101| TupleFieldList
102
103Enum =
104 Attr* Visibility? 'enum' Name GenericParamList? WhereClause?
105 VariantList
106
107VariantList =
108 '{' (Variant (',' Variant)* ','?)? '}'
109
110Variant =
111 Attr* Visibility? Name FieldList ('=' Expr)?
112
113Union =
114 Attr* Visibility? 'union' Name GenericParamList? WhereClause?
115 RecordFieldList
116
117Const =
118 Attr* Visibility? 'default'? 'const' (Name | '_') ':' ty:TypeRef
119 '=' body:Expr ';'
120
121Static =
122 Attr* Visibility? 'static'? 'mut'? Name ':' ty:TypeRef
123 '=' body:Expr ';'
124
125Trait =
126 Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList
127 (':' TypeBoundList?)? WhereClause
128 AssocItemList
129
130AssocItemList =
131 '{' Attr* AssocItem* '}'
132
133AssocItem =
134 Fn
135| TypeAlias
136| Const
137| MacroCall
138
139Impl =
140 Attr* Visibility?
141 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? (
142 TypeRef
143 | '!'? TypeRef 'for' TypeRef
144 ) WhereClause?
145 AssocItemList
146
147ExternBlock =
148 Attr* Abi ExternItemList
149
150ExternItemList =
151 '{' Attr* ExternItem* '}'
152
153ExternItem =
154 Fn | Static | MacroCall
155
156GenericParamList =
157 '<' (GenericParam (',' GenericParam)* ','?)? '>'
158
159GenericParam =
160 LifetimeParam
161| TypeParam
162| ConstParam
163
164TypeParam =
165 Attr* Name (':' TypeBoundList?)?
166 ('=' default_type:TypeRef)?
167
168ConstParam =
169 Attr* 'const' Name ':' ty:TypeRef
170 ('=' default_val:Expr)?
171
172LifetimeParam =
173 Attr* 'lifetime'
174
175Visibility =
176 'pub' ('('
177 'super'
178 | 'self'
179 | 'crate'
180 | 'in' Path
181 ')')?
182
183Attr =
184 '#' '!'? '[' Path ('=' Literal | TokenTree)? ']'
185
186ParenType =
187 '(' ty:TypeRef ')'
188
189TupleType =
190 '(' fields:TypeRef* ')'
191
192NeverType =
193 '!'
194
195PathType =
196 Path
197
198PointerType =
199 '*' ('const' | 'mut') ty:TypeRef
200
201ArrayType =
202 '[' ty:TypeRef ';' Expr ']'
203
204SliceType =
205 '[' ty:TypeRef ']'
206
207ReferenceType =
208 '&' 'lifetime'? 'mut'? ty:TypeRef
209
210PlaceholderType =
211 '_'
212
213FnPointerType =
214 Abi 'unsafe'? 'fn' ParamList RetType?
215
216ForType =
217 'for' GenericParamList ty:TypeRef
218
219ImplTraitType =
220 'impl' TypeBoundList
221
222DynTraitType =
223 'dyn' TypeBoundList
224
225TupleExpr =
226 Attr* '(' Expr* ')'
227
228ArrayExpr =
229 Attr* '[' (Expr* | Expr ';' Expr) ']'
230
231ParenExpr =
232 Attr* '(' Expr ')'
233
234PathExpr =
235 Path
236
237LambdaExpr =
238 Attr* 'static'? 'async'? 'move'? ParamList RetType?
239 body:Expr
240
241IfExpr =
242 Attr* 'if' Condition
243
244Condition =
245 'let' Pat '=' Expr
246| Expr
247
248EffectExpr =
249 Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr
250
251LoopExpr =
252 Attr* Label? 'loop'
253 loop_body:BlockExpr?
254
255ForExpr =
256 Attr* Label? 'for' Pat 'in' iterable:Expr
257 loop_body:BlockExpr?
258
259WhileExpr =
260 Attr* Label? 'while' Condition
261 loop_body:BlockExpr?
262
263ContinueExpr =
264 Attr* 'continue' 'lifetime'?
265
266BreakExpr =
267 Attr* 'break' 'lifetime'? Expr?
268
269Label =
270 'lifetime'
271
272BlockExpr =
273 Attr* Label
274 '{'
275 Item*
276 statements:Stmt*
277 Expr?
278 '}'
279
280ReturnExpr =
281 Attr* 'return' Expr
282
283CallExpr =
284 Attr* Expr ArgList
285
286MethodCallExpr =
287 Attr* Expr '.' NameRef TypeArgList? ArgList
288
289ArgList =
290 '(' args:Expr* ')'
291
292FieldExpr =
293 Attr* Expr '.' NameRef
294
295IndexExpr =
296 Attr* '[' ']'
297
298AwaitExpr =
299 Attr* Expr '.' 'await'
300
301TryExpr =
302 Attr* Expr '?'
303
304CastExpr =
305 Attr* Expr 'as' ty:TypeRef
306
307RefExpr =
308 Attr* '&' ('raw' | 'mut' | 'const') Expr
309
310PrefixExpr =
311 Attr* Expr
312
313BoxExpr =
314 Attr* 'box' Expr
315
316RangeExpr =
317 Attr*
318
319BinExpr =
320 Attr*
321
322Literal =
323 'int_number'
324
325MatchExpr =
326 Attr* 'match' Expr MatchArmList
327
328MatchArmList =
329 '{' arms:MatchArm* '}'
330
331MatchArm =
332 Attr* Pat guard:MatchGuard? '=>' Expr
333
334MatchGuard =
335 'if' Expr
336
337RecordExpr =
338 Path RecordExprFieldList
339
340RecordExprFieldList =
341 '{'
342 fields:RecordExprField*
343 ('..' spread:Expr)?
344 '}'
345
346RecordExprField =
347 Attr* NameRef (':' Expr)?
348
349OrPat =
350 Pat*
351
352ParenPat =
353 '(' Pat ')'
354
355RefPat =
356 '&' 'mut'? Pat
357
358BoxPat =
359 'box' Path
360
361BindPat =
362 Attr* 'ref'? 'mut'? Name ('@' Pat)?
363
364PlaceholderPat =
365 '_'
366
367DotDotPat =
368 '..'
369
370PathPat =
371 Path
372
373SlicePat =
374 '[' args:Pat* ']'
375
376RangePat =
377 '..' | '..='
378
379LiteralPat =
380 Literal
381
382MacroPat =
383 MacroCall
384
385RecordPat =
386 Path RecordFieldPatList
387
388RecordFieldPatList =
389 '{'
390 record_field_pats:RecordFieldPat*
391 BindPat*
392 '..'?
393 '}'
394
395RecordFieldPat =
396 Attr* NameRef ':' Pat
397
398TupleStructPat =
399 Path '(' args:Pat* ')'
400
401TuplePat =
402 '(' args:Pat* ')'
403
404Name =
405 'ident'
406
407NameRef =
408 'ident' | 'int_number'
409
410MacroCall =
411 Attr* Path '!' Name? TokenTree ';'?
412
413MacroDef =
414 Name TokenTree
415
416TokenTree =
417 '(' ')' | '{' '}' | '[' ']'
418
419MacroItems =
420 Item*
421
422MacroStmts =
423 statements:Stmt*
424 Expr?
425
426TypeBound =
427 'lifetime' | 'const'? TypeRef
428
429TypeBoundList =
430 bounds:TypeBound*
431
432WherePred =
433 ('for' GenericParamList)? ('lifetime' | TypeRef) ':' TypeBoundList
434
435WhereClause =
436 'where' predicates:WherePred*
437
438ExprStmt =
439 Attr* Expr ';'
440
441LetStmt =
442 Attr* 'let' Pat (':' ty:TypeRef)
443 '=' initializer:Expr ';'
444
445Path =
446 (qualifier:Path '::')? segment:PathSegment
447
448PathSegment =
449 '::' | 'crate' | 'self' | 'super'
450| '<' NameRef TypeArgList ParamList RetType PathType '>'
451
452TypeArgList =
453 '::'? '<'
454 TypeArg*
455 LifetimeArg*
456 AssocTypeArg*
457 ConstArg*
458 '>'
459
460TypeArg =
461 TypeRef
462
463AssocTypeArg =
464 NameRef (':' TypeBoundList | '=' TypeRef)
465
466LifetimeArg =
467 'lifetime'
468
469ConstArg =
470 Literal | BlockExpr BlockExpr
471
472AdtDef =
473 Struct
474| Enum
475| Union
476
477TypeRef =
478 ParenType
479| TupleType
480| NeverType
481| PathType
482| PointerType
483| ArrayType
484| SliceType
485| ReferenceType
486| PlaceholderType
487| FnPointerType
488| ForType
489| ImplTraitType
490| DynTraitType
491
492Stmt =
493 LetStmt
494| ExprStmt
495
496Pat =
497 OrPat
498| ParenPat
499| RefPat
500| BoxPat
501| BindPat
502| PlaceholderPat
503| DotDotPat
504| PathPat
505| RecordPat
506| TupleStructPat
507| TuplePat
508| SlicePat
509| RangePat
510| LiteralPat
511| MacroPat
512
513Expr =
514 TupleExpr
515| ArrayExpr
516| ParenExpr
517| PathExpr
518| LambdaExpr
519| IfExpr
520| LoopExpr
521| ForExpr
522| WhileExpr
523| ContinueExpr
524| BreakExpr
525| Label
526| BlockExpr
527| ReturnExpr
528| MatchExpr
529| RecordExpr
530| CallExpr
531| IndexExpr
532| MethodCallExpr
533| FieldExpr
534| AwaitExpr
535| TryExpr
536| EffectExpr
537| CastExpr
538| RefExpr
539| PrefixExpr
540| RangeExpr
541| BinExpr
542| Literal
543| MacroCall
544| BoxExpr
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index aef68089e..01d903cde 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -1,4 +1,10 @@
1use std::path::PathBuf; 1use flate2::{write::GzEncoder, Compression};
2use std::{
3 env,
4 fs::File,
5 io,
6 path::{Path, PathBuf},
7};
2 8
3use anyhow::Result; 9use anyhow::Result;
4 10
@@ -7,17 +13,24 @@ use crate::{
7 project_root, 13 project_root,
8}; 14};
9 15
10pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> { 16pub struct DistCmd {
11 let dist = project_root().join("dist"); 17 pub nightly: bool,
12 rm_rf(&dist)?; 18 pub client_version: Option<String>,
13 fs2::create_dir_all(&dist)?; 19}
20
21impl DistCmd {
22 pub fn run(self) -> Result<()> {
23 let dist = project_root().join("dist");
24 rm_rf(&dist)?;
25 fs2::create_dir_all(&dist)?;
14 26
15 if let Some(version) = client_version { 27 if let Some(version) = self.client_version {
16 let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; 28 let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? };
17 dist_client(&version, &release_tag)?; 29 dist_client(&version, &release_tag)?;
30 }
31 dist_server()?;
32 Ok(())
18 } 33 }
19 dist_server(nightly)?;
20 Ok(())
21} 34}
22 35
23fn dist_client(version: &str, release_tag: &str) -> Result<()> { 36fn dist_client(version: &str, release_tag: &str) -> Result<()> {
@@ -46,17 +59,12 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
46 Ok(()) 59 Ok(())
47} 60}
48 61
49fn dist_server(nightly: bool) -> Result<()> { 62fn dist_server() -> Result<()> {
50 if cfg!(target_os = "linux") { 63 if cfg!(target_os = "linux") {
51 std::env::set_var("CC", "clang"); 64 env::set_var("CC", "clang");
52 run!( 65 run!(
53 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" 66 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release"
54 // We'd want to add, but that requires setting the right linker somehow
55 // --features=jemalloc
56 )?; 67 )?;
57 if !nightly {
58 run!("strip ./target/release/rust-analyzer")?;
59 }
60 } else { 68 } else {
61 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; 69 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?;
62 } 70 }
@@ -71,8 +79,20 @@ fn dist_server(nightly: bool) -> Result<()> {
71 panic!("Unsupported OS") 79 panic!("Unsupported OS")
72 }; 80 };
73 81
74 fs2::copy(src, dst)?; 82 let src = Path::new(src);
83 let dst = Path::new(dst);
84
85 fs2::copy(&src, &dst)?;
86 gzip(&src, &dst.with_extension("gz"))?;
87
88 Ok(())
89}
75 90
91fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
92 let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
93 let mut input = io::BufReader::new(File::open(src_path)?);
94 io::copy(&mut input, &mut encoder)?;
95 encoder.finish()?;
76 Ok(()) 96 Ok(())
77} 97}
78 98
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 9ba77a3aa..b25a6e301 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -19,7 +19,12 @@ pub enum ClientOpt {
19} 19}
20 20
21pub struct ServerOpt { 21pub struct ServerOpt {
22 pub jemalloc: bool, 22 pub malloc: Malloc,
23}
24
25pub enum Malloc {
26 System,
27 Mimalloc,
23} 28}
24 29
25impl InstallCmd { 30impl InstallCmd {
@@ -130,8 +135,11 @@ fn install_server(opts: ServerOpt) -> Result<()> {
130 ) 135 )
131 } 136 }
132 137
133 let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" }; 138 let malloc_feature = match opts.malloc {
134 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", jemalloc); 139 Malloc::System => "",
140 Malloc::Mimalloc => "--features mimalloc",
141 };
142 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature);
135 143
136 if res.is_err() && old_rust { 144 if res.is_err() && old_rust {
137 eprintln!( 145 eprintln!(
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 747654c1f..2fdb08f2e 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -7,6 +7,7 @@ pub mod install;
7pub mod release; 7pub mod release;
8pub mod dist; 8pub mod dist;
9pub mod pre_commit; 9pub mod pre_commit;
10pub mod metrics;
10 11
11pub mod codegen; 12pub mod codegen;
12mod ast_src; 13mod ast_src;
@@ -20,7 +21,7 @@ use walkdir::{DirEntry, WalkDir};
20 21
21use crate::{ 22use crate::{
22 codegen::Mode, 23 codegen::Mode,
23 not_bash::{fs2, pushd, pushenv, rm_rf, run}, 24 not_bash::{fs2, pushd, pushenv, rm_rf},
24}; 25};
25 26
26pub use anyhow::{bail, Context as _, Result}; 27pub use anyhow::{bail, Context as _, Result};
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index f7a79362d..b69b884e5 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -13,11 +13,12 @@ use std::env;
13use pico_args::Arguments; 13use pico_args::Arguments;
14use xtask::{ 14use xtask::{
15 codegen::{self, Mode}, 15 codegen::{self, Mode},
16 dist::run_dist, 16 dist::DistCmd,
17 install::{ClientOpt, InstallCmd, ServerOpt}, 17 install::{ClientOpt, InstallCmd, Malloc, ServerOpt},
18 metrics::MetricsCmd,
18 not_bash::pushd, 19 not_bash::pushd,
19 pre_commit, project_root, 20 pre_commit, project_root,
20 release::ReleaseCmd, 21 release::{PromoteCmd, ReleaseCmd},
21 run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result, 22 run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result,
22}; 23};
23 24
@@ -45,7 +46,7 @@ USAGE:
45FLAGS: 46FLAGS:
46 --client-code Install only VS Code plugin 47 --client-code Install only VS Code plugin
47 --server Install only the language server 48 --server Install only the language server
48 --jemalloc Use jemalloc for server 49 --mimalloc Use mimalloc for server
49 -h, --help Prints help information 50 -h, --help Prints help information
50 " 51 "
51 ); 52 );
@@ -61,13 +62,14 @@ FLAGS:
61 return Ok(()); 62 return Ok(());
62 } 63 }
63 64
64 let jemalloc = args.contains("--jemalloc"); 65 let malloc =
66 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };
65 67
66 args.finish()?; 68 args.finish()?;
67 69
68 InstallCmd { 70 InstallCmd {
69 client: if server { None } else { Some(ClientOpt::VsCode) }, 71 client: if server { None } else { Some(ClientOpt::VsCode) },
70 server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, 72 server: if client_code { None } else { Some(ServerOpt { malloc }) },
71 } 73 }
72 .run() 74 .run()
73 } 75 }
@@ -105,11 +107,21 @@ FLAGS:
105 args.finish()?; 107 args.finish()?;
106 ReleaseCmd { dry_run }.run() 108 ReleaseCmd { dry_run }.run()
107 } 109 }
110 "promote" => {
111 let dry_run = args.contains("--dry-run");
112 args.finish()?;
113 PromoteCmd { dry_run }.run()
114 }
108 "dist" => { 115 "dist" => {
109 let nightly = args.contains("--nightly"); 116 let nightly = args.contains("--nightly");
110 let client_version: Option<String> = args.opt_value_from_str("--client")?; 117 let client_version: Option<String> = args.opt_value_from_str("--client")?;
111 args.finish()?; 118 args.finish()?;
112 run_dist(nightly, client_version) 119 DistCmd { nightly, client_version }.run()
120 }
121 "metrics" => {
122 let dry_run = args.contains("--dry-run");
123 args.finish()?;
124 MetricsCmd { dry_run }.run()
113 } 125 }
114 _ => { 126 _ => {
115 eprintln!( 127 eprintln!(
@@ -127,7 +139,8 @@ SUBCOMMANDS:
127 codegen 139 codegen
128 install 140 install
129 lint 141 lint
130 dist" 142 dist
143 promote"
131 ); 144 );
132 Ok(()) 145 Ok(())
133 } 146 }
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
new file mode 100644
index 000000000..9ac3fa51d
--- /dev/null
+++ b/xtask/src/metrics.rs
@@ -0,0 +1,279 @@
1use std::{
2 collections::BTreeMap,
3 env,
4 fmt::{self, Write as _},
5 io::Write as _,
6 path::Path,
7 time::{Instant, SystemTime, UNIX_EPOCH},
8};
9
10use anyhow::{bail, format_err, Result};
11
12use crate::not_bash::{fs2, pushd, pushenv, rm_rf, run};
13
14type Unit = String;
15
16pub struct MetricsCmd {
17 pub dry_run: bool,
18}
19
20impl MetricsCmd {
21 pub fn run(self) -> Result<()> {
22 let mut metrics = Metrics::new()?;
23 if !self.dry_run {
24 rm_rf("./target/release")?;
25 }
26 if !Path::new("./target/rustc-perf").exists() {
27 fs2::create_dir_all("./target/rustc-perf")?;
28 run!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")?;
29 }
30 {
31 let _d = pushd("./target/rustc-perf");
32 run!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033")?;
33 }
34
35 let _env = pushenv("RA_METRICS", "1");
36
37 metrics.measure_build()?;
38 metrics.measure_analysis_stats_self()?;
39 metrics.measure_analysis_stats("ripgrep")?;
40 metrics.measure_analysis_stats("webrender")?;
41
42 if !self.dry_run {
43 let _d = pushd("target");
44 let metrics_token = env::var("METRICS_TOKEN").unwrap();
45 let repo = format!("https://{}@github.com/rust-analyzer/metrics.git", metrics_token);
46 run!("git clone --depth 1 {}", repo)?;
47 let _d = pushd("metrics");
48
49 let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
50 writeln!(file, "{}", metrics.json())?;
51 run!("git add .")?;
52 run!("git -c user.name=Bot -c [email protected] commit --message 📈")?;
53 run!("git push origin master")?;
54 }
55 eprintln!("{:#?}", metrics);
56 Ok(())
57 }
58}
59
60impl Metrics {
61 fn measure_build(&mut self) -> Result<()> {
62 eprintln!("\nMeasuring build");
63 run!("cargo fetch")?;
64
65 let time = Instant::now();
66 run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?;
67 let time = time.elapsed();
68 self.report("build", time.as_millis() as u64, "ms".into());
69 Ok(())
70 }
71 fn measure_analysis_stats_self(&mut self) -> Result<()> {
72 self.measure_analysis_stats_path("self", &".")
73 }
74 fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
75 self.measure_analysis_stats_path(
76 bench,
77 &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
78 )
79 }
80 fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
81 eprintln!("\nMeasuring analysis-stats/{}", name);
82 let output = run!("./target/release/rust-analyzer analysis-stats --quiet {}", path)?;
83 for (metric, value, unit) in parse_metrics(&output) {
84 self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
85 }
86 Ok(())
87 }
88}
89
90fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> {
91 output
92 .lines()
93 .filter_map(|it| {
94 let entry = it.split(':').collect::<Vec<_>>();
95 match entry.as_slice() {
96 ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)),
97 _ => None,
98 }
99 })
100 .collect()
101}
102
103#[derive(Debug)]
104struct Metrics {
105 host: Host,
106 timestamp: SystemTime,
107 revision: String,
108 metrics: BTreeMap<String, (u64, Unit)>,
109}
110
111#[derive(Debug)]
112struct Host {
113 os: String,
114 cpu: String,
115 mem: String,
116}
117
118impl Metrics {
119 fn new() -> Result<Metrics> {
120 let host = Host::new()?;
121 let timestamp = SystemTime::now();
122 let revision = run!("git rev-parse HEAD")?;
123 Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
124 }
125
126 fn report(&mut self, name: &str, value: u64, unit: Unit) {
127 self.metrics.insert(name.into(), (value, unit));
128 }
129
130 fn json(&self) -> Json {
131 let mut json = Json::default();
132 self.to_json(&mut json);
133 json
134 }
135 fn to_json(&self, json: &mut Json) {
136 json.begin_object();
137 {
138 json.field("host");
139 self.host.to_json(json);
140
141 json.field("timestamp");
142 let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
143 json.number(timestamp.as_secs() as f64);
144
145 json.field("revision");
146 json.string(&self.revision);
147
148 json.field("metrics");
149 json.begin_object();
150 {
151 for (k, (value, unit)) in &self.metrics {
152 json.field(k);
153 json.begin_array();
154 {
155 json.number(*value as f64);
156 json.string(unit);
157 }
158 json.end_array();
159 }
160 }
161 json.end_object()
162 }
163 json.end_object();
164 }
165}
166
167impl Host {
168 fn new() -> Result<Host> {
169 if cfg!(not(target_os = "linux")) {
170 bail!("can only collect metrics on Linux ");
171 }
172
173 let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
174
175 let cpu =
176 read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();
177
178 let mem = read_field("/proc/meminfo", "MemTotal:")?;
179
180 return Ok(Host { os, cpu, mem });
181
182 fn read_field<'a>(path: &str, field: &str) -> Result<String> {
183 let text = fs2::read_to_string(path)?;
184
185 let line = text
186 .lines()
187 .find(|it| it.starts_with(field))
188 .ok_or_else(|| format_err!("can't parse {}", path))?;
189 Ok(line[field.len()..].trim().to_string())
190 }
191 }
192 fn to_json(&self, json: &mut Json) {
193 json.begin_object();
194 {
195 json.field("os");
196 json.string(&self.os);
197
198 json.field("cpu");
199 json.string(&self.cpu);
200
201 json.field("mem");
202 json.string(&self.mem);
203 }
204 json.end_object();
205 }
206}
207
208struct State {
209 obj: bool,
210 first: bool,
211}
212
213#[derive(Default)]
214struct Json {
215 stack: Vec<State>,
216 buf: String,
217}
218
219impl Json {
220 fn begin_object(&mut self) {
221 self.stack.push(State { obj: true, first: true });
222 self.buf.push('{');
223 }
224 fn end_object(&mut self) {
225 self.stack.pop();
226 self.buf.push('}')
227 }
228 fn begin_array(&mut self) {
229 self.stack.push(State { obj: false, first: true });
230 self.buf.push('[');
231 }
232 fn end_array(&mut self) {
233 self.stack.pop();
234 self.buf.push(']')
235 }
236 fn field(&mut self, name: &str) {
237 self.object_comma();
238 self.string_token(name);
239 self.buf.push(':');
240 }
241 fn string(&mut self, value: &str) {
242 self.array_comma();
243 self.string_token(value);
244 }
245 fn string_token(&mut self, value: &str) {
246 self.buf.push('"');
247 self.buf.extend(value.escape_default());
248 self.buf.push('"');
249 }
250 fn number(&mut self, value: f64) {
251 self.array_comma();
252 write!(self.buf, "{}", value).unwrap();
253 }
254
255 fn array_comma(&mut self) {
256 let state = self.stack.last_mut().unwrap();
257 if state.obj {
258 return;
259 }
260 if !state.first {
261 self.buf.push(',');
262 }
263 state.first = false;
264 }
265
266 fn object_comma(&mut self) {
267 let state = self.stack.last_mut().unwrap();
268 if !state.first {
269 self.buf.push(',');
270 }
271 state.first = false;
272 }
273}
274
275impl fmt::Display for Json {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "{}", self.buf)
278 }
279}
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
index a6431e586..ef811e5bf 100644
--- a/xtask/src/not_bash.rs
+++ b/xtask/src/not_bash.rs
@@ -54,7 +54,8 @@ pub mod fs2 {
54 } 54 }
55} 55}
56 56
57macro_rules! _run { 57#[macro_export]
58macro_rules! run {
58 ($($expr:expr),*) => { 59 ($($expr:expr),*) => {
59 run!($($expr),*; echo = true) 60 run!($($expr),*; echo = true)
60 }; 61 };
@@ -65,7 +66,7 @@ macro_rules! _run {
65 $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) 66 $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin))
66 }; 67 };
67} 68}
68pub(crate) use _run as run; 69pub use crate::run;
69 70
70pub struct Pushd { 71pub struct Pushd {
71 _p: (), 72 _p: (),
@@ -153,7 +154,17 @@ fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<Stri
153 154
154// FIXME: some real shell lexing here 155// FIXME: some real shell lexing here
155fn shelx(cmd: &str) -> Vec<String> { 156fn shelx(cmd: &str) -> Vec<String> {
156 cmd.split_whitespace().map(|it| it.to_string()).collect() 157 let mut res = Vec::new();
158 for (string_piece, in_quotes) in cmd.split('\'').zip([false, true].iter().copied().cycle()) {
159 if in_quotes {
160 res.push(string_piece.to_string())
161 } else {
162 if !string_piece.is_empty() {
163 res.extend(string_piece.split_ascii_whitespace().map(|it| it.to_string()))
164 }
165 }
166 }
167 res
157} 168}
158 169
159struct Env { 170struct Env {
@@ -175,7 +186,8 @@ impl Env {
175 fn pushd(&mut self, dir: PathBuf) { 186 fn pushd(&mut self, dir: PathBuf) {
176 let dir = self.cwd().join(dir); 187 let dir = self.cwd().join(dir);
177 self.pushd_stack.push(dir); 188 self.pushd_stack.push(dir);
178 env::set_current_dir(self.cwd()).unwrap(); 189 env::set_current_dir(self.cwd())
190 .unwrap_or_else(|err| panic!("Failed to set cwd to {}: {}", self.cwd().display(), err));
179 } 191 }
180 fn popd(&mut self) { 192 fn popd(&mut self) {
181 self.pushd_stack.pop().unwrap(); 193 self.pushd_stack.pop().unwrap();
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index b6502b952..7fa0966aa 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -1,6 +1,6 @@
1use crate::{ 1use crate::{
2 codegen, is_release_tag, 2 codegen, is_release_tag,
3 not_bash::{date_iso, fs2, run}, 3 not_bash::{date_iso, fs2, pushd, run},
4 project_root, Mode, Result, 4 project_root, Mode, Result,
5}; 5};
6 6
@@ -37,6 +37,8 @@ Release: release:{}[]
37 37
38== Sponsors 38== Sponsors
39 39
40**Become a sponsor:** https://opencollective.com/rust-analyzer/[opencollective.com/rust-analyzer]
41
40== New Features 42== New Features
41 43
42* pr:[] . 44* pr:[] .
@@ -67,3 +69,35 @@ Release: release:{}[]
67 Ok(()) 69 Ok(())
68 } 70 }
69} 71}
72
73pub struct PromoteCmd {
74 pub dry_run: bool,
75}
76
77impl PromoteCmd {
78 pub fn run(self) -> Result<()> {
79 let _dir = pushd("../rust-rust-analyzer");
80 run!("git switch master")?;
81 run!("git fetch upstream")?;
82 run!("git reset --hard upstream/master")?;
83 run!("git submodule update --recursive")?;
84
85 let branch = format!("rust-analyzer-{}", date_iso()?);
86 run!("git switch -c {}", branch)?;
87 {
88 let _dir = pushd("src/tools/rust-analyzer");
89 run!("git fetch origin")?;
90 run!("git reset --hard origin/release")?;
91 }
92 run!("git add src/tools/rust-analyzer")?;
93 run!("git commit -m':arrow_up: rust-analyzer'")?;
94 if !self.dry_run {
95 run!("git push")?;
96 run!(
97 "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost",
98 branch
99 )?;
100 }
101 Ok(())
102 }
103}
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index d38ac7f17..d65a2acbc 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -5,7 +5,7 @@ use std::{
5 5
6use xtask::{ 6use xtask::{
7 codegen::{self, Mode}, 7 codegen::{self, Mode},
8 not_bash::fs2, 8 not_bash::{fs2, run},
9 project_root, run_rustfmt, rust_files, 9 project_root, run_rustfmt, rust_files,
10}; 10};
11 11
@@ -49,19 +49,56 @@ fn rust_files_are_tidy() {
49 tidy_docs.finish(); 49 tidy_docs.finish();
50} 50}
51 51
52#[test]
53fn check_licenses() {
54 let expected = "
550BSD OR MIT OR Apache-2.0
56Apache-2.0 OR BSL-1.0
57Apache-2.0 OR MIT
58Apache-2.0/MIT
59BSD-2-Clause
60BSD-3-Clause
61CC0-1.0
62ISC
63MIT
64MIT / Apache-2.0
65MIT OR Apache-2.0
66MIT/Apache-2.0
67MIT/Apache-2.0 AND BSD-2-Clause
68Unlicense OR MIT
69Unlicense/MIT
70Zlib
71"
72 .lines()
73 .filter(|it| !it.is_empty())
74 .collect::<Vec<_>>();
75
76 let meta = run!("cargo metadata --format-version 1"; echo = false).unwrap();
77 let mut licenses = meta
78 .split(|c| c == ',' || c == '{' || c == '}')
79 .filter(|it| it.contains(r#""license""#))
80 .map(|it| it.trim())
81 .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
82 .collect::<Vec<_>>();
83 licenses.sort();
84 licenses.dedup();
85 assert_eq!(licenses, expected);
86}
87
52fn check_todo(path: &Path, text: &str) { 88fn check_todo(path: &Path, text: &str) {
53 let whitelist = &[ 89 let need_todo = &[
54 // This file itself is whitelisted since this test itself contains matches. 90 // This file itself obviously needs to use todo (<- like this!).
55 "tests/cli.rs", 91 "tests/cli.rs",
56 // Some of our assists generate `todo!()` so those files are whitelisted. 92 // Some of our assists generate `todo!()`.
57 "tests/generated.rs", 93 "tests/generated.rs",
58 "handlers/add_missing_impl_members.rs", 94 "handlers/add_missing_impl_members.rs",
59 "handlers/add_function.rs",
60 "handlers/add_turbo_fish.rs", 95 "handlers/add_turbo_fish.rs",
61 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make. 96 "handlers/generate_function.rs",
97 // To support generating `todo!()` in assists, we have `expr_todo()` in
98 // `ast::make`.
62 "ast/make.rs", 99 "ast/make.rs",
63 ]; 100 ];
64 if whitelist.iter().any(|p| path.ends_with(p)) { 101 if need_todo.iter().any(|p| path.ends_with(p)) {
65 return; 102 return;
66 } 103 }
67 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { 104 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
@@ -139,7 +176,7 @@ impl TidyDocs {
139 ) 176 )
140 } 177 }
141 178
142 let whitelist = [ 179 let poorly_documented = [
143 "ra_hir", 180 "ra_hir",
144 "ra_hir_expand", 181 "ra_hir_expand",
145 "ra_ide", 182 "ra_ide",
@@ -153,9 +190,9 @@ impl TidyDocs {
153 ]; 190 ];
154 191
155 let mut has_fixmes = 192 let mut has_fixmes =
156 whitelist.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>(); 193 poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
157 'outer: for path in self.contains_fixme { 194 'outer: for path in self.contains_fixme {
158 for krate in whitelist.iter() { 195 for krate in poorly_documented.iter() {
159 if path.components().any(|it| it.as_os_str() == *krate) { 196 if path.components().any(|it| it.as_os_str() == *krate) {
160 has_fixmes.insert(krate, true); 197 has_fixmes.insert(krate, true);
161 continue 'outer; 198 continue 'outer;
@@ -166,7 +203,7 @@ impl TidyDocs {
166 203
167 for (krate, has_fixme) in has_fixmes.iter() { 204 for (krate, has_fixme) in has_fixmes.iter() {
168 if !has_fixme { 205 if !has_fixme {
169 panic!("crate {} is fully documented, remove it from the white list", krate) 206 panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
170 } 207 }
171 } 208 }
172 } 209 }