aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-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
613 files changed, 31173 insertions, 32781 deletions
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 }