aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock118
-rw-r--r--PRIVACY.md18
-rw-r--r--README.md4
-rw-r--r--crates/base_db/src/fixture.rs45
-rw-r--r--crates/cfg/src/lib.rs17
-rw-r--r--crates/hir/src/has_source.rs2
-rw-r--r--crates/hir/src/lib.rs12
-rw-r--r--crates/hir/src/semantics.rs17
-rw-r--r--crates/hir_def/src/generics.rs10
-rw-r--r--crates/hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs4
-rw-r--r--crates/hir_def/src/nameres/collector.rs41
-rw-r--r--crates/hir_def/src/resolver.rs6
-rw-r--r--crates/hir_def/src/visibility.rs5
-rw-r--r--crates/hir_expand/src/builtin_macro.rs4
-rw-r--r--crates/hir_expand/src/hygiene.rs9
-rw-r--r--crates/hir_expand/src/lib.rs9
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/hir_ty/src/chalk_db.rs5
-rw-r--r--crates/hir_ty/src/consteval.rs3
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs9
-rw-r--r--crates/hir_ty/src/infer/coerce.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs26
-rw-r--r--crates/hir_ty/src/infer/pat.rs11
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/op.rs38
-rw-r--r--crates/hir_ty/src/test_db.rs10
-rw-r--r--crates/hir_ty/src/tests.rs235
-rw-r--r--crates/hir_ty/src/tests/coercion.rs1017
-rw-r--r--crates/hir_ty/src/tests/display_source_code.rs10
-rw-r--r--crates/hir_ty/src/tests/macros.rs29
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs363
-rw-r--r--crates/hir_ty/src/tests/patterns.rs80
-rw-r--r--crates/hir_ty/src/tests/regression.rs280
-rw-r--r--crates/hir_ty/src/tests/simple.rs793
-rw-r--r--crates/hir_ty/src/tests/traits.rs1086
-rw-r--r--crates/ide/Cargo.toml1
-rw-r--r--crates/ide/src/diagnostics.rs498
-rw-r--r--crates/ide/src/display/navigation_target.rs6
-rw-r--r--crates/ide/src/doc_links.rs18
-rw-r--r--crates/ide/src/fixture.rs8
-rw-r--r--crates/ide/src/goto_definition.rs10
-rw-r--r--crates/ide/src/goto_implementation.rs7
-rw-r--r--crates/ide/src/goto_type_definition.rs60
-rw-r--r--crates/ide/src/hover.rs47
-rw-r--r--crates/ide/src/inlay_hints.rs52
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/lib.rs26
-rw-r--r--crates/ide/src/references.rs5
-rw-r--r--crates/ide/src/rename.rs (renamed from crates/ide/src/references/rename.rs)460
-rw-r--r--crates/ide/src/syntax_highlighting.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs50
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/injection.html1
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html1
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs5
-rw-r--r--crates/ide/src/typing.rs36
-rw-r--r--crates/ide_assists/src/handlers/apply_demorgan.rs114
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs3
-rw-r--r--crates/ide_assists/src/handlers/convert_into_to_from.rs50
-rw-r--r--crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs135
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs747
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs29
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs45
-rw-r--r--crates/ide_assists/src/handlers/fix_visibility.rs34
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs41
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs83
-rw-r--r--crates/ide_assists/src/handlers/generate_deref.rs27
-rw-r--r--crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs105
-rw-r--r--crates/ide_assists/src/handlers/generate_function.rs49
-rw-r--r--crates/ide_assists/src/handlers/inline_local_variable.rs55
-rw-r--r--crates/ide_assists/src/handlers/move_module_to_file.rs65
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs1201
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs4
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs173
-rw-r--r--crates/ide_assists/src/handlers/replace_if_let_with_match.rs66
-rw-r--r--crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs5
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs13
-rw-r--r--crates/ide_assists/src/handlers/replace_unwrap_with_match.rs60
-rw-r--r--crates/ide_assists/src/handlers/unmerge_use.rs16
-rw-r--r--crates/ide_assists/src/lib.rs164
-rw-r--r--crates/ide_assists/src/tests.rs35
-rw-r--r--crates/ide_assists/src/tests/generated.rs27
-rw-r--r--crates/ide_assists/src/utils.rs6
-rw-r--r--crates/ide_completion/src/completions.rs134
-rw-r--r--crates/ide_completion/src/completions/attribute.rs7
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs66
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs3
-rw-r--r--crates/ide_completion/src/completions/attribute/repr.rs199
-rw-r--r--crates/ide_completion/src/completions/dot.rs9
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs6
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs4
-rw-r--r--crates/ide_completion/src/completions/keyword.rs278
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs13
-rw-r--r--crates/ide_completion/src/completions/mod_.rs138
-rw-r--r--crates/ide_completion/src/completions/pattern.rs397
-rw-r--r--crates/ide_completion/src/completions/postfix.rs31
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs336
-rw-r--r--crates/ide_completion/src/completions/record.rs30
-rw-r--r--crates/ide_completion/src/completions/snippet.rs32
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs313
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs278
-rw-r--r--crates/ide_completion/src/context.rs156
-rw-r--r--crates/ide_completion/src/item.rs2
-rw-r--r--crates/ide_completion/src/lib.rs123
-rw-r--r--crates/ide_completion/src/patterns.rs44
-rw-r--r--crates/ide_completion/src/render.rs212
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs4
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs2
-rw-r--r--crates/ide_completion/src/render/function.rs2
-rw-r--r--crates/ide_completion/src/render/macro_.rs8
-rw-r--r--crates/ide_completion/src/tests.rs (renamed from crates/ide_completion/src/test_utils.rs)74
-rw-r--r--crates/ide_completion/src/tests/item_list.rs223
-rw-r--r--crates/ide_completion/src/tests/items.rs95
-rw-r--r--crates/ide_completion/src/tests/pattern.rs348
-rw-r--r--crates/ide_completion/src/tests/type_pos.rs177
-rw-r--r--crates/ide_completion/src/tests/use_tree.rs255
-rw-r--r--crates/ide_db/src/assists.rs136
-rw-r--r--crates/ide_db/src/helpers.rs11
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs153
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs78
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs172
-rw-r--r--crates/ide_db/src/lib.rs6
-rw-r--r--crates/ide_db/src/path_transform.rs (renamed from crates/ide_assists/src/path_transform.rs)12
-rw-r--r--crates/ide_db/src/rename.rs468
-rw-r--r--crates/ide_diagnostics/Cargo.toml29
-rw-r--r--crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs (renamed from crates/ide/src/diagnostics/break_outside_of_loop.rs)8
-rw-r--r--crates/ide_diagnostics/src/handlers/field_shorthand.rs (renamed from crates/ide/src/diagnostics/field_shorthand.rs)6
-rw-r--r--crates/ide_diagnostics/src/handlers/inactive_code.rs (renamed from crates/ide/src/diagnostics/inactive_code.rs)35
-rw-r--r--crates/ide_diagnostics/src/handlers/incorrect_case.rs (renamed from crates/ide/src/diagnostics/incorrect_case.rs)115
-rw-r--r--crates/ide_diagnostics/src/handlers/macro_error.rs (renamed from crates/ide/src/diagnostics/macro_error.rs)26
-rw-r--r--crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs (renamed from crates/ide/src/diagnostics/mismatched_arg_count.rs)28
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_fields.rs (renamed from crates/ide/src/diagnostics/missing_fields.rs)42
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_match_arms.rs (renamed from crates/ide/src/diagnostics/missing_match_arms.rs)106
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs (renamed from crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs)85
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_unsafe.rs (renamed from crates/ide/src/diagnostics/missing_unsafe.rs)16
-rw-r--r--crates/ide_diagnostics/src/handlers/no_such_field.rs (renamed from crates/ide/src/diagnostics/no_such_field.rs)13
-rw-r--r--crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs (renamed from crates/ide/src/diagnostics/remove_this_semicolon.rs)11
-rw-r--r--crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs (renamed from crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs)93
-rw-r--r--crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs (renamed from crates/ide/src/diagnostics/unimplemented_builtin_macro.rs)7
-rw-r--r--crates/ide_diagnostics/src/handlers/unlinked_file.rs (renamed from crates/ide/src/diagnostics/unlinked_file.rs)30
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs (renamed from crates/ide/src/diagnostics/unresolved_extern_crate.rs)10
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_import.rs (renamed from crates/ide/src/diagnostics/unresolved_import.rs)24
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs (renamed from crates/ide/src/diagnostics/unresolved_macro_call.rs)14
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_module.rs (renamed from crates/ide/src/diagnostics/unresolved_module.rs)11
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs (renamed from crates/ide/src/diagnostics/unresolved_proc_macro.rs)7
-rw-r--r--crates/ide_diagnostics/src/handlers/useless_braces.rs148
-rw-r--r--crates/ide_diagnostics/src/lib.rs374
-rw-r--r--crates/mbe/src/expander/matcher.rs22
-rw-r--r--crates/parser/src/grammar/params.rs3
-rw-r--r--crates/proc_macro_api/src/version.rs10
-rw-r--r--crates/project_model/src/build_data.rs4
-rw-r--r--crates/project_model/src/cargo_workspace.rs17
-rw-r--r--crates/project_model/src/lib.rs2
-rw-r--r--crates/project_model/src/sysroot.rs11
-rw-r--r--crates/project_model/src/workspace.rs124
-rw-r--r--crates/rust-analyzer/src/config.rs22
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt2
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs34
-rw-r--r--crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt4
-rw-r--r--crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt8
-rw-r--r--crates/syntax/test_data/lexer/ok/0006_chars.txt16
-rw-r--r--crates/syntax/test_data/lexer/ok/0007_lifetimes.txt8
-rw-r--r--crates/syntax/test_data/lexer/ok/0008_byte_strings.txt14
-rw-r--r--crates/syntax/test_data/parser/err/0024_many_type_parens.rast16
-rw-r--r--crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast2
-rw-r--r--crates/syntax/test_data/parser/err/0043_weird_blocks.rast2
-rw-r--r--crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast30
-rw-r--r--crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0006_self_param.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast12
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0081_for_type.rast10
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0109_label.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast4
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast2
-rw-r--r--crates/syntax/test_data/parser/ok/0011_outer_attribute.rast2
-rw-r--r--crates/syntax/test_data/parser/ok/0011_outer_attribute.rs2
-rw-r--r--crates/syntax/test_data/parser/ok/0018_struct_type_params.rast34
-rw-r--r--crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast28
-rw-r--r--crates/syntax/test_data/parser/ok/0030_string_suffixes.rast4
-rw-r--r--crates/syntax/test_data/parser/ok/0032_where_for.rast4
-rw-r--r--crates/syntax/test_data/parser/ok/0033_label_break.rast14
-rw-r--r--crates/syntax/test_data/parser/ok/0035_weird_exprs.rast18
-rw-r--r--crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast12
-rw-r--r--crates/syntax/test_data/parser/ok/0067_where_for_pred.rast30
-rw-r--r--crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast6
-rw-r--r--crates/test_utils/src/fixture.rs194
-rw-r--r--crates/test_utils/src/lib.rs55
-rw-r--r--crates/test_utils/src/minicore.rs549
-rw-r--r--crates/vfs/src/vfs_path.rs2
-rw-r--r--docs/dev/debugging.md5
-rw-r--r--docs/dev/style.md7
-rw-r--r--docs/user/.gitignore1
-rw-r--r--docs/user/generated_config.adoc10
-rw-r--r--docs/user/manual.adoc20
-rw-r--r--editors/code/package-lock.json12
-rw-r--r--editors/code/package.json29
-rw-r--r--editors/code/src/main.ts14
-rw-r--r--editors/code/src/net.ts18
-rw-r--r--editors/code/src/toolchain.ts16
-rw-r--r--xtask/src/dist.rs4
-rw-r--r--xtask/src/install.rs2
-rw-r--r--xtask/src/tidy.rs33
244 files changed, 8815 insertions, 8083 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e47b87964..238c21f52 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -37,9 +37,9 @@ dependencies = [
37 37
38[[package]] 38[[package]]
39name = "anyhow" 39name = "anyhow"
40version = "1.0.40" 40version = "1.0.41"
41source = "registry+https://github.com/rust-lang/crates.io-index" 41source = "registry+https://github.com/rust-lang/crates.io-index"
42checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" 42checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
43 43
44[[package]] 44[[package]]
45name = "anymap" 45name = "anymap"
@@ -49,9 +49,9 @@ checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
49 49
50[[package]] 50[[package]]
51name = "arrayvec" 51name = "arrayvec"
52version = "0.7.0" 52version = "0.7.1"
53source = "registry+https://github.com/rust-lang/crates.io-index" 53source = "registry+https://github.com/rust-lang/crates.io-index"
54checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7" 54checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
55 55
56[[package]] 56[[package]]
57name = "atty" 57name = "atty"
@@ -216,20 +216,6 @@ dependencies = [
216 "petgraph", 216 "petgraph",
217 "rustc-hash", 217 "rustc-hash",
218 "tracing", 218 "tracing",
219 "tracing-subscriber",
220 "tracing-tree",
221]
222
223[[package]]
224name = "chrono"
225version = "0.4.19"
226source = "registry+https://github.com/rust-lang/crates.io-index"
227checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
228dependencies = [
229 "libc",
230 "num-integer",
231 "num-traits",
232 "winapi",
233] 219]
234 220
235[[package]] 221[[package]]
@@ -347,9 +333,9 @@ dependencies = [
347 333
348[[package]] 334[[package]]
349name = "env_logger" 335name = "env_logger"
350version = "0.8.3" 336version = "0.8.4"
351source = "registry+https://github.com/rust-lang/crates.io-index" 337source = "registry+https://github.com/rust-lang/crates.io-index"
352checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" 338checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
353dependencies = [ 339dependencies = [
354 "log", 340 "log",
355] 341]
@@ -435,9 +421,9 @@ dependencies = [
435 421
436[[package]] 422[[package]]
437name = "fst" 423name = "fst"
438version = "0.4.6" 424version = "0.4.7"
439source = "registry+https://github.com/rust-lang/crates.io-index" 425source = "registry+https://github.com/rust-lang/crates.io-index"
440checksum = "e398fae362f4124bbe630d99519fb2d68a03e2e3a23b441028cdcdc4f4895687" 426checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
441 427
442[[package]] 428[[package]]
443name = "gimli" 429name = "gimli"
@@ -591,6 +577,7 @@ dependencies = [
591 "ide_assists", 577 "ide_assists",
592 "ide_completion", 578 "ide_completion",
593 "ide_db", 579 "ide_db",
580 "ide_diagnostics",
594 "ide_ssr", 581 "ide_ssr",
595 "indexmap", 582 "indexmap",
596 "itertools", 583 "itertools",
@@ -669,6 +656,25 @@ dependencies = [
669] 656]
670 657
671[[package]] 658[[package]]
659name = "ide_diagnostics"
660version = "0.0.0"
661dependencies = [
662 "cfg",
663 "cov-mark",
664 "either",
665 "expect-test",
666 "hir",
667 "ide_db",
668 "itertools",
669 "profile",
670 "rustc-hash",
671 "stdx",
672 "syntax",
673 "test_utils",
674 "text_edit",
675]
676
677[[package]]
672name = "ide_ssr" 678name = "ide_ssr"
673version = "0.0.0" 679version = "0.0.0"
674dependencies = [ 680dependencies = [
@@ -735,9 +741,9 @@ dependencies = [
735 741
736[[package]] 742[[package]]
737name = "itertools" 743name = "itertools"
738version = "0.10.0" 744version = "0.10.1"
739source = "registry+https://github.com/rust-lang/crates.io-index" 745source = "registry+https://github.com/rust-lang/crates.io-index"
740checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" 746checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
741dependencies = [ 747dependencies = [
742 "either", 748 "either",
743] 749]
@@ -782,9 +788,9 @@ dependencies = [
782 788
783[[package]] 789[[package]]
784name = "libmimalloc-sys" 790name = "libmimalloc-sys"
785version = "0.1.21" 791version = "0.1.22"
786source = "registry+https://github.com/rust-lang/crates.io-index" 792source = "registry+https://github.com/rust-lang/crates.io-index"
787checksum = "2396cf99d2f58611cd69f0efeee4af3d2e2c7b61bed433515029163aa567e65c" 793checksum = "1d1b8479c593dba88c2741fc50b92e13dbabbbe0bd504d979f244ccc1a5b1c01"
788dependencies = [ 794dependencies = [
789 "cc", 795 "cc",
790] 796]
@@ -821,9 +827,9 @@ dependencies = [
821 827
822[[package]] 828[[package]]
823name = "lsp-types" 829name = "lsp-types"
824version = "0.89.1" 830version = "0.89.2"
825source = "registry+https://github.com/rust-lang/crates.io-index" 831source = "registry+https://github.com/rust-lang/crates.io-index"
826checksum = "48b8a871b0a450bcec0e26d74a59583c8173cb9fb7d7f98889e18abb84838e0f" 832checksum = "852e0dedfd52cc32325598b2631e0eba31b7b708959676a9f837042f276b09a2"
827dependencies = [ 833dependencies = [
828 "bitflags", 834 "bitflags",
829 "serde", 835 "serde",
@@ -889,9 +895,9 @@ dependencies = [
889 895
890[[package]] 896[[package]]
891name = "mimalloc" 897name = "mimalloc"
892version = "0.1.25" 898version = "0.1.26"
893source = "registry+https://github.com/rust-lang/crates.io-index" 899source = "registry+https://github.com/rust-lang/crates.io-index"
894checksum = "1e7c6b11afd1e5e689ac96b6d18b1fc763398fe3d7eed99e8773426bc2033dfb" 900checksum = "fb74897ce508e6c49156fd1476fc5922cbc6e75183c65e399c765a09122e5130"
895dependencies = [ 901dependencies = [
896 "libmimalloc-sys", 902 "libmimalloc-sys",
897] 903]
@@ -955,25 +961,6 @@ dependencies = [
955] 961]
956 962
957[[package]] 963[[package]]
958name = "num-integer"
959version = "0.1.44"
960source = "registry+https://github.com/rust-lang/crates.io-index"
961checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
962dependencies = [
963 "autocfg",
964 "num-traits",
965]
966
967[[package]]
968name = "num-traits"
969version = "0.2.14"
970source = "registry+https://github.com/rust-lang/crates.io-index"
971checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
972dependencies = [
973 "autocfg",
974]
975
976[[package]]
977name = "num_cpus" 964name = "num_cpus"
978version = "1.13.0" 965version = "1.13.0"
979source = "registry+https://github.com/rust-lang/crates.io-index" 966source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -991,9 +978,9 @@ checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
991 978
992[[package]] 979[[package]]
993name = "once_cell" 980name = "once_cell"
994version = "1.7.2" 981version = "1.8.0"
995source = "registry+https://github.com/rust-lang/crates.io-index" 982source = "registry+https://github.com/rust-lang/crates.io-index"
996checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 983checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
997 984
998[[package]] 985[[package]]
999name = "oorandom" 986name = "oorandom"
@@ -1217,9 +1204,9 @@ dependencies = [
1217 1204
1218[[package]] 1205[[package]]
1219name = "pulldown-cmark-to-cmark" 1206name = "pulldown-cmark-to-cmark"
1220version = "6.0.0" 1207version = "6.0.1"
1221source = "registry+https://github.com/rust-lang/crates.io-index" 1208source = "registry+https://github.com/rust-lang/crates.io-index"
1222checksum = "e8f2b9878102358ec65434fdd1a9a161f8648bb2f531acc9260e4d094c96de23" 1209checksum = "6a95f396125c68d833fc40cca35532c49ab7394382f7b0e46144a4761896ce80"
1223dependencies = [ 1210dependencies = [
1224 "pulldown-cmark", 1211 "pulldown-cmark",
1225] 1212]
@@ -1742,35 +1729,18 @@ dependencies = [
1742] 1729]
1743 1730
1744[[package]] 1731[[package]]
1745name = "tracing-serde"
1746version = "0.1.2"
1747source = "registry+https://github.com/rust-lang/crates.io-index"
1748checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
1749dependencies = [
1750 "serde",
1751 "tracing-core",
1752]
1753
1754[[package]]
1755name = "tracing-subscriber" 1732name = "tracing-subscriber"
1756version = "0.2.18" 1733version = "0.2.18"
1757source = "registry+https://github.com/rust-lang/crates.io-index" 1734source = "registry+https://github.com/rust-lang/crates.io-index"
1758checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5" 1735checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5"
1759dependencies = [ 1736dependencies = [
1760 "ansi_term",
1761 "chrono",
1762 "lazy_static", 1737 "lazy_static",
1763 "matchers", 1738 "matchers",
1764 "regex", 1739 "regex",
1765 "serde",
1766 "serde_json",
1767 "sharded-slab", 1740 "sharded-slab",
1768 "smallvec",
1769 "thread_local", 1741 "thread_local",
1770 "tracing", 1742 "tracing",
1771 "tracing-core", 1743 "tracing-core",
1772 "tracing-log",
1773 "tracing-serde",
1774] 1744]
1775 1745
1776[[package]] 1746[[package]]
@@ -1939,18 +1909,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
1939 1909
1940[[package]] 1910[[package]]
1941name = "xflags" 1911name = "xflags"
1942version = "0.2.1" 1912version = "0.2.2"
1943source = "registry+https://github.com/rust-lang/crates.io-index" 1913source = "registry+https://github.com/rust-lang/crates.io-index"
1944checksum = "59ad6ce6a0b7224130015b4ebac796478ac04e0079f5d222a690efea06a9208a" 1914checksum = "a25b85ca0fcf2d003f2b0cfdce73897c54ec3d793dfe008a64de5040209363c9"
1945dependencies = [ 1915dependencies = [
1946 "xflags-macros", 1916 "xflags-macros",
1947] 1917]
1948 1918
1949[[package]] 1919[[package]]
1950name = "xflags-macros" 1920name = "xflags-macros"
1951version = "0.2.1" 1921version = "0.2.2"
1952source = "registry+https://github.com/rust-lang/crates.io-index" 1922source = "registry+https://github.com/rust-lang/crates.io-index"
1953checksum = "c8037d3ca14996158b03c0fa905d0834906ef0fc7044df72c1f5ff690e5e62c9" 1923checksum = "00055208d8839f11689012fecb42bbc024e25bf3af91b3b9879739d3cda65bf0"
1954dependencies = [ 1924dependencies = [
1955 "proc-macro2", 1925 "proc-macro2",
1956] 1926]
diff --git a/PRIVACY.md b/PRIVACY.md
index 27e39ca60..718fbed12 100644
--- a/PRIVACY.md
+++ b/PRIVACY.md
@@ -1,17 +1 @@
1# Privacy Notes See the [Privacy](https://rust-analyzer.github.io/manual.html#security) section of the user manual.
2
3## LSP server binary
4
5The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies.
6
7## Visual Studio Code extension
8
9The Code extension connects to GitHub to download updated LSP binaries and, if the nightly channel is selected, to perform update checks.
10
11## Other editor plugins
12
13Any other editor plugins that integrate with `rust-analyzer` are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers.
14
15## Others
16
17If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (on by default).
diff --git a/README.md b/README.md
index 5fbc03964..e01542416 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,10 @@ If you want to **use** rust-analyzer's language server with your editor of
27choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. 27choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder.
28It also contains some tips & tricks to help you be more productive when using rust-analyzer. 28It also contains some tips & tricks to help you be more productive when using rust-analyzer.
29 29
30## Security and Privacy
31
32See the corresponding sections of [the manual](https://rust-analyzer.github.io/manual.html#security).
33
30## Communication 34## Communication
31 35
32For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum: 36For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum:
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index da4afb5eb..6ce377710 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -9,8 +9,8 @@ use test_utils::{
9use vfs::{file_set::FileSet, VfsPath}; 9use vfs::{file_set::FileSet, VfsPath};
10 10
11use crate::{ 11use crate::{
12 input::CrateName, Change, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, FileRange, 12 input::CrateName, Change, CrateDisplayName, CrateGraph, CrateId, Edition, Env, FileId,
13 SourceDatabaseExt, SourceRoot, SourceRootId, 13 FilePosition, FileRange, SourceDatabaseExt, SourceRoot, SourceRootId,
14}; 14};
15 15
16pub const WORKSPACE: SourceRootId = SourceRootId(0); 16pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -24,6 +24,14 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
24 (db, fixture.files[0]) 24 (db, fixture.files[0])
25 } 25 }
26 26
27 fn with_many_files(ra_fixture: &str) -> (Self, Vec<FileId>) {
28 let fixture = ChangeFixture::parse(ra_fixture);
29 let mut db = Self::default();
30 fixture.change.apply(&mut db);
31 assert!(fixture.file_position.is_none());
32 (db, fixture.files)
33 }
34
27 fn with_files(ra_fixture: &str) -> Self { 35 fn with_files(ra_fixture: &str) -> Self {
28 let fixture = ChangeFixture::parse(ra_fixture); 36 let fixture = ChangeFixture::parse(ra_fixture);
29 let mut db = Self::default(); 37 let mut db = Self::default();
@@ -73,7 +81,7 @@ pub struct ChangeFixture {
73 81
74impl ChangeFixture { 82impl ChangeFixture {
75 pub fn parse(ra_fixture: &str) -> ChangeFixture { 83 pub fn parse(ra_fixture: &str) -> ChangeFixture {
76 let fixture = Fixture::parse(ra_fixture); 84 let (mini_core, fixture) = Fixture::parse(ra_fixture);
77 let mut change = Change::new(); 85 let mut change = Change::new();
78 86
79 let mut files = Vec::new(); 87 let mut files = Vec::new();
@@ -98,7 +106,7 @@ impl ChangeFixture {
98 let (range_or_offset, text) = extract_range_or_offset(&entry.text); 106 let (range_or_offset, text) = extract_range_or_offset(&entry.text);
99 assert!(file_position.is_none()); 107 assert!(file_position.is_none());
100 file_position = Some((file_id, range_or_offset)); 108 file_position = Some((file_id, range_or_offset));
101 text.to_string() 109 text
102 } 110 }
103 } else { 111 } else {
104 entry.text.clone() 112 entry.text.clone()
@@ -106,6 +114,9 @@ impl ChangeFixture {
106 114
107 let meta = FileMeta::from(entry); 115 let meta = FileMeta::from(entry);
108 assert!(meta.path.starts_with(&source_root_prefix)); 116 assert!(meta.path.starts_with(&source_root_prefix));
117 if !meta.deps.is_empty() {
118 assert!(meta.krate.is_some(), "can't specify deps without naming the crate")
119 }
109 120
110 if meta.introduce_new_source_root { 121 if meta.introduce_new_source_root {
111 roots.push(SourceRoot::new_local(mem::take(&mut file_set))); 122 roots.push(SourceRoot::new_local(mem::take(&mut file_set)));
@@ -158,6 +169,31 @@ impl ChangeFixture {
158 } 169 }
159 } 170 }
160 171
172 if let Some(mini_core) = mini_core {
173 let core_file = file_id;
174 file_id.0 += 1;
175
176 let mut fs = FileSet::default();
177 fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string()));
178 roots.push(SourceRoot::new_library(fs));
179
180 change.change_file(core_file, Some(Arc::new(mini_core.source_code())));
181
182 let all_crates = crate_graph.crates_in_topological_order();
183
184 let core_crate = crate_graph.add_crate_root(
185 core_file,
186 Edition::Edition2021,
187 Some(CrateDisplayName::from_canonical_name("core".to_string())),
188 CfgOptions::default(),
189 Env::default(),
190 Vec::new(),
191 );
192
193 for krate in all_crates {
194 crate_graph.add_dep(krate, CrateName::new("core").unwrap(), core_crate).unwrap();
195 }
196 }
161 roots.push(SourceRoot::new_local(mem::take(&mut file_set))); 197 roots.push(SourceRoot::new_local(mem::take(&mut file_set)));
162 change.set_roots(roots); 198 change.set_roots(roots);
163 change.set_crate_graph(crate_graph); 199 change.set_crate_graph(crate_graph);
@@ -166,6 +202,7 @@ impl ChangeFixture {
166 } 202 }
167} 203}
168 204
205#[derive(Debug)]
169struct FileMeta { 206struct FileMeta {
170 path: String, 207 path: String,
171 krate: Option<String>, 208 krate: Option<String>,
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 03b8dd767..916d39a0b 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -1,4 +1,4 @@
1//! cfg defines conditional compiling options, `cfg` attibute parser and evaluator 1//! cfg defines conditional compiling options, `cfg` attribute parser and evaluator
2 2
3mod cfg_expr; 3mod cfg_expr;
4mod dnf; 4mod dnf;
@@ -52,6 +52,7 @@ impl CfgOptions {
52 } 52 }
53} 53}
54 54
55#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct CfgDiff { 56pub struct CfgDiff {
56 // Invariants: No duplicates, no atom that's both in `enable` and `disable`. 57 // Invariants: No duplicates, no atom that's both in `enable` and `disable`.
57 enable: Vec<CfgAtom>, 58 enable: Vec<CfgAtom>,
@@ -59,6 +60,20 @@ pub struct CfgDiff {
59} 60}
60 61
61impl CfgDiff { 62impl CfgDiff {
63 /// Create a new CfgDiff. Will return None if the same item appears more than once in the set
64 /// of both.
65 pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> {
66 let mut occupied = FxHashSet::default();
67 for item in enable.iter().chain(disable.iter()) {
68 if !occupied.insert(item) {
69 // was present
70 return None;
71 }
72 }
73
74 Some(CfgDiff { enable, disable })
75 }
76
62 /// Returns the total number of atoms changed by this diff. 77 /// Returns the total number of atoms changed by this diff.
63 pub fn len(&self) -> usize { 78 pub fn len(&self) -> usize {
64 self.enable.len() + self.disable.len() 79 self.enable.len() + self.disable.len()
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index dc10a4d0f..197149c5e 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -127,7 +127,7 @@ impl HasSource for Impl {
127} 127}
128 128
129impl HasSource for TypeParam { 129impl HasSource for TypeParam {
130 type Ast = Either<ast::Trait, ast::TypeParam>; 130 type Ast = Either<ast::TypeParam, ast::Trait>;
131 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { 131 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
132 let child_source = self.id.parent.child_source(db.upcast()); 132 let child_source = self.id.parent.child_source(db.upcast());
133 Some(child_source.map(|it| it[self.id.local_id].clone())) 133 Some(child_source.map(|it| it[self.id.local_id].clone()))
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 5bc0b2338..b7eabaabb 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2688,18 +2688,6 @@ impl ScopeDef {
2688 2688
2689 items 2689 items
2690 } 2690 }
2691
2692 pub fn is_value_def(&self) -> bool {
2693 matches!(
2694 self,
2695 ScopeDef::ModuleDef(ModuleDef::Function(_))
2696 | ScopeDef::ModuleDef(ModuleDef::Variant(_))
2697 | ScopeDef::ModuleDef(ModuleDef::Const(_))
2698 | ScopeDef::ModuleDef(ModuleDef::Static(_))
2699 | ScopeDef::GenericParam(GenericParam::ConstParam(_))
2700 | ScopeDef::Local(_)
2701 )
2702 }
2703} 2691}
2704 2692
2705impl From<ItemInNs> for ScopeDef { 2693impl From<ItemInNs> for ScopeDef {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 613266e07..43162797e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -51,12 +51,14 @@ impl PathResolution {
51 PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { 51 PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
52 Some(TypeNs::BuiltinType((*builtin).into())) 52 Some(TypeNs::BuiltinType((*builtin).into()))
53 } 53 }
54 PathResolution::Def(ModuleDef::Const(_)) 54 PathResolution::Def(
55 | PathResolution::Def(ModuleDef::Variant(_)) 55 ModuleDef::Const(_)
56 | PathResolution::Def(ModuleDef::Function(_)) 56 | ModuleDef::Variant(_)
57 | PathResolution::Def(ModuleDef::Module(_)) 57 | ModuleDef::Function(_)
58 | PathResolution::Def(ModuleDef::Static(_)) 58 | ModuleDef::Module(_)
59 | PathResolution::Def(ModuleDef::Trait(_)) => None, 59 | ModuleDef::Static(_)
60 | ModuleDef::Trait(_),
61 ) => None,
60 PathResolution::Def(ModuleDef::TypeAlias(alias)) => { 62 PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
61 Some(TypeNs::TypeAliasId((*alias).into())) 63 Some(TypeNs::TypeAliasId((*alias).into()))
62 } 64 }
@@ -65,8 +67,7 @@ impl PathResolution {
65 } 67 }
66 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), 68 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
67 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), 69 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
68 PathResolution::AssocItem(AssocItem::Const(_)) 70 PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
69 | PathResolution::AssocItem(AssocItem::Function(_)) => None,
70 PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => { 71 PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
71 Some(TypeNs::TypeAliasId((*alias).into())) 72 Some(TypeNs::TypeAliasId((*alias).into()))
72 } 73 }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 6933f6e3c..0f04b2bae 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -92,7 +92,7 @@ pub enum WherePredicateTypeTarget {
92 92
93#[derive(Default)] 93#[derive(Default)]
94pub(crate) struct SourceMap { 94pub(crate) struct SourceMap {
95 pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, 95 pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::TypeParam, ast::Trait>>,
96 lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, 96 lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
97 const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, 97 const_params: ArenaMap<LocalConstParamId, ast::ConstParam>,
98} 98}
@@ -199,7 +199,7 @@ impl GenericParams {
199 default: None, 199 default: None,
200 provenance: TypeParamProvenance::TraitSelf, 200 provenance: TypeParamProvenance::TraitSelf,
201 }); 201 });
202 sm.type_params.insert(self_param_id, Either::Left(src.value.clone())); 202 sm.type_params.insert(self_param_id, Either::Right(src.value.clone()));
203 // add super traits as bounds on Self 203 // add super traits as bounds on Self
204 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 204 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
205 let self_param = TypeRef::Path(name![Self].into()); 205 let self_param = TypeRef::Path(name![Self].into());
@@ -277,7 +277,7 @@ impl GenericParams {
277 provenance: TypeParamProvenance::TypeParamList, 277 provenance: TypeParamProvenance::TypeParamList,
278 }; 278 };
279 let param_id = self.types.alloc(param); 279 let param_id = self.types.alloc(param);
280 sm.type_params.insert(param_id, Either::Right(type_param.clone())); 280 sm.type_params.insert(param_id, Either::Left(type_param.clone()));
281 281
282 let type_ref = TypeRef::Path(name.into()); 282 let type_ref = TypeRef::Path(name.into());
283 self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); 283 self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
@@ -413,7 +413,7 @@ impl GenericParams {
413} 413}
414 414
415impl HasChildSource<LocalTypeParamId> for GenericDefId { 415impl HasChildSource<LocalTypeParamId> for GenericDefId {
416 type Value = Either<ast::Trait, ast::TypeParam>; 416 type Value = Either<ast::TypeParam, ast::Trait>;
417 fn child_source( 417 fn child_source(
418 &self, 418 &self,
419 db: &dyn DefDatabase, 419 db: &dyn DefDatabase,
@@ -449,7 +449,7 @@ impl ChildBySource for GenericDefId {
449 let sm = sm.as_ref(); 449 let sm = sm.as_ref();
450 for (local_id, src) in sm.value.type_params.iter() { 450 for (local_id, src) in sm.value.type_params.iter() {
451 let id = TypeParamId { parent: *self, local_id }; 451 let id = TypeParamId { parent: *self, local_id };
452 if let Either::Right(type_param) = src { 452 if let Either::Left(type_param) = src {
453 res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) 453 res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id)
454 } 454 }
455 } 455 }
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 3f90bda74..5b1386406 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -674,7 +674,7 @@ impl<'a> Ctx<'a> {
674 default: None, 674 default: None,
675 provenance: TypeParamProvenance::TraitSelf, 675 provenance: TypeParamProvenance::TraitSelf,
676 }); 676 });
677 sm.type_params.insert(self_param_id, Either::Left(trait_def.clone())); 677 sm.type_params.insert(self_param_id, Either::Right(trait_def.clone()));
678 // add super traits as bounds on Self 678 // add super traits as bounds on Self
679 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 679 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
680 let self_param = TypeRef::Path(name![Self].into()); 680 let self_param = TypeRef::Path(name![Self].into());
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index b1e1b70d0..e63bc8232 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -63,7 +63,7 @@ impl<'a> Printer<'a> {
63 fn blank(&mut self) { 63 fn blank(&mut self) {
64 let mut iter = self.buf.chars().rev().fuse(); 64 let mut iter = self.buf.chars().rev().fuse();
65 match (iter.next(), iter.next()) { 65 match (iter.next(), iter.next()) {
66 (Some('\n'), Some('\n')) | (Some('\n'), None) | (None, None) => {} 66 (Some('\n'), Some('\n') | None) | (None, None) => {}
67 (Some('\n'), Some(_)) => { 67 (Some('\n'), Some(_)) => {
68 self.buf.push('\n'); 68 self.buf.push('\n');
69 } 69 }
@@ -77,7 +77,7 @@ impl<'a> Printer<'a> {
77 77
78 fn whitespace(&mut self) { 78 fn whitespace(&mut self) {
79 match self.buf.chars().next_back() { 79 match self.buf.chars().next_back() {
80 None | Some('\n') | Some(' ') => {} 80 None | Some('\n' | ' ') => {}
81 _ => self.buf.push(' '), 81 _ => self.buf.push(' '),
82 } 82 }
83 } 83 }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 6fab58f15..927a7b6e8 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1260,7 +1260,7 @@ impl DefCollector<'_> {
1260 for directive in &self.unresolved_imports { 1260 for directive in &self.unresolved_imports {
1261 if let ImportSource::Import { id: import, use_tree } = &directive.import.source { 1261 if let ImportSource::Import { id: import, use_tree } = &directive.import.source {
1262 match (directive.import.path.segments().first(), &directive.import.path.kind) { 1262 match (directive.import.path.segments().first(), &directive.import.path.kind) {
1263 (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { 1263 (Some(krate), PathKind::Plain | PathKind::Abs) => {
1264 if diagnosed_extern_crates.contains(krate) { 1264 if diagnosed_extern_crates.contains(krate) {
1265 continue; 1265 continue;
1266 } 1266 }
@@ -1992,8 +1992,8 @@ mod tests {
1992 collector.def_map 1992 collector.def_map
1993 } 1993 }
1994 1994
1995 fn do_resolve(code: &str) -> DefMap { 1995 fn do_resolve(not_ra_fixture: &str) -> DefMap {
1996 let (db, _file_id) = TestDB::with_single_file(code); 1996 let (db, _file_id) = TestDB::with_single_file(not_ra_fixture);
1997 let krate = db.test_crate(); 1997 let krate = db.test_crate();
1998 1998
1999 let edition = db.crate_graph()[krate].edition; 1999 let edition = db.crate_graph()[krate].edition;
@@ -2005,24 +2005,37 @@ mod tests {
2005 fn test_macro_expand_will_stop_1() { 2005 fn test_macro_expand_will_stop_1() {
2006 do_resolve( 2006 do_resolve(
2007 r#" 2007 r#"
2008 macro_rules! foo { 2008macro_rules! foo {
2009 ($($ty:ty)*) => { foo!($($ty)*); } 2009 ($($ty:ty)*) => { foo!($($ty)*); }
2010 } 2010}
2011 foo!(KABOOM); 2011foo!(KABOOM);
2012 "#, 2012"#,
2013 );
2014 do_resolve(
2015 r#"
2016macro_rules! foo {
2017 ($($ty:ty)*) => { foo!(() $($ty)*); }
2018}
2019foo!(KABOOM);
2020"#,
2013 ); 2021 );
2014 } 2022 }
2015 2023
2016 #[ignore] // this test does succeed, but takes quite a while :/ 2024 #[ignore]
2017 #[test] 2025 #[test]
2018 fn test_macro_expand_will_stop_2() { 2026 fn test_macro_expand_will_stop_2() {
2027 // FIXME: this test does succeed, but takes quite a while: 90 seconds in
2028 // the release mode. That's why the argument is not an ra_fixture --
2029 // otherwise injection highlighting gets stuck.
2030 //
2031 // We need to find a way to fail this faster.
2019 do_resolve( 2032 do_resolve(
2020 r#" 2033 r#"
2021 macro_rules! foo { 2034macro_rules! foo {
2022 ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } 2035 ($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
2023 } 2036}
2024 foo!(KABOOM); 2037foo!(KABOOM);
2025 "#, 2038"#,
2026 ); 2039 );
2027 } 2040 }
2028} 2041}
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index d4681fa3e..49c573087 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -605,8 +605,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
605 ModuleDefId::ConstId(it) => ValueNs::ConstId(it), 605 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
606 ModuleDefId::StaticId(it) => ValueNs::StaticId(it), 606 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
607 607
608 ModuleDefId::AdtId(AdtId::EnumId(_)) 608 ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_))
609 | ModuleDefId::AdtId(AdtId::UnionId(_))
610 | ModuleDefId::TraitId(_) 609 | ModuleDefId::TraitId(_)
611 | ModuleDefId::TypeAliasId(_) 610 | ModuleDefId::TypeAliasId(_)
612 | ModuleDefId::BuiltinType(_) 611 | ModuleDefId::BuiltinType(_)
@@ -641,8 +640,7 @@ pub trait HasResolver: Copy {
641impl HasResolver for ModuleId { 640impl HasResolver for ModuleId {
642 fn resolver(self, db: &dyn DefDatabase) -> Resolver { 641 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
643 let mut def_map = self.def_map(db); 642 let mut def_map = self.def_map(db);
644 let mut modules = Vec::new(); 643 let mut modules = vec![(def_map.clone(), self.local_id)];
645 modules.push((def_map.clone(), self.local_id));
646 while let Some(parent) = def_map.parent() { 644 while let Some(parent) = def_map.parent() {
647 def_map = parent.def_map(db); 645 def_map = parent.def_map(db);
648 modules.push((def_map.clone(), parent.local_id)); 646 modules.push((def_map.clone(), parent.local_id));
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 83500f54e..aeb1e7726 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -172,9 +172,8 @@ impl Visibility {
172 /// visible in unrelated modules). 172 /// visible in unrelated modules).
173 pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { 173 pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
174 match (self, other) { 174 match (self, other) {
175 (Visibility::Module(_), Visibility::Public) 175 (Visibility::Module(_) | Visibility::Public, Visibility::Public)
176 | (Visibility::Public, Visibility::Module(_)) 176 | (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public),
177 | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
178 (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { 177 (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
179 if mod_a.krate != mod_b.krate { 178 if mod_a.krate != mod_b.krate {
180 return None; 179 return None;
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index f24d1d919..4c83a2efe 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -202,7 +202,7 @@ fn assert_expand(
202 202
203 let arg_tts = args.into_iter().flat_map(|arg| { 203 let arg_tts = args.into_iter().flat_map(|arg| {
204 quote! { &(#arg), } 204 quote! { &(#arg), }
205 }.token_trees).collect::<Vec<_>>(); 205 }.token_trees);
206 206
207 let expanded = quote! { 207 let expanded = quote! {
208 { { (##arg_tts); } } 208 { { (##arg_tts); } }
@@ -254,7 +254,7 @@ fn format_args_expand(
254 let _format_string = args.remove(0); 254 let _format_string = args.remove(0);
255 let arg_tts = args.into_iter().flat_map(|arg| { 255 let arg_tts = args.into_iter().flat_map(|arg| {
256 quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), } 256 quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
257 }.token_trees).collect::<Vec<_>>(); 257 }.token_trees);
258 let expanded = quote! { 258 let expanded = quote! {
259 std::fmt::Arguments::new_v1(&[], &[##arg_tts]) 259 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
260 }; 260 };
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 05c6c3fb1..848522411 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -146,10 +146,11 @@ impl HygieneInfo {
146 (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) 146 (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start))
147 } 147 }
148 mbe::Origin::Def => match (&*self.macro_def, self.def_start) { 148 mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
149 (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) 149 (
150 | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { 150 TokenExpander::MacroDef { def_site_token_map, .. }
151 (def_site_token_map, tt) 151 | TokenExpander::MacroRules { def_site_token_map, .. },
152 } 152 Some(tt),
153 ) => (def_site_token_map, tt),
153 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), 154 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
154 }, 155 },
155 }; 156 };
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 33107aa24..c31426d7c 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -368,10 +368,11 @@ impl ExpansionInfo {
368 let (token_map, tt) = match origin { 368 let (token_map, tt) = match origin {
369 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), 369 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
370 mbe::Origin::Def => match (&*self.macro_def, self.def.as_ref()) { 370 mbe::Origin::Def => match (&*self.macro_def, self.def.as_ref()) {
371 (db::TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) 371 (
372 | (db::TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) => { 372 db::TokenExpander::MacroRules { def_site_token_map, .. }
373 (def_site_token_map, tt.as_ref().map(|tt| tt.syntax().clone())) 373 | db::TokenExpander::MacroDef { def_site_token_map, .. },
374 } 374 Some(tt),
375 ) => (def_site_token_map, tt.as_ref().map(|tt| tt.syntax().clone())),
375 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), 376 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
376 }, 377 },
377 }; 378 };
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index a1894e8d8..74129eb21 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -20,7 +20,7 @@ rustc-hash = "1.1.0"
20scoped-tls = "1" 20scoped-tls = "1"
21chalk-solve = { version = "0.68", default-features = false } 21chalk-solve = { version = "0.68", default-features = false }
22chalk-ir = "0.68" 22chalk-ir = "0.68"
23chalk-recursive = "0.68" 23chalk-recursive = { version = "0.68", default-features = false }
24la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
25once_cell = { version = "1.5.0" } 25once_cell = { version = "1.5.0" }
26 26
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index a4c09c742..a55b99de0 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -2,6 +2,7 @@
2//! about the code that Chalk needs. 2//! about the code that Chalk needs.
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use cov_mark::hit;
5use log::debug; 6use log::debug;
6 7
7use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; 8use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -106,7 +107,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
106 }; 107 };
107 108
108 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> { 109 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
109 db.trait_impls_in_block(module.containing_block()?) 110 let block = module.containing_block()?;
111 hit!(block_local_impls);
112 db.trait_impls_in_block(block)
110 } 113 }
111 114
112 // Note: Since we're using impls_for_trait, only impls where the trait 115 // Note: Since we're using impls_for_trait, only impls where the trait
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs
index 6f0bf8f8c..ab1afce08 100644
--- a/crates/hir_ty/src/consteval.rs
+++ b/crates/hir_ty/src/consteval.rs
@@ -38,8 +38,7 @@ impl ConstExt for Const {
38// FIXME: support more than just evaluating literals 38// FIXME: support more than just evaluating literals
39pub fn eval_usize(expr: &Expr) -> Option<u64> { 39pub fn eval_usize(expr: &Expr) -> Option<u64> {
40 match expr { 40 match expr {
41 Expr::Literal(Literal::Uint(v, None)) 41 Expr::Literal(Literal::Uint(v, None | Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
42 | Expr::Literal(Literal::Uint(v, Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
43 _ => None, 42 _ => None,
44 } 43 }
45} 44}
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index b809b96a0..dc8f20138 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -56,7 +56,7 @@ impl BodyValidationDiagnostic {
56 pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> { 56 pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> {
57 let _p = profile::span("BodyValidationDiagnostic::collect"); 57 let _p = profile::span("BodyValidationDiagnostic::collect");
58 let infer = db.infer(owner); 58 let infer = db.infer(owner);
59 let mut validator = ExprValidator::new(owner, infer.clone()); 59 let mut validator = ExprValidator::new(owner, infer);
60 validator.validate_body(db); 60 validator.validate_body(db);
61 validator.diagnostics 61 validator.diagnostics
62 } 62 }
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
index 471cd4921..e3d640a79 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -84,10 +84,7 @@ impl IntRange {
84 #[inline] 84 #[inline]
85 fn is_integral(ty: &Ty) -> bool { 85 fn is_integral(ty: &Ty) -> bool {
86 match ty.kind(&Interner) { 86 match ty.kind(&Interner) {
87 TyKind::Scalar(Scalar::Char) 87 TyKind::Scalar(Scalar::Char | Scalar::Int(_) | Scalar::Uint(_) | Scalar::Bool) => true,
88 | TyKind::Scalar(Scalar::Int(_))
89 | TyKind::Scalar(Scalar::Uint(_))
90 | TyKind::Scalar(Scalar::Bool) => true,
91 _ => false, 88 _ => false,
92 } 89 }
93 } 90 }
@@ -381,7 +378,7 @@ impl Constructor {
381 // Wildcards cover anything 378 // Wildcards cover anything
382 (_, Wildcard) => true, 379 (_, Wildcard) => true,
383 // The missing ctors are not covered by anything in the matrix except wildcards. 380 // The missing ctors are not covered by anything in the matrix except wildcards.
384 (Missing, _) | (Wildcard, _) => false, 381 (Missing | Wildcard, _) => false,
385 382
386 (Single, Single) => true, 383 (Single, Single) => true,
387 (Variant(self_id), Variant(other_id)) => self_id == other_id, 384 (Variant(self_id), Variant(other_id)) => self_id == other_id,
@@ -523,7 +520,7 @@ impl SplitWildcard {
523 } 520 }
524 } 521 }
525 TyKind::Scalar(Scalar::Char) => unhandled(), 522 TyKind::Scalar(Scalar::Char) => unhandled(),
526 TyKind::Scalar(Scalar::Int(..)) | TyKind::Scalar(Scalar::Uint(..)) => unhandled(), 523 TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
527 TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => { 524 TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => {
528 smallvec![NonExhaustive] 525 smallvec![NonExhaustive]
529 } 526 }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 4b7f31521..7be914451 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -47,10 +47,7 @@ impl<'a> InferenceContext<'a> {
47 // pointers to have a chance at getting a match. See 47 // pointers to have a chance at getting a match. See
48 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 48 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
49 let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) { 49 let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) {
50 (TyKind::FnDef(..), TyKind::FnDef(..)) 50 (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
51 | (TyKind::Closure(..), TyKind::FnDef(..))
52 | (TyKind::FnDef(..), TyKind::Closure(..))
53 | (TyKind::Closure(..), TyKind::Closure(..)) => {
54 // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, 51 // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
55 // we should be coercing the closure to a fn pointer of the safety of the FnDef 52 // we should be coercing the closure to a fn pointer of the safety of the FnDef
56 cov_mark::hit!(coerce_fn_reification); 53 cov_mark::hit!(coerce_fn_reification);
@@ -448,8 +445,7 @@ fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer {
448 445
449fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { 446fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> {
450 match (from, to) { 447 match (from, to) {
451 (Mutability::Mut, Mutability::Mut) 448 (Mutability::Mut, Mutability::Mut | Mutability::Not)
452 | (Mutability::Mut, Mutability::Not)
453 | (Mutability::Not, Mutability::Not) => Ok(()), 449 | (Mutability::Not, Mutability::Not) => Ok(()),
454 (Mutability::Not, Mutability::Mut) => Err(TypeError), 450 (Mutability::Not, Mutability::Mut) => Err(TypeError),
455 } 451 }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 5ea2e5934..c3a5b979f 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -367,7 +367,7 @@ impl<'a> InferenceContext<'a> {
367 Expr::Path(p) => { 367 Expr::Path(p) => {
368 // FIXME this could be more efficient... 368 // FIXME this could be more efficient...
369 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); 369 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
370 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(self.err_ty()) 370 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
371 } 371 }
372 Expr::Continue { .. } => TyKind::Never.intern(&Interner), 372 Expr::Continue { .. } => TyKind::Never.intern(&Interner),
373 Expr::Break { expr, label } => { 373 Expr::Break { expr, label } => {
@@ -511,7 +511,7 @@ impl<'a> InferenceContext<'a> {
511 _ => None, 511 _ => None,
512 } 512 }
513 }) 513 })
514 .unwrap_or(self.err_ty()); 514 .unwrap_or_else(|| self.err_ty());
515 let ty = self.insert_type_vars(ty); 515 let ty = self.insert_type_vars(ty);
516 self.normalize_associated_types_in(ty) 516 self.normalize_associated_types_in(ty)
517 } 517 }
@@ -593,11 +593,11 @@ impl<'a> InferenceContext<'a> {
593 UnaryOp::Neg => { 593 UnaryOp::Neg => {
594 match inner_ty.kind(&Interner) { 594 match inner_ty.kind(&Interner) {
595 // Fast path for builtins 595 // Fast path for builtins
596 TyKind::Scalar(Scalar::Int(_)) 596 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
597 | TyKind::Scalar(Scalar::Uint(_)) 597 | TyKind::InferenceVar(
598 | TyKind::Scalar(Scalar::Float(_)) 598 _,
599 | TyKind::InferenceVar(_, TyVariableKind::Integer) 599 TyVariableKind::Integer | TyVariableKind::Float,
600 | TyKind::InferenceVar(_, TyVariableKind::Float) => inner_ty, 600 ) => inner_ty,
601 // Otherwise we resolve via the std::ops::Neg trait 601 // Otherwise we resolve via the std::ops::Neg trait
602 _ => self 602 _ => self
603 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), 603 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
@@ -606,9 +606,7 @@ impl<'a> InferenceContext<'a> {
606 UnaryOp::Not => { 606 UnaryOp::Not => {
607 match inner_ty.kind(&Interner) { 607 match inner_ty.kind(&Interner) {
608 // Fast path for builtins 608 // Fast path for builtins
609 TyKind::Scalar(Scalar::Bool) 609 TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_))
610 | TyKind::Scalar(Scalar::Int(_))
611 | TyKind::Scalar(Scalar::Uint(_))
612 | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty, 610 | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty,
613 // Otherwise we resolve via the std::ops::Not trait 611 // Otherwise we resolve via the std::ops::Not trait
614 _ => self 612 _ => self
@@ -735,7 +733,7 @@ impl<'a> InferenceContext<'a> {
735 Expr::Array(array) => { 733 Expr::Array(array) => {
736 let elem_ty = 734 let elem_ty =
737 match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) { 735 match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
738 Some(TyKind::Array(st, _)) | Some(TyKind::Slice(st)) => st.clone(), 736 Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(),
739 _ => self.table.new_type_var(), 737 _ => self.table.new_type_var(),
740 }; 738 };
741 739
@@ -820,8 +818,10 @@ impl<'a> InferenceContext<'a> {
820 for stmt in statements { 818 for stmt in statements {
821 match stmt { 819 match stmt {
822 Statement::Let { pat, type_ref, initializer } => { 820 Statement::Let { pat, type_ref, initializer } => {
823 let decl_ty = 821 let decl_ty = type_ref
824 type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(self.err_ty()); 822 .as_ref()
823 .map(|tr| self.make_ty(tr))
824 .unwrap_or_else(|| self.err_ty());
825 825
826 // Always use the declared type when specified 826 // Always use the declared type when specified
827 let mut ty = decl_ty.clone(); 827 let mut ty = decl_ty.clone();
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 035f4ded6..c79ed91ea 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -192,7 +192,7 @@ impl<'a> InferenceContext<'a> {
192 Pat::Path(path) => { 192 Pat::Path(path) => {
193 // FIXME use correct resolver for the surrounding expression 193 // FIXME use correct resolver for the surrounding expression
194 let resolver = self.resolver.clone(); 194 let resolver = self.resolver.clone();
195 self.infer_path(&resolver, path, pat.into()).unwrap_or(self.err_ty()) 195 self.infer_path(&resolver, path, pat.into()).unwrap_or_else(|| self.err_ty())
196 } 196 }
197 Pat::Bind { mode, name: _, subpat } => { 197 Pat::Bind { mode, name: _, subpat } => {
198 let mode = if mode == &BindingAnnotation::Unannotated { 198 let mode = if mode == &BindingAnnotation::Unannotated {
@@ -297,10 +297,11 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
297 Expr::Literal(Literal::String(..)) => false, 297 Expr::Literal(Literal::String(..)) => false,
298 _ => true, 298 _ => true,
299 }, 299 },
300 Pat::Bind { mode: BindingAnnotation::Mutable, subpat: Some(subpat), .. } 300 Pat::Bind {
301 | Pat::Bind { mode: BindingAnnotation::Unannotated, subpat: Some(subpat), .. } => { 301 mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated,
302 is_non_ref_pat(body, *subpat) 302 subpat: Some(subpat),
303 } 303 ..
304 } => is_non_ref_pat(body, *subpat),
304 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, 305 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
305 } 306 }
306} 307}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 817a65c20..ea03b6a6c 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -562,7 +562,7 @@ impl<'a> TyLoweringContext<'a> {
562 }, 562 },
563 ); 563 );
564 564
565 ty.unwrap_or(TyKind::Error.intern(&Interner)) 565 ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
566 } else { 566 } else {
567 TyKind::Error.intern(&Interner) 567 TyKind::Error.intern(&Interner)
568 } 568 }
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs
index 0222de2bc..5ef6342d5 100644
--- a/crates/hir_ty/src/op.rs
+++ b/crates/hir_ty/src/op.rs
@@ -8,17 +8,15 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
8 match op { 8 match op {
9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
10 BinaryOp::Assignment { .. } => TyBuilder::unit(), 10 BinaryOp::Assignment { .. } => TyBuilder::unit(),
11 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { 11 BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => {
12 // all integer combinations are valid here 12 // all integer combinations are valid here
13 if matches!( 13 if matches!(
14 lhs_ty.kind(&Interner), 14 lhs_ty.kind(&Interner),
15 TyKind::Scalar(Scalar::Int(_)) 15 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
16 | TyKind::Scalar(Scalar::Uint(_))
17 | TyKind::InferenceVar(_, TyVariableKind::Integer) 16 | TyKind::InferenceVar(_, TyVariableKind::Integer)
18 ) && matches!( 17 ) && matches!(
19 rhs_ty.kind(&Interner), 18 rhs_ty.kind(&Interner),
20 TyKind::Scalar(Scalar::Int(_)) 19 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
21 | TyKind::Scalar(Scalar::Uint(_))
22 | TyKind::InferenceVar(_, TyVariableKind::Integer) 20 | TyKind::InferenceVar(_, TyVariableKind::Integer)
23 ) { 21 ) {
24 lhs_ty 22 lhs_ty
@@ -32,15 +30,15 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
32 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_))) 30 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
33 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty, 31 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty,
34 // ({int}, int) | ({int}, uint) 32 // ({int}, int) | ({int}, uint)
35 (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Int(_))) 33 (
36 | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Uint(_))) => { 34 TyKind::InferenceVar(_, TyVariableKind::Integer),
37 rhs_ty 35 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
38 } 36 ) => rhs_ty,
39 // (int, {int}) | (uint, {int}) 37 // (int, {int}) | (uint, {int})
40 (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) 38 (
41 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => { 39 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)),
42 lhs_ty 40 TyKind::InferenceVar(_, TyVariableKind::Integer),
43 } 41 ) => lhs_ty,
44 // ({float} | float) 42 // ({float} | float)
45 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => { 43 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
46 rhs_ty 44 rhs_ty
@@ -69,21 +67,15 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
69 BinaryOp::Assignment { op: None } => lhs_ty, 67 BinaryOp::Assignment { op: None } => lhs_ty,
70 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) { 68 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) {
71 TyKind::Scalar(_) | TyKind::Str => lhs_ty, 69 TyKind::Scalar(_) | TyKind::Str => lhs_ty,
72 TyKind::InferenceVar(_, TyVariableKind::Integer) 70 TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
73 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
74 _ => TyKind::Error.intern(&Interner), 71 _ => TyKind::Error.intern(&Interner),
75 }, 72 },
76 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { 73 BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => TyKind::Error.intern(&Interner),
77 TyKind::Error.intern(&Interner)
78 }
79 BinaryOp::CmpOp(CmpOp::Ord { .. }) 74 BinaryOp::CmpOp(CmpOp::Ord { .. })
80 | BinaryOp::Assignment { op: Some(_) } 75 | BinaryOp::Assignment { op: Some(_) }
81 | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) { 76 | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) {
82 TyKind::Scalar(Scalar::Int(_)) 77 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty,
83 | TyKind::Scalar(Scalar::Uint(_)) 78 TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty,
84 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty,
85 TyKind::InferenceVar(_, TyVariableKind::Integer)
86 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
87 _ => TyKind::Error.intern(&Interner), 79 _ => TyKind::Error.intern(&Interner),
88 }, 80 },
89 } 81 }
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs
index 4640ea821..b99a03492 100644
--- a/crates/hir_ty/src/test_db.rs
+++ b/crates/hir_ty/src/test_db.rs
@@ -86,16 +86,20 @@ impl FileLoader for TestDB {
86} 86}
87 87
88impl TestDB { 88impl TestDB {
89 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { 89 pub(crate) fn module_for_file_opt(&self, file_id: FileId) -> Option<ModuleId> {
90 for &krate in self.relevant_crates(file_id).iter() { 90 for &krate in self.relevant_crates(file_id).iter() {
91 let crate_def_map = self.crate_def_map(krate); 91 let crate_def_map = self.crate_def_map(krate);
92 for (local_id, data) in crate_def_map.modules() { 92 for (local_id, data) in crate_def_map.modules() {
93 if data.origin.file_id() == Some(file_id) { 93 if data.origin.file_id() == Some(file_id) {
94 return crate_def_map.module_id(local_id); 94 return Some(crate_def_map.module_id(local_id));
95 } 95 }
96 } 96 }
97 } 97 }
98 panic!("Can't find module for file") 98 None
99 }
100
101 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
102 self.module_for_file_opt(file_id).unwrap()
99 } 103 }
100 104
101 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { 105 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index b873585c4..0651f34ae 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -11,23 +11,21 @@ mod incremental;
11 11
12use std::{collections::HashMap, env, sync::Arc}; 12use std::{collections::HashMap, env, sync::Arc};
13 13
14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 14use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
15use expect_test::Expect; 15use expect_test::Expect;
16use hir_def::{ 16use hir_def::{
17 body::{Body, BodySourceMap, SyntheticSyntax}, 17 body::{Body, BodySourceMap, SyntheticSyntax},
18 child_by_source::ChildBySource,
19 db::DefDatabase, 18 db::DefDatabase,
19 expr::{ExprId, PatId},
20 item_scope::ItemScope, 20 item_scope::ItemScope,
21 keys,
22 nameres::DefMap, 21 nameres::DefMap,
23 src::HasSource, 22 src::HasSource,
24 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 23 AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
25}; 24};
26use hir_expand::{db::AstDatabase, InFile}; 25use hir_expand::{db::AstDatabase, InFile};
27use once_cell::race::OnceBool; 26use once_cell::race::OnceBool;
28use stdx::format_to; 27use stdx::format_to;
29use syntax::{ 28use syntax::{
30 algo,
31 ast::{self, AstNode, NameOwner}, 29 ast::{self, AstNode, NameOwner},
32 SyntaxNode, 30 SyntaxNode,
33}; 31};
@@ -59,51 +57,55 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
59} 57}
60 58
61fn check_types(ra_fixture: &str) { 59fn check_types(ra_fixture: &str) {
62 check_types_impl(ra_fixture, false) 60 check_impl(ra_fixture, false, true, false)
63} 61}
64 62
65fn check_types_source_code(ra_fixture: &str) { 63fn check_types_source_code(ra_fixture: &str) {
66 check_types_impl(ra_fixture, true) 64 check_impl(ra_fixture, false, true, true)
67}
68
69fn check_types_impl(ra_fixture: &str, display_source: bool) {
70 let _tracing = setup_tracing();
71 let db = TestDB::with_files(ra_fixture);
72 let mut checked_one = false;
73 for (file_id, annotations) in db.extract_annotations() {
74 for (range, expected) in annotations {
75 let ty = type_at_range(&db, FileRange { file_id, range });
76 let actual = if display_source {
77 let module = db.module_for_file(file_id);
78 ty.display_source_code(&db, module).unwrap()
79 } else {
80 ty.display_test(&db).to_string()
81 };
82 assert_eq!(expected, actual);
83 checked_one = true;
84 }
85 }
86
87 assert!(checked_one, "no `//^` annotations found");
88} 65}
89 66
90fn check_no_mismatches(ra_fixture: &str) { 67fn check_no_mismatches(ra_fixture: &str) {
91 check_mismatches_impl(ra_fixture, true) 68 check_impl(ra_fixture, true, false, false)
92} 69}
93 70
94#[allow(unused)] 71fn check(ra_fixture: &str) {
95fn check_mismatches(ra_fixture: &str) { 72 check_impl(ra_fixture, false, false, false)
96 check_mismatches_impl(ra_fixture, false)
97} 73}
98 74
99fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { 75fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) {
100 let _tracing = setup_tracing(); 76 let _tracing = setup_tracing();
101 let (db, file_id) = TestDB::with_single_file(ra_fixture); 77 let (db, files) = TestDB::with_many_files(ra_fixture);
102 let module = db.module_for_file(file_id); 78
103 let def_map = module.def_map(&db); 79 let mut had_annotations = false;
80 let mut mismatches = HashMap::new();
81 let mut types = HashMap::new();
82 for (file_id, annotations) in db.extract_annotations() {
83 for (range, expected) in annotations {
84 let file_range = FileRange { file_id, range };
85 if only_types {
86 types.insert(file_range, expected);
87 } else if expected.starts_with("type: ") {
88 types.insert(file_range, expected.trim_start_matches("type: ").to_string());
89 } else if expected.starts_with("expected") {
90 mismatches.insert(file_range, expected);
91 } else {
92 panic!("unexpected annotation: {}", expected);
93 }
94 had_annotations = true;
95 }
96 }
97 assert!(had_annotations || allow_none, "no `//^` annotations found");
104 98
105 let mut defs: Vec<DefWithBodyId> = Vec::new(); 99 let mut defs: Vec<DefWithBodyId> = Vec::new();
106 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); 100 for file_id in files {
101 let module = db.module_for_file_opt(file_id);
102 let module = match module {
103 Some(m) => m,
104 None => continue,
105 };
106 let def_map = module.def_map(&db);
107 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
108 }
107 defs.sort_by_key(|def| match def { 109 defs.sort_by_key(|def| match def {
108 DefWithBodyId::FunctionId(it) => { 110 DefWithBodyId::FunctionId(it) => {
109 let loc = it.lookup(&db); 111 let loc = it.lookup(&db);
@@ -118,37 +120,59 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
118 loc.source(&db).value.syntax().text_range().start() 120 loc.source(&db).value.syntax().text_range().start()
119 } 121 }
120 }); 122 });
121 let mut mismatches = HashMap::new(); 123 let mut unexpected_type_mismatches = String::new();
122 let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| {
123 let range = src_ptr.value.text_range();
124 if src_ptr.file_id.call_node(&db).is_some() {
125 panic!("type mismatch in macro expansion");
126 }
127 let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range };
128 let actual = format!(
129 "expected {}, got {}",
130 mismatch.expected.display_test(&db),
131 mismatch.actual.display_test(&db)
132 );
133 mismatches.insert(file_range, actual);
134 };
135 for def in defs { 124 for def in defs {
136 let (_body, body_source_map) = db.body_with_source_map(def); 125 let (_body, body_source_map) = db.body_with_source_map(def);
137 let inference_result = db.infer(def); 126 let inference_result = db.infer(def);
127
128 for (pat, ty) in inference_result.type_of_pat.iter() {
129 let node = match pat_node(&body_source_map, pat, &db) {
130 Some(value) => value,
131 None => continue,
132 };
133 let range = node.as_ref().original_file_range(&db);
134 if let Some(expected) = types.remove(&range) {
135 let actual = if display_source {
136 ty.display_source_code(&db, def.module(&db)).unwrap()
137 } else {
138 ty.display_test(&db).to_string()
139 };
140 assert_eq!(actual, expected);
141 }
142 }
143
144 for (expr, ty) in inference_result.type_of_expr.iter() {
145 let node = match expr_node(&body_source_map, expr, &db) {
146 Some(value) => value,
147 None => continue,
148 };
149 let range = node.as_ref().original_file_range(&db);
150 if let Some(expected) = types.remove(&range) {
151 let actual = if display_source {
152 ty.display_source_code(&db, def.module(&db)).unwrap()
153 } else {
154 ty.display_test(&db).to_string()
155 };
156 assert_eq!(actual, expected);
157 }
158 }
159
138 for (pat, mismatch) in inference_result.pat_type_mismatches() { 160 for (pat, mismatch) in inference_result.pat_type_mismatches() {
139 let syntax_ptr = match body_source_map.pat_syntax(pat) { 161 let node = match pat_node(&body_source_map, pat, &db) {
140 Ok(sp) => { 162 Some(value) => value,
141 let root = db.parse_or_expand(sp.file_id).unwrap(); 163 None => continue,
142 sp.map(|ptr| {
143 ptr.either(
144 |it| it.to_node(&root).syntax().clone(),
145 |it| it.to_node(&root).syntax().clone(),
146 )
147 })
148 }
149 Err(SyntheticSyntax) => continue,
150 }; 164 };
151 push_mismatch(syntax_ptr, mismatch.clone()); 165 let range = node.as_ref().original_file_range(&db);
166 let actual = format!(
167 "expected {}, got {}",
168 mismatch.expected.display_test(&db),
169 mismatch.actual.display_test(&db)
170 );
171 if let Some(annotation) = mismatches.remove(&range) {
172 assert_eq!(actual, annotation);
173 } else {
174 format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual);
175 }
152 } 176 }
153 for (expr, mismatch) in inference_result.expr_type_mismatches() { 177 for (expr, mismatch) in inference_result.expr_type_mismatches() {
154 let node = match body_source_map.expr_syntax(expr) { 178 let node = match body_source_map.expr_syntax(expr) {
@@ -158,45 +182,70 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
158 } 182 }
159 Err(SyntheticSyntax) => continue, 183 Err(SyntheticSyntax) => continue,
160 }; 184 };
161 push_mismatch(node, mismatch.clone()); 185 let range = node.as_ref().original_file_range(&db);
162 } 186 let actual = format!(
163 } 187 "expected {}, got {}",
164 let mut checked_one = false; 188 mismatch.expected.display_test(&db),
165 for (file_id, annotations) in db.extract_annotations() { 189 mismatch.actual.display_test(&db)
166 for (range, expected) in annotations { 190 );
167 let file_range = FileRange { file_id, range }; 191 if let Some(annotation) = mismatches.remove(&range) {
168 if let Some(mismatch) = mismatches.remove(&file_range) { 192 assert_eq!(actual, annotation);
169 assert_eq!(mismatch, expected);
170 } else { 193 } else {
171 assert!(false, "Expected mismatch not encountered: {}\n", expected); 194 format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual);
172 } 195 }
173 checked_one = true;
174 } 196 }
175 } 197 }
198
176 let mut buf = String::new(); 199 let mut buf = String::new();
177 for (range, mismatch) in mismatches { 200 if !unexpected_type_mismatches.is_empty() {
178 format_to!(buf, "{:?}: {}\n", range.range, mismatch,); 201 format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches);
202 }
203 if !mismatches.is_empty() {
204 format_to!(buf, "Unchecked mismatch annotations:\n");
205 for m in mismatches {
206 format_to!(buf, "{:?}: {}\n", m.0.range, m.1);
207 }
179 } 208 }
180 assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf); 209 if !types.is_empty() {
210 format_to!(buf, "Unchecked type annotations:\n");
211 for t in types {
212 format_to!(buf, "{:?}: type {}\n", t.0.range, t.1);
213 }
214 }
215 assert!(buf.is_empty(), "{}", buf);
216}
181 217
182 assert!(checked_one || allow_none, "no `//^` annotations found"); 218fn expr_node(
219 body_source_map: &BodySourceMap,
220 expr: ExprId,
221 db: &TestDB,
222) -> Option<InFile<SyntaxNode>> {
223 Some(match body_source_map.expr_syntax(expr) {
224 Ok(sp) => {
225 let root = db.parse_or_expand(sp.file_id).unwrap();
226 sp.map(|ptr| ptr.to_node(&root).syntax().clone())
227 }
228 Err(SyntheticSyntax) => return None,
229 })
183} 230}
184 231
185fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 232fn pat_node(
186 let file = db.parse(pos.file_id).ok().unwrap(); 233 body_source_map: &BodySourceMap,
187 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 234 pat: PatId,
188 let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); 235 db: &TestDB,
189 let module = db.module_for_file(pos.file_id); 236) -> Option<InFile<SyntaxNode>> {
190 let func = *module.child_by_source(db)[keys::FUNCTION] 237 Some(match body_source_map.pat_syntax(pat) {
191 .get(&InFile::new(pos.file_id.into(), fn_def)) 238 Ok(sp) => {
192 .unwrap(); 239 let root = db.parse_or_expand(sp.file_id).unwrap();
193 240 sp.map(|ptr| {
194 let (_body, source_map) = db.body_with_source_map(func.into()); 241 ptr.either(
195 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { 242 |it| it.to_node(&root).syntax().clone(),
196 let infer = db.infer(func.into()); 243 |it| it.to_node(&root).syntax().clone(),
197 return infer[expr_id].clone(); 244 )
198 } 245 })
199 panic!("Can't find expression") 246 }
247 Err(SyntheticSyntax) => return None,
248 })
200} 249}
201 250
202fn infer(ra_fixture: &str) -> String { 251fn infer(ra_fixture: &str) -> String {
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 71047703d..87089f09d 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,380 +1,157 @@
1use expect_test::expect; 1use super::{check, check_no_mismatches, check_types};
2
3use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
4 2
5#[test] 3#[test]
6fn infer_block_expr_type_mismatch() { 4fn block_expr_type_mismatch() {
7 check_infer( 5 // FIXME fix double type mismatch
6 check(
8 r" 7 r"
9 fn test() { 8fn test() {
10 let a: i32 = { 1i64 }; 9 let a: i32 = { 1i64 };
11 } 10 // ^^^^^^^^ expected i32, got i64
11 // ^^^^ expected i32, got i64
12}
12 ", 13 ",
13 expect![[r"
14 10..40 '{ ...4 }; }': ()
15 20..21 'a': i32
16 29..37 '{ 1i64 }': i64
17 31..35 '1i64': i64
18 "]],
19 ); 14 );
20} 15}
21 16
22#[test] 17#[test]
23fn coerce_places() { 18fn coerce_places() {
24 check_infer( 19 check_no_mismatches(
25 r#" 20 r#"
26 struct S<T> { a: T } 21//- minicore: coerce_unsized
22struct S<T> { a: T }
27 23
28 fn f<T>(_: &[T]) -> T { loop {} } 24fn f<T>(_: &[T]) -> T { loop {} }
29 fn g<T>(_: S<&[T]>) -> T { loop {} } 25fn g<T>(_: S<&[T]>) -> T { loop {} }
30 26
31 fn gen<T>() -> *mut [T; 2] { loop {} } 27fn gen<T>() -> *mut [T; 2] { loop {} }
32 fn test1<U>() -> *mut [U] { 28fn test1<U>() -> *mut [U] {
33 gen() 29 gen()
34 } 30}
35
36 fn test2() {
37 let arr: &[u8; 1] = &[1];
38
39 let a: &[_] = arr;
40 let b = f(arr);
41 let c: &[_] = { arr };
42 let d = g(S { a: arr });
43 let e: [&[_]; 1] = [arr];
44 let f: [&[_]; 2] = [arr; 2];
45 let g: (&[_], &[_]) = (arr, arr);
46 }
47 31
48 #[lang = "sized"] 32fn test2() {
49 pub trait Sized {} 33 let arr: &[u8; 1] = &[1];
50 #[lang = "unsize"]
51 pub trait Unsize<T: ?Sized> {}
52 #[lang = "coerce_unsized"]
53 pub trait CoerceUnsized<T> {}
54 34
55 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 35 let a: &[_] = arr;
56 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 36 let b = f(arr);
57 "#, 37 let c: &[_] = { arr };
58 expect![[r#" 38 let d = g(S { a: arr });
59 30..31 '_': &[T] 39 let e: [&[_]; 1] = [arr];
60 44..55 '{ loop {} }': T 40 let f: [&[_]; 2] = [arr; 2];
61 46..53 'loop {}': ! 41 let g: (&[_], &[_]) = (arr, arr);
62 51..53 '{}': () 42}
63 64..65 '_': S<&[T]> 43"#,
64 81..92 '{ loop {} }': T
65 83..90 'loop {}': !
66 88..90 '{}': ()
67 121..132 '{ loop {} }': *mut [T; 2]
68 123..130 'loop {}': !
69 128..130 '{}': ()
70 159..172 '{ gen() }': *mut [U]
71 165..168 'gen': fn gen<U>() -> *mut [U; 2]
72 165..170 'gen()': *mut [U; 2]
73 185..419 '{ ...rr); }': ()
74 195..198 'arr': &[u8; 1]
75 211..215 '&[1]': &[u8; 1]
76 212..215 '[1]': [u8; 1]
77 213..214 '1': u8
78 226..227 'a': &[u8]
79 236..239 'arr': &[u8; 1]
80 249..250 'b': u8
81 253..254 'f': fn f<u8>(&[u8]) -> u8
82 253..259 'f(arr)': u8
83 255..258 'arr': &[u8; 1]
84 269..270 'c': &[u8]
85 279..286 '{ arr }': &[u8]
86 281..284 'arr': &[u8; 1]
87 296..297 'd': u8
88 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
89 300..315 'g(S { a: arr })': u8
90 302..314 'S { a: arr }': S<&[u8]>
91 309..312 'arr': &[u8; 1]
92 325..326 'e': [&[u8]; 1]
93 340..345 '[arr]': [&[u8]; 1]
94 341..344 'arr': &[u8; 1]
95 355..356 'f': [&[u8]; 2]
96 370..378 '[arr; 2]': [&[u8]; 2]
97 371..374 'arr': &[u8; 1]
98 376..377 '2': usize
99 388..389 'g': (&[u8], &[u8])
100 406..416 '(arr, arr)': (&[u8], &[u8])
101 407..410 'arr': &[u8; 1]
102 412..415 'arr': &[u8; 1]
103 "#]],
104 ); 44 );
105} 45}
106 46
107#[test] 47#[test]
108fn infer_let_stmt_coerce() { 48fn let_stmt_coerce() {
109 check_infer( 49 check_no_mismatches(
110 r" 50 r"
111 fn test() { 51//- minicore: coerce_unsized
112 let x: &[isize] = &[1]; 52fn test() {
113 let x: *const [isize] = &[1]; 53 let x: &[isize] = &[1];
114 } 54 let x: *const [isize] = &[1];
115 ", 55}
116 expect![[r#" 56",
117 10..75 '{ ...[1]; }': ()
118 20..21 'x': &[isize]
119 34..38 '&[1]': &[isize; 1]
120 35..38 '[1]': [isize; 1]
121 36..37 '1': isize
122 48..49 'x': *const [isize]
123 68..72 '&[1]': &[isize; 1]
124 69..72 '[1]': [isize; 1]
125 70..71 '1': isize
126 "#]],
127 ); 57 );
128} 58}
129 59
130#[test] 60#[test]
131fn infer_custom_coerce_unsized() { 61fn custom_coerce_unsized() {
132 check_infer( 62 check(
133 r#" 63 r#"
134 struct A<T: ?Sized>(*const T); 64//- minicore: coerce_unsized
135 struct B<T: ?Sized>(*const T); 65use core::{marker::Unsize, ops::CoerceUnsized};
136 struct C<T: ?Sized> { inner: *const T }
137 66
138 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} 67struct A<T: ?Sized>(*const T);
139 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} 68struct B<T: ?Sized>(*const T);
69struct C<T: ?Sized> { inner: *const T }
140 70
141 fn foo1<T>(x: A<[T]>) -> A<[T]> { x } 71impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {}
142 fn foo2<T>(x: B<[T]>) -> B<[T]> { x } 72impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {}
143 fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
144 73
145 fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { 74fn foo1<T>(x: A<[T]>) -> A<[T]> { x }
146 let d = foo1(a); 75fn foo2<T>(x: B<[T]>) -> B<[T]> { x }
147 let e = foo2(b); 76fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
148 let f = foo3(c);
149 }
150 77
151 78fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) {
152 #[lang = "sized"] 79 let d = foo1(a);
153 pub trait Sized {} 80 // ^ expected A<[{unknown}]>, got A<[u8; 2]>
154 #[lang = "unsize"] 81 let e = foo2(b);
155 pub trait Unsize<T: ?Sized> {} 82 // ^ type: B<[u8]>
156 #[lang = "coerce_unsized"] 83 let f = foo3(c);
157 pub trait CoerceUnsized<T> {} 84 // ^ type: C<[u8]>
158 85}
159 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 86"#,
160 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
161 "#,
162 expect![[r#"
163 257..258 'x': A<[T]>
164 278..283 '{ x }': A<[T]>
165 280..281 'x': A<[T]>
166 295..296 'x': B<[T]>
167 316..321 '{ x }': B<[T]>
168 318..319 'x': B<[T]>
169 333..334 'x': C<[T]>
170 354..359 '{ x }': C<[T]>
171 356..357 'x': C<[T]>
172 369..370 'a': A<[u8; 2]>
173 384..385 'b': B<[u8; 2]>
174 399..400 'c': C<[u8; 2]>
175 414..480 '{ ...(c); }': ()
176 424..425 'd': A<[{unknown}]>
177 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
178 428..435 'foo1(a)': A<[{unknown}]>
179 433..434 'a': A<[u8; 2]>
180 445..446 'e': B<[u8]>
181 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
182 449..456 'foo2(b)': B<[u8]>
183 454..455 'b': B<[u8; 2]>
184 466..467 'f': C<[u8]>
185 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
186 470..477 'foo3(c)': C<[u8]>
187 475..476 'c': C<[u8; 2]>
188 "#]],
189 ); 87 );
190} 88}
191 89
192#[test] 90#[test]
193fn infer_if_coerce() { 91fn if_coerce() {
194 check_infer( 92 check_no_mismatches(
195 r#" 93 r#"
196 fn foo<T>(x: &[T]) -> &[T] { loop {} } 94//- minicore: coerce_unsized
197 fn test() { 95fn foo<T>(x: &[T]) -> &[T] { x }
198 let x = if true { 96fn test() {
199 foo(&[1]) 97 let x = if true {
200 } else { 98 foo(&[1])
201 &[1] 99 } else {
202 }; 100 &[1]
203 } 101 };
204 102}
205 103"#,
206 #[lang = "sized"]
207 pub trait Sized {}
208 #[lang = "unsize"]
209 pub trait Unsize<T: ?Sized> {}
210 "#,
211 expect![[r#"
212 10..11 'x': &[T]
213 27..38 '{ loop {} }': &[T]
214 29..36 'loop {}': !
215 34..36 '{}': ()
216 49..125 '{ ... }; }': ()
217 59..60 'x': &[i32]
218 63..122 'if tru... }': &[i32]
219 66..70 'true': bool
220 71..96 '{ ... }': &[i32]
221 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
222 81..90 'foo(&[1])': &[i32]
223 85..89 '&[1]': &[i32; 1]
224 86..89 '[1]': [i32; 1]
225 87..88 '1': i32
226 102..122 '{ ... }': &[i32; 1]
227 112..116 '&[1]': &[i32; 1]
228 113..116 '[1]': [i32; 1]
229 114..115 '1': i32
230 "#]],
231 ); 104 );
232} 105}
233 106
234#[test] 107#[test]
235fn infer_if_else_coerce() { 108fn if_else_coerce() {
236 check_infer( 109 check_no_mismatches(
237 r#" 110 r#"
238 fn foo<T>(x: &[T]) -> &[T] { loop {} } 111//- minicore: coerce_unsized
239 fn test() { 112fn foo<T>(x: &[T]) -> &[T] { x }
240 let x = if true { 113fn test() {
241 &[1] 114 let x = if true {
242 } else { 115 &[1]
243 foo(&[1]) 116 } else {
244 }; 117 foo(&[1])
245 } 118 };
246 119}
247 #[lang = "sized"] 120"#,
248 pub trait Sized {}
249 #[lang = "unsize"]
250 pub trait Unsize<T: ?Sized> {}
251 #[lang = "coerce_unsized"]
252 pub trait CoerceUnsized<T> {}
253
254 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
255 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
256 "#,
257 expect![[r#"
258 10..11 'x': &[T]
259 27..38 '{ loop {} }': &[T]
260 29..36 'loop {}': !
261 34..36 '{}': ()
262 49..125 '{ ... }; }': ()
263 59..60 'x': &[i32]
264 63..122 'if tru... }': &[i32]
265 66..70 'true': bool
266 71..91 '{ ... }': &[i32; 1]
267 81..85 '&[1]': &[i32; 1]
268 82..85 '[1]': [i32; 1]
269 83..84 '1': i32
270 97..122 '{ ... }': &[i32]
271 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
272 107..116 'foo(&[1])': &[i32]
273 111..115 '&[1]': &[i32; 1]
274 112..115 '[1]': [i32; 1]
275 113..114 '1': i32
276 "#]],
277 ) 121 )
278} 122}
279 123
280#[test] 124#[test]
281fn infer_match_first_coerce() { 125fn match_first_coerce() {
282 check_infer( 126 check_no_mismatches(
283 r#" 127 r#"
284 fn foo<T>(x: &[T]) -> &[T] { loop {} } 128//- minicore: coerce_unsized
285 fn test(i: i32) { 129fn foo<T>(x: &[T]) -> &[T] { x }
286 let x = match i { 130fn test(i: i32) {
287 2 => foo(&[2]), 131 let x = match i {
288 1 => &[1], 132 2 => foo(&[2]),
289 _ => &[3], 133 1 => &[1],
290 }; 134 _ => &[3],
291 } 135 };
292 136}
293 #[lang = "sized"] 137"#,
294 pub trait Sized {}
295 #[lang = "unsize"]
296 pub trait Unsize<T: ?Sized> {}
297 "#,
298 expect![[r#"
299 10..11 'x': &[T]
300 27..38 '{ loop {} }': &[T]
301 29..36 'loop {}': !
302 34..36 '{}': ()
303 47..48 'i': i32
304 55..149 '{ ... }; }': ()
305 65..66 'x': &[i32]
306 69..146 'match ... }': &[i32]
307 75..76 'i': i32
308 87..88 '2': i32
309 87..88 '2': i32
310 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
311 92..101 'foo(&[2])': &[i32]
312 96..100 '&[2]': &[i32; 1]
313 97..100 '[2]': [i32; 1]
314 98..99 '2': i32
315 111..112 '1': i32
316 111..112 '1': i32
317 116..120 '&[1]': &[i32; 1]
318 117..120 '[1]': [i32; 1]
319 118..119 '1': i32
320 130..131 '_': i32
321 135..139 '&[3]': &[i32; 1]
322 136..139 '[3]': [i32; 1]
323 137..138 '3': i32
324 "#]],
325 ); 138 );
326} 139}
327 140
328#[test] 141#[test]
329fn infer_match_second_coerce() { 142fn match_second_coerce() {
330 check_infer( 143 check_no_mismatches(
331 r#" 144 r#"
332 fn foo<T>(x: &[T]) -> &[T] { loop {} } 145//- minicore: coerce_unsized
333 fn test(i: i32) { 146fn foo<T>(x: &[T]) -> &[T] { loop {} }
334 let x = match i { 147fn test(i: i32) {
335 1 => &[1], 148 let x = match i {
336 2 => foo(&[2]), 149 1 => &[1],
337 _ => &[3], 150 2 => foo(&[2]),
338 }; 151 _ => &[3],
339 } 152 };
340 153}
341 #[lang = "sized"] 154"#,
342 pub trait Sized {}
343 #[lang = "unsize"]
344 pub trait Unsize<T: ?Sized> {}
345 #[lang = "coerce_unsized"]
346 pub trait CoerceUnsized<T> {}
347
348 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
349 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
350 "#,
351 expect![[r#"
352 10..11 'x': &[T]
353 27..38 '{ loop {} }': &[T]
354 29..36 'loop {}': !
355 34..36 '{}': ()
356 47..48 'i': i32
357 55..149 '{ ... }; }': ()
358 65..66 'x': &[i32]
359 69..146 'match ... }': &[i32]
360 75..76 'i': i32
361 87..88 '1': i32
362 87..88 '1': i32
363 92..96 '&[1]': &[i32; 1]
364 93..96 '[1]': [i32; 1]
365 94..95 '1': i32
366 106..107 '2': i32
367 106..107 '2': i32
368 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
369 111..120 'foo(&[2])': &[i32]
370 115..119 '&[2]': &[i32; 1]
371 116..119 '[2]': [i32; 1]
372 117..118 '2': i32
373 130..131 '_': i32
374 135..139 '&[3]': &[i32; 1]
375 136..139 '[3]': [i32; 1]
376 137..138 '3': i32
377 "#]],
378 ); 155 );
379} 156}
380 157
@@ -382,207 +159,103 @@ fn infer_match_second_coerce() {
382fn coerce_merge_one_by_one1() { 159fn coerce_merge_one_by_one1() {
383 cov_mark::check!(coerce_merge_fail_fallback); 160 cov_mark::check!(coerce_merge_fail_fallback);
384 161
385 check_infer( 162 check(
386 r" 163 r"
387 fn test() { 164fn test() {
388 let t = &mut 1; 165 let t = &mut 1;
389 let x = match 1 { 166 let x = match 1 {
390 1 => t as *mut i32, 167 1 => t as *mut i32,
391 2 => t as &i32, 168 2 => t as &i32,
392 _ => t as *const i32, 169 //^^^^^^^^^ expected *mut i32, got &i32
393 }; 170 _ => t as *const i32,
394 } 171 };
172 x;
173 //^ type: *const i32
174}
395 ", 175 ",
396 expect![[r"
397 10..144 '{ ... }; }': ()
398 20..21 't': &mut i32
399 24..30 '&mut 1': &mut i32
400 29..30 '1': i32
401 40..41 'x': *const i32
402 44..141 'match ... }': *const i32
403 50..51 '1': i32
404 62..63 '1': i32
405 62..63 '1': i32
406 67..68 't': &mut i32
407 67..80 't as *mut i32': *mut i32
408 90..91 '2': i32
409 90..91 '2': i32
410 95..96 't': &mut i32
411 95..104 't as &i32': &i32
412 114..115 '_': i32
413 119..120 't': &mut i32
414 119..134 't as *const i32': *const i32
415 "]],
416 ); 176 );
417} 177}
418 178
419#[test] 179#[test]
420fn return_coerce_unknown() { 180fn return_coerce_unknown() {
421 check_infer_with_mismatches( 181 check_types(
422 r" 182 r"
423 fn foo() -> u32 { 183fn foo() -> u32 {
424 return unknown; 184 return unknown;
425 } 185 //^^^^^^^ u32
186}
426 ", 187 ",
427 expect![[r"
428 16..39 '{ ...own; }': u32
429 22..36 'return unknown': !
430 29..36 'unknown': u32
431 "]],
432 ); 188 );
433} 189}
434 190
435#[test] 191#[test]
436fn coerce_autoderef() { 192fn coerce_autoderef() {
437 check_infer_with_mismatches( 193 check_no_mismatches(
438 r" 194 r"
439 struct Foo; 195struct Foo;
440 fn takes_ref_foo(x: &Foo) {} 196fn takes_ref_foo(x: &Foo) {}
441 fn test() { 197fn test() {
442 takes_ref_foo(&Foo); 198 takes_ref_foo(&Foo);
443 takes_ref_foo(&&Foo); 199 takes_ref_foo(&&Foo);
444 takes_ref_foo(&&&Foo); 200 takes_ref_foo(&&&Foo);
445 } 201}",
446 ",
447 expect![[r"
448 29..30 'x': &Foo
449 38..40 '{}': ()
450 51..132 '{ ...oo); }': ()
451 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo)
452 57..76 'takes_...(&Foo)': ()
453 71..75 '&Foo': &Foo
454 72..75 'Foo': Foo
455 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo)
456 82..102 'takes_...&&Foo)': ()
457 96..101 '&&Foo': &&Foo
458 97..101 '&Foo': &Foo
459 98..101 'Foo': Foo
460 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo)
461 108..129 'takes_...&&Foo)': ()
462 122..128 '&&&Foo': &&&Foo
463 123..128 '&&Foo': &&Foo
464 124..128 '&Foo': &Foo
465 125..128 'Foo': Foo
466 "]],
467 ); 202 );
468} 203}
469 204
470#[test] 205#[test]
471fn coerce_autoderef_generic() { 206fn coerce_autoderef_generic() {
472 check_infer_with_mismatches( 207 check_no_mismatches(
473 r" 208 r#"
474 struct Foo; 209struct Foo;
475 fn takes_ref<T>(x: &T) -> T { *x } 210fn takes_ref<T>(x: &T) -> T { *x }
476 fn test() { 211fn test() {
477 takes_ref(&Foo); 212 takes_ref(&Foo);
478 takes_ref(&&Foo); 213 takes_ref(&&Foo);
479 takes_ref(&&&Foo); 214 takes_ref(&&&Foo);
480 } 215}
481 ", 216"#,
482 expect![[r"
483 28..29 'x': &T
484 40..46 '{ *x }': T
485 42..44 '*x': T
486 43..44 'x': &T
487 57..126 '{ ...oo); }': ()
488 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo
489 63..78 'takes_ref(&Foo)': Foo
490 73..77 '&Foo': &Foo
491 74..77 'Foo': Foo
492 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo
493 84..100 'takes_...&&Foo)': &Foo
494 94..99 '&&Foo': &&Foo
495 95..99 '&Foo': &Foo
496 96..99 'Foo': Foo
497 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo
498 106..123 'takes_...&&Foo)': &&Foo
499 116..122 '&&&Foo': &&&Foo
500 117..122 '&&Foo': &&Foo
501 118..122 '&Foo': &Foo
502 119..122 'Foo': Foo
503 "]],
504 ); 217 );
505} 218}
506 219
507#[test] 220#[test]
508fn coerce_autoderef_block() { 221fn coerce_autoderef_block() {
509 check_infer_with_mismatches( 222 check_no_mismatches(
510 r#" 223 r#"
511 struct String {} 224//- minicore: deref
512 #[lang = "deref"] 225struct String {}
513 trait Deref { type Target; } 226impl core::ops::Deref for String { type Target = str; }
514 impl Deref for String { type Target = str; } 227fn takes_ref_str(x: &str) {}
515 fn takes_ref_str(x: &str) {} 228fn returns_string() -> String { loop {} }
516 fn returns_string() -> String { loop {} } 229fn test() {
517 fn test() { 230 takes_ref_str(&{ returns_string() });
518 takes_ref_str(&{ returns_string() }); 231}
519 } 232"#,
520 "#,
521 expect![[r"
522 126..127 'x': &str
523 135..137 '{}': ()
524 168..179 '{ loop {} }': String
525 170..177 'loop {}': !
526 175..177 '{}': ()
527 190..235 '{ ... }); }': ()
528 196..209 'takes_ref_str': fn takes_ref_str(&str)
529 196..232 'takes_...g() })': ()
530 210..231 '&{ ret...ng() }': &String
531 211..231 '{ retu...ng() }': String
532 213..227 'returns_string': fn returns_string() -> String
533 213..229 'return...ring()': String
534 "]],
535 ); 233 );
536} 234}
537 235
538#[test] 236#[test]
539fn closure_return_coerce() { 237fn closure_return_coerce() {
540 check_infer_with_mismatches( 238 check_no_mismatches(
541 r" 239 r"
542 fn foo() { 240fn foo() {
543 let x = || { 241 let x = || {
544 if true { 242 if true {
545 return &1u32; 243 return &1u32;
546 }
547 &&1u32
548 };
549 } 244 }
550 ", 245 &&1u32
551 expect![[r" 246 };
552 9..105 '{ ... }; }': () 247}",
553 19..20 'x': || -> &u32
554 23..102 '|| { ... }': || -> &u32
555 26..102 '{ ... }': &u32
556 36..81 'if tru... }': ()
557 39..43 'true': bool
558 44..81 '{ ... }': ()
559 58..70 'return &1u32': !
560 65..70 '&1u32': &u32
561 66..70 '1u32': u32
562 90..96 '&&1u32': &&u32
563 91..96 '&1u32': &u32
564 92..96 '1u32': u32
565 "]],
566 ); 248 );
567} 249}
568 250
569#[test] 251#[test]
570fn coerce_fn_item_to_fn_ptr() { 252fn coerce_fn_item_to_fn_ptr() {
571 check_infer_with_mismatches( 253 check_no_mismatches(
572 r" 254 r"
573 fn foo(x: u32) -> isize { 1 } 255fn foo(x: u32) -> isize { 1 }
574 fn test() { 256fn test() {
575 let f: fn(u32) -> isize = foo; 257 let f: fn(u32) -> isize = foo;
576 } 258}",
577 ",
578 expect![[r"
579 7..8 'x': u32
580 24..29 '{ 1 }': isize
581 26..27 '1': isize
582 40..78 '{ ...foo; }': ()
583 50..51 'f': fn(u32) -> isize
584 72..75 'foo': fn foo(u32) -> isize
585 "]],
586 ); 259 );
587} 260}
588 261
@@ -590,340 +263,160 @@ fn coerce_fn_item_to_fn_ptr() {
590fn coerce_fn_items_in_match_arms() { 263fn coerce_fn_items_in_match_arms() {
591 cov_mark::check!(coerce_fn_reification); 264 cov_mark::check!(coerce_fn_reification);
592 265
593 check_infer_with_mismatches( 266 check_types(
594 r" 267 r"
595 fn foo1(x: u32) -> isize { 1 } 268fn foo1(x: u32) -> isize { 1 }
596 fn foo2(x: u32) -> isize { 2 } 269fn foo2(x: u32) -> isize { 2 }
597 fn foo3(x: u32) -> isize { 3 } 270fn foo3(x: u32) -> isize { 3 }
598 fn test() { 271fn test() {
599 let x = match 1 { 272 let x = match 1 {
600 1 => foo1, 273 1 => foo1,
601 2 => foo2, 274 2 => foo2,
602 _ => foo3, 275 _ => foo3,
603 }; 276 };
604 } 277 x;
605 ", 278 //^ fn(u32) -> isize
606 expect![[r" 279}",
607 8..9 'x': u32
608 25..30 '{ 1 }': isize
609 27..28 '1': isize
610 39..40 'x': u32
611 56..61 '{ 2 }': isize
612 58..59 '2': isize
613 70..71 'x': u32
614 87..92 '{ 3 }': isize
615 89..90 '3': isize
616 103..192 '{ ... }; }': ()
617 113..114 'x': fn(u32) -> isize
618 117..189 'match ... }': fn(u32) -> isize
619 123..124 '1': i32
620 135..136 '1': i32
621 135..136 '1': i32
622 140..144 'foo1': fn foo1(u32) -> isize
623 154..155 '2': i32
624 154..155 '2': i32
625 159..163 'foo2': fn foo2(u32) -> isize
626 173..174 '_': i32
627 178..182 'foo3': fn foo3(u32) -> isize
628 "]],
629 ); 280 );
630} 281}
631 282
632#[test] 283#[test]
633fn coerce_closure_to_fn_ptr() { 284fn coerce_closure_to_fn_ptr() {
634 check_infer_with_mismatches( 285 check_no_mismatches(
635 r" 286 r"
636 fn test() { 287fn test() {
637 let f: fn(u32) -> isize = |x| { 1 }; 288 let f: fn(u32) -> isize = |x| { 1 };
638 } 289}",
639 ",
640 expect![[r"
641 10..54 '{ ...1 }; }': ()
642 20..21 'f': fn(u32) -> isize
643 42..51 '|x| { 1 }': |u32| -> isize
644 43..44 'x': u32
645 46..51 '{ 1 }': isize
646 48..49 '1': isize
647 "]],
648 ); 290 );
649} 291}
650 292
651#[test] 293#[test]
652fn coerce_placeholder_ref() { 294fn coerce_placeholder_ref() {
653 // placeholders should unify, even behind references 295 // placeholders should unify, even behind references
654 check_infer_with_mismatches( 296 check_no_mismatches(
655 r" 297 r"
656 struct S<T> { t: T } 298struct S<T> { t: T }
657 impl<TT> S<TT> { 299impl<TT> S<TT> {
658 fn get(&self) -> &TT { 300 fn get(&self) -> &TT {
659 &self.t 301 &self.t
660 } 302 }
661 } 303}",
662 ",
663 expect![[r"
664 50..54 'self': &S<TT>
665 63..86 '{ ... }': &TT
666 73..80 '&self.t': &TT
667 74..78 'self': &S<TT>
668 74..80 'self.t': TT
669 "]],
670 ); 304 );
671} 305}
672 306
673#[test] 307#[test]
674fn coerce_unsize_array() { 308fn coerce_unsize_array() {
675 check_infer_with_mismatches( 309 check_types(
676 r#" 310 r#"
677 #[lang = "unsize"] 311//- minicore: coerce_unsized
678 pub trait Unsize<T> {} 312fn test() {
679 #[lang = "coerce_unsized"] 313 let f: &[usize] = &[1, 2, 3];
680 pub trait CoerceUnsized<T> {} 314 //^ usize
681 315}"#,
682 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
683
684 fn test() {
685 let f: &[usize] = &[1, 2, 3];
686 }
687 "#,
688 expect![[r#"
689 161..198 '{ ... 3]; }': ()
690 171..172 'f': &[usize]
691 185..195 '&[1, 2, 3]': &[usize; 3]
692 186..195 '[1, 2, 3]': [usize; 3]
693 187..188 '1': usize
694 190..191 '2': usize
695 193..194 '3': usize
696 "#]],
697 ); 316 );
698} 317}
699 318
700#[test] 319#[test]
701fn coerce_unsize_trait_object_simple() { 320fn coerce_unsize_trait_object_simple() {
702 check_infer_with_mismatches( 321 check_types(
703 r#"
704 #[lang = "sized"]
705 pub trait Sized {}
706 #[lang = "unsize"]
707 pub trait Unsize<T> {}
708 #[lang = "coerce_unsized"]
709 pub trait CoerceUnsized<T> {}
710
711 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
712
713 trait Foo<T, U> {}
714 trait Bar<U, T, X>: Foo<T, U> {}
715 trait Baz<T, X>: Bar<usize, T, X> {}
716
717 struct S<T, X>;
718 impl<T, X> Foo<T, usize> for S<T, X> {}
719 impl<T, X> Bar<usize, T, X> for S<T, X> {}
720 impl<T, X> Baz<T, X> for S<T, X> {}
721
722 fn test() {
723 let obj: &dyn Baz<i8, i16> = &S;
724 let obj: &dyn Bar<_, i8, i16> = &S;
725 let obj: &dyn Foo<i8, _> = &S;
726 }
727 "#,
728 expect![[r"
729 424..539 '{ ... &S; }': ()
730 434..437 'obj': &dyn Baz<i8, i16>
731 459..461 '&S': &S<i8, i16>
732 460..461 'S': S<i8, i16>
733 471..474 'obj': &dyn Bar<usize, i8, i16>
734 499..501 '&S': &S<i8, i16>
735 500..501 'S': S<i8, i16>
736 511..514 'obj': &dyn Foo<i8, usize>
737 534..536 '&S': &S<i8, {unknown}>
738 535..536 'S': S<i8, {unknown}>
739 "]],
740 );
741}
742
743#[test]
744// The rust reference says this should be possible, but rustc doesn't implement
745// it. We used to support it, but Chalk doesn't.
746#[ignore]
747fn coerce_unsize_trait_object_to_trait_object() {
748 check_infer_with_mismatches(
749 r#" 322 r#"
750 #[lang = "sized"] 323//- minicore: coerce_unsized
751 pub trait Sized {} 324trait Foo<T, U> {}
752 #[lang = "unsize"] 325trait Bar<U, T, X>: Foo<T, U> {}
753 pub trait Unsize<T> {} 326trait Baz<T, X>: Bar<usize, T, X> {}
754 #[lang = "coerce_unsized"] 327
755 pub trait CoerceUnsized<T> {} 328struct S<T, X>;
756 329impl<T, X> Foo<T, usize> for S<T, X> {}
757 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 330impl<T, X> Bar<usize, T, X> for S<T, X> {}
758 331impl<T, X> Baz<T, X> for S<T, X> {}
759 trait Foo<T, U> {} 332
760 trait Bar<U, T, X>: Foo<T, U> {} 333fn test() {
761 trait Baz<T, X>: Bar<usize, T, X> {} 334 let obj: &dyn Baz<i8, i16> = &S;
762 335 //^ S<i8, i16>
763 struct S<T, X>; 336 let obj: &dyn Bar<_, i8, i16> = &S;
764 impl<T, X> Foo<T, usize> for S<T, X> {} 337 //^ S<i8, i16>
765 impl<T, X> Bar<usize, T, X> for S<T, X> {} 338 let obj: &dyn Foo<i8, _> = &S;
766 impl<T, X> Baz<T, X> for S<T, X> {} 339 //^ S<i8, {unknown}>
767 340}"#,
768 fn test() {
769 let obj: &dyn Baz<i8, i16> = &S;
770 let obj: &dyn Bar<_, _, _> = obj;
771 let obj: &dyn Foo<_, _> = obj;
772 let obj2: &dyn Baz<i8, i16> = &S;
773 let _: &dyn Foo<_, _> = obj2;
774 }
775 "#,
776 expect![[r"
777 424..609 '{ ...bj2; }': ()
778 434..437 'obj': &dyn Baz<i8, i16>
779 459..461 '&S': &S<i8, i16>
780 460..461 'S': S<i8, i16>
781 471..474 'obj': &dyn Bar<usize, i8, i16>
782 496..499 'obj': &dyn Baz<i8, i16>
783 509..512 'obj': &dyn Foo<i8, usize>
784 531..534 'obj': &dyn Bar<usize, i8, i16>
785 544..548 'obj2': &dyn Baz<i8, i16>
786 570..572 '&S': &S<i8, i16>
787 571..572 'S': S<i8, i16>
788 582..583 '_': &dyn Foo<i8, usize>
789 602..606 'obj2': &dyn Baz<i8, i16>
790 "]],
791 ); 341 );
792} 342}
793 343
794#[test] 344#[test]
795fn coerce_unsize_super_trait_cycle() { 345fn coerce_unsize_super_trait_cycle() {
796 check_infer_with_mismatches( 346 check_no_mismatches(
797 r#" 347 r#"
798 #[lang = "sized"] 348//- minicore: coerce_unsized
799 pub trait Sized {} 349trait A {}
800 #[lang = "unsize"] 350trait B: C + A {}
801 pub trait Unsize<T> {} 351trait C: B {}
802 #[lang = "coerce_unsized"] 352trait D: C
803 pub trait CoerceUnsized<T> {} 353
804 354struct S;
805 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 355impl A for S {}
806 356impl B for S {}
807 trait A {} 357impl C for S {}
808 trait B: C + A {} 358impl D for S {}
809 trait C: B {} 359
810 trait D: C 360fn test() {
811 361 let obj: &dyn D = &S;
812 struct S; 362 let obj: &dyn A = &S;
813 impl A for S {} 363}
814 impl B for S {} 364"#,
815 impl C for S {}
816 impl D for S {}
817
818 fn test() {
819 let obj: &dyn D = &S;
820 let obj: &dyn A = &S;
821 }
822 "#,
823 expect![[r"
824 328..383 '{ ... &S; }': ()
825 338..341 'obj': &dyn D
826 352..354 '&S': &S
827 353..354 'S': S
828 364..367 'obj': &dyn A
829 378..380 '&S': &S
830 379..380 'S': S
831 "]],
832 ); 365 );
833} 366}
834 367
835#[test] 368#[test]
836fn coerce_unsize_generic() { 369fn coerce_unsize_generic() {
837 // FIXME: fix the type mismatches here 370 // FIXME: fix the type mismatches here
838 check_infer_with_mismatches( 371 check(
839 r#" 372 r#"
840 #[lang = "unsize"] 373//- minicore: coerce_unsized
841 pub trait Unsize<T> {} 374struct Foo<T> { t: T };
842 #[lang = "coerce_unsized"] 375struct Bar<T>(Foo<T>);
843 pub trait CoerceUnsized<T> {}
844
845 impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
846
847 struct Foo<T> { t: T };
848 struct Bar<T>(Foo<T>);
849 376
850 fn test() { 377fn test() {
851 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; 378 let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
852 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); 379 //^^^^^^^^^ expected [usize], got [usize; 3]
853 } 380 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
854 "#, 381 //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
855 expect![[r#" 382}
856 209..317 '{ ... }); }': () 383"#,
857 219..220 '_': &Foo<[usize]>
858 238..259 '&Foo {..., 3] }': &Foo<[usize]>
859 239..259 'Foo { ..., 3] }': Foo<[usize]>
860 248..257 '[1, 2, 3]': [usize; 3]
861 249..250 '1': usize
862 252..253 '2': usize
863 255..256 '3': usize
864 269..270 '_': &Bar<[usize]>
865 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]>
866 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]>
867 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]>
868 293..313 'Foo { ..., 3] }': Foo<[i32; 3]>
869 302..311 '[1, 2, 3]': [i32; 3]
870 303..304 '1': i32
871 306..307 '2': i32
872 309..310 '3': i32
873 248..257: expected [usize], got [usize; 3]
874 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]>
875 "#]],
876 ); 384 );
877} 385}
878 386
879#[test] 387#[test]
880fn coerce_unsize_apit() { 388fn coerce_unsize_apit() {
881 // FIXME: #8984 389 // FIXME: #8984
882 check_infer_with_mismatches( 390 check(
883 r#" 391 r#"
884#[lang = "sized"] 392//- minicore: coerce_unsized
885pub trait Sized {}
886#[lang = "unsize"]
887pub trait Unsize<T> {}
888#[lang = "coerce_unsized"]
889pub trait CoerceUnsized<T> {}
890
891impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
892
893trait Foo {} 393trait Foo {}
894 394
895fn test(f: impl Foo) { 395fn test(f: impl Foo) {
896 let _: &dyn Foo = &f; 396 let _: &dyn Foo = &f;
397 //^^ expected &dyn Foo, got &impl Foo
897} 398}
898 "#, 399 "#,
899 expect![[r#"
900 210..211 'f': impl Foo
901 223..252 '{ ... &f; }': ()
902 233..234 '_': &dyn Foo
903 247..249 '&f': &impl Foo
904 248..249 'f': impl Foo
905 247..249: expected &dyn Foo, got &impl Foo
906 "#]],
907 ); 400 );
908} 401}
909 402
910#[test] 403#[test]
911fn infer_two_closures_lub() { 404fn two_closures_lub() {
912 check_types( 405 check_types(
913 r#" 406 r#"
914fn foo(c: i32) { 407fn foo(c: i32) {
915 let add = |a: i32, b: i32| a + b; 408 let add = |a: i32, b: i32| a + b;
916 let sub = |a, b| a - b; 409 let sub = |a, b| a - b;
917 //^ |i32, i32| -> i32 410 //^^^^^^^^^^^^ |i32, i32| -> i32
918 if c > 42 { add } else { sub }; 411 if c > 42 { add } else { sub };
919 //^ fn(i32, i32) -> i32 412 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32
920} 413}
921 "#, 414 "#,
922 ) 415 )
923} 416}
924 417
925#[test] 418#[test]
926fn infer_match_diverging_branch_1() { 419fn match_diverging_branch_1() {
927 check_types( 420 check_types(
928 r#" 421 r#"
929enum Result<T> { Ok(T), Err } 422enum Result<T> { Ok(T), Err }
@@ -942,7 +435,7 @@ fn test() -> i32 {
942} 435}
943 436
944#[test] 437#[test]
945fn infer_match_diverging_branch_2() { 438fn match_diverging_branch_2() {
946 // same as 1 except for order of branches 439 // same as 1 except for order of branches
947 check_types( 440 check_types(
948 r#" 441 r#"
@@ -998,15 +491,7 @@ fn main() {
998fn coerce_unsize_expected_type() { 491fn coerce_unsize_expected_type() {
999 check_no_mismatches( 492 check_no_mismatches(
1000 r#" 493 r#"
1001#[lang = "sized"] 494//- minicore: coerce_unsized
1002pub trait Sized {}
1003#[lang = "unsize"]
1004pub trait Unsize<T> {}
1005#[lang = "coerce_unsized"]
1006pub trait CoerceUnsized<T> {}
1007
1008impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
1009
1010fn main() { 495fn main() {
1011 let foo: &[u32] = &[1, 2]; 496 let foo: &[u32] = &[1, 2];
1012 let foo: &[u32] = match true { 497 let foo: &[u32] = match true {
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs
index 3d29021aa..058cd02d7 100644
--- a/crates/hir_ty/src/tests/display_source_code.rs
+++ b/crates/hir_ty/src/tests/display_source_code.rs
@@ -10,8 +10,8 @@ mod foo {
10 10
11fn bar() { 11fn bar() {
12 let foo: foo::Foo = foo::Foo; 12 let foo: foo::Foo = foo::Foo;
13 foo 13 foo;
14} //^ foo::Foo 14} //^^^ foo::Foo
15 15
16"#, 16"#,
17 ); 17 );
@@ -25,7 +25,7 @@ struct Foo<T = u8> { t: T }
25fn main() { 25fn main() {
26 let foo = Foo { t: 5u8 }; 26 let foo = Foo { t: 5u8 };
27 foo; 27 foo;
28} //^ Foo 28} //^^^ Foo
29"#, 29"#,
30 ); 30 );
31 31
@@ -35,7 +35,7 @@ struct Foo<K, T = u8> { k: K, t: T }
35fn main() { 35fn main() {
36 let foo = Foo { k: 400, t: 5u8 }; 36 let foo = Foo { k: 400, t: 5u8 };
37 foo; 37 foo;
38} //^ Foo<i32> 38} //^^^ Foo<i32>
39"#, 39"#,
40 ); 40 );
41} 41}
@@ -50,7 +50,7 @@ fn foo() -> *const (impl Unpin + Sized) { loop {} }
50fn main() { 50fn main() {
51 let foo = foo(); 51 let foo = foo();
52 foo; 52 foo;
53} //^ *const (impl Unpin + Sized) 53} //^^^ *const (impl Unpin + Sized)
54"#, 54"#,
55 ); 55 );
56} 56}
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index d14103aab..2cf41e49e 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -435,11 +435,11 @@ fn processes_impls_generated_by_macros() {
435macro_rules! m { 435macro_rules! m {
436 ($ident:ident) => (impl Trait for $ident {}) 436 ($ident:ident) => (impl Trait for $ident {})
437} 437}
438trait Trait { fn foo(self) -> u128 {} } 438trait Trait { fn foo(self) -> u128 { 0 } }
439struct S; 439struct S;
440m!(S); 440m!(S);
441fn test() { S.foo(); } 441fn test() { S.foo(); }
442 //^ u128 442 //^^^^^^^ u128
443"#, 443"#,
444 ); 444 );
445} 445}
@@ -457,7 +457,7 @@ impl S {
457} 457}
458 458
459fn test() { S.foo(); } 459fn test() { S.foo(); }
460 //^ u128 460 //^^^^^^^ u128
461"#, 461"#,
462 ); 462 );
463} 463}
@@ -479,7 +479,7 @@ impl S {
479} 479}
480 480
481fn test() { S.foo(); } 481fn test() { S.foo(); }
482 //^ u128 482 //^^^^^^^ u128
483"#, 483"#,
484 ); 484 );
485} 485}
@@ -743,7 +743,7 @@ include!("foo.rs");
743 743
744fn main() { 744fn main() {
745 bar(); 745 bar();
746} //^ u32 746} //^^^^^ u32
747 747
748//- /foo.rs 748//- /foo.rs
749fn bar() -> u32 {0} 749fn bar() -> u32 {0}
@@ -781,7 +781,7 @@ include!("f/foo.rs");
781 781
782fn main() { 782fn main() {
783 bar::bar(); 783 bar::bar();
784} //^ u32 784} //^^^^^^^^^^ u32
785 785
786//- /f/foo.rs 786//- /f/foo.rs
787pub mod bar; 787pub mod bar;
@@ -853,7 +853,7 @@ include!("foo.rs");
853 853
854fn main() { 854fn main() {
855 RegisterBlock { }; 855 RegisterBlock { };
856 //^ RegisterBlock 856 //^^^^^^^^^^^^^^^^^ RegisterBlock
857} 857}
858 "#; 858 "#;
859 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); 859 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data);
@@ -879,7 +879,7 @@ include!(concat!("f", "oo.rs"));
879 879
880fn main() { 880fn main() {
881 bar(); 881 bar();
882} //^ u32 882} //^^^^^ u32
883 883
884//- /foo.rs 884//- /foo.rs
885fn bar() -> u32 {0} 885fn bar() -> u32 {0}
@@ -905,7 +905,7 @@ include!(concat!(env!("OUT_DIR"), "/foo.rs"));
905 905
906fn main() { 906fn main() {
907 bar(); 907 bar();
908} //^ {unknown} 908} //^^^^^ {unknown}
909 909
910//- /foo.rs 910//- /foo.rs
911fn bar() -> u32 {0} 911fn bar() -> u32 {0}
@@ -923,7 +923,7 @@ macro_rules! include {() => {}}
923include!("main.rs"); 923include!("main.rs");
924 924
925fn main() { 925fn main() {
926 0 926 0;
927} //^ i32 927} //^ i32
928"#, 928"#,
929 ); 929 );
@@ -979,7 +979,7 @@ fn infer_derive_clone_simple() {
979struct S; 979struct S;
980fn test() { 980fn test() {
981 S.clone(); 981 S.clone();
982} //^ S 982} //^^^^^^^^^ S
983 983
984//- /lib.rs crate:core 984//- /lib.rs crate:core
985pub mod prelude { 985pub mod prelude {
@@ -1028,7 +1028,7 @@ pub struct S;
1028use core::S; 1028use core::S;
1029fn test() { 1029fn test() {
1030 S.clone(); 1030 S.clone();
1031} //^ S 1031} //^^^^^^^^^ S
1032"#, 1032"#,
1033 ); 1033 );
1034} 1034}
@@ -1044,7 +1044,8 @@ struct S;
1044struct Wrapper<T>(T); 1044struct Wrapper<T>(T);
1045struct NonClone; 1045struct NonClone;
1046fn test() { 1046fn test() {
1047 (Wrapper(S).clone(), Wrapper(NonClone).clone()); 1047 let x = (Wrapper(S).clone(), Wrapper(NonClone).clone());
1048 x;
1048 //^ (Wrapper<S>, {unknown}) 1049 //^ (Wrapper<S>, {unknown})
1049} 1050}
1050 1051
@@ -1079,7 +1080,7 @@ struct S{}
1079 1080
1080fn test() { 1081fn test() {
1081 S{}; 1082 S{};
1082} //^ S 1083} //^^^ S
1083"#, 1084"#,
1084 ); 1085 );
1085} 1086}
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index f26b2c8a7..3f7a37295 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -257,7 +257,7 @@ fn test() {
257mod foo { 257mod foo {
258 struct S; 258 struct S;
259 impl S { 259 impl S {
260 fn thing() -> i128 {} 260 fn thing() -> i128 { 0 }
261 } 261 }
262} 262}
263"#, 263"#,
@@ -267,164 +267,128 @@ mod foo {
267#[test] 267#[test]
268fn infer_trait_method_simple() { 268fn infer_trait_method_simple() {
269 // the trait implementation is intentionally incomplete -- it shouldn't matter 269 // the trait implementation is intentionally incomplete -- it shouldn't matter
270 check_infer( 270 check_types(
271 r#" 271 r#"
272 trait Trait1 { 272trait Trait1 {
273 fn method(&self) -> u32; 273 fn method(&self) -> u32;
274 } 274}
275 struct S1; 275struct S1;
276 impl Trait1 for S1 {} 276impl Trait1 for S1 {}
277 trait Trait2 { 277trait Trait2 {
278 fn method(&self) -> i128; 278 fn method(&self) -> i128;
279 } 279}
280 struct S2; 280struct S2;
281 impl Trait2 for S2 {} 281impl Trait2 for S2 {}
282 fn test() { 282fn test() {
283 S1.method(); // -> u32 283 S1.method();
284 S2.method(); // -> i128 284 //^^^^^^^^^^^ u32
285 } 285 S2.method(); // -> i128
286 //^^^^^^^^^^^ i128
287}
286 "#, 288 "#,
287 expect![[r#"
288 30..34 'self': &Self
289 109..113 'self': &Self
290 169..227 '{ ...i128 }': ()
291 175..177 'S1': S1
292 175..186 'S1.method()': u32
293 202..204 'S2': S2
294 202..213 'S2.method()': i128
295 "#]],
296 ); 289 );
297} 290}
298 291
299#[test] 292#[test]
300fn infer_trait_method_scoped() { 293fn infer_trait_method_scoped() {
301 // the trait implementation is intentionally incomplete -- it shouldn't matter 294 // the trait implementation is intentionally incomplete -- it shouldn't matter
302 check_infer( 295 check_types(
303 r#" 296 r#"
304 struct S; 297struct S;
305 mod foo { 298mod foo {
306 pub trait Trait1 { 299 pub trait Trait1 {
307 fn method(&self) -> u32; 300 fn method(&self) -> u32;
308 } 301 }
309 impl Trait1 for super::S {} 302 impl Trait1 for super::S {}
310 } 303}
311 mod bar { 304mod bar {
312 pub trait Trait2 { 305 pub trait Trait2 {
313 fn method(&self) -> i128; 306 fn method(&self) -> i128;
314 } 307 }
315 impl Trait2 for super::S {} 308 impl Trait2 for super::S {}
316 } 309}
317 310
318 mod foo_test { 311mod foo_test {
319 use super::S; 312 use super::S;
320 use super::foo::Trait1; 313 use super::foo::Trait1;
321 fn test() { 314 fn test() {
322 S.method(); // -> u32 315 S.method();
323 } 316 //^^^^^^^^^^ u32
324 } 317 }
318}
325 319
326 mod bar_test { 320mod bar_test {
327 use super::S; 321 use super::S;
328 use super::bar::Trait2; 322 use super::bar::Trait2;
329 fn test() { 323 fn test() {
330 S.method(); // -> i128 324 S.method();
331 } 325 //^^^^^^^^^^ i128
332 } 326 }
327}
333 "#, 328 "#,
334 expect![[r#"
335 62..66 'self': &Self
336 168..172 'self': &Self
337 299..336 '{ ... }': ()
338 309..310 'S': S
339 309..319 'S.method()': u32
340 415..453 '{ ... }': ()
341 425..426 'S': S
342 425..435 'S.method()': i128
343 "#]],
344 ); 329 );
345} 330}
346 331
347#[test] 332#[test]
348fn infer_trait_method_generic_1() { 333fn infer_trait_method_generic_1() {
349 // the trait implementation is intentionally incomplete -- it shouldn't matter 334 // the trait implementation is intentionally incomplete -- it shouldn't matter
350 check_infer( 335 check_types(
351 r#" 336 r#"
352 trait Trait<T> { 337trait Trait<T> {
353 fn method(&self) -> T; 338 fn method(&self) -> T;
354 } 339}
355 struct S; 340struct S;
356 impl Trait<u32> for S {} 341impl Trait<u32> for S {}
357 fn test() { 342fn test() {
358 S.method(); 343 S.method();
359 } 344 //^^^^^^^^^^ u32
345}
360 "#, 346 "#,
361 expect![[r#"
362 32..36 'self': &Self
363 91..110 '{ ...d(); }': ()
364 97..98 'S': S
365 97..107 'S.method()': u32
366 "#]],
367 ); 347 );
368} 348}
369 349
370#[test] 350#[test]
371fn infer_trait_method_generic_more_params() { 351fn infer_trait_method_generic_more_params() {
372 // the trait implementation is intentionally incomplete -- it shouldn't matter 352 // the trait implementation is intentionally incomplete -- it shouldn't matter
373 check_infer( 353 check_types(
374 r#" 354 r#"
375 trait Trait<T1, T2, T3> { 355trait Trait<T1, T2, T3> {
376 fn method1(&self) -> (T1, T2, T3); 356 fn method1(&self) -> (T1, T2, T3);
377 fn method2(&self) -> (T3, T2, T1); 357 fn method2(&self) -> (T3, T2, T1);
378 } 358}
379 struct S1; 359struct S1;
380 impl Trait<u8, u16, u32> for S1 {} 360impl Trait<u8, u16, u32> for S1 {}
381 struct S2; 361struct S2;
382 impl<T> Trait<i8, i16, T> for S2 {} 362impl<T> Trait<i8, i16, T> for S2 {}
383 fn test() { 363fn test() {
384 S1.method1(); // u8, u16, u32 364 S1.method1();
385 S1.method2(); // u32, u16, u8 365 //^^^^^^^^^^^^ (u8, u16, u32)
386 S2.method1(); // i8, i16, {unknown} 366 S1.method2();
387 S2.method2(); // {unknown}, i16, i8 367 //^^^^^^^^^^^^ (u32, u16, u8)
388 } 368 S2.method1();
369 //^^^^^^^^^^^^ (i8, i16, {unknown})
370 S2.method2();
371 //^^^^^^^^^^^^ ({unknown}, i16, i8)
372}
389 "#, 373 "#,
390 expect![[r#"
391 42..46 'self': &Self
392 81..85 'self': &Self
393 209..360 '{ ..., i8 }': ()
394 215..217 'S1': S1
395 215..227 'S1.method1()': (u8, u16, u32)
396 249..251 'S1': S1
397 249..261 'S1.method2()': (u32, u16, u8)
398 283..285 'S2': S2
399 283..295 'S2.method1()': (i8, i16, {unknown})
400 323..325 'S2': S2
401 323..335 'S2.method2()': ({unknown}, i16, i8)
402 "#]],
403 ); 374 );
404} 375}
405 376
406#[test] 377#[test]
407fn infer_trait_method_generic_2() { 378fn infer_trait_method_generic_2() {
408 // the trait implementation is intentionally incomplete -- it shouldn't matter 379 // the trait implementation is intentionally incomplete -- it shouldn't matter
409 check_infer( 380 check_types(
410 r#" 381 r#"
411 trait Trait<T> { 382trait Trait<T> {
412 fn method(&self) -> T; 383 fn method(&self) -> T;
413 } 384}
414 struct S<T>(T); 385struct S<T>(T);
415 impl<U> Trait<U> for S<U> {} 386impl<U> Trait<U> for S<U> {}
416 fn test() { 387fn test() {
417 S(1u32).method(); 388 S(1u32).method();
418 } 389 //^^^^^^^^^^^^^^^^ u32
390}
419 "#, 391 "#,
420 expect![[r#"
421 32..36 'self': &Self
422 101..126 '{ ...d(); }': ()
423 107..108 'S': S<u32>(u32) -> S<u32>
424 107..114 'S(1u32)': S<u32>
425 107..123 'S(1u32...thod()': u32
426 109..113 '1u32': u32
427 "#]],
428 ); 392 );
429} 393}
430 394
@@ -685,10 +649,10 @@ fn method_resolution_unify_impl_self_type() {
685 check_types( 649 check_types(
686 r#" 650 r#"
687struct S<T>; 651struct S<T>;
688impl S<u32> { fn foo(&self) -> u8 {} } 652impl S<u32> { fn foo(&self) -> u8 { 0 } }
689impl S<i32> { fn foo(&self) -> i8 {} } 653impl S<i32> { fn foo(&self) -> i8 { 0 } }
690fn test() { (S::<u32>.foo(), S::<i32>.foo()); } 654fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
691 //^ (u8, i8) 655 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8)
692"#, 656"#,
693 ); 657 );
694} 658}
@@ -702,7 +666,7 @@ struct S;
702impl S { fn foo(&self) -> i8 { 0 } } 666impl S { fn foo(&self) -> i8 { 0 } }
703impl Trait for S { fn foo(self) -> u128 { 0 } } 667impl Trait for S { fn foo(self) -> u128 { 0 } }
704fn test() { S.foo(); } 668fn test() { S.foo(); }
705 //^ u128 669 //^^^^^^^ u128
706"#, 670"#,
707 ); 671 );
708} 672}
@@ -716,7 +680,7 @@ struct S;
716impl Clone for S {} 680impl Clone for S {}
717impl Clone for &S {} 681impl Clone for &S {}
718fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } 682fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
719 //^ (S, S, &S) 683 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
720"#, 684"#,
721 ); 685 );
722} 686}
@@ -730,7 +694,7 @@ struct S;
730impl S { fn foo(self) -> i8 { 0 } } 694impl S { fn foo(self) -> i8 { 0 } }
731impl Trait for &S { fn foo(self) -> u128 { 0 } } 695impl Trait for &S { fn foo(self) -> u128 { 0 } }
732fn test() { (&S).foo(); } 696fn test() { (&S).foo(); }
733 //^ u128 697 //^^^^^^^^^^ u128
734"#, 698"#,
735 ); 699 );
736} 700}
@@ -744,7 +708,7 @@ struct S;
744impl S { fn foo(self) -> i8 { 0 } } 708impl S { fn foo(self) -> i8 { 0 } }
745impl Trait for S { fn foo(self) -> u128 { 0 } } 709impl Trait for S { fn foo(self) -> u128 { 0 } }
746fn test() { S.foo(); } 710fn test() { S.foo(); }
747 //^ i8 711 //^^^^^^^ i8
748"#, 712"#,
749 ); 713 );
750} 714}
@@ -758,7 +722,7 @@ struct S;
758impl S { fn foo(&self) -> i8 { 0 } } 722impl S { fn foo(&self) -> i8 { 0 } }
759impl Trait for &S { fn foo(self) -> u128 { 0 } } 723impl Trait for &S { fn foo(self) -> u128 { 0 } }
760fn test() { S.foo(); } 724fn test() { S.foo(); }
761 //^ i8 725 //^^^^^^^ i8
762"#, 726"#,
763 ); 727 );
764} 728}
@@ -771,7 +735,7 @@ trait Trait { fn foo(self) -> u128; }
771struct S; 735struct S;
772impl Trait for S { fn foo(self) -> u128 { 0 } } 736impl Trait for S { fn foo(self) -> u128 { 0 } }
773fn test() { (&S).foo(); } 737fn test() { (&S).foo(); }
774 //^ u128 738 //^^^^^^^^^^ u128
775"#, 739"#,
776 ); 740 );
777} 741}
@@ -780,14 +744,11 @@ fn test() { (&S).foo(); }
780fn method_resolution_unsize_array() { 744fn method_resolution_unsize_array() {
781 check_types( 745 check_types(
782 r#" 746 r#"
783#[lang = "slice"] 747//- minicore: slice
784impl<T> [T] {
785 fn len(&self) -> usize { loop {} }
786}
787fn test() { 748fn test() {
788 let a = [1, 2, 3]; 749 let a = [1, 2, 3];
789 a.len(); 750 a.len();
790} //^ usize 751} //^^^^^^^ usize
791"#, 752"#,
792 ); 753 );
793} 754}
@@ -802,7 +763,7 @@ impl Clone for S {}
802 763
803fn test() { 764fn test() {
804 S.clone(); 765 S.clone();
805 //^ S 766 //^^^^^^^^^ S
806} 767}
807 768
808//- /lib.rs crate:core 769//- /lib.rs crate:core
@@ -826,7 +787,7 @@ trait Trait { fn foo(self) -> u128; }
826struct S; 787struct S;
827impl<T> Trait for T where T: UnknownTrait {} 788impl<T> Trait for T where T: UnknownTrait {}
828fn test() { (&S).foo(); } 789fn test() { (&S).foo(); }
829 //^ u128 790 //^^^^^^^^^^ u128
830"#, 791"#,
831 ); 792 );
832} 793}
@@ -844,7 +805,7 @@ trait Trait { fn foo(self) -> u128; }
844struct S; 805struct S;
845impl<T> Trait for T where T: Clone {} 806impl<T> Trait for T where T: Clone {}
846fn test() { (&S).foo(); } 807fn test() { (&S).foo(); }
847 //^ {unknown} 808 //^^^^^^^^^^ {unknown}
848"#, 809"#,
849 ); 810 );
850} 811}
@@ -859,7 +820,7 @@ trait Trait { fn foo(self) -> u128; }
859struct S; 820struct S;
860impl<T: Clone> Trait for T {} 821impl<T: Clone> Trait for T {}
861fn test() { (&S).foo(); } 822fn test() { (&S).foo(); }
862 //^ {unknown} 823 //^^^^^^^^^^ {unknown}
863"#, 824"#,
864 ); 825 );
865} 826}
@@ -874,7 +835,7 @@ struct S;
874impl Clone for S {} 835impl Clone for S {}
875impl<T> Trait for T where T: Clone {} 836impl<T> Trait for T where T: Clone {}
876fn test() { S.foo(); } 837fn test() { S.foo(); }
877 //^ u128 838 //^^^^^^^ u128
878"#, 839"#,
879 ); 840 );
880} 841}
@@ -890,7 +851,7 @@ struct S2;
890impl From<S2> for S1 {} 851impl From<S2> for S1 {}
891impl<T, U> Into<U> for T where U: From<T> {} 852impl<T, U> Into<U> for T where U: From<T> {}
892fn test() { S2.into(); } 853fn test() { S2.into(); }
893 //^ {unknown} 854 //^^^^^^^^^ {unknown}
894"#, 855"#,
895 ); 856 );
896} 857}
@@ -906,7 +867,7 @@ struct S2;
906impl From<S2> for S1 {} 867impl From<S2> for S1 {}
907impl<T, U: From<T>> Into<U> for T {} 868impl<T, U: From<T>> Into<U> for T {}
908fn test() { S2.into(); } 869fn test() { S2.into(); }
909 //^ {unknown} 870 //^^^^^^^^^ {unknown}
910"#, 871"#,
911 ); 872 );
912} 873}
@@ -936,7 +897,7 @@ fn main() {
936 let a = Wrapper::<Foo<f32>>::new(1.0); 897 let a = Wrapper::<Foo<f32>>::new(1.0);
937 let b = Wrapper::<Bar<f32>>::new(1.0); 898 let b = Wrapper::<Bar<f32>>::new(1.0);
938 (a, b); 899 (a, b);
939 //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) 900 //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
940} 901}
941"#, 902"#,
942 ); 903 );
@@ -950,7 +911,7 @@ fn method_resolution_encountering_fn_type() {
950fn foo() {} 911fn foo() {}
951trait FnOnce { fn call(self); } 912trait FnOnce { fn call(self); }
952fn test() { foo.call(); } 913fn test() { foo.call(); }
953 //^ {unknown} 914 //^^^^^^^^^^ {unknown}
954"#, 915"#,
955 ); 916 );
956} 917}
@@ -1016,7 +977,7 @@ where
1016 Wrapper<T>: a::Foo, 977 Wrapper<T>: a::Foo,
1017{ 978{
1018 t.foo(); 979 t.foo();
1019} //^ {unknown} 980} //^^^^^^^ {unknown}
1020"#, 981"#,
1021 ); 982 );
1022} 983}
@@ -1033,7 +994,7 @@ impl A<i32> {
1033 994
1034fn main() { 995fn main() {
1035 A::from(3); 996 A::from(3);
1036} //^ A<i32> 997} //^^^^^^^^^^ A<i32>
1037"#, 998"#,
1038 ); 999 );
1039} 1000}
@@ -1061,7 +1022,7 @@ trait FnX {}
1061impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} 1022impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
1062 1023
1063fn test() { (S {}).method(); } 1024fn test() { (S {}).method(); }
1064 //^ () 1025 //^^^^^^^^^^^^^^^ ()
1065"#, 1026"#,
1066 ); 1027 );
1067} 1028}
@@ -1146,8 +1107,8 @@ impl<T> Slice<T> {
1146 1107
1147fn main() { 1108fn main() {
1148 let foo: Slice<u32>; 1109 let foo: Slice<u32>;
1149 (foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least 1110 foo.into_vec(); // we shouldn't crash on this at least
1150} //^ {unknown} 1111} //^^^^^^^^^^^^^^ {unknown}
1151"#, 1112"#,
1152 ); 1113 );
1153} 1114}
@@ -1168,7 +1129,7 @@ impl dyn Foo + '_ {
1168fn main() { 1129fn main() {
1169 let f = &42u32 as &dyn Foo; 1130 let f = &42u32 as &dyn Foo;
1170 f.dyn_foo(); 1131 f.dyn_foo();
1171 // ^u32 1132 // ^^^^^^^^^^^ u32
1172} 1133}
1173"#, 1134"#,
1174 ); 1135 );
@@ -1178,11 +1139,7 @@ fn main() {
1178fn autoderef_visibility_field() { 1139fn autoderef_visibility_field() {
1179 check_infer( 1140 check_infer(
1180 r#" 1141 r#"
1181#[lang = "deref"] 1142//- minicore: deref
1182pub trait Deref {
1183 type Target;
1184 fn deref(&self) -> &Self::Target;
1185}
1186mod a { 1143mod a {
1187 pub struct Foo(pub char); 1144 pub struct Foo(pub char);
1188 pub struct Bar(i32); 1145 pub struct Bar(i32);
@@ -1191,7 +1148,7 @@ mod a {
1191 Self(0) 1148 Self(0)
1192 } 1149 }
1193 } 1150 }
1194 impl super::Deref for Bar { 1151 impl core::ops::Deref for Bar {
1195 type Target = Foo; 1152 type Target = Foo;
1196 fn deref(&self) -> &Foo { 1153 fn deref(&self) -> &Foo {
1197 &Foo('z') 1154 &Foo('z')
@@ -1205,22 +1162,21 @@ mod b {
1205} 1162}
1206 "#, 1163 "#,
1207 expect![[r#" 1164 expect![[r#"
1208 67..71 'self': &Self 1165 107..138 '{ ... }': Bar
1209 200..231 '{ ... }': Bar 1166 121..125 'Self': Bar(i32) -> Bar
1210 214..218 'Self': Bar(i32) -> Bar 1167 121..128 'Self(0)': Bar
1211 214..221 'Self(0)': Bar 1168 126..127 '0': i32
1212 219..220 '0': i32 1169 226..230 'self': &Bar
1213 315..319 'self': &Bar 1170 240..273 '{ ... }': &Foo
1214 329..362 '{ ... }': &Foo 1171 254..263 '&Foo('z')': &Foo
1215 343..352 '&Foo('z')': &Foo 1172 255..258 'Foo': Foo(char) -> Foo
1216 344..347 'Foo': Foo(char) -> Foo 1173 255..263 'Foo('z')': Foo
1217 344..352 'Foo('z')': Foo 1174 259..262 ''z'': char
1218 348..351 ''z'': char 1175 303..350 '{ ... }': ()
1219 392..439 '{ ... }': () 1176 317..318 'x': char
1220 406..407 'x': char 1177 321..339 'super:...r::new': fn new() -> Bar
1221 410..428 'super:...r::new': fn new() -> Bar 1178 321..341 'super:...:new()': Bar
1222 410..430 'super:...:new()': Bar 1179 321..343 'super:...ew().0': char
1223 410..432 'super:...ew().0': char
1224 "#]], 1180 "#]],
1225 ) 1181 )
1226} 1182}
@@ -1230,11 +1186,7 @@ fn autoderef_visibility_method() {
1230 cov_mark::check!(autoderef_candidate_not_visible); 1186 cov_mark::check!(autoderef_candidate_not_visible);
1231 check_infer( 1187 check_infer(
1232 r#" 1188 r#"
1233#[lang = "deref"] 1189//- minicore: deref
1234pub trait Deref {
1235 type Target;
1236 fn deref(&self) -> &Self::Target;
1237}
1238mod a { 1190mod a {
1239 pub struct Foo(pub char); 1191 pub struct Foo(pub char);
1240 impl Foo { 1192 impl Foo {
@@ -1251,7 +1203,7 @@ mod a {
1251 self.0 1203 self.0
1252 } 1204 }
1253 } 1205 }
1254 impl super::Deref for Bar { 1206 impl core::ops::Deref for Bar {
1255 type Target = Foo; 1207 type Target = Foo;
1256 fn deref(&self) -> &Foo { 1208 fn deref(&self) -> &Foo {
1257 &Foo('z') 1209 &Foo('z')
@@ -1265,30 +1217,29 @@ mod b {
1265} 1217}
1266 "#, 1218 "#,
1267 expect![[r#" 1219 expect![[r#"
1268 67..71 'self': &Self 1220 75..79 'self': &Foo
1269 168..172 'self': &Foo 1221 89..119 '{ ... }': char
1270 182..212 '{ ... }': char 1222 103..107 'self': &Foo
1271 196..200 'self': &Foo 1223 103..109 'self.0': char
1272 196..202 'self.0': char 1224 195..226 '{ ... }': Bar
1273 288..319 '{ ... }': Bar 1225 209..213 'Self': Bar(i32) -> Bar
1274 302..306 'Self': Bar(i32) -> Bar 1226 209..216 'Self(0)': Bar
1275 302..309 'Self(0)': Bar 1227 214..215 '0': i32
1276 307..308 '0': i32 1228 245..249 'self': &Bar
1277 338..342 'self': &Bar 1229 258..288 '{ ... }': i32
1278 351..381 '{ ... }': i32 1230 272..276 'self': &Bar
1279 365..369 'self': &Bar 1231 272..278 'self.0': i32
1280 365..371 'self.0': i32 1232 376..380 'self': &Bar
1281 465..469 'self': &Bar 1233 390..423 '{ ... }': &Foo
1282 479..512 '{ ... }': &Foo 1234 404..413 '&Foo('z')': &Foo
1283 493..502 '&Foo('z')': &Foo 1235 405..408 'Foo': Foo(char) -> Foo
1284 494..497 'Foo': Foo(char) -> Foo 1236 405..413 'Foo('z')': Foo
1285 494..502 'Foo('z')': Foo 1237 409..412 ''z'': char
1286 498..501 ''z'': char 1238 453..506 '{ ... }': ()
1287 542..595 '{ ... }': () 1239 467..468 'x': char
1288 556..557 'x': char 1240 471..489 'super:...r::new': fn new() -> Bar
1289 560..578 'super:...r::new': fn new() -> Bar 1241 471..491 'super:...:new()': Bar
1290 560..580 'super:...:new()': Bar 1242 471..499 'super:...ango()': char
1291 560..588 'super:...ango()': char
1292 "#]], 1243 "#]],
1293 ) 1244 )
1294} 1245}
@@ -1389,11 +1340,11 @@ pub trait IntoIterator {
1389 1340
1390impl<T> IntoIterator for [T; 1] { 1341impl<T> IntoIterator for [T; 1] {
1391 type Out = T; 1342 type Out = T;
1392 fn into_iter(self) -> Self::Out {} 1343 fn into_iter(self) -> Self::Out { loop {} }
1393} 1344}
1394impl<'a, T> IntoIterator for &'a [T] { 1345impl<'a, T> IntoIterator for &'a [T] {
1395 type Out = &'a T; 1346 type Out = &'a T;
1396 fn into_iter(self) -> Self::Out {} 1347 fn into_iter(self) -> Self::Out { loop {} }
1397} 1348}
1398 "#, 1349 "#,
1399 ); 1350 );
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index aa513c56d..47aa30d2e 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types}; 3use super::{check, check_infer, check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -518,7 +518,7 @@ fn infer_generics_in_patterns() {
518 518
519#[test] 519#[test]
520fn infer_const_pattern() { 520fn infer_const_pattern() {
521 check_mismatches( 521 check(
522 r#" 522 r#"
523enum Option<T> { None } 523enum Option<T> { None }
524use Option::None; 524use Option::None;
@@ -571,48 +571,44 @@ fn main() {
571fn match_ergonomics_in_closure_params() { 571fn match_ergonomics_in_closure_params() {
572 check_infer( 572 check_infer(
573 r#" 573 r#"
574 #[lang = "fn_once"] 574//- minicore: fn
575 trait FnOnce<Args> { 575fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
576 type Output;
577 }
578
579 fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
580 576
581 fn test() { 577fn test() {
582 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics 578 foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
583 foo(&(1, "a"), |(x, y)| x); 579 foo(&(1, "a"), |(x, y)| x);
584 } 580}
585 "#, 581"#,
586 expect![[r#" 582 expect![[r#"
587 93..94 't': T 583 32..33 't': T
588 99..100 'f': F 584 38..39 'f': F
589 110..121 '{ loop {} }': U 585 49..60 '{ loop {} }': U
590 112..119 'loop {}': ! 586 51..58 'loop {}': !
591 117..119 '{}': () 587 56..58 '{}': ()
592 133..232 '{ ... x); }': () 588 72..171 '{ ... x); }': ()
593 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 589 78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
594 139..166 'foo(&(...y)| x)': i32 590 78..105 'foo(&(...y)| x)': i32
595 143..152 '&(1, "a")': &(i32, &str) 591 82..91 '&(1, "a")': &(i32, &str)
596 144..152 '(1, "a")': (i32, &str) 592 83..91 '(1, "a")': (i32, &str)
597 145..146 '1': i32 593 84..85 '1': i32
598 148..151 '"a"': &str 594 87..90 '"a"': &str
599 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32 595 93..104 '|&(x, y)| x': |&(i32, &str)| -> i32
600 155..162 '&(x, y)': &(i32, &str) 596 94..101 '&(x, y)': &(i32, &str)
601 156..162 '(x, y)': (i32, &str) 597 95..101 '(x, y)': (i32, &str)
602 157..158 'x': i32 598 96..97 'x': i32
603 160..161 'y': &str 599 99..100 'y': &str
604 164..165 'x': i32 600 103..104 'x': i32
605 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 601 142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
606 203..229 'foo(&(...y)| x)': &i32 602 142..168 'foo(&(...y)| x)': &i32
607 207..216 '&(1, "a")': &(i32, &str) 603 146..155 '&(1, "a")': &(i32, &str)
608 208..216 '(1, "a")': (i32, &str) 604 147..155 '(1, "a")': (i32, &str)
609 209..210 '1': i32 605 148..149 '1': i32
610 212..215 '"a"': &str 606 151..154 '"a"': &str
611 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32 607 157..167 '|(x, y)| x': |&(i32, &str)| -> &i32
612 219..225 '(x, y)': (i32, &str) 608 158..164 '(x, y)': (i32, &str)
613 220..221 'x': &i32 609 159..160 'x': &i32
614 223..224 'y': &&str 610 162..163 'y': &&str
615 227..228 'x': &i32 611 166..167 'x': &i32
616 "#]], 612 "#]],
617 ); 613 );
618} 614}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 1019e783b..8c5e8954c 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_types}; 3use super::{check_infer, check_no_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn bug_484() { 6fn bug_484() {
@@ -418,55 +418,24 @@ fn issue_2705() {
418fn issue_2683_chars_impl() { 418fn issue_2683_chars_impl() {
419 check_types( 419 check_types(
420 r#" 420 r#"
421//- /main.rs crate:main deps:std 421//- minicore: iterator
422fn test() { 422pub struct Chars<'a> {}
423 let chars: std::str::Chars<'_>; 423impl<'a> Iterator for Chars<'a> {
424 (chars.next(), chars.nth(1)); 424 type Item = char;
425} //^ (Option<char>, Option<char>) 425 fn next(&mut self) -> Option<char> { loop {} }
426
427//- /std.rs crate:std
428#[prelude_import]
429use self::prelude::rust_2018::*;
430pub mod prelude {
431 pub mod rust_2018 {
432 pub use crate::iter::Iterator;
433 pub use crate::option::Option;
434 }
435} 426}
436 427
437pub mod iter { 428fn test() {
438 pub use self::traits::Iterator; 429 let chars: Chars<'_>;
439 pub mod traits { 430 (chars.next(), chars.nth(1));
440 pub use self::iterator::Iterator; 431} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>)
441
442 pub mod iterator {
443 pub trait Iterator {
444 type Item;
445 fn next(&mut self) -> Option<Self::Item>;
446 fn nth(&mut self, n: usize) -> Option<Self::Item> {}
447 }
448 }
449 }
450}
451
452pub mod option {
453 pub enum Option<T> {}
454}
455
456pub mod str {
457 pub struct Chars<'a> {}
458 impl<'a> Iterator for Chars<'a> {
459 type Item = char;
460 fn next(&mut self) -> Option<char> {}
461 }
462}
463"#, 432"#,
464 ); 433 );
465} 434}
466 435
467#[test] 436#[test]
468fn issue_3642_bad_macro_stackover() { 437fn issue_3642_bad_macro_stackover() {
469 check_types( 438 check_no_mismatches(
470 r#" 439 r#"
471#[macro_export] 440#[macro_export]
472macro_rules! match_ast { 441macro_rules! match_ast {
@@ -483,7 +452,6 @@ macro_rules! match_ast {
483 452
484fn main() { 453fn main() {
485 let anchor = match_ast! { 454 let anchor = match_ast! {
486 //^ ()
487 match parent { 455 match parent {
488 as => {}, 456 as => {},
489 _ => return None 457 _ => return None
@@ -736,12 +704,8 @@ fn issue_4931() {
736fn issue_4885() { 704fn issue_4885() {
737 check_infer( 705 check_infer(
738 r#" 706 r#"
739 #[lang = "coerce_unsized"] 707 //- minicore: coerce_unsized, future
740 pub trait CoerceUnsized<T> {} 708 use core::future::Future;
741
742 trait Future {
743 type Output;
744 }
745 trait Foo<R> { 709 trait Foo<R> {
746 type Bar; 710 type Bar;
747 } 711 }
@@ -758,13 +722,13 @@ fn issue_4885() {
758 } 722 }
759 "#, 723 "#,
760 expect![[r#" 724 expect![[r#"
761 136..139 'key': &K 725 70..73 'key': &K
762 198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> 726 132..148 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
763 204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> 727 138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
764 204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> 728 138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
765 208..211 'key': &K 729 142..145 'key': &K
766 228..231 'key': &K 730 162..165 'key': &K
767 290..293 '{ }': () 731 224..227 '{ }': ()
768 "#]], 732 "#]],
769 ); 733 );
770} 734}
@@ -827,6 +791,7 @@ fn issue_4800() {
827fn issue_4966() { 791fn issue_4966() {
828 check_infer( 792 check_infer(
829 r#" 793 r#"
794 //- minicore: deref
830 pub trait IntoIterator { 795 pub trait IntoIterator {
831 type Item; 796 type Item;
832 } 797 }
@@ -837,12 +802,7 @@ fn issue_4966() {
837 802
838 struct Vec<T> {} 803 struct Vec<T> {}
839 804
840 #[lang = "deref"] 805 impl<T> core::ops::Deref for Vec<T> {
841 pub trait Deref {
842 type Target;
843 }
844
845 impl<T> Deref for Vec<T> {
846 type Target = [T]; 806 type Target = [T];
847 } 807 }
848 808
@@ -859,23 +819,23 @@ fn issue_4966() {
859 } 819 }
860 "#, 820 "#,
861 expect![[r#" 821 expect![[r#"
862 270..274 'iter': T 822 225..229 'iter': T
863 289..291 '{}': () 823 244..246 '{}': ()
864 303..447 '{ ...r(); }': () 824 258..402 '{ ...r(); }': ()
865 313..318 'inner': Map<|&f64| -> f64> 825 268..273 'inner': Map<|&f64| -> f64>
866 321..345 'Map { ... 0.0 }': Map<|&f64| -> f64> 826 276..300 'Map { ... 0.0 }': Map<|&f64| -> f64>
867 330..343 '|_: &f64| 0.0': |&f64| -> f64 827 285..298 '|_: &f64| 0.0': |&f64| -> f64
868 331..332 '_': &f64 828 286..287 '_': &f64
869 340..343 '0.0': f64 829 295..298 '0.0': f64
870 356..362 'repeat': Repeat<Map<|&f64| -> f64>> 830 311..317 'repeat': Repeat<Map<|&f64| -> f64>>
871 365..390 'Repeat...nner }': Repeat<Map<|&f64| -> f64>> 831 320..345 'Repeat...nner }': Repeat<Map<|&f64| -> f64>>
872 383..388 'inner': Map<|&f64| -> f64> 832 338..343 'inner': Map<|&f64| -> f64>
873 401..404 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> 833 356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
874 407..416 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> 834 362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
875 407..424 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> 835 362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
876 417..423 'repeat': Repeat<Map<|&f64| -> f64>> 836 372..378 'repeat': Repeat<Map<|&f64| -> f64>>
877 431..434 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> 837 386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
878 431..444 'vec.foo_bar()': {unknown} 838 386..399 'vec.foo_bar()': {unknown}
879 "#]], 839 "#]],
880 ); 840 );
881} 841}
@@ -884,41 +844,37 @@ fn issue_4966() {
884fn issue_6628() { 844fn issue_6628() {
885 check_infer( 845 check_infer(
886 r#" 846 r#"
887 #[lang = "fn_once"] 847//- minicore: fn
888 pub trait FnOnce<Args> { 848struct S<T>();
889 type Output; 849impl<T> S<T> {
890 } 850 fn f(&self, _t: T) {}
891 851 fn g<F: FnOnce(&T)>(&self, _f: F) {}
892 struct S<T>(); 852}
893 impl<T> S<T> { 853fn main() {
894 fn f(&self, _t: T) {} 854 let s = S();
895 fn g<F: FnOnce(&T)>(&self, _f: F) {} 855 s.g(|_x| {});
896 } 856 s.f(10);
897 fn main() { 857}
898 let s = S(); 858"#,
899 s.g(|_x| {});
900 s.f(10);
901 }
902 "#,
903 expect![[r#" 859 expect![[r#"
904 105..109 'self': &S<T> 860 40..44 'self': &S<T>
905 111..113 '_t': T 861 46..48 '_t': T
906 118..120 '{}': () 862 53..55 '{}': ()
907 146..150 'self': &S<T> 863 81..85 'self': &S<T>
908 152..154 '_f': F 864 87..89 '_f': F
909 159..161 '{}': () 865 94..96 '{}': ()
910 174..225 '{ ...10); }': () 866 109..160 '{ ...10); }': ()
911 184..185 's': S<i32> 867 119..120 's': S<i32>
912 188..189 'S': S<i32>() -> S<i32> 868 123..124 'S': S<i32>() -> S<i32>
913 188..191 'S()': S<i32> 869 123..126 'S()': S<i32>
914 197..198 's': S<i32> 870 132..133 's': S<i32>
915 197..209 's.g(|_x| {})': () 871 132..144 's.g(|_x| {})': ()
916 201..208 '|_x| {}': |&i32| -> () 872 136..143 '|_x| {}': |&i32| -> ()
917 202..204 '_x': &i32 873 137..139 '_x': &i32
918 206..208 '{}': () 874 141..143 '{}': ()
919 215..216 's': S<i32> 875 150..151 's': S<i32>
920 215..222 's.f(10)': () 876 150..157 's.f(10)': ()
921 219..221 '10': i32 877 154..156 '10': i32
922 "#]], 878 "#]],
923 ); 879 );
924} 880}
@@ -927,35 +883,33 @@ fn issue_6628() {
927fn issue_6852() { 883fn issue_6852() {
928 check_infer( 884 check_infer(
929 r#" 885 r#"
930 #[lang = "deref"] 886//- minicore: deref
931 pub trait Deref { 887use core::ops::Deref;
932 type Target;
933 }
934 888
935 struct BufWriter {} 889struct BufWriter {}
936 890
937 struct Mutex<T> {} 891struct Mutex<T> {}
938 struct MutexGuard<'a, T> {} 892struct MutexGuard<'a, T> {}
939 impl<T> Mutex<T> { 893impl<T> Mutex<T> {
940 fn lock(&self) -> MutexGuard<'_, T> {} 894 fn lock(&self) -> MutexGuard<'_, T> {}
941 } 895}
942 impl<'a, T: 'a> Deref for MutexGuard<'a, T> { 896impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
943 type Target = T; 897 type Target = T;
944 } 898}
945 fn flush(&self) { 899fn flush(&self) {
946 let w: &Mutex<BufWriter>; 900 let w: &Mutex<BufWriter>;
947 *(w.lock()); 901 *(w.lock());
948 } 902}
949 "#, 903"#,
950 expect![[r#" 904 expect![[r#"
951 156..160 'self': &Mutex<T> 905 123..127 'self': &Mutex<T>
952 183..185 '{}': () 906 150..152 '{}': ()
953 267..271 'self': &{unknown} 907 234..238 'self': &{unknown}
954 273..323 '{ ...()); }': () 908 240..290 '{ ...()); }': ()
955 283..284 'w': &Mutex<BufWriter> 909 250..251 'w': &Mutex<BufWriter>
956 309..320 '*(w.lock())': BufWriter 910 276..287 '*(w.lock())': BufWriter
957 311..312 'w': &Mutex<BufWriter> 911 278..279 'w': &Mutex<BufWriter>
958 311..319 'w.lock()': MutexGuard<BufWriter> 912 278..286 'w.lock()': MutexGuard<BufWriter>
959 "#]], 913 "#]],
960 ); 914 );
961} 915}
@@ -977,37 +931,33 @@ fn param_overrides_fn() {
977fn lifetime_from_chalk_during_deref() { 931fn lifetime_from_chalk_during_deref() {
978 check_types( 932 check_types(
979 r#" 933 r#"
980 #[lang = "deref"] 934//- minicore: deref
981 pub trait Deref { 935struct Box<T: ?Sized> {}
982 type Target; 936impl<T> core::ops::Deref for Box<T> {
983 } 937 type Target = T;
984
985 struct Box<T: ?Sized> {}
986 impl<T> Deref for Box<T> {
987 type Target = T;
988 938
989 fn deref(&self) -> &Self::Target { 939 fn deref(&self) -> &Self::Target {
990 loop {} 940 loop {}
991 } 941 }
992 } 942}
993 943
994 trait Iterator { 944trait Iterator {
995 type Item; 945 type Item;
996 } 946}
997 947
998 pub struct Iter<'a, T: 'a> { 948pub struct Iter<'a, T: 'a> {
999 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, 949 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1000 } 950}
1001 951
1002 trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { 952trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1003 fn clone_box(&self); 953 fn clone_box(&self);
1004 } 954}
1005 955
1006 fn clone_iter<T>(s: Iter<T>) { 956fn clone_iter<T>(s: Iter<T>) {
1007 s.inner.clone_box(); 957 s.inner.clone_box();
1008 //^^^^^^^^^^^^^^^^^^^ () 958 //^^^^^^^^^^^^^^^^^^^ ()
1009 } 959}
1010 "#, 960"#,
1011 ) 961 )
1012} 962}
1013 963
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 3418ed21e..b4bcc6d95 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -60,7 +60,7 @@ enum Nat { Succ(Self), Demo(Nat), Zero }
60fn test() { 60fn test() {
61 let foo: Nat = Nat::Zero; 61 let foo: Nat = Nat::Zero;
62 if let Nat::Succ(x) = foo { 62 if let Nat::Succ(x) = foo {
63 x 63 x;
64 } //^ Nat 64 } //^ Nat
65} 65}
66"#, 66"#,
@@ -113,7 +113,7 @@ fn type_alias_in_struct_lit() {
113fn infer_ranges() { 113fn infer_ranges() {
114 check_types( 114 check_types(
115 r#" 115 r#"
116//- /main.rs crate:main deps:core 116//- minicore: range
117fn test() { 117fn test() {
118 let a = ..; 118 let a = ..;
119 let b = 1..; 119 let b = 1..;
@@ -125,32 +125,6 @@ fn test() {
125 let t = (a, b, c, d, e, f); 125 let t = (a, b, c, d, e, f);
126 t; 126 t;
127} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) 127} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
128
129//- /core.rs crate:core
130#[prelude_import] use prelude::*;
131mod prelude {}
132
133pub mod ops {
134 pub struct Range<Idx> {
135 pub start: Idx,
136 pub end: Idx,
137 }
138 pub struct RangeFrom<Idx> {
139 pub start: Idx,
140 }
141 struct RangeFull;
142 pub struct RangeInclusive<Idx> {
143 start: Idx,
144 end: Idx,
145 is_empty: u8,
146 }
147 pub struct RangeTo<Idx> {
148 pub end: Idx,
149 }
150 pub struct RangeToInclusive<Idx> {
151 pub end: Idx,
152 }
153}
154"#, 128"#,
155 ); 129 );
156} 130}
@@ -164,7 +138,7 @@ enum Option<T> { Some(T), None }
164fn test() { 138fn test() {
165 let foo: Option<f32> = None; 139 let foo: Option<f32> = None;
166 while let Option::Some(x) = foo { 140 while let Option::Some(x) = foo {
167 x 141 x;
168 } //^ f32 142 } //^ f32
169} 143}
170"#, 144"#,
@@ -175,16 +149,17 @@ fn test() {
175fn infer_basics() { 149fn infer_basics() {
176 check_infer( 150 check_infer(
177 r#" 151 r#"
178 fn test(a: u32, b: isize, c: !, d: &str) { 152fn test(a: u32, b: isize, c: !, d: &str) {
179 a; 153 a;
180 b; 154 b;
181 c; 155 c;
182 d; 156 d;
183 1usize; 157 1usize;
184 1isize; 158 1isize;
185 "test"; 159 "test";
186 1.0f32; 160 1.0f32;
187 }"#, 161}
162"#,
188 expect![[r#" 163 expect![[r#"
189 8..9 'a': u32 164 8..9 'a': u32
190 16..17 'b': isize 165 16..17 'b': isize
@@ -207,15 +182,15 @@ fn infer_basics() {
207fn infer_let() { 182fn infer_let() {
208 check_infer( 183 check_infer(
209 r#" 184 r#"
210 fn test() { 185fn test() {
211 let a = 1isize; 186 let a = 1isize;
212 let b: usize = 1; 187 let b: usize = 1;
213 let c = b; 188 let c = b;
214 let d: u32; 189 let d: u32;
215 let e; 190 let e;
216 let f: i32 = e; 191 let f: i32 = e;
217 } 192}
218 "#, 193"#,
219 expect![[r#" 194 expect![[r#"
220 10..117 '{ ...= e; }': () 195 10..117 '{ ...= e; }': ()
221 20..21 'a': isize 196 20..21 'a': isize
@@ -236,17 +211,17 @@ fn infer_let() {
236fn infer_paths() { 211fn infer_paths() {
237 check_infer( 212 check_infer(
238 r#" 213 r#"
239 fn a() -> u32 { 1 } 214fn a() -> u32 { 1 }
240 215
241 mod b { 216mod b {
242 fn c() -> u32 { 1 } 217 fn c() -> u32 { 1 }
243 } 218}
244 219
245 fn test() { 220fn test() {
246 a(); 221 a();
247 b::c(); 222 b::c();
248 } 223}
249 "#, 224"#,
250 expect![[r#" 225 expect![[r#"
251 14..19 '{ 1 }': u32 226 14..19 '{ 1 }': u32
252 16..17 '1': u32 227 16..17 '1': u32
@@ -265,17 +240,17 @@ fn infer_paths() {
265fn infer_path_type() { 240fn infer_path_type() {
266 check_infer( 241 check_infer(
267 r#" 242 r#"
268 struct S; 243struct S;
269 244
270 impl S { 245impl S {
271 fn foo() -> i32 { 1 } 246 fn foo() -> i32 { 1 }
272 } 247}
273 248
274 fn test() { 249fn test() {
275 S::foo(); 250 S::foo();
276 <S>::foo(); 251 <S>::foo();
277 } 252}
278 "#, 253"#,
279 expect![[r#" 254 expect![[r#"
280 40..45 '{ 1 }': i32 255 40..45 '{ 1 }': i32
281 42..43 '1': i32 256 42..43 '1': i32
@@ -292,21 +267,21 @@ fn infer_path_type() {
292fn infer_struct() { 267fn infer_struct() {
293 check_infer( 268 check_infer(
294 r#" 269 r#"
295 struct A { 270struct A {
296 b: B, 271 b: B,
297 c: C, 272 c: C,
298 } 273}
299 struct B; 274struct B;
300 struct C(usize); 275struct C(usize);
301 276
302 fn test() { 277fn test() {
303 let c = C(1); 278 let c = C(1);
304 B; 279 B;
305 let a: A = A { b: B, c: C(1) }; 280 let a: A = A { b: B, c: C(1) };
306 a.b; 281 a.b;
307 a.c; 282 a.c;
308 } 283}
309 "#, 284"#,
310 expect![[r#" 285 expect![[r#"
311 71..153 '{ ...a.c; }': () 286 71..153 '{ ...a.c; }': ()
312 81..82 'c': C 287 81..82 'c': C
@@ -332,14 +307,15 @@ fn infer_struct() {
332fn infer_enum() { 307fn infer_enum() {
333 check_infer( 308 check_infer(
334 r#" 309 r#"
335 enum E { 310enum E {
336 V1 { field: u32 }, 311 V1 { field: u32 },
337 V2 312 V2
338 } 313}
339 fn test() { 314fn test() {
340 E::V1 { field: 1 }; 315 E::V1 { field: 1 };
341 E::V2; 316 E::V2;
342 }"#, 317}
318"#,
343 expect![[r#" 319 expect![[r#"
344 51..89 '{ ...:V2; }': () 320 51..89 '{ ...:V2; }': ()
345 57..75 'E::V1 ...d: 1 }': E 321 57..75 'E::V1 ...d: 1 }': E
@@ -353,23 +329,23 @@ fn infer_enum() {
353fn infer_union() { 329fn infer_union() {
354 check_infer( 330 check_infer(
355 r#" 331 r#"
356 union MyUnion { 332union MyUnion {
357 foo: u32, 333 foo: u32,
358 bar: f32, 334 bar: f32,
359 } 335}
360 336
361 fn test() { 337fn test() {
362 let u = MyUnion { foo: 0 }; 338 let u = MyUnion { foo: 0 };
363 unsafe { baz(u); } 339 unsafe { baz(u); }
364 let u = MyUnion { bar: 0.0 }; 340 let u = MyUnion { bar: 0.0 };
365 unsafe { baz(u); } 341 unsafe { baz(u); }
366 } 342}
367 343
368 unsafe fn baz(u: MyUnion) { 344unsafe fn baz(u: MyUnion) {
369 let inner = u.foo; 345 let inner = u.foo;
370 let inner = u.bar; 346 let inner = u.bar;
371 } 347}
372 "#, 348"#,
373 expect![[r#" 349 expect![[r#"
374 57..172 '{ ...); } }': () 350 57..172 '{ ...); } }': ()
375 67..68 'u': MyUnion 351 67..68 'u': MyUnion
@@ -404,19 +380,19 @@ fn infer_union() {
404fn infer_refs() { 380fn infer_refs() {
405 check_infer( 381 check_infer(
406 r#" 382 r#"
407 fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { 383fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
408 a; 384 a;
409 *a; 385 *a;
410 &a; 386 &a;
411 &mut a; 387 &mut a;
412 b; 388 b;
413 *b; 389 *b;
414 &b; 390 &b;
415 c; 391 c;
416 *c; 392 *c;
417 d; 393 d;
418 *d; 394 *d;
419 } 395}
420 "#, 396 "#,
421 expect![[r#" 397 expect![[r#"
422 8..9 'a': &u32 398 8..9 'a': &u32
@@ -450,11 +426,11 @@ fn infer_refs() {
450fn infer_raw_ref() { 426fn infer_raw_ref() {
451 check_infer( 427 check_infer(
452 r#" 428 r#"
453 fn test(a: i32) { 429fn test(a: i32) {
454 &raw mut a; 430 &raw mut a;
455 &raw const a; 431 &raw const a;
456 } 432}
457 "#, 433"#,
458 expect![[r#" 434 expect![[r#"
459 8..9 'a': i32 435 8..9 'a': i32
460 16..53 '{ ...t a; }': () 436 16..53 '{ ...t a; }': ()
@@ -524,26 +500,26 @@ h";
524fn infer_unary_op() { 500fn infer_unary_op() {
525 check_infer( 501 check_infer(
526 r#" 502 r#"
527 enum SomeType {} 503enum SomeType {}
528 504
529 fn test(x: SomeType) { 505fn test(x: SomeType) {
530 let b = false; 506 let b = false;
531 let c = !b; 507 let c = !b;
532 let a = 100; 508 let a = 100;
533 let d: i128 = -a; 509 let d: i128 = -a;
534 let e = -100; 510 let e = -100;
535 let f = !!!true; 511 let f = !!!true;
536 let g = !42; 512 let g = !42;
537 let h = !10u32; 513 let h = !10u32;
538 let j = !a; 514 let j = !a;
539 -3.14; 515 -3.14;
540 !3; 516 !3;
541 -x; 517 -x;
542 !x; 518 !x;
543 -"hello"; 519 -"hello";
544 !"hello"; 520 !"hello";
545 } 521}
546 "#, 522"#,
547 expect![[r#" 523 expect![[r#"
548 26..27 'x': SomeType 524 26..27 'x': SomeType
549 39..271 '{ ...lo"; }': () 525 39..271 '{ ...lo"; }': ()
@@ -594,19 +570,19 @@ fn infer_unary_op() {
594fn infer_backwards() { 570fn infer_backwards() {
595 check_infer( 571 check_infer(
596 r#" 572 r#"
597 fn takes_u32(x: u32) {} 573fn takes_u32(x: u32) {}
598 574
599 struct S { i32_field: i32 } 575struct S { i32_field: i32 }
600 576
601 fn test() -> &mut &f64 { 577fn test() -> &mut &f64 {
602 let a = unknown_function(); 578 let a = unknown_function();
603 takes_u32(a); 579 takes_u32(a);
604 let b = unknown_function(); 580 let b = unknown_function();
605 S { i32_field: b }; 581 S { i32_field: b };
606 let c = unknown_function(); 582 let c = unknown_function();
607 &mut &c 583 &mut &c
608 } 584}
609 "#, 585"#,
610 expect![[r#" 586 expect![[r#"
611 13..14 'x': u32 587 13..14 'x': u32
612 21..23 '{}': () 588 21..23 '{}': ()
@@ -636,23 +612,23 @@ fn infer_backwards() {
636fn infer_self() { 612fn infer_self() {
637 check_infer( 613 check_infer(
638 r#" 614 r#"
639 struct S; 615struct S;
640 616
641 impl S { 617impl S {
642 fn test(&self) { 618 fn test(&self) {
643 self; 619 self;
644 } 620 }
645 fn test2(self: &Self) { 621 fn test2(self: &Self) {
646 self; 622 self;
647 } 623 }
648 fn test3() -> Self { 624 fn test3() -> Self {
649 S {} 625 S {}
650 } 626 }
651 fn test4() -> Self { 627 fn test4() -> Self {
652 Self {} 628 Self {}
653 } 629 }
654 } 630}
655 "#, 631"#,
656 expect![[r#" 632 expect![[r#"
657 33..37 'self': &S 633 33..37 'self': &S
658 39..60 '{ ... }': () 634 39..60 '{ ... }': ()
@@ -672,30 +648,30 @@ fn infer_self() {
672fn infer_self_as_path() { 648fn infer_self_as_path() {
673 check_infer( 649 check_infer(
674 r#" 650 r#"
675 struct S1; 651struct S1;
676 struct S2(isize); 652struct S2(isize);
677 enum E { 653enum E {
678 V1, 654 V1,
679 V2(u32), 655 V2(u32),
680 } 656}
681 657
682 impl S1 { 658impl S1 {
683 fn test() { 659 fn test() {
684 Self; 660 Self;
685 } 661 }
686 } 662}
687 impl S2 { 663impl S2 {
688 fn test() { 664 fn test() {
689 Self(1); 665 Self(1);
690 } 666 }
691 } 667}
692 impl E { 668impl E {
693 fn test() { 669 fn test() {
694 Self::V1; 670 Self::V1;
695 Self::V2(1); 671 Self::V2(1);
696 } 672 }
697 } 673}
698 "#, 674"#,
699 expect![[r#" 675 expect![[r#"
700 86..107 '{ ... }': () 676 86..107 '{ ... }': ()
701 96..100 'Self': S1 677 96..100 'Self': S1
@@ -716,26 +692,26 @@ fn infer_self_as_path() {
716fn infer_binary_op() { 692fn infer_binary_op() {
717 check_infer( 693 check_infer(
718 r#" 694 r#"
719 fn f(x: bool) -> i32 { 695fn f(x: bool) -> i32 {
720 0i32 696 0i32
721 } 697}
722 698
723 fn test() -> bool { 699fn test() -> bool {
724 let x = a && b; 700 let x = a && b;
725 let y = true || false; 701 let y = true || false;
726 let z = x == y; 702 let z = x == y;
727 let t = x != y; 703 let t = x != y;
728 let minus_forty: isize = -40isize; 704 let minus_forty: isize = -40isize;
729 let h = minus_forty <= CONST_2; 705 let h = minus_forty <= CONST_2;
730 let c = f(z || y) + 5; 706 let c = f(z || y) + 5;
731 let d = b; 707 let d = b;
732 let g = minus_forty ^= i; 708 let g = minus_forty ^= i;
733 let ten: usize = 10; 709 let ten: usize = 10;
734 let ten_is_eleven = ten == some_num; 710 let ten_is_eleven = ten == some_num;
735 711
736 ten < 3 712 ten < 3
737 } 713}
738 "#, 714"#,
739 expect![[r#" 715 expect![[r#"
740 5..6 'x': bool 716 5..6 'x': bool
741 21..33 '{ 0i32 }': i32 717 21..33 '{ 0i32 }': i32
@@ -795,11 +771,11 @@ fn infer_binary_op() {
795fn infer_shift_op() { 771fn infer_shift_op() {
796 check_infer( 772 check_infer(
797 r#" 773 r#"
798 fn test() { 774fn test() {
799 1u32 << 5u8; 775 1u32 << 5u8;
800 1u32 >> 5u8; 776 1u32 >> 5u8;
801 } 777}
802 "#, 778"#,
803 expect![[r#" 779 expect![[r#"
804 10..47 '{ ...5u8; }': () 780 10..47 '{ ...5u8; }': ()
805 16..20 '1u32': u32 781 16..20 '1u32': u32
@@ -816,29 +792,29 @@ fn infer_shift_op() {
816fn infer_field_autoderef() { 792fn infer_field_autoderef() {
817 check_infer( 793 check_infer(
818 r#" 794 r#"
819 struct A { 795struct A {
820 b: B, 796 b: B,
821 } 797}
822 struct B; 798struct B;
823
824 fn test1(a: A) {
825 let a1 = a;
826 a1.b;
827 let a2 = &a;
828 a2.b;
829 let a3 = &mut a;
830 a3.b;
831 let a4 = &&&&&&&a;
832 a4.b;
833 let a5 = &mut &&mut &&mut a;
834 a5.b;
835 }
836 799
837 fn test2(a1: *const A, a2: *mut A) { 800fn test1(a: A) {
838 a1.b; 801 let a1 = a;
839 a2.b; 802 a1.b;
840 } 803 let a2 = &a;
841 "#, 804 a2.b;
805 let a3 = &mut a;
806 a3.b;
807 let a4 = &&&&&&&a;
808 a4.b;
809 let a5 = &mut &&mut &&mut a;
810 a5.b;
811}
812
813fn test2(a1: *const A, a2: *mut A) {
814 a1.b;
815 a2.b;
816}
817"#,
842 expect![[r#" 818 expect![[r#"
843 43..44 'a': A 819 43..44 'a': A
844 49..212 '{ ...5.b; }': () 820 49..212 '{ ...5.b; }': ()
@@ -891,58 +867,53 @@ fn infer_field_autoderef() {
891fn infer_argument_autoderef() { 867fn infer_argument_autoderef() {
892 check_infer( 868 check_infer(
893 r#" 869 r#"
894 #[lang = "deref"] 870//- minicore: deref
895 pub trait Deref { 871use core::ops::Deref;
896 type Target; 872struct A<T>(T);
897 fn deref(&self) -> &Self::Target;
898 }
899 873
900 struct A<T>(T); 874impl<T> A<T> {
901 875 fn foo(&self) -> &T {
902 impl<T> A<T> { 876 &self.0
903 fn foo(&self) -> &T { 877 }
904 &self.0 878}
905 }
906 }
907 879
908 struct B<T>(T); 880struct B<T>(T);
909 881
910 impl<T> Deref for B<T> { 882impl<T> Deref for B<T> {
911 type Target = T; 883 type Target = T;
912 fn deref(&self) -> &Self::Target { 884 fn deref(&self) -> &Self::Target {
913 &self.0 885 &self.0
914 } 886 }
915 } 887}
916 888
917 fn test() { 889fn test() {
918 let t = A::foo(&&B(B(A(42)))); 890 let t = A::foo(&&B(B(A(42))));
919 } 891}
920 "#, 892"#,
921 expect![[r#" 893 expect![[r#"
922 67..71 'self': &Self 894 66..70 'self': &A<T>
923 138..142 'self': &A<T> 895 78..101 '{ ... }': &T
924 150..173 '{ ... }': &T 896 88..95 '&self.0': &T
925 160..167 '&self.0': &T 897 89..93 'self': &A<T>
926 161..165 'self': &A<T> 898 89..95 'self.0': T
927 161..167 'self.0': T 899 182..186 'self': &B<T>
928 254..258 'self': &B<T> 900 205..228 '{ ... }': &T
929 277..300 '{ ... }': &T 901 215..222 '&self.0': &T
930 287..294 '&self.0': &T 902 216..220 'self': &B<T>
931 288..292 'self': &B<T> 903 216..222 'self.0': T
932 288..294 'self.0': T 904 242..280 '{ ...))); }': ()
933 314..352 '{ ...))); }': () 905 252..253 't': &i32
934 324..325 't': &i32 906 256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
935 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 907 256..277 'A::foo...42))))': &i32
936 328..349 'A::foo...42))))': &i32 908 263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
937 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> 909 264..276 '&B(B(A(42)))': &B<B<A<i32>>>
938 336..348 '&B(B(A(42)))': &B<B<A<i32>>> 910 265..266 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
939 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 911 265..276 'B(B(A(42)))': B<B<A<i32>>>
940 337..348 'B(B(A(42)))': B<B<A<i32>>> 912 267..268 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
941 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 913 267..275 'B(A(42))': B<A<i32>>
942 339..347 'B(A(42))': B<A<i32>> 914 269..270 'A': A<i32>(i32) -> A<i32>
943 341..342 'A': A<i32>(i32) -> A<i32> 915 269..274 'A(42)': A<i32>
944 341..346 'A(42)': A<i32> 916 271..273 '42': i32
945 343..345 '42': i32
946 "#]], 917 "#]],
947 ); 918 );
948} 919}
@@ -951,62 +922,57 @@ fn infer_argument_autoderef() {
951fn infer_method_argument_autoderef() { 922fn infer_method_argument_autoderef() {
952 check_infer( 923 check_infer(
953 r#" 924 r#"
954 #[lang = "deref"] 925//- minicore: deref
955 pub trait Deref { 926use core::ops::Deref;
956 type Target; 927struct A<T>(*mut T);
957 fn deref(&self) -> &Self::Target;
958 }
959 928
960 struct A<T>(*mut T); 929impl<T> A<T> {
961 930 fn foo(&self, x: &A<T>) -> &T {
962 impl<T> A<T> { 931 &*x.0
963 fn foo(&self, x: &A<T>) -> &T { 932 }
964 &*x.0 933}
965 }
966 }
967 934
968 struct B<T>(T); 935struct B<T>(T);
969 936
970 impl<T> Deref for B<T> { 937impl<T> Deref for B<T> {
971 type Target = T; 938 type Target = T;
972 fn deref(&self) -> &Self::Target { 939 fn deref(&self) -> &Self::Target {
973 &self.0 940 &self.0
974 } 941 }
975 } 942}
976 943
977 fn test(a: A<i32>) { 944fn test(a: A<i32>) {
978 let t = A(0 as *mut _).foo(&&B(B(a))); 945 let t = A(0 as *mut _).foo(&&B(B(a)));
979 } 946}
980 "#, 947"#,
981 expect![[r#" 948 expect![[r#"
982 67..71 'self': &Self 949 71..75 'self': &A<T>
983 143..147 'self': &A<T> 950 77..78 'x': &A<T>
984 149..150 'x': &A<T> 951 93..114 '{ ... }': &T
985 165..186 '{ ... }': &T 952 103..108 '&*x.0': &T
986 175..180 '&*x.0': &T 953 104..108 '*x.0': T
987 176..180 '*x.0': T 954 105..106 'x': &A<T>
988 177..178 'x': &A<T> 955 105..108 'x.0': *mut T
989 177..180 'x.0': *mut T 956 195..199 'self': &B<T>
990 267..271 'self': &B<T> 957 218..241 '{ ... }': &T
991 290..313 '{ ... }': &T 958 228..235 '&self.0': &T
992 300..307 '&self.0': &T 959 229..233 'self': &B<T>
993 301..305 'self': &B<T> 960 229..235 'self.0': T
994 301..307 'self.0': T 961 253..254 'a': A<i32>
995 325..326 'a': A<i32> 962 264..310 '{ ...))); }': ()
996 336..382 '{ ...))); }': () 963 274..275 't': &i32
997 346..347 't': &i32 964 278..279 'A': A<i32>(*mut i32) -> A<i32>
998 350..351 'A': A<i32>(*mut i32) -> A<i32> 965 278..292 'A(0 as *mut _)': A<i32>
999 350..364 'A(0 as *mut _)': A<i32> 966 278..307 'A(0 as...B(a)))': &i32
1000 350..379 'A(0 as...B(a)))': &i32 967 280..281 '0': i32
1001 352..353 '0': i32 968 280..291 '0 as *mut _': *mut i32
1002 352..363 '0 as *mut _': *mut i32 969 297..306 '&&B(B(a))': &&B<B<A<i32>>>
1003 369..378 '&&B(B(a))': &&B<B<A<i32>>> 970 298..306 '&B(B(a))': &B<B<A<i32>>>
1004 370..378 '&B(B(a))': &B<B<A<i32>>> 971 299..300 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
1005 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> 972 299..306 'B(B(a))': B<B<A<i32>>>
1006 371..378 'B(B(a))': B<B<A<i32>>> 973 301..302 'B': B<A<i32>>(A<i32>) -> B<A<i32>>
1007 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> 974 301..305 'B(a)': B<A<i32>>
1008 373..377 'B(a)': B<A<i32>> 975 303..304 'a': A<i32>
1009 375..376 'a': A<i32>
1010 "#]], 976 "#]],
1011 ); 977 );
1012} 978}
@@ -1015,15 +981,15 @@ fn infer_method_argument_autoderef() {
1015fn infer_in_elseif() { 981fn infer_in_elseif() {
1016 check_infer( 982 check_infer(
1017 r#" 983 r#"
1018 struct Foo { field: i32 } 984struct Foo { field: i32 }
1019 fn main(foo: Foo) { 985fn main(foo: Foo) {
1020 if true { 986 if true {
1021 987
1022 } else if false { 988 } else if false {
1023 foo.field 989 foo.field
1024 } 990 }
1025 } 991}
1026 "#, 992"#,
1027 expect![[r#" 993 expect![[r#"
1028 34..37 'foo': Foo 994 34..37 'foo': Foo
1029 44..108 '{ ... } }': () 995 44..108 '{ ... } }': ()
@@ -1043,28 +1009,29 @@ fn infer_in_elseif() {
1043fn infer_if_match_with_return() { 1009fn infer_if_match_with_return() {
1044 check_infer( 1010 check_infer(
1045 r#" 1011 r#"
1046 fn foo() { 1012fn foo() {
1047 let _x1 = if true { 1013 let _x1 = if true {
1048 1 1014 1
1049 } else { 1015 } else {
1050 return; 1016 return;
1051 }; 1017 };
1052 let _x2 = if true { 1018 let _x2 = if true {
1053 2 1019 2
1054 } else { 1020 } else {
1055 return 1021 return
1056 }; 1022 };
1057 let _x3 = match true { 1023 let _x3 = match true {
1058 true => 3, 1024 true => 3,
1059 _ => { 1025 _ => {
1060 return; 1026 return;
1061 } 1027 }
1062 }; 1028 };
1063 let _x4 = match true { 1029 let _x4 = match true {
1064 true => 4, 1030 true => 4,
1065 _ => return 1031 _ => return
1066 }; 1032 };
1067 }"#, 1033}
1034"#,
1068 expect![[r#" 1035 expect![[r#"
1069 9..322 '{ ... }; }': () 1036 9..322 '{ ... }; }': ()
1070 19..22 '_x1': i32 1037 19..22 '_x1': i32
@@ -1778,7 +1745,7 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
1778fn main() { 1745fn main() {
1779 let x: i32 = i32; 1746 let x: i32 = i32;
1780 x.foo(); 1747 x.foo();
1781 //^ Foo 1748 //^^^^^^^ Foo
1782}"#, 1749}"#,
1783 ); 1750 );
1784} 1751}
@@ -1796,7 +1763,7 @@ fn main() {
1796 fn inner() {} 1763 fn inner() {}
1797 let x: i32 = i32; 1764 let x: i32 = i32;
1798 x.foo(); 1765 x.foo();
1799 //^ Foo 1766 //^^^^^^^ Foo
1800}"#, 1767}"#,
1801 ); 1768 );
1802} 1769}
@@ -1814,7 +1781,7 @@ fn foo() -> &'static str { "" }
1814 1781
1815fn main() { 1782fn main() {
1816 foo(); 1783 foo();
1817 //^ &str 1784 //^^^^^ &str
1818}"#, 1785}"#,
1819 ); 1786 );
1820} 1787}
@@ -1832,7 +1799,7 @@ fn foo() -> &'static str { "" }
1832 1799
1833fn main() { 1800fn main() {
1834 str::foo(); 1801 str::foo();
1835 //^ u32 1802 //^^^^^^^^^^ u32
1836}"#, 1803}"#,
1837 ); 1804 );
1838} 1805}
@@ -1858,9 +1825,9 @@ mod d {
1858 1825
1859fn main() { 1826fn main() {
1860 d::foo(); 1827 d::foo();
1861 //^ u8 1828 //^^^^^^^^ u8
1862 d::foo{a:0}; 1829 d::foo{a:0};
1863 //^ u8 1830 //^^^^^^^^^^^ foo
1864}"#, 1831}"#,
1865 ); 1832 );
1866} 1833}
@@ -1950,6 +1917,7 @@ fn fn_pointer_return() {
1950fn effects_smoke_test() { 1917fn effects_smoke_test() {
1951 check_infer( 1918 check_infer(
1952 r#" 1919 r#"
1920 //- minicore: future
1953 async fn main() { 1921 async fn main() {
1954 let x = unsafe { 92 }; 1922 let x = unsafe { 92 };
1955 let y = async { async { () }.await }; 1923 let y = async { async { () }.await };
@@ -1957,13 +1925,6 @@ fn effects_smoke_test() {
1957 let w = const { 92 }; 1925 let w = const { 92 };
1958 let t = 'a: { 92 }; 1926 let t = 'a: { 92 };
1959 } 1927 }
1960
1961 #[prelude_import] use future::*;
1962
1963 mod future {
1964 #[lang = "future_trait"]
1965 pub trait Future { type Output; }
1966 }
1967 "#, 1928 "#,
1968 expect![[r#" 1929 expect![[r#"
1969 16..162 '{ ...2 }; }': () 1930 16..162 '{ ...2 }; }': ()
@@ -2639,11 +2600,8 @@ fn f() {
2639fn infer_boxed_self_receiver() { 2600fn infer_boxed_self_receiver() {
2640 check_infer( 2601 check_infer(
2641 r#" 2602 r#"
2642#[lang = "deref"] 2603//- minicore: deref
2643pub trait Deref { 2604use core::ops::Deref;
2644 type Target;
2645 fn deref(&self) -> &Self::Target;
2646}
2647 2605
2648struct Box<T>(T); 2606struct Box<T>(T);
2649 2607
@@ -2675,40 +2633,39 @@ fn main() {
2675} 2633}
2676 "#, 2634 "#,
2677 expect![[r#" 2635 expect![[r#"
2678 67..71 'self': &Self 2636 104..108 'self': &Box<T>
2679 175..179 'self': &Box<T> 2637 188..192 'self': &Box<Foo<T>>
2680 259..263 'self': &Box<Foo<T>> 2638 218..220 '{}': ()
2681 289..291 '{}': () 2639 242..246 'self': &Box<Foo<T>>
2682 313..317 'self': &Box<Foo<T>> 2640 275..277 '{}': ()
2683 346..348 '{}': () 2641 297..301 'self': Box<Foo<T>>
2684 368..372 'self': Box<Foo<T>> 2642 322..324 '{}': ()
2685 393..395 '{}': () 2643 338..559 '{ ...r(); }': ()
2686 409..630 '{ ...r(); }': () 2644 348..353 'boxed': Box<Foo<i32>>
2687 419..424 'boxed': Box<Foo<i32>> 2645 356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>>
2688 427..430 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> 2646 356..371 'Box(Foo(0_i32))': Box<Foo<i32>>
2689 427..442 'Box(Foo(0_i32))': Box<Foo<i32>> 2647 360..363 'Foo': Foo<i32>(i32) -> Foo<i32>
2690 431..434 'Foo': Foo<i32>(i32) -> Foo<i32> 2648 360..370 'Foo(0_i32)': Foo<i32>
2691 431..441 'Foo(0_i32)': Foo<i32> 2649 364..369 '0_i32': i32
2692 435..440 '0_i32': i32 2650 382..386 'bad1': &i32
2693 453..457 'bad1': &i32 2651 389..394 'boxed': Box<Foo<i32>>
2694 460..465 'boxed': Box<Foo<i32>> 2652 389..406 'boxed....nner()': &i32
2695 460..477 'boxed....nner()': &i32 2653 416..421 'good1': &i32
2696 487..492 'good1': &i32 2654 424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32
2697 495..509 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 2655 424..446 'Foo::g...boxed)': &i32
2698 495..517 'Foo::g...boxed)': &i32 2656 439..445 '&boxed': &Box<Foo<i32>>
2699 510..516 '&boxed': &Box<Foo<i32>> 2657 440..445 'boxed': Box<Foo<i32>>
2700 511..516 'boxed': Box<Foo<i32>> 2658 457..461 'bad2': &Foo<i32>
2701 528..532 'bad2': &Foo<i32> 2659 464..469 'boxed': Box<Foo<i32>>
2702 535..540 'boxed': Box<Foo<i32>> 2660 464..480 'boxed....self()': &Foo<i32>
2703 535..551 'boxed....self()': &Foo<i32> 2661 490..495 'good2': &Foo<i32>
2704 561..566 'good2': &Foo<i32> 2662 498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32>
2705 569..582 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> 2663 498..519 'Foo::g...boxed)': &Foo<i32>
2706 569..590 'Foo::g...boxed)': &Foo<i32> 2664 512..518 '&boxed': &Box<Foo<i32>>
2707 583..589 '&boxed': &Box<Foo<i32>> 2665 513..518 'boxed': Box<Foo<i32>>
2708 584..589 'boxed': Box<Foo<i32>> 2666 530..535 'inner': Foo<i32>
2709 601..606 'inner': Foo<i32> 2667 538..543 'boxed': Box<Foo<i32>>
2710 609..614 'boxed': Box<Foo<i32>> 2668 538..556 'boxed....nner()': Foo<i32>
2711 609..627 'boxed....nner()': Foo<i32>
2712 "#]], 2669 "#]],
2713 ); 2670 );
2714} 2671}
@@ -2720,7 +2677,7 @@ fn prelude_2015() {
2720//- /main.rs edition:2015 crate:main deps:core 2677//- /main.rs edition:2015 crate:main deps:core
2721fn f() { 2678fn f() {
2722 Rust; 2679 Rust;
2723 //^ Rust 2680 //^^^^ Rust
2724} 2681}
2725 2682
2726//- /core.rs crate:core 2683//- /core.rs crate:core
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 6bcede4c4..a0ddad570 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1,15 +1,16 @@
1use cov_mark::check;
1use expect_test::expect; 2use expect_test::expect;
2 3
3use super::{check_infer, check_infer_with_mismatches, check_types}; 4use super::{check, check_infer, check_infer_with_mismatches, check_types};
4 5
5#[test] 6#[test]
6fn infer_await() { 7fn infer_await() {
7 check_types( 8 check_types(
8 r#" 9 r#"
9//- /main.rs crate:main deps:core 10//- minicore: future
10struct IntFuture; 11struct IntFuture;
11 12
12impl Future for IntFuture { 13impl core::future::Future for IntFuture {
13 type Output = u64; 14 type Output = u64;
14} 15}
15 16
@@ -18,16 +19,6 @@ fn test() {
18 let v = r.await; 19 let v = r.await;
19 v; 20 v;
20} //^ u64 21} //^ u64
21
22//- /core.rs crate:core
23pub mod prelude {
24 pub mod rust_2018 {
25 #[lang = "future_trait"]
26 pub trait Future {
27 type Output;
28 }
29 }
30}
31"#, 22"#,
32 ); 23 );
33} 24}
@@ -36,25 +27,14 @@ pub mod prelude {
36fn infer_async() { 27fn infer_async() {
37 check_types( 28 check_types(
38 r#" 29 r#"
39//- /main.rs crate:main deps:core 30//- minicore: future
40async fn foo() -> u64 { 31async fn foo() -> u64 { 128 }
41 128
42}
43 32
44fn test() { 33fn test() {
45 let r = foo(); 34 let r = foo();
46 let v = r.await; 35 let v = r.await;
47 v; 36 v;
48} //^ u64 37} //^ u64
49
50//- /core.rs crate:core
51#[prelude_import] use future::*;
52mod future {
53 #[lang = "future_trait"]
54 trait Future {
55 type Output;
56 }
57}
58"#, 38"#,
59 ); 39 );
60} 40}
@@ -63,24 +43,13 @@ mod future {
63fn infer_desugar_async() { 43fn infer_desugar_async() {
64 check_types( 44 check_types(
65 r#" 45 r#"
66//- /main.rs crate:main deps:core 46//- minicore: future
67async fn foo() -> u64 { 47async fn foo() -> u64 { 128 }
68 128
69}
70 48
71fn test() { 49fn test() {
72 let r = foo(); 50 let r = foo();
73 r; 51 r;
74} //^ impl Future<Output = u64> 52} //^ impl Future<Output = u64>
75
76//- /core.rs crate:core
77#[prelude_import] use future::*;
78mod future {
79 trait Future {
80 type Output;
81 }
82}
83
84"#, 53"#,
85 ); 54 );
86} 55}
@@ -89,7 +58,7 @@ mod future {
89fn infer_async_block() { 58fn infer_async_block() {
90 check_types( 59 check_types(
91 r#" 60 r#"
92//- /main.rs crate:main deps:core 61//- minicore: future, option
93async fn test() { 62async fn test() {
94 let a = async { 42 }; 63 let a = async { 42 };
95 a; 64 a;
@@ -101,7 +70,7 @@ async fn test() {
101 b; 70 b;
102// ^ () 71// ^ ()
103 let c = async { 72 let c = async {
104 let y = Option::None; 73 let y = None;
105 y 74 y
106 // ^ Option<u64> 75 // ^ Option<u64>
107 }; 76 };
@@ -109,18 +78,6 @@ async fn test() {
109 c; 78 c;
110// ^ impl Future<Output = Option<u64>> 79// ^ impl Future<Output = Option<u64>>
111} 80}
112
113enum Option<T> { None, Some(T) }
114
115//- /core.rs crate:core
116#[prelude_import] use future::*;
117mod future {
118 #[lang = "future_trait"]
119 trait Future {
120 type Output;
121 }
122}
123
124"#, 81"#,
125 ); 82 );
126} 83}
@@ -329,7 +286,7 @@ mod ops {
329 286
330#[test] 287#[test]
331fn infer_from_bound_1() { 288fn infer_from_bound_1() {
332 check_infer( 289 check_types(
333 r#" 290 r#"
334trait Trait<T> {} 291trait Trait<T> {}
335struct S<T>(T); 292struct S<T>(T);
@@ -337,99 +294,62 @@ impl<U> Trait<U> for S<U> {}
337fn foo<T: Trait<u32>>(t: T) {} 294fn foo<T: Trait<u32>>(t: T) {}
338fn test() { 295fn test() {
339 let s = S(unknown); 296 let s = S(unknown);
297 // ^^^^^^^ u32
340 foo(s); 298 foo(s);
341}"#, 299}"#,
342 expect![[r#"
343 85..86 't': T
344 91..93 '{}': ()
345 104..143 '{ ...(s); }': ()
346 114..115 's': S<u32>
347 118..119 'S': S<u32>(u32) -> S<u32>
348 118..128 'S(unknown)': S<u32>
349 120..127 'unknown': u32
350 134..137 'foo': fn foo<S<u32>>(S<u32>)
351 134..140 'foo(s)': ()
352 138..139 's': S<u32>
353 "#]],
354 ); 300 );
355} 301}
356 302
357#[test] 303#[test]
358fn infer_from_bound_2() { 304fn infer_from_bound_2() {
359 check_infer( 305 check_types(
360 r#" 306 r#"
361trait Trait<T> {} 307trait Trait<T> {}
362struct S<T>(T); 308struct S<T>(T);
363impl<U> Trait<U> for S<U> {} 309impl<U> Trait<U> for S<U> {}
364fn foo<U, T: Trait<U>>(t: T) -> U {} 310fn foo<U, T: Trait<U>>(t: T) -> U { loop {} }
365fn test() { 311fn test() {
366 let s = S(unknown); 312 let s = S(unknown);
313 // ^^^^^^^ u32
367 let x: u32 = foo(s); 314 let x: u32 = foo(s);
368}"#, 315}"#,
369 expect![[r#"
370 86..87 't': T
371 97..99 '{}': ()
372 110..162 '{ ...(s); }': ()
373 120..121 's': S<u32>
374 124..125 'S': S<u32>(u32) -> S<u32>
375 124..134 'S(unknown)': S<u32>
376 126..133 'unknown': u32
377 144..145 'x': u32
378 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32
379 153..159 'foo(s)': u32
380 157..158 's': S<u32>
381 "#]],
382 ); 316 );
383} 317}
384 318
385#[test] 319#[test]
386fn trait_default_method_self_bound_implements_trait() { 320fn trait_default_method_self_bound_implements_trait() {
387 cov_mark::check!(trait_self_implements_self); 321 cov_mark::check!(trait_self_implements_self);
388 check_infer( 322 check(
389 r#" 323 r#"
390trait Trait { 324trait Trait {
391 fn foo(&self) -> i64; 325 fn foo(&self) -> i64;
392 fn bar(&self) -> { 326 fn bar(&self) -> () {
393 let x = self.foo(); 327 self.foo();
328 // ^^^^^^^^^^ type: i64
394 } 329 }
395}"#, 330}"#,
396 expect![[r#"
397 26..30 'self': &Self
398 52..56 'self': &Self
399 61..96 '{ ... }': ()
400 75..76 'x': i64
401 79..83 'self': &Self
402 79..89 'self.foo()': i64
403 "#]],
404 ); 331 );
405} 332}
406 333
407#[test] 334#[test]
408fn trait_default_method_self_bound_implements_super_trait() { 335fn trait_default_method_self_bound_implements_super_trait() {
409 check_infer( 336 check(
410 r#" 337 r#"
411trait SuperTrait { 338trait SuperTrait {
412 fn foo(&self) -> i64; 339 fn foo(&self) -> i64;
413} 340}
414trait Trait: SuperTrait { 341trait Trait: SuperTrait {
415 fn bar(&self) -> { 342 fn bar(&self) -> () {
416 let x = self.foo(); 343 self.foo();
344 // ^^^^^^^^^^ type: i64
417 } 345 }
418}"#, 346}"#,
419 expect![[r#"
420 31..35 'self': &Self
421 85..89 'self': &Self
422 94..129 '{ ... }': ()
423 108..109 'x': i64
424 112..116 'self': &Self
425 112..122 'self.foo()': i64
426 "#]],
427 ); 347 );
428} 348}
429 349
430#[test] 350#[test]
431fn infer_project_associated_type() { 351fn infer_project_associated_type() {
432 check_infer( 352 check_types(
433 r#" 353 r#"
434trait Iterable { 354trait Iterable {
435 type Item; 355 type Item;
@@ -438,89 +358,62 @@ struct S;
438impl Iterable for S { type Item = u32; } 358impl Iterable for S { type Item = u32; }
439fn test<T: Iterable>() { 359fn test<T: Iterable>() {
440 let x: <S as Iterable>::Item = 1; 360 let x: <S as Iterable>::Item = 1;
441 let y: <T as Iterable>::Item = no_matter; 361 // ^ u32
442 let z: T::Item = no_matter; 362 let y: <T as Iterable>::Item = u;
443 let a: <T>::Item = no_matter; 363 // ^ Iterable::Item<T>
364 let z: T::Item = u;
365 // ^ Iterable::Item<T>
366 let a: <T>::Item = u;
367 // ^ Iterable::Item<T>
444}"#, 368}"#,
445 expect![[r#"
446 108..261 '{ ...ter; }': ()
447 118..119 'x': u32
448 145..146 '1': u32
449 156..157 'y': Iterable::Item<T>
450 183..192 'no_matter': Iterable::Item<T>
451 202..203 'z': Iterable::Item<T>
452 215..224 'no_matter': Iterable::Item<T>
453 234..235 'a': Iterable::Item<T>
454 249..258 'no_matter': Iterable::Item<T>
455 "#]],
456 ); 369 );
457} 370}
458 371
459#[test] 372#[test]
460fn infer_return_associated_type() { 373fn infer_return_associated_type() {
461 check_infer( 374 check_types(
462 r#" 375 r#"
463trait Iterable { 376trait Iterable {
464 type Item; 377 type Item;
465} 378}
466struct S; 379struct S;
467impl Iterable for S { type Item = u32; } 380impl Iterable for S { type Item = u32; }
468fn foo1<T: Iterable>(t: T) -> T::Item {} 381fn foo1<T: Iterable>(t: T) -> T::Item { loop {} }
469fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} 382fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} }
470fn foo3<T: Iterable>(t: T) -> <T>::Item {} 383fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} }
471fn test() { 384fn test() {
472 let x = foo1(S); 385 foo1(S);
473 let y = foo2(S); 386 // ^^^^^^^ u32
474 let z = foo3(S); 387 foo2(S);
388 // ^^^^^^^ u32
389 foo3(S);
390 // ^^^^^^^ u32
475}"#, 391}"#,
476 expect![[r#"
477 106..107 't': T
478 123..125 '{}': ()
479 147..148 't': T
480 178..180 '{}': ()
481 202..203 't': T
482 221..223 '{}': ()
483 234..300 '{ ...(S); }': ()
484 244..245 'x': u32
485 248..252 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item
486 248..255 'foo1(S)': u32
487 253..254 'S': S
488 265..266 'y': u32
489 269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item
490 269..276 'foo2(S)': u32
491 274..275 'S': S
492 286..287 'z': u32
493 290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item
494 290..297 'foo3(S)': u32
495 295..296 'S': S
496 "#]],
497 ); 392 );
498} 393}
499 394
500#[test] 395#[test]
501fn infer_associated_type_bound() { 396fn infer_associated_type_bound() {
502 check_infer( 397 check_types(
503 r#" 398 r#"
504trait Iterable { 399trait Iterable {
505 type Item; 400 type Item;
506} 401}
507fn test<T: Iterable<Item=u32>>() { 402fn test<T: Iterable<Item=u32>>() {
508 let y: T::Item = unknown; 403 let y: T::Item = unknown;
404 // ^^^^^^^ u32
509}"#, 405}"#,
510 expect![[r#"
511 67..100 '{ ...own; }': ()
512 77..78 'y': u32
513 90..97 'unknown': u32
514 "#]],
515 ); 406 );
516} 407}
517 408
518#[test] 409#[test]
519fn infer_const_body() { 410fn infer_const_body() {
411 // FIXME make check_types work with other bodies
520 check_infer( 412 check_infer(
521 r#" 413 r#"
522const A: u32 = 1 + 1; 414const A: u32 = 1 + 1;
523static B: u64 = { let x = 1; x };"#, 415static B: u64 = { let x = 1; x };
416"#,
524 expect![[r#" 417 expect![[r#"
525 15..16 '1': u32 418 15..16 '1': u32
526 15..20 '1 + 1': u32 419 15..20 '1 + 1': u32
@@ -611,11 +504,11 @@ fn indexing_arrays() {
611fn infer_ops_index() { 504fn infer_ops_index() {
612 check_types( 505 check_types(
613 r#" 506 r#"
614//- /main.rs crate:main deps:std 507//- minicore: index
615struct Bar; 508struct Bar;
616struct Foo; 509struct Foo;
617 510
618impl std::ops::Index<u32> for Bar { 511impl core::ops::Index<u32> for Bar {
619 type Output = Foo; 512 type Output = Foo;
620} 513}
621 514
@@ -624,15 +517,6 @@ fn test() {
624 let b = a[1u32]; 517 let b = a[1u32];
625 b; 518 b;
626} //^ Foo 519} //^ Foo
627
628//- /std.rs crate:std
629#[prelude_import] use ops::*;
630mod ops {
631 #[lang = "index"]
632 pub trait Index<Idx> {
633 type Output;
634 }
635}
636"#, 520"#,
637 ); 521 );
638} 522}
@@ -641,16 +525,16 @@ mod ops {
641fn infer_ops_index_int() { 525fn infer_ops_index_int() {
642 check_types( 526 check_types(
643 r#" 527 r#"
644//- /main.rs crate:main deps:std 528//- minicore: index
645struct Bar; 529struct Bar;
646struct Foo; 530struct Foo;
647 531
648impl std::ops::Index<u32> for Bar { 532impl core::ops::Index<u32> for Bar {
649 type Output = Foo; 533 type Output = Foo;
650} 534}
651 535
652struct Range; 536struct Range;
653impl std::ops::Index<Range> for Bar { 537impl core::ops::Index<Range> for Bar {
654 type Output = Bar; 538 type Output = Bar;
655} 539}
656 540
@@ -660,15 +544,6 @@ fn test() {
660 b; 544 b;
661 //^ Foo 545 //^ Foo
662} 546}
663
664//- /std.rs crate:std
665#[prelude_import] use ops::*;
666mod ops {
667 #[lang = "index"]
668 pub trait Index<Idx> {
669 type Output;
670 }
671}
672"#, 547"#,
673 ); 548 );
674} 549}
@@ -677,25 +552,12 @@ mod ops {
677fn infer_ops_index_autoderef() { 552fn infer_ops_index_autoderef() {
678 check_types( 553 check_types(
679 r#" 554 r#"
680//- /main.rs crate:main deps:std 555//- minicore: index, slice
681fn test() { 556fn test() {
682 let a = &[1u32, 2, 3]; 557 let a = &[1u32, 2, 3];
683 let b = a[1u32]; 558 let b = a[1];
684 b; 559 b;
685} //^ u32 560} //^ u32
686
687//- /std.rs crate:std
688impl<T> ops::Index<u32> for [T] {
689 type Output = T;
690}
691
692#[prelude_import] use ops::*;
693mod ops {
694 #[lang = "index"]
695 pub trait Index<Idx> {
696 type Output;
697 }
698}
699"#, 561"#,
700 ); 562 );
701} 563}
@@ -704,25 +566,20 @@ mod ops {
704fn deref_trait() { 566fn deref_trait() {
705 check_types( 567 check_types(
706 r#" 568 r#"
707#[lang = "deref"] 569//- minicore: deref
708trait Deref {
709 type Target;
710 fn deref(&self) -> &Self::Target;
711}
712
713struct Arc<T>; 570struct Arc<T>;
714impl<T> Deref for Arc<T> { 571impl<T> core::ops::Deref for Arc<T> {
715 type Target = T; 572 type Target = T;
716} 573}
717 574
718struct S; 575struct S;
719impl S { 576impl S {
720 fn foo(&self) -> u128 {} 577 fn foo(&self) -> u128 { 0 }
721} 578}
722 579
723fn test(s: Arc<S>) { 580fn test(s: Arc<S>) {
724 (*s, s.foo()); 581 (*s, s.foo());
725} //^ (S, u128) 582} //^^^^^^^^^^^^^ (S, u128)
726"#, 583"#,
727 ); 584 );
728} 585}
@@ -731,16 +588,10 @@ fn test(s: Arc<S>) {
731fn deref_trait_with_inference_var() { 588fn deref_trait_with_inference_var() {
732 check_types( 589 check_types(
733 r#" 590 r#"
734//- /main.rs 591//- minicore: deref
735#[lang = "deref"]
736trait Deref {
737 type Target;
738 fn deref(&self) -> &Self::Target;
739}
740
741struct Arc<T>; 592struct Arc<T>;
742fn new_arc<T>() -> Arc<T> {} 593fn new_arc<T>() -> Arc<T> { Arc }
743impl<T> Deref for Arc<T> { 594impl<T> core::ops::Deref for Arc<T> {
744 type Target = T; 595 type Target = T;
745} 596}
746 597
@@ -749,8 +600,8 @@ fn foo(a: Arc<S>) {}
749 600
750fn test() { 601fn test() {
751 let a = new_arc(); 602 let a = new_arc();
752 let b = (*a); 603 let b = *a;
753 //^ S 604 //^^ S
754 foo(a); 605 foo(a);
755} 606}
756"#, 607"#,
@@ -761,21 +612,16 @@ fn test() {
761fn deref_trait_infinite_recursion() { 612fn deref_trait_infinite_recursion() {
762 check_types( 613 check_types(
763 r#" 614 r#"
764#[lang = "deref"] 615//- minicore: deref
765trait Deref {
766 type Target;
767 fn deref(&self) -> &Self::Target;
768}
769
770struct S; 616struct S;
771 617
772impl Deref for S { 618impl core::ops::Deref for S {
773 type Target = S; 619 type Target = S;
774} 620}
775 621
776fn test(s: S) { 622fn test(s: S) {
777 s.foo(); 623 s.foo();
778} //^ {unknown} 624} //^^^^^^^ {unknown}
779"#, 625"#,
780 ); 626 );
781} 627}
@@ -784,25 +630,20 @@ fn test(s: S) {
784fn deref_trait_with_question_mark_size() { 630fn deref_trait_with_question_mark_size() {
785 check_types( 631 check_types(
786 r#" 632 r#"
787#[lang = "deref"] 633//- minicore: deref
788trait Deref {
789 type Target;
790 fn deref(&self) -> &Self::Target;
791}
792
793struct Arc<T>; 634struct Arc<T>;
794impl<T> Deref for Arc<T> { 635impl<T: ?Sized> core::ops::Deref for Arc<T> {
795 type Target = T; 636 type Target = T;
796} 637}
797 638
798struct S; 639struct S;
799impl S { 640impl S {
800 fn foo(&self) -> u128 {} 641 fn foo(&self) -> u128 { 0 }
801} 642}
802 643
803fn test(s: Arc<S>) { 644fn test(s: Arc<S>) {
804 (*s, s.foo()); 645 (*s, s.foo());
805} //^ (S, u128) 646} //^^^^^^^^^^^^^ (S, u128)
806"#, 647"#,
807 ); 648 );
808} 649}
@@ -816,11 +657,11 @@ struct S;
816trait Trait<T> {} 657trait Trait<T> {}
817impl Trait<u32> for S {} 658impl Trait<u32> for S {}
818 659
819fn foo<T: Trait<U>, U>(t: T) -> U {} 660fn foo<T: Trait<U>, U>(t: T) -> U { loop {} }
820 661
821fn test(s: S) { 662fn test(s: S) {
822 (foo(s)); 663 foo(s);
823} //^ u32 664} //^^^^^^ u32
824"#, 665"#,
825 ); 666 );
826} 667}
@@ -837,12 +678,12 @@ impl Trait<isize> for S {}
837 678
838struct O; 679struct O;
839impl O { 680impl O {
840 fn foo<T: Trait<U>, U>(&self, t: T) -> U {} 681 fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} }
841} 682}
842 683
843fn test() { 684fn test() {
844 O.foo(S); 685 O.foo(S);
845} //^ isize 686} //^^^^^^^^ isize
846"#, 687"#,
847 ); 688 );
848} 689}
@@ -857,12 +698,12 @@ trait Trait<T> {}
857impl Trait<i64> for S {} 698impl Trait<i64> for S {}
858 699
859impl S { 700impl S {
860 fn foo<U>(&self) -> U where Self: Trait<U> {} 701 fn foo<U>(&self) -> U where Self: Trait<U> { loop {} }
861} 702}
862 703
863fn test() { 704fn test() {
864 S.foo(); 705 S.foo();
865} //^ i64 706} //^^^^^^^ i64
866"#, 707"#,
867 ); 708 );
868} 709}
@@ -878,12 +719,12 @@ impl Trait<&str> for S {}
878 719
879struct O<T>; 720struct O<T>;
880impl<U, T: Trait<U>> O<T> { 721impl<U, T: Trait<U>> O<T> {
881 fn foo(&self) -> U {} 722 fn foo(&self) -> U { loop {} }
882} 723}
883 724
884fn test(o: O<S>) { 725fn test(o: O<S>) {
885 o.foo(); 726 o.foo();
886} //^ &str 727} //^^^^^^^ &str
887"#, 728"#,
888 ); 729 );
889} 730}
@@ -898,7 +739,7 @@ struct S;
898impl Clone for S {} 739impl Clone for S {}
899impl<T> Trait for T where T: Clone {} 740impl<T> Trait for T where T: Clone {}
900fn test<T: Clone>(t: T) { t.foo(); } 741fn test<T: Clone>(t: T) { t.foo(); }
901 //^ u128 742 //^^^^^^^ u128
902"#, 743"#,
903 ); 744 );
904} 745}
@@ -914,7 +755,7 @@ struct S;
914impl Clone for S {} 755impl Clone for S {}
915impl<T> Trait for T where T: Clone {} 756impl<T> Trait for T where T: Clone {}
916fn test<T>(t: T) { t.foo(); } 757fn test<T>(t: T) { t.foo(); }
917 //^ {unknown} 758 //^^^^^^^ {unknown}
918"#, 759"#,
919 ); 760 );
920} 761}
@@ -927,7 +768,7 @@ trait Trait { fn foo(self) -> u128; }
927struct S; 768struct S;
928impl Trait for S {} 769impl Trait for S {}
929fn test<T: Trait>(t: T) { t.foo(); } 770fn test<T: Trait>(t: T) { t.foo(); }
930 //^ u128 771 //^^^^^^^ u128
931"#, 772"#,
932 ); 773 );
933} 774}
@@ -940,7 +781,7 @@ trait Trait { fn foo(self) -> u128; }
940struct S; 781struct S;
941impl Trait for S {} 782impl Trait for S {}
942fn test<T>(t: T) { t.foo(); } 783fn test<T>(t: T) { t.foo(); }
943 //^ {unknown} 784 //^^^^^^^ {unknown}
944"#, 785"#,
945 ); 786 );
946} 787}
@@ -949,16 +790,13 @@ fn test<T>(t: T) { t.foo(); }
949fn generic_param_env_deref() { 790fn generic_param_env_deref() {
950 check_types( 791 check_types(
951 r#" 792 r#"
952#[lang = "deref"] 793//- minicore: deref
953trait Deref {
954 type Target;
955}
956trait Trait {} 794trait Trait {}
957impl<T> Deref for T where T: Trait { 795impl<T> core::ops::Deref for T where T: Trait {
958 type Target = i128; 796 type Target = i128;
959} 797}
960fn test<T: Trait>(t: T) { (*t); } 798fn test<T: Trait>(t: T) { *t; }
961 //^ i128 799 //^^ i128
962"#, 800"#,
963 ); 801 );
964} 802}
@@ -1475,17 +1313,16 @@ fn test(
1475} 1313}
1476 1314
1477#[test] 1315#[test]
1478#[ignore]
1479fn error_bound_chalk() { 1316fn error_bound_chalk() {
1480 check_types( 1317 check_types(
1481 r#" 1318 r#"
1482trait Trait { 1319trait Trait {
1483 fn foo(&self) -> u32 {} 1320 fn foo(&self) -> u32 { 0 }
1484} 1321}
1485 1322
1486fn test(x: (impl Trait + UnknownTrait)) { 1323fn test(x: (impl Trait + UnknownTrait)) {
1487 x.foo(); 1324 x.foo();
1488} //^ u32 1325} //^^^^^^^ u32
1489"#, 1326"#,
1490 ); 1327 );
1491} 1328}
@@ -1558,7 +1395,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
1558fn impl_trait_assoc_binding_projection_bug() { 1395fn impl_trait_assoc_binding_projection_bug() {
1559 check_types( 1396 check_types(
1560 r#" 1397 r#"
1561//- /main.rs crate:main deps:std 1398//- minicore: iterator
1562pub trait Language { 1399pub trait Language {
1563 type Kind; 1400 type Kind;
1564} 1401}
@@ -1576,21 +1413,7 @@ trait Clone {
1576fn api_walkthrough() { 1413fn api_walkthrough() {
1577 for node in foo() { 1414 for node in foo() {
1578 node.clone(); 1415 node.clone();
1579 } //^ {unknown} 1416 } //^^^^^^^^^^^^ {unknown}
1580}
1581
1582//- /std.rs crate:std
1583#[prelude_import] use iter::*;
1584mod iter {
1585 trait IntoIterator {
1586 type Item;
1587 }
1588 trait Iterator {
1589 type Item;
1590 }
1591 impl<T: Iterator> IntoIterator for T {
1592 type Item = <T as Iterator>::Item;
1593 }
1594} 1417}
1595"#, 1418"#,
1596 ); 1419 );
@@ -1627,13 +1450,13 @@ fn where_clause_trait_in_scope_for_method_resolution() {
1627 r#" 1450 r#"
1628mod foo { 1451mod foo {
1629 trait Trait { 1452 trait Trait {
1630 fn foo(&self) -> u32 {} 1453 fn foo(&self) -> u32 { 0 }
1631 } 1454 }
1632} 1455}
1633 1456
1634fn test<T: foo::Trait>(x: T) { 1457fn test<T: foo::Trait>(x: T) {
1635 x.foo(); 1458 x.foo();
1636} //^ u32 1459} //^^^^^^^ u32
1637"#, 1460"#,
1638 ); 1461 );
1639} 1462}
@@ -1838,20 +1661,7 @@ fn test() {
1838fn fn_trait_deref_with_ty_default() { 1661fn fn_trait_deref_with_ty_default() {
1839 check_infer( 1662 check_infer(
1840 r#" 1663 r#"
1841#[lang = "deref"] 1664//- minicore: deref, fn
1842trait Deref {
1843 type Target;
1844
1845 fn deref(&self) -> &Self::Target;
1846}
1847
1848#[lang="fn_once"]
1849trait FnOnce<Args> {
1850 type Output;
1851
1852 fn call_once(self, args: Args) -> Self::Output;
1853}
1854
1855struct Foo; 1665struct Foo;
1856 1666
1857impl Foo { 1667impl Foo {
@@ -1864,7 +1674,7 @@ impl<T, F> Lazy<T, F> {
1864 pub fn new(f: F) -> Lazy<T, F> {} 1674 pub fn new(f: F) -> Lazy<T, F> {}
1865} 1675}
1866 1676
1867impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { 1677impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> {
1868 type Target = T; 1678 type Target = T;
1869} 1679}
1870 1680
@@ -1878,32 +1688,29 @@ fn test() {
1878 let r2 = lazy2.foo(); 1688 let r2 = lazy2.foo();
1879}"#, 1689}"#,
1880 expect![[r#" 1690 expect![[r#"
1881 64..68 'self': &Self 1691 36..40 'self': &Foo
1882 165..169 'self': Self 1692 51..53 '{}': ()
1883 171..175 'args': Args 1693 131..132 'f': F
1884 239..243 'self': &Foo 1694 151..153 '{}': ()
1885 254..256 '{}': () 1695 251..497 '{ ...o(); }': ()
1886 334..335 'f': F 1696 261..266 'lazy1': Lazy<Foo, || -> Foo>
1887 354..356 '{}': () 1697 283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
1888 443..689 '{ ...o(); }': () 1698 283..300 'Lazy::...| Foo)': Lazy<Foo, || -> Foo>
1889 453..458 'lazy1': Lazy<Foo, || -> Foo> 1699 293..299 '|| Foo': || -> Foo
1890 475..484 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> 1700 296..299 'Foo': Foo
1891 475..492 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> 1701 310..312 'r1': usize
1892 485..491 '|| Foo': || -> Foo 1702 315..320 'lazy1': Lazy<Foo, || -> Foo>
1893 488..491 'Foo': Foo 1703 315..326 'lazy1.foo()': usize
1894 502..504 'r1': usize 1704 368..383 'make_foo_fn_ptr': fn() -> Foo
1895 507..512 'lazy1': Lazy<Foo, || -> Foo> 1705 399..410 'make_foo_fn': fn make_foo_fn() -> Foo
1896 507..518 'lazy1.foo()': usize 1706 420..425 'lazy2': Lazy<Foo, fn() -> Foo>
1897 560..575 'make_foo_fn_ptr': fn() -> Foo 1707 442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo>
1898 591..602 'make_foo_fn': fn make_foo_fn() -> Foo 1708 442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo>
1899 612..617 'lazy2': Lazy<Foo, fn() -> Foo> 1709 452..467 'make_foo_fn_ptr': fn() -> Foo
1900 634..643 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> 1710 478..480 'r2': usize
1901 634..660 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> 1711 483..488 'lazy2': Lazy<Foo, fn() -> Foo>
1902 644..659 'make_foo_fn_ptr': fn() -> Foo 1712 483..494 'lazy2.foo()': usize
1903 670..672 'r2': usize 1713 357..359 '{}': ()
1904 675..680 'lazy2': Lazy<Foo, fn() -> Foo>
1905 675..686 'lazy2.foo()': usize
1906 549..551 '{}': ()
1907 "#]], 1714 "#]],
1908 ); 1715 );
1909} 1716}
@@ -1912,11 +1719,7 @@ fn test() {
1912fn closure_1() { 1719fn closure_1() {
1913 check_infer_with_mismatches( 1720 check_infer_with_mismatches(
1914 r#" 1721 r#"
1915#[lang = "fn_once"] 1722//- minicore: fn
1916trait FnOnce<Args> {
1917 type Output;
1918}
1919
1920enum Option<T> { Some(T), None } 1723enum Option<T> { Some(T), None }
1921impl<T> Option<T> { 1724impl<T> Option<T> {
1922 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } 1725 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
@@ -1929,34 +1732,34 @@ fn test() {
1929 let y: Option<i64> = x.map(|_v| 1); 1732 let y: Option<i64> = x.map(|_v| 1);
1930}"#, 1733}"#,
1931 expect![[r#" 1734 expect![[r#"
1932 147..151 'self': Option<T> 1735 86..90 'self': Option<T>
1933 153..154 'f': F 1736 92..93 'f': F
1934 172..183 '{ loop {} }': Option<U> 1737 111..122 '{ loop {} }': Option<U>
1935 174..181 'loop {}': ! 1738 113..120 'loop {}': !
1936 179..181 '{}': () 1739 118..120 '{}': ()
1937 197..316 '{ ... 1); }': () 1740 136..255 '{ ... 1); }': ()
1938 207..208 'x': Option<u32> 1741 146..147 'x': Option<u32>
1939 211..223 'Option::Some': Some<u32>(u32) -> Option<u32> 1742 150..162 'Option::Some': Some<u32>(u32) -> Option<u32>
1940 211..229 'Option...(1u32)': Option<u32> 1743 150..168 'Option...(1u32)': Option<u32>
1941 224..228 '1u32': u32 1744 163..167 '1u32': u32
1942 235..236 'x': Option<u32> 1745 174..175 'x': Option<u32>
1943 235..251 'x.map(...v + 1)': Option<u32> 1746 174..190 'x.map(...v + 1)': Option<u32>
1944 241..250 '|v| v + 1': |u32| -> u32 1747 180..189 '|v| v + 1': |u32| -> u32
1945 242..243 'v': u32 1748 181..182 'v': u32
1946 245..246 'v': u32 1749 184..185 'v': u32
1947 245..250 'v + 1': u32 1750 184..189 'v + 1': u32
1948 249..250 '1': u32 1751 188..189 '1': u32
1949 257..258 'x': Option<u32> 1752 196..197 'x': Option<u32>
1950 257..273 'x.map(... 1u64)': Option<u64> 1753 196..212 'x.map(... 1u64)': Option<u64>
1951 263..272 '|_v| 1u64': |u32| -> u64 1754 202..211 '|_v| 1u64': |u32| -> u64
1952 264..266 '_v': u32 1755 203..205 '_v': u32
1953 268..272 '1u64': u64 1756 207..211 '1u64': u64
1954 283..284 'y': Option<i64> 1757 222..223 'y': Option<i64>
1955 300..301 'x': Option<u32> 1758 239..240 'x': Option<u32>
1956 300..313 'x.map(|_v| 1)': Option<i64> 1759 239..252 'x.map(|_v| 1)': Option<i64>
1957 306..312 '|_v| 1': |u32| -> i64 1760 245..251 '|_v| 1': |u32| -> i64
1958 307..309 '_v': u32 1761 246..248 '_v': u32
1959 311..312 '1': i64 1762 250..251 '1': i64
1960 "#]], 1763 "#]],
1961 ); 1764 );
1962} 1765}
@@ -2030,11 +1833,7 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
2030fn closure_as_argument_inference_order() { 1833fn closure_as_argument_inference_order() {
2031 check_infer_with_mismatches( 1834 check_infer_with_mismatches(
2032 r#" 1835 r#"
2033#[lang = "fn_once"] 1836//- minicore: fn
2034trait FnOnce<Args> {
2035 type Output;
2036}
2037
2038fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } 1837fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
2039fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } 1838fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
2040 1839
@@ -2053,62 +1852,62 @@ fn test() {
2053 let x4 = S.foo2(|s| s.method(), S); 1852 let x4 = S.foo2(|s| s.method(), S);
2054}"#, 1853}"#,
2055 expect![[r#" 1854 expect![[r#"
2056 94..95 'x': T 1855 33..34 'x': T
2057 100..101 'f': F 1856 39..40 'f': F
2058 111..122 '{ loop {} }': U 1857 50..61 '{ loop {} }': U
2059 113..120 'loop {}': ! 1858 52..59 'loop {}': !
2060 118..120 '{}': () 1859 57..59 '{}': ()
2061 156..157 'f': F 1860 95..96 'f': F
2062 162..163 'x': T 1861 101..102 'x': T
2063 173..184 '{ loop {} }': U 1862 112..123 '{ loop {} }': U
2064 175..182 'loop {}': ! 1863 114..121 'loop {}': !
2065 180..182 '{}': () 1864 119..121 '{}': ()
2066 219..223 'self': S 1865 158..162 'self': S
2067 271..275 'self': S 1866 210..214 'self': S
2068 277..278 'x': T 1867 216..217 'x': T
2069 283..284 'f': F 1868 222..223 'f': F
2070 294..305 '{ loop {} }': U 1869 233..244 '{ loop {} }': U
2071 296..303 'loop {}': ! 1870 235..242 'loop {}': !
2072 301..303 '{}': () 1871 240..242 '{}': ()
2073 343..347 'self': S 1872 282..286 'self': S
2074 349..350 'f': F 1873 288..289 'f': F
2075 355..356 'x': T 1874 294..295 'x': T
2076 366..377 '{ loop {} }': U 1875 305..316 '{ loop {} }': U
2077 368..375 'loop {}': ! 1876 307..314 'loop {}': !
2078 373..375 '{}': () 1877 312..314 '{}': ()
2079 391..550 '{ ... S); }': () 1878 330..489 '{ ... S); }': ()
2080 401..403 'x1': u64 1879 340..342 'x1': u64
2081 406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 1880 345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
2082 406..429 'foo1(S...hod())': u64 1881 345..368 'foo1(S...hod())': u64
2083 411..412 'S': S 1882 350..351 'S': S
2084 414..428 '|s| s.method()': |S| -> u64 1883 353..367 '|s| s.method()': |S| -> u64
2085 415..416 's': S 1884 354..355 's': S
2086 418..419 's': S 1885 357..358 's': S
2087 418..428 's.method()': u64 1886 357..367 's.method()': u64
2088 439..441 'x2': u64 1887 378..380 'x2': u64
2089 444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 1888 383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
2090 444..467 'foo2(|...(), S)': u64 1889 383..406 'foo2(|...(), S)': u64
2091 449..463 '|s| s.method()': |S| -> u64 1890 388..402 '|s| s.method()': |S| -> u64
2092 450..451 's': S 1891 389..390 's': S
2093 453..454 's': S 1892 392..393 's': S
2094 453..463 's.method()': u64 1893 392..402 's.method()': u64
2095 465..466 'S': S 1894 404..405 'S': S
2096 477..479 'x3': u64 1895 416..418 'x3': u64
2097 482..483 'S': S 1896 421..422 'S': S
2098 482..507 'S.foo1...hod())': u64 1897 421..446 'S.foo1...hod())': u64
2099 489..490 'S': S 1898 428..429 'S': S
2100 492..506 '|s| s.method()': |S| -> u64 1899 431..445 '|s| s.method()': |S| -> u64
2101 493..494 's': S 1900 432..433 's': S
2102 496..497 's': S 1901 435..436 's': S
2103 496..506 's.method()': u64 1902 435..445 's.method()': u64
2104 517..519 'x4': u64 1903 456..458 'x4': u64
2105 522..523 'S': S 1904 461..462 'S': S
2106 522..547 'S.foo2...(), S)': u64 1905 461..486 'S.foo2...(), S)': u64
2107 529..543 '|s| s.method()': |S| -> u64 1906 468..482 '|s| s.method()': |S| -> u64
2108 530..531 's': S 1907 469..470 's': S
2109 533..534 's': S 1908 472..473 's': S
2110 533..543 's.method()': u64 1909 472..482 's.method()': u64
2111 545..546 'S': S 1910 484..485 'S': S
2112 "#]], 1911 "#]],
2113 ); 1912 );
2114} 1913}
@@ -2117,14 +1916,10 @@ fn test() {
2117fn fn_item_fn_trait() { 1916fn fn_item_fn_trait() {
2118 check_types( 1917 check_types(
2119 r#" 1918 r#"
2120#[lang = "fn_once"] 1919//- minicore: fn
2121trait FnOnce<Args> {
2122 type Output;
2123}
2124
2125struct S; 1920struct S;
2126 1921
2127fn foo() -> S {} 1922fn foo() -> S { S }
2128 1923
2129fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } 1924fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() }
2130 1925
@@ -2151,7 +1946,7 @@ trait Trait2 {
2151fn test<T: Trait>() where T::Item: Trait2 { 1946fn test<T: Trait>() where T::Item: Trait2 {
2152 let x: T::Item = no_matter; 1947 let x: T::Item = no_matter;
2153 x.foo(); 1948 x.foo();
2154} //^ u32 1949} //^^^^^^^ u32
2155"#, 1950"#,
2156 ); 1951 );
2157} 1952}
@@ -2171,7 +1966,7 @@ trait Trait2 {
2171fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { 1966fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
2172 let x: T::Item = no_matter; 1967 let x: T::Item = no_matter;
2173 x.foo(); 1968 x.foo();
2174} //^ u32 1969} //^^^^^^^ u32
2175"#, 1970"#,
2176 ); 1971 );
2177} 1972}
@@ -2234,7 +2029,7 @@ impl Trait for S {
2234 2029
2235fn test() { 2030fn test() {
2236 S.f(); 2031 S.f();
2237} //^ u32 2032} //^^^^^ u32
2238"#, 2033"#,
2239 ); 2034 );
2240} 2035}
@@ -2262,7 +2057,7 @@ where
2262 2057
2263fn foo<I: Interner>(interner: &I, t: Ty<I>) { 2058fn foo<I: Interner>(interner: &I, t: Ty<I>) {
2264 fold(interner, t); 2059 fold(interner, t);
2265} //^ Ty<I> 2060} //^^^^^^^^^^^^^^^^^ Ty<I>
2266"#, 2061"#,
2267 ); 2062 );
2268} 2063}
@@ -2281,7 +2076,7 @@ impl Trait<Self> for S {}
2281 2076
2282fn test() { 2077fn test() {
2283 S.foo(); 2078 S.foo();
2284} //^ () 2079} //^^^^^^^ ()
2285"#, 2080"#,
2286 ); 2081 );
2287} 2082}
@@ -2300,7 +2095,7 @@ impl Trait for S<Self> {}
2300 2095
2301fn test() { 2096fn test() {
2302 S.foo(); 2097 S.foo();
2303} //^ {unknown} 2098} //^^^^^^^ {unknown}
2304"#, 2099"#,
2305 ); 2100 );
2306} 2101}
@@ -2318,7 +2113,7 @@ trait Trait2<T> {}
2318 2113
2319fn test<T: Trait>() where T: Trait2<T::Item> { 2114fn test<T: Trait>() where T: Trait2<T::Item> {
2320 let x: T::Item = no_matter; 2115 let x: T::Item = no_matter;
2321} //^ {unknown} 2116} //^^^^^^^^^ {unknown}
2322"#, 2117"#,
2323 ); 2118 );
2324} 2119}
@@ -2335,7 +2130,7 @@ trait Trait<T> {
2335 2130
2336fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { 2131fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
2337 let x: T::Item = no_matter; 2132 let x: T::Item = no_matter;
2338} //^ {unknown} 2133} //^^^^^^^^^ {unknown}
2339"#, 2134"#,
2340 ); 2135 );
2341} 2136}
@@ -2353,7 +2148,7 @@ trait Trait {
2353 2148
2354fn test<T>() where T: Trait<OtherItem = T::Item> { 2149fn test<T>() where T: Trait<OtherItem = T::Item> {
2355 let x: T::Item = no_matter; 2150 let x: T::Item = no_matter;
2356} //^ Trait::Item<T> 2151} //^^^^^^^^^ Trait::Item<T>
2357"#, 2152"#,
2358 ); 2153 );
2359} 2154}
@@ -2385,7 +2180,7 @@ fn test<T>(t: T) where T: UnificationStoreMut {
2385 t.push(x); 2180 t.push(x);
2386 let y: Key<T>; 2181 let y: Key<T>;
2387 (x, y); 2182 (x, y);
2388} //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) 2183} //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>)
2389"#, 2184"#,
2390 ); 2185 );
2391} 2186}
@@ -2410,7 +2205,7 @@ impl<T: Iterator> Iterator for S<T> {
2410fn test<I: Iterator<Item: OtherTrait<u32>>>() { 2205fn test<I: Iterator<Item: OtherTrait<u32>>>() {
2411 let x: <S<I> as Iterator>::Item; 2206 let x: <S<I> as Iterator>::Item;
2412 x.foo(); 2207 x.foo();
2413} //^ u32 2208} //^^^^^^^ u32
2414"#, 2209"#,
2415 ); 2210 );
2416} 2211}
@@ -2560,12 +2355,7 @@ fn test() -> impl Trait<i32> {
2560fn assoc_types_from_bounds() { 2355fn assoc_types_from_bounds() {
2561 check_infer( 2356 check_infer(
2562 r#" 2357 r#"
2563//- /main.rs 2358//- minicore: fn
2564#[lang = "fn_once"]
2565trait FnOnce<Args> {
2566 type Output;
2567}
2568
2569trait T { 2359trait T {
2570 type O; 2360 type O;
2571} 2361}
@@ -2584,15 +2374,15 @@ fn main() {
2584 f::<(), _>(|z| { z; }); 2374 f::<(), _>(|z| { z; });
2585}"#, 2375}"#,
2586 expect![[r#" 2376 expect![[r#"
2587 133..135 '_v': F 2377 72..74 '_v': F
2588 178..181 '{ }': () 2378 117..120 '{ }': ()
2589 193..224 '{ ... }); }': () 2379 132..163 '{ ... }); }': ()
2590 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) 2380 138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ())
2591 199..221 'f::<()... z; })': () 2381 138..160 'f::<()... z; })': ()
2592 210..220 '|z| { z; }': |&()| -> () 2382 149..159 '|z| { z; }': |&()| -> ()
2593 211..212 'z': &() 2383 150..151 'z': &()
2594 214..220 '{ z; }': () 2384 153..159 '{ z; }': ()
2595 216..217 'z': &() 2385 155..156 'z': &()
2596 "#]], 2386 "#]],
2597 ); 2387 );
2598} 2388}
@@ -2617,7 +2407,7 @@ impl<T: Trait> Trait for S<T> {
2617fn test<T: Trait>() { 2407fn test<T: Trait>() {
2618 let y: <S<T> as Trait>::Item = no_matter; 2408 let y: <S<T> as Trait>::Item = no_matter;
2619 y.foo(); 2409 y.foo();
2620} //^ u32 2410} //^^^^^^^ u32
2621"#, 2411"#,
2622 ); 2412 );
2623} 2413}
@@ -2626,12 +2416,9 @@ fn test<T: Trait>() {
2626fn dyn_trait_through_chalk() { 2416fn dyn_trait_through_chalk() {
2627 check_types( 2417 check_types(
2628 r#" 2418 r#"
2419//- minicore: deref
2629struct Box<T> {} 2420struct Box<T> {}
2630#[lang = "deref"] 2421impl<T> core::ops::Deref for Box<T> {
2631trait Deref {
2632 type Target;
2633}
2634impl<T> Deref for Box<T> {
2635 type Target = T; 2422 type Target = T;
2636} 2423}
2637trait Trait { 2424trait Trait {
@@ -2640,7 +2427,7 @@ trait Trait {
2640 2427
2641fn test(x: Box<dyn Trait>) { 2428fn test(x: Box<dyn Trait>) {
2642 x.foo(); 2429 x.foo();
2643} //^ () 2430} //^^^^^^^ ()
2644"#, 2431"#,
2645 ); 2432 );
2646} 2433}
@@ -2659,7 +2446,7 @@ impl ToOwned for str {
2659} 2446}
2660fn test() { 2447fn test() {
2661 "foo".to_owned(); 2448 "foo".to_owned();
2662} //^ String 2449} //^^^^^^^^^^^^^^^^ String
2663"#, 2450"#,
2664 ); 2451 );
2665} 2452}
@@ -2668,17 +2455,7 @@ fn test() {
2668fn iterator_chain() { 2455fn iterator_chain() {
2669 check_infer_with_mismatches( 2456 check_infer_with_mismatches(
2670 r#" 2457 r#"
2671//- /main.rs 2458//- minicore: fn, option
2672#[lang = "fn_once"]
2673trait FnOnce<Args> {
2674 type Output;
2675}
2676#[lang = "fn_mut"]
2677trait FnMut<Args>: FnOnce<Args> { }
2678
2679enum Option<T> { Some(T), None }
2680use Option::*;
2681
2682pub trait Iterator { 2459pub trait Iterator {
2683 type Item; 2460 type Item;
2684 2461
@@ -2738,46 +2515,46 @@ fn main() {
2738 .for_each(|y| { y; }); 2515 .for_each(|y| { y; });
2739}"#, 2516}"#,
2740 expect![[r#" 2517 expect![[r#"
2741 226..230 'self': Self 2518 61..65 'self': Self
2742 232..233 'f': F 2519 67..68 'f': F
2743 317..328 '{ loop {} }': FilterMap<Self, F> 2520 152..163 '{ loop {} }': FilterMap<Self, F>
2744 319..326 'loop {}': ! 2521 154..161 'loop {}': !
2745 324..326 '{}': () 2522 159..161 '{}': ()
2746 349..353 'self': Self 2523 184..188 'self': Self
2747 355..356 'f': F 2524 190..191 'f': F
2748 405..416 '{ loop {} }': () 2525 240..251 '{ loop {} }': ()
2749 407..414 'loop {}': ! 2526 242..249 'loop {}': !
2750 412..414 '{}': () 2527 247..249 '{}': ()
2751 525..529 'self': Self 2528 360..364 'self': Self
2752 854..858 'self': I 2529 689..693 'self': I
2753 865..885 '{ ... }': I 2530 700..720 '{ ... }': I
2754 875..879 'self': I 2531 710..714 'self': I
2755 944..955 '{ loop {} }': Vec<T> 2532 779..790 '{ loop {} }': Vec<T>
2756 946..953 'loop {}': ! 2533 781..788 'loop {}': !
2757 951..953 '{}': () 2534 786..788 '{}': ()
2758 1142..1269 '{ ... }); }': () 2535 977..1104 '{ ... }); }': ()
2759 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> 2536 983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32>
2760 1148..1165 'Vec::<...:new()': Vec<i32> 2537 983..1000 'Vec::<...:new()': Vec<i32>
2761 1148..1177 'Vec::<...iter()': IntoIter<i32> 2538 983..1012 'Vec::<...iter()': IntoIter<i32>
2762 1148..1240 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> 2539 983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>>
2763 1148..1266 'Vec::<... y; })': () 2540 983..1101 'Vec::<... y; })': ()
2764 1194..1239 '|x| if...None }': |i32| -> Option<u32> 2541 1029..1074 '|x| if...None }': |i32| -> Option<u32>
2765 1195..1196 'x': i32 2542 1030..1031 'x': i32
2766 1198..1239 'if x >...None }': Option<u32> 2543 1033..1074 'if x >...None }': Option<u32>
2767 1201..1202 'x': i32 2544 1036..1037 'x': i32
2768 1201..1206 'x > 0': bool 2545 1036..1041 'x > 0': bool
2769 1205..1206 '0': i32 2546 1040..1041 '0': i32
2770 1207..1225 '{ Some...u32) }': Option<u32> 2547 1042..1060 '{ Some...u32) }': Option<u32>
2771 1209..1213 'Some': Some<u32>(u32) -> Option<u32> 2548 1044..1048 'Some': Some<u32>(u32) -> Option<u32>
2772 1209..1223 'Some(x as u32)': Option<u32> 2549 1044..1058 'Some(x as u32)': Option<u32>
2773 1214..1215 'x': i32 2550 1049..1050 'x': i32
2774 1214..1222 'x as u32': u32 2551 1049..1057 'x as u32': u32
2775 1231..1239 '{ None }': Option<u32> 2552 1066..1074 '{ None }': Option<u32>
2776 1233..1237 'None': Option<u32> 2553 1068..1072 'None': Option<u32>
2777 1255..1265 '|y| { y; }': |u32| -> () 2554 1090..1100 '|y| { y; }': |u32| -> ()
2778 1256..1257 'y': u32 2555 1091..1092 'y': u32
2779 1259..1265 '{ y; }': () 2556 1094..1100 '{ y; }': ()
2780 1261..1262 'y': u32 2557 1096..1097 'y': u32
2781 "#]], 2558 "#]],
2782 ); 2559 );
2783} 2560}
@@ -2809,7 +2586,7 @@ impl<T:A> B for T {
2809 2586
2810fn main() { 2587fn main() {
2811 Bar::foo(); 2588 Bar::foo();
2812} //^ Foo 2589} //^^^^^^^^^^ Foo
2813"#, 2590"#,
2814 ); 2591 );
2815} 2592}
@@ -2841,9 +2618,7 @@ fn test(x: &dyn Foo) {
2841fn builtin_copy() { 2618fn builtin_copy() {
2842 check_infer_with_mismatches( 2619 check_infer_with_mismatches(
2843 r#" 2620 r#"
2844#[lang = "copy"] 2621//- minicore: copy
2845trait Copy {}
2846
2847struct IsCopy; 2622struct IsCopy;
2848impl Copy for IsCopy {} 2623impl Copy for IsCopy {}
2849struct NotCopy; 2624struct NotCopy;
@@ -2858,20 +2633,20 @@ fn test() {
2858 (IsCopy, NotCopy).test(); 2633 (IsCopy, NotCopy).test();
2859}"#, 2634}"#,
2860 expect![[r#" 2635 expect![[r#"
2861 110..114 'self': &Self 2636 78..82 'self': &Self
2862 166..267 '{ ...t(); }': () 2637 134..235 '{ ...t(); }': ()
2863 172..178 'IsCopy': IsCopy 2638 140..146 'IsCopy': IsCopy
2864 172..185 'IsCopy.test()': bool 2639 140..153 'IsCopy.test()': bool
2865 191..198 'NotCopy': NotCopy 2640 159..166 'NotCopy': NotCopy
2866 191..205 'NotCopy.test()': {unknown} 2641 159..173 'NotCopy.test()': {unknown}
2867 211..227 '(IsCop...sCopy)': (IsCopy, IsCopy) 2642 179..195 '(IsCop...sCopy)': (IsCopy, IsCopy)
2868 211..234 '(IsCop...test()': bool 2643 179..202 '(IsCop...test()': bool
2869 212..218 'IsCopy': IsCopy 2644 180..186 'IsCopy': IsCopy
2870 220..226 'IsCopy': IsCopy 2645 188..194 'IsCopy': IsCopy
2871 240..257 '(IsCop...tCopy)': (IsCopy, NotCopy) 2646 208..225 '(IsCop...tCopy)': (IsCopy, NotCopy)
2872 240..264 '(IsCop...test()': {unknown} 2647 208..232 '(IsCop...test()': {unknown}
2873 241..247 'IsCopy': IsCopy 2648 209..215 'IsCopy': IsCopy
2874 249..256 'NotCopy': NotCopy 2649 217..224 'NotCopy': NotCopy
2875 "#]], 2650 "#]],
2876 ); 2651 );
2877} 2652}
@@ -2880,9 +2655,7 @@ fn test() {
2880fn builtin_fn_def_copy() { 2655fn builtin_fn_def_copy() {
2881 check_infer_with_mismatches( 2656 check_infer_with_mismatches(
2882 r#" 2657 r#"
2883#[lang = "copy"] 2658//- minicore: copy
2884trait Copy {}
2885
2886fn foo() {} 2659fn foo() {}
2887fn bar<T: Copy>(T) -> T {} 2660fn bar<T: Copy>(T) -> T {}
2888struct Struct(usize); 2661struct Struct(usize);
@@ -2898,20 +2671,20 @@ fn test() {
2898 Enum::Variant.test(); 2671 Enum::Variant.test();
2899}"#, 2672}"#,
2900 expect![[r#" 2673 expect![[r#"
2901 41..43 '{}': () 2674 9..11 '{}': ()
2902 60..61 'T': {unknown} 2675 28..29 'T': {unknown}
2903 68..70 '{}': () 2676 36..38 '{}': ()
2904 68..70: expected T, got () 2677 36..38: expected T, got ()
2905 145..149 'self': &Self 2678 113..117 'self': &Self
2906 201..281 '{ ...t(); }': () 2679 169..249 '{ ...t(); }': ()
2907 207..210 'foo': fn foo() 2680 175..178 'foo': fn foo()
2908 207..217 'foo.test()': bool 2681 175..185 'foo.test()': bool
2909 223..226 'bar': fn bar<{unknown}>({unknown}) -> {unknown} 2682 191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
2910 223..233 'bar.test()': bool 2683 191..201 'bar.test()': bool
2911 239..245 'Struct': Struct(usize) -> Struct 2684 207..213 'Struct': Struct(usize) -> Struct
2912 239..252 'Struct.test()': bool 2685 207..220 'Struct.test()': bool
2913 258..271 'Enum::Variant': Variant(usize) -> Enum 2686 226..239 'Enum::Variant': Variant(usize) -> Enum
2914 258..278 'Enum::...test()': bool 2687 226..246 'Enum::...test()': bool
2915 "#]], 2688 "#]],
2916 ); 2689 );
2917} 2690}
@@ -2920,9 +2693,7 @@ fn test() {
2920fn builtin_fn_ptr_copy() { 2693fn builtin_fn_ptr_copy() {
2921 check_infer_with_mismatches( 2694 check_infer_with_mismatches(
2922 r#" 2695 r#"
2923#[lang = "copy"] 2696//- minicore: copy
2924trait Copy {}
2925
2926trait Test { fn test(&self) -> bool; } 2697trait Test { fn test(&self) -> bool; }
2927impl<T: Copy> Test for T {} 2698impl<T: Copy> Test for T {}
2928 2699
@@ -2932,17 +2703,17 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2932 f3.test(); 2703 f3.test();
2933}"#, 2704}"#,
2934 expect![[r#" 2705 expect![[r#"
2935 54..58 'self': &Self 2706 22..26 'self': &Self
2936 108..110 'f1': fn() 2707 76..78 'f1': fn()
2937 118..120 'f2': fn(usize) -> u8 2708 86..88 'f2': fn(usize) -> u8
2938 139..141 'f3': fn(u8, u8) -> &u8 2709 107..109 'f3': fn(u8, u8) -> &u8
2939 162..210 '{ ...t(); }': () 2710 130..178 '{ ...t(); }': ()
2940 168..170 'f1': fn() 2711 136..138 'f1': fn()
2941 168..177 'f1.test()': bool 2712 136..145 'f1.test()': bool
2942 183..185 'f2': fn(usize) -> u8 2713 151..153 'f2': fn(usize) -> u8
2943 183..192 'f2.test()': bool 2714 151..160 'f2.test()': bool
2944 198..200 'f3': fn(u8, u8) -> &u8 2715 166..168 'f3': fn(u8, u8) -> &u8
2945 198..207 'f3.test()': bool 2716 166..175 'f3.test()': bool
2946 "#]], 2717 "#]],
2947 ); 2718 );
2948} 2719}
@@ -2951,9 +2722,7 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2951fn builtin_sized() { 2722fn builtin_sized() {
2952 check_infer_with_mismatches( 2723 check_infer_with_mismatches(
2953 r#" 2724 r#"
2954#[lang = "sized"] 2725//- minicore: sized
2955trait Sized {}
2956
2957trait Test { fn test(&self) -> bool; } 2726trait Test { fn test(&self) -> bool; }
2958impl<T: Sized> Test for T {} 2727impl<T: Sized> Test for T {}
2959 2728
@@ -2964,22 +2733,22 @@ fn test() {
2964 (1u8, *"foo").test(); // not Sized 2733 (1u8, *"foo").test(); // not Sized
2965}"#, 2734}"#,
2966 expect![[r#" 2735 expect![[r#"
2967 56..60 'self': &Self 2736 22..26 'self': &Self
2968 113..228 '{ ...ized }': () 2737 79..194 '{ ...ized }': ()
2969 119..122 '1u8': u8 2738 85..88 '1u8': u8
2970 119..129 '1u8.test()': bool 2739 85..95 '1u8.test()': bool
2971 135..150 '(*"foo").test()': {unknown} 2740 101..116 '(*"foo").test()': {unknown}
2972 136..142 '*"foo"': str 2741 102..108 '*"foo"': str
2973 137..142 '"foo"': &str 2742 103..108 '"foo"': &str
2974 169..179 '(1u8, 1u8)': (u8, u8) 2743 135..145 '(1u8, 1u8)': (u8, u8)
2975 169..186 '(1u8, ...test()': bool 2744 135..152 '(1u8, ...test()': bool
2976 170..173 '1u8': u8 2745 136..139 '1u8': u8
2977 175..178 '1u8': u8 2746 141..144 '1u8': u8
2978 192..205 '(1u8, *"foo")': (u8, str) 2747 158..171 '(1u8, *"foo")': (u8, str)
2979 192..212 '(1u8, ...test()': {unknown} 2748 158..178 '(1u8, ...test()': {unknown}
2980 193..196 '1u8': u8 2749 159..162 '1u8': u8
2981 198..204 '*"foo"': str 2750 164..170 '*"foo"': str
2982 199..204 '"foo"': &str 2751 165..170 '"foo"': &str
2983 "#]], 2752 "#]],
2984 ); 2753 );
2985} 2754}
@@ -3064,45 +2833,23 @@ fn foo() {
3064fn infer_fn_trait_arg() { 2833fn infer_fn_trait_arg() {
3065 check_infer_with_mismatches( 2834 check_infer_with_mismatches(
3066 r#" 2835 r#"
3067 //- /lib.rs deps:std 2836//- minicore: fn, option
3068 2837fn foo<F, T>(f: F) -> T
3069 #[lang = "fn_once"] 2838where
3070 pub trait FnOnce<Args> { 2839 F: Fn(Option<i32>) -> T,
3071 type Output; 2840{
3072 2841 let s = None;
3073 extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; 2842 f(s)
3074 } 2843}
3075 2844"#,
3076 #[lang = "fn"]
3077 pub trait Fn<Args>:FnOnce<Args> {
3078 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
3079 }
3080
3081 enum Option<T> {
3082 None,
3083 Some(T)
3084 }
3085
3086 fn foo<F, T>(f: F) -> T
3087 where
3088 F: Fn(Option<i32>) -> T,
3089 {
3090 let s = None;
3091 f(s)
3092 }
3093 "#,
3094 expect![[r#" 2845 expect![[r#"
3095 101..105 'self': &Self 2846 13..14 'f': F
3096 107..111 'args': Args 2847 59..89 '{ ...f(s) }': T
3097 220..224 'self': &Self 2848 69..70 's': Option<i32>
3098 226..230 'args': Args 2849 73..77 'None': Option<i32>
3099 313..314 'f': F 2850 83..84 'f': F
3100 359..389 '{ ...f(s) }': T 2851 83..87 'f(s)': T
3101 369..370 's': Option<i32> 2852 85..86 's': Option<i32>
3102 373..377 'None': Option<i32>
3103 383..384 'f': F
3104 383..387 'f(s)': T
3105 385..386 's': Option<i32>
3106 "#]], 2853 "#]],
3107 ); 2854 );
3108} 2855}
@@ -3112,28 +2859,13 @@ fn infer_box_fn_arg() {
3112 // The type mismatch is because we don't define Unsize and CoerceUnsized 2859 // The type mismatch is because we don't define Unsize and CoerceUnsized
3113 check_infer_with_mismatches( 2860 check_infer_with_mismatches(
3114 r#" 2861 r#"
3115//- /lib.rs deps:std 2862//- minicore: fn, deref, option
3116
3117#[lang = "fn_once"]
3118pub trait FnOnce<Args> {
3119 type Output;
3120
3121 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3122}
3123
3124#[lang = "deref"]
3125pub trait Deref {
3126 type Target: ?Sized;
3127
3128 fn deref(&self) -> &Self::Target;
3129}
3130
3131#[lang = "owned_box"] 2863#[lang = "owned_box"]
3132pub struct Box<T: ?Sized> { 2864pub struct Box<T: ?Sized> {
3133 inner: *mut T, 2865 inner: *mut T,
3134} 2866}
3135 2867
3136impl<T: ?Sized> Deref for Box<T> { 2868impl<T: ?Sized> core::ops::Deref for Box<T> {
3137 type Target = T; 2869 type Target = T;
3138 2870
3139 fn deref(&self) -> &T { 2871 fn deref(&self) -> &T {
@@ -3141,38 +2873,30 @@ impl<T: ?Sized> Deref for Box<T> {
3141 } 2873 }
3142} 2874}
3143 2875
3144enum Option<T> {
3145 None,
3146 Some(T)
3147}
3148
3149fn foo() { 2876fn foo() {
3150 let s = Option::None; 2877 let s = None;
3151 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); 2878 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
3152 f(&s); 2879 f(&s);
3153}"#, 2880}"#,
3154 expect![[r#" 2881 expect![[r#"
3155 100..104 'self': Self 2882 154..158 'self': &Box<T>
3156 106..110 'args': Args 2883 166..193 '{ ... }': &T
3157 214..218 'self': &Self 2884 176..187 '&self.inner': &*mut T
3158 384..388 'self': &Box<T> 2885 177..181 'self': &Box<T>
3159 396..423 '{ ... }': &T 2886 177..187 'self.inner': *mut T
3160 406..417 '&self.inner': &*mut T 2887 206..296 '{ ...&s); }': ()
3161 407..411 'self': &Box<T> 2888 216..217 's': Option<i32>
3162 407..417 'self.inner': *mut T 2889 220..224 'None': Option<i32>
3163 478..576 '{ ...&s); }': () 2890 234..235 'f': Box<dyn FnOnce(&Option<i32>)>
3164 488..489 's': Option<i32> 2891 269..282 'box (|ps| {})': Box<|{unknown}| -> ()>
3165 492..504 'Option::None': Option<i32> 2892 274..281 '|ps| {}': |{unknown}| -> ()
3166 514..515 'f': Box<dyn FnOnce(&Option<i32>)> 2893 275..277 'ps': {unknown}
3167 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> 2894 279..281 '{}': ()
3168 554..561 '|ps| {}': |{unknown}| -> () 2895 288..289 'f': Box<dyn FnOnce(&Option<i32>)>
3169 555..557 'ps': {unknown} 2896 288..293 'f(&s)': ()
3170 559..561 '{}': () 2897 290..292 '&s': &Option<i32>
3171 568..569 'f': Box<dyn FnOnce(&Option<i32>)> 2898 291..292 's': Option<i32>
3172 568..573 'f(&s)': () 2899 269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()>
3173 570..572 '&s': &Option<i32>
3174 571..572 's': Option<i32>
3175 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()>
3176 "#]], 2900 "#]],
3177 ); 2901 );
3178} 2902}
@@ -3181,17 +2905,7 @@ fn foo() {
3181fn infer_dyn_fn_output() { 2905fn infer_dyn_fn_output() {
3182 check_types( 2906 check_types(
3183 r#" 2907 r#"
3184#[lang = "fn_once"] 2908//- minicore: fn
3185pub trait FnOnce<Args> {
3186 type Output;
3187 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3188}
3189
3190#[lang = "fn"]
3191pub trait Fn<Args>: FnOnce<Args> {
3192 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
3193}
3194
3195fn foo() { 2909fn foo() {
3196 let f: &dyn Fn() -> i32; 2910 let f: &dyn Fn() -> i32;
3197 f(); 2911 f();
@@ -3204,12 +2918,7 @@ fn foo() {
3204fn infer_dyn_fn_once_output() { 2918fn infer_dyn_fn_once_output() {
3205 check_types( 2919 check_types(
3206 r#" 2920 r#"
3207#[lang = "fn_once"] 2921//- minicore: fn
3208pub trait FnOnce<Args> {
3209 type Output;
3210 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3211}
3212
3213fn foo() { 2922fn foo() {
3214 let f: dyn FnOnce() -> i32; 2923 let f: dyn FnOnce() -> i32;
3215 f(); 2924 f();
@@ -3230,7 +2939,7 @@ fn test() {
3230 S.get(1); 2939 S.get(1);
3231 //^^^^^^^^ u128 2940 //^^^^^^^^ u128
3232 S.get(1.); 2941 S.get(1.);
3233 //^^^^^^^^ f32 2942 //^^^^^^^^^ f32
3234} 2943}
3235 "#, 2944 "#,
3236 ); 2945 );
@@ -3644,20 +3353,16 @@ fn main() {
3644fn fn_returning_unit() { 3353fn fn_returning_unit() {
3645 check_infer_with_mismatches( 3354 check_infer_with_mismatches(
3646 r#" 3355 r#"
3647#[lang = "fn_once"] 3356//- minicore: fn
3648trait FnOnce<Args> {
3649 type Output;
3650}
3651
3652fn test<F: FnOnce()>(f: F) { 3357fn test<F: FnOnce()>(f: F) {
3653 let _: () = f(); 3358 let _: () = f();
3654}"#, 3359}"#,
3655 expect![[r#" 3360 expect![[r#"
3656 82..83 'f': F 3361 21..22 'f': F
3657 88..112 '{ ...f(); }': () 3362 27..51 '{ ...f(); }': ()
3658 98..99 '_': () 3363 37..38 '_': ()
3659 106..107 'f': F 3364 45..46 'f': F
3660 106..109 'f()': () 3365 45..48 'f()': ()
3661 "#]], 3366 "#]],
3662 ); 3367 );
3663} 3368}
@@ -3696,16 +3401,7 @@ impl foo::Foo for u32 {
3696fn infer_async_ret_type() { 3401fn infer_async_ret_type() {
3697 check_types( 3402 check_types(
3698 r#" 3403 r#"
3699//- /main.rs crate:main deps:core 3404//- minicore: future, result
3700
3701enum Result<T, E> {
3702 Ok(T),
3703 Err(E),
3704}
3705
3706use Result::*;
3707
3708
3709struct Fooey; 3405struct Fooey;
3710 3406
3711impl Fooey { 3407impl Fooey {
@@ -3718,31 +3414,21 @@ trait Convert {
3718 fn new() -> Self; 3414 fn new() -> Self;
3719} 3415}
3720impl Convert for u32 { 3416impl Convert for u32 {
3721 fn new() -> Self { 3417 fn new() -> Self { 0 }
3722 0
3723 }
3724} 3418}
3725 3419
3726async fn get_accounts() -> Result<u32, ()> { 3420async fn get_accounts() -> Result<u32, ()> {
3727 let ret = Fooey.collect(); 3421 let ret = Fooey.collect();
3728 // ^ u32 3422 // ^^^^^^^^^^^^^^^ u32
3729 Ok(ret) 3423 Ok(ret)
3730} 3424}
3731
3732//- /core.rs crate:core
3733#[prelude_import] use future::*;
3734mod future {
3735 #[lang = "future_trait"]
3736 trait Future {
3737 type Output;
3738 }
3739}
3740"#, 3425"#,
3741 ); 3426 );
3742} 3427}
3743 3428
3744#[test] 3429#[test]
3745fn local_impl_1() { 3430fn local_impl_1() {
3431 check!(block_local_impls);
3746 check_types( 3432 check_types(
3747 r#" 3433 r#"
3748trait Trait<T> { 3434trait Trait<T> {
@@ -3752,7 +3438,7 @@ trait Trait<T> {
3752fn test() { 3438fn test() {
3753 struct S; 3439 struct S;
3754 impl Trait<u32> for S { 3440 impl Trait<u32> for S {
3755 fn foo(&self) { 0 } 3441 fn foo(&self) -> u32 { 0 }
3756 } 3442 }
3757 3443
3758 S.foo(); 3444 S.foo();
@@ -3764,6 +3450,7 @@ fn test() {
3764 3450
3765#[test] 3451#[test]
3766fn local_impl_2() { 3452fn local_impl_2() {
3453 check!(block_local_impls);
3767 check_types( 3454 check_types(
3768 r#" 3455 r#"
3769struct S; 3456struct S;
@@ -3773,7 +3460,7 @@ fn test() {
3773 fn foo(&self) -> T; 3460 fn foo(&self) -> T;
3774 } 3461 }
3775 impl Trait<u32> for S { 3462 impl Trait<u32> for S {
3776 fn foo(&self) { 0 } 3463 fn foo(&self) -> u32 { 0 }
3777 } 3464 }
3778 3465
3779 S.foo(); 3466 S.foo();
@@ -3785,6 +3472,7 @@ fn test() {
3785 3472
3786#[test] 3473#[test]
3787fn local_impl_3() { 3474fn local_impl_3() {
3475 check!(block_local_impls);
3788 check_types( 3476 check_types(
3789 r#" 3477 r#"
3790trait Trait<T> { 3478trait Trait<T> {
@@ -3797,7 +3485,7 @@ fn test() {
3797 struct S2; 3485 struct S2;
3798 3486
3799 impl Trait<S1> for S2 { 3487 impl Trait<S1> for S2 {
3800 fn foo(&self) { S1 } 3488 fn foo(&self) -> S1 { S1 }
3801 } 3489 }
3802 3490
3803 S2.foo(); 3491 S2.foo();
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f12928225..0e8447394 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -29,6 +29,7 @@ ide_db = { path = "../ide_db", version = "0.0.0" }
29cfg = { path = "../cfg", version = "0.0.0" } 29cfg = { path = "../cfg", version = "0.0.0" }
30profile = { path = "../profile", version = "0.0.0" } 30profile = { path = "../profile", version = "0.0.0" }
31ide_assists = { path = "../ide_assists", version = "0.0.0" } 31ide_assists = { path = "../ide_assists", version = "0.0.0" }
32ide_diagnostics = { path = "../ide_diagnostics", version = "0.0.0" }
32ide_ssr = { path = "../ide_ssr", version = "0.0.0" } 33ide_ssr = { path = "../ide_ssr", version = "0.0.0" }
33ide_completion = { path = "../ide_completion", version = "0.0.0" } 34ide_completion = { path = "../ide_completion", version = "0.0.0" }
34 35
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
deleted file mode 100644
index 815a633e5..000000000
--- a/crates/ide/src/diagnostics.rs
+++ /dev/null
@@ -1,498 +0,0 @@
1//! Collects diagnostics & fixits for a single file.
2//!
3//! The tricky bit here is that diagnostics are produced by hir in terms of
4//! macro-expanded files, but we need to present them to the users in terms of
5//! original files. So we need to map the ranges.
6
7mod break_outside_of_loop;
8mod inactive_code;
9mod incorrect_case;
10mod macro_error;
11mod mismatched_arg_count;
12mod missing_fields;
13mod missing_match_arms;
14mod missing_ok_or_some_in_tail_expr;
15mod missing_unsafe;
16mod no_such_field;
17mod remove_this_semicolon;
18mod replace_filter_map_next_with_find_map;
19mod unimplemented_builtin_macro;
20mod unlinked_file;
21mod unresolved_extern_crate;
22mod unresolved_import;
23mod unresolved_macro_call;
24mod unresolved_module;
25mod unresolved_proc_macro;
26
27mod field_shorthand;
28
29use hir::{diagnostics::AnyDiagnostic, Semantics};
30use ide_assists::AssistResolveStrategy;
31use ide_db::{base_db::SourceDatabase, RootDatabase};
32use itertools::Itertools;
33use rustc_hash::FxHashSet;
34use syntax::{
35 ast::{self, AstNode},
36 SyntaxNode, TextRange,
37};
38use text_edit::TextEdit;
39use unlinked_file::UnlinkedFile;
40
41use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange};
42
43#[derive(Copy, Clone, Debug, PartialEq)]
44pub struct DiagnosticCode(pub &'static str);
45
46impl DiagnosticCode {
47 pub fn as_str(&self) -> &str {
48 self.0
49 }
50}
51
52#[derive(Debug)]
53pub struct Diagnostic {
54 pub code: DiagnosticCode,
55 pub message: String,
56 pub range: TextRange,
57 pub severity: Severity,
58 pub unused: bool,
59 pub experimental: bool,
60 pub fixes: Option<Vec<Assist>>,
61}
62
63impl Diagnostic {
64 fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
65 let message = message.into();
66 Diagnostic {
67 code: DiagnosticCode(code),
68 message,
69 range,
70 severity: Severity::Error,
71 unused: false,
72 experimental: false,
73 fixes: None,
74 }
75 }
76
77 fn experimental(mut self) -> Diagnostic {
78 self.experimental = true;
79 self
80 }
81
82 fn severity(mut self, severity: Severity) -> Diagnostic {
83 self.severity = severity;
84 self
85 }
86
87 fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic {
88 self.fixes = fixes;
89 self
90 }
91
92 fn with_unused(mut self, unused: bool) -> Diagnostic {
93 self.unused = unused;
94 self
95 }
96}
97
98#[derive(Debug, Copy, Clone)]
99pub enum Severity {
100 Error,
101 WeakWarning,
102}
103
104#[derive(Default, Debug, Clone)]
105pub struct DiagnosticsConfig {
106 pub disable_experimental: bool,
107 pub disabled: FxHashSet<String>,
108}
109
110struct DiagnosticsContext<'a> {
111 config: &'a DiagnosticsConfig,
112 sema: Semantics<'a, RootDatabase>,
113 resolve: &'a AssistResolveStrategy,
114}
115
116pub(crate) fn diagnostics(
117 db: &RootDatabase,
118 config: &DiagnosticsConfig,
119 resolve: &AssistResolveStrategy,
120 file_id: FileId,
121) -> Vec<Diagnostic> {
122 let _p = profile::span("diagnostics");
123 let sema = Semantics::new(db);
124 let parse = db.parse(file_id);
125 let mut res = Vec::new();
126
127 // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
128 res.extend(
129 parse.errors().iter().take(128).map(|err| {
130 Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range())
131 }),
132 );
133
134 for node in parse.tree().syntax().descendants() {
135 check_unnecessary_braces_in_use_statement(&mut res, file_id, &node);
136 field_shorthand::check(&mut res, file_id, &node);
137 }
138
139 let mut diags = Vec::new();
140 let module = sema.to_module_def(file_id);
141 if let Some(m) = module {
142 m.diagnostics(db, &mut diags)
143 }
144
145 let ctx = DiagnosticsContext { config, sema, resolve };
146 if module.is_none() {
147 let d = UnlinkedFile { file: file_id };
148 let d = unlinked_file::unlinked_file(&ctx, &d);
149 res.push(d)
150 }
151
152 for diag in diags {
153 #[rustfmt::skip]
154 let d = match diag {
155 AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d),
156 AnyDiagnostic::IncorrectCase(d) => incorrect_case::incorrect_case(&ctx, &d),
157 AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
158 AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
159 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
160 AnyDiagnostic::MissingMatchArms(d) => missing_match_arms::missing_match_arms(&ctx, &d),
161 AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
162 AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d),
163 AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d),
164 AnyDiagnostic::RemoveThisSemicolon(d) => remove_this_semicolon::remove_this_semicolon(&ctx, &d),
165 AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
166 AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
167 AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
168 AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
169 AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
170 AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
171 AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
172
173 AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) {
174 Some(it) => it,
175 None => continue,
176 }
177 };
178 res.push(d)
179 }
180
181 res.retain(|d| {
182 !ctx.config.disabled.contains(d.code.as_str())
183 && !(ctx.config.disable_experimental && d.experimental)
184 });
185
186 res
187}
188
189fn check_unnecessary_braces_in_use_statement(
190 acc: &mut Vec<Diagnostic>,
191 file_id: FileId,
192 node: &SyntaxNode,
193) -> Option<()> {
194 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
195 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
196 // If there is a comment inside the bracketed `use`,
197 // assume it is a commented out module path and don't show diagnostic.
198 if use_tree_list.has_inner_comment() {
199 return Some(());
200 }
201
202 let use_range = use_tree_list.syntax().text_range();
203 let edit =
204 text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
205 .unwrap_or_else(|| {
206 let to_replace = single_use_tree.syntax().text().to_string();
207 let mut edit_builder = TextEdit::builder();
208 edit_builder.delete(use_range);
209 edit_builder.insert(use_range.start(), to_replace);
210 edit_builder.finish()
211 });
212
213 acc.push(
214 Diagnostic::new(
215 "unnecessary-braces",
216 "Unnecessary braces in use statement".to_string(),
217 use_range,
218 )
219 .severity(Severity::WeakWarning)
220 .with_fixes(Some(vec![fix(
221 "remove_braces",
222 "Remove unnecessary braces",
223 SourceChange::from_text_edit(file_id, edit),
224 use_range,
225 )])),
226 );
227 }
228
229 Some(())
230}
231
232fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
233 single_use_tree: &ast::UseTree,
234) -> Option<TextEdit> {
235 let use_tree_list_node = single_use_tree.syntax().parent()?;
236 if single_use_tree.path()?.segment()?.self_token().is_some() {
237 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
238 let end = use_tree_list_node.text_range().end();
239 return Some(TextEdit::delete(TextRange::new(start, end)));
240 }
241 None
242}
243
244fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
245 let mut res = unresolved_fix(id, label, target);
246 res.source_change = Some(source_change);
247 res
248}
249
250fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
251 assert!(!id.contains(' '));
252 Assist {
253 id: AssistId(id, AssistKind::QuickFix),
254 label: Label::new(label),
255 group: None,
256 target,
257 source_change: None,
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use expect_test::Expect;
264 use ide_assists::AssistResolveStrategy;
265 use stdx::trim_indent;
266 use test_utils::{assert_eq_text, extract_annotations};
267
268 use crate::{fixture, DiagnosticsConfig};
269
270 /// Takes a multi-file input fixture with annotated cursor positions,
271 /// and checks that:
272 /// * a diagnostic is produced
273 /// * the first diagnostic fix trigger range touches the input cursor position
274 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
275 #[track_caller]
276 pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
277 check_nth_fix(0, ra_fixture_before, ra_fixture_after);
278 }
279 /// Takes a multi-file input fixture with annotated cursor positions,
280 /// and checks that:
281 /// * a diagnostic is produced
282 /// * every diagnostic fixes trigger range touches the input cursor position
283 /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
284 pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
285 for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
286 check_nth_fix(i, ra_fixture_before, ra_fixture_after)
287 }
288 }
289
290 #[track_caller]
291 fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
292 let after = trim_indent(ra_fixture_after);
293
294 let (analysis, file_position) = fixture::position(ra_fixture_before);
295 let diagnostic = analysis
296 .diagnostics(
297 &DiagnosticsConfig::default(),
298 AssistResolveStrategy::All,
299 file_position.file_id,
300 )
301 .unwrap()
302 .pop()
303 .expect("no diagnostics");
304 let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth];
305 let actual = {
306 let source_change = fix.source_change.as_ref().unwrap();
307 let file_id = *source_change.source_file_edits.keys().next().unwrap();
308 let mut actual = analysis.file_text(file_id).unwrap().to_string();
309
310 for edit in source_change.source_file_edits.values() {
311 edit.apply(&mut actual);
312 }
313 actual
314 };
315
316 assert_eq_text!(&after, &actual);
317 assert!(
318 fix.target.contains_inclusive(file_position.offset),
319 "diagnostic fix range {:?} does not touch cursor position {:?}",
320 fix.target,
321 file_position.offset
322 );
323 }
324
325 /// Checks that there's a diagnostic *without* fix at `$0`.
326 pub(crate) fn check_no_fix(ra_fixture: &str) {
327 let (analysis, file_position) = fixture::position(ra_fixture);
328 let diagnostic = analysis
329 .diagnostics(
330 &DiagnosticsConfig::default(),
331 AssistResolveStrategy::All,
332 file_position.file_id,
333 )
334 .unwrap()
335 .pop()
336 .unwrap();
337 assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic);
338 }
339
340 pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
341 let (analysis, file_id) = fixture::file(ra_fixture);
342 let diagnostics = analysis
343 .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
344 .unwrap();
345 expect.assert_debug_eq(&diagnostics)
346 }
347
348 #[track_caller]
349 pub(crate) fn check_diagnostics(ra_fixture: &str) {
350 let mut config = DiagnosticsConfig::default();
351 config.disabled.insert("inactive-code".to_string());
352 check_diagnostics_with_config(config, ra_fixture)
353 }
354
355 #[track_caller]
356 pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
357 let (analysis, files) = fixture::files(ra_fixture);
358 for file_id in files {
359 let diagnostics =
360 analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
361
362 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
363 let mut actual =
364 diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>();
365 actual.sort_by_key(|(range, _)| range.start());
366 assert_eq!(expected, actual);
367 }
368 }
369
370 #[test]
371 fn test_check_unnecessary_braces_in_use_statement() {
372 check_diagnostics(
373 r#"
374use a;
375use a::{c, d::e};
376
377mod a {
378 mod c {}
379 mod d {
380 mod e {}
381 }
382}
383"#,
384 );
385 check_diagnostics(
386 r#"
387use a;
388use a::{
389 c,
390 // d::e
391};
392
393mod a {
394 mod c {}
395 mod d {
396 mod e {}
397 }
398}
399"#,
400 );
401 check_fix(
402 r"
403 mod b {}
404 use {$0b};
405 ",
406 r"
407 mod b {}
408 use b;
409 ",
410 );
411 check_fix(
412 r"
413 mod b {}
414 use {b$0};
415 ",
416 r"
417 mod b {}
418 use b;
419 ",
420 );
421 check_fix(
422 r"
423 mod a { mod c {} }
424 use a::{c$0};
425 ",
426 r"
427 mod a { mod c {} }
428 use a::c;
429 ",
430 );
431 check_fix(
432 r"
433 mod a {}
434 use a::{self$0};
435 ",
436 r"
437 mod a {}
438 use a;
439 ",
440 );
441 check_fix(
442 r"
443 mod a { mod c {} mod d { mod e {} } }
444 use a::{c, d::{e$0}};
445 ",
446 r"
447 mod a { mod c {} mod d { mod e {} } }
448 use a::{c, d::e};
449 ",
450 );
451 }
452
453 #[test]
454 fn test_disabled_diagnostics() {
455 let mut config = DiagnosticsConfig::default();
456 config.disabled.insert("unresolved-module".into());
457
458 let (analysis, file_id) = fixture::file(r#"mod foo;"#);
459
460 let diagnostics =
461 analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
462 assert!(diagnostics.is_empty());
463
464 let diagnostics = analysis
465 .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
466 .unwrap();
467 assert!(!diagnostics.is_empty());
468 }
469
470 #[test]
471 fn import_extern_crate_clash_with_inner_item() {
472 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
473
474 check_diagnostics(
475 r#"
476//- /lib.rs crate:lib deps:jwt
477mod permissions;
478
479use permissions::jwt;
480
481fn f() {
482 fn inner() {}
483 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
484}
485
486//- /permissions.rs
487pub mod jwt {
488 pub struct Claims {}
489}
490
491//- /jwt/lib.rs crate:jwt
492pub struct Claims {
493 field: u8,
494}
495 "#,
496 );
497 }
498}
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index b75ec411c..455b32456 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -442,10 +442,10 @@ impl TryToNav for hir::TypeParam {
442 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 442 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
443 let src = self.source(db)?; 443 let src = self.source(db)?;
444 let full_range = match &src.value { 444 let full_range = match &src.value {
445 Either::Left(it) => it 445 Either::Left(type_param) => type_param.syntax().text_range(),
446 Either::Right(trait_) => trait_
446 .name() 447 .name()
447 .map_or_else(|| it.syntax().text_range(), |name| name.syntax().text_range()), 448 .map_or_else(|| trait_.syntax().text_range(), |name| name.syntax().text_range()),
448 Either::Right(it) => it.syntax().text_range(),
449 }; 449 };
450 let focus_range = match &src.value { 450 let focus_range = match &src.value {
451 Either::Left(it) => it.name(), 451 Either::Left(it) => it.name(),
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 57ae9455b..7ac0118fe 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -241,6 +241,10 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
241 Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), 241 Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(),
242 _ => definition.module(db)?.krate(), 242 _ => definition.module(db)?.krate(),
243 }; 243 };
244 // FIXME: using import map doesn't make sense here. What we want here is
245 // canonical path. What import map returns is the shortest path suitable for
246 // import. See this test:
247 cov_mark::hit!(test_reexport_order);
244 let import_map = db.import_map(krate.into()); 248 let import_map = db.import_map(krate.into());
245 249
246 let mut base = krate.display_name(db)?.to_string(); 250 let mut base = krate.display_name(db)?.to_string();
@@ -642,13 +646,15 @@ pub mod foo {
642 ) 646 )
643 } 647 }
644 648
645 // FIXME: ImportMap will return re-export paths instead of public module
646 // paths. The correct path to documentation will never be a re-export.
647 // This problem stops us from resolving stdlib items included in the prelude
648 // such as `Option::Some` correctly.
649 #[ignore = "ImportMap may return re-exports"]
650 #[test] 649 #[test]
651 fn test_reexport_order() { 650 fn test_reexport_order() {
651 cov_mark::check!(test_reexport_order);
652 // FIXME: This should return
653 //
654 // https://docs.rs/test/*/test/wrapper/modulestruct.Item.html
655 //
656 // That is, we should point inside the module, rather than at the
657 // re-export.
652 check( 658 check(
653 r#" 659 r#"
654pub mod wrapper { 660pub mod wrapper {
@@ -663,7 +669,7 @@ fn foo() {
663 let bar: wrapper::It$0em; 669 let bar: wrapper::It$0em;
664} 670}
665 "#, 671 "#,
666 expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], 672 expect![[r#"https://docs.rs/test/*/test/wrapper/struct.Item.html"#]],
667 ) 673 )
668 } 674 }
669} 675}
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index 38e2e866b..cf679edd3 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -12,14 +12,6 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
12 (host.analysis(), change_fixture.files[0]) 12 (host.analysis(), change_fixture.files[0])
13} 13}
14 14
15/// Creates analysis for many files.
16pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) {
17 let mut host = AnalysisHost::default();
18 let change_fixture = ChangeFixture::parse(ra_fixture);
19 host.db.apply_change(change_fixture.change);
20 (host.analysis(), change_fixture.files)
21}
22
23/// Creates analysis from a multi-file fixture, returns positions marked with $0. 15/// Creates analysis from a multi-file fixture, returns positions marked with $0.
24pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { 16pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
25 let mut host = AnalysisHost::default(); 17 let mut host = AnalysisHost::default();
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 8dd643a0f..d8e0dc4d5 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1130,15 +1130,15 @@ fn foo<'foobar>(_: &'foobar ()) {
1130 } 1130 }
1131 1131
1132 #[test] 1132 #[test]
1133 #[ignore] // requires the HIR to somehow track these hrtb lifetimes
1134 fn goto_lifetime_hrtb() { 1133 fn goto_lifetime_hrtb() {
1135 check( 1134 // FIXME: requires the HIR to somehow track these hrtb lifetimes
1135 check_unresolved(
1136 r#"trait Foo<T> {} 1136 r#"trait Foo<T> {}
1137fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} 1137fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1138 //^^ 1138 //^^
1139"#, 1139"#,
1140 ); 1140 );
1141 check( 1141 check_unresolved(
1142 r#"trait Foo<T> {} 1142 r#"trait Foo<T> {}
1143fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} 1143fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1144 //^^ 1144 //^^
@@ -1147,9 +1147,9 @@ fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1147 } 1147 }
1148 1148
1149 #[test] 1149 #[test]
1150 #[ignore] // requires ForTypes to be implemented
1151 fn goto_lifetime_hrtb_for_type() { 1150 fn goto_lifetime_hrtb_for_type() {
1152 check( 1151 // FIXME: requires ForTypes to be implemented
1152 check_unresolved(
1153 r#"trait Foo<T> {} 1153 r#"trait Foo<T> {}
1154fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} 1154fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
1155 //^^ 1155 //^^
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 0013820b4..07686017d 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -236,15 +236,10 @@ impl T for &Foo {}
236 fn goto_implementation_to_builtin_derive() { 236 fn goto_implementation_to_builtin_derive() {
237 check( 237 check(
238 r#" 238 r#"
239//- minicore: copy, derive
239 #[derive(Copy)] 240 #[derive(Copy)]
240//^^^^^^^^^^^^^^^ 241//^^^^^^^^^^^^^^^
241struct Foo$0; 242struct Foo$0;
242
243mod marker {
244 trait Copy {}
245}
246#[rustc_builtin_macro]
247macro Copy {}
248"#, 243"#,
249 ); 244 );
250 } 245 }
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 004d9cb68..43cffefe5 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -33,13 +33,23 @@ pub(crate) fn goto_type_definition(
33 ast::SelfParam(it) => sema.type_of_self(&it)?, 33 ast::SelfParam(it) => sema.type_of_self(&it)?,
34 ast::Type(it) => sema.resolve_type(&it)?, 34 ast::Type(it) => sema.resolve_type(&it)?,
35 ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, 35 ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
36 ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
37 // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
38 ast::NameRef(it) => {
39 if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
40 let (_, _, ty) = sema.resolve_record_field(&record_field)?;
41 ty
42 } else {
43 let record_field = ast::RecordPatField::for_field_name_ref(&it)?;
44 sema.resolve_record_pat_field(&record_field)?.ty(db)
45 }
46 },
36 _ => return None, 47 _ => return None,
37 } 48 }
38 }; 49 };
39 50
40 Some((ty, node)) 51 Some((ty, node))
41 })?; 52 })?;
42
43 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; 53 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
44 54
45 let nav = adt_def.try_to_nav(db)?; 55 let nav = adt_def.try_to_nav(db)?;
@@ -88,6 +98,54 @@ fn foo() {
88 } 98 }
89 99
90 #[test] 100 #[test]
101 fn goto_type_definition_record_expr_field() {
102 check(
103 r#"
104struct Bar;
105 // ^^^
106struct Foo { foo: Bar }
107fn foo() {
108 Foo { foo$0 }
109}
110"#,
111 );
112 check(
113 r#"
114struct Bar;
115 // ^^^
116struct Foo { foo: Bar }
117fn foo() {
118 Foo { foo$0: Bar }
119}
120"#,
121 );
122 }
123
124 #[test]
125 fn goto_type_definition_record_pat_field() {
126 check(
127 r#"
128struct Bar;
129 // ^^^
130struct Foo { foo: Bar }
131fn foo() {
132 let Foo { foo$0 };
133}
134"#,
135 );
136 check(
137 r#"
138struct Bar;
139 // ^^^
140struct Foo { foo: Bar }
141fn foo() {
142 let Foo { foo$0: bar };
143}
144"#,
145 );
146 }
147
148 #[test]
91 fn goto_type_definition_works_simple_ref() { 149 fn goto_type_definition_works_simple_ref() {
92 check( 150 check(
93 r#" 151 r#"
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 4e1ab534b..0c1da8774 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -563,8 +563,6 @@ mod tests {
563 563
564 use crate::fixture; 564 use crate::fixture;
565 565
566 use super::*;
567
568 fn check_hover_no_result(ra_fixture: &str) { 566 fn check_hover_no_result(ra_fixture: &str) {
569 let (analysis, position) = fixture::position(ra_fixture); 567 let (analysis, position) = fixture::position(ra_fixture);
570 assert!(analysis.hover(position, true, true, true).unwrap().is_none()); 568 assert!(analysis.hover(position, true, true, true).unwrap().is_none());
@@ -1816,9 +1814,10 @@ pub struct B$0ar
1816 ); 1814 );
1817 } 1815 }
1818 1816
1819 #[ignore = "path based links currently only support documentation on ModuleDef items"]
1820 #[test] 1817 #[test]
1821 fn test_hover_path_link_field() { 1818 fn test_hover_path_link_field() {
1819 // FIXME: Should be
1820 // [Foo](https://docs.rs/test/*/test/struct.Foo.html)
1822 check( 1821 check(
1823 r#" 1822 r#"
1824pub struct Foo; 1823pub struct Foo;
@@ -1840,7 +1839,7 @@ pub struct Bar {
1840 1839
1841 --- 1840 ---
1842 1841
1843 [Foo](https://docs.rs/test/*/test/struct.Foo.html) 1842 [Foo](struct.Foo.html)
1844 "#]], 1843 "#]],
1845 ); 1844 );
1846 } 1845 }
@@ -2254,7 +2253,7 @@ pub fn fo$0o() {}
2254 case 13. collapsed link: foo 2253 case 13. collapsed link: foo
2255 case 14. shortcut link: foo 2254 case 14. shortcut link: foo
2256 case 15. inline without URL: foo 2255 case 15. inline without URL: foo
2257 case 16. just escaped text: \[foo] 2256 case 16. just escaped text: \[foo\]
2258 case 17. inline link: Foo 2257 case 17. inline link: Foo
2259 2258
2260 [^example]: https://www.example.com/ 2259 [^example]: https://www.example.com/
@@ -2994,29 +2993,24 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
2994 fn test_hover_async_block_impl_trait_has_goto_type_action() { 2993 fn test_hover_async_block_impl_trait_has_goto_type_action() {
2995 check_actions( 2994 check_actions(
2996 r#" 2995 r#"
2996//- minicore: future
2997struct S; 2997struct S;
2998fn foo() { 2998fn foo() {
2999 let fo$0o = async { S }; 2999 let fo$0o = async { S };
3000} 3000}
3001
3002#[prelude_import] use future::*;
3003mod future {
3004 #[lang = "future_trait"]
3005 pub trait Future { type Output; }
3006}
3007"#, 3001"#,
3008 expect![[r#" 3002 expect![[r#"
3009 [ 3003 [
3010 GoToType( 3004 GoToType(
3011 [ 3005 [
3012 HoverGotoTypeData { 3006 HoverGotoTypeData {
3013 mod_path: "test::future::Future", 3007 mod_path: "core::future::Future",
3014 nav: NavigationTarget { 3008 nav: NavigationTarget {
3015 file_id: FileId( 3009 file_id: FileId(
3016 0, 3010 1,
3017 ), 3011 ),
3018 full_range: 101..163, 3012 full_range: 251..433,
3019 focus_range: 140..146, 3013 focus_range: 290..296,
3020 name: "Future", 3014 name: "Future",
3021 kind: Trait, 3015 kind: Trait,
3022 description: "pub trait Future", 3016 description: "pub trait Future",
@@ -3812,11 +3806,14 @@ use foo::bar::{self$0};
3812 3806
3813 #[test] 3807 #[test]
3814 fn hover_keyword() { 3808 fn hover_keyword() {
3815 let ra_fixture = r#"//- /main.rs crate:main deps:std
3816fn f() { retur$0n; }"#;
3817 let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE);
3818 check( 3809 check(
3819 &fixture, 3810 r#"
3811//- /main.rs crate:main deps:std
3812fn f() { retur$0n; }
3813//- /libstd.rs crate:std
3814/// Docs for return_keyword
3815mod return_keyword {}
3816"#,
3820 expect![[r#" 3817 expect![[r#"
3821 *return* 3818 *return*
3822 3819
@@ -3833,11 +3830,15 @@ fn f() { retur$0n; }"#;
3833 3830
3834 #[test] 3831 #[test]
3835 fn hover_builtin() { 3832 fn hover_builtin() {
3836 let ra_fixture = r#"//- /main.rs crate:main deps:std
3837cosnt _: &str$0 = ""; }"#;
3838 let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE);
3839 check( 3833 check(
3840 &fixture, 3834 r#"
3835//- /main.rs crate:main deps:std
3836cosnt _: &str$0 = ""; }
3837
3838//- /libstd.rs crate:std
3839/// Docs for prim_str
3840mod prim_str {}
3841"#,
3841 expect![[r#" 3842 expect![[r#"
3842 *str* 3843 *str*
3843 3844
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 9cd33d0e4..95f9edce4 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -434,7 +434,6 @@ fn get_callable(
434#[cfg(test)] 434#[cfg(test)]
435mod tests { 435mod tests {
436 use expect_test::{expect, Expect}; 436 use expect_test::{expect, Expect};
437 use ide_db::helpers::FamousDefs;
438 use test_utils::extract_annotations; 437 use test_utils::extract_annotations;
439 438
440 use crate::{fixture, inlay_hints::InlayHintsConfig}; 439 use crate::{fixture, inlay_hints::InlayHintsConfig};
@@ -487,8 +486,6 @@ mod tests {
487 } 486 }
488 487
489 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { 488 fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
490 let ra_fixture =
491 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
492 let (analysis, file_id) = fixture::file(&ra_fixture); 489 let (analysis, file_id) = fixture::file(&ra_fixture);
493 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); 490 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
494 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); 491 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
@@ -498,8 +495,6 @@ mod tests {
498 } 495 }
499 496
500 fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { 497 fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
501 let ra_fixture =
502 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
503 let (analysis, file_id) = fixture::file(&ra_fixture); 498 let (analysis, file_id) = fixture::file(&ra_fixture);
504 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); 499 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
505 expect.assert_debug_eq(&inlay_hints) 500 expect.assert_debug_eq(&inlay_hints)
@@ -666,9 +661,7 @@ fn main() {
666 fn function_call_parameter_hint() { 661 fn function_call_parameter_hint() {
667 check_params( 662 check_params(
668 r#" 663 r#"
669enum Option<T> { None, Some(T) } 664//- minicore: option
670use Option::*;
671
672struct FileId {} 665struct FileId {}
673struct SmolStr {} 666struct SmolStr {}
674 667
@@ -823,6 +816,7 @@ fn main() {
823 fn shorten_iterators_in_associated_params() { 816 fn shorten_iterators_in_associated_params() {
824 check_types( 817 check_types(
825 r#" 818 r#"
819//- minicore: iterators
826use core::iter; 820use core::iter;
827 821
828pub struct SomeIter<T> {} 822pub struct SomeIter<T> {}
@@ -875,8 +869,7 @@ fn main() {
875 fn fn_hints() { 869 fn fn_hints() {
876 check_types( 870 check_types(
877 r#" 871 r#"
878trait Sized {} 872//- minicore: fn, sized
879
880fn foo() -> impl Fn() { loop {} } 873fn foo() -> impl Fn() { loop {} }
881fn foo1() -> impl Fn(f64) { loop {} } 874fn foo1() -> impl Fn(f64) { loop {} }
882fn foo2() -> impl Fn(f64, f64) { loop {} } 875fn foo2() -> impl Fn(f64, f64) { loop {} }
@@ -912,9 +905,7 @@ fn main() {
912 fn unit_structs_have_no_type_hints() { 905 fn unit_structs_have_no_type_hints() {
913 check_types( 906 check_types(
914 r#" 907 r#"
915enum Result<T, E> { Ok(T), Err(E) } 908//- minicore: result
916use Result::*;
917
918struct SyntheticSyntax; 909struct SyntheticSyntax;
919 910
920fn main() { 911fn main() {
@@ -966,9 +957,7 @@ fn main() {
966 fn if_expr() { 957 fn if_expr() {
967 check_types( 958 check_types(
968 r#" 959 r#"
969enum Option<T> { None, Some(T) } 960//- minicore: option
970use Option::*;
971
972struct Test { a: Option<u32>, b: u8 } 961struct Test { a: Option<u32>, b: u8 }
973 962
974fn main() { 963fn main() {
@@ -998,9 +987,7 @@ fn main() {
998 fn while_expr() { 987 fn while_expr() {
999 check_types( 988 check_types(
1000 r#" 989 r#"
1001enum Option<T> { None, Some(T) } 990//- minicore: option
1002use Option::*;
1003
1004struct Test { a: Option<u32>, b: u8 } 991struct Test { a: Option<u32>, b: u8 }
1005 992
1006fn main() { 993fn main() {
@@ -1016,9 +1003,7 @@ fn main() {
1016 fn match_arm_list() { 1003 fn match_arm_list() {
1017 check_types( 1004 check_types(
1018 r#" 1005 r#"
1019enum Option<T> { None, Some(T) } 1006//- minicore: option
1020use Option::*;
1021
1022struct Test { a: Option<u32>, b: u8 } 1007struct Test { a: Option<u32>, b: u8 }
1023 1008
1024fn main() { 1009fn main() {
@@ -1073,6 +1058,7 @@ fn main() {
1073 fn complete_for_hint() { 1058 fn complete_for_hint() {
1074 check_types( 1059 check_types(
1075 r#" 1060 r#"
1061//- minicore: iterator
1076pub struct Vec<T> {} 1062pub struct Vec<T> {}
1077 1063
1078impl<T> Vec<T> { 1064impl<T> Vec<T> {
@@ -1129,6 +1115,7 @@ fn main() {
1129 fn shorten_iterator_hints() { 1115 fn shorten_iterator_hints() {
1130 check_types( 1116 check_types(
1131 r#" 1117 r#"
1118//- minicore: iterators
1132use core::iter; 1119use core::iter;
1133 1120
1134struct MyIter; 1121struct MyIter;
@@ -1230,12 +1217,12 @@ fn main() {
1230 expect![[r#" 1217 expect![[r#"
1231 [ 1218 [
1232 InlayHint { 1219 InlayHint {
1233 range: 148..173, 1220 range: 147..172,
1234 kind: ChainingHint, 1221 kind: ChainingHint,
1235 label: "B", 1222 label: "B",
1236 }, 1223 },
1237 InlayHint { 1224 InlayHint {
1238 range: 148..155, 1225 range: 147..154,
1239 kind: ChainingHint, 1226 kind: ChainingHint,
1240 label: "A", 1227 label: "A",
1241 }, 1228 },
@@ -1290,12 +1277,12 @@ fn main() {
1290 expect![[r#" 1277 expect![[r#"
1291 [ 1278 [
1292 InlayHint { 1279 InlayHint {
1293 range: 144..191, 1280 range: 143..190,
1294 kind: ChainingHint, 1281 kind: ChainingHint,
1295 label: "C", 1282 label: "C",
1296 }, 1283 },
1297 InlayHint { 1284 InlayHint {
1298 range: 144..180, 1285 range: 143..179,
1299 kind: ChainingHint, 1286 kind: ChainingHint,
1300 label: "B", 1287 label: "B",
1301 }, 1288 },
@@ -1335,12 +1322,12 @@ fn main() {
1335 expect![[r#" 1322 expect![[r#"
1336 [ 1323 [
1337 InlayHint { 1324 InlayHint {
1338 range: 247..284, 1325 range: 246..283,
1339 kind: ChainingHint, 1326 kind: ChainingHint,
1340 label: "B<X<i32, bool>>", 1327 label: "B<X<i32, bool>>",
1341 }, 1328 },
1342 InlayHint { 1329 InlayHint {
1343 range: 247..266, 1330 range: 246..265,
1344 kind: ChainingHint, 1331 kind: ChainingHint,
1345 label: "A<X<i32, bool>>", 1332 label: "A<X<i32, bool>>",
1346 }, 1333 },
@@ -1359,6 +1346,7 @@ fn main() {
1359 max_length: None, 1346 max_length: None,
1360 }, 1347 },
1361 r#" 1348 r#"
1349//- minicore: iterators
1362use core::iter; 1350use core::iter;
1363 1351
1364struct MyIter; 1352struct MyIter;
@@ -1381,22 +1369,22 @@ fn main() {
1381 expect![[r#" 1369 expect![[r#"
1382 [ 1370 [
1383 InlayHint { 1371 InlayHint {
1384 range: 175..242, 1372 range: 174..241,
1385 kind: ChainingHint, 1373 kind: ChainingHint,
1386 label: "impl Iterator<Item = ()>", 1374 label: "impl Iterator<Item = ()>",
1387 }, 1375 },
1388 InlayHint { 1376 InlayHint {
1389 range: 175..225, 1377 range: 174..224,
1390 kind: ChainingHint, 1378 kind: ChainingHint,
1391 label: "impl Iterator<Item = ()>", 1379 label: "impl Iterator<Item = ()>",
1392 }, 1380 },
1393 InlayHint { 1381 InlayHint {
1394 range: 175..207, 1382 range: 174..206,
1395 kind: ChainingHint, 1383 kind: ChainingHint,
1396 label: "impl Iterator<Item = ()>", 1384 label: "impl Iterator<Item = ()>",
1397 }, 1385 },
1398 InlayHint { 1386 InlayHint {
1399 range: 175..190, 1387 range: 174..189,
1400 kind: ChainingHint, 1388 kind: ChainingHint,
1401 label: "&mut MyIter", 1389 label: "&mut MyIter",
1402 }, 1390 },
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 93d3760bf..ffa8bd182 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -197,7 +197,7 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti
197} 197}
198 198
199fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { 199fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
200 matches!((left, right), (T![,], T![')']) | (T![,], T![']'])) 200 matches!((left, right), (T![,], T![')'] | T![']']))
201} 201}
202 202
203fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { 203fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 8d0270319..3798f32cc 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -24,7 +24,6 @@ mod display;
24 24
25mod annotations; 25mod annotations;
26mod call_hierarchy; 26mod call_hierarchy;
27mod diagnostics;
28mod expand_macro; 27mod expand_macro;
29mod extend_selection; 28mod extend_selection;
30mod file_structure; 29mod file_structure;
@@ -40,6 +39,7 @@ mod matching_brace;
40mod move_item; 39mod move_item;
41mod parent_module; 40mod parent_module;
42mod references; 41mod references;
42mod rename;
43mod fn_references; 43mod fn_references;
44mod runnables; 44mod runnables;
45mod ssr; 45mod ssr;
@@ -71,7 +71,6 @@ use crate::display::ToNav;
71pub use crate::{ 71pub use crate::{
72 annotations::{Annotation, AnnotationConfig, AnnotationKind}, 72 annotations::{Annotation, AnnotationConfig, AnnotationKind},
73 call_hierarchy::CallItem, 73 call_hierarchy::CallItem,
74 diagnostics::{Diagnostic, DiagnosticsConfig, Severity},
75 display::navigation_target::NavigationTarget, 74 display::navigation_target::NavigationTarget,
76 expand_macro::ExpandedMacro, 75 expand_macro::ExpandedMacro,
77 file_structure::{StructureNode, StructureNodeKind}, 76 file_structure::{StructureNode, StructureNodeKind},
@@ -81,7 +80,8 @@ pub use crate::{
81 markup::Markup, 80 markup::Markup,
82 move_item::Direction, 81 move_item::Direction,
83 prime_caches::PrimeCachesProgress, 82 prime_caches::PrimeCachesProgress,
84 references::{rename::RenameError, ReferenceSearchResult}, 83 references::ReferenceSearchResult,
84 rename::RenameError,
85 runnables::{Runnable, RunnableKind, TestId}, 85 runnables::{Runnable, RunnableKind, TestId},
86 syntax_highlighting::{ 86 syntax_highlighting::{
87 tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, 87 tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
@@ -109,6 +109,7 @@ pub use ide_db::{
109 symbol_index::Query, 109 symbol_index::Query,
110 RootDatabase, SymbolKind, 110 RootDatabase, SymbolKind,
111}; 111};
112pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, Severity};
112pub use ide_ssr::SsrError; 113pub use ide_ssr::SsrError;
113pub use syntax::{TextRange, TextSize}; 114pub use syntax::{TextRange, TextSize};
114pub use text_edit::{Indel, TextEdit}; 115pub use text_edit::{Indel, TextEdit};
@@ -537,7 +538,7 @@ impl Analysis {
537 ) -> Cancellable<Vec<Assist>> { 538 ) -> Cancellable<Vec<Assist>> {
538 self.with_db(|db| { 539 self.with_db(|db| {
539 let ssr_assists = ssr::ssr_assists(db, &resolve, frange); 540 let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
540 let mut acc = Assist::get(db, config, resolve, frange); 541 let mut acc = ide_assists::assists(db, config, resolve, frange);
541 acc.extend(ssr_assists.into_iter()); 542 acc.extend(ssr_assists.into_iter());
542 acc 543 acc
543 }) 544 })
@@ -550,7 +551,7 @@ impl Analysis {
550 resolve: AssistResolveStrategy, 551 resolve: AssistResolveStrategy,
551 file_id: FileId, 552 file_id: FileId,
552 ) -> Cancellable<Vec<Diagnostic>> { 553 ) -> Cancellable<Vec<Diagnostic>> {
553 self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id)) 554 self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id))
554 } 555 }
555 556
556 /// Convenience function to return assists + quick fixes for diagnostics 557 /// Convenience function to return assists + quick fixes for diagnostics
@@ -567,9 +568,8 @@ impl Analysis {
567 }; 568 };
568 569
569 self.with_db(|db| { 570 self.with_db(|db| {
570 let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
571 let diagnostic_assists = if include_fixes { 571 let diagnostic_assists = if include_fixes {
572 diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) 572 ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id)
573 .into_iter() 573 .into_iter()
574 .flat_map(|it| it.fixes.unwrap_or_default()) 574 .flat_map(|it| it.fixes.unwrap_or_default())
575 .filter(|it| it.target.intersect(frange.range).is_some()) 575 .filter(|it| it.target.intersect(frange.range).is_some())
@@ -577,10 +577,12 @@ impl Analysis {
577 } else { 577 } else {
578 Vec::new() 578 Vec::new()
579 }; 579 };
580 let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
581 let assists = ide_assists::assists(db, assist_config, resolve, frange);
580 582
581 let mut res = Assist::get(db, assist_config, resolve, frange); 583 let mut res = diagnostic_assists;
582 res.extend(ssr_assists.into_iter()); 584 res.extend(ssr_assists.into_iter());
583 res.extend(diagnostic_assists.into_iter()); 585 res.extend(assists.into_iter());
584 586
585 res 587 res
586 }) 588 })
@@ -593,14 +595,14 @@ impl Analysis {
593 position: FilePosition, 595 position: FilePosition,
594 new_name: &str, 596 new_name: &str,
595 ) -> Cancellable<Result<SourceChange, RenameError>> { 597 ) -> Cancellable<Result<SourceChange, RenameError>> {
596 self.with_db(|db| references::rename::rename(db, position, new_name)) 598 self.with_db(|db| rename::rename(db, position, new_name))
597 } 599 }
598 600
599 pub fn prepare_rename( 601 pub fn prepare_rename(
600 &self, 602 &self,
601 position: FilePosition, 603 position: FilePosition,
602 ) -> Cancellable<Result<RangeInfo<()>, RenameError>> { 604 ) -> Cancellable<Result<RangeInfo<()>, RenameError>> {
603 self.with_db(|db| references::rename::prepare_rename(db, position)) 605 self.with_db(|db| rename::prepare_rename(db, position))
604 } 606 }
605 607
606 pub fn will_rename_file( 608 pub fn will_rename_file(
@@ -608,7 +610,7 @@ impl Analysis {
608 file_id: FileId, 610 file_id: FileId,
609 new_name_stem: &str, 611 new_name_stem: &str,
610 ) -> Cancellable<Option<SourceChange>> { 612 ) -> Cancellable<Option<SourceChange>> {
611 self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem)) 613 self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem))
612 } 614 }
613 615
614 pub fn structural_search_replace( 616 pub fn structural_search_replace(
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index a0fdead2c..5808562a7 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -9,8 +9,6 @@
9//! at the index that the match starts at and its tree parent is 9//! at the index that the match starts at and its tree parent is
10//! resolved to the search element definition, we get a reference. 10//! resolved to the search element definition, we get a reference.
11 11
12pub(crate) mod rename;
13
14use hir::{PathResolution, Semantics}; 12use hir::{PathResolution, Semantics};
15use ide_db::{ 13use ide_db::{
16 base_db::FileId, 14 base_db::FileId,
@@ -81,8 +79,7 @@ pub(crate) fn find_all_refs(
81 }); 79 });
82 usages.references.retain(|_, it| !it.is_empty()); 80 usages.references.retain(|_, it| !it.is_empty());
83 } 81 }
84 Definition::ModuleDef(hir::ModuleDef::Adt(_)) 82 Definition::ModuleDef(hir::ModuleDef::Adt(_) | hir::ModuleDef::Variant(_)) => {
85 | Definition::ModuleDef(hir::ModuleDef::Variant(_)) => {
86 refs.for_each(|it| { 83 refs.for_each(|it| {
87 it.retain(|reference| { 84 it.retain(|reference| {
88 reference.name.as_name_ref().map_or(false, is_lit_name_ref) 85 reference.name.as_name_ref().map_or(false, is_lit_name_ref)
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/rename.rs
index 50cc1f963..96bd07708 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -1,45 +1,25 @@
1//! Renaming functionality 1//! Renaming functionality.
2//! 2//!
3//! All reference and file rename requests go through here where the corresponding [`SourceChange`]s 3//! This is mostly front-end for [`ide_db::rename`], but it also includes the
4//! will be calculated. 4//! tests. This module also implements a couple of magic tricks, like renaming
5use std::fmt::{self, Display}; 5//! `self` and to `self` (to switch between associated function and method).
6 6use hir::{AsAssocItem, InFile, Semantics};
7use either::Either;
8use hir::{AsAssocItem, InFile, Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::{ 7use ide_db::{
10 base_db::{AnchoredPathBuf, FileId}, 8 base_db::FileId,
11 defs::{Definition, NameClass, NameRefClass}, 9 defs::{Definition, NameClass, NameRefClass},
12 search::FileReference, 10 rename::{bail, format_err, source_edit_from_references, IdentifierKind},
13 RootDatabase, 11 RootDatabase,
14}; 12};
15use stdx::never; 13use stdx::{always, never};
16use syntax::{ 14use syntax::{ast, AstNode, SyntaxNode};
17 ast::{self, NameOwner},
18 lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T,
19};
20 15
21use text_edit::TextEdit; 16use text_edit::TextEdit;
22 17
23use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; 18use crate::{FilePosition, RangeInfo, SourceChange};
24 19
25type RenameResult<T> = Result<T, RenameError>; 20pub use ide_db::rename::RenameError;
26#[derive(Debug)]
27pub struct RenameError(String);
28 21
29impl fmt::Display for RenameError { 22type RenameResult<T> = Result<T, RenameError>;
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 Display::fmt(&self.0, f)
32 }
33}
34
35macro_rules! format_err {
36 ($fmt:expr) => {RenameError(format!($fmt))};
37 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
38}
39
40macro_rules! bail {
41 ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))}
42}
43 23
44/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is 24/// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is
45/// being targeted for a rename. 25/// being targeted for a rename.
@@ -51,27 +31,14 @@ pub(crate) fn prepare_rename(
51 let source_file = sema.parse(position.file_id); 31 let source_file = sema.parse(position.file_id);
52 let syntax = source_file.syntax(); 32 let syntax = source_file.syntax();
53 33
54 let def = find_definition(&sema, syntax, position)?; 34 let (name_like, def) = find_definition(&sema, syntax, position)?;
55 match def { 35 if def.range_for_rename(&sema).is_none() {
56 Definition::SelfType(_) => bail!("Cannot rename `Self`"), 36 bail!("No references found at position")
57 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), 37 }
58 Definition::ModuleDef(ModuleDef::Module(_)) => (), 38
59 _ => { 39 let frange = sema.original_range(name_like.syntax());
60 let nav = def 40 always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
61 .try_to_nav(sema.db) 41 Ok(RangeInfo::new(frange.range, ()))
62 .ok_or_else(|| format_err!("No references found at position"))?;
63 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
64 }
65 };
66 let name_like = sema
67 .find_node_at_offset_with_descend(syntax, position.offset)
68 .ok_or_else(|| format_err!("No references found at position"))?;
69 let node = match &name_like {
70 ast::NameLike::Name(it) => it.syntax(),
71 ast::NameLike::NameRef(it) => it.syntax(),
72 ast::NameLike::Lifetime(it) => it.syntax(),
73 };
74 Ok(RangeInfo::new(sema.original_range(node).range, ()))
75} 42}
76 43
77// Feature: Rename 44// Feature: Rename
@@ -91,24 +58,23 @@ pub(crate) fn rename(
91 new_name: &str, 58 new_name: &str,
92) -> RenameResult<SourceChange> { 59) -> RenameResult<SourceChange> {
93 let sema = Semantics::new(db); 60 let sema = Semantics::new(db);
94 rename_with_semantics(&sema, position, new_name)
95}
96
97pub(crate) fn rename_with_semantics(
98 sema: &Semantics<RootDatabase>,
99 position: FilePosition,
100 new_name: &str,
101) -> RenameResult<SourceChange> {
102 let source_file = sema.parse(position.file_id); 61 let source_file = sema.parse(position.file_id);
103 let syntax = source_file.syntax(); 62 let syntax = source_file.syntax();
104 63
105 let def = find_definition(sema, syntax, position)?; 64 let (_name_like, def) = find_definition(&sema, syntax, position)?;
106 match def { 65
107 Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(sema, module, new_name), 66 if let Definition::Local(local) = def {
108 Definition::SelfType(_) => bail!("Cannot rename `Self`"), 67 if let Some(self_param) = local.as_self_param(sema.db) {
109 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), 68 cov_mark::hit!(rename_self_to_param);
110 def => rename_reference(sema, def, new_name), 69 return rename_self_to_param(&sema, local, self_param, new_name);
70 }
71 if new_name == "self" {
72 cov_mark::hit!(rename_to_self);
73 return rename_to_self(&sema, local);
74 }
111 } 75 }
76
77 def.rename(&sema, new_name)
112} 78}
113 79
114/// Called by the client when it is about to rename a file. 80/// Called by the client when it is about to rename a file.
@@ -119,47 +85,22 @@ pub(crate) fn will_rename_file(
119) -> Option<SourceChange> { 85) -> Option<SourceChange> {
120 let sema = Semantics::new(db); 86 let sema = Semantics::new(db);
121 let module = sema.to_module_def(file_id)?; 87 let module = sema.to_module_def(file_id)?;
122 let mut change = rename_mod(&sema, module, new_name_stem).ok()?; 88 let def = Definition::ModuleDef(module.into());
89 let mut change = def.rename(&sema, new_name_stem).ok()?;
123 change.file_system_edits.clear(); 90 change.file_system_edits.clear();
124 Some(change) 91 Some(change)
125} 92}
126 93
127#[derive(Copy, Clone, Debug, PartialEq)]
128enum IdentifierKind {
129 Ident,
130 Lifetime,
131 ToSelf,
132 Underscore,
133}
134
135fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
136 match lex_single_syntax_kind(new_name) {
137 Some(res) => match res {
138 (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
139 (T![_], _) => Ok(IdentifierKind::Underscore),
140 (T![self], _) => Ok(IdentifierKind::ToSelf),
141 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
142 Ok(IdentifierKind::Lifetime)
143 }
144 (SyntaxKind::LIFETIME_IDENT, _) => {
145 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
146 }
147 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
148 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
149 },
150 None => bail!("Invalid name `{}`: not an identifier", new_name),
151 }
152}
153
154fn find_definition( 94fn find_definition(
155 sema: &Semantics<RootDatabase>, 95 sema: &Semantics<RootDatabase>,
156 syntax: &SyntaxNode, 96 syntax: &SyntaxNode,
157 position: FilePosition, 97 position: FilePosition,
158) -> RenameResult<Definition> { 98) -> RenameResult<(ast::NameLike, Definition)> {
159 match sema 99 let name_like = sema
160 .find_node_at_offset_with_descend(syntax, position.offset) 100 .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
161 .ok_or_else(|| format_err!("No references found at position"))? 101 .ok_or_else(|| format_err!("No references found at position"))?;
162 { 102
103 let def = match &name_like {
163 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet 104 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
164 ast::NameLike::Name(name) 105 ast::NameLike::Name(name)
165 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => 106 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
@@ -189,146 +130,9 @@ fn find_definition(
189 .map(|it| it.referenced_or_defined(sema.db)) 130 .map(|it| it.referenced_or_defined(sema.db))
190 }), 131 }),
191 } 132 }
192 .ok_or_else(|| format_err!("No references found at position")) 133 .ok_or_else(|| format_err!("No references found at position"))?;
193}
194
195fn rename_mod(
196 sema: &Semantics<RootDatabase>,
197 module: Module,
198 new_name: &str,
199) -> RenameResult<SourceChange> {
200 if IdentifierKind::Ident != check_identifier(new_name)? {
201 bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
202 }
203
204 let mut source_change = SourceChange::default();
205
206 let InFile { file_id, value: def_source } = module.definition_source(sema.db);
207 let file_id = file_id.original_file(sema.db);
208 if let ModuleSource::SourceFile(..) = def_source {
209 // mod is defined in path/to/dir/mod.rs
210 let path = if module.is_mod_rs(sema.db) {
211 format!("../{}/mod.rs", new_name)
212 } else {
213 format!("{}.rs", new_name)
214 };
215 let dst = AnchoredPathBuf { anchor: file_id, path };
216 let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
217 source_change.push_file_system_edit(move_file);
218 }
219
220 if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) {
221 let file_id = file_id.original_file(sema.db);
222 match decl_source.name() {
223 Some(name) => source_change.insert_source_edit(
224 file_id,
225 TextEdit::replace(name.syntax().text_range(), new_name.to_string()),
226 ),
227 _ => never!("Module source node is missing a name"),
228 }
229 }
230 let def = Definition::ModuleDef(ModuleDef::Module(module));
231 let usages = def.usages(sema).all();
232 let ref_edits = usages.iter().map(|(&file_id, references)| {
233 (file_id, source_edit_from_references(references, def, new_name))
234 });
235 source_change.extend(ref_edits);
236 134
237 Ok(source_change) 135 Ok((name_like, def))
238}
239
240fn rename_reference(
241 sema: &Semantics<RootDatabase>,
242 mut def: Definition,
243 new_name: &str,
244) -> RenameResult<SourceChange> {
245 let ident_kind = check_identifier(new_name)?;
246
247 if matches!(
248 def, // is target a lifetime?
249 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
250 ) {
251 match ident_kind {
252 IdentifierKind::Ident | IdentifierKind::ToSelf | IdentifierKind::Underscore => {
253 cov_mark::hit!(rename_not_a_lifetime_ident_ref);
254 bail!("Invalid name `{}`: not a lifetime identifier", new_name);
255 }
256 IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
257 }
258 } else {
259 match (ident_kind, def) {
260 (IdentifierKind::Lifetime, _) => {
261 cov_mark::hit!(rename_not_an_ident_ref);
262 bail!("Invalid name `{}`: not an identifier", new_name);
263 }
264 (IdentifierKind::ToSelf, Definition::Local(local)) => {
265 if local.is_self(sema.db) {
266 // no-op
267 cov_mark::hit!(rename_self_to_self);
268 return Ok(SourceChange::default());
269 } else {
270 cov_mark::hit!(rename_to_self);
271 return rename_to_self(sema, local);
272 }
273 }
274 (ident_kind, Definition::Local(local)) => {
275 if let Some(self_param) = local.as_self_param(sema.db) {
276 cov_mark::hit!(rename_self_to_param);
277 return rename_self_to_param(sema, local, self_param, new_name, ident_kind);
278 } else {
279 cov_mark::hit!(rename_local);
280 }
281 }
282 (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name),
283 (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local),
284 (IdentifierKind::Underscore, _) => (),
285 }
286 }
287
288 def = match def {
289 // HACK: resolve trait impl items to the item def of the trait definition
290 // so that we properly resolve all trait item references
291 Definition::ModuleDef(mod_def) => mod_def
292 .as_assoc_item(sema.db)
293 .and_then(|it| it.containing_trait_impl(sema.db))
294 .and_then(|it| {
295 it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) {
296 (hir::AssocItem::Function(trait_func), ModuleDef::Function(func))
297 if trait_func.name(sema.db) == func.name(sema.db) =>
298 {
299 Some(Definition::ModuleDef(ModuleDef::Function(trait_func)))
300 }
301 (hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst))
302 if trait_konst.name(sema.db) == konst.name(sema.db) =>
303 {
304 Some(Definition::ModuleDef(ModuleDef::Const(trait_konst)))
305 }
306 (
307 hir::AssocItem::TypeAlias(trait_type_alias),
308 ModuleDef::TypeAlias(type_alias),
309 ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => {
310 Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias)))
311 }
312 _ => None,
313 })
314 })
315 .unwrap_or(def),
316 _ => def,
317 };
318 let usages = def.usages(sema).all();
319
320 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
321 cov_mark::hit!(rename_underscore_multiple);
322 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
323 }
324 let mut source_change = SourceChange::default();
325 source_change.extend(usages.iter().map(|(&file_id, references)| {
326 (file_id, source_edit_from_references(references, def, new_name))
327 }));
328
329 let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
330 source_change.insert_source_edit(file_id, edit);
331 Ok(source_change)
332} 136}
333 137
334fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { 138fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
@@ -398,8 +202,15 @@ fn rename_self_to_param(
398 local: hir::Local, 202 local: hir::Local,
399 self_param: hir::SelfParam, 203 self_param: hir::SelfParam,
400 new_name: &str, 204 new_name: &str,
401 identifier_kind: IdentifierKind,
402) -> RenameResult<SourceChange> { 205) -> RenameResult<SourceChange> {
206 if new_name == "self" {
207 // Let's do nothing rather than complain.
208 cov_mark::hit!(rename_self_to_self);
209 return Ok(SourceChange::default());
210 }
211
212 let identifier_kind = IdentifierKind::classify(new_name)?;
213
403 let InFile { file_id, value: self_param } = 214 let InFile { file_id, value: self_param } =
404 self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?; 215 self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?;
405 216
@@ -441,150 +252,6 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
441 Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) 252 Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
442} 253}
443 254
444fn source_edit_from_references(
445 references: &[FileReference],
446 def: Definition,
447 new_name: &str,
448) -> TextEdit {
449 let mut edit = TextEdit::builder();
450 for reference in references {
451 let (range, replacement) = match &reference.name {
452 // if the ranges differ then the node is inside a macro call, we can't really attempt
453 // to make special rewrites like shorthand syntax and such, so just rename the node in
454 // the macro input
455 ast::NameLike::NameRef(name_ref)
456 if name_ref.syntax().text_range() == reference.range =>
457 {
458 source_edit_from_name_ref(name_ref, new_name, def)
459 }
460 ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => {
461 source_edit_from_name(name, new_name)
462 }
463 _ => None,
464 }
465 .unwrap_or_else(|| (reference.range, new_name.to_string()));
466 edit.replace(range, replacement);
467 }
468 edit.finish()
469}
470
471fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> {
472 if let Some(_) = ast::RecordPatField::for_field_name(name) {
473 if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
474 return Some((
475 TextRange::empty(ident_pat.syntax().text_range().start()),
476 [new_name, ": "].concat(),
477 ));
478 }
479 }
480 None
481}
482
483fn source_edit_from_name_ref(
484 name_ref: &ast::NameRef,
485 new_name: &str,
486 def: Definition,
487) -> Option<(TextRange, String)> {
488 if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
489 let rcf_name_ref = record_field.name_ref();
490 let rcf_expr = record_field.expr();
491 match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) {
492 // field: init-expr, check if we can use a field init shorthand
493 (Some(field_name), Some(init)) => {
494 if field_name == *name_ref {
495 if init.text() == new_name {
496 cov_mark::hit!(test_rename_field_put_init_shorthand);
497 // same names, we can use a shorthand here instead.
498 // we do not want to erase attributes hence this range start
499 let s = field_name.syntax().text_range().start();
500 let e = record_field.syntax().text_range().end();
501 return Some((TextRange::new(s, e), new_name.to_owned()));
502 }
503 } else if init == *name_ref {
504 if field_name.text() == new_name {
505 cov_mark::hit!(test_rename_local_put_init_shorthand);
506 // same names, we can use a shorthand here instead.
507 // we do not want to erase attributes hence this range start
508 let s = field_name.syntax().text_range().start();
509 let e = record_field.syntax().text_range().end();
510 return Some((TextRange::new(s, e), new_name.to_owned()));
511 }
512 }
513 None
514 }
515 // init shorthand
516 // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
517 // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
518 (None, Some(_)) if matches!(def, Definition::Field(_)) => {
519 cov_mark::hit!(test_rename_field_in_field_shorthand);
520 let s = name_ref.syntax().text_range().start();
521 Some((TextRange::empty(s), format!("{}: ", new_name)))
522 }
523 (None, Some(_)) if matches!(def, Definition::Local(_)) => {
524 cov_mark::hit!(test_rename_local_in_field_shorthand);
525 let s = name_ref.syntax().text_range().end();
526 Some((TextRange::empty(s), format!(": {}", new_name)))
527 }
528 _ => None,
529 }
530 } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
531 let rcf_name_ref = record_field.name_ref();
532 let rcf_pat = record_field.pat();
533 match (rcf_name_ref, rcf_pat) {
534 // field: rename
535 (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => {
536 // field name is being renamed
537 if pat.name().map_or(false, |it| it.text() == new_name) {
538 cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
539 // same names, we can use a shorthand here instead/
540 // we do not want to erase attributes hence this range start
541 let s = field_name.syntax().text_range().start();
542 let e = record_field.syntax().text_range().end();
543 Some((TextRange::new(s, e), pat.to_string()))
544 } else {
545 None
546 }
547 }
548 _ => None,
549 }
550 } else {
551 None
552 }
553}
554
555fn source_edit_from_def(
556 sema: &Semantics<RootDatabase>,
557 def: Definition,
558 new_name: &str,
559) -> RenameResult<(FileId, TextEdit)> {
560 let nav =
561 def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?;
562
563 let mut replacement_text = String::new();
564 let mut repl_range =
565 nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?;
566 if let Definition::Local(local) = def {
567 if let Either::Left(pat) = local.source(sema.db).value {
568 if matches!(
569 pat.syntax().parent().and_then(ast::RecordPatField::cast),
570 Some(pat_field) if pat_field.name_ref().is_none()
571 ) {
572 replacement_text.push_str(": ");
573 replacement_text.push_str(new_name);
574 repl_range = TextRange::new(
575 pat.syntax().text_range().end(),
576 pat.syntax().text_range().end(),
577 );
578 }
579 }
580 }
581 if replacement_text.is_empty() {
582 replacement_text.push_str(new_name);
583 }
584 let edit = TextEdit::replace(repl_range, replacement_text);
585 Ok((nav.file_id, edit))
586}
587
588#[cfg(test)] 255#[cfg(test)]
589mod tests { 256mod tests {
590 use expect_test::{expect, Expect}; 257 use expect_test::{expect, Expect};
@@ -691,7 +358,7 @@ fn baz() {
691 x.0$0 = 5; 358 x.0$0 = 5;
692} 359}
693"#, 360"#,
694 expect![[r#"No identifier available to rename"#]], 361 expect![[r#"No references found at position"#]],
695 ); 362 );
696 } 363 }
697 364
@@ -703,7 +370,7 @@ fn foo() {
703 let x: i32$0 = 0; 370 let x: i32$0 = 0;
704} 371}
705"#, 372"#,
706 expect![[r#"Cannot rename builtin type"#]], 373 expect![[r#"No references found at position"#]],
707 ); 374 );
708 } 375 }
709 376
@@ -719,7 +386,7 @@ impl Foo {
719 } 386 }
720} 387}
721"#, 388"#,
722 expect![[r#"Cannot rename `Self`"#]], 389 expect![[r#"No references found at position"#]],
723 ); 390 );
724 } 391 }
725 392
@@ -801,7 +468,6 @@ impl Foo {
801 468
802 #[test] 469 #[test]
803 fn test_rename_for_local() { 470 fn test_rename_for_local() {
804 cov_mark::check!(rename_local);
805 check( 471 check(
806 "k", 472 "k",
807 r#" 473 r#"
@@ -2101,4 +1767,22 @@ fn f() { <()>::BAR$0; }"#,
2101 res, 1767 res,
2102 ); 1768 );
2103 } 1769 }
1770
1771 #[test]
1772 fn macros_are_broken_lol() {
1773 cov_mark::check!(macros_are_broken_lol);
1774 check(
1775 "lol",
1776 r#"
1777macro_rules! m { () => { fn f() {} } }
1778m!();
1779fn main() { f$0() }
1780"#,
1781 r#"
1782macro_rules! m { () => { fn f() {} } }
1783lol
1784fn main() { lol() }
1785"#,
1786 )
1787 }
2104} 1788}
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e186b82b7..d44a1b45f 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -294,7 +294,7 @@ fn traverse(
294 Some(parent) => { 294 Some(parent) => {
295 // We only care Name and Name_ref 295 // We only care Name and Name_ref
296 match (token.kind(), parent.kind()) { 296 match (token.kind(), parent.kind()) {
297 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), 297 (IDENT, NAME | NAME_REF) => parent.into(),
298 _ => token.into(), 298 _ => token.into(),
299 } 299 }
300 } 300 }
@@ -310,7 +310,7 @@ fn traverse(
310 Some(parent) => { 310 Some(parent) => {
311 // We only care Name and Name_ref 311 // We only care Name and Name_ref
312 match (token.kind(), parent.kind()) { 312 match (token.kind(), parent.kind()) {
313 (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), 313 (IDENT, NAME | NAME_REF) => parent.into(),
314 _ => token.into(), 314 _ => token.into(),
315 } 315 }
316 } 316 }
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 7a53268e8..6834fe11a 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -48,7 +48,13 @@ pub(super) fn element(
48 match name_kind { 48 match name_kind {
49 Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), 49 Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(),
50 Some(NameClass::Definition(def)) => { 50 Some(NameClass::Definition(def)) => {
51 highlight_def(db, krate, def) | HlMod::Definition 51 let mut h = highlight_def(db, krate, def) | HlMod::Definition;
52 if let Definition::ModuleDef(hir::ModuleDef::Trait(trait_)) = &def {
53 if trait_.is_unsafe(db) {
54 h |= HlMod::Unsafe;
55 }
56 }
57 h
52 } 58 }
53 Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), 59 Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def),
54 Some(NameClass::PatFieldShorthand { field_ref, .. }) => { 60 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
@@ -87,20 +93,34 @@ pub(super) fn element(
87 93
88 let mut h = highlight_def(db, krate, def); 94 let mut h = highlight_def(db, krate, def);
89 95
90 if let Definition::Local(local) = &def { 96 match def {
91 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { 97 Definition::Local(local)
98 if is_consumed_lvalue(
99 name_ref.syntax().clone().into(),
100 &local,
101 db,
102 ) =>
103 {
92 h |= HlMod::Consuming; 104 h |= HlMod::Consuming;
93 } 105 }
94 } 106 Definition::ModuleDef(hir::ModuleDef::Trait(trait_))
95 107 if trait_.is_unsafe(db) =>
96 if let Some(parent) = name_ref.syntax().parent() { 108 {
97 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { 109 if ast::Impl::for_trait_name_ref(&name_ref).is_some() {
98 if let Definition::Field(field) = def { 110 h |= HlMod::Unsafe;
99 if let hir::VariantDef::Union(_) = field.parent_def(db) { 111 }
100 h |= HlMod::Unsafe; 112 }
113 Definition::Field(field) => {
114 if let Some(parent) = name_ref.syntax().parent() {
115 if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
116 if let hir::VariantDef::Union(_) = field.parent_def(db)
117 {
118 h |= HlMod::Unsafe;
119 }
101 } 120 }
102 } 121 }
103 } 122 }
123 _ => (),
104 } 124 }
105 125
106 h 126 h
@@ -354,15 +374,7 @@ fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition)
354 374
355 h 375 h
356 } 376 }
357 hir::ModuleDef::Trait(trait_) => { 377 hir::ModuleDef::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)),
358 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait));
359
360 if trait_.is_unsafe(db) {
361 h |= HlMod::Unsafe;
362 }
363
364 h
365 }
366 hir::ModuleDef::TypeAlias(type_) => { 378 hir::ModuleDef::TypeAlias(type_) => {
367 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 379 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
368 380
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 478facfee..21376a7ae 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -67,6 +67,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
67.field { color: #94BFF3; } 67.field { color: #94BFF3; }
68.function { color: #93E0E3; } 68.function { color: #93E0E3; }
69.function.unsafe { color: #BC8383; } 69.function.unsafe { color: #BC8383; }
70.trait.unsafe { color: #BC8383; }
70.operator.unsafe { color: #BC8383; } 71.operator.unsafe { color: #BC8383; }
71.parameter { color: #94BFF3; } 72.parameter { color: #94BFF3; }
72.text { color: #DCDCCC; } 73.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index a0ea1db34..4e85f7c0b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 921a956e6..79a285107 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index ca9bb1e7d..13f589cc0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 6202a03ce..50df376ae 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index e860d713e..96cb09642 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 68165bdbf..55453468b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
@@ -61,6 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
61 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> 62 <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
62<span class="brace">}</span> 63<span class="brace">}</span>
63 64
65<span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">UnsafeTrait</span> <span class="brace">{</span><span class="brace">}</span>
66<span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="struct">Packed</span> <span class="brace">{</span><span class="brace">}</span>
67
68<span class="keyword">fn</span> <span class="function declaration">require_unsafe_trait</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
69
64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 70<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
65 <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 71 <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66<span class="brace">}</span> 72<span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 59f1e8e4c..9232cf905 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html
index 9ab46d05c..082837328 100644
--- a/crates/ide/src/syntax_highlighting/test_data/injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/injection.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
index 666b0b228..763917714 100644
--- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
15.field { color: #94BFF3; } 15.field { color: #94BFF3; }
16.function { color: #93E0E3; } 16.function { color: #93E0E3; }
17.function.unsafe { color: #BC8383; } 17.function.unsafe { color: #BC8383; }
18.trait.unsafe { color: #BC8383; }
18.operator.unsafe { color: #BC8383; } 19.operator.unsafe { color: #BC8383; }
19.parameter { color: #94BFF3; } 20.parameter { color: #94BFF3; }
20.text { color: #DCDCCC; } 21.text { color: #DCDCCC; }
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index f7d8334a0..4f0b1ce85 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -527,6 +527,11 @@ struct Packed {
527 a: u16, 527 a: u16,
528} 528}
529 529
530unsafe trait UnsafeTrait {}
531unsafe impl UnsafeTrait for Packed {}
532
533fn require_unsafe_trait<T: UnsafeTrait>(_: T) {}
534
530trait DoTheAutoref { 535trait DoTheAutoref {
531 fn calls_autoref(&self); 536 fn calls_autoref(&self);
532} 537}
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 4ad49eca0..37ae92350 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@ use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, Parse, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{self, FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
@@ -95,9 +95,16 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<
95 } 95 }
96 96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; 97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98 if brace_token.kind() != SyntaxKind::L_CURLY {
99 return None;
100 }
98 101
99 // Remove the `{` to get a better parse tree, and reparse 102 // Remove the `{` to get a better parse tree, and reparse.
100 let file = file.reparse(&Indel::delete(brace_token.text_range())); 103 let range = brace_token.text_range();
104 if !stdx::always!(range.len() == TextSize::of('{')) {
105 return None;
106 }
107 let file = file.reparse(&Indel::delete(range));
101 108
102 if let Some(edit) = brace_expr(&file.tree(), offset) { 109 if let Some(edit) = brace_expr(&file.tree(), offset) {
103 return Some(edit); 110 return Some(edit);
@@ -550,6 +557,29 @@ fn f() {
550 } 557 }
551 558
552 #[test] 559 #[test]
560 fn noop_in_string_literal() {
561 // Regression test for #9351
562 type_char_noop(
563 '{',
564 r##"
565fn check_with(ra_fixture: &str, expect: Expect) {
566 let base = r#"
567enum E { T(), R$0, C }
568use self::E::X;
569const Z: E = E::C;
570mod m {}
571asdasdasdasdasdasda
572sdasdasdasdasdasda
573sdasdasdasdasd
574"#;
575 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
576 expect.assert_eq(&actual)
577}
578 "##,
579 );
580 }
581
582 #[test]
553 fn adds_closing_brace_for_use_tree() { 583 fn adds_closing_brace_for_use_tree() {
554 type_char( 584 type_char(
555 '{', 585 '{',
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs
index c93959e66..e2bd6e456 100644
--- a/crates/ide_assists/src/handlers/apply_demorgan.rs
+++ b/crates/ide_assists/src/handlers/apply_demorgan.rs
@@ -147,74 +147,92 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
147 147
148#[cfg(test)] 148#[cfg(test)]
149mod tests { 149mod tests {
150 use ide_db::helpers::FamousDefs;
151
152 use super::*;
153
154 use crate::tests::{check_assist, check_assist_not_applicable}; 150 use crate::tests::{check_assist, check_assist_not_applicable};
155 151
156 const ORDABLE_FIXTURE: &'static str = r" 152 use super::*;
157//- /lib.rs deps:core crate:ordable
158struct NonOrderable;
159struct Orderable;
160impl core::cmp::Ord for Orderable {}
161";
162
163 fn check(ra_fixture_before: &str, ra_fixture_after: &str) {
164 let before = &format!(
165 "//- /main.rs crate:main deps:core,ordable\n{}\n{}{}",
166 ra_fixture_before,
167 FamousDefs::FIXTURE,
168 ORDABLE_FIXTURE
169 );
170 check_assist(apply_demorgan, before, &format!("{}\n", ra_fixture_after));
171 }
172 153
173 #[test] 154 #[test]
174 fn demorgan_handles_leq() { 155 fn demorgan_handles_leq() {
175 check( 156 check_assist(
176 r"use ordable::Orderable; 157 apply_demorgan,
158 r#"
159//- minicore: ord, derive
160#[derive(PartialEq, Eq, PartialOrd, Ord)]
161struct S;
162
177fn f() { 163fn f() {
178 Orderable < Orderable &&$0 Orderable <= Orderable 164 S < S &&$0 S <= S
179}", 165}
180 r"use ordable::Orderable; 166"#,
167 r#"
168#[derive(PartialEq, Eq, PartialOrd, Ord)]
169struct S;
170
181fn f() { 171fn f() {
182 !(Orderable >= Orderable || Orderable > Orderable) 172 !(S >= S || S > S)
183}", 173}
174"#,
184 ); 175 );
185 check( 176
186 r"use ordable::NonOrderable; 177 check_assist(
178 apply_demorgan,
179 r#"
180//- minicore: ord, derive
181struct S;
182
187fn f() { 183fn f() {
188 NonOrderable < NonOrderable &&$0 NonOrderable <= NonOrderable 184 S < S &&$0 S <= S
189}", 185}
190 r"use ordable::NonOrderable; 186"#,
187 r#"
188struct S;
189
191fn f() { 190fn f() {
192 !(!(NonOrderable < NonOrderable) || !(NonOrderable <= NonOrderable)) 191 !(!(S < S) || !(S <= S))
193}", 192}
193"#,
194 ); 194 );
195 } 195 }
196 196
197 #[test] 197 #[test]
198 fn demorgan_handles_geq() { 198 fn demorgan_handles_geq() {
199 check( 199 check_assist(
200 r"use ordable::Orderable; 200 apply_demorgan,
201 r#"
202//- minicore: ord, derive
203#[derive(PartialEq, Eq, PartialOrd, Ord)]
204struct S;
205
201fn f() { 206fn f() {
202 Orderable > Orderable &&$0 Orderable >= Orderable 207 S > S &&$0 S >= S
203}", 208}
204 r"use ordable::Orderable; 209"#,
210 r#"
211#[derive(PartialEq, Eq, PartialOrd, Ord)]
212struct S;
213
205fn f() { 214fn f() {
206 !(Orderable <= Orderable || Orderable < Orderable) 215 !(S <= S || S < S)
207}", 216}
217"#,
208 ); 218 );
209 check( 219 check_assist(
210 r"use ordable::NonOrderable; 220 apply_demorgan,
221 r#"
222//- minicore: ord, derive
223struct S;
224
211fn f() { 225fn f() {
212 Orderable > Orderable &&$0 Orderable >= Orderable 226 S > S &&$0 S >= S
213}", 227}
214 r"use ordable::NonOrderable; 228"#,
229 r#"
230struct S;
231
215fn f() { 232fn f() {
216 !(!(Orderable > Orderable) || !(Orderable >= Orderable)) 233 !(!(S > S) || !(S >= S))
217}", 234}
235"#,
218 ); 236 );
219 } 237 }
220 238
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index d4748ef3a..accc345fc 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -103,8 +103,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
103 let scope = match scope.clone() { 103 let scope = match scope.clone() {
104 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), 104 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
105 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), 105 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
106 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
106 }; 107 };
107 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); 108 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
108 }, 109 },
109 ); 110 );
110 } 111 }
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs
index 199e1ad5c..2d8b936cd 100644
--- a/crates/ide_assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs
@@ -6,15 +6,14 @@ use syntax::ast::{self, AstNode, NameOwner};
6 6
7use crate::{AssistContext, AssistId, AssistKind, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
8 8
9// FIXME: this should be a diagnostic
10
9// Assist: convert_into_to_from 11// Assist: convert_into_to_from
10// 12//
11// Converts an Into impl to an equivalent From impl. 13// Converts an Into impl to an equivalent From impl.
12// 14//
13// ``` 15// ```
14// # //- /lib.rs crate:core 16// # //- minicore: from
15// # pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } }
16// # //- /lib.rs crate:main deps:core
17// # use core::convert::Into;
18// impl $0Into<Thing> for usize { 17// impl $0Into<Thing> for usize {
19// fn into(self) -> Thing { 18// fn into(self) -> Thing {
20// Thing { 19// Thing {
@@ -26,7 +25,6 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
26// ``` 25// ```
27// -> 26// ->
28// ``` 27// ```
29// # use core::convert::Into;
30// impl From<usize> for Thing { 28// impl From<usize> for Thing {
31// fn from(val: usize) -> Self { 29// fn from(val: usize) -> Self {
32// Thing { 30// Thing {
@@ -114,12 +112,14 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Op
114mod tests { 112mod tests {
115 use super::*; 113 use super::*;
116 114
117 use crate::tests::check_assist; 115 use crate::tests::{check_assist, check_assist_not_applicable};
118 116
119 #[test] 117 #[test]
120 fn convert_into_to_from_converts_a_struct() { 118 fn convert_into_to_from_converts_a_struct() {
121 check_convert_into_to_from( 119 check_assist(
120 convert_into_to_from,
122 r#" 121 r#"
122//- minicore: from
123struct Thing { 123struct Thing {
124 a: String, 124 a: String,
125 b: usize 125 b: usize
@@ -154,8 +154,10 @@ impl From<usize> for Thing {
154 154
155 #[test] 155 #[test]
156 fn convert_into_to_from_converts_enums() { 156 fn convert_into_to_from_converts_enums() {
157 check_convert_into_to_from( 157 check_assist(
158 convert_into_to_from,
158 r#" 159 r#"
160//- minicore: from
159enum Thing { 161enum Thing {
160 Foo(String), 162 Foo(String),
161 Bar(String) 163 Bar(String)
@@ -190,8 +192,10 @@ impl From<Thing> for String {
190 192
191 #[test] 193 #[test]
192 fn convert_into_to_from_on_enum_with_lifetimes() { 194 fn convert_into_to_from_on_enum_with_lifetimes() {
193 check_convert_into_to_from( 195 check_assist(
196 convert_into_to_from,
194 r#" 197 r#"
198//- minicore: from
195enum Thing<'a> { 199enum Thing<'a> {
196 Foo(&'a str), 200 Foo(&'a str),
197 Bar(&'a str) 201 Bar(&'a str)
@@ -226,8 +230,10 @@ impl<'a> From<Thing<'a>> for &'a str {
226 230
227 #[test] 231 #[test]
228 fn convert_into_to_from_works_on_references() { 232 fn convert_into_to_from_works_on_references() {
229 check_convert_into_to_from( 233 check_assist(
234 convert_into_to_from,
230 r#" 235 r#"
236//- minicore: from
231struct Thing(String); 237struct Thing(String);
232 238
233impl $0core::convert::Into<String> for &Thing { 239impl $0core::convert::Into<String> for &Thing {
@@ -250,8 +256,10 @@ impl From<&Thing> for String {
250 256
251 #[test] 257 #[test]
252 fn convert_into_to_from_works_on_qualified_structs() { 258 fn convert_into_to_from_works_on_qualified_structs() {
253 check_convert_into_to_from( 259 check_assist(
260 convert_into_to_from,
254 r#" 261 r#"
262//- minicore: from
255mod things { 263mod things {
256 pub struct Thing(String); 264 pub struct Thing(String);
257 pub struct BetterThing(String); 265 pub struct BetterThing(String);
@@ -280,8 +288,10 @@ impl From<&things::Thing> for things::BetterThing {
280 288
281 #[test] 289 #[test]
282 fn convert_into_to_from_works_on_qualified_enums() { 290 fn convert_into_to_from_works_on_qualified_enums() {
283 check_convert_into_to_from( 291 check_assist(
292 convert_into_to_from,
284 r#" 293 r#"
294//- minicore: from
285mod things { 295mod things {
286 pub enum Thing { 296 pub enum Thing {
287 A(String) 297 A(String)
@@ -323,10 +333,12 @@ impl From<&things::Thing> for things::BetterThing {
323 #[test] 333 #[test]
324 fn convert_into_to_from_not_applicable_on_any_trait_named_into() { 334 fn convert_into_to_from_not_applicable_on_any_trait_named_into() {
325 check_assist_not_applicable( 335 check_assist_not_applicable(
336 convert_into_to_from,
326 r#" 337 r#"
327pub trait Into<T> {{ 338//- minicore: from
339pub trait Into<T> {
328 pub fn into(self) -> T; 340 pub fn into(self) -> T;
329}} 341}
330 342
331struct Thing { 343struct Thing {
332 a: String, 344 a: String,
@@ -342,14 +354,4 @@ impl $0Into<Thing> for String {
342"#, 354"#,
343 ); 355 );
344 } 356 }
345
346 fn check_convert_into_to_from(before: &str, after: &str) {
347 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
348 check_assist(convert_into_to_from, before, after);
349 }
350
351 fn check_assist_not_applicable(before: &str) {
352 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
353 crate::tests::check_assist_not_applicable(convert_into_to_from, before);
354 }
355} 357}
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index 4e75a7b14..70754adf9 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -11,14 +11,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
11// Converts an Iterator::for_each function into a for loop. 11// Converts an Iterator::for_each function into a for loop.
12// 12//
13// ``` 13// ```
14// # //- /lib.rs crate:core 14// # //- minicore: iterators
15// # pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } } 15// # use core::iter;
16// # pub struct SomeIter;
17// # impl self::iter::traits::iterator::Iterator for SomeIter {}
18// # //- /lib.rs crate:main deps:core
19// # use core::SomeIter;
20// fn main() { 16// fn main() {
21// let iter = SomeIter; 17// let iter = iter::repeat((9, 2));
22// iter.for_each$0(|(x, y)| { 18// iter.for_each$0(|(x, y)| {
23// println!("x: {}, y: {}", x, y); 19// println!("x: {}, y: {}", x, y);
24// }); 20// });
@@ -26,9 +22,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
26// ``` 22// ```
27// -> 23// ->
28// ``` 24// ```
29// # use core::SomeIter; 25// # use core::iter;
30// fn main() { 26// fn main() {
31// let iter = SomeIter; 27// let iter = iter::repeat((9, 2));
32// for (x, y) in iter { 28// for (x, y) in iter {
33// println!("x: {}, y: {}", x, y); 29// println!("x: {}, y: {}", x, y);
34// } 30// }
@@ -77,9 +73,11 @@ fn validate_method_call_expr(
77 expr: ast::MethodCallExpr, 73 expr: ast::MethodCallExpr,
78) -> Option<(ast::Expr, ast::Expr)> { 74) -> Option<(ast::Expr, ast::Expr)> {
79 let name_ref = expr.name_ref()?; 75 let name_ref = expr.name_ref()?;
80 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() 76 if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() {
81 || name_ref.text() != "for_each" 77 cov_mark::hit!(test_for_each_not_applicable_invalid_cursor_pos);
82 { 78 return None;
79 }
80 if name_ref.text() != "for_each" {
83 return None; 81 return None;
84 } 82 }
85 83
@@ -98,59 +96,27 @@ fn validate_method_call_expr(
98 96
99#[cfg(test)] 97#[cfg(test)]
100mod tests { 98mod tests {
101 use crate::tests::{self, check_assist}; 99 use crate::tests::{check_assist, check_assist_not_applicable};
102 100
103 use super::*; 101 use super::*;
104 102
105 const EMPTY_ITER_FIXTURE: &'static str = r"
106//- /lib.rs deps:core crate:empty_iter
107pub struct EmptyIter;
108impl Iterator for EmptyIter {
109 type Item = usize;
110 fn next(&mut self) -> Option<Self::Item> { None }
111}
112pub struct Empty;
113impl Empty {
114 pub fn iter(&self) -> EmptyIter { EmptyIter }
115}
116";
117
118 fn check_assist_with_fixtures(before: &str, after: &str) {
119 let before = &format!(
120 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
121 before,
122 EMPTY_ITER_FIXTURE,
123 FamousDefs::FIXTURE,
124 );
125 check_assist(convert_iter_for_each_to_for, before, after);
126 }
127
128 fn check_assist_not_applicable(before: &str) {
129 let before = &format!(
130 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
131 before,
132 EMPTY_ITER_FIXTURE,
133 FamousDefs::FIXTURE,
134 );
135 tests::check_assist_not_applicable(convert_iter_for_each_to_for, before);
136 }
137
138 #[test] 103 #[test]
139 fn test_for_each_in_method_stmt() { 104 fn test_for_each_in_method_stmt() {
140 check_assist_with_fixtures( 105 check_assist(
106 convert_iter_for_each_to_for,
141 r#" 107 r#"
142use empty_iter::*; 108//- minicore: iterators
143fn main() { 109fn main() {
144 let x = Empty; 110 let it = core::iter::repeat(92);
145 x.iter().$0for_each(|(x, y)| { 111 it.$0for_each(|(x, y)| {
146 println!("x: {}, y: {}", x, y); 112 println!("x: {}, y: {}", x, y);
147 }); 113 });
148}"#, 114}
115"#,
149 r#" 116 r#"
150use empty_iter::*;
151fn main() { 117fn main() {
152 let x = Empty; 118 let it = core::iter::repeat(92);
153 for (x, y) in x.iter() { 119 for (x, y) in it {
154 println!("x: {}, y: {}", x, y); 120 println!("x: {}, y: {}", x, y);
155 } 121 }
156} 122}
@@ -160,43 +126,21 @@ fn main() {
160 126
161 #[test] 127 #[test]
162 fn test_for_each_in_method() { 128 fn test_for_each_in_method() {
163 check_assist_with_fixtures( 129 check_assist(
130 convert_iter_for_each_to_for,
164 r#" 131 r#"
165use empty_iter::*; 132//- minicore: iterators
166fn main() { 133fn main() {
167 let x = Empty; 134 let it = core::iter::repeat(92);
168 x.iter().$0for_each(|(x, y)| { 135 it.$0for_each(|(x, y)| {
169 println!("x: {}, y: {}", x, y); 136 println!("x: {}, y: {}", x, y);
170 }) 137 })
171}"#,
172 r#"
173use empty_iter::*;
174fn main() {
175 let x = Empty;
176 for (x, y) in x.iter() {
177 println!("x: {}, y: {}", x, y);
178 }
179} 138}
180"#, 139"#,
181 )
182 }
183
184 #[test]
185 fn test_for_each_in_iter_stmt() {
186 check_assist_with_fixtures(
187 r#"
188use empty_iter::*;
189fn main() {
190 let x = Empty.iter();
191 x.$0for_each(|(x, y)| {
192 println!("x: {}, y: {}", x, y);
193 });
194}"#,
195 r#" 140 r#"
196use empty_iter::*;
197fn main() { 141fn main() {
198 let x = Empty.iter(); 142 let it = core::iter::repeat(92);
199 for (x, y) in x { 143 for (x, y) in it {
200 println!("x: {}, y: {}", x, y); 144 println!("x: {}, y: {}", x, y);
201 } 145 }
202} 146}
@@ -206,18 +150,19 @@ fn main() {
206 150
207 #[test] 151 #[test]
208 fn test_for_each_without_braces_stmt() { 152 fn test_for_each_without_braces_stmt() {
209 check_assist_with_fixtures( 153 check_assist(
154 convert_iter_for_each_to_for,
210 r#" 155 r#"
211use empty_iter::*; 156//- minicore: iterators
212fn main() { 157fn main() {
213 let x = Empty; 158 let it = core::iter::repeat(92);
214 x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); 159 it.$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
215}"#, 160}
161"#,
216 r#" 162 r#"
217use empty_iter::*;
218fn main() { 163fn main() {
219 let x = Empty; 164 let it = core::iter::repeat(92);
220 for (x, y) in x.iter() { 165 for (x, y) in it {
221 println!("x: {}, y: {}", x, y) 166 println!("x: {}, y: {}", x, y)
222 } 167 }
223} 168}
@@ -228,7 +173,9 @@ fn main() {
228 #[test] 173 #[test]
229 fn test_for_each_not_applicable() { 174 fn test_for_each_not_applicable() {
230 check_assist_not_applicable( 175 check_assist_not_applicable(
176 convert_iter_for_each_to_for,
231 r#" 177 r#"
178//- minicore: iterators
232fn main() { 179fn main() {
233 ().$0for_each(|x| println!("{}", x)); 180 ().$0for_each(|x| println!("{}", x));
234}"#, 181}"#,
@@ -237,11 +184,13 @@ fn main() {
237 184
238 #[test] 185 #[test]
239 fn test_for_each_not_applicable_invalid_cursor_pos() { 186 fn test_for_each_not_applicable_invalid_cursor_pos() {
187 cov_mark::check!(test_for_each_not_applicable_invalid_cursor_pos);
240 check_assist_not_applicable( 188 check_assist_not_applicable(
189 convert_iter_for_each_to_for,
241 r#" 190 r#"
242use empty_iter::*; 191//- minicore: iterators
243fn main() { 192fn main() {
244 Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y)); 193 core::iter::repeat(92).for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
245}"#, 194}"#,
246 ) 195 )
247 } 196 }
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index f2be091f4..870d4f665 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -109,10 +109,15 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
109 109
110 let new_indent = IndentLevel::from_node(&insert_after); 110 let new_indent = IndentLevel::from_node(&insert_after);
111 let old_indent = fun.body.indent_level(); 111 let old_indent = fun.body.indent_level();
112 let body_contains_await = body_contains_await(&fun.body);
112 113
113 builder.replace(target_range, format_replacement(ctx, &fun, old_indent)); 114 builder.replace(
115 target_range,
116 format_replacement(ctx, &fun, old_indent, body_contains_await),
117 );
114 118
115 let fn_def = format_function(ctx, module, &fun, old_indent, new_indent); 119 let fn_def =
120 format_function(ctx, module, &fun, old_indent, new_indent, body_contains_await);
116 let insert_offset = insert_after.text_range().end(); 121 let insert_offset = insert_after.text_range().end();
117 match ctx.config.snippet_cap { 122 match ctx.config.snippet_cap {
118 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), 123 Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
@@ -954,7 +959,12 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode, anchor: Anchor) -> Option<Synt
954 last_ancestor 959 last_ancestor
955} 960}
956 961
957fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String { 962fn format_replacement(
963 ctx: &AssistContext,
964 fun: &Function,
965 indent: IndentLevel,
966 body_contains_await: bool,
967) -> String {
958 let ret_ty = fun.return_type(ctx); 968 let ret_ty = fun.return_type(ctx);
959 969
960 let args = fun.params.iter().map(|param| param.to_arg(ctx)); 970 let args = fun.params.iter().map(|param| param.to_arg(ctx));
@@ -994,6 +1004,9 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel)
994 } 1004 }
995 } 1005 }
996 format_to!(buf, "{}", expr); 1006 format_to!(buf, "{}", expr);
1007 if body_contains_await {
1008 buf.push_str(".await");
1009 }
997 if fun.ret_ty.is_unit() 1010 if fun.ret_ty.is_unit()
998 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) 1011 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like())
999 { 1012 {
@@ -1122,12 +1135,13 @@ fn format_function(
1122 fun: &Function, 1135 fun: &Function,
1123 old_indent: IndentLevel, 1136 old_indent: IndentLevel,
1124 new_indent: IndentLevel, 1137 new_indent: IndentLevel,
1138 body_contains_await: bool,
1125) -> String { 1139) -> String {
1126 let mut fn_def = String::new(); 1140 let mut fn_def = String::new();
1127 let params = make_param_list(ctx, module, fun); 1141 let params = make_param_list(ctx, module, fun);
1128 let ret_ty = make_ret_ty(ctx, module, fun); 1142 let ret_ty = make_ret_ty(ctx, module, fun);
1129 let body = make_body(ctx, old_indent, new_indent, fun); 1143 let body = make_body(ctx, old_indent, new_indent, fun);
1130 let async_kw = if body_contains_await(&fun.body) { "async " } else { "" }; 1144 let async_kw = if body_contains_await { "async " } else { "" };
1131 match ctx.config.snippet_cap { 1145 match ctx.config.snippet_cap {
1132 Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), 1146 Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params),
1133 None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), 1147 None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params),
@@ -1384,7 +1398,7 @@ fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode)
1384 for (param, usages) in usages_for_param { 1398 for (param, usages) in usages_for_param {
1385 for usage in usages { 1399 for usage in usages {
1386 match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { 1400 match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) {
1387 Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => { 1401 Some(ast::Expr::MethodCallExpr(_) | ast::Expr::FieldExpr(_)) => {
1388 // do nothing 1402 // do nothing
1389 } 1403 }
1390 Some(ast::Expr::RefExpr(node)) 1404 Some(ast::Expr::RefExpr(node))
@@ -1501,7 +1515,8 @@ mod tests {
1501 r#" 1515 r#"
1502fn foo() { 1516fn foo() {
1503 foo($01 + 1$0); 1517 foo($01 + 1$0);
1504}"#, 1518}
1519"#,
1505 r#" 1520 r#"
1506fn foo() { 1521fn foo() {
1507 foo(fun_name()); 1522 foo(fun_name());
@@ -1509,7 +1524,8 @@ fn foo() {
1509 1524
1510fn $0fun_name() -> i32 { 1525fn $0fun_name() -> i32 {
1511 1 + 1 1526 1 + 1
1512}"#, 1527}
1528"#,
1513 ); 1529 );
1514 } 1530 }
1515 1531
@@ -1522,7 +1538,8 @@ mod bar {
1522 fn foo() { 1538 fn foo() {
1523 foo($01 + 1$0); 1539 foo($01 + 1$0);
1524 } 1540 }
1525}"#, 1541}
1542"#,
1526 r#" 1543 r#"
1527mod bar { 1544mod bar {
1528 fn foo() { 1545 fn foo() {
@@ -1532,7 +1549,8 @@ mod bar {
1532 fn $0fun_name() -> i32 { 1549 fn $0fun_name() -> i32 {
1533 1 + 1 1550 1 + 1
1534 } 1551 }
1535}"#, 1552}
1553"#,
1536 ); 1554 );
1537 } 1555 }
1538 1556
@@ -1543,7 +1561,8 @@ mod bar {
1543 r#" 1561 r#"
1544fn foo() { 1562fn foo() {
1545 $0{ 1 + 1 }$0; 1563 $0{ 1 + 1 }$0;
1546}"#, 1564}
1565"#,
1547 r#" 1566 r#"
1548fn foo() { 1567fn foo() {
1549 fun_name(); 1568 fun_name();
@@ -1551,7 +1570,8 @@ fn foo() {
1551 1570
1552fn $0fun_name() -> i32 { 1571fn $0fun_name() -> i32 {
1553 1 + 1 1572 1 + 1
1554}"#, 1573}
1574"#,
1555 ); 1575 );
1556 } 1576 }
1557 1577
@@ -1564,7 +1584,8 @@ fn foo() -> i32 {
1564 let k = 1; 1584 let k = 1;
1565 $0let m = 1; 1585 $0let m = 1;
1566 m + 1$0 1586 m + 1$0
1567}"#, 1587}
1588"#,
1568 r#" 1589 r#"
1569fn foo() -> i32 { 1590fn foo() -> i32 {
1570 let k = 1; 1591 let k = 1;
@@ -1574,7 +1595,8 @@ fn foo() -> i32 {
1574fn $0fun_name() -> i32 { 1595fn $0fun_name() -> i32 {
1575 let m = 1; 1596 let m = 1;
1576 m + 1 1597 m + 1
1577}"#, 1598}
1599"#,
1578 ); 1600 );
1579 } 1601 }
1580 1602
@@ -1588,7 +1610,8 @@ fn foo() {
1588 $0let m = 1; 1610 $0let m = 1;
1589 let n = m + 1;$0 1611 let n = m + 1;$0
1590 let g = 5; 1612 let g = 5;
1591}"#, 1613}
1614"#,
1592 r#" 1615 r#"
1593fn foo() { 1616fn foo() {
1594 let k = 3; 1617 let k = 3;
@@ -1599,7 +1622,8 @@ fn foo() {
1599fn $0fun_name() { 1622fn $0fun_name() {
1600 let m = 1; 1623 let m = 1;
1601 let n = m + 1; 1624 let n = m + 1;
1602}"#, 1625}
1626"#,
1603 ); 1627 );
1604 } 1628 }
1605 1629
@@ -1610,7 +1634,8 @@ fn $0fun_name() {
1610 r#" 1634 r#"
1611fn foo() { 1635fn foo() {
1612 $0if true { }$0 1636 $0if true { }$0
1613}"#, 1637}
1638"#,
1614 r#" 1639 r#"
1615fn foo() { 1640fn foo() {
1616 fun_name(); 1641 fun_name();
@@ -1618,7 +1643,8 @@ fn foo() {
1618 1643
1619fn $0fun_name() { 1644fn $0fun_name() {
1620 if true { } 1645 if true { }
1621}"#, 1646}
1647"#,
1622 ); 1648 );
1623 } 1649 }
1624 1650
@@ -1629,7 +1655,8 @@ fn $0fun_name() {
1629 r#" 1655 r#"
1630fn foo() -> i32 { 1656fn foo() -> i32 {
1631 $0if true { 1 } else { 2 }$0 1657 $0if true { 1 } else { 2 }$0
1632}"#, 1658}
1659"#,
1633 r#" 1660 r#"
1634fn foo() -> i32 { 1661fn foo() -> i32 {
1635 fun_name() 1662 fun_name()
@@ -1637,7 +1664,8 @@ fn foo() -> i32 {
1637 1664
1638fn $0fun_name() -> i32 { 1665fn $0fun_name() -> i32 {
1639 if true { 1 } else { 2 } 1666 if true { 1 } else { 2 }
1640}"#, 1667}
1668"#,
1641 ); 1669 );
1642 } 1670 }
1643 1671
@@ -1648,7 +1676,8 @@ fn $0fun_name() -> i32 {
1648 r#" 1676 r#"
1649fn foo() -> i32 { 1677fn foo() -> i32 {
1650 $0if let true = false { 1 } else { 2 }$0 1678 $0if let true = false { 1 } else { 2 }$0
1651}"#, 1679}
1680"#,
1652 r#" 1681 r#"
1653fn foo() -> i32 { 1682fn foo() -> i32 {
1654 fun_name() 1683 fun_name()
@@ -1656,7 +1685,8 @@ fn foo() -> i32 {
1656 1685
1657fn $0fun_name() -> i32 { 1686fn $0fun_name() -> i32 {
1658 if let true = false { 1 } else { 2 } 1687 if let true = false { 1 } else { 2 }
1659}"#, 1688}
1689"#,
1660 ); 1690 );
1661 } 1691 }
1662 1692
@@ -1670,7 +1700,8 @@ fn foo() -> i32 {
1670 true => 1, 1700 true => 1,
1671 false => 2, 1701 false => 2,
1672 }$0 1702 }$0
1673}"#, 1703}
1704"#,
1674 r#" 1705 r#"
1675fn foo() -> i32 { 1706fn foo() -> i32 {
1676 fun_name() 1707 fun_name()
@@ -1681,7 +1712,8 @@ fn $0fun_name() -> i32 {
1681 true => 1, 1712 true => 1,
1682 false => 2, 1713 false => 2,
1683 } 1714 }
1684}"#, 1715}
1716"#,
1685 ); 1717 );
1686 } 1718 }
1687 1719
@@ -1692,7 +1724,8 @@ fn $0fun_name() -> i32 {
1692 r#" 1724 r#"
1693fn foo() { 1725fn foo() {
1694 $0while true { }$0 1726 $0while true { }$0
1695}"#, 1727}
1728"#,
1696 r#" 1729 r#"
1697fn foo() { 1730fn foo() {
1698 fun_name(); 1731 fun_name();
@@ -1700,7 +1733,8 @@ fn foo() {
1700 1733
1701fn $0fun_name() { 1734fn $0fun_name() {
1702 while true { } 1735 while true { }
1703}"#, 1736}
1737"#,
1704 ); 1738 );
1705 } 1739 }
1706 1740
@@ -1711,7 +1745,8 @@ fn $0fun_name() {
1711 r#" 1745 r#"
1712fn foo() { 1746fn foo() {
1713 $0for v in &[0, 1] { }$0 1747 $0for v in &[0, 1] { }$0
1714}"#, 1748}
1749"#,
1715 r#" 1750 r#"
1716fn foo() { 1751fn foo() {
1717 fun_name(); 1752 fun_name();
@@ -1719,7 +1754,8 @@ fn foo() {
1719 1754
1720fn $0fun_name() { 1755fn $0fun_name() {
1721 for v in &[0, 1] { } 1756 for v in &[0, 1] { }
1722}"#, 1757}
1758"#,
1723 ); 1759 );
1724 } 1760 }
1725 1761
@@ -1732,7 +1768,8 @@ fn foo() {
1732 $0loop { 1768 $0loop {
1733 let m = 1; 1769 let m = 1;
1734 }$0 1770 }$0
1735}"#, 1771}
1772"#,
1736 r#" 1773 r#"
1737fn foo() { 1774fn foo() {
1738 fun_name() 1775 fun_name()
@@ -1742,7 +1779,8 @@ fn $0fun_name() -> ! {
1742 loop { 1779 loop {
1743 let m = 1; 1780 let m = 1;
1744 } 1781 }
1745}"#, 1782}
1783"#,
1746 ); 1784 );
1747 } 1785 }
1748 1786
@@ -1756,7 +1794,8 @@ fn foo() {
1756 let m = 1; 1794 let m = 1;
1757 break m; 1795 break m;
1758 }$0; 1796 }$0;
1759}"#, 1797}
1798"#,
1760 r#" 1799 r#"
1761fn foo() { 1800fn foo() {
1762 let v = fun_name(); 1801 let v = fun_name();
@@ -1767,7 +1806,8 @@ fn $0fun_name() -> i32 {
1767 let m = 1; 1806 let m = 1;
1768 break m; 1807 break m;
1769 } 1808 }
1770}"#, 1809}
1810"#,
1771 ); 1811 );
1772 } 1812 }
1773 1813
@@ -1781,7 +1821,8 @@ fn foo() {
1781 Some(x) => x, 1821 Some(x) => x,
1782 None => 0, 1822 None => 0,
1783 }$0; 1823 }$0;
1784}"#, 1824}
1825"#,
1785 r#" 1826 r#"
1786fn foo() { 1827fn foo() {
1787 let v: i32 = fun_name(); 1828 let v: i32 = fun_name();
@@ -1792,7 +1833,8 @@ fn $0fun_name() -> i32 {
1792 Some(x) => x, 1833 Some(x) => x,
1793 None => 0, 1834 None => 0,
1794 } 1835 }
1795}"#, 1836}
1837"#,
1796 ); 1838 );
1797 } 1839 }
1798 1840
@@ -1805,7 +1847,8 @@ fn foo() {
1805 let n = 1; 1847 let n = 1;
1806 let mut v = $0n * n;$0 1848 let mut v = $0n * n;$0
1807 v += 1; 1849 v += 1;
1808}"#, 1850}
1851"#,
1809 r#" 1852 r#"
1810fn foo() { 1853fn foo() {
1811 let n = 1; 1854 let n = 1;
@@ -1816,7 +1859,8 @@ fn foo() {
1816fn $0fun_name(n: i32) -> i32 { 1859fn $0fun_name(n: i32) -> i32 {
1817 let mut v = n * n; 1860 let mut v = n * n;
1818 v 1861 v
1819}"#, 1862}
1863"#,
1820 ); 1864 );
1821 } 1865 }
1822 1866
@@ -1832,7 +1876,8 @@ fn foo() {
1832 let mut w = 3;$0 1876 let mut w = 3;$0
1833 v += 1; 1877 v += 1;
1834 w += 1; 1878 w += 1;
1835}"#, 1879}
1880"#,
1836 r#" 1881 r#"
1837fn foo() { 1882fn foo() {
1838 let m = 2; 1883 let m = 2;
@@ -1846,7 +1891,8 @@ fn $0fun_name(m: i32, n: i32) -> (i32, i32) {
1846 let mut v = m * n; 1891 let mut v = m * n;
1847 let mut w = 3; 1892 let mut w = 3;
1848 (v, w) 1893 (v, w)
1849}"#, 1894}
1895"#,
1850 ); 1896 );
1851 } 1897 }
1852 1898
@@ -1854,12 +1900,13 @@ fn $0fun_name(m: i32, n: i32) -> (i32, i32) {
1854 fn argument_form_expr() { 1900 fn argument_form_expr() {
1855 check_assist( 1901 check_assist(
1856 extract_function, 1902 extract_function,
1857 r" 1903 r#"
1858fn foo() -> u32 { 1904fn foo() -> u32 {
1859 let n = 2; 1905 let n = 2;
1860 $0n+2$0 1906 $0n+2$0
1861}", 1907}
1862 r" 1908"#,
1909 r#"
1863fn foo() -> u32 { 1910fn foo() -> u32 {
1864 let n = 2; 1911 let n = 2;
1865 fun_name(n) 1912 fun_name(n)
@@ -1867,7 +1914,8 @@ fn foo() -> u32 {
1867 1914
1868fn $0fun_name(n: u32) -> u32 { 1915fn $0fun_name(n: u32) -> u32 {
1869 n+2 1916 n+2
1870}", 1917}
1918"#,
1871 ) 1919 )
1872 } 1920 }
1873 1921
@@ -1875,12 +1923,13 @@ fn $0fun_name(n: u32) -> u32 {
1875 fn argument_used_twice_form_expr() { 1923 fn argument_used_twice_form_expr() {
1876 check_assist( 1924 check_assist(
1877 extract_function, 1925 extract_function,
1878 r" 1926 r#"
1879fn foo() -> u32 { 1927fn foo() -> u32 {
1880 let n = 2; 1928 let n = 2;
1881 $0n+n$0 1929 $0n+n$0
1882}", 1930}
1883 r" 1931"#,
1932 r#"
1884fn foo() -> u32 { 1933fn foo() -> u32 {
1885 let n = 2; 1934 let n = 2;
1886 fun_name(n) 1935 fun_name(n)
@@ -1888,7 +1937,8 @@ fn foo() -> u32 {
1888 1937
1889fn $0fun_name(n: u32) -> u32 { 1938fn $0fun_name(n: u32) -> u32 {
1890 n+n 1939 n+n
1891}", 1940}
1941"#,
1892 ) 1942 )
1893 } 1943 }
1894 1944
@@ -1896,13 +1946,14 @@ fn $0fun_name(n: u32) -> u32 {
1896 fn two_arguments_form_expr() { 1946 fn two_arguments_form_expr() {
1897 check_assist( 1947 check_assist(
1898 extract_function, 1948 extract_function,
1899 r" 1949 r#"
1900fn foo() -> u32 { 1950fn foo() -> u32 {
1901 let n = 2; 1951 let n = 2;
1902 let m = 3; 1952 let m = 3;
1903 $0n+n*m$0 1953 $0n+n*m$0
1904}", 1954}
1905 r" 1955"#,
1956 r#"
1906fn foo() -> u32 { 1957fn foo() -> u32 {
1907 let n = 2; 1958 let n = 2;
1908 let m = 3; 1959 let m = 3;
@@ -1911,7 +1962,8 @@ fn foo() -> u32 {
1911 1962
1912fn $0fun_name(n: u32, m: u32) -> u32 { 1963fn $0fun_name(n: u32, m: u32) -> u32 {
1913 n+n*m 1964 n+n*m
1914}", 1965}
1966"#,
1915 ) 1967 )
1916 } 1968 }
1917 1969
@@ -1919,13 +1971,14 @@ fn $0fun_name(n: u32, m: u32) -> u32 {
1919 fn argument_and_locals() { 1971 fn argument_and_locals() {
1920 check_assist( 1972 check_assist(
1921 extract_function, 1973 extract_function,
1922 r" 1974 r#"
1923fn foo() -> u32 { 1975fn foo() -> u32 {
1924 let n = 2; 1976 let n = 2;
1925 $0let m = 1; 1977 $0let m = 1;
1926 n + m$0 1978 n + m$0
1927}", 1979}
1928 r" 1980"#,
1981 r#"
1929fn foo() -> u32 { 1982fn foo() -> u32 {
1930 let n = 2; 1983 let n = 2;
1931 fun_name(n) 1984 fun_name(n)
@@ -1934,7 +1987,8 @@ fn foo() -> u32 {
1934fn $0fun_name(n: u32) -> u32 { 1987fn $0fun_name(n: u32) -> u32 {
1935 let m = 1; 1988 let m = 1;
1936 n + m 1989 n + m
1937}", 1990}
1991"#,
1938 ) 1992 )
1939 } 1993 }
1940 1994
@@ -1948,18 +2002,20 @@ fn $0fun_name(n: u32) -> u32 {
1948 fn part_of_expr_stmt() { 2002 fn part_of_expr_stmt() {
1949 check_assist( 2003 check_assist(
1950 extract_function, 2004 extract_function,
1951 " 2005 r#"
1952fn foo() { 2006fn foo() {
1953 $01$0 + 1; 2007 $01$0 + 1;
1954}", 2008}
1955 " 2009"#,
2010 r#"
1956fn foo() { 2011fn foo() {
1957 fun_name() + 1; 2012 fun_name() + 1;
1958} 2013}
1959 2014
1960fn $0fun_name() -> i32 { 2015fn $0fun_name() -> i32 {
1961 1 2016 1
1962}", 2017}
2018"#,
1963 ); 2019 );
1964 } 2020 }
1965 2021
@@ -1970,7 +2026,8 @@ fn $0fun_name() -> i32 {
1970 r#" 2026 r#"
1971fn foo() { 2027fn foo() {
1972 $0bar(1 + 1)$0 2028 $0bar(1 + 1)$0
1973}"#, 2029}
2030"#,
1974 r#" 2031 r#"
1975fn foo() { 2032fn foo() {
1976 fun_name(); 2033 fun_name();
@@ -1978,7 +2035,8 @@ fn foo() {
1978 2035
1979fn $0fun_name() { 2036fn $0fun_name() {
1980 bar(1 + 1) 2037 bar(1 + 1)
1981}"#, 2038}
2039"#,
1982 ) 2040 )
1983 } 2041 }
1984 2042
@@ -1986,15 +2044,16 @@ fn $0fun_name() {
1986 fn extract_from_nested() { 2044 fn extract_from_nested() {
1987 check_assist( 2045 check_assist(
1988 extract_function, 2046 extract_function,
1989 r" 2047 r#"
1990fn main() { 2048fn main() {
1991 let x = true; 2049 let x = true;
1992 let tuple = match x { 2050 let tuple = match x {
1993 true => ($02 + 2$0, true) 2051 true => ($02 + 2$0, true)
1994 _ => (0, false) 2052 _ => (0, false)
1995 }; 2053 };
1996}", 2054}
1997 r" 2055"#,
2056 r#"
1998fn main() { 2057fn main() {
1999 let x = true; 2058 let x = true;
2000 let tuple = match x { 2059 let tuple = match x {
@@ -2005,7 +2064,8 @@ fn main() {
2005 2064
2006fn $0fun_name() -> i32 { 2065fn $0fun_name() -> i32 {
2007 2 + 2 2066 2 + 2
2008}", 2067}
2068"#,
2009 ); 2069 );
2010 } 2070 }
2011 2071
@@ -2013,18 +2073,20 @@ fn $0fun_name() -> i32 {
2013 fn param_from_closure() { 2073 fn param_from_closure() {
2014 check_assist( 2074 check_assist(
2015 extract_function, 2075 extract_function,
2016 r" 2076 r#"
2017fn main() { 2077fn main() {
2018 let lambda = |x: u32| $0x * 2$0; 2078 let lambda = |x: u32| $0x * 2$0;
2019}", 2079}
2020 r" 2080"#,
2081 r#"
2021fn main() { 2082fn main() {
2022 let lambda = |x: u32| fun_name(x); 2083 let lambda = |x: u32| fun_name(x);
2023} 2084}
2024 2085
2025fn $0fun_name(x: u32) -> u32 { 2086fn $0fun_name(x: u32) -> u32 {
2026 x * 2 2087 x * 2
2027}", 2088}
2089"#,
2028 ); 2090 );
2029 } 2091 }
2030 2092
@@ -2032,18 +2094,20 @@ fn $0fun_name(x: u32) -> u32 {
2032 fn extract_return_stmt() { 2094 fn extract_return_stmt() {
2033 check_assist( 2095 check_assist(
2034 extract_function, 2096 extract_function,
2035 r" 2097 r#"
2036fn foo() -> u32 { 2098fn foo() -> u32 {
2037 $0return 2 + 2$0; 2099 $0return 2 + 2$0;
2038}", 2100}
2039 r" 2101"#,
2102 r#"
2040fn foo() -> u32 { 2103fn foo() -> u32 {
2041 return fun_name(); 2104 return fun_name();
2042} 2105}
2043 2106
2044fn $0fun_name() -> u32 { 2107fn $0fun_name() -> u32 {
2045 2 + 2 2108 2 + 2
2046}", 2109}
2110"#,
2047 ); 2111 );
2048 } 2112 }
2049 2113
@@ -2051,13 +2115,14 @@ fn $0fun_name() -> u32 {
2051 fn does_not_add_extra_whitespace() { 2115 fn does_not_add_extra_whitespace() {
2052 check_assist( 2116 check_assist(
2053 extract_function, 2117 extract_function,
2054 r" 2118 r#"
2055fn foo() -> u32 { 2119fn foo() -> u32 {
2056 2120
2057 2121
2058 $0return 2 + 2$0; 2122 $0return 2 + 2$0;
2059}", 2123}
2060 r" 2124"#,
2125 r#"
2061fn foo() -> u32 { 2126fn foo() -> u32 {
2062 2127
2063 2128
@@ -2066,7 +2131,8 @@ fn foo() -> u32 {
2066 2131
2067fn $0fun_name() -> u32 { 2132fn $0fun_name() -> u32 {
2068 2 + 2 2133 2 + 2
2069}", 2134}
2135"#,
2070 ); 2136 );
2071 } 2137 }
2072 2138
@@ -2074,13 +2140,14 @@ fn $0fun_name() -> u32 {
2074 fn break_stmt() { 2140 fn break_stmt() {
2075 check_assist( 2141 check_assist(
2076 extract_function, 2142 extract_function,
2077 r" 2143 r#"
2078fn main() { 2144fn main() {
2079 let result = loop { 2145 let result = loop {
2080 $0break 2 + 2$0; 2146 $0break 2 + 2$0;
2081 }; 2147 };
2082}", 2148}
2083 r" 2149"#,
2150 r#"
2084fn main() { 2151fn main() {
2085 let result = loop { 2152 let result = loop {
2086 break fun_name(); 2153 break fun_name();
@@ -2089,7 +2156,8 @@ fn main() {
2089 2156
2090fn $0fun_name() -> i32 { 2157fn $0fun_name() -> i32 {
2091 2 + 2 2158 2 + 2
2092}", 2159}
2160"#,
2093 ); 2161 );
2094 } 2162 }
2095 2163
@@ -2097,18 +2165,20 @@ fn $0fun_name() -> i32 {
2097 fn extract_cast() { 2165 fn extract_cast() {
2098 check_assist( 2166 check_assist(
2099 extract_function, 2167 extract_function,
2100 r" 2168 r#"
2101fn main() { 2169fn main() {
2102 let v = $00f32 as u32$0; 2170 let v = $00f32 as u32$0;
2103}", 2171}
2104 r" 2172"#,
2173 r#"
2105fn main() { 2174fn main() {
2106 let v = fun_name(); 2175 let v = fun_name();
2107} 2176}
2108 2177
2109fn $0fun_name() -> u32 { 2178fn $0fun_name() -> u32 {
2110 0f32 as u32 2179 0f32 as u32
2111}", 2180}
2181"#,
2112 ); 2182 );
2113 } 2183 }
2114 2184
@@ -2121,15 +2191,16 @@ fn $0fun_name() -> u32 {
2121 fn method_to_freestanding() { 2191 fn method_to_freestanding() {
2122 check_assist( 2192 check_assist(
2123 extract_function, 2193 extract_function,
2124 r" 2194 r#"
2125struct S; 2195struct S;
2126 2196
2127impl S { 2197impl S {
2128 fn foo(&self) -> i32 { 2198 fn foo(&self) -> i32 {
2129 $01+1$0 2199 $01+1$0
2130 } 2200 }
2131}", 2201}
2132 r" 2202"#,
2203 r#"
2133struct S; 2204struct S;
2134 2205
2135impl S { 2206impl S {
@@ -2140,7 +2211,8 @@ impl S {
2140 2211
2141fn $0fun_name() -> i32 { 2212fn $0fun_name() -> i32 {
2142 1+1 2213 1+1
2143}", 2214}
2215"#,
2144 ); 2216 );
2145 } 2217 }
2146 2218
@@ -2148,15 +2220,16 @@ fn $0fun_name() -> i32 {
2148 fn method_with_reference() { 2220 fn method_with_reference() {
2149 check_assist( 2221 check_assist(
2150 extract_function, 2222 extract_function,
2151 r" 2223 r#"
2152struct S { f: i32 }; 2224struct S { f: i32 };
2153 2225
2154impl S { 2226impl S {
2155 fn foo(&self) -> i32 { 2227 fn foo(&self) -> i32 {
2156 $01+self.f$0 2228 $01+self.f$0
2157 } 2229 }
2158}", 2230}
2159 r" 2231"#,
2232 r#"
2160struct S { f: i32 }; 2233struct S { f: i32 };
2161 2234
2162impl S { 2235impl S {
@@ -2167,7 +2240,8 @@ impl S {
2167 fn $0fun_name(&self) -> i32 { 2240 fn $0fun_name(&self) -> i32 {
2168 1+self.f 2241 1+self.f
2169 } 2242 }
2170}", 2243}
2244"#,
2171 ); 2245 );
2172 } 2246 }
2173 2247
@@ -2175,15 +2249,16 @@ impl S {
2175 fn method_with_mut() { 2249 fn method_with_mut() {
2176 check_assist( 2250 check_assist(
2177 extract_function, 2251 extract_function,
2178 r" 2252 r#"
2179struct S { f: i32 }; 2253struct S { f: i32 };
2180 2254
2181impl S { 2255impl S {
2182 fn foo(&mut self) { 2256 fn foo(&mut self) {
2183 $0self.f += 1;$0 2257 $0self.f += 1;$0
2184 } 2258 }
2185}", 2259}
2186 r" 2260"#,
2261 r#"
2187struct S { f: i32 }; 2262struct S { f: i32 };
2188 2263
2189impl S { 2264impl S {
@@ -2194,7 +2269,8 @@ impl S {
2194 fn $0fun_name(&mut self) { 2269 fn $0fun_name(&mut self) {
2195 self.f += 1; 2270 self.f += 1;
2196 } 2271 }
2197}", 2272}
2273"#,
2198 ); 2274 );
2199 } 2275 }
2200 2276
@@ -2202,13 +2278,14 @@ impl S {
2202 fn variable_defined_inside_and_used_after_no_ret() { 2278 fn variable_defined_inside_and_used_after_no_ret() {
2203 check_assist( 2279 check_assist(
2204 extract_function, 2280 extract_function,
2205 r" 2281 r#"
2206fn foo() { 2282fn foo() {
2207 let n = 1; 2283 let n = 1;
2208 $0let k = n * n;$0 2284 $0let k = n * n;$0
2209 let m = k + 1; 2285 let m = k + 1;
2210}", 2286}
2211 r" 2287"#,
2288 r#"
2212fn foo() { 2289fn foo() {
2213 let n = 1; 2290 let n = 1;
2214 let k = fun_name(n); 2291 let k = fun_name(n);
@@ -2218,7 +2295,8 @@ fn foo() {
2218fn $0fun_name(n: i32) -> i32 { 2295fn $0fun_name(n: i32) -> i32 {
2219 let k = n * n; 2296 let k = n * n;
2220 k 2297 k
2221}", 2298}
2299"#,
2222 ); 2300 );
2223 } 2301 }
2224 2302
@@ -2226,13 +2304,14 @@ fn $0fun_name(n: i32) -> i32 {
2226 fn variable_defined_inside_and_used_after_mutably_no_ret() { 2304 fn variable_defined_inside_and_used_after_mutably_no_ret() {
2227 check_assist( 2305 check_assist(
2228 extract_function, 2306 extract_function,
2229 r" 2307 r#"
2230fn foo() { 2308fn foo() {
2231 let n = 1; 2309 let n = 1;
2232 $0let mut k = n * n;$0 2310 $0let mut k = n * n;$0
2233 k += 1; 2311 k += 1;
2234}", 2312}
2235 r" 2313"#,
2314 r#"
2236fn foo() { 2315fn foo() {
2237 let n = 1; 2316 let n = 1;
2238 let mut k = fun_name(n); 2317 let mut k = fun_name(n);
@@ -2242,7 +2321,8 @@ fn foo() {
2242fn $0fun_name(n: i32) -> i32 { 2321fn $0fun_name(n: i32) -> i32 {
2243 let mut k = n * n; 2322 let mut k = n * n;
2244 k 2323 k
2245}", 2324}
2325"#,
2246 ); 2326 );
2247 } 2327 }
2248 2328
@@ -2250,14 +2330,15 @@ fn $0fun_name(n: i32) -> i32 {
2250 fn two_variables_defined_inside_and_used_after_no_ret() { 2330 fn two_variables_defined_inside_and_used_after_no_ret() {
2251 check_assist( 2331 check_assist(
2252 extract_function, 2332 extract_function,
2253 r" 2333 r#"
2254fn foo() { 2334fn foo() {
2255 let n = 1; 2335 let n = 1;
2256 $0let k = n * n; 2336 $0let k = n * n;
2257 let m = k + 2;$0 2337 let m = k + 2;$0
2258 let h = k + m; 2338 let h = k + m;
2259}", 2339}
2260 r" 2340"#,
2341 r#"
2261fn foo() { 2342fn foo() {
2262 let n = 1; 2343 let n = 1;
2263 let (k, m) = fun_name(n); 2344 let (k, m) = fun_name(n);
@@ -2268,7 +2349,8 @@ fn $0fun_name(n: i32) -> (i32, i32) {
2268 let k = n * n; 2349 let k = n * n;
2269 let m = k + 2; 2350 let m = k + 2;
2270 (k, m) 2351 (k, m)
2271}", 2352}
2353"#,
2272 ); 2354 );
2273 } 2355 }
2274 2356
@@ -2276,7 +2358,7 @@ fn $0fun_name(n: i32) -> (i32, i32) {
2276 fn multi_variables_defined_inside_and_used_after_mutably_no_ret() { 2358 fn multi_variables_defined_inside_and_used_after_mutably_no_ret() {
2277 check_assist( 2359 check_assist(
2278 extract_function, 2360 extract_function,
2279 r" 2361 r#"
2280fn foo() { 2362fn foo() {
2281 let n = 1; 2363 let n = 1;
2282 $0let mut k = n * n; 2364 $0let mut k = n * n;
@@ -2285,8 +2367,9 @@ fn foo() {
2285 o += 1;$0 2367 o += 1;$0
2286 k += o; 2368 k += o;
2287 m = 1; 2369 m = 1;
2288}", 2370}
2289 r" 2371"#,
2372 r#"
2290fn foo() { 2373fn foo() {
2291 let n = 1; 2374 let n = 1;
2292 let (mut k, mut m, o) = fun_name(n); 2375 let (mut k, mut m, o) = fun_name(n);
@@ -2300,7 +2383,8 @@ fn $0fun_name(n: i32) -> (i32, i32, i32) {
2300 let mut o = m + 3; 2383 let mut o = m + 3;
2301 o += 1; 2384 o += 1;
2302 (k, m, o) 2385 (k, m, o)
2303}", 2386}
2387"#,
2304 ); 2388 );
2305 } 2389 }
2306 2390
@@ -2308,13 +2392,14 @@ fn $0fun_name(n: i32) -> (i32, i32, i32) {
2308 fn nontrivial_patterns_define_variables() { 2392 fn nontrivial_patterns_define_variables() {
2309 check_assist( 2393 check_assist(
2310 extract_function, 2394 extract_function,
2311 r" 2395 r#"
2312struct Counter(i32); 2396struct Counter(i32);
2313fn foo() { 2397fn foo() {
2314 $0let Counter(n) = Counter(0);$0 2398 $0let Counter(n) = Counter(0);$0
2315 let m = n; 2399 let m = n;
2316}", 2400}
2317 r" 2401"#,
2402 r#"
2318struct Counter(i32); 2403struct Counter(i32);
2319fn foo() { 2404fn foo() {
2320 let n = fun_name(); 2405 let n = fun_name();
@@ -2324,7 +2409,8 @@ fn foo() {
2324fn $0fun_name() -> i32 { 2409fn $0fun_name() -> i32 {
2325 let Counter(n) = Counter(0); 2410 let Counter(n) = Counter(0);
2326 n 2411 n
2327}", 2412}
2413"#,
2328 ); 2414 );
2329 } 2415 }
2330 2416
@@ -2332,13 +2418,14 @@ fn $0fun_name() -> i32 {
2332 fn struct_with_two_fields_pattern_define_variables() { 2418 fn struct_with_two_fields_pattern_define_variables() {
2333 check_assist( 2419 check_assist(
2334 extract_function, 2420 extract_function,
2335 r" 2421 r#"
2336struct Counter { n: i32, m: i32 }; 2422struct Counter { n: i32, m: i32 };
2337fn foo() { 2423fn foo() {
2338 $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0 2424 $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0
2339 let h = n + k; 2425 let h = n + k;
2340}", 2426}
2341 r" 2427"#,
2428 r#"
2342struct Counter { n: i32, m: i32 }; 2429struct Counter { n: i32, m: i32 };
2343fn foo() { 2430fn foo() {
2344 let (n, k) = fun_name(); 2431 let (n, k) = fun_name();
@@ -2348,7 +2435,8 @@ fn foo() {
2348fn $0fun_name() -> (i32, i32) { 2435fn $0fun_name() -> (i32, i32) {
2349 let Counter { n, m: k } = Counter { n: 1, m: 2 }; 2436 let Counter { n, m: k } = Counter { n: 1, m: 2 };
2350 (n, k) 2437 (n, k)
2351}", 2438}
2439"#,
2352 ); 2440 );
2353 } 2441 }
2354 2442
@@ -2356,13 +2444,14 @@ fn $0fun_name() -> (i32, i32) {
2356 fn mut_var_from_outer_scope() { 2444 fn mut_var_from_outer_scope() {
2357 check_assist( 2445 check_assist(
2358 extract_function, 2446 extract_function,
2359 r" 2447 r#"
2360fn foo() { 2448fn foo() {
2361 let mut n = 1; 2449 let mut n = 1;
2362 $0n += 1;$0 2450 $0n += 1;$0
2363 let m = n + 1; 2451 let m = n + 1;
2364}", 2452}
2365 r" 2453"#,
2454 r#"
2366fn foo() { 2455fn foo() {
2367 let mut n = 1; 2456 let mut n = 1;
2368 fun_name(&mut n); 2457 fun_name(&mut n);
@@ -2371,7 +2460,8 @@ fn foo() {
2371 2460
2372fn $0fun_name(n: &mut i32) { 2461fn $0fun_name(n: &mut i32) {
2373 *n += 1; 2462 *n += 1;
2374}", 2463}
2464"#,
2375 ); 2465 );
2376 } 2466 }
2377 2467
@@ -2379,14 +2469,15 @@ fn $0fun_name(n: &mut i32) {
2379 fn mut_field_from_outer_scope() { 2469 fn mut_field_from_outer_scope() {
2380 check_assist( 2470 check_assist(
2381 extract_function, 2471 extract_function,
2382 r" 2472 r#"
2383struct C { n: i32 } 2473struct C { n: i32 }
2384fn foo() { 2474fn foo() {
2385 let mut c = C { n: 0 }; 2475 let mut c = C { n: 0 };
2386 $0c.n += 1;$0 2476 $0c.n += 1;$0
2387 let m = c.n + 1; 2477 let m = c.n + 1;
2388}", 2478}
2389 r" 2479"#,
2480 r#"
2390struct C { n: i32 } 2481struct C { n: i32 }
2391fn foo() { 2482fn foo() {
2392 let mut c = C { n: 0 }; 2483 let mut c = C { n: 0 };
@@ -2396,7 +2487,8 @@ fn foo() {
2396 2487
2397fn $0fun_name(c: &mut C) { 2488fn $0fun_name(c: &mut C) {
2398 c.n += 1; 2489 c.n += 1;
2399}", 2490}
2491"#,
2400 ); 2492 );
2401 } 2493 }
2402 2494
@@ -2404,7 +2496,7 @@ fn $0fun_name(c: &mut C) {
2404 fn mut_nested_field_from_outer_scope() { 2496 fn mut_nested_field_from_outer_scope() {
2405 check_assist( 2497 check_assist(
2406 extract_function, 2498 extract_function,
2407 r" 2499 r#"
2408struct P { n: i32} 2500struct P { n: i32}
2409struct C { p: P } 2501struct C { p: P }
2410fn foo() { 2502fn foo() {
@@ -2414,8 +2506,9 @@ fn foo() {
2414 $0c.p.n += u.p.n; 2506 $0c.p.n += u.p.n;
2415 let r = &mut v.p.n;$0 2507 let r = &mut v.p.n;$0
2416 let m = c.p.n + v.p.n + u.p.n; 2508 let m = c.p.n + v.p.n + u.p.n;
2417}", 2509}
2418 r" 2510"#,
2511 r#"
2419struct P { n: i32} 2512struct P { n: i32}
2420struct C { p: P } 2513struct C { p: P }
2421fn foo() { 2514fn foo() {
@@ -2429,7 +2522,8 @@ fn foo() {
2429fn $0fun_name(c: &mut C, u: &C, v: &mut C) { 2522fn $0fun_name(c: &mut C, u: &C, v: &mut C) {
2430 c.p.n += u.p.n; 2523 c.p.n += u.p.n;
2431 let r = &mut v.p.n; 2524 let r = &mut v.p.n;
2432}", 2525}
2526"#,
2433 ); 2527 );
2434 } 2528 }
2435 2529
@@ -2437,7 +2531,7 @@ fn $0fun_name(c: &mut C, u: &C, v: &mut C) {
2437 fn mut_param_many_usages_stmt() { 2531 fn mut_param_many_usages_stmt() {
2438 check_assist( 2532 check_assist(
2439 extract_function, 2533 extract_function,
2440 r" 2534 r#"
2441fn bar(k: i32) {} 2535fn bar(k: i32) {}
2442trait I: Copy { 2536trait I: Copy {
2443 fn succ(&self) -> Self; 2537 fn succ(&self) -> Self;
@@ -2458,8 +2552,9 @@ fn foo() {
2458 *v = v.succ(); 2552 *v = v.succ();
2459 n.succ();$0 2553 n.succ();$0
2460 let m = n + 1; 2554 let m = n + 1;
2461}", 2555}
2462 r" 2556"#,
2557 r#"
2463fn bar(k: i32) {} 2558fn bar(k: i32) {}
2464trait I: Copy { 2559trait I: Copy {
2465 fn succ(&self) -> Self; 2560 fn succ(&self) -> Self;
@@ -2484,7 +2579,8 @@ fn $0fun_name(n: &mut i32) {
2484 let v = n; 2579 let v = n;
2485 *v = v.succ(); 2580 *v = v.succ();
2486 n.succ(); 2581 n.succ();
2487}", 2582}
2583"#,
2488 ); 2584 );
2489 } 2585 }
2490 2586
@@ -2492,7 +2588,7 @@ fn $0fun_name(n: &mut i32) {
2492 fn mut_param_many_usages_expr() { 2588 fn mut_param_many_usages_expr() {
2493 check_assist( 2589 check_assist(
2494 extract_function, 2590 extract_function,
2495 r" 2591 r#"
2496fn bar(k: i32) {} 2592fn bar(k: i32) {}
2497trait I: Copy { 2593trait I: Copy {
2498 fn succ(&self) -> Self; 2594 fn succ(&self) -> Self;
@@ -2515,8 +2611,9 @@ fn foo() {
2515 n.succ(); 2611 n.succ();
2516 }$0 2612 }$0
2517 let m = n + 1; 2613 let m = n + 1;
2518}", 2614}
2519 r" 2615"#,
2616 r#"
2520fn bar(k: i32) {} 2617fn bar(k: i32) {}
2521trait I: Copy { 2618trait I: Copy {
2522 fn succ(&self) -> Self; 2619 fn succ(&self) -> Self;
@@ -2541,7 +2638,8 @@ fn $0fun_name(n: &mut i32) {
2541 let v = n; 2638 let v = n;
2542 *v = v.succ(); 2639 *v = v.succ();
2543 n.succ(); 2640 n.succ();
2544}", 2641}
2642"#,
2545 ); 2643 );
2546 } 2644 }
2547 2645
@@ -2549,11 +2647,12 @@ fn $0fun_name(n: &mut i32) {
2549 fn mut_param_by_value() { 2647 fn mut_param_by_value() {
2550 check_assist( 2648 check_assist(
2551 extract_function, 2649 extract_function,
2552 r" 2650 r#"
2553fn foo() { 2651fn foo() {
2554 let mut n = 1; 2652 let mut n = 1;
2555 $0n += 1;$0 2653 $0n += 1;$0
2556}", 2654}
2655"#,
2557 r" 2656 r"
2558fn foo() { 2657fn foo() {
2559 let mut n = 1; 2658 let mut n = 1;
@@ -2562,7 +2661,8 @@ fn foo() {
2562 2661
2563fn $0fun_name(mut n: i32) { 2662fn $0fun_name(mut n: i32) {
2564 n += 1; 2663 n += 1;
2565}", 2664}
2665",
2566 ); 2666 );
2567 } 2667 }
2568 2668
@@ -2570,14 +2670,15 @@ fn $0fun_name(mut n: i32) {
2570 fn mut_param_because_of_mut_ref() { 2670 fn mut_param_because_of_mut_ref() {
2571 check_assist( 2671 check_assist(
2572 extract_function, 2672 extract_function,
2573 r" 2673 r#"
2574fn foo() { 2674fn foo() {
2575 let mut n = 1; 2675 let mut n = 1;
2576 $0let v = &mut n; 2676 $0let v = &mut n;
2577 *v += 1;$0 2677 *v += 1;$0
2578 let k = n; 2678 let k = n;
2579}", 2679}
2580 r" 2680"#,
2681 r#"
2581fn foo() { 2682fn foo() {
2582 let mut n = 1; 2683 let mut n = 1;
2583 fun_name(&mut n); 2684 fun_name(&mut n);
@@ -2587,7 +2688,8 @@ fn foo() {
2587fn $0fun_name(n: &mut i32) { 2688fn $0fun_name(n: &mut i32) {
2588 let v = n; 2689 let v = n;
2589 *v += 1; 2690 *v += 1;
2590}", 2691}
2692"#,
2591 ); 2693 );
2592 } 2694 }
2593 2695
@@ -2600,8 +2702,9 @@ fn foo() {
2600 let mut n = 1; 2702 let mut n = 1;
2601 $0let v = &mut n; 2703 $0let v = &mut n;
2602 *v += 1;$0 2704 *v += 1;$0
2603}", 2705}
2604 r" 2706",
2707 r#"
2605fn foo() { 2708fn foo() {
2606 let mut n = 1; 2709 let mut n = 1;
2607 fun_name(n); 2710 fun_name(n);
@@ -2610,7 +2713,8 @@ fn foo() {
2610fn $0fun_name(mut n: i32) { 2713fn $0fun_name(mut n: i32) {
2611 let v = &mut n; 2714 let v = &mut n;
2612 *v += 1; 2715 *v += 1;
2613}", 2716}
2717"#,
2614 ); 2718 );
2615 } 2719 }
2616 2720
@@ -2618,7 +2722,7 @@ fn $0fun_name(mut n: i32) {
2618 fn mut_method_call() { 2722 fn mut_method_call() {
2619 check_assist( 2723 check_assist(
2620 extract_function, 2724 extract_function,
2621 r" 2725 r#"
2622trait I { 2726trait I {
2623 fn inc(&mut self); 2727 fn inc(&mut self);
2624} 2728}
@@ -2628,8 +2732,9 @@ impl I for i32 {
2628fn foo() { 2732fn foo() {
2629 let mut n = 1; 2733 let mut n = 1;
2630 $0n.inc();$0 2734 $0n.inc();$0
2631}", 2735}
2632 r" 2736"#,
2737 r#"
2633trait I { 2738trait I {
2634 fn inc(&mut self); 2739 fn inc(&mut self);
2635} 2740}
@@ -2643,7 +2748,8 @@ fn foo() {
2643 2748
2644fn $0fun_name(mut n: i32) { 2749fn $0fun_name(mut n: i32) {
2645 n.inc(); 2750 n.inc();
2646}", 2751}
2752"#,
2647 ); 2753 );
2648 } 2754 }
2649 2755
@@ -2651,7 +2757,7 @@ fn $0fun_name(mut n: i32) {
2651 fn shared_method_call() { 2757 fn shared_method_call() {
2652 check_assist( 2758 check_assist(
2653 extract_function, 2759 extract_function,
2654 r" 2760 r#"
2655trait I { 2761trait I {
2656 fn succ(&self); 2762 fn succ(&self);
2657} 2763}
@@ -2661,7 +2767,8 @@ impl I for i32 {
2661fn foo() { 2767fn foo() {
2662 let mut n = 1; 2768 let mut n = 1;
2663 $0n.succ();$0 2769 $0n.succ();$0
2664}", 2770}
2771"#,
2665 r" 2772 r"
2666trait I { 2773trait I {
2667 fn succ(&self); 2774 fn succ(&self);
@@ -2676,7 +2783,8 @@ fn foo() {
2676 2783
2677fn $0fun_name(n: i32) { 2784fn $0fun_name(n: i32) {
2678 n.succ(); 2785 n.succ();
2679}", 2786}
2787",
2680 ); 2788 );
2681 } 2789 }
2682 2790
@@ -2684,7 +2792,7 @@ fn $0fun_name(n: i32) {
2684 fn mut_method_call_with_other_receiver() { 2792 fn mut_method_call_with_other_receiver() {
2685 check_assist( 2793 check_assist(
2686 extract_function, 2794 extract_function,
2687 r" 2795 r#"
2688trait I { 2796trait I {
2689 fn inc(&mut self, n: i32); 2797 fn inc(&mut self, n: i32);
2690} 2798}
@@ -2695,7 +2803,8 @@ fn foo() {
2695 let mut n = 1; 2803 let mut n = 1;
2696 $0let mut m = 2; 2804 $0let mut m = 2;
2697 m.inc(n);$0 2805 m.inc(n);$0
2698}", 2806}
2807"#,
2699 r" 2808 r"
2700trait I { 2809trait I {
2701 fn inc(&mut self, n: i32); 2810 fn inc(&mut self, n: i32);
@@ -2711,7 +2820,8 @@ fn foo() {
2711fn $0fun_name(n: i32) { 2820fn $0fun_name(n: i32) {
2712 let mut m = 2; 2821 let mut m = 2;
2713 m.inc(n); 2822 m.inc(n);
2714}", 2823}
2824",
2715 ); 2825 );
2716 } 2826 }
2717 2827
@@ -2719,12 +2829,13 @@ fn $0fun_name(n: i32) {
2719 fn non_copy_without_usages_after() { 2829 fn non_copy_without_usages_after() {
2720 check_assist( 2830 check_assist(
2721 extract_function, 2831 extract_function,
2722 r" 2832 r#"
2723struct Counter(i32); 2833struct Counter(i32);
2724fn foo() { 2834fn foo() {
2725 let c = Counter(0); 2835 let c = Counter(0);
2726 $0let n = c.0;$0 2836 $0let n = c.0;$0
2727}", 2837}
2838"#,
2728 r" 2839 r"
2729struct Counter(i32); 2840struct Counter(i32);
2730fn foo() { 2841fn foo() {
@@ -2734,7 +2845,8 @@ fn foo() {
2734 2845
2735fn $0fun_name(c: Counter) { 2846fn $0fun_name(c: Counter) {
2736 let n = c.0; 2847 let n = c.0;
2737}", 2848}
2849",
2738 ); 2850 );
2739 } 2851 }
2740 2852
@@ -2748,8 +2860,9 @@ fn foo() {
2748 let c = Counter(0); 2860 let c = Counter(0);
2749 $0let n = c.0;$0 2861 $0let n = c.0;$0
2750 let m = c.0; 2862 let m = c.0;
2751}", 2863}
2752 r" 2864",
2865 r#"
2753struct Counter(i32); 2866struct Counter(i32);
2754fn foo() { 2867fn foo() {
2755 let c = Counter(0); 2868 let c = Counter(0);
@@ -2759,7 +2872,8 @@ fn foo() {
2759 2872
2760fn $0fun_name(c: &Counter) { 2873fn $0fun_name(c: &Counter) {
2761 let n = c.0; 2874 let n = c.0;
2762}", 2875}
2876"#,
2763 ); 2877 );
2764 } 2878 }
2765 2879
@@ -2767,19 +2881,15 @@ fn $0fun_name(c: &Counter) {
2767 fn copy_used_after() { 2881 fn copy_used_after() {
2768 check_assist( 2882 check_assist(
2769 extract_function, 2883 extract_function,
2770 r##" 2884 r#"
2771#[lang = "copy"] 2885//- minicore: copy
2772pub trait Copy {}
2773impl Copy for i32 {}
2774fn foo() { 2886fn foo() {
2775 let n = 0; 2887 let n = 0;
2776 $0let m = n;$0 2888 $0let m = n;$0
2777 let k = n; 2889 let k = n;
2778}"##, 2890}
2779 r##" 2891"#,
2780#[lang = "copy"] 2892 r#"
2781pub trait Copy {}
2782impl Copy for i32 {}
2783fn foo() { 2893fn foo() {
2784 let n = 0; 2894 let n = 0;
2785 fun_name(n); 2895 fun_name(n);
@@ -2788,7 +2898,8 @@ fn foo() {
2788 2898
2789fn $0fun_name(n: i32) { 2899fn $0fun_name(n: i32) {
2790 let m = n; 2900 let m = n;
2791}"##, 2901}
2902"#,
2792 ) 2903 )
2793 } 2904 }
2794 2905
@@ -2796,21 +2907,19 @@ fn $0fun_name(n: i32) {
2796 fn copy_custom_used_after() { 2907 fn copy_custom_used_after() {
2797 check_assist( 2908 check_assist(
2798 extract_function, 2909 extract_function,
2799 r##" 2910 r#"
2800#[lang = "copy"] 2911//- minicore: copy, derive
2801pub trait Copy {} 2912#[derive(Clone, Copy)]
2802struct Counter(i32); 2913struct Counter(i32);
2803impl Copy for Counter {}
2804fn foo() { 2914fn foo() {
2805 let c = Counter(0); 2915 let c = Counter(0);
2806 $0let n = c.0;$0 2916 $0let n = c.0;$0
2807 let m = c.0; 2917 let m = c.0;
2808}"##, 2918}
2809 r##" 2919"#,
2810#[lang = "copy"] 2920 r#"
2811pub trait Copy {} 2921#[derive(Clone, Copy)]
2812struct Counter(i32); 2922struct Counter(i32);
2813impl Copy for Counter {}
2814fn foo() { 2923fn foo() {
2815 let c = Counter(0); 2924 let c = Counter(0);
2816 fun_name(c); 2925 fun_name(c);
@@ -2819,7 +2928,8 @@ fn foo() {
2819 2928
2820fn $0fun_name(c: Counter) { 2929fn $0fun_name(c: Counter) {
2821 let n = c.0; 2930 let n = c.0;
2822}"##, 2931}
2932"#,
2823 ); 2933 );
2824 } 2934 }
2825 2935
@@ -2827,7 +2937,7 @@ fn $0fun_name(c: Counter) {
2827 fn indented_stmts() { 2937 fn indented_stmts() {
2828 check_assist( 2938 check_assist(
2829 extract_function, 2939 extract_function,
2830 r" 2940 r#"
2831fn foo() { 2941fn foo() {
2832 if true { 2942 if true {
2833 loop { 2943 loop {
@@ -2835,8 +2945,9 @@ fn foo() {
2835 let m = 2;$0 2945 let m = 2;$0
2836 } 2946 }
2837 } 2947 }
2838}", 2948}
2839 r" 2949"#,
2950 r#"
2840fn foo() { 2951fn foo() {
2841 if true { 2952 if true {
2842 loop { 2953 loop {
@@ -2848,7 +2959,8 @@ fn foo() {
2848fn $0fun_name() { 2959fn $0fun_name() {
2849 let n = 1; 2960 let n = 1;
2850 let m = 2; 2961 let m = 2;
2851}", 2962}
2963"#,
2852 ); 2964 );
2853 } 2965 }
2854 2966
@@ -2856,7 +2968,7 @@ fn $0fun_name() {
2856 fn indented_stmts_inside_mod() { 2968 fn indented_stmts_inside_mod() {
2857 check_assist( 2969 check_assist(
2858 extract_function, 2970 extract_function,
2859 r" 2971 r#"
2860mod bar { 2972mod bar {
2861 fn foo() { 2973 fn foo() {
2862 if true { 2974 if true {
@@ -2866,8 +2978,9 @@ mod bar {
2866 } 2978 }
2867 } 2979 }
2868 } 2980 }
2869}", 2981}
2870 r" 2982"#,
2983 r#"
2871mod bar { 2984mod bar {
2872 fn foo() { 2985 fn foo() {
2873 if true { 2986 if true {
@@ -2881,7 +2994,8 @@ mod bar {
2881 let n = 1; 2994 let n = 1;
2882 let m = 2; 2995 let m = 2;
2883 } 2996 }
2884}", 2997}
2998"#,
2885 ); 2999 );
2886 } 3000 }
2887 3001
@@ -2889,12 +3003,8 @@ mod bar {
2889 fn break_loop() { 3003 fn break_loop() {
2890 check_assist( 3004 check_assist(
2891 extract_function, 3005 extract_function,
2892 r##" 3006 r#"
2893enum Option<T> { 3007//- minicore: option
2894 #[lang = "None"] None,
2895 #[lang = "Some"] Some(T),
2896}
2897use Option::*;
2898fn foo() { 3008fn foo() {
2899 loop { 3009 loop {
2900 let n = 1; 3010 let n = 1;
@@ -2903,13 +3013,9 @@ fn foo() {
2903 let k = 2;$0 3013 let k = 2;$0
2904 let h = 1 + k; 3014 let h = 1 + k;
2905 } 3015 }
2906}"##,
2907 r##"
2908enum Option<T> {
2909 #[lang = "None"] None,
2910 #[lang = "Some"] Some(T),
2911} 3016}
2912use Option::*; 3017"#,
3018 r#"
2913fn foo() { 3019fn foo() {
2914 loop { 3020 loop {
2915 let n = 1; 3021 let n = 1;
@@ -2926,7 +3032,8 @@ fn $0fun_name(n: i32) -> Option<i32> {
2926 return None; 3032 return None;
2927 let k = 2; 3033 let k = 2;
2928 Some(k) 3034 Some(k)
2929}"##, 3035}
3036"#,
2930 ); 3037 );
2931 } 3038 }
2932 3039
@@ -2934,31 +3041,17 @@ fn $0fun_name(n: i32) -> Option<i32> {
2934 fn return_to_parent() { 3041 fn return_to_parent() {
2935 check_assist( 3042 check_assist(
2936 extract_function, 3043 extract_function,
2937 r##" 3044 r#"
2938#[lang = "copy"] 3045//- minicore: copy, result
2939pub trait Copy {}
2940impl Copy for i32 {}
2941enum Result<T, E> {
2942 #[lang = "Ok"] Ok(T),
2943 #[lang = "Err"] Err(E),
2944}
2945use Result::*;
2946fn foo() -> i64 { 3046fn foo() -> i64 {
2947 let n = 1; 3047 let n = 1;
2948 $0let m = n + 1; 3048 $0let m = n + 1;
2949 return 1; 3049 return 1;
2950 let k = 2;$0 3050 let k = 2;$0
2951 (n + k) as i64 3051 (n + k) as i64
2952}"##, 3052}
2953 r##" 3053"#,
2954#[lang = "copy"] 3054 r#"
2955pub trait Copy {}
2956impl Copy for i32 {}
2957enum Result<T, E> {
2958 #[lang = "Ok"] Ok(T),
2959 #[lang = "Err"] Err(E),
2960}
2961use Result::*;
2962fn foo() -> i64 { 3055fn foo() -> i64 {
2963 let n = 1; 3056 let n = 1;
2964 let k = match fun_name(n) { 3057 let k = match fun_name(n) {
@@ -2973,7 +3066,8 @@ fn $0fun_name(n: i32) -> Result<i32, i64> {
2973 return Err(1); 3066 return Err(1);
2974 let k = 2; 3067 let k = 2;
2975 Ok(k) 3068 Ok(k)
2976}"##, 3069}
3070"#,
2977 ); 3071 );
2978 } 3072 }
2979 3073
@@ -2982,7 +3076,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> {
2982 cov_mark::check!(external_control_flow_break_and_continue); 3076 cov_mark::check!(external_control_flow_break_and_continue);
2983 check_assist_not_applicable( 3077 check_assist_not_applicable(
2984 extract_function, 3078 extract_function,
2985 r##" 3079 r#"
2986fn foo() { 3080fn foo() {
2987 loop { 3081 loop {
2988 let n = 1; 3082 let n = 1;
@@ -2993,7 +3087,8 @@ fn foo() {
2993 let k = k + 1;$0 3087 let k = k + 1;$0
2994 let r = n + k; 3088 let r = n + k;
2995 } 3089 }
2996}"##, 3090}
3091"#,
2997 ); 3092 );
2998 } 3093 }
2999 3094
@@ -3002,7 +3097,7 @@ fn foo() {
3002 cov_mark::check!(external_control_flow_return_and_bc); 3097 cov_mark::check!(external_control_flow_return_and_bc);
3003 check_assist_not_applicable( 3098 check_assist_not_applicable(
3004 extract_function, 3099 extract_function,
3005 r##" 3100 r#"
3006fn foo() { 3101fn foo() {
3007 loop { 3102 loop {
3008 let n = 1; 3103 let n = 1;
@@ -3013,7 +3108,8 @@ fn foo() {
3013 let k = k + 1;$0 3108 let k = k + 1;$0
3014 let r = n + k; 3109 let r = n + k;
3015 } 3110 }
3016}"##, 3111}
3112"#,
3017 ); 3113 );
3018 } 3114 }
3019 3115
@@ -3021,7 +3117,7 @@ fn foo() {
3021 fn break_loop_with_if() { 3117 fn break_loop_with_if() {
3022 check_assist( 3118 check_assist(
3023 extract_function, 3119 extract_function,
3024 r##" 3120 r#"
3025fn foo() { 3121fn foo() {
3026 loop { 3122 loop {
3027 let mut n = 1; 3123 let mut n = 1;
@@ -3030,8 +3126,9 @@ fn foo() {
3030 n += m;$0 3126 n += m;$0
3031 let h = 1 + n; 3127 let h = 1 + n;
3032 } 3128 }
3033}"##, 3129}
3034 r##" 3130"#,
3131 r#"
3035fn foo() { 3132fn foo() {
3036 loop { 3133 loop {
3037 let mut n = 1; 3134 let mut n = 1;
@@ -3047,7 +3144,8 @@ fn $0fun_name(n: &mut i32) -> bool {
3047 return true; 3144 return true;
3048 *n += m; 3145 *n += m;
3049 false 3146 false
3050}"##, 3147}
3148"#,
3051 ); 3149 );
3052 } 3150 }
3053 3151
@@ -3055,7 +3153,7 @@ fn $0fun_name(n: &mut i32) -> bool {
3055 fn break_loop_nested() { 3153 fn break_loop_nested() {
3056 check_assist( 3154 check_assist(
3057 extract_function, 3155 extract_function,
3058 r##" 3156 r#"
3059fn foo() { 3157fn foo() {
3060 loop { 3158 loop {
3061 let mut n = 1; 3159 let mut n = 1;
@@ -3065,8 +3163,9 @@ fn foo() {
3065 }$0 3163 }$0
3066 let h = 1; 3164 let h = 1;
3067 } 3165 }
3068}"##, 3166}
3069 r##" 3167"#,
3168 r#"
3070fn foo() { 3169fn foo() {
3071 loop { 3170 loop {
3072 let mut n = 1; 3171 let mut n = 1;
@@ -3083,7 +3182,8 @@ fn $0fun_name(n: i32) -> bool {
3083 return true; 3182 return true;
3084 } 3183 }
3085 false 3184 false
3086}"##, 3185}
3186"#,
3087 ); 3187 );
3088 } 3188 }
3089 3189
@@ -3091,7 +3191,7 @@ fn $0fun_name(n: i32) -> bool {
3091 fn return_from_nested_loop() { 3191 fn return_from_nested_loop() {
3092 check_assist( 3192 check_assist(
3093 extract_function, 3193 extract_function,
3094 r##" 3194 r#"
3095fn foo() { 3195fn foo() {
3096 loop { 3196 loop {
3097 let n = 1; 3197 let n = 1;
@@ -3103,8 +3203,9 @@ fn foo() {
3103 let m = k + 1;$0 3203 let m = k + 1;$0
3104 let h = 1 + m; 3204 let h = 1 + m;
3105 } 3205 }
3106}"##, 3206}
3107 r##" 3207"#,
3208 r#"
3108fn foo() { 3209fn foo() {
3109 loop { 3210 loop {
3110 let n = 1; 3211 let n = 1;
@@ -3123,7 +3224,8 @@ fn $0fun_name() -> Option<i32> {
3123 } 3224 }
3124 let m = k + 1; 3225 let m = k + 1;
3125 Some(m) 3226 Some(m)
3126}"##, 3227}
3228"#,
3127 ); 3229 );
3128 } 3230 }
3129 3231
@@ -3131,7 +3233,7 @@ fn $0fun_name() -> Option<i32> {
3131 fn break_from_nested_loop() { 3233 fn break_from_nested_loop() {
3132 check_assist( 3234 check_assist(
3133 extract_function, 3235 extract_function,
3134 r##" 3236 r#"
3135fn foo() { 3237fn foo() {
3136 loop { 3238 loop {
3137 let n = 1; 3239 let n = 1;
@@ -3142,8 +3244,9 @@ fn foo() {
3142 let m = k + 1;$0 3244 let m = k + 1;$0
3143 let h = 1 + m; 3245 let h = 1 + m;
3144 } 3246 }
3145}"##, 3247}
3146 r##" 3248"#,
3249 r#"
3147fn foo() { 3250fn foo() {
3148 loop { 3251 loop {
3149 let n = 1; 3252 let n = 1;
@@ -3159,7 +3262,8 @@ fn $0fun_name() -> i32 {
3159 } 3262 }
3160 let m = k + 1; 3263 let m = k + 1;
3161 m 3264 m
3162}"##, 3265}
3266"#,
3163 ); 3267 );
3164 } 3268 }
3165 3269
@@ -3167,7 +3271,7 @@ fn $0fun_name() -> i32 {
3167 fn break_from_nested_and_outer_loops() { 3271 fn break_from_nested_and_outer_loops() {
3168 check_assist( 3272 check_assist(
3169 extract_function, 3273 extract_function,
3170 r##" 3274 r#"
3171fn foo() { 3275fn foo() {
3172 loop { 3276 loop {
3173 let n = 1; 3277 let n = 1;
@@ -3181,8 +3285,9 @@ fn foo() {
3181 let m = k + 1;$0 3285 let m = k + 1;$0
3182 let h = 1 + m; 3286 let h = 1 + m;
3183 } 3287 }
3184}"##, 3288}
3185 r##" 3289"#,
3290 r#"
3186fn foo() { 3291fn foo() {
3187 loop { 3292 loop {
3188 let n = 1; 3293 let n = 1;
@@ -3204,7 +3309,8 @@ fn $0fun_name() -> Option<i32> {
3204 } 3309 }
3205 let m = k + 1; 3310 let m = k + 1;
3206 Some(m) 3311 Some(m)
3207}"##, 3312}
3313"#,
3208 ); 3314 );
3209 } 3315 }
3210 3316
@@ -3212,7 +3318,7 @@ fn $0fun_name() -> Option<i32> {
3212 fn return_from_nested_fn() { 3318 fn return_from_nested_fn() {
3213 check_assist( 3319 check_assist(
3214 extract_function, 3320 extract_function,
3215 r##" 3321 r#"
3216fn foo() { 3322fn foo() {
3217 loop { 3323 loop {
3218 let n = 1; 3324 let n = 1;
@@ -3223,8 +3329,9 @@ fn foo() {
3223 let m = k + 1;$0 3329 let m = k + 1;$0
3224 let h = 1 + m; 3330 let h = 1 + m;
3225 } 3331 }
3226}"##, 3332}
3227 r##" 3333"#,
3334 r#"
3228fn foo() { 3335fn foo() {
3229 loop { 3336 loop {
3230 let n = 1; 3337 let n = 1;
@@ -3240,7 +3347,8 @@ fn $0fun_name() -> i32 {
3240 } 3347 }
3241 let m = k + 1; 3348 let m = k + 1;
3242 m 3349 m
3243}"##, 3350}
3351"#,
3244 ); 3352 );
3245 } 3353 }
3246 3354
@@ -3248,7 +3356,7 @@ fn $0fun_name() -> i32 {
3248 fn break_with_value() { 3356 fn break_with_value() {
3249 check_assist( 3357 check_assist(
3250 extract_function, 3358 extract_function,
3251 r##" 3359 r#"
3252fn foo() -> i32 { 3360fn foo() -> i32 {
3253 loop { 3361 loop {
3254 let n = 1; 3362 let n = 1;
@@ -3259,8 +3367,9 @@ fn foo() -> i32 {
3259 let m = k + 1;$0 3367 let m = k + 1;$0
3260 let h = 1; 3368 let h = 1;
3261 } 3369 }
3262}"##, 3370}
3263 r##" 3371"#,
3372 r#"
3264fn foo() -> i32 { 3373fn foo() -> i32 {
3265 loop { 3374 loop {
3266 let n = 1; 3375 let n = 1;
@@ -3278,7 +3387,8 @@ fn $0fun_name() -> Option<i32> {
3278 } 3387 }
3279 let m = k + 1; 3388 let m = k + 1;
3280 None 3389 None
3281}"##, 3390}
3391"#,
3282 ); 3392 );
3283 } 3393 }
3284 3394
@@ -3286,7 +3396,7 @@ fn $0fun_name() -> Option<i32> {
3286 fn break_with_value_and_return() { 3396 fn break_with_value_and_return() {
3287 check_assist( 3397 check_assist(
3288 extract_function, 3398 extract_function,
3289 r##" 3399 r#"
3290fn foo() -> i64 { 3400fn foo() -> i64 {
3291 loop { 3401 loop {
3292 let n = 1; 3402 let n = 1;
@@ -3298,8 +3408,9 @@ fn foo() -> i64 {
3298 let m = k + 1;$0 3408 let m = k + 1;$0
3299 let h = 1 + m; 3409 let h = 1 + m;
3300 } 3410 }
3301}"##, 3411}
3302 r##" 3412"#,
3413 r#"
3303fn foo() -> i64 { 3414fn foo() -> i64 {
3304 loop { 3415 loop {
3305 let n = 1; 3416 let n = 1;
@@ -3318,7 +3429,8 @@ fn $0fun_name() -> Result<i32, i64> {
3318 } 3429 }
3319 let m = k + 1; 3430 let m = k + 1;
3320 Ok(m) 3431 Ok(m)
3321}"##, 3432}
3433"#,
3322 ); 3434 );
3323 } 3435 }
3324 3436
@@ -3326,9 +3438,8 @@ fn $0fun_name() -> Result<i32, i64> {
3326 fn try_option() { 3438 fn try_option() {
3327 check_assist( 3439 check_assist(
3328 extract_function, 3440 extract_function,
3329 r##" 3441 r#"
3330enum Option<T> { None, Some(T), } 3442//- minicore: option
3331use Option::*;
3332fn bar() -> Option<i32> { None } 3443fn bar() -> Option<i32> { None }
3333fn foo() -> Option<()> { 3444fn foo() -> Option<()> {
3334 let n = bar()?; 3445 let n = bar()?;
@@ -3336,10 +3447,9 @@ fn foo() -> Option<()> {
3336 let m = k + 1;$0 3447 let m = k + 1;$0
3337 let h = 1 + m; 3448 let h = 1 + m;
3338 Some(()) 3449 Some(())
3339}"##, 3450}
3340 r##" 3451"#,
3341enum Option<T> { None, Some(T), } 3452 r#"
3342use Option::*;
3343fn bar() -> Option<i32> { None } 3453fn bar() -> Option<i32> { None }
3344fn foo() -> Option<()> { 3454fn foo() -> Option<()> {
3345 let n = bar()?; 3455 let n = bar()?;
@@ -3352,7 +3462,8 @@ fn $0fun_name() -> Option<i32> {
3352 let k = foo()?; 3462 let k = foo()?;
3353 let m = k + 1; 3463 let m = k + 1;
3354 Some(m) 3464 Some(m)
3355}"##, 3465}
3466"#,
3356 ); 3467 );
3357 } 3468 }
3358 3469
@@ -3360,19 +3471,17 @@ fn $0fun_name() -> Option<i32> {
3360 fn try_option_unit() { 3471 fn try_option_unit() {
3361 check_assist( 3472 check_assist(
3362 extract_function, 3473 extract_function,
3363 r##" 3474 r#"
3364enum Option<T> { None, Some(T), } 3475//- minicore: option
3365use Option::*;
3366fn foo() -> Option<()> { 3476fn foo() -> Option<()> {
3367 let n = 1; 3477 let n = 1;
3368 $0let k = foo()?; 3478 $0let k = foo()?;
3369 let m = k + 1;$0 3479 let m = k + 1;$0
3370 let h = 1 + n; 3480 let h = 1 + n;
3371 Some(()) 3481 Some(())
3372}"##, 3482}
3373 r##" 3483"#,
3374enum Option<T> { None, Some(T), } 3484 r#"
3375use Option::*;
3376fn foo() -> Option<()> { 3485fn foo() -> Option<()> {
3377 let n = 1; 3486 let n = 1;
3378 fun_name()?; 3487 fun_name()?;
@@ -3384,7 +3493,8 @@ fn $0fun_name() -> Option<()> {
3384 let k = foo()?; 3493 let k = foo()?;
3385 let m = k + 1; 3494 let m = k + 1;
3386 Some(()) 3495 Some(())
3387}"##, 3496}
3497"#,
3388 ); 3498 );
3389 } 3499 }
3390 3500
@@ -3392,19 +3502,17 @@ fn $0fun_name() -> Option<()> {
3392 fn try_result() { 3502 fn try_result() {
3393 check_assist( 3503 check_assist(
3394 extract_function, 3504 extract_function,
3395 r##" 3505 r#"
3396enum Result<T, E> { Ok(T), Err(E), } 3506//- minicore: result
3397use Result::*;
3398fn foo() -> Result<(), i64> { 3507fn foo() -> Result<(), i64> {
3399 let n = 1; 3508 let n = 1;
3400 $0let k = foo()?; 3509 $0let k = foo()?;
3401 let m = k + 1;$0 3510 let m = k + 1;$0
3402 let h = 1 + m; 3511 let h = 1 + m;
3403 Ok(()) 3512 Ok(())
3404}"##, 3513}
3405 r##" 3514"#,
3406enum Result<T, E> { Ok(T), Err(E), } 3515 r#"
3407use Result::*;
3408fn foo() -> Result<(), i64> { 3516fn foo() -> Result<(), i64> {
3409 let n = 1; 3517 let n = 1;
3410 let m = fun_name()?; 3518 let m = fun_name()?;
@@ -3416,7 +3524,8 @@ fn $0fun_name() -> Result<i32, i64> {
3416 let k = foo()?; 3524 let k = foo()?;
3417 let m = k + 1; 3525 let m = k + 1;
3418 Ok(m) 3526 Ok(m)
3419}"##, 3527}
3528"#,
3420 ); 3529 );
3421 } 3530 }
3422 3531
@@ -3424,9 +3533,8 @@ fn $0fun_name() -> Result<i32, i64> {
3424 fn try_option_with_return() { 3533 fn try_option_with_return() {
3425 check_assist( 3534 check_assist(
3426 extract_function, 3535 extract_function,
3427 r##" 3536 r#"
3428enum Option<T> { None, Some(T) } 3537//- minicore: option
3429use Option::*;
3430fn foo() -> Option<()> { 3538fn foo() -> Option<()> {
3431 let n = 1; 3539 let n = 1;
3432 $0let k = foo()?; 3540 $0let k = foo()?;
@@ -3436,10 +3544,9 @@ fn foo() -> Option<()> {
3436 let m = k + 1;$0 3544 let m = k + 1;$0
3437 let h = 1 + m; 3545 let h = 1 + m;
3438 Some(()) 3546 Some(())
3439}"##, 3547}
3440 r##" 3548"#,
3441enum Option<T> { None, Some(T) } 3549 r#"
3442use Option::*;
3443fn foo() -> Option<()> { 3550fn foo() -> Option<()> {
3444 let n = 1; 3551 let n = 1;
3445 let m = fun_name()?; 3552 let m = fun_name()?;
@@ -3454,7 +3561,8 @@ fn $0fun_name() -> Option<i32> {
3454 } 3561 }
3455 let m = k + 1; 3562 let m = k + 1;
3456 Some(m) 3563 Some(m)
3457}"##, 3564}
3565"#,
3458 ); 3566 );
3459 } 3567 }
3460 3568
@@ -3462,9 +3570,8 @@ fn $0fun_name() -> Option<i32> {
3462 fn try_result_with_return() { 3570 fn try_result_with_return() {
3463 check_assist( 3571 check_assist(
3464 extract_function, 3572 extract_function,
3465 r##" 3573 r#"
3466enum Result<T, E> { Ok(T), Err(E), } 3574//- minicore: result
3467use Result::*;
3468fn foo() -> Result<(), i64> { 3575fn foo() -> Result<(), i64> {
3469 let n = 1; 3576 let n = 1;
3470 $0let k = foo()?; 3577 $0let k = foo()?;
@@ -3474,10 +3581,9 @@ fn foo() -> Result<(), i64> {
3474 let m = k + 1;$0 3581 let m = k + 1;$0
3475 let h = 1 + m; 3582 let h = 1 + m;
3476 Ok(()) 3583 Ok(())
3477}"##, 3584}
3478 r##" 3585"#,
3479enum Result<T, E> { Ok(T), Err(E), } 3586 r#"
3480use Result::*;
3481fn foo() -> Result<(), i64> { 3587fn foo() -> Result<(), i64> {
3482 let n = 1; 3588 let n = 1;
3483 let m = fun_name()?; 3589 let m = fun_name()?;
@@ -3492,7 +3598,8 @@ fn $0fun_name() -> Result<i32, i64> {
3492 } 3598 }
3493 let m = k + 1; 3599 let m = k + 1;
3494 Ok(m) 3600 Ok(m)
3495}"##, 3601}
3602"#,
3496 ); 3603 );
3497 } 3604 }
3498 3605
@@ -3501,9 +3608,8 @@ fn $0fun_name() -> Result<i32, i64> {
3501 cov_mark::check!(external_control_flow_try_and_bc); 3608 cov_mark::check!(external_control_flow_try_and_bc);
3502 check_assist_not_applicable( 3609 check_assist_not_applicable(
3503 extract_function, 3610 extract_function,
3504 r##" 3611 r#"
3505enum Option<T> { None, Some(T) } 3612//- minicore: option
3506use Option::*;
3507fn foo() -> Option<()> { 3613fn foo() -> Option<()> {
3508 loop { 3614 loop {
3509 let n = Some(1); 3615 let n = Some(1);
@@ -3514,7 +3620,8 @@ fn foo() -> Option<()> {
3514 let r = n + k; 3620 let r = n + k;
3515 } 3621 }
3516 Some(()) 3622 Some(())
3517}"##, 3623}
3624"#,
3518 ); 3625 );
3519 } 3626 }
3520 3627
@@ -3523,9 +3630,8 @@ fn foo() -> Option<()> {
3523 cov_mark::check!(external_control_flow_try_and_return_non_err); 3630 cov_mark::check!(external_control_flow_try_and_return_non_err);
3524 check_assist_not_applicable( 3631 check_assist_not_applicable(
3525 extract_function, 3632 extract_function,
3526 r##" 3633 r#"
3527enum Result<T, E> { Ok(T), Err(E), } 3634//- minicore: result
3528use Result::*;
3529fn foo() -> Result<(), i64> { 3635fn foo() -> Result<(), i64> {
3530 let n = 1; 3636 let n = 1;
3531 $0let k = foo()?; 3637 $0let k = foo()?;
@@ -3535,7 +3641,8 @@ fn foo() -> Result<(), i64> {
3535 let m = k + 1;$0 3641 let m = k + 1;$0
3536 let h = 1 + m; 3642 let h = 1 + m;
3537 Ok(()) 3643 Ok(())
3538}"##, 3644}
3645"#,
3539 ); 3646 );
3540 } 3647 }
3541 3648
@@ -3543,7 +3650,7 @@ fn foo() -> Result<(), i64> {
3543 fn param_usage_in_macro() { 3650 fn param_usage_in_macro() {
3544 check_assist( 3651 check_assist(
3545 extract_function, 3652 extract_function,
3546 r" 3653 r#"
3547macro_rules! m { 3654macro_rules! m {
3548 ($val:expr) => { $val }; 3655 ($val:expr) => { $val };
3549} 3656}
@@ -3552,8 +3659,9 @@ fn foo() {
3552 let n = 1; 3659 let n = 1;
3553 $0let k = n * m!(n);$0 3660 $0let k = n * m!(n);$0
3554 let m = k + 1; 3661 let m = k + 1;
3555}", 3662}
3556 r" 3663"#,
3664 r#"
3557macro_rules! m { 3665macro_rules! m {
3558 ($val:expr) => { $val }; 3666 ($val:expr) => { $val };
3559} 3667}
@@ -3567,7 +3675,8 @@ fn foo() {
3567fn $0fun_name(n: i32) -> i32 { 3675fn $0fun_name(n: i32) -> i32 {
3568 let k = n * m!(n); 3676 let k = n * m!(n);
3569 k 3677 k
3570}", 3678}
3679"#,
3571 ); 3680 );
3572 } 3681 }
3573 3682
@@ -3575,7 +3684,8 @@ fn $0fun_name(n: i32) -> i32 {
3575 fn extract_with_await() { 3684 fn extract_with_await() {
3576 check_assist( 3685 check_assist(
3577 extract_function, 3686 extract_function,
3578 r#"fn main() { 3687 r#"
3688fn main() {
3579 $0some_function().await;$0 3689 $0some_function().await;$0
3580} 3690}
3581 3691
@@ -3585,7 +3695,7 @@ async fn some_function() {
3585"#, 3695"#,
3586 r#" 3696 r#"
3587fn main() { 3697fn main() {
3588 fun_name(); 3698 fun_name().await;
3589} 3699}
3590 3700
3591async fn $0fun_name() { 3701async fn $0fun_name() {
@@ -3603,7 +3713,8 @@ async fn some_function() {
3603 fn extract_with_await_in_args() { 3713 fn extract_with_await_in_args() {
3604 check_assist( 3714 check_assist(
3605 extract_function, 3715 extract_function,
3606 r#"fn main() { 3716 r#"
3717fn main() {
3607 $0function_call("a", some_function().await);$0 3718 $0function_call("a", some_function().await);$0
3608} 3719}
3609 3720
@@ -3613,7 +3724,7 @@ async fn some_function() {
3613"#, 3724"#,
3614 r#" 3725 r#"
3615fn main() { 3726fn main() {
3616 fun_name(); 3727 fun_name().await;
3617} 3728}
3618 3729
3619async fn $0fun_name() { 3730async fn $0fun_name() {
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index d3ff7b65c..430710448 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -48,6 +48,7 @@ pub(crate) fn extract_struct_from_enum_variant(
48 let variant_name = variant.name()?; 48 let variant_name = variant.name()?;
49 let variant_hir = ctx.sema.to_def(&variant)?; 49 let variant_hir = ctx.sema.to_def(&variant)?;
50 if existing_definition(ctx.db(), &variant_name, &variant_hir) { 50 if existing_definition(ctx.db(), &variant_name, &variant_hir) {
51 cov_mark::hit!(test_extract_enum_not_applicable_if_struct_exists);
51 return None; 52 return None;
52 } 53 }
53 54
@@ -235,7 +236,7 @@ fn apply_references(
235 import: Option<(ImportScope, hir::ModPath)>, 236 import: Option<(ImportScope, hir::ModPath)>,
236) { 237) {
237 if let Some((scope, path)) = import { 238 if let Some((scope, path)) = import {
238 insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); 239 insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg);
239 } 240 }
240 // deep clone to prevent cycle 241 // deep clone to prevent cycle
241 let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); 242 let path = make::path_from_segments(iter::once(segment.clone_subtree()), false);
@@ -300,18 +301,10 @@ fn reference_to_node(
300 301
301#[cfg(test)] 302#[cfg(test)]
302mod tests { 303mod tests {
303 use ide_db::helpers::FamousDefs;
304
305 use crate::tests::{check_assist, check_assist_not_applicable}; 304 use crate::tests::{check_assist, check_assist_not_applicable};
306 305
307 use super::*; 306 use super::*;
308 307
309 fn check_not_applicable(ra_fixture: &str) {
310 let fixture =
311 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
312 check_assist_not_applicable(extract_struct_from_enum_variant, &fixture)
313 }
314
315 #[test] 308 #[test]
316 fn test_extract_struct_several_fields_tuple() { 309 fn test_extract_struct_several_fields_tuple() {
317 check_assist( 310 check_assist(
@@ -699,29 +692,33 @@ fn foo() {
699 692
700 #[test] 693 #[test]
701 fn test_extract_enum_not_applicable_for_element_with_no_fields() { 694 fn test_extract_enum_not_applicable_for_element_with_no_fields() {
702 check_not_applicable("enum A { $0One }"); 695 check_assist_not_applicable(extract_struct_from_enum_variant, r#"enum A { $0One }"#);
703 } 696 }
704 697
705 #[test] 698 #[test]
706 fn test_extract_enum_not_applicable_if_struct_exists() { 699 fn test_extract_enum_not_applicable_if_struct_exists() {
707 check_not_applicable( 700 cov_mark::check!(test_extract_enum_not_applicable_if_struct_exists);
708 r#"struct One; 701 check_assist_not_applicable(
709 enum A { $0One(u8, u32) }"#, 702 extract_struct_from_enum_variant,
703 r#"
704struct One;
705enum A { $0One(u8, u32) }
706"#,
710 ); 707 );
711 } 708 }
712 709
713 #[test] 710 #[test]
714 fn test_extract_not_applicable_one_field() { 711 fn test_extract_not_applicable_one_field() {
715 check_not_applicable(r"enum A { $0One(u32) }"); 712 check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0One(u32) }");
716 } 713 }
717 714
718 #[test] 715 #[test]
719 fn test_extract_not_applicable_no_field_tuple() { 716 fn test_extract_not_applicable_no_field_tuple() {
720 check_not_applicable(r"enum A { $0None() }"); 717 check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None() }");
721 } 718 }
722 719
723 #[test] 720 #[test]
724 fn test_extract_not_applicable_no_field_named() { 721 fn test_extract_not_applicable_no_field_named() {
725 check_not_applicable(r"enum A { $0None {} }"); 722 check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None {} }");
726 } 723 }
727} 724}
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 5a43bdd6f..318faa0fc 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -278,8 +278,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Op
278 278
279#[cfg(test)] 279#[cfg(test)]
280mod tests { 280mod tests {
281 use ide_db::helpers::FamousDefs;
282
283 use crate::tests::{ 281 use crate::tests::{
284 check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved, 282 check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved,
285 }; 283 };
@@ -483,26 +481,21 @@ fn main() {
483 check_assist( 481 check_assist(
484 fill_match_arms, 482 fill_match_arms,
485 r#" 483 r#"
486enum Option<T> { Some(T), None } 484//- minicore: option
487use Option::*;
488
489fn main() { 485fn main() {
490 match None$0 { 486 match None$0 {
491 None => {} 487 None => {}
492 } 488 }
493} 489}
494 "#, 490"#,
495 r#" 491 r#"
496enum Option<T> { Some(T), None }
497use Option::*;
498
499fn main() { 492fn main() {
500 match None { 493 match None {
501 None => {} 494 None => {}
502 Some(${0:_}) => todo!(), 495 Some(${0:_}) => todo!(),
503 } 496 }
504} 497}
505 "#, 498"#,
506 ); 499 );
507 } 500 }
508 501
@@ -716,7 +709,10 @@ fn main() {
716 709
717 #[test] 710 #[test]
718 fn fill_match_arms_tuple_of_enum_partial_with_wildcards() { 711 fn fill_match_arms_tuple_of_enum_partial_with_wildcards() {
719 let ra_fixture = r#" 712 check_assist(
713 fill_match_arms,
714 r#"
715//- minicore: option
720fn main() { 716fn main() {
721 let a = Some(1); 717 let a = Some(1);
722 let b = Some(()); 718 let b = Some(());
@@ -725,10 +721,7 @@ fn main() {
725 (None, Some(_)) => {} 721 (None, Some(_)) => {}
726 } 722 }
727} 723}
728"#; 724"#,
729 check_assist(
730 fill_match_arms,
731 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
732 r#" 725 r#"
733fn main() { 726fn main() {
734 let a = Some(1); 727 let a = Some(1);
@@ -746,17 +739,17 @@ fn main() {
746 #[test] 739 #[test]
747 fn fill_match_arms_partial_with_deep_pattern() { 740 fn fill_match_arms_partial_with_deep_pattern() {
748 // Fixme: cannot handle deep patterns 741 // Fixme: cannot handle deep patterns
749 let ra_fixture = r#" 742 check_assist_not_applicable(
743 fill_match_arms,
744 r#"
745//- minicore: option
750fn main() { 746fn main() {
751 match $0Some(true) { 747 match $0Some(true) {
752 Some(true) => {} 748 Some(true) => {}
753 None => {} 749 None => {}
754 } 750 }
755} 751}
756"#; 752"#,
757 check_assist_not_applicable(
758 fill_match_arms,
759 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
760 ); 753 );
761 } 754 }
762 755
@@ -1007,17 +1000,15 @@ fn foo(a: A) {
1007 #[test] 1000 #[test]
1008 fn option_order() { 1001 fn option_order() {
1009 cov_mark::check!(option_order); 1002 cov_mark::check!(option_order);
1010 let before = r#" 1003 check_assist(
1004 fill_match_arms,
1005 r#"
1006//- minicore: option
1011fn foo(opt: Option<i32>) { 1007fn foo(opt: Option<i32>) {
1012 match opt$0 { 1008 match opt$0 {
1013 } 1009 }
1014} 1010}
1015"#; 1011"#,
1016 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
1017
1018 check_assist(
1019 fill_match_arms,
1020 before,
1021 r#" 1012 r#"
1022fn foo(opt: Option<i32>) { 1013fn foo(opt: Option<i32>) {
1023 match opt { 1014 match opt {
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs
index 9b432e92f..f834bf16a 100644
--- a/crates/ide_assists/src/handlers/fix_visibility.rs
+++ b/crates/ide_assists/src/handlers/fix_visibility.rs
@@ -361,8 +361,6 @@ pub struct Foo { pub bar: () }
361 } 361 }
362 362
363 #[test] 363 #[test]
364 #[ignore]
365 // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields
366 fn fix_visibility_of_union_field() { 364 fn fix_visibility_of_union_field() {
367 check_assist( 365 check_assist(
368 fix_visibility, 366 fix_visibility,
@@ -583,25 +581,25 @@ pub struct Foo { pub(crate) bar: () }
583 } 581 }
584 582
585 #[test] 583 #[test]
586 #[ignore]
587 // FIXME handle reexports properly
588 fn fix_visibility_of_reexport() { 584 fn fix_visibility_of_reexport() {
585 // FIXME: broken test, this should fix visibility of the re-export
586 // rather than the struct.
589 check_assist( 587 check_assist(
590 fix_visibility, 588 fix_visibility,
591 r" 589 r#"
592 mod foo { 590mod foo {
593 use bar::Baz; 591 use bar::Baz;
594 mod bar { pub(super) struct Baz; } 592 mod bar { pub(super) struct Baz; }
595 } 593}
596 foo::Baz$0 594foo::Baz$0
597 ", 595"#,
598 r" 596 r#"
599 mod foo { 597mod foo {
600 $0pub(crate) use bar::Baz; 598 use bar::Baz;
601 mod bar { pub(super) struct Baz; } 599 mod bar { $0pub(crate) struct Baz; }
602 } 600}
603 foo::Baz 601foo::Baz
604 ", 602"#,
605 ) 603 )
606 } 604 }
607} 605}
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index 588ee1350..e55c38502 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -1,5 +1,4 @@
1use ide_db::helpers::FamousDefs; 1use ide_db::{helpers::FamousDefs, RootDatabase};
2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner}; 2use syntax::ast::{self, AstNode, NameOwner};
4 3
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 4use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -92,23 +91,20 @@ mod tests {
92 91
93 use super::*; 92 use super::*;
94 93
95 fn check_not_applicable(ra_fixture: &str) {
96 let fixture =
97 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
98 check_assist_not_applicable(generate_default_from_enum_variant, &fixture)
99 }
100
101 #[test] 94 #[test]
102 fn test_generate_default_from_variant() { 95 fn test_generate_default_from_variant() {
103 check_assist( 96 check_assist(
104 generate_default_from_enum_variant, 97 generate_default_from_enum_variant,
105 r#" 98 r#"
99//- minicore: default
106enum Variant { 100enum Variant {
107 Undefined, 101 Undefined,
108 Minor$0, 102 Minor$0,
109 Major, 103 Major,
110}"#, 104}
111 r#"enum Variant { 105"#,
106 r#"
107enum Variant {
112 Undefined, 108 Undefined,
113 Minor, 109 Minor,
114 Major, 110 Major,
@@ -118,15 +114,18 @@ impl Default for Variant {
118 fn default() -> Self { 114 fn default() -> Self {
119 Self::Minor 115 Self::Minor
120 } 116 }
121}"#, 117}
118"#,
122 ); 119 );
123 } 120 }
124 121
125 #[test] 122 #[test]
126 fn test_generate_default_already_implemented() { 123 fn test_generate_default_already_implemented() {
127 cov_mark::check!(test_gen_default_impl_already_exists); 124 cov_mark::check!(test_gen_default_impl_already_exists);
128 check_not_applicable( 125 check_assist_not_applicable(
126 generate_default_from_enum_variant,
129 r#" 127 r#"
128//- minicore: default
130enum Variant { 129enum Variant {
131 Undefined, 130 Undefined,
132 Minor$0, 131 Minor$0,
@@ -137,20 +136,24 @@ impl Default for Variant {
137 fn default() -> Self { 136 fn default() -> Self {
138 Self::Minor 137 Self::Minor
139 } 138 }
140}"#, 139}
140"#,
141 ); 141 );
142 } 142 }
143 143
144 #[test] 144 #[test]
145 fn test_add_from_impl_no_element() { 145 fn test_add_from_impl_no_element() {
146 cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented); 146 cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented);
147 check_not_applicable( 147 check_assist_not_applicable(
148 generate_default_from_enum_variant,
148 r#" 149 r#"
150//- minicore: default
149enum Variant { 151enum Variant {
150 Undefined, 152 Undefined,
151 Minor(u32)$0, 153 Minor(u32)$0,
152 Major, 154 Major,
153}"#, 155}
156"#,
154 ); 157 );
155 } 158 }
156 159
@@ -158,7 +161,10 @@ enum Variant {
158 fn test_generate_default_from_variant_with_one_variant() { 161 fn test_generate_default_from_variant_with_one_variant() {
159 check_assist( 162 check_assist(
160 generate_default_from_enum_variant, 163 generate_default_from_enum_variant,
161 r#"enum Variant { Undefi$0ned }"#, 164 r#"
165//- minicore: default
166enum Variant { Undefi$0ned }
167"#,
162 r#" 168 r#"
163enum Variant { Undefined } 169enum Variant { Undefined }
164 170
@@ -166,7 +172,8 @@ impl Default for Variant {
166 fn default() -> Self { 172 fn default() -> Self {
167 Self::Undefined 173 Self::Undefined
168 } 174 }
169}"#, 175}
176"#,
170 ); 177 );
171 } 178 }
172} 179}
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index bad826366..b54ec59da 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -1,7 +1,3 @@
1use crate::{
2 assist_context::{AssistContext, Assists},
3 AssistId,
4};
5use ide_db::helpers::FamousDefs; 1use ide_db::helpers::FamousDefs;
6use itertools::Itertools; 2use itertools::Itertools;
7use stdx::format_to; 3use stdx::format_to;
@@ -10,6 +6,11 @@ use syntax::{
10 AstNode, 6 AstNode,
11}; 7};
12 8
9use crate::{
10 assist_context::{AssistContext, Assists},
11 AssistId,
12};
13
13// Assist: generate_default_from_new 14// Assist: generate_default_from_new
14// 15//
15// Generates default implementation from new method. 16// Generates default implementation from new method.
@@ -140,16 +141,16 @@ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
140 141
141#[cfg(test)] 142#[cfg(test)]
142mod tests { 143mod tests {
143 use ide_db::helpers::FamousDefs;
144
145 use crate::tests::{check_assist, check_assist_not_applicable}; 144 use crate::tests::{check_assist, check_assist_not_applicable};
146 145
147 use super::*; 146 use super::*;
148 147
149 #[test] 148 #[test]
150 fn generate_default() { 149 fn generate_default() {
151 check_pass( 150 check_assist(
151 generate_default_from_new,
152 r#" 152 r#"
153//- minicore: default
153struct Example { _inner: () } 154struct Example { _inner: () }
154 155
155impl Example { 156impl Example {
@@ -182,8 +183,10 @@ fn main() {}
182 183
183 #[test] 184 #[test]
184 fn generate_default2() { 185 fn generate_default2() {
185 check_pass( 186 check_assist(
187 generate_default_from_new,
186 r#" 188 r#"
189//- minicore: default
187struct Test { value: u32 } 190struct Test { value: u32 }
188 191
189impl Test { 192impl Test {
@@ -212,8 +215,10 @@ impl Default for Test {
212 215
213 #[test] 216 #[test]
214 fn new_function_with_generic() { 217 fn new_function_with_generic() {
215 check_pass( 218 check_assist(
219 generate_default_from_new,
216 r#" 220 r#"
221//- minicore: default
217pub struct Foo<T> { 222pub struct Foo<T> {
218 _bar: *mut T, 223 _bar: *mut T,
219} 224}
@@ -246,8 +251,10 @@ impl<T> Default for Foo<T> {
246 251
247 #[test] 252 #[test]
248 fn new_function_with_generics() { 253 fn new_function_with_generics() {
249 check_pass( 254 check_assist(
255 generate_default_from_new,
250 r#" 256 r#"
257//- minicore: default
251pub struct Foo<T, B> { 258pub struct Foo<T, B> {
252 _tars: *mut T, 259 _tars: *mut T,
253 _bar: *mut B, 260 _bar: *mut B,
@@ -282,8 +289,10 @@ impl<T, B> Default for Foo<T, B> {
282 289
283 #[test] 290 #[test]
284 fn new_function_with_generic_and_bound() { 291 fn new_function_with_generic_and_bound() {
285 check_pass( 292 check_assist(
293 generate_default_from_new,
286 r#" 294 r#"
295//- minicore: default
287pub struct Foo<T> { 296pub struct Foo<T> {
288 t: T, 297 t: T,
289} 298}
@@ -316,8 +325,10 @@ impl<T: From<i32>> Default for Foo<T> {
316 325
317 #[test] 326 #[test]
318 fn new_function_with_generics_and_bounds() { 327 fn new_function_with_generics_and_bounds() {
319 check_pass( 328 check_assist(
329 generate_default_from_new,
320 r#" 330 r#"
331//- minicore: default
321pub struct Foo<T, B> { 332pub struct Foo<T, B> {
322 _tars: T, 333 _tars: T,
323 _bar: B, 334 _bar: B,
@@ -352,8 +363,10 @@ impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> {
352 363
353 #[test] 364 #[test]
354 fn new_function_with_generic_and_where() { 365 fn new_function_with_generic_and_where() {
355 check_pass( 366 check_assist(
367 generate_default_from_new,
356 r#" 368 r#"
369//- minicore: default
357pub struct Foo<T> { 370pub struct Foo<T> {
358 t: T, 371 t: T,
359} 372}
@@ -395,8 +408,10 @@ where
395 408
396 #[test] 409 #[test]
397 fn new_function_with_generics_and_wheres() { 410 fn new_function_with_generics_and_wheres() {
398 check_pass( 411 check_assist(
412 generate_default_from_new,
399 r#" 413 r#"
414//- minicore: default
400pub struct Foo<T, B> { 415pub struct Foo<T, B> {
401 _tars: T, 416 _tars: T,
402 _bar: B, 417 _bar: B,
@@ -441,8 +456,10 @@ where
441 #[test] 456 #[test]
442 fn new_function_with_parameters() { 457 fn new_function_with_parameters() {
443 cov_mark::check!(new_function_with_parameters); 458 cov_mark::check!(new_function_with_parameters);
444 check_not_applicable( 459 check_assist_not_applicable(
460 generate_default_from_new,
445 r#" 461 r#"
462//- minicore: default
446struct Example { _inner: () } 463struct Example { _inner: () }
447 464
448impl Example { 465impl Example {
@@ -457,7 +474,8 @@ impl Example {
457 #[test] 474 #[test]
458 fn other_function_than_new() { 475 fn other_function_than_new() {
459 cov_mark::check!(other_function_than_new); 476 cov_mark::check!(other_function_than_new);
460 check_not_applicable( 477 check_assist_not_applicable(
478 generate_default_from_new,
461 r#" 479 r#"
462struct Example { _inner: () } 480struct Example { _inner: () }
463 481
@@ -474,8 +492,10 @@ impl Example {
474 #[test] 492 #[test]
475 fn default_block_is_already_present() { 493 fn default_block_is_already_present() {
476 cov_mark::check!(default_block_is_already_present); 494 cov_mark::check!(default_block_is_already_present);
477 check_not_applicable( 495 check_assist_not_applicable(
496 generate_default_from_new,
478 r#" 497 r#"
498//- minicore: default
479struct Example { _inner: () } 499struct Example { _inner: () }
480 500
481impl Example { 501impl Example {
@@ -495,7 +515,8 @@ impl Default for Example {
495 515
496 #[test] 516 #[test]
497 fn standalone_new_function() { 517 fn standalone_new_function() {
498 check_not_applicable( 518 check_assist_not_applicable(
519 generate_default_from_new,
499 r#" 520 r#"
500fn n$0ew() -> u32 { 521fn n$0ew() -> u32 {
501 0 522 0
@@ -506,8 +527,10 @@ fn n$0ew() -> u32 {
506 527
507 #[test] 528 #[test]
508 fn multiple_struct_blocks() { 529 fn multiple_struct_blocks() {
509 check_pass( 530 check_assist(
531 generate_default_from_new,
510 r#" 532 r#"
533//- minicore: default
511struct Example { _inner: () } 534struct Example { _inner: () }
512struct Test { value: u32 } 535struct Test { value: u32 }
513 536
@@ -538,8 +561,10 @@ impl Default for Example {
538 561
539 #[test] 562 #[test]
540 fn when_struct_is_after_impl() { 563 fn when_struct_is_after_impl() {
541 check_pass( 564 check_assist(
565 generate_default_from_new,
542 r#" 566 r#"
567//- minicore: default
543impl Example { 568impl Example {
544 pub fn $0new() -> Self { 569 pub fn $0new() -> Self {
545 Self { _inner: () } 570 Self { _inner: () }
@@ -568,8 +593,10 @@ struct Example { _inner: () }
568 593
569 #[test] 594 #[test]
570 fn struct_in_module() { 595 fn struct_in_module() {
571 check_pass( 596 check_assist(
597 generate_default_from_new,
572 r#" 598 r#"
599//- minicore: default
573mod test { 600mod test {
574 struct Example { _inner: () } 601 struct Example { _inner: () }
575 602
@@ -603,8 +630,10 @@ impl Default for Example {
603 #[test] 630 #[test]
604 fn struct_in_module_with_default() { 631 fn struct_in_module_with_default() {
605 cov_mark::check!(struct_in_module_with_default); 632 cov_mark::check!(struct_in_module_with_default);
606 check_not_applicable( 633 check_assist_not_applicable(
634 generate_default_from_new,
607 r#" 635 r#"
636//- minicore: default
608mod test { 637mod test {
609 struct Example { _inner: () } 638 struct Example { _inner: () }
610 639
@@ -623,14 +652,4 @@ mod test {
623"#, 652"#,
624 ); 653 );
625 } 654 }
626
627 fn check_pass(before: &str, after: &str) {
628 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
629 check_assist(generate_default_from_new, before, after);
630 }
631
632 fn check_not_applicable(before: &str) {
633 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
634 check_assist_not_applicable(generate_default_from_new, before);
635 }
636} 655}
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
index 4998ff7a4..4e10fdb85 100644
--- a/crates/ide_assists/src/handlers/generate_deref.rs
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -182,23 +182,17 @@ impl std::ops::Deref for B {
182 ); 182 );
183 } 183 }
184 184
185 fn check_not_applicable(ra_fixture: &str) {
186 let fixture = format!(
187 "//- /main.rs crate:main deps:core,std\n{}\n{}",
188 ra_fixture,
189 FamousDefs::FIXTURE
190 );
191 check_assist_not_applicable(generate_deref, &fixture)
192 }
193
194 #[test] 185 #[test]
195 fn test_generate_record_deref_not_applicable_if_already_impl() { 186 fn test_generate_record_deref_not_applicable_if_already_impl() {
196 cov_mark::check!(test_add_record_deref_impl_already_exists); 187 cov_mark::check!(test_add_record_deref_impl_already_exists);
197 check_not_applicable( 188 check_assist_not_applicable(
198 r#"struct A { } 189 generate_deref,
190 r#"
191//- minicore: deref
192struct A { }
199struct B { $0a: A } 193struct B { $0a: A }
200 194
201impl std::ops::Deref for B { 195impl core::ops::Deref for B {
202 type Target = A; 196 type Target = A;
203 197
204 fn deref(&self) -> &Self::Target { 198 fn deref(&self) -> &Self::Target {
@@ -211,11 +205,14 @@ impl std::ops::Deref for B {
211 #[test] 205 #[test]
212 fn test_generate_field_deref_not_applicable_if_already_impl() { 206 fn test_generate_field_deref_not_applicable_if_already_impl() {
213 cov_mark::check!(test_add_field_deref_impl_already_exists); 207 cov_mark::check!(test_add_field_deref_impl_already_exists);
214 check_not_applicable( 208 check_assist_not_applicable(
215 r#"struct A { } 209 generate_deref,
210 r#"
211//- minicore: deref
212struct A { }
216struct B($0A) 213struct B($0A)
217 214
218impl std::ops::Deref for B { 215impl core::ops::Deref for B {
219 type Target = A; 216 type Target = A;
220 217
221 fn deref(&self) -> &Self::Target { 218 fn deref(&self) -> &Self::Target {
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index ce6998d82..8727be07d 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -110,14 +110,19 @@ mod tests {
110 fn test_generate_from_impl_for_enum() { 110 fn test_generate_from_impl_for_enum() {
111 check_assist( 111 check_assist(
112 generate_from_impl_for_enum, 112 generate_from_impl_for_enum,
113 "enum A { $0One(u32) }", 113 r#"
114 r#"enum A { One(u32) } 114//- minicore: from
115enum A { $0One(u32) }
116"#,
117 r#"
118enum A { One(u32) }
115 119
116impl From<u32> for A { 120impl From<u32> for A {
117 fn from(v: u32) -> Self { 121 fn from(v: u32) -> Self {
118 Self::One(v) 122 Self::One(v)
119 } 123 }
120}"#, 124}
125"#,
121 ); 126 );
122 } 127 }
123 128
@@ -125,53 +130,71 @@ impl From<u32> for A {
125 fn test_generate_from_impl_for_enum_complicated_path() { 130 fn test_generate_from_impl_for_enum_complicated_path() {
126 check_assist( 131 check_assist(
127 generate_from_impl_for_enum, 132 generate_from_impl_for_enum,
128 r#"enum A { $0One(foo::bar::baz::Boo) }"#, 133 r#"
129 r#"enum A { One(foo::bar::baz::Boo) } 134//- minicore: from
135enum A { $0One(foo::bar::baz::Boo) }
136"#,
137 r#"
138enum A { One(foo::bar::baz::Boo) }
130 139
131impl From<foo::bar::baz::Boo> for A { 140impl From<foo::bar::baz::Boo> for A {
132 fn from(v: foo::bar::baz::Boo) -> Self { 141 fn from(v: foo::bar::baz::Boo) -> Self {
133 Self::One(v) 142 Self::One(v)
134 } 143 }
135}"#, 144}
145"#,
136 ); 146 );
137 } 147 }
138 148
139 fn check_not_applicable(ra_fixture: &str) {
140 let fixture =
141 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
142 check_assist_not_applicable(generate_from_impl_for_enum, &fixture)
143 }
144
145 #[test] 149 #[test]
146 fn test_add_from_impl_no_element() { 150 fn test_add_from_impl_no_element() {
147 check_not_applicable("enum A { $0One }"); 151 check_assist_not_applicable(
152 generate_from_impl_for_enum,
153 r#"
154//- minicore: from
155enum A { $0One }
156"#,
157 );
148 } 158 }
149 159
150 #[test] 160 #[test]
151 fn test_add_from_impl_more_than_one_element_in_tuple() { 161 fn test_add_from_impl_more_than_one_element_in_tuple() {
152 check_not_applicable("enum A { $0One(u32, String) }"); 162 check_assist_not_applicable(
163 generate_from_impl_for_enum,
164 r#"
165//- minicore: from
166enum A { $0One(u32, String) }
167"#,
168 );
153 } 169 }
154 170
155 #[test] 171 #[test]
156 fn test_add_from_impl_struct_variant() { 172 fn test_add_from_impl_struct_variant() {
157 check_assist( 173 check_assist(
158 generate_from_impl_for_enum, 174 generate_from_impl_for_enum,
159 "enum A { $0One { x: u32 } }", 175 r#"
160 r#"enum A { One { x: u32 } } 176//- minicore: from
177enum A { $0One { x: u32 } }
178"#,
179 r#"
180enum A { One { x: u32 } }
161 181
162impl From<u32> for A { 182impl From<u32> for A {
163 fn from(x: u32) -> Self { 183 fn from(x: u32) -> Self {
164 Self::One { x } 184 Self::One { x }
165 } 185 }
166}"#, 186}
187"#,
167 ); 188 );
168 } 189 }
169 190
170 #[test] 191 #[test]
171 fn test_add_from_impl_already_exists() { 192 fn test_add_from_impl_already_exists() {
172 cov_mark::check!(test_add_from_impl_already_exists); 193 cov_mark::check!(test_add_from_impl_already_exists);
173 check_not_applicable( 194 check_assist_not_applicable(
195 generate_from_impl_for_enum,
174 r#" 196 r#"
197//- minicore: from
175enum A { $0One(u32), } 198enum A { $0One(u32), }
176 199
177impl From<u32> for A { 200impl From<u32> for A {
@@ -187,7 +210,9 @@ impl From<u32> for A {
187 fn test_add_from_impl_different_variant_impl_exists() { 210 fn test_add_from_impl_different_variant_impl_exists() {
188 check_assist( 211 check_assist(
189 generate_from_impl_for_enum, 212 generate_from_impl_for_enum,
190 r#"enum A { $0One(u32), Two(String), } 213 r#"
214//- minicore: from
215enum A { $0One(u32), Two(String), }
191 216
192impl From<String> for A { 217impl From<String> for A {
193 fn from(v: String) -> Self { 218 fn from(v: String) -> Self {
@@ -197,8 +222,10 @@ impl From<String> for A {
197 222
198pub trait From<T> { 223pub trait From<T> {
199 fn from(T) -> Self; 224 fn from(T) -> Self;
200}"#, 225}
201 r#"enum A { One(u32), Two(String), } 226"#,
227 r#"
228enum A { One(u32), Two(String), }
202 229
203impl From<u32> for A { 230impl From<u32> for A {
204 fn from(v: u32) -> Self { 231 fn from(v: u32) -> Self {
@@ -214,7 +241,8 @@ impl From<String> for A {
214 241
215pub trait From<T> { 242pub trait From<T> {
216 fn from(T) -> Self; 243 fn from(T) -> Self;
217}"#, 244}
245"#,
218 ); 246 );
219 } 247 }
220 248
@@ -222,14 +250,19 @@ pub trait From<T> {
222 fn test_add_from_impl_static_str() { 250 fn test_add_from_impl_static_str() {
223 check_assist( 251 check_assist(
224 generate_from_impl_for_enum, 252 generate_from_impl_for_enum,
225 "enum A { $0One(&'static str) }", 253 r#"
226 r#"enum A { One(&'static str) } 254//- minicore: from
255enum A { $0One(&'static str) }
256"#,
257 r#"
258enum A { One(&'static str) }
227 259
228impl From<&'static str> for A { 260impl From<&'static str> for A {
229 fn from(v: &'static str) -> Self { 261 fn from(v: &'static str) -> Self {
230 Self::One(v) 262 Self::One(v)
231 } 263 }
232}"#, 264}
265"#,
233 ); 266 );
234 } 267 }
235 268
@@ -237,14 +270,19 @@ impl From<&'static str> for A {
237 fn test_add_from_impl_generic_enum() { 270 fn test_add_from_impl_generic_enum() {
238 check_assist( 271 check_assist(
239 generate_from_impl_for_enum, 272 generate_from_impl_for_enum,
240 "enum Generic<T, U: Clone> { $0One(T), Two(U) }", 273 r#"
241 r#"enum Generic<T, U: Clone> { One(T), Two(U) } 274//- minicore: from
275enum Generic<T, U: Clone> { $0One(T), Two(U) }
276"#,
277 r#"
278enum Generic<T, U: Clone> { One(T), Two(U) }
242 279
243impl<T, U: Clone> From<T> for Generic<T, U> { 280impl<T, U: Clone> From<T> for Generic<T, U> {
244 fn from(v: T) -> Self { 281 fn from(v: T) -> Self {
245 Self::One(v) 282 Self::One(v)
246 } 283 }
247}"#, 284}
285"#,
248 ); 286 );
249 } 287 }
250 288
@@ -252,14 +290,19 @@ impl<T, U: Clone> From<T> for Generic<T, U> {
252 fn test_add_from_impl_with_lifetime() { 290 fn test_add_from_impl_with_lifetime() {
253 check_assist( 291 check_assist(
254 generate_from_impl_for_enum, 292 generate_from_impl_for_enum,
255 "enum Generic<'a> { $0One(&'a i32) }", 293 r#"
256 r#"enum Generic<'a> { One(&'a i32) } 294//- minicore: from
295enum Generic<'a> { $0One(&'a i32) }
296"#,
297 r#"
298enum Generic<'a> { One(&'a i32) }
257 299
258impl<'a> From<&'a i32> for Generic<'a> { 300impl<'a> From<&'a i32> for Generic<'a> {
259 fn from(v: &'a i32) -> Self { 301 fn from(v: &'a i32) -> Self {
260 Self::One(v) 302 Self::One(v)
261 } 303 }
262}"#, 304}
305"#,
263 ); 306 );
264 } 307 }
265} 308}
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index 706c995ac..6a658d4cf 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -811,9 +811,8 @@ fn bar(baz: Baz::Bof) ${0:-> ()} {
811 } 811 }
812 812
813 #[test] 813 #[test]
814 #[ignore]
815 // FIXME fix printing the generics of a `Ty` to make this test pass
816 fn add_function_with_generic_arg() { 814 fn add_function_with_generic_arg() {
815 // FIXME: This is wrong, generated `bar` should include generic parameter.
817 check_assist( 816 check_assist(
818 generate_function, 817 generate_function,
819 r" 818 r"
@@ -826,7 +825,7 @@ fn foo<T>(t: T) {
826 bar(t) 825 bar(t)
827} 826}
828 827
829fn bar<T>(t: T) ${0:-> ()} { 828fn bar(t: T) ${0:-> ()} {
830 todo!() 829 todo!()
831} 830}
832", 831",
@@ -834,9 +833,8 @@ fn bar<T>(t: T) ${0:-> ()} {
834 } 833 }
835 834
836 #[test] 835 #[test]
837 #[ignore]
838 // FIXME Fix function type printing to make this test pass
839 fn add_function_with_fn_arg() { 836 fn add_function_with_fn_arg() {
837 // FIXME: The argument in `bar` is wrong.
840 check_assist( 838 check_assist(
841 generate_function, 839 generate_function,
842 r" 840 r"
@@ -857,7 +855,7 @@ fn foo() {
857 bar(Baz::new); 855 bar(Baz::new);
858} 856}
859 857
860fn bar(arg: fn() -> Baz) ${0:-> ()} { 858fn bar(new: fn) ${0:-> ()} {
861 todo!() 859 todo!()
862} 860}
863", 861",
@@ -865,9 +863,8 @@ fn bar(arg: fn() -> Baz) ${0:-> ()} {
865 } 863 }
866 864
867 #[test] 865 #[test]
868 #[ignore]
869 // FIXME Fix closure type printing to make this test pass
870 fn add_function_with_closure_arg() { 866 fn add_function_with_closure_arg() {
867 // FIXME: The argument in `bar` is wrong.
871 check_assist( 868 check_assist(
872 generate_function, 869 generate_function,
873 r" 870 r"
@@ -882,7 +879,7 @@ fn foo() {
882 bar(closure) 879 bar(closure)
883} 880}
884 881
885fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} { 882fn bar(closure: ()) ${0:-> ()} {
886 todo!() 883 todo!()
887} 884}
888", 885",
@@ -986,13 +983,10 @@ fn foo() {
986 } 983 }
987 984
988 #[test] 985 #[test]
989 #[ignore]
990 // Ignored until local imports are supported.
991 // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
992 fn qualified_path_uses_correct_scope() { 986 fn qualified_path_uses_correct_scope() {
993 check_assist( 987 check_assist(
994 generate_function, 988 generate_function,
995 " 989 r#"
996mod foo { 990mod foo {
997 pub struct Foo; 991 pub struct Foo;
998} 992}
@@ -1001,8 +995,8 @@ fn bar() {
1001 let foo = Foo; 995 let foo = Foo;
1002 baz$0(foo) 996 baz$0(foo)
1003} 997}
1004", 998"#,
1005 " 999 r#"
1006mod foo { 1000mod foo {
1007 pub struct Foo; 1001 pub struct Foo;
1008} 1002}
@@ -1015,7 +1009,7 @@ fn bar() {
1015fn baz(foo: foo::Foo) ${0:-> ()} { 1009fn baz(foo: foo::Foo) ${0:-> ()} {
1016 todo!() 1010 todo!()
1017} 1011}
1018", 1012"#,
1019 ) 1013 )
1020 } 1014 }
1021 1015
@@ -1141,40 +1135,29 @@ fn bar() {}
1141 // The assist is only active if the cursor is on an unresolved path, 1135 // The assist is only active if the cursor is on an unresolved path,
1142 // but the assist should only be offered if the path is a function call. 1136 // but the assist should only be offered if the path is a function call.
1143 generate_function, 1137 generate_function,
1144 r" 1138 r#"
1145fn foo() { 1139fn foo() {
1146 bar(b$0az); 1140 bar(b$0az);
1147} 1141}
1148 1142
1149fn bar(baz: ()) {} 1143fn bar(baz: ()) {}
1150", 1144"#,
1151 ) 1145 )
1152 } 1146 }
1153 1147
1154 #[test] 1148 #[test]
1155 #[ignore]
1156 fn create_method_with_no_args() { 1149 fn create_method_with_no_args() {
1157 check_assist( 1150 // FIXME: This is wrong, this should just work.
1151 check_assist_not_applicable(
1158 generate_function, 1152 generate_function,
1159 r" 1153 r#"
1160struct Foo; 1154struct Foo;
1161impl Foo { 1155impl Foo {
1162 fn foo(&self) { 1156 fn foo(&self) {
1163 self.bar()$0; 1157 self.bar()$0;
1164 } 1158 }
1165} 1159}
1166 ", 1160 "#,
1167 r"
1168struct Foo;
1169impl Foo {
1170 fn foo(&self) {
1171 self.bar();
1172 }
1173 fn bar(&self) {
1174 todo!();
1175 }
1176}
1177 ",
1178 ) 1161 )
1179 } 1162 }
1180} 1163}
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs
index 2441dbb8b..945d28650 100644
--- a/crates/ide_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ide_assists/src/handlers/inline_local_variable.rs
@@ -65,32 +65,35 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
65 Some(u) => u, 65 Some(u) => u,
66 None => return Some(false), 66 None => return Some(false),
67 }; 67 };
68 68 Some(
69 Some(!matches!( 69 !(matches!(
70 (&initializer_expr, usage_parent), 70 initializer_expr,
71 (ast::Expr::CallExpr(_), _) 71 ast::Expr::CallExpr(_)
72 | (ast::Expr::IndexExpr(_), _) 72 | ast::Expr::IndexExpr(_)
73 | (ast::Expr::MethodCallExpr(_), _) 73 | ast::Expr::MethodCallExpr(_)
74 | (ast::Expr::FieldExpr(_), _) 74 | ast::Expr::FieldExpr(_)
75 | (ast::Expr::TryExpr(_), _) 75 | ast::Expr::TryExpr(_)
76 | (ast::Expr::RefExpr(_), _) 76 | ast::Expr::RefExpr(_)
77 | (ast::Expr::Literal(_), _) 77 | ast::Expr::Literal(_)
78 | (ast::Expr::TupleExpr(_), _) 78 | ast::Expr::TupleExpr(_)
79 | (ast::Expr::ArrayExpr(_), _) 79 | ast::Expr::ArrayExpr(_)
80 | (ast::Expr::ParenExpr(_), _) 80 | ast::Expr::ParenExpr(_)
81 | (ast::Expr::PathExpr(_), _) 81 | ast::Expr::PathExpr(_)
82 | (ast::Expr::BlockExpr(_), _) 82 | ast::Expr::BlockExpr(_)
83 | (ast::Expr::EffectExpr(_), _) 83 | ast::Expr::EffectExpr(_),
84 | (_, ast::Expr::CallExpr(_)) 84 ) || matches!(
85 | (_, ast::Expr::TupleExpr(_)) 85 usage_parent,
86 | (_, ast::Expr::ArrayExpr(_)) 86 ast::Expr::CallExpr(_)
87 | (_, ast::Expr::ParenExpr(_)) 87 | ast::Expr::TupleExpr(_)
88 | (_, ast::Expr::ForExpr(_)) 88 | ast::Expr::ArrayExpr(_)
89 | (_, ast::Expr::WhileExpr(_)) 89 | ast::Expr::ParenExpr(_)
90 | (_, ast::Expr::BreakExpr(_)) 90 | ast::Expr::ForExpr(_)
91 | (_, ast::Expr::ReturnExpr(_)) 91 | ast::Expr::WhileExpr(_)
92 | (_, ast::Expr::MatchExpr(_)) 92 | ast::Expr::BreakExpr(_)
93 )) 93 | ast::Expr::ReturnExpr(_)
94 | ast::Expr::MatchExpr(_)
95 )),
96 )
94 }) 97 })
95 .collect::<Option<_>>() 98 .collect::<Option<_>>()
96 .map(|b| (file_id, b)) 99 .map(|b| (file_id, b))
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 93f702c55..cfc54be8d 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -1,5 +1,8 @@
1use std::iter;
2
1use ast::edit::IndentLevel; 3use ast::edit::IndentLevel;
2use ide_db::base_db::AnchoredPathBuf; 4use ide_db::base_db::AnchoredPathBuf;
5use itertools::Itertools;
3use stdx::format_to; 6use stdx::format_to;
4use syntax::{ 7use syntax::{
5 ast::{self, edit::AstNodeEdit, NameOwner}, 8 ast::{self, edit::AstNodeEdit, NameOwner},
@@ -34,7 +37,10 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
34 37
35 let module_name = module_ast.name()?; 38 let module_name = module_ast.name()?;
36 39
37 let module_def = ctx.sema.to_def(&module_ast)?; 40 // get to the outermost module syntax so we can grab the module of file we are in
41 let outermost_mod_decl =
42 iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
43 let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
38 let parent_module = module_def.parent(ctx.db())?; 44 let parent_module = module_def.parent(ctx.db())?;
39 45
40 acc.add( 46 acc.add(
@@ -43,11 +49,19 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
43 target, 49 target,
44 |builder| { 50 |builder| {
45 let path = { 51 let path = {
46 let dir = match parent_module.name(ctx.db()) { 52 let mut buf = String::from("./");
47 Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), 53 match parent_module.name(ctx.db()) {
48 _ => String::new(), 54 Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
49 }; 55 format_to!(buf, "{}/", name)
50 format!("./{}{}.rs", dir, module_name) 56 }
57 _ => (),
58 }
59 let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
60 .filter_map(|it| it.name())
61 .collect::<Vec<_>>();
62 format_to!(buf, "{}", segments.into_iter().rev().format("/"));
63 format_to!(buf, ".rs");
64 buf
51 }; 65 };
52 let contents = { 66 let contents = {
53 let items = module_items.dedent(IndentLevel(1)).to_string(); 67 let items = module_items.dedent(IndentLevel(1)).to_string();
@@ -59,14 +73,13 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
59 items 73 items
60 }; 74 };
61 75
62 let mut buf = String::new(); 76 let buf = format!("mod {};", module_name);
63 format_to!(buf, "mod {};", module_name);
64 77
65 let replacement_start = if let Some(mod_token) = module_ast.mod_token() { 78 let replacement_start = match module_ast.mod_token() {
66 mod_token.text_range().start() 79 Some(mod_token) => mod_token.text_range(),
67 } else { 80 None => module_ast.syntax().text_range(),
68 module_ast.syntax().text_range().start() 81 }
69 }; 82 .start();
70 83
71 builder.replace( 84 builder.replace(
72 TextRange::new(replacement_start, module_ast.syntax().text_range().end()), 85 TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
@@ -212,4 +225,30 @@ mod tests;
212"#, 225"#,
213 ); 226 );
214 } 227 }
228
229 #[test]
230 fn extract_nested() {
231 check_assist(
232 move_module_to_file,
233 r#"
234//- /lib.rs
235mod foo;
236//- /foo.rs
237mod bar {
238 mod baz {
239 mod qux$0 {}
240 }
241}
242"#,
243 r#"
244//- /foo.rs
245mod bar {
246 mod baz {
247 mod qux;
248 }
249}
250//- /foo/bar/baz/qux.rs
251"#,
252 );
253 }
215} 254}
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index f91770a76..1d7be183a 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -216,28 +216,28 @@ mod tests {
216 cov_mark::check!(qualify_path_unqualified_name); 216 cov_mark::check!(qualify_path_unqualified_name);
217 check_assist( 217 check_assist(
218 qualify_path, 218 qualify_path,
219 r" 219 r#"
220 mod std { 220mod std {
221 pub mod fmt { 221 pub mod fmt {
222 pub struct Formatter; 222 pub struct Formatter;
223 } 223 }
224 } 224}
225 225
226 use std::fmt; 226use std::fmt;
227 227
228 $0Formatter 228$0Formatter
229 ", 229"#,
230 r" 230 r#"
231 mod std { 231mod std {
232 pub mod fmt { 232 pub mod fmt {
233 pub struct Formatter; 233 pub struct Formatter;
234 } 234 }
235 } 235}
236 236
237 use std::fmt; 237use std::fmt;
238 238
239 fmt::Formatter 239fmt::Formatter
240 ", 240"#,
241 ); 241 );
242 } 242 }
243 243
@@ -245,20 +245,20 @@ mod tests {
245 fn applicable_when_found_an_import() { 245 fn applicable_when_found_an_import() {
246 check_assist( 246 check_assist(
247 qualify_path, 247 qualify_path,
248 r" 248 r#"
249 $0PubStruct 249$0PubStruct
250 250
251 pub mod PubMod { 251pub mod PubMod {
252 pub struct PubStruct; 252 pub struct PubStruct;
253 } 253}
254 ", 254"#,
255 r" 255 r#"
256 PubMod::PubStruct 256PubMod::PubStruct
257 257
258 pub mod PubMod { 258pub mod PubMod {
259 pub struct PubStruct; 259 pub struct PubStruct;
260 } 260}
261 ", 261"#,
262 ); 262 );
263 } 263 }
264 264
@@ -266,26 +266,26 @@ mod tests {
266 fn applicable_in_macros() { 266 fn applicable_in_macros() {
267 check_assist( 267 check_assist(
268 qualify_path, 268 qualify_path,
269 r" 269 r#"
270 macro_rules! foo { 270macro_rules! foo {
271 ($i:ident) => { fn foo(a: $i) {} } 271 ($i:ident) => { fn foo(a: $i) {} }
272 } 272}
273 foo!(Pub$0Struct); 273foo!(Pub$0Struct);
274 274
275 pub mod PubMod { 275pub mod PubMod {
276 pub struct PubStruct; 276 pub struct PubStruct;
277 } 277}
278 ", 278"#,
279 r" 279 r#"
280 macro_rules! foo { 280macro_rules! foo {
281 ($i:ident) => { fn foo(a: $i) {} } 281 ($i:ident) => { fn foo(a: $i) {} }
282 } 282}
283 foo!(PubMod::PubStruct); 283foo!(PubMod::PubStruct);
284 284
285 pub mod PubMod { 285pub mod PubMod {
286 pub struct PubStruct; 286 pub struct PubStruct;
287 } 287}
288 ", 288"#,
289 ); 289 );
290 } 290 }
291 291
@@ -293,32 +293,32 @@ mod tests {
293 fn applicable_when_found_multiple_imports() { 293 fn applicable_when_found_multiple_imports() {
294 check_assist( 294 check_assist(
295 qualify_path, 295 qualify_path,
296 r" 296 r#"
297 PubSt$0ruct 297PubSt$0ruct
298 298
299 pub mod PubMod1 { 299pub mod PubMod1 {
300 pub struct PubStruct; 300 pub struct PubStruct;
301 } 301}
302 pub mod PubMod2 { 302pub mod PubMod2 {
303 pub struct PubStruct; 303 pub struct PubStruct;
304 } 304}
305 pub mod PubMod3 { 305pub mod PubMod3 {
306 pub struct PubStruct; 306 pub struct PubStruct;
307 } 307}
308 ", 308"#,
309 r" 309 r#"
310 PubMod3::PubStruct 310PubMod3::PubStruct
311 311
312 pub mod PubMod1 { 312pub mod PubMod1 {
313 pub struct PubStruct; 313 pub struct PubStruct;
314 } 314}
315 pub mod PubMod2 { 315pub mod PubMod2 {
316 pub struct PubStruct; 316 pub struct PubStruct;
317 } 317}
318 pub mod PubMod3 { 318pub mod PubMod3 {
319 pub struct PubStruct; 319 pub struct PubStruct;
320 } 320}
321 ", 321"#,
322 ); 322 );
323 } 323 }
324 324
@@ -326,15 +326,15 @@ mod tests {
326 fn not_applicable_for_already_imported_types() { 326 fn not_applicable_for_already_imported_types() {
327 check_assist_not_applicable( 327 check_assist_not_applicable(
328 qualify_path, 328 qualify_path,
329 r" 329 r#"
330 use PubMod::PubStruct; 330use PubMod::PubStruct;
331 331
332 PubStruct$0 332PubStruct$0
333 333
334 pub mod PubMod { 334pub mod PubMod {
335 pub struct PubStruct; 335 pub struct PubStruct;
336 } 336}
337 ", 337"#,
338 ); 338 );
339 } 339 }
340 340
@@ -342,35 +342,32 @@ mod tests {
342 fn not_applicable_for_types_with_private_paths() { 342 fn not_applicable_for_types_with_private_paths() {
343 check_assist_not_applicable( 343 check_assist_not_applicable(
344 qualify_path, 344 qualify_path,
345 r" 345 r#"
346 PrivateStruct$0 346PrivateStruct$0
347 347
348 pub mod PubMod { 348pub mod PubMod {
349 struct PrivateStruct; 349 struct PrivateStruct;
350 } 350}
351 ", 351"#,
352 ); 352 );
353 } 353 }
354 354
355 #[test] 355 #[test]
356 fn not_applicable_when_no_imports_found() { 356 fn not_applicable_when_no_imports_found() {
357 check_assist_not_applicable( 357 check_assist_not_applicable(qualify_path, r#"PubStruct$0"#);
358 qualify_path,
359 "
360 PubStruct$0",
361 );
362 } 358 }
363 359
364 #[test] 360 #[test]
365 fn not_applicable_in_import_statements() { 361 fn not_applicable_in_import_statements() {
366 check_assist_not_applicable( 362 check_assist_not_applicable(
367 qualify_path, 363 qualify_path,
368 r" 364 r#"
369 use PubStruct$0; 365use PubStruct$0;
370 366
371 pub mod PubMod { 367pub mod PubMod {
372 pub struct PubStruct; 368 pub struct PubStruct;
373 }", 369}
370"#,
374 ); 371 );
375 } 372 }
376 373
@@ -378,20 +375,20 @@ mod tests {
378 fn qualify_function() { 375 fn qualify_function() {
379 check_assist( 376 check_assist(
380 qualify_path, 377 qualify_path,
381 r" 378 r#"
382 test_function$0 379test_function$0
383 380
384 pub mod PubMod { 381pub mod PubMod {
385 pub fn test_function() {}; 382 pub fn test_function() {};
386 } 383}
387 ", 384"#,
388 r" 385 r#"
389 PubMod::test_function 386PubMod::test_function
390 387
391 pub mod PubMod { 388pub mod PubMod {
392 pub fn test_function() {}; 389 pub fn test_function() {};
393 } 390}
394 ", 391"#,
395 ); 392 );
396 } 393 }
397 394
@@ -399,7 +396,7 @@ mod tests {
399 fn qualify_macro() { 396 fn qualify_macro() {
400 check_assist( 397 check_assist(
401 qualify_path, 398 qualify_path,
402 r" 399 r#"
403//- /lib.rs crate:crate_with_macro 400//- /lib.rs crate:crate_with_macro
404#[macro_export] 401#[macro_export]
405macro_rules! foo { 402macro_rules! foo {
@@ -410,12 +407,12 @@ macro_rules! foo {
410fn main() { 407fn main() {
411 foo$0 408 foo$0
412} 409}
413", 410"#,
414 r" 411 r#"
415fn main() { 412fn main() {
416 crate_with_macro::foo 413 crate_with_macro::foo
417} 414}
418", 415"#,
419 ); 416 );
420 } 417 }
421 418
@@ -423,13 +420,13 @@ fn main() {
423 fn qualify_path_target() { 420 fn qualify_path_target() {
424 check_assist_target( 421 check_assist_target(
425 qualify_path, 422 qualify_path,
426 r" 423 r#"
427 struct AssistInfo { 424struct AssistInfo {
428 group_label: Option<$0GroupLabel>, 425 group_label: Option<$0GroupLabel>,
429 } 426}
430 427
431 mod m { pub struct GroupLabel; } 428mod m { pub struct GroupLabel; }
432 ", 429"#,
433 "GroupLabel", 430 "GroupLabel",
434 ) 431 )
435 } 432 }
@@ -438,20 +435,20 @@ fn main() {
438 fn not_applicable_when_path_start_is_imported() { 435 fn not_applicable_when_path_start_is_imported() {
439 check_assist_not_applicable( 436 check_assist_not_applicable(
440 qualify_path, 437 qualify_path,
441 r" 438 r#"
442 pub mod mod1 { 439pub mod mod1 {
443 pub mod mod2 { 440 pub mod mod2 {
444 pub mod mod3 { 441 pub mod mod3 {
445 pub struct TestStruct; 442 pub struct TestStruct;
446 } 443 }
447 } 444 }
448 } 445}
449 446
450 use mod1::mod2; 447use mod1::mod2;
451 fn main() { 448fn main() {
452 mod2::mod3::TestStruct$0 449 mod2::mod3::TestStruct$0
453 } 450}
454 ", 451"#,
455 ); 452 );
456 } 453 }
457 454
@@ -459,16 +456,16 @@ fn main() {
459 fn not_applicable_for_imported_function() { 456 fn not_applicable_for_imported_function() {
460 check_assist_not_applicable( 457 check_assist_not_applicable(
461 qualify_path, 458 qualify_path,
462 r" 459 r#"
463 pub mod test_mod { 460pub mod test_mod {
464 pub fn test_function() {} 461 pub fn test_function() {}
465 } 462}
466 463
467 use test_mod::test_function; 464use test_mod::test_function;
468 fn main() { 465fn main() {
469 test_function$0 466 test_function$0
470 } 467}
471 ", 468"#,
472 ); 469 );
473 } 470 }
474 471
@@ -476,30 +473,30 @@ fn main() {
476 fn associated_struct_function() { 473 fn associated_struct_function() {
477 check_assist( 474 check_assist(
478 qualify_path, 475 qualify_path,
479 r" 476 r#"
480 mod test_mod { 477mod test_mod {
481 pub struct TestStruct {} 478 pub struct TestStruct {}
482 impl TestStruct { 479 impl TestStruct {
483 pub fn test_function() {} 480 pub fn test_function() {}
484 } 481 }
485 } 482}
486 483
487 fn main() { 484fn main() {
488 TestStruct::test_function$0 485 TestStruct::test_function$0
489 } 486}
490 ", 487"#,
491 r" 488 r#"
492 mod test_mod { 489mod test_mod {
493 pub struct TestStruct {} 490 pub struct TestStruct {}
494 impl TestStruct { 491 impl TestStruct {
495 pub fn test_function() {} 492 pub fn test_function() {}
496 } 493 }
497 } 494}
498 495
499 fn main() { 496fn main() {
500 test_mod::TestStruct::test_function 497 test_mod::TestStruct::test_function
501 } 498}
502 ", 499"#,
503 ); 500 );
504 } 501 }
505 502
@@ -508,62 +505,50 @@ fn main() {
508 cov_mark::check!(qualify_path_qualifier_start); 505 cov_mark::check!(qualify_path_qualifier_start);
509 check_assist( 506 check_assist(
510 qualify_path, 507 qualify_path,
511 r" 508 r#"
512 mod test_mod { 509mod test_mod {
513 pub struct TestStruct {} 510 pub struct TestStruct {}
514 impl TestStruct { 511 impl TestStruct {
515 const TEST_CONST: u8 = 42; 512 const TEST_CONST: u8 = 42;
516 } 513 }
517 } 514}
518 515
519 fn main() { 516fn main() {
520 TestStruct::TEST_CONST$0 517 TestStruct::TEST_CONST$0
521 } 518}
522 ", 519"#,
523 r" 520 r#"
524 mod test_mod { 521mod test_mod {
525 pub struct TestStruct {} 522 pub struct TestStruct {}
526 impl TestStruct { 523 impl TestStruct {
527 const TEST_CONST: u8 = 42; 524 const TEST_CONST: u8 = 42;
528 } 525 }
529 } 526}
530 527
531 fn main() { 528fn main() {
532 test_mod::TestStruct::TEST_CONST 529 test_mod::TestStruct::TEST_CONST
533 } 530}
534 ", 531"#,
535 ); 532 );
536 } 533 }
537 534
538 #[test] 535 #[test]
539 #[ignore = "FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details"]
540 fn associated_struct_const_unqualified() { 536 fn associated_struct_const_unqualified() {
541 check_assist( 537 // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details
538 check_assist_not_applicable(
542 qualify_path, 539 qualify_path,
543 r" 540 r#"
544 mod test_mod { 541mod test_mod {
545 pub struct TestStruct {} 542 pub struct TestStruct {}
546 impl TestStruct { 543 impl TestStruct {
547 const TEST_CONST: u8 = 42; 544 const TEST_CONST: u8 = 42;
548 } 545 }
549 } 546}
550
551 fn main() {
552 TEST_CONST$0
553 }
554 ",
555 r"
556 mod test_mod {
557 pub struct TestStruct {}
558 impl TestStruct {
559 const TEST_CONST: u8 = 42;
560 }
561 }
562 547
563 fn main() { 548fn main() {
564 test_mod::TestStruct::TEST_CONST 549 TEST_CONST$0
565 } 550}
566 ", 551"#,
567 ); 552 );
568 } 553 }
569 554
@@ -571,36 +556,36 @@ fn main() {
571 fn associated_trait_function() { 556 fn associated_trait_function() {
572 check_assist( 557 check_assist(
573 qualify_path, 558 qualify_path,
574 r" 559 r#"
575 mod test_mod { 560mod test_mod {
576 pub trait TestTrait { 561 pub trait TestTrait {
577 fn test_function(); 562 fn test_function();
578 } 563 }
579 pub struct TestStruct {} 564 pub struct TestStruct {}
580 impl TestTrait for TestStruct { 565 impl TestTrait for TestStruct {
581 fn test_function() {} 566 fn test_function() {}
582 } 567 }
583 } 568}
584 569
585 fn main() { 570fn main() {
586 test_mod::TestStruct::test_function$0 571 test_mod::TestStruct::test_function$0
587 } 572}
588 ", 573"#,
589 r" 574 r#"
590 mod test_mod { 575mod test_mod {
591 pub trait TestTrait { 576 pub trait TestTrait {
592 fn test_function(); 577 fn test_function();
593 } 578 }
594 pub struct TestStruct {} 579 pub struct TestStruct {}
595 impl TestTrait for TestStruct { 580 impl TestTrait for TestStruct {
596 fn test_function() {} 581 fn test_function() {}
597 } 582 }
598 } 583}
599 584
600 fn main() { 585fn main() {
601 <test_mod::TestStruct as test_mod::TestTrait>::test_function 586 <test_mod::TestStruct as test_mod::TestTrait>::test_function
602 } 587}
603 ", 588"#,
604 ); 589 );
605 } 590 }
606 591
@@ -608,31 +593,31 @@ fn main() {
608 fn not_applicable_for_imported_trait_for_function() { 593 fn not_applicable_for_imported_trait_for_function() {
609 check_assist_not_applicable( 594 check_assist_not_applicable(
610 qualify_path, 595 qualify_path,
611 r" 596 r#"
612 mod test_mod { 597mod test_mod {
613 pub trait TestTrait { 598 pub trait TestTrait {
614 fn test_function(); 599 fn test_function();
615 } 600 }
616 pub trait TestTrait2 { 601 pub trait TestTrait2 {
617 fn test_function(); 602 fn test_function();
618 } 603 }
619 pub enum TestEnum { 604 pub enum TestEnum {
620 One, 605 One,
621 Two, 606 Two,
622 } 607 }
623 impl TestTrait2 for TestEnum { 608 impl TestTrait2 for TestEnum {
624 fn test_function() {} 609 fn test_function() {}
625 } 610 }
626 impl TestTrait for TestEnum { 611 impl TestTrait for TestEnum {
627 fn test_function() {} 612 fn test_function() {}
628 } 613 }
629 } 614}
630 615
631 use test_mod::TestTrait2; 616use test_mod::TestTrait2;
632 fn main() { 617fn main() {
633 test_mod::TestEnum::test_function$0; 618 test_mod::TestEnum::test_function$0;
634 } 619}
635 ", 620"#,
636 ) 621 )
637 } 622 }
638 623
@@ -641,36 +626,36 @@ fn main() {
641 cov_mark::check!(qualify_path_trait_assoc_item); 626 cov_mark::check!(qualify_path_trait_assoc_item);
642 check_assist( 627 check_assist(
643 qualify_path, 628 qualify_path,
644 r" 629 r#"
645 mod test_mod { 630mod test_mod {
646 pub trait TestTrait { 631 pub trait TestTrait {
647 const TEST_CONST: u8; 632 const TEST_CONST: u8;
648 } 633 }
649 pub struct TestStruct {} 634 pub struct TestStruct {}
650 impl TestTrait for TestStruct { 635 impl TestTrait for TestStruct {
651 const TEST_CONST: u8 = 42; 636 const TEST_CONST: u8 = 42;
652 } 637 }
653 } 638}
654 639
655 fn main() { 640fn main() {
656 test_mod::TestStruct::TEST_CONST$0 641 test_mod::TestStruct::TEST_CONST$0
657 } 642}
658 ", 643"#,
659 r" 644 r#"
660 mod test_mod { 645mod test_mod {
661 pub trait TestTrait { 646 pub trait TestTrait {
662 const TEST_CONST: u8; 647 const TEST_CONST: u8;
663 } 648 }
664 pub struct TestStruct {} 649 pub struct TestStruct {}
665 impl TestTrait for TestStruct { 650 impl TestTrait for TestStruct {
666 const TEST_CONST: u8 = 42; 651 const TEST_CONST: u8 = 42;
667 } 652 }
668 } 653}
669 654
670 fn main() { 655fn main() {
671 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST 656 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
672 } 657}
673 ", 658"#,
674 ); 659 );
675 } 660 }
676 661
@@ -678,31 +663,31 @@ fn main() {
678 fn not_applicable_for_imported_trait_for_const() { 663 fn not_applicable_for_imported_trait_for_const() {
679 check_assist_not_applicable( 664 check_assist_not_applicable(
680 qualify_path, 665 qualify_path,
681 r" 666 r#"
682 mod test_mod { 667mod test_mod {
683 pub trait TestTrait { 668 pub trait TestTrait {
684 const TEST_CONST: u8; 669 const TEST_CONST: u8;
685 } 670 }
686 pub trait TestTrait2 { 671 pub trait TestTrait2 {
687 const TEST_CONST: f64; 672 const TEST_CONST: f64;
688 } 673 }
689 pub enum TestEnum { 674 pub enum TestEnum {
690 One, 675 One,
691 Two, 676 Two,
692 } 677 }
693 impl TestTrait2 for TestEnum { 678 impl TestTrait2 for TestEnum {
694 const TEST_CONST: f64 = 42.0; 679 const TEST_CONST: f64 = 42.0;
695 } 680 }
696 impl TestTrait for TestEnum { 681 impl TestTrait for TestEnum {
697 const TEST_CONST: u8 = 42; 682 const TEST_CONST: u8 = 42;
698 } 683 }
699 } 684}
700 685
701 use test_mod::TestTrait2; 686use test_mod::TestTrait2;
702 fn main() { 687fn main() {
703 test_mod::TestEnum::TEST_CONST$0; 688 test_mod::TestEnum::TEST_CONST$0;
704 } 689}
705 ", 690"#,
706 ) 691 )
707 } 692 }
708 693
@@ -711,38 +696,38 @@ fn main() {
711 cov_mark::check!(qualify_path_trait_method); 696 cov_mark::check!(qualify_path_trait_method);
712 check_assist( 697 check_assist(
713 qualify_path, 698 qualify_path,
714 r" 699 r#"
715 mod test_mod { 700mod test_mod {
716 pub trait TestTrait { 701 pub trait TestTrait {
717 fn test_method(&self); 702 fn test_method(&self);
718 } 703 }
719 pub struct TestStruct {} 704 pub struct TestStruct {}
720 impl TestTrait for TestStruct { 705 impl TestTrait for TestStruct {
721 fn test_method(&self) {} 706 fn test_method(&self) {}
722 } 707 }
723 } 708}
724 709
725 fn main() { 710fn main() {
726 let test_struct = test_mod::TestStruct {}; 711 let test_struct = test_mod::TestStruct {};
727 test_struct.test_meth$0od() 712 test_struct.test_meth$0od()
728 } 713}
729 ", 714"#,
730 r" 715 r#"
731 mod test_mod { 716mod test_mod {
732 pub trait TestTrait { 717 pub trait TestTrait {
733 fn test_method(&self); 718 fn test_method(&self);
734 } 719 }
735 pub struct TestStruct {} 720 pub struct TestStruct {}
736 impl TestTrait for TestStruct { 721 impl TestTrait for TestStruct {
737 fn test_method(&self) {} 722 fn test_method(&self) {}
738 } 723 }
739 } 724}
740 725
741 fn main() { 726fn main() {
742 let test_struct = test_mod::TestStruct {}; 727 let test_struct = test_mod::TestStruct {};
743 test_mod::TestTrait::test_method(&test_struct) 728 test_mod::TestTrait::test_method(&test_struct)
744 } 729}
745 ", 730"#,
746 ); 731 );
747 } 732 }
748 733
@@ -750,38 +735,38 @@ fn main() {
750 fn trait_method_multi_params() { 735 fn trait_method_multi_params() {
751 check_assist( 736 check_assist(
752 qualify_path, 737 qualify_path,
753 r" 738 r#"
754 mod test_mod { 739mod test_mod {
755 pub trait TestTrait { 740 pub trait TestTrait {
756 fn test_method(&self, test: i32); 741 fn test_method(&self, test: i32);
757 } 742 }
758 pub struct TestStruct {} 743 pub struct TestStruct {}
759 impl TestTrait for TestStruct { 744 impl TestTrait for TestStruct {
760 fn test_method(&self, test: i32) {} 745 fn test_method(&self, test: i32) {}
761 } 746 }
762 } 747}
763 748
764 fn main() { 749fn main() {
765 let test_struct = test_mod::TestStruct {}; 750 let test_struct = test_mod::TestStruct {};
766 test_struct.test_meth$0od(42) 751 test_struct.test_meth$0od(42)
767 } 752}
768 ", 753"#,
769 r" 754 r#"
770 mod test_mod { 755mod test_mod {
771 pub trait TestTrait { 756 pub trait TestTrait {
772 fn test_method(&self, test: i32); 757 fn test_method(&self, test: i32);
773 } 758 }
774 pub struct TestStruct {} 759 pub struct TestStruct {}
775 impl TestTrait for TestStruct { 760 impl TestTrait for TestStruct {
776 fn test_method(&self, test: i32) {} 761 fn test_method(&self, test: i32) {}
777 } 762 }
778 } 763}
779 764
780 fn main() { 765fn main() {
781 let test_struct = test_mod::TestStruct {}; 766 let test_struct = test_mod::TestStruct {};
782 test_mod::TestTrait::test_method(&test_struct, 42) 767 test_mod::TestTrait::test_method(&test_struct, 42)
783 } 768}
784 ", 769"#,
785 ); 770 );
786 } 771 }
787 772
@@ -789,38 +774,38 @@ fn main() {
789 fn trait_method_consume() { 774 fn trait_method_consume() {
790 check_assist( 775 check_assist(
791 qualify_path, 776 qualify_path,
792 r" 777 r#"
793 mod test_mod { 778mod test_mod {
794 pub trait TestTrait { 779 pub trait TestTrait {
795 fn test_method(self); 780 fn test_method(self);
796 } 781 }
797 pub struct TestStruct {} 782 pub struct TestStruct {}
798 impl TestTrait for TestStruct { 783 impl TestTrait for TestStruct {
799 fn test_method(self) {} 784 fn test_method(self) {}
800 } 785 }
801 } 786}
802 787
803 fn main() { 788fn main() {
804 let test_struct = test_mod::TestStruct {}; 789 let test_struct = test_mod::TestStruct {};
805 test_struct.test_meth$0od() 790 test_struct.test_meth$0od()
806 } 791}
807 ", 792"#,
808 r" 793 r#"
809 mod test_mod { 794mod test_mod {
810 pub trait TestTrait { 795 pub trait TestTrait {
811 fn test_method(self); 796 fn test_method(self);
812 } 797 }
813 pub struct TestStruct {} 798 pub struct TestStruct {}
814 impl TestTrait for TestStruct { 799 impl TestTrait for TestStruct {
815 fn test_method(self) {} 800 fn test_method(self) {}
816 } 801 }
817 } 802}
818 803
819 fn main() { 804fn main() {
820 let test_struct = test_mod::TestStruct {}; 805 let test_struct = test_mod::TestStruct {};
821 test_mod::TestTrait::test_method(test_struct) 806 test_mod::TestTrait::test_method(test_struct)
822 } 807}
823 ", 808"#,
824 ); 809 );
825 } 810 }
826 811
@@ -828,29 +813,29 @@ fn main() {
828 fn trait_method_cross_crate() { 813 fn trait_method_cross_crate() {
829 check_assist( 814 check_assist(
830 qualify_path, 815 qualify_path,
831 r" 816 r#"
832 //- /main.rs crate:main deps:dep 817//- /main.rs crate:main deps:dep
833 fn main() { 818fn main() {
834 let test_struct = dep::test_mod::TestStruct {}; 819 let test_struct = dep::test_mod::TestStruct {};
835 test_struct.test_meth$0od() 820 test_struct.test_meth$0od()
836 } 821}
837 //- /dep.rs crate:dep 822//- /dep.rs crate:dep
838 pub mod test_mod { 823pub mod test_mod {
839 pub trait TestTrait { 824 pub trait TestTrait {
840 fn test_method(&self); 825 fn test_method(&self);
841 } 826 }
842 pub struct TestStruct {} 827 pub struct TestStruct {}
843 impl TestTrait for TestStruct { 828 impl TestTrait for TestStruct {
844 fn test_method(&self) {} 829 fn test_method(&self) {}
845 } 830 }
846 } 831}
847 ", 832"#,
848 r" 833 r#"
849 fn main() { 834fn main() {
850 let test_struct = dep::test_mod::TestStruct {}; 835 let test_struct = dep::test_mod::TestStruct {};
851 dep::test_mod::TestTrait::test_method(&test_struct) 836 dep::test_mod::TestTrait::test_method(&test_struct)
852 } 837}
853 ", 838"#,
854 ); 839 );
855 } 840 }
856 841
@@ -858,27 +843,27 @@ fn main() {
858 fn assoc_fn_cross_crate() { 843 fn assoc_fn_cross_crate() {
859 check_assist( 844 check_assist(
860 qualify_path, 845 qualify_path,
861 r" 846 r#"
862 //- /main.rs crate:main deps:dep 847//- /main.rs crate:main deps:dep
863 fn main() { 848fn main() {
864 dep::test_mod::TestStruct::test_func$0tion 849 dep::test_mod::TestStruct::test_func$0tion
865 } 850}
866 //- /dep.rs crate:dep 851//- /dep.rs crate:dep
867 pub mod test_mod { 852pub mod test_mod {
868 pub trait TestTrait { 853 pub trait TestTrait {
869 fn test_function(); 854 fn test_function();
870 } 855 }
871 pub struct TestStruct {} 856 pub struct TestStruct {}
872 impl TestTrait for TestStruct { 857 impl TestTrait for TestStruct {
873 fn test_function() {} 858 fn test_function() {}
874 } 859 }
875 } 860}
876 ", 861"#,
877 r" 862 r#"
878 fn main() { 863fn main() {
879 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function 864 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
880 } 865}
881 ", 866"#,
882 ); 867 );
883 } 868 }
884 869
@@ -886,27 +871,27 @@ fn main() {
886 fn assoc_const_cross_crate() { 871 fn assoc_const_cross_crate() {
887 check_assist( 872 check_assist(
888 qualify_path, 873 qualify_path,
889 r" 874 r#"
890 //- /main.rs crate:main deps:dep 875//- /main.rs crate:main deps:dep
891 fn main() { 876fn main() {
892 dep::test_mod::TestStruct::CONST$0 877 dep::test_mod::TestStruct::CONST$0
893 } 878}
894 //- /dep.rs crate:dep 879//- /dep.rs crate:dep
895 pub mod test_mod { 880pub mod test_mod {
896 pub trait TestTrait { 881 pub trait TestTrait {
897 const CONST: bool; 882 const CONST: bool;
898 } 883 }
899 pub struct TestStruct {} 884 pub struct TestStruct {}
900 impl TestTrait for TestStruct { 885 impl TestTrait for TestStruct {
901 const CONST: bool = true; 886 const CONST: bool = true;
902 } 887 }
903 } 888}
904 ", 889"#,
905 r" 890 r#"
906 fn main() { 891fn main() {
907 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST 892 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
908 } 893}
909 ", 894"#,
910 ); 895 );
911 } 896 }
912 897
@@ -914,23 +899,23 @@ fn main() {
914 fn assoc_fn_as_method_cross_crate() { 899 fn assoc_fn_as_method_cross_crate() {
915 check_assist_not_applicable( 900 check_assist_not_applicable(
916 qualify_path, 901 qualify_path,
917 r" 902 r#"
918 //- /main.rs crate:main deps:dep 903//- /main.rs crate:main deps:dep
919 fn main() { 904fn main() {
920 let test_struct = dep::test_mod::TestStruct {}; 905 let test_struct = dep::test_mod::TestStruct {};
921 test_struct.test_func$0tion() 906 test_struct.test_func$0tion()
922 } 907}
923 //- /dep.rs crate:dep 908//- /dep.rs crate:dep
924 pub mod test_mod { 909pub mod test_mod {
925 pub trait TestTrait { 910 pub trait TestTrait {
926 fn test_function(); 911 fn test_function();
927 } 912 }
928 pub struct TestStruct {} 913 pub struct TestStruct {}
929 impl TestTrait for TestStruct { 914 impl TestTrait for TestStruct {
930 fn test_function() {} 915 fn test_function() {}
931 } 916 }
932 } 917}
933 ", 918"#,
934 ); 919 );
935 } 920 }
936 921
@@ -938,23 +923,23 @@ fn main() {
938 fn private_trait_cross_crate() { 923 fn private_trait_cross_crate() {
939 check_assist_not_applicable( 924 check_assist_not_applicable(
940 qualify_path, 925 qualify_path,
941 r" 926 r#"
942 //- /main.rs crate:main deps:dep 927//- /main.rs crate:main deps:dep
943 fn main() { 928fn main() {
944 let test_struct = dep::test_mod::TestStruct {}; 929 let test_struct = dep::test_mod::TestStruct {};
945 test_struct.test_meth$0od() 930 test_struct.test_meth$0od()
946 } 931}
947 //- /dep.rs crate:dep 932//- /dep.rs crate:dep
948 pub mod test_mod { 933pub mod test_mod {
949 trait TestTrait { 934 trait TestTrait {
950 fn test_method(&self); 935 fn test_method(&self);
951 } 936 }
952 pub struct TestStruct {} 937 pub struct TestStruct {}
953 impl TestTrait for TestStruct { 938 impl TestTrait for TestStruct {
954 fn test_method(&self) {} 939 fn test_method(&self) {}
955 } 940 }
956 } 941}
957 ", 942"#,
958 ); 943 );
959 } 944 }
960 945
@@ -962,32 +947,32 @@ fn main() {
962 fn not_applicable_for_imported_trait_for_method() { 947 fn not_applicable_for_imported_trait_for_method() {
963 check_assist_not_applicable( 948 check_assist_not_applicable(
964 qualify_path, 949 qualify_path,
965 r" 950 r#"
966 mod test_mod { 951mod test_mod {
967 pub trait TestTrait { 952 pub trait TestTrait {
968 fn test_method(&self); 953 fn test_method(&self);
969 } 954 }
970 pub trait TestTrait2 { 955 pub trait TestTrait2 {
971 fn test_method(&self); 956 fn test_method(&self);
972 } 957 }
973 pub enum TestEnum { 958 pub enum TestEnum {
974 One, 959 One,
975 Two, 960 Two,
976 } 961 }
977 impl TestTrait2 for TestEnum { 962 impl TestTrait2 for TestEnum {
978 fn test_method(&self) {} 963 fn test_method(&self) {}
979 } 964 }
980 impl TestTrait for TestEnum { 965 impl TestTrait for TestEnum {
981 fn test_method(&self) {} 966 fn test_method(&self) {}
982 } 967 }
983 } 968}
984 969
985 use test_mod::TestTrait2; 970use test_mod::TestTrait2;
986 fn main() { 971fn main() {
987 let one = test_mod::TestEnum::One; 972 let one = test_mod::TestEnum::One;
988 one.test$0_method(); 973 one.test$0_method();
989 } 974}
990 ", 975"#,
991 ) 976 )
992 } 977 }
993 978
@@ -1114,7 +1099,7 @@ fn main() {}
1114 fn keep_generic_annotations_leading_colon() { 1099 fn keep_generic_annotations_leading_colon() {
1115 check_assist( 1100 check_assist(
1116 qualify_path, 1101 qualify_path,
1117 r" 1102 r#"
1118//- /lib.rs crate:dep 1103//- /lib.rs crate:dep
1119pub mod generic { pub struct Thing<'a, T>(&'a T); } 1104pub mod generic { pub struct Thing<'a, T>(&'a T); }
1120 1105
@@ -1122,7 +1107,7 @@ pub mod generic { pub struct Thing<'a, T>(&'a T); }
1122fn foo() -> Thin$0g::<'static, ()> {} 1107fn foo() -> Thin$0g::<'static, ()> {}
1123 1108
1124fn main() {} 1109fn main() {}
1125", 1110"#,
1126 r" 1111 r"
1127fn foo() -> dep::generic::Thing::<'static, ()> {} 1112fn foo() -> dep::generic::Thing::<'static, ()> {}
1128 1113
@@ -1135,30 +1120,30 @@ fn main() {}
1135 fn associated_struct_const_generic() { 1120 fn associated_struct_const_generic() {
1136 check_assist( 1121 check_assist(
1137 qualify_path, 1122 qualify_path,
1138 r" 1123 r#"
1139 mod test_mod { 1124mod test_mod {
1140 pub struct TestStruct<T> {} 1125 pub struct TestStruct<T> {}
1141 impl<T> TestStruct<T> { 1126 impl<T> TestStruct<T> {
1142 const TEST_CONST: u8 = 42; 1127 const TEST_CONST: u8 = 42;
1143 } 1128 }
1144 } 1129}
1145 1130
1146 fn main() { 1131fn main() {
1147 TestStruct::<()>::TEST_CONST$0 1132 TestStruct::<()>::TEST_CONST$0
1148 } 1133}
1149 ", 1134"#,
1150 r" 1135 r#"
1151 mod test_mod { 1136mod test_mod {
1152 pub struct TestStruct<T> {} 1137 pub struct TestStruct<T> {}
1153 impl<T> TestStruct<T> { 1138 impl<T> TestStruct<T> {
1154 const TEST_CONST: u8 = 42; 1139 const TEST_CONST: u8 = 42;
1155 } 1140 }
1156 } 1141}
1157 1142
1158 fn main() { 1143fn main() {
1159 test_mod::TestStruct::<()>::TEST_CONST 1144 test_mod::TestStruct::<()>::TEST_CONST
1160 } 1145}
1161 ", 1146"#,
1162 ); 1147 );
1163 } 1148 }
1164 1149
@@ -1166,36 +1151,36 @@ fn main() {}
1166 fn associated_trait_const_generic() { 1151 fn associated_trait_const_generic() {
1167 check_assist( 1152 check_assist(
1168 qualify_path, 1153 qualify_path,
1169 r" 1154 r#"
1170 mod test_mod { 1155mod test_mod {
1171 pub trait TestTrait { 1156 pub trait TestTrait {
1172 const TEST_CONST: u8; 1157 const TEST_CONST: u8;
1173 } 1158 }
1174 pub struct TestStruct<T> {} 1159 pub struct TestStruct<T> {}
1175 impl<T> TestTrait for TestStruct<T> { 1160 impl<T> TestTrait for TestStruct<T> {
1176 const TEST_CONST: u8 = 42; 1161 const TEST_CONST: u8 = 42;
1177 } 1162 }
1178 } 1163}
1179 1164
1180 fn main() { 1165fn main() {
1181 test_mod::TestStruct::<()>::TEST_CONST$0 1166 test_mod::TestStruct::<()>::TEST_CONST$0
1182 } 1167}
1183 ", 1168"#,
1184 r" 1169 r#"
1185 mod test_mod { 1170mod test_mod {
1186 pub trait TestTrait { 1171 pub trait TestTrait {
1187 const TEST_CONST: u8; 1172 const TEST_CONST: u8;
1188 } 1173 }
1189 pub struct TestStruct<T> {} 1174 pub struct TestStruct<T> {}
1190 impl<T> TestTrait for TestStruct<T> { 1175 impl<T> TestTrait for TestStruct<T> {
1191 const TEST_CONST: u8 = 42; 1176 const TEST_CONST: u8 = 42;
1192 } 1177 }
1193 } 1178}
1194 1179
1195 fn main() { 1180fn main() {
1196 <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST 1181 <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
1197 } 1182}
1198 ", 1183"#,
1199 ); 1184 );
1200 } 1185 }
1201 1186
@@ -1203,38 +1188,38 @@ fn main() {}
1203 fn trait_method_generic() { 1188 fn trait_method_generic() {
1204 check_assist( 1189 check_assist(
1205 qualify_path, 1190 qualify_path,
1206 r" 1191 r#"
1207 mod test_mod { 1192mod test_mod {
1208 pub trait TestTrait { 1193 pub trait TestTrait {
1209 fn test_method<T>(&self); 1194 fn test_method<T>(&self);
1210 } 1195 }
1211 pub struct TestStruct {} 1196 pub struct TestStruct {}
1212 impl TestTrait for TestStruct { 1197 impl TestTrait for TestStruct {
1213 fn test_method<T>(&self) {} 1198 fn test_method<T>(&self) {}
1214 } 1199 }
1215 } 1200}
1216 1201
1217 fn main() { 1202fn main() {
1218 let test_struct = test_mod::TestStruct {}; 1203 let test_struct = test_mod::TestStruct {};
1219 test_struct.test_meth$0od::<()>() 1204 test_struct.test_meth$0od::<()>()
1220 } 1205}
1221 ", 1206"#,
1222 r" 1207 r#"
1223 mod test_mod { 1208mod test_mod {
1224 pub trait TestTrait { 1209 pub trait TestTrait {
1225 fn test_method<T>(&self); 1210 fn test_method<T>(&self);
1226 } 1211 }
1227 pub struct TestStruct {} 1212 pub struct TestStruct {}
1228 impl TestTrait for TestStruct { 1213 impl TestTrait for TestStruct {
1229 fn test_method<T>(&self) {} 1214 fn test_method<T>(&self) {}
1230 } 1215 }
1231 } 1216}
1232 1217
1233 fn main() { 1218fn main() {
1234 let test_struct = test_mod::TestStruct {}; 1219 let test_struct = test_mod::TestStruct {};
1235 test_mod::TestTrait::test_method::<()>(&test_struct) 1220 test_mod::TestTrait::test_method::<()>(&test_struct)
1236 } 1221}
1237 ", 1222"#,
1238 ); 1223 );
1239 } 1224 }
1240} 1225}
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index b20fe992d..5866d8974 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -35,14 +35,14 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
35 .prev_sibling_or_token() 35 .prev_sibling_or_token()
36 .and_then(whitespace_start) 36 .and_then(whitespace_start)
37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end())) 37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
38 .unwrap_or(macro_call.syntax().text_range()) 38 .unwrap_or_else(|| macro_call.syntax().text_range())
39 }, 39 },
40 ast::ExprStmt(it) => { 40 ast::ExprStmt(it) => {
41 let start = it 41 let start = it
42 .syntax() 42 .syntax()
43 .prev_sibling_or_token() 43 .prev_sibling_or_token()
44 .and_then(whitespace_start) 44 .and_then(whitespace_start)
45 .unwrap_or(it.syntax().text_range().start()); 45 .unwrap_or_else(|| it.syntax().text_range().start());
46 let end = it.syntax().text_range().end(); 46 let end = it.syntax().text_range().end();
47 47
48 TextRange::new(start, end) 48 TextRange::new(start, end)
diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
index 50b05ab0b..5f2aa016f 100644
--- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
+++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
@@ -85,38 +85,48 @@ fn is_ref_and_impls_iter_method(
85 let krate = scope.module()?.krate(); 85 let krate = scope.module()?.krate();
86 let traits_in_scope = scope.traits_in_scope(); 86 let traits_in_scope = scope.traits_in_scope();
87 let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; 87 let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
88 let has_wanted_method = typ.iterate_method_candidates( 88
89 sema.db, 89 let has_wanted_method = typ
90 krate, 90 .iterate_method_candidates(
91 &traits_in_scope, 91 sema.db,
92 Some(&wanted_method), 92 krate,
93 |_, func| { 93 &traits_in_scope,
94 if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { 94 Some(&wanted_method),
95 return Some(()); 95 |_, func| {
96 } 96 if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) {
97 None 97 return Some(());
98 }, 98 }
99 ); 99 None
100 has_wanted_method.and(Some((expr_behind_ref, wanted_method))) 100 },
101 )
102 .is_some();
103 if !has_wanted_method {
104 return None;
105 }
106
107 Some((expr_behind_ref, wanted_method))
101} 108}
102 109
103/// Whether iterable implements core::Iterator 110/// Whether iterable implements core::Iterator
104fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { 111fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool {
105 let it_typ = if let Some(i) = sema.type_of_expr(iterable) { 112 let it_typ = match sema.type_of_expr(iterable) {
106 i 113 Some(it) => it,
107 } else { 114 None => return false,
108 return false;
109 }; 115 };
110 let module = if let Some(m) = sema.scope(iterable.syntax()).module() { 116
111 m 117 let module = match sema.scope(iterable.syntax()).module() {
112 } else { 118 Some(it) => it,
113 return false; 119 None => return false,
114 }; 120 };
121
115 let krate = module.krate(); 122 let krate = module.krate();
116 if let Some(iter_trait) = FamousDefs(sema, Some(krate)).core_iter_Iterator() { 123 match FamousDefs(sema, Some(krate)).core_iter_Iterator() {
117 return it_typ.impls_trait(sema.db, iter_trait, &[]); 124 Some(iter_trait) => {
125 cov_mark::hit!(test_already_impls_iterator);
126 it_typ.impls_trait(sema.db, iter_trait, &[])
127 }
128 None => false,
118 } 129 }
119 false
120} 130}
121 131
122#[cfg(test)] 132#[cfg(test)]
@@ -125,33 +135,6 @@ mod tests {
125 135
126 use super::*; 136 use super::*;
127 137
128 const EMPTY_ITER_FIXTURE: &'static str = r"
129//- /lib.rs deps:core crate:empty_iter
130pub struct EmptyIter;
131impl Iterator for EmptyIter {
132 type Item = usize;
133 fn next(&mut self) -> Option<Self::Item> { None }
134}
135
136pub struct Empty;
137impl Empty {
138 pub fn iter(&self) -> EmptyIter { EmptyIter }
139 pub fn iter_mut(&self) -> EmptyIter { EmptyIter }
140}
141
142pub struct NoIterMethod;
143";
144
145 fn check_assist_with_fixtures(before: &str, after: &str) {
146 let before = &format!(
147 "//- /main.rs crate:main deps:core,empty_iter{}{}{}",
148 before,
149 FamousDefs::FIXTURE,
150 EMPTY_ITER_FIXTURE
151 );
152 check_assist(replace_for_loop_with_for_each, before, after);
153 }
154
155 #[test] 138 #[test]
156 fn test_not_for() { 139 fn test_not_for() {
157 check_assist_not_applicable( 140 check_assist_not_applicable(
@@ -201,33 +184,50 @@ fn main() {
201 184
202 #[test] 185 #[test]
203 fn test_for_borrowed() { 186 fn test_for_borrowed() {
204 check_assist_with_fixtures( 187 check_assist(
205 r" 188 replace_for_loop_with_for_each,
206use empty_iter::*; 189 r#"
190//- minicore: iterators
191use core::iter::{Repeat, repeat};
192
193struct S;
194impl S {
195 fn iter(&self) -> Repeat<i32> { repeat(92) }
196 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
197}
198
207fn main() { 199fn main() {
208 let x = Empty; 200 let x = S;
209 for $0v in &x { 201 for $0v in &x {
210 let a = v * 2; 202 let a = v * 2;
211 } 203 }
212} 204}
213", 205"#,
214 r" 206 r#"
215use empty_iter::*; 207use core::iter::{Repeat, repeat};
208
209struct S;
210impl S {
211 fn iter(&self) -> Repeat<i32> { repeat(92) }
212 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
213}
214
216fn main() { 215fn main() {
217 let x = Empty; 216 let x = S;
218 x.iter().for_each(|v| { 217 x.iter().for_each(|v| {
219 let a = v * 2; 218 let a = v * 2;
220 }); 219 });
221} 220}
222", 221"#,
223 ) 222 )
224 } 223 }
225 224
226 #[test] 225 #[test]
227 fn test_for_borrowed_no_iter_method() { 226 fn test_for_borrowed_no_iter_method() {
228 check_assist_with_fixtures( 227 check_assist(
228 replace_for_loop_with_for_each,
229 r" 229 r"
230use empty_iter::*; 230struct NoIterMethod;
231fn main() { 231fn main() {
232 let x = NoIterMethod; 232 let x = NoIterMethod;
233 for $0v in &x { 233 for $0v in &x {
@@ -236,7 +236,7 @@ fn main() {
236} 236}
237", 237",
238 r" 238 r"
239use empty_iter::*; 239struct NoIterMethod;
240fn main() { 240fn main() {
241 let x = NoIterMethod; 241 let x = NoIterMethod;
242 (&x).into_iter().for_each(|v| { 242 (&x).into_iter().for_each(|v| {
@@ -249,25 +249,41 @@ fn main() {
249 249
250 #[test] 250 #[test]
251 fn test_for_borrowed_mut() { 251 fn test_for_borrowed_mut() {
252 check_assist_with_fixtures( 252 check_assist(
253 r" 253 replace_for_loop_with_for_each,
254use empty_iter::*; 254 r#"
255//- minicore: iterators
256use core::iter::{Repeat, repeat};
257
258struct S;
259impl S {
260 fn iter(&self) -> Repeat<i32> { repeat(92) }
261 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
262}
263
255fn main() { 264fn main() {
256 let x = Empty; 265 let x = S;
257 for $0v in &mut x { 266 for $0v in &mut x {
258 let a = v * 2; 267 let a = v * 2;
259 } 268 }
260} 269}
261", 270"#,
262 r" 271 r#"
263use empty_iter::*; 272use core::iter::{Repeat, repeat};
273
274struct S;
275impl S {
276 fn iter(&self) -> Repeat<i32> { repeat(92) }
277 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
278}
279
264fn main() { 280fn main() {
265 let x = Empty; 281 let x = S;
266 x.iter_mut().for_each(|v| { 282 x.iter_mut().for_each(|v| {
267 let a = v * 2; 283 let a = v * 2;
268 }); 284 });
269} 285}
270", 286"#,
271 ) 287 )
272 } 288 }
273 289
@@ -296,21 +312,20 @@ fn main() {
296 312
297 #[test] 313 #[test]
298 fn test_already_impls_iterator() { 314 fn test_already_impls_iterator() {
299 check_assist_with_fixtures( 315 cov_mark::check!(test_already_impls_iterator);
316 check_assist(
317 replace_for_loop_with_for_each,
300 r#" 318 r#"
301use empty_iter::*; 319//- minicore: iterators
302fn main() { 320fn main() {
303 let x = Empty; 321 for$0 a in core::iter::repeat(92).take(1) {
304 for$0 a in x.iter().take(1) {
305 println!("{}", a); 322 println!("{}", a);
306 } 323 }
307} 324}
308"#, 325"#,
309 r#" 326 r#"
310use empty_iter::*;
311fn main() { 327fn main() {
312 let x = Empty; 328 core::iter::repeat(92).take(1).for_each(|a| {
313 x.iter().take(1).for_each(|a| {
314 println!("{}", a); 329 println!("{}", a);
315 }); 330 });
316} 331}
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
index 9404aa26d..f37aa0d53 100644
--- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
@@ -262,9 +262,7 @@ impl VariantData {
262 check_assist( 262 check_assist(
263 replace_if_let_with_match, 263 replace_if_let_with_match,
264 r#" 264 r#"
265enum Option<T> { Some(T), None } 265//- minicore: option
266use Option::*;
267
268fn foo(x: Option<i32>) { 266fn foo(x: Option<i32>) {
269 $0if let Some(x) = x { 267 $0if let Some(x) = x {
270 println!("{}", x) 268 println!("{}", x)
@@ -272,18 +270,15 @@ fn foo(x: Option<i32>) {
272 println!("none") 270 println!("none")
273 } 271 }
274} 272}
275 "#, 273"#,
276 r#" 274 r#"
277enum Option<T> { Some(T), None }
278use Option::*;
279
280fn foo(x: Option<i32>) { 275fn foo(x: Option<i32>) {
281 match x { 276 match x {
282 Some(x) => println!("{}", x), 277 Some(x) => println!("{}", x),
283 None => println!("none"), 278 None => println!("none"),
284 } 279 }
285} 280}
286 "#, 281"#,
287 ); 282 );
288 } 283 }
289 284
@@ -292,9 +287,7 @@ fn foo(x: Option<i32>) {
292 check_assist( 287 check_assist(
293 replace_if_let_with_match, 288 replace_if_let_with_match,
294 r#" 289 r#"
295enum Option<T> { Some(T), None } 290//- minicore: option
296use Option::*;
297
298fn foo(x: Option<i32>) { 291fn foo(x: Option<i32>) {
299 $0if let None = x { 292 $0if let None = x {
300 println!("none") 293 println!("none")
@@ -302,18 +295,15 @@ fn foo(x: Option<i32>) {
302 println!("some") 295 println!("some")
303 } 296 }
304} 297}
305 "#, 298"#,
306 r#" 299 r#"
307enum Option<T> { Some(T), None }
308use Option::*;
309
310fn foo(x: Option<i32>) { 300fn foo(x: Option<i32>) {
311 match x { 301 match x {
312 None => println!("none"), 302 None => println!("none"),
313 Some(_) => println!("some"), 303 Some(_) => println!("some"),
314 } 304 }
315} 305}
316 "#, 306"#,
317 ); 307 );
318 } 308 }
319 309
@@ -322,9 +312,7 @@ fn foo(x: Option<i32>) {
322 check_assist( 312 check_assist(
323 replace_if_let_with_match, 313 replace_if_let_with_match,
324 r#" 314 r#"
325enum Result<T, E> { Ok(T), Err(E) } 315//- minicore: result
326use Result::*;
327
328fn foo(x: Result<i32, ()>) { 316fn foo(x: Result<i32, ()>) {
329 $0if let Ok(x) = x { 317 $0if let Ok(x) = x {
330 println!("{}", x) 318 println!("{}", x)
@@ -332,18 +320,15 @@ fn foo(x: Result<i32, ()>) {
332 println!("none") 320 println!("none")
333 } 321 }
334} 322}
335 "#, 323"#,
336 r#" 324 r#"
337enum Result<T, E> { Ok(T), Err(E) }
338use Result::*;
339
340fn foo(x: Result<i32, ()>) { 325fn foo(x: Result<i32, ()>) {
341 match x { 326 match x {
342 Ok(x) => println!("{}", x), 327 Ok(x) => println!("{}", x),
343 Err(_) => println!("none"), 328 Err(_) => println!("none"),
344 } 329 }
345} 330}
346 "#, 331"#,
347 ); 332 );
348 } 333 }
349 334
@@ -352,9 +337,7 @@ fn foo(x: Result<i32, ()>) {
352 check_assist( 337 check_assist(
353 replace_if_let_with_match, 338 replace_if_let_with_match,
354 r#" 339 r#"
355enum Result<T, E> { Ok(T), Err(E) } 340//- minicore: result
356use Result::*;
357
358fn foo(x: Result<i32, ()>) { 341fn foo(x: Result<i32, ()>) {
359 $0if let Err(x) = x { 342 $0if let Err(x) = x {
360 println!("{}", x) 343 println!("{}", x)
@@ -362,18 +345,15 @@ fn foo(x: Result<i32, ()>) {
362 println!("ok") 345 println!("ok")
363 } 346 }
364} 347}
365 "#, 348"#,
366 r#" 349 r#"
367enum Result<T, E> { Ok(T), Err(E) }
368use Result::*;
369
370fn foo(x: Result<i32, ()>) { 350fn foo(x: Result<i32, ()>) {
371 match x { 351 match x {
372 Err(x) => println!("{}", x), 352 Err(x) => println!("{}", x),
373 Ok(_) => println!("ok"), 353 Ok(_) => println!("ok"),
374 } 354 }
375} 355}
376 "#, 356"#,
377 ); 357 );
378 } 358 }
379 359
@@ -488,20 +468,15 @@ impl VariantData {
488 check_assist( 468 check_assist(
489 replace_match_with_if_let, 469 replace_match_with_if_let,
490 r#" 470 r#"
491enum Option<T> { Some(T), None } 471//- minicore: option
492use Option::*;
493
494fn foo(x: Option<i32>) { 472fn foo(x: Option<i32>) {
495 $0match x { 473 $0match x {
496 Some(x) => println!("{}", x), 474 Some(x) => println!("{}", x),
497 None => println!("none"), 475 None => println!("none"),
498 } 476 }
499} 477}
500 "#, 478"#,
501 r#" 479 r#"
502enum Option<T> { Some(T), None }
503use Option::*;
504
505fn foo(x: Option<i32>) { 480fn foo(x: Option<i32>) {
506 if let Some(x) = x { 481 if let Some(x) = x {
507 println!("{}", x) 482 println!("{}", x)
@@ -509,7 +484,7 @@ fn foo(x: Option<i32>) {
509 println!("none") 484 println!("none")
510 } 485 }
511} 486}
512 "#, 487"#,
513 ); 488 );
514 } 489 }
515 490
@@ -518,20 +493,15 @@ fn foo(x: Option<i32>) {
518 check_assist( 493 check_assist(
519 replace_match_with_if_let, 494 replace_match_with_if_let,
520 r#" 495 r#"
521enum Result<T, E> { Ok(T), Err(E) } 496//- minicore: result
522use Result::*;
523
524fn foo(x: Result<i32, ()>) { 497fn foo(x: Result<i32, ()>) {
525 $0match x { 498 $0match x {
526 Ok(x) => println!("{}", x), 499 Ok(x) => println!("{}", x),
527 Err(_) => println!("none"), 500 Err(_) => println!("none"),
528 } 501 }
529} 502}
530 "#, 503"#,
531 r#" 504 r#"
532enum Result<T, E> { Ok(T), Err(E) }
533use Result::*;
534
535fn foo(x: Result<i32, ()>) { 505fn foo(x: Result<i32, ()>) {
536 if let Ok(x) = x { 506 if let Ok(x) = x {
537 println!("{}", x) 507 println!("{}", x)
@@ -539,7 +509,7 @@ fn foo(x: Result<i32, ()>) {
539 println!("none") 509 println!("none")
540 } 510 }
541} 511}
542 "#, 512"#,
543 ); 513 );
544 } 514 }
545 515
diff --git a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
index 540a905cc..a2af2035f 100644
--- a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
+++ b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs
@@ -105,12 +105,13 @@ fn foo<B: Bar
105 } 105 }
106 106
107 #[test] 107 #[test]
108 #[ignore = "This case is very rare but there is no simple solutions to fix it."]
109 fn replace_impl_trait_with_exist_generic_letter() { 108 fn replace_impl_trait_with_exist_generic_letter() {
109 // FIXME: This is wrong, we should pick a different name if the one we
110 // want is already bound.
110 check_assist( 111 check_assist(
111 replace_impl_trait_with_generic, 112 replace_impl_trait_with_generic,
112 r#"fn foo<B>(bar: $0impl Bar) {}"#, 113 r#"fn foo<B>(bar: $0impl Bar) {}"#,
113 r#"fn foo<B, C: Bar>(bar: C) {}"#, 114 r#"fn foo<B, B: Bar>(bar: B) {}"#,
114 ); 115 );
115 } 116 }
116 117
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 39f5eb4ff..26778ee74 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -32,7 +32,6 @@ pub(crate) fn replace_qualified_name_with_use(
32 32
33 let target = path.syntax().text_range(); 33 let target = path.syntax().text_range();
34 let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?; 34 let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?;
35 let syntax = scope.as_syntax_node();
36 acc.add( 35 acc.add(
37 AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), 36 AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
38 "Replace qualified path with use", 37 "Replace qualified path with use",
@@ -40,11 +39,13 @@ pub(crate) fn replace_qualified_name_with_use(
40 |builder| { 39 |builder| {
41 // Now that we've brought the name into scope, re-qualify all paths that could be 40 // Now that we've brought the name into scope, re-qualify all paths that could be
42 // affected (that is, all paths inside the node we added the `use` to). 41 // affected (that is, all paths inside the node we added the `use` to).
43 let syntax = builder.make_syntax_mut(syntax.clone()); 42 let scope = match scope {
44 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 43 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
45 shorten_paths(&syntax, &path.clone_for_update()); 44 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
46 insert_use(import_scope, path, ctx.config.insert_use); 45 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
47 } 46 };
47 shorten_paths(scope.as_syntax_node(), &path.clone_for_update());
48 insert_use(&scope, path, &ctx.config.insert_use);
48 }, 49 },
49 ) 50 )
50} 51}
diff --git a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
index a3bfa221c..f39c48d8f 100644
--- a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
@@ -20,17 +20,16 @@ use ide_db::ty_filter::TryEnum;
20// Replaces `unwrap` with a `match` expression. Works for Result and Option. 20// Replaces `unwrap` with a `match` expression. Works for Result and Option.
21// 21//
22// ``` 22// ```
23// enum Result<T, E> { Ok(T), Err(E) } 23// # //- minicore: result
24// fn main() { 24// fn main() {
25// let x: Result<i32, i32> = Result::Ok(92); 25// let x: Result<i32, i32> = Ok(92);
26// let y = x.$0unwrap(); 26// let y = x.$0unwrap();
27// } 27// }
28// ``` 28// ```
29// -> 29// ->
30// ``` 30// ```
31// enum Result<T, E> { Ok(T), Err(E) }
32// fn main() { 31// fn main() {
33// let x: Result<i32, i32> = Result::Ok(92); 32// let x: Result<i32, i32> = Ok(92);
34// let y = match x { 33// let y = match x {
35// Ok(it) => it, 34// Ok(it) => it,
36// $0_ => unreachable!(), 35// $0_ => unreachable!(),
@@ -97,25 +96,24 @@ mod tests {
97 fn test_replace_result_unwrap_with_match() { 96 fn test_replace_result_unwrap_with_match() {
98 check_assist( 97 check_assist(
99 replace_unwrap_with_match, 98 replace_unwrap_with_match,
100 r" 99 r#"
101enum Result<T, E> { Ok(T), Err(E) } 100//- minicore: result
102fn i<T>(a: T) -> T { a } 101fn i<T>(a: T) -> T { a }
103fn main() { 102fn main() {
104 let x: Result<i32, i32> = Result::Ok(92); 103 let x: Result<i32, i32> = Ok(92);
105 let y = i(x).$0unwrap(); 104 let y = i(x).$0unwrap();
106} 105}
107 ", 106"#,
108 r" 107 r#"
109enum Result<T, E> { Ok(T), Err(E) }
110fn i<T>(a: T) -> T { a } 108fn i<T>(a: T) -> T { a }
111fn main() { 109fn main() {
112 let x: Result<i32, i32> = Result::Ok(92); 110 let x: Result<i32, i32> = Ok(92);
113 let y = match i(x) { 111 let y = match i(x) {
114 Ok(it) => it, 112 Ok(it) => it,
115 $0_ => unreachable!(), 113 $0_ => unreachable!(),
116 }; 114 };
117} 115}
118 ", 116"#,
119 ) 117 )
120 } 118 }
121 119
@@ -123,25 +121,24 @@ fn main() {
123 fn test_replace_option_unwrap_with_match() { 121 fn test_replace_option_unwrap_with_match() {
124 check_assist( 122 check_assist(
125 replace_unwrap_with_match, 123 replace_unwrap_with_match,
126 r" 124 r#"
127enum Option<T> { Some(T), None } 125//- minicore: option
128fn i<T>(a: T) -> T { a } 126fn i<T>(a: T) -> T { a }
129fn main() { 127fn main() {
130 let x = Option::Some(92); 128 let x = Some(92);
131 let y = i(x).$0unwrap(); 129 let y = i(x).$0unwrap();
132} 130}
133 ", 131"#,
134 r" 132 r#"
135enum Option<T> { Some(T), None }
136fn i<T>(a: T) -> T { a } 133fn i<T>(a: T) -> T { a }
137fn main() { 134fn main() {
138 let x = Option::Some(92); 135 let x = Some(92);
139 let y = match i(x) { 136 let y = match i(x) {
140 Some(it) => it, 137 Some(it) => it,
141 $0_ => unreachable!(), 138 $0_ => unreachable!(),
142 }; 139 };
143} 140}
144 ", 141"#,
145 ); 142 );
146 } 143 }
147 144
@@ -149,25 +146,24 @@ fn main() {
149 fn test_replace_result_unwrap_with_match_chaining() { 146 fn test_replace_result_unwrap_with_match_chaining() {
150 check_assist( 147 check_assist(
151 replace_unwrap_with_match, 148 replace_unwrap_with_match,
152 r" 149 r#"
153enum Result<T, E> { Ok(T), Err(E) } 150//- minicore: result
154fn i<T>(a: T) -> T { a } 151fn i<T>(a: T) -> T { a }
155fn main() { 152fn main() {
156 let x: Result<i32, i32> = Result::Ok(92); 153 let x: Result<i32, i32> = Ok(92);
157 let y = i(x).$0unwrap().count_zeroes(); 154 let y = i(x).$0unwrap().count_zeroes();
158} 155}
159 ", 156"#,
160 r" 157 r#"
161enum Result<T, E> { Ok(T), Err(E) }
162fn i<T>(a: T) -> T { a } 158fn i<T>(a: T) -> T { a }
163fn main() { 159fn main() {
164 let x: Result<i32, i32> = Result::Ok(92); 160 let x: Result<i32, i32> = Ok(92);
165 let y = match i(x) { 161 let y = match i(x) {
166 Ok(it) => it, 162 Ok(it) => it,
167 $0_ => unreachable!(), 163 $0_ => unreachable!(),
168 }.count_zeroes(); 164 }.count_zeroes();
169} 165}
170 ", 166"#,
171 ) 167 )
172 } 168 }
173 169
@@ -175,14 +171,14 @@ fn main() {
175 fn replace_unwrap_with_match_target() { 171 fn replace_unwrap_with_match_target() {
176 check_assist_target( 172 check_assist_target(
177 replace_unwrap_with_match, 173 replace_unwrap_with_match,
178 r" 174 r#"
179enum Option<T> { Some(T), None } 175//- minicore: option
180fn i<T>(a: T) -> T { a } 176fn i<T>(a: T) -> T { a }
181fn main() { 177fn main() {
182 let x = Option::Some(92); 178 let x = Some(92);
183 let y = i(x).$0unwrap(); 179 let y = i(x).$0unwrap();
184} 180}
185 ", 181"#,
186 r"i(x).unwrap()", 182 r"i(x).unwrap()",
187 ); 183 );
188 } 184 }
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs
index 8d271e056..14e862cd0 100644
--- a/crates/ide_assists/src/handlers/unmerge_use.rs
+++ b/crates/ide_assists/src/handlers/unmerge_use.rs
@@ -73,7 +73,11 @@ fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> {
73 for path in paths { 73 for path in paths {
74 final_path = ast::make::path_concat(path, final_path) 74 final_path = ast::make::path_concat(path, final_path)
75 } 75 }
76 Some(final_path) 76 if final_path.segment().map_or(false, |it| it.self_token().is_some()) {
77 final_path.qualifier()
78 } else {
79 Some(final_path)
80 }
77} 81}
78 82
79#[cfg(test)] 83#[cfg(test)]
@@ -223,4 +227,14 @@ pub use std::fmt::Display;
223", 227",
224 ); 228 );
225 } 229 }
230
231 #[test]
232 fn unmerge_use_item_on_self() {
233 check_assist(
234 unmerge_use,
235 r"use std::process::{Command, self$0};",
236 r"use std::process::{Command};
237use std::process;",
238 );
239 }
226} 240}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 331a6df2b..86a57ce5d 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -15,158 +15,32 @@ mod assist_context;
15#[cfg(test)] 15#[cfg(test)]
16mod tests; 16mod tests;
17pub mod utils; 17pub mod utils;
18pub mod path_transform;
19
20use std::str::FromStr;
21 18
22use hir::Semantics; 19use hir::Semantics;
23use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; 20use ide_db::{base_db::FileRange, RootDatabase};
24use syntax::TextRange; 21use syntax::TextRange;
25 22
26pub(crate) use crate::assist_context::{AssistContext, Assists}; 23pub(crate) use crate::assist_context::{AssistContext, Assists};
27 24
28pub use assist_config::AssistConfig; 25pub use assist_config::AssistConfig;
29 26pub use ide_db::assists::{
30#[derive(Debug, Clone, Copy, PartialEq, Eq)] 27 Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve,
31pub enum AssistKind { 28};
32 // FIXME: does the None variant make sense? Probably not. 29
33 None, 30/// Return all the assists applicable at the given position.
34 31pub fn assists(
35 QuickFix, 32 db: &RootDatabase,
36 Generate, 33 config: &AssistConfig,
37 Refactor, 34 resolve: AssistResolveStrategy,
38 RefactorExtract, 35 range: FileRange,
39 RefactorInline, 36) -> Vec<Assist> {
40 RefactorRewrite, 37 let sema = Semantics::new(db);
41} 38 let ctx = AssistContext::new(sema, config, range);
42 39 let mut acc = Assists::new(&ctx, resolve);
43impl AssistKind { 40 handlers::all().iter().for_each(|handler| {
44 pub fn contains(self, other: AssistKind) -> bool { 41 handler(&mut acc, &ctx);
45 if self == other { 42 });
46 return true; 43 acc.finish()
47 }
48
49 match self {
50 AssistKind::None | AssistKind::Generate => true,
51 AssistKind::Refactor => match other {
52 AssistKind::RefactorExtract
53 | AssistKind::RefactorInline
54 | AssistKind::RefactorRewrite => true,
55 _ => false,
56 },
57 _ => false,
58 }
59 }
60
61 pub fn name(&self) -> &str {
62 match self {
63 AssistKind::None => "None",
64 AssistKind::QuickFix => "QuickFix",
65 AssistKind::Generate => "Generate",
66 AssistKind::Refactor => "Refactor",
67 AssistKind::RefactorExtract => "RefactorExtract",
68 AssistKind::RefactorInline => "RefactorInline",
69 AssistKind::RefactorRewrite => "RefactorRewrite",
70 }
71 }
72}
73
74impl FromStr for AssistKind {
75 type Err = String;
76
77 fn from_str(s: &str) -> Result<Self, Self::Err> {
78 match s {
79 "None" => Ok(AssistKind::None),
80 "QuickFix" => Ok(AssistKind::QuickFix),
81 "Generate" => Ok(AssistKind::Generate),
82 "Refactor" => Ok(AssistKind::Refactor),
83 "RefactorExtract" => Ok(AssistKind::RefactorExtract),
84 "RefactorInline" => Ok(AssistKind::RefactorInline),
85 "RefactorRewrite" => Ok(AssistKind::RefactorRewrite),
86 unknown => Err(format!("Unknown AssistKind: '{}'", unknown)),
87 }
88 }
89}
90
91/// Unique identifier of the assist, should not be shown to the user
92/// directly.
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub struct AssistId(pub &'static str, pub AssistKind);
95
96/// A way to control how many asssist to resolve during the assist resolution.
97/// When an assist is resolved, its edits are calculated that might be costly to always do by default.
98#[derive(Debug)]
99pub enum AssistResolveStrategy {
100 /// No assists should be resolved.
101 None,
102 /// All assists should be resolved.
103 All,
104 /// Only a certain assist should be resolved.
105 Single(SingleResolve),
106}
107
108/// Hold the [`AssistId`] data of a certain assist to resolve.
109/// The original id object cannot be used due to a `'static` lifetime
110/// and the requirement to construct this struct dynamically during the resolve handling.
111#[derive(Debug)]
112pub struct SingleResolve {
113 /// The id of the assist.
114 pub assist_id: String,
115 // The kind of the assist.
116 pub assist_kind: AssistKind,
117}
118
119impl AssistResolveStrategy {
120 pub fn should_resolve(&self, id: &AssistId) -> bool {
121 match self {
122 AssistResolveStrategy::None => false,
123 AssistResolveStrategy::All => true,
124 AssistResolveStrategy::Single(single_resolve) => {
125 single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
126 }
127 }
128 }
129}
130
131#[derive(Clone, Debug)]
132pub struct GroupLabel(pub String);
133
134#[derive(Debug, Clone)]
135pub struct Assist {
136 pub id: AssistId,
137 /// Short description of the assist, as shown in the UI.
138 pub label: Label,
139 pub group: Option<GroupLabel>,
140 /// Target ranges are used to sort assists: the smaller the target range,
141 /// the more specific assist is, and so it should be sorted first.
142 pub target: TextRange,
143 /// Computing source change sometimes is much more costly then computing the
144 /// other fields. Additionally, the actual change is not required to show
145 /// the lightbulb UI, it only is needed when the user tries to apply an
146 /// assist. So, we compute it lazily: the API allow requesting assists with
147 /// or without source change. We could (and in fact, used to) distinguish
148 /// between resolved and unresolved assists at the type level, but this is
149 /// cumbersome, especially if you want to embed an assist into another data
150 /// structure, such as a diagnostic.
151 pub source_change: Option<SourceChange>,
152}
153
154impl Assist {
155 /// Return all the assists applicable at the given position.
156 pub fn get(
157 db: &RootDatabase,
158 config: &AssistConfig,
159 resolve: AssistResolveStrategy,
160 range: FileRange,
161 ) -> Vec<Assist> {
162 let sema = Semantics::new(db);
163 let ctx = AssistContext::new(sema, config, range);
164 let mut acc = Assists::new(&ctx, resolve);
165 handlers::all().iter().for_each(|handler| {
166 handler(&mut acc, &ctx);
167 });
168 acc.finish()
169 }
170} 44}
171 45
172mod handlers { 46mod handlers {
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index bdf9cb71c..841537c77 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -16,8 +16,8 @@ use syntax::TextRange;
16use test_utils::{assert_eq_text, extract_offset}; 16use test_utils::{assert_eq_text, extract_offset};
17 17
18use crate::{ 18use crate::{
19 handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, AssistResolveStrategy, 19 assists, handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind,
20 Assists, SingleResolve, 20 AssistResolveStrategy, Assists, SingleResolve,
21}; 21};
22 22
23pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { 23pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
@@ -28,6 +28,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
28 prefix_kind: hir::PrefixKind::Plain, 28 prefix_kind: hir::PrefixKind::Plain,
29 enforce_granularity: true, 29 enforce_granularity: true,
30 group: true, 30 group: true,
31 skip_glob_imports: true,
31 }, 32 },
32}; 33};
33 34
@@ -35,6 +36,7 @@ pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
35 RootDatabase::with_single_file(text) 36 RootDatabase::with_single_file(text)
36} 37}
37 38
39#[track_caller]
38pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { 40pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
39 let ra_fixture_after = trim_indent(ra_fixture_after); 41 let ra_fixture_after = trim_indent(ra_fixture_after);
40 check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None); 42 check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None);
@@ -78,14 +80,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
78 let before = db.file_text(file_id).to_string(); 80 let before = db.file_text(file_id).to_string();
79 let frange = FileRange { file_id, range: selection.into() }; 81 let frange = FileRange { file_id, range: selection.into() };
80 82
81 let assist = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange) 83 let assist = assists(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange)
82 .into_iter() 84 .into_iter()
83 .find(|assist| assist.id.0 == assist_id) 85 .find(|assist| assist.id.0 == assist_id)
84 .unwrap_or_else(|| { 86 .unwrap_or_else(|| {
85 panic!( 87 panic!(
86 "\n\nAssist is not applicable: {}\nAvailable assists: {}", 88 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
87 assist_id, 89 assist_id,
88 Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange) 90 assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange)
89 .into_iter() 91 .into_iter()
90 .map(|assist| assist.id.0) 92 .map(|assist| assist.id.0)
91 .collect::<Vec<_>>() 93 .collect::<Vec<_>>()
@@ -179,9 +181,10 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
179 "unresolved assist should not contain source changes" 181 "unresolved assist should not contain source changes"
180 ), 182 ),
181 (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), 183 (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
182 (None, ExpectedResult::After(_)) 184 (
183 | (None, ExpectedResult::Target(_)) 185 None,
184 | (None, ExpectedResult::Unresolved) => { 186 ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved,
187 ) => {
185 panic!("code action is not applicable") 188 panic!("code action is not applicable")
186 } 189 }
187 (None, ExpectedResult::NotApplicable) => (), 190 (None, ExpectedResult::NotApplicable) => (),
@@ -210,7 +213,7 @@ fn assist_order_field_struct() {
210 let (before_cursor_pos, before) = extract_offset(before); 213 let (before_cursor_pos, before) = extract_offset(before);
211 let (db, file_id) = with_single_file(&before); 214 let (db, file_id) = with_single_file(&before);
212 let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; 215 let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
213 let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); 216 let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
214 let mut assists = assists.iter(); 217 let mut assists = assists.iter();
215 218
216 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); 219 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
@@ -235,7 +238,7 @@ pub fn test_some_range(a: int) -> bool {
235"#, 238"#,
236 ); 239 );
237 240
238 let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); 241 let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange);
239 let expected = labels(&assists); 242 let expected = labels(&assists);
240 243
241 expect![[r#" 244 expect![[r#"
@@ -264,7 +267,7 @@ pub fn test_some_range(a: int) -> bool {
264 let mut cfg = TEST_CONFIG; 267 let mut cfg = TEST_CONFIG;
265 cfg.allowed = Some(vec![AssistKind::Refactor]); 268 cfg.allowed = Some(vec![AssistKind::Refactor]);
266 269
267 let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); 270 let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
268 let expected = labels(&assists); 271 let expected = labels(&assists);
269 272
270 expect![[r#" 273 expect![[r#"
@@ -279,7 +282,7 @@ pub fn test_some_range(a: int) -> bool {
279 { 282 {
280 let mut cfg = TEST_CONFIG; 283 let mut cfg = TEST_CONFIG;
281 cfg.allowed = Some(vec![AssistKind::RefactorExtract]); 284 cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
282 let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); 285 let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
283 let expected = labels(&assists); 286 let expected = labels(&assists);
284 287
285 expect![[r#" 288 expect![[r#"
@@ -292,7 +295,7 @@ pub fn test_some_range(a: int) -> bool {
292 { 295 {
293 let mut cfg = TEST_CONFIG; 296 let mut cfg = TEST_CONFIG;
294 cfg.allowed = Some(vec![AssistKind::QuickFix]); 297 cfg.allowed = Some(vec![AssistKind::QuickFix]);
295 let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); 298 let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
296 let expected = labels(&assists); 299 let expected = labels(&assists);
297 300
298 expect![[r#""#]].assert_eq(&expected); 301 expect![[r#""#]].assert_eq(&expected);
@@ -317,7 +320,7 @@ pub fn test_some_range(a: int) -> bool {
317 cfg.allowed = Some(vec![AssistKind::RefactorExtract]); 320 cfg.allowed = Some(vec![AssistKind::RefactorExtract]);
318 321
319 { 322 {
320 let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); 323 let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange);
321 assert_eq!(2, assists.len()); 324 assert_eq!(2, assists.len());
322 let mut assists = assists.into_iter(); 325 let mut assists = assists.into_iter();
323 326
@@ -353,7 +356,7 @@ pub fn test_some_range(a: int) -> bool {
353 } 356 }
354 357
355 { 358 {
356 let assists = Assist::get( 359 let assists = assists(
357 &db, 360 &db,
358 &cfg, 361 &cfg,
359 AssistResolveStrategy::Single(SingleResolve { 362 AssistResolveStrategy::Single(SingleResolve {
@@ -397,7 +400,7 @@ pub fn test_some_range(a: int) -> bool {
397 } 400 }
398 401
399 { 402 {
400 let assists = Assist::get( 403 let assists = assists(
401 &db, 404 &db,
402 &cfg, 405 &cfg,
403 AssistResolveStrategy::Single(SingleResolve { 406 AssistResolveStrategy::Single(SingleResolve {
@@ -462,7 +465,7 @@ pub fn test_some_range(a: int) -> bool {
462 } 465 }
463 466
464 { 467 {
465 let assists = Assist::get(&db, &cfg, AssistResolveStrategy::All, frange); 468 let assists = assists(&db, &cfg, AssistResolveStrategy::All, frange);
466 assert_eq!(2, assists.len()); 469 assert_eq!(2, assists.len());
467 let mut assists = assists.into_iter(); 470 let mut assists = assists.into_iter();
468 471
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index de5d9e55a..1509c3c63 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -209,10 +209,7 @@ fn doctest_convert_into_to_from() {
209 check_doc_test( 209 check_doc_test(
210 "convert_into_to_from", 210 "convert_into_to_from",
211 r#####" 211 r#####"
212//- /lib.rs crate:core 212//- minicore: from
213pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } }
214//- /lib.rs crate:main deps:core
215use core::convert::Into;
216impl $0Into<Thing> for usize { 213impl $0Into<Thing> for usize {
217 fn into(self) -> Thing { 214 fn into(self) -> Thing {
218 Thing { 215 Thing {
@@ -223,7 +220,6 @@ impl $0Into<Thing> for usize {
223} 220}
224"#####, 221"#####,
225 r#####" 222 r#####"
226use core::convert::Into;
227impl From<usize> for Thing { 223impl From<usize> for Thing {
228 fn from(val: usize) -> Self { 224 fn from(val: usize) -> Self {
229 Thing { 225 Thing {
@@ -241,23 +237,19 @@ fn doctest_convert_iter_for_each_to_for() {
241 check_doc_test( 237 check_doc_test(
242 "convert_iter_for_each_to_for", 238 "convert_iter_for_each_to_for",
243 r#####" 239 r#####"
244//- /lib.rs crate:core 240//- minicore: iterators
245pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } } 241use core::iter;
246pub struct SomeIter;
247impl self::iter::traits::iterator::Iterator for SomeIter {}
248//- /lib.rs crate:main deps:core
249use core::SomeIter;
250fn main() { 242fn main() {
251 let iter = SomeIter; 243 let iter = iter::repeat((9, 2));
252 iter.for_each$0(|(x, y)| { 244 iter.for_each$0(|(x, y)| {
253 println!("x: {}, y: {}", x, y); 245 println!("x: {}, y: {}", x, y);
254 }); 246 });
255} 247}
256"#####, 248"#####,
257 r#####" 249 r#####"
258use core::SomeIter; 250use core::iter;
259fn main() { 251fn main() {
260 let iter = SomeIter; 252 let iter = iter::repeat((9, 2));
261 for (x, y) in iter { 253 for (x, y) in iter {
262 println!("x: {}, y: {}", x, y); 254 println!("x: {}, y: {}", x, y);
263 } 255 }
@@ -1519,16 +1511,15 @@ fn doctest_replace_unwrap_with_match() {
1519 check_doc_test( 1511 check_doc_test(
1520 "replace_unwrap_with_match", 1512 "replace_unwrap_with_match",
1521 r#####" 1513 r#####"
1522enum Result<T, E> { Ok(T), Err(E) } 1514//- minicore: result
1523fn main() { 1515fn main() {
1524 let x: Result<i32, i32> = Result::Ok(92); 1516 let x: Result<i32, i32> = Ok(92);
1525 let y = x.$0unwrap(); 1517 let y = x.$0unwrap();
1526} 1518}
1527"#####, 1519"#####,
1528 r#####" 1520 r#####"
1529enum Result<T, E> { Ok(T), Err(E) }
1530fn main() { 1521fn main() {
1531 let x: Result<i32, i32> = Result::Ok(92); 1522 let x: Result<i32, i32> = Ok(92);
1532 let y = match x { 1523 let y = match x {
1533 Ok(it) => it, 1524 Ok(it) => it,
1534 $0_ => unreachable!(), 1525 $0_ => unreachable!(),
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 068df005b..0ec236aa0 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -8,6 +8,7 @@ use ast::TypeBoundsOwner;
8use hir::{Adt, HasSource, Semantics}; 8use hir::{Adt, HasSource, Semantics};
9use ide_db::{ 9use ide_db::{
10 helpers::{FamousDefs, SnippetCap}, 10 helpers::{FamousDefs, SnippetCap},
11 path_transform::PathTransform,
11 RootDatabase, 12 RootDatabase,
12}; 13};
13use itertools::Itertools; 14use itertools::Itertools;
@@ -22,10 +23,7 @@ use syntax::{
22 SyntaxNode, TextSize, T, 23 SyntaxNode, TextSize, T,
23}; 24};
24 25
25use crate::{ 26use crate::assist_context::{AssistBuilder, AssistContext};
26 assist_context::{AssistBuilder, AssistContext},
27 path_transform::PathTransform,
28};
29 27
30pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { 28pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
31 extract_trivial_expression(&block) 29 extract_trivial_expression(&block)
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index bd90cefb2..cba5eb0c6 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -41,9 +41,9 @@ pub struct Completions {
41 buf: Vec<CompletionItem>, 41 buf: Vec<CompletionItem>,
42} 42}
43 43
44impl Into<Vec<CompletionItem>> for Completions { 44impl From<Completions> for Vec<CompletionItem> {
45 fn into(self) -> Vec<CompletionItem> { 45 fn from(val: Completions) -> Self {
46 self.buf 46 val.buf
47 } 47 }
48} 48}
49 49
@@ -74,44 +74,12 @@ impl Completions {
74 items.into_iter().for_each(|item| self.add(item.into())) 74 items.into_iter().for_each(|item| self.add(item.into()))
75 } 75 }
76 76
77 pub(crate) fn add_field(
78 &mut self,
79 ctx: &CompletionContext,
80 receiver: Option<hir::Name>,
81 field: hir::Field,
82 ty: &hir::Type,
83 ) {
84 let item = render_field(RenderContext::new(ctx), receiver, field, ty);
85 self.add(item);
86 }
87
88 pub(crate) fn add_tuple_field(
89 &mut self,
90 ctx: &CompletionContext,
91 receiver: Option<hir::Name>,
92 field: usize,
93 ty: &hir::Type,
94 ) {
95 let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
96 self.add(item);
97 }
98
99 pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) {
100 let mut item =
101 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static");
102 item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam));
103 self.add(item.build());
104 }
105
106 pub(crate) fn add_resolution( 77 pub(crate) fn add_resolution(
107 &mut self, 78 &mut self,
108 ctx: &CompletionContext, 79 ctx: &CompletionContext,
109 local_name: hir::Name, 80 local_name: hir::Name,
110 resolution: &hir::ScopeDef, 81 resolution: &hir::ScopeDef,
111 ) { 82 ) {
112 if ctx.expects_type() && resolution.is_value_def() {
113 return;
114 }
115 self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); 83 self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
116 } 84 }
117 85
@@ -134,9 +102,6 @@ impl Completions {
134 func: hir::Function, 102 func: hir::Function,
135 local_name: Option<hir::Name>, 103 local_name: Option<hir::Name>,
136 ) { 104 ) {
137 if ctx.expects_type() {
138 return;
139 }
140 self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); 105 self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
141 } 106 }
142 107
@@ -150,94 +115,119 @@ impl Completions {
150 self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); 115 self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
151 } 116 }
152 117
153 pub(crate) fn add_variant_pat( 118 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
119 self.add_opt(render_const(RenderContext::new(ctx), constant));
120 }
121
122 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
123 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
124 }
125
126 pub(crate) fn add_type_alias_with_eq(
154 &mut self, 127 &mut self,
155 ctx: &CompletionContext, 128 ctx: &CompletionContext,
156 variant: hir::Variant, 129 type_alias: hir::TypeAlias,
157 local_name: Option<hir::Name>,
158 ) { 130 ) {
159 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); 131 self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
160 } 132 }
161 133
162 pub(crate) fn add_qualified_variant_pat( 134 pub(crate) fn add_qualified_enum_variant(
163 &mut self, 135 &mut self,
164 ctx: &CompletionContext, 136 ctx: &CompletionContext,
165 variant: hir::Variant, 137 variant: hir::Variant,
166 path: hir::ModPath, 138 path: hir::ModPath,
167 ) { 139 ) {
168 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); 140 let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path));
141 self.add(item);
169 } 142 }
170 143
171 pub(crate) fn add_struct_pat( 144 pub(crate) fn add_enum_variant(
172 &mut self, 145 &mut self,
173 ctx: &CompletionContext, 146 ctx: &CompletionContext,
174 strukt: hir::Struct, 147 variant: hir::Variant,
175 local_name: Option<hir::Name>, 148 local_name: Option<hir::Name>,
176 ) { 149 ) {
177 self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); 150 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
151 self.add(item);
178 } 152 }
179 153
180 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 154 pub(crate) fn add_field(
181 if ctx.expects_type() { 155 &mut self,
182 return; 156 ctx: &CompletionContext,
183 } 157 receiver: Option<hir::Name>,
184 self.add_opt(render_const(RenderContext::new(ctx), constant)); 158 field: hir::Field,
159 ty: &hir::Type,
160 ) {
161 let item = render_field(RenderContext::new(ctx), receiver, field, ty);
162 self.add(item);
185 } 163 }
186 164
187 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { 165 pub(crate) fn add_tuple_field(
188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); 166 &mut self,
167 ctx: &CompletionContext,
168 receiver: Option<hir::Name>,
169 field: usize,
170 ty: &hir::Type,
171 ) {
172 let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
173 self.add(item);
189 } 174 }
190 175
191 pub(crate) fn add_type_alias_with_eq( 176 pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) {
177 let mut item =
178 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static");
179 item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam));
180 self.add(item.build());
181 }
182
183 pub(crate) fn add_variant_pat(
192 &mut self, 184 &mut self,
193 ctx: &CompletionContext, 185 ctx: &CompletionContext,
194 type_alias: hir::TypeAlias, 186 variant: hir::Variant,
187 local_name: Option<hir::Name>,
195 ) { 188 ) {
196 self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); 189 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None));
197 } 190 }
198 191
199 pub(crate) fn add_qualified_enum_variant( 192 pub(crate) fn add_qualified_variant_pat(
200 &mut self, 193 &mut self,
201 ctx: &CompletionContext, 194 ctx: &CompletionContext,
202 variant: hir::Variant, 195 variant: hir::Variant,
203 path: hir::ModPath, 196 path: hir::ModPath,
204 ) { 197 ) {
205 let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); 198 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)));
206 self.add(item);
207 } 199 }
208 200
209 pub(crate) fn add_enum_variant( 201 pub(crate) fn add_struct_pat(
210 &mut self, 202 &mut self,
211 ctx: &CompletionContext, 203 ctx: &CompletionContext,
212 variant: hir::Variant, 204 strukt: hir::Struct,
213 local_name: Option<hir::Name>, 205 local_name: Option<hir::Name>,
214 ) { 206 ) {
215 if ctx.expects_type() { 207 self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
216 return;
217 }
218 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
219 self.add(item);
220 } 208 }
221} 209}
222 210
223fn complete_enum_variants( 211/// Calls the callback for each variant of the provided enum with the path to the variant.
212/// Skips variants that are visible with single segment paths.
213fn enum_variants_with_paths(
224 acc: &mut Completions, 214 acc: &mut Completions,
225 ctx: &CompletionContext, 215 ctx: &CompletionContext,
226 enum_data: hir::Enum, 216 enum_: hir::Enum,
227 cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), 217 cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath),
228) { 218) {
229 let variants = enum_data.variants(ctx.db); 219 let variants = enum_.variants(ctx.db);
230 220
231 let module = if let Some(module) = ctx.scope.module() { 221 let module = if let Some(module) = ctx.scope.module() {
232 // Compute path from the completion site if available. 222 // Compute path from the completion site if available.
233 module 223 module
234 } else { 224 } else {
235 // Otherwise fall back to the enum's definition site. 225 // Otherwise fall back to the enum's definition site.
236 enum_data.module(ctx.db) 226 enum_.module(ctx.db)
237 }; 227 };
238 228
239 if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { 229 if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
240 if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_data)) { 230 if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
241 for &variant in &variants { 231 for &variant in &variants {
242 let self_path = hir::ModPath::from_segments( 232 let self_path = hir::ModPath::from_segments(
243 hir::PathKind::Plain, 233 hir::PathKind::Plain,
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 6df569c2a..78fc30e16 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -17,12 +17,14 @@ use crate::{
17 17
18mod derive; 18mod derive;
19mod lint; 19mod lint;
20mod repr;
20 21
21pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 22pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
22 let attribute = ctx.attribute_under_caret.as_ref()?; 23 let attribute = ctx.attribute_under_caret.as_ref()?;
23 match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { 24 match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) {
24 (Some(path), Some(token_tree)) => match path.text().as_str() { 25 (Some(path), Some(token_tree)) => match path.text().as_str() {
25 "derive" => derive::complete_derive(acc, ctx, token_tree), 26 "derive" => derive::complete_derive(acc, ctx, token_tree),
27 "repr" => repr::complete_repr(acc, ctx, token_tree),
26 "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), 28 "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES),
27 "allow" | "warn" | "deny" | "forbid" => { 29 "allow" | "warn" | "deny" | "forbid" => {
28 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); 30 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
@@ -322,7 +324,7 @@ mod tests {
322 324
323 use expect_test::{expect, Expect}; 325 use expect_test::{expect, Expect};
324 326
325 use crate::{test_utils::completion_list, CompletionKind}; 327 use crate::tests::completion_list;
326 328
327 #[test] 329 #[test]
328 fn attributes_are_sorted() { 330 fn attributes_are_sorted() {
@@ -341,7 +343,7 @@ mod tests {
341 } 343 }
342 344
343 fn check(ra_fixture: &str, expect: Expect) { 345 fn check(ra_fixture: &str, expect: Expect) {
344 let actual = completion_list(ra_fixture, CompletionKind::Attribute); 346 let actual = completion_list(ra_fixture);
345 expect.assert_eq(&actual); 347 expect.assert_eq(&actual);
346 } 348 }
347 349
@@ -792,6 +794,7 @@ mod tests {
792 794
793 #[test] 795 #[test]
794 fn complete_attribute_on_expr() { 796 fn complete_attribute_on_expr() {
797 cov_mark::check!(no_keyword_completion_in_attr_of_expr);
795 check( 798 check(
796 r#"fn main() { #[$0] foo() }"#, 799 r#"fn main() { #[$0] foo() }"#,
797 expect![[r#" 800 expect![[r#"
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index d526824fb..6fe41e0d6 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -31,6 +31,8 @@ pub(super) fn complete_derive(
31 let lookup = components.join(", "); 31 let lookup = components.join(", ");
32 let label = components.iter().rev().join(", "); 32 let label = components.iter().rev().join(", ");
33 (label, Some(lookup)) 33 (label, Some(lookup))
34 } else if existing_derives.contains(&derive) {
35 continue;
34 } else { 36 } else {
35 (derive, None) 37 (derive, None)
36 }; 38 };
@@ -80,10 +82,31 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
80mod tests { 82mod tests {
81 use expect_test::{expect, Expect}; 83 use expect_test::{expect, Expect};
82 84
83 use crate::{test_utils::completion_list, CompletionKind}; 85 use crate::tests::completion_list;
84 86
85 fn check(ra_fixture: &str, expect: Expect) { 87 fn check(ra_fixture: &str, expect: Expect) {
86 let actual = completion_list(ra_fixture, CompletionKind::Attribute); 88 let builtin_derives = r#"
89#[rustc_builtin_macro]
90pub macro Clone {}
91#[rustc_builtin_macro]
92pub macro Copy {}
93#[rustc_builtin_macro]
94pub macro Default {}
95#[rustc_builtin_macro]
96pub macro Debug {}
97#[rustc_builtin_macro]
98pub macro Hash {}
99#[rustc_builtin_macro]
100pub macro PartialEq {}
101#[rustc_builtin_macro]
102pub macro Eq {}
103#[rustc_builtin_macro]
104pub macro PartialOrd {}
105#[rustc_builtin_macro]
106pub macro Ord {}
107
108"#;
109 let actual = completion_list(&format!("{} {}", builtin_derives, ra_fixture));
87 expect.assert_eq(&actual); 110 expect.assert_eq(&actual);
88 } 111 }
89 112
@@ -93,56 +116,53 @@ mod tests {
93 } 116 }
94 117
95 #[test] 118 #[test]
96 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
97 fn empty_derive() { 119 fn empty_derive() {
98 check( 120 check(
99 r#"#[derive($0)] struct Test;"#, 121 r#"#[derive($0)] struct Test;"#,
100 expect![[r#" 122 expect![[r#"
101 at Clone 123 at PartialEq
102 at Clone, Copy 124 at Default
103 at Debug 125 at PartialEq, Eq
104 at Default 126 at PartialEq, Eq, PartialOrd, Ord
105 at Hash 127 at Clone, Copy
106 at PartialEq 128 at Debug
107 at PartialEq, Eq 129 at Clone
108 at PartialEq, PartialOrd 130 at Hash
109 at PartialEq, Eq, PartialOrd, Ord 131 at PartialEq, PartialOrd
110 "#]], 132 "#]],
111 ); 133 );
112 } 134 }
113 135
114 #[test] 136 #[test]
115 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
116 fn derive_with_input() { 137 fn derive_with_input() {
117 check( 138 check(
118 r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, 139 r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
119 expect![[r#" 140 expect![[r#"
120 at Clone 141 at Default
142 at Eq
143 at Eq, PartialOrd, Ord
121 at Clone, Copy 144 at Clone, Copy
122 at Debug 145 at Debug
123 at Default 146 at Clone
124 at Hash 147 at Hash
125 at Eq
126 at PartialOrd 148 at PartialOrd
127 at Eq, PartialOrd, Ord
128 "#]], 149 "#]],
129 ) 150 )
130 } 151 }
131 152
132 #[test] 153 #[test]
133 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
134 fn derive_with_input2() { 154 fn derive_with_input2() {
135 check( 155 check(
136 r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, 156 r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,
137 expect![[r#" 157 expect![[r#"
138 at Clone 158 at Default
159 at Eq
160 at Eq, PartialOrd, Ord
139 at Clone, Copy 161 at Clone, Copy
140 at Debug 162 at Debug
141 at Default 163 at Clone
142 at Hash 164 at Hash
143 at Eq
144 at PartialOrd 165 at PartialOrd
145 at Eq, PartialOrd, Ord
146 "#]], 166 "#]],
147 ) 167 )
148 } 168 }
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
index ca99e9759..1ddc38986 100644
--- a/crates/ide_completion/src/completions/attribute/lint.rs
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -33,8 +33,7 @@ pub(super) fn complete_lint(
33 33
34#[cfg(test)] 34#[cfg(test)]
35mod tests { 35mod tests {
36 36 use crate::tests::check_edit;
37 use crate::test_utils::check_edit;
38 37
39 #[test] 38 #[test]
40 fn check_empty() { 39 fn check_empty() {
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs
new file mode 100644
index 000000000..92a262a43
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/repr.rs
@@ -0,0 +1,199 @@
1//! Completion for representations.
2
3use syntax::ast;
4
5use crate::{
6 context::CompletionContext,
7 item::{CompletionItem, CompletionItemKind, CompletionKind},
8 Completions,
9};
10
11pub(super) fn complete_repr(
12 acc: &mut Completions,
13 ctx: &CompletionContext,
14 derive_input: ast::TokenTree,
15) {
16 if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) {
17 for repr_completion in REPR_COMPLETIONS {
18 if existing_reprs
19 .iter()
20 .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it))
21 {
22 continue;
23 }
24 let mut item = CompletionItem::new(
25 CompletionKind::Attribute,
26 ctx.source_range(),
27 repr_completion.label,
28 );
29 item.kind(CompletionItemKind::Attribute);
30 if let Some(lookup) = repr_completion.lookup {
31 item.lookup_by(lookup);
32 }
33 if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) {
34 item.insert_snippet(cap, snippet);
35 }
36 item.add_to(acc);
37 }
38 }
39}
40
41struct ReprCompletion {
42 label: &'static str,
43 snippet: Option<&'static str>,
44 lookup: Option<&'static str>,
45 collides: &'static [&'static str],
46}
47
48const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion {
49 ReprCompletion { label, snippet: None, lookup: None, collides }
50}
51
52#[rustfmt::skip]
53const REPR_COMPLETIONS: &[ReprCompletion] = &[
54 ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] },
55 attr("packed", &["transparent", "align"]),
56 attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
57 attr("C", &["transparent"]),
58 attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
59 attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
60 attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
61 attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
62 attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
63 attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]),
64 attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]),
65 attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]),
66 attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]),
67 attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]),
68 attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]),
69 attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]),
70];
71
72#[cfg(test)]
73mod tests {
74 use expect_test::{expect, Expect};
75
76 use crate::tests::completion_list;
77
78 fn check(ra_fixture: &str, expect: Expect) {
79 let actual = completion_list(ra_fixture);
80 expect.assert_eq(&actual);
81 }
82
83 #[test]
84 fn no_completion_for_incorrect_repr() {
85 check(r#"#[repr{$0)] struct Test;"#, expect![[]])
86 }
87
88 #[test]
89 fn empty() {
90 check(
91 r#"#[repr($0)] struct Test;"#,
92 expect![[r#"
93 at align($0)
94 at packed
95 at transparent
96 at C
97 at u8
98 at u16
99 at u32
100 at u64
101 at u128
102 at usize
103 at i8
104 at i16
105 at i32
106 at i64
107 at i28
108 at isize
109 "#]],
110 );
111 }
112
113 #[test]
114 fn transparent() {
115 check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
116 }
117
118 #[test]
119 fn align() {
120 check(
121 r#"#[repr(align(1), $0)] struct Test;"#,
122 expect![[r#"
123 at align($0)
124 at transparent
125 at C
126 at u8
127 at u16
128 at u32
129 at u64
130 at u128
131 at usize
132 at i8
133 at i16
134 at i32
135 at i64
136 at i28
137 at isize
138 "#]],
139 );
140 }
141
142 #[test]
143 fn packed() {
144 check(
145 r#"#[repr(packed, $0)] struct Test;"#,
146 expect![[r#"
147 at transparent
148 at C
149 at u8
150 at u16
151 at u32
152 at u64
153 at u128
154 at usize
155 at i8
156 at i16
157 at i32
158 at i64
159 at i28
160 at isize
161 "#]],
162 );
163 }
164
165 #[test]
166 fn c() {
167 check(
168 r#"#[repr(C, $0)] struct Test;"#,
169 expect![[r#"
170 at align($0)
171 at packed
172 at u8
173 at u16
174 at u32
175 at u64
176 at u128
177 at usize
178 at i8
179 at i16
180 at i32
181 at i64
182 at i28
183 at isize
184 "#]],
185 );
186 }
187
188 #[test]
189 fn prim() {
190 check(
191 r#"#[repr(usize, $0)] struct Test;"#,
192 expect![[r#"
193 at align($0)
194 at packed
195 at C
196 "#]],
197 );
198 }
199}
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 9552875c1..286d7cb67 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -101,10 +101,10 @@ fn complete_methods(
101mod tests { 101mod tests {
102 use expect_test::{expect, Expect}; 102 use expect_test::{expect, Expect};
103 103
104 use crate::{test_utils::completion_list, CompletionKind}; 104 use crate::{tests::filtered_completion_list, CompletionKind};
105 105
106 fn check(ra_fixture: &str, expect: Expect) { 106 fn check(ra_fixture: &str, expect: Expect) {
107 let actual = completion_list(ra_fixture, CompletionKind::Reference); 107 let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
108 expect.assert_eq(&actual); 108 expect.assert_eq(&actual);
109 } 109 }
110 110
@@ -498,10 +498,7 @@ mod foo {
498 fn issue_8931() { 498 fn issue_8931() {
499 check( 499 check(
500 r#" 500 r#"
501#[lang = "fn_once"] 501//- minicore: fn
502trait FnOnce<Args> {
503 type Output;
504}
505struct S; 502struct S;
506 503
507struct Foo; 504struct Foo;
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 30b8d44bd..814c15653 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
109 if !ctx.config.enable_imports_on_the_fly { 109 if !ctx.config.enable_imports_on_the_fly {
110 return None; 110 return None;
111 } 111 }
112 if ctx.use_item_syntax.is_some() 112 if ctx.in_use_tree()
113 || ctx.is_path_disallowed() 113 || ctx.is_path_disallowed()
114 || ctx.expects_item() 114 || ctx.expects_item()
115 || ctx.expects_assoc_item() 115 || ctx.expects_assoc_item()
@@ -227,11 +227,11 @@ mod tests {
227 227
228 use crate::{ 228 use crate::{
229 item::CompletionKind, 229 item::CompletionKind,
230 test_utils::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, 230 tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG},
231 }; 231 };
232 232
233 fn check(ra_fixture: &str, expect: Expect) { 233 fn check(ra_fixture: &str, expect: Expect) {
234 let actual = completion_list(ra_fixture, CompletionKind::Magic); 234 let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
235 expect.assert_eq(&actual); 235 expect.assert_eq(&actual);
236 } 236 }
237 237
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index cb90e8a3e..c9f0e2473 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -64,10 +64,10 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
64mod tests { 64mod tests {
65 use expect_test::{expect, Expect}; 65 use expect_test::{expect, Expect};
66 66
67 use crate::{test_utils::completion_list, CompletionKind}; 67 use crate::{tests::filtered_completion_list, CompletionKind};
68 68
69 fn check(ra_fixture: &str, expect: Expect) { 69 fn check(ra_fixture: &str, expect: Expect) {
70 let actual = completion_list(ra_fixture, CompletionKind::Magic); 70 let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
71 expect.assert_eq(&actual); 71 expect.assert_eq(&actual);
72 } 72 }
73 73
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index ba13d3707..407f796ef 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -18,26 +18,22 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
18 item 18 item
19 }; 19 };
20 20
21 if ctx.use_item_syntax.is_some() { 21 if ctx.in_use_tree() {
22 let qual = ctx.path_qual(); 22 match &ctx.path_context {
23 if qual.is_none() { 23 Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => {
24 kw_completion("crate::").add_to(acc); 24 if iter::successors(Some(qual.clone()), |p| p.qualifier())
25 } 25 .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
26 kw_completion("self").add_to(acc); 26 {
27 if iter::successors(qual.cloned(), |p| p.qualifier()) 27 kw_completion("super::").add_to(acc);
28 .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) 28 }
29 { 29 if *use_tree_parent {
30 kw_completion("super::").add_to(acc); 30 kw_completion("self").add_to(acc);
31 } 31 }
32 } 32 }
33 33 _ => {
34 // Suggest .await syntax for types that implement Future trait 34 kw_completion("crate::").add_to(acc);
35 if let Some(receiver) = ctx.dot_receiver() { 35 kw_completion("self::").add_to(acc);
36 if let Some(ty) = ctx.sema.type_of_expr(receiver) { 36 kw_completion("super::").add_to(acc);
37 if ty.impls_future(ctx.db) {
38 let mut item = kw_completion("await");
39 item.detail("expr.await");
40 item.add_to(acc);
41 } 37 }
42 }; 38 };
43 } 39 }
@@ -52,6 +48,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
52 cov_mark::hit!(no_keyword_completion_in_record_lit); 48 cov_mark::hit!(no_keyword_completion_in_record_lit);
53 return; 49 return;
54 } 50 }
51 if ctx.attribute_under_caret.is_some() {
52 cov_mark::hit!(no_keyword_completion_in_attr_of_expr);
53 return;
54 }
55
56 // Suggest .await syntax for types that implement Future trait
57 if let Some(receiver) = ctx.dot_receiver() {
58 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
59 if ty.impls_future(ctx.db) {
60 let mut item =
61 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
62 item.kind(CompletionItemKind::Keyword).detail("expr.await");
63 item.add_to(acc);
64 }
65 };
66 }
67
55 let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); 68 let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);
56 69
57 let expects_assoc_item = ctx.expects_assoc_item(); 70 let expects_assoc_item = ctx.expects_assoc_item();
@@ -60,6 +73,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
60 73
61 if ctx.has_impl_or_trait_prev_sibling() { 74 if ctx.has_impl_or_trait_prev_sibling() {
62 add_keyword("where", "where "); 75 add_keyword("where", "where ");
76 if ctx.has_impl_prev_sibling() {
77 add_keyword("for", "for ");
78 }
63 return; 79 return;
64 } 80 }
65 if ctx.previous_token_is(T![unsafe]) { 81 if ctx.previous_token_is(T![unsafe]) {
@@ -75,7 +91,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
75 return; 91 return;
76 } 92 }
77 93
78 if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { 94 if !ctx.has_visibility_prev_sibling()
95 && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field())
96 {
79 add_keyword("pub(crate)", "pub(crate) "); 97 add_keyword("pub(crate)", "pub(crate) ");
80 add_keyword("pub", "pub "); 98 add_keyword("pub", "pub ");
81 } 99 }
@@ -88,11 +106,13 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
88 } 106 }
89 107
90 if expects_item || has_block_expr_parent { 108 if expects_item || has_block_expr_parent {
109 if !ctx.has_visibility_prev_sibling() {
110 add_keyword("impl", "impl $1 {\n $0\n}");
111 add_keyword("extern", "extern $0");
112 }
91 add_keyword("use", "use $0"); 113 add_keyword("use", "use $0");
92 add_keyword("impl", "impl $1 {\n $0\n}");
93 add_keyword("trait", "trait $1 {\n $0\n}"); 114 add_keyword("trait", "trait $1 {\n $0\n}");
94 add_keyword("static", "static $0"); 115 add_keyword("static", "static $0");
95 add_keyword("extern", "extern $0");
96 add_keyword("mod", "mod $0"); 116 add_keyword("mod", "mod $0");
97 } 117 }
98 118
@@ -102,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
102 add_keyword("union", "union $1 {\n $0\n}"); 122 add_keyword("union", "union $1 {\n $0\n}");
103 } 123 }
104 124
125 if ctx.expects_type() {
126 return;
127 }
128
105 if ctx.expects_expression() { 129 if ctx.expects_expression() {
106 if !has_block_expr_parent { 130 if !has_block_expr_parent {
107 add_keyword("unsafe", "unsafe {\n $0\n}"); 131 add_keyword("unsafe", "unsafe {\n $0\n}");
@@ -186,75 +210,16 @@ mod tests {
186 use expect_test::{expect, Expect}; 210 use expect_test::{expect, Expect};
187 211
188 use crate::{ 212 use crate::{
189 test_utils::{check_edit, completion_list}, 213 tests::{check_edit, filtered_completion_list},
190 CompletionKind, 214 CompletionKind,
191 }; 215 };
192 216
193 fn check(ra_fixture: &str, expect: Expect) { 217 fn check(ra_fixture: &str, expect: Expect) {
194 let actual = completion_list(ra_fixture, CompletionKind::Keyword); 218 let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword);
195 expect.assert_eq(&actual) 219 expect.assert_eq(&actual)
196 } 220 }
197 221
198 #[test] 222 #[test]
199 fn test_keywords_in_use_stmt() {
200 check(
201 r"use $0",
202 expect![[r#"
203 kw crate::
204 kw self
205 kw super::
206 "#]],
207 );
208
209 // FIXME: `self` shouldn't be shown here and the check below
210 check(
211 r"use a::$0",
212 expect![[r#"
213 kw self
214 "#]],
215 );
216
217 check(
218 r"use super::$0",
219 expect![[r#"
220 kw self
221 kw super::
222 "#]],
223 );
224
225 check(
226 r"use a::{b, $0}",
227 expect![[r#"
228 kw self
229 "#]],
230 );
231 }
232
233 #[test]
234 fn test_keywords_at_source_file_level() {
235 check(
236 r"m$0",
237 expect![[r#"
238 kw pub(crate)
239 kw pub
240 kw unsafe
241 kw fn
242 kw const
243 kw type
244 kw use
245 kw impl
246 kw trait
247 kw static
248 kw extern
249 kw mod
250 kw enum
251 kw struct
252 kw union
253 "#]],
254 );
255 }
256
257 #[test]
258 fn test_keywords_in_function() { 223 fn test_keywords_in_function() {
259 check( 224 check(
260 r"fn quux() { $0 }", 225 r"fn quux() { $0 }",
@@ -263,11 +228,11 @@ mod tests {
263 kw fn 228 kw fn
264 kw const 229 kw const
265 kw type 230 kw type
266 kw use
267 kw impl 231 kw impl
232 kw extern
233 kw use
268 kw trait 234 kw trait
269 kw static 235 kw static
270 kw extern
271 kw mod 236 kw mod
272 kw match 237 kw match
273 kw while 238 kw while
@@ -291,11 +256,11 @@ mod tests {
291 kw fn 256 kw fn
292 kw const 257 kw const
293 kw type 258 kw type
294 kw use
295 kw impl 259 kw impl
260 kw extern
261 kw use
296 kw trait 262 kw trait
297 kw static 263 kw static
298 kw extern
299 kw mod 264 kw mod
300 kw match 265 kw match
301 kw while 266 kw while
@@ -319,11 +284,11 @@ mod tests {
319 kw fn 284 kw fn
320 kw const 285 kw const
321 kw type 286 kw type
322 kw use
323 kw impl 287 kw impl
288 kw extern
289 kw use
324 kw trait 290 kw trait
325 kw static 291 kw static
326 kw extern
327 kw mod 292 kw mod
328 kw match 293 kw match
329 kw while 294 kw while
@@ -370,49 +335,6 @@ fn quux() -> i32 {
370 } 335 }
371 336
372 #[test] 337 #[test]
373 fn test_keywords_in_trait_def() {
374 check(
375 r"trait My { $0 }",
376 expect![[r#"
377 kw unsafe
378 kw fn
379 kw const
380 kw type
381 "#]],
382 );
383 }
384
385 #[test]
386 fn test_keywords_in_impl_def() {
387 check(
388 r"impl My { $0 }",
389 expect![[r#"
390 kw pub(crate)
391 kw pub
392 kw unsafe
393 kw fn
394 kw const
395 kw type
396 "#]],
397 );
398 }
399
400 #[test]
401 fn test_keywords_in_impl_def_with_attr() {
402 check(
403 r"impl My { #[foo] $0 }",
404 expect![[r#"
405 kw pub(crate)
406 kw pub
407 kw unsafe
408 kw fn
409 kw const
410 kw type
411 "#]],
412 );
413 }
414
415 #[test]
416 fn test_keywords_in_loop() { 338 fn test_keywords_in_loop() {
417 check( 339 check(
418 r"fn my() { loop { $0 } }", 340 r"fn my() { loop { $0 } }",
@@ -421,11 +343,11 @@ fn quux() -> i32 {
421 kw fn 343 kw fn
422 kw const 344 kw const
423 kw type 345 kw type
424 kw use
425 kw impl 346 kw impl
347 kw extern
348 kw use
426 kw trait 349 kw trait
427 kw static 350 kw static
428 kw extern
429 kw mod 351 kw mod
430 kw match 352 kw match
431 kw while 353 kw while
@@ -443,18 +365,6 @@ fn quux() -> i32 {
443 } 365 }
444 366
445 #[test] 367 #[test]
446 fn test_keywords_after_unsafe_in_item_list() {
447 check(
448 r"unsafe $0",
449 expect![[r#"
450 kw fn
451 kw trait
452 kw impl
453 "#]],
454 );
455 }
456
457 #[test]
458 fn test_keywords_after_unsafe_in_block_expr() { 368 fn test_keywords_after_unsafe_in_block_expr() {
459 check( 369 check(
460 r"fn my_fn() { unsafe $0 }", 370 r"fn my_fn() { unsafe $0 }",
@@ -467,44 +377,6 @@ fn quux() -> i32 {
467 } 377 }
468 378
469 #[test] 379 #[test]
470 fn test_mut_in_ref_and_in_fn_parameters_list() {
471 check(
472 r"fn my_fn(&$0) {}",
473 expect![[r#"
474 kw mut
475 "#]],
476 );
477 check(
478 r"fn my_fn($0) {}",
479 expect![[r#"
480 kw mut
481 "#]],
482 );
483 check(
484 r"fn my_fn() { let &$0 }",
485 expect![[r#"
486 kw mut
487 "#]],
488 );
489 }
490
491 #[test]
492 fn test_where_keyword() {
493 check(
494 r"trait A $0",
495 expect![[r#"
496 kw where
497 "#]],
498 );
499 check(
500 r"impl A $0",
501 expect![[r#"
502 kw where
503 "#]],
504 );
505 }
506
507 #[test]
508 fn no_keyword_completion_in_comments() { 380 fn no_keyword_completion_in_comments() {
509 cov_mark::check!(no_keyword_completion_in_comments); 381 cov_mark::check!(no_keyword_completion_in_comments);
510 check( 382 check(
@@ -536,17 +408,11 @@ Some multi-line comment$0
536 fn test_completion_await_impls_future() { 408 fn test_completion_await_impls_future() {
537 check( 409 check(
538 r#" 410 r#"
539//- /main.rs crate:main deps:std 411//- minicore: future
540use std::future::*; 412use core::future::*;
541struct A {} 413struct A {}
542impl Future for A {} 414impl Future for A {}
543fn foo(a: A) { a.$0 } 415fn foo(a: A) { a.$0 }
544
545//- /std/lib.rs crate:std
546pub mod future {
547 #[lang = "future_trait"]
548 pub trait Future {}
549}
550"#, 416"#,
551 expect![[r#" 417 expect![[r#"
552 kw await expr.await 418 kw await expr.await
@@ -555,20 +421,12 @@ pub mod future {
555 421
556 check( 422 check(
557 r#" 423 r#"
558//- /main.rs crate:main deps:std 424//- minicore: future
559use std::future::*; 425use std::future::*;
560fn foo() { 426fn foo() {
561 let a = async {}; 427 let a = async {};
562 a.$0 428 a.$0
563} 429}
564
565//- /std/lib.rs crate:std
566pub mod future {
567 #[lang = "future_trait"]
568 pub trait Future {
569 type Output;
570 }
571}
572"#, 430"#,
573 expect![[r#" 431 expect![[r#"
574 kw await expr.await 432 kw await expr.await
@@ -595,22 +453,6 @@ pub mod future {
595 } 453 }
596 454
597 #[test] 455 #[test]
598 fn before_field() {
599 check(
600 r#"
601struct Foo {
602 $0
603 pub f: i32,
604}
605"#,
606 expect![[r#"
607 kw pub(crate)
608 kw pub
609 "#]],
610 )
611 }
612
613 #[test]
614 fn skip_struct_initializer() { 456 fn skip_struct_initializer() {
615 cov_mark::check!(no_keyword_completion_in_record_lit); 457 cov_mark::check!(no_keyword_completion_in_record_lit);
616 check( 458 check(
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs
index 8ccccb646..abf6935c9 100644
--- a/crates/ide_completion/src/completions/lifetime.rs
+++ b/crates/ide_completion/src/completions/lifetime.rs
@@ -49,18 +49,11 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
49mod tests { 49mod tests {
50 use expect_test::{expect, Expect}; 50 use expect_test::{expect, Expect};
51 51
52 use crate::{ 52 use crate::tests::{check_edit, completion_list};
53 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
54 CompletionConfig, CompletionKind,
55 };
56 53
57 fn check(ra_fixture: &str, expect: Expect) { 54 fn check(ra_fixture: &str, expect: Expect) {
58 check_with_config(TEST_CONFIG, ra_fixture, expect); 55 let actual = completion_list(ra_fixture);
59 } 56 expect.assert_eq(&actual);
60
61 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
62 let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
63 expect.assert_eq(&actual)
64 } 57 }
65 58
66 #[test] 59 #[test]
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 6a5746fb9..1c864c0e7 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -141,11 +141,11 @@ fn module_chain_to_containing_module_file(
141 141
142#[cfg(test)] 142#[cfg(test)]
143mod tests { 143mod tests {
144 use crate::{test_utils::completion_list, CompletionKind}; 144 use crate::tests::completion_list;
145 use expect_test::{expect, Expect}; 145 use expect_test::{expect, Expect};
146 146
147 fn check(ra_fixture: &str, expect: Expect) { 147 fn check(ra_fixture: &str, expect: Expect) {
148 let actual = completion_list(ra_fixture, CompletionKind::Magic); 148 let actual = completion_list(ra_fixture);
149 expect.assert_eq(&actual); 149 expect.assert_eq(&actual);
150 } 150 }
151 151
@@ -153,17 +153,17 @@ mod tests {
153 fn lib_module_completion() { 153 fn lib_module_completion() {
154 check( 154 check(
155 r#" 155 r#"
156 //- /lib.rs 156//- /lib.rs
157 mod $0 157mod $0
158 //- /foo.rs 158//- /foo.rs
159 fn foo() {} 159fn foo() {}
160 //- /foo/ignored_foo.rs 160//- /foo/ignored_foo.rs
161 fn ignored_foo() {} 161fn ignored_foo() {}
162 //- /bar/mod.rs 162//- /bar/mod.rs
163 fn bar() {} 163fn bar() {}
164 //- /bar/ignored_bar.rs 164//- /bar/ignored_bar.rs
165 fn ignored_bar() {} 165fn ignored_bar() {}
166 "#, 166"#,
167 expect![[r#" 167 expect![[r#"
168 md foo; 168 md foo;
169 md bar; 169 md bar;
@@ -175,13 +175,13 @@ mod tests {
175 fn no_module_completion_with_module_body() { 175 fn no_module_completion_with_module_body() {
176 check( 176 check(
177 r#" 177 r#"
178 //- /lib.rs 178//- /lib.rs
179 mod $0 { 179mod $0 {
180 180
181 } 181}
182 //- /foo.rs 182//- /foo.rs
183 fn foo() {} 183fn foo() {}
184 "#, 184"#,
185 expect![[r#""#]], 185 expect![[r#""#]],
186 ); 186 );
187 } 187 }
@@ -190,17 +190,17 @@ mod tests {
190 fn main_module_completion() { 190 fn main_module_completion() {
191 check( 191 check(
192 r#" 192 r#"
193 //- /main.rs 193//- /main.rs
194 mod $0 194mod $0
195 //- /foo.rs 195//- /foo.rs
196 fn foo() {} 196fn foo() {}
197 //- /foo/ignored_foo.rs 197//- /foo/ignored_foo.rs
198 fn ignored_foo() {} 198fn ignored_foo() {}
199 //- /bar/mod.rs 199//- /bar/mod.rs
200 fn bar() {} 200fn bar() {}
201 //- /bar/ignored_bar.rs 201//- /bar/ignored_bar.rs
202 fn ignored_bar() {} 202fn ignored_bar() {}
203 "#, 203"#,
204 expect![[r#" 204 expect![[r#"
205 md foo; 205 md foo;
206 md bar; 206 md bar;
@@ -212,13 +212,13 @@ mod tests {
212 fn main_test_module_completion() { 212 fn main_test_module_completion() {
213 check( 213 check(
214 r#" 214 r#"
215 //- /main.rs 215//- /main.rs
216 mod tests { 216mod tests {
217 mod $0; 217 mod $0;
218 } 218}
219 //- /tests/foo.rs 219//- /tests/foo.rs
220 fn foo() {} 220fn foo() {}
221 "#, 221"#,
222 expect![[r#" 222 expect![[r#"
223 md foo 223 md foo
224 "#]], 224 "#]],
@@ -229,19 +229,19 @@ mod tests {
229 fn directly_nested_module_completion() { 229 fn directly_nested_module_completion() {
230 check( 230 check(
231 r#" 231 r#"
232 //- /lib.rs 232//- /lib.rs
233 mod foo; 233mod foo;
234 //- /foo.rs 234//- /foo.rs
235 mod $0; 235mod $0;
236 //- /foo/bar.rs 236//- /foo/bar.rs
237 fn bar() {} 237fn bar() {}
238 //- /foo/bar/ignored_bar.rs 238//- /foo/bar/ignored_bar.rs
239 fn ignored_bar() {} 239fn ignored_bar() {}
240 //- /foo/baz/mod.rs 240//- /foo/baz/mod.rs
241 fn baz() {} 241fn baz() {}
242 //- /foo/moar/ignored_moar.rs 242//- /foo/moar/ignored_moar.rs
243 fn ignored_moar() {} 243fn ignored_moar() {}
244 "#, 244"#,
245 expect![[r#" 245 expect![[r#"
246 md bar 246 md bar
247 md baz 247 md baz
@@ -253,15 +253,15 @@ mod tests {
253 fn nested_in_source_module_completion() { 253 fn nested_in_source_module_completion() {
254 check( 254 check(
255 r#" 255 r#"
256 //- /lib.rs 256//- /lib.rs
257 mod foo; 257mod foo;
258 //- /foo.rs 258//- /foo.rs
259 mod bar { 259mod bar {
260 mod $0 260 mod $0
261 } 261}
262 //- /foo/bar/baz.rs 262//- /foo/bar/baz.rs
263 fn baz() {} 263fn baz() {}
264 "#, 264"#,
265 expect![[r#" 265 expect![[r#"
266 md baz; 266 md baz;
267 "#]], 267 "#]],
@@ -299,16 +299,16 @@ mod tests {
299 fn already_declared_bin_module_completion_omitted() { 299 fn already_declared_bin_module_completion_omitted() {
300 check( 300 check(
301 r#" 301 r#"
302 //- /src/bin.rs crate:main 302//- /src/bin.rs crate:main
303 fn main() {} 303fn main() {}
304 //- /src/bin/foo.rs 304//- /src/bin/foo.rs
305 mod $0 305mod $0
306 //- /src/bin/bar.rs 306//- /src/bin/bar.rs
307 mod foo; 307mod foo;
308 fn bar() {} 308fn bar() {}
309 //- /src/bin/bar/bar_ignored.rs 309//- /src/bin/bar/bar_ignored.rs
310 fn bar_ignored() {} 310fn bar_ignored() {}
311 "#, 311"#,
312 expect![[r#""#]], 312 expect![[r#""#]],
313 ); 313 );
314 } 314 }
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 1daa8595a..bd13a62d7 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -13,7 +13,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
13 if let Some(hir::Adt::Enum(e)) = 13 if let Some(hir::Adt::Enum(e)) =
14 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) 14 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
15 { 15 {
16 super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { 16 super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
17 acc.add_qualified_variant_pat(ctx, variant, path.clone()); 17 acc.add_qualified_variant_pat(ctx, variant, path.clone());
18 acc.add_qualified_enum_variant(ctx, variant, path); 18 acc.add_qualified_enum_variant(ctx, variant, path);
19 }); 19 });
@@ -55,398 +55,3 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
55 } 55 }
56 }); 56 });
57} 57}
58
59#[cfg(test)]
60mod tests {
61 use expect_test::{expect, Expect};
62
63 use crate::{
64 test_utils::{check_edit, completion_list},
65 CompletionKind,
66 };
67
68 fn check(ra_fixture: &str, expect: Expect) {
69 let actual = completion_list(ra_fixture, CompletionKind::Reference);
70 expect.assert_eq(&actual)
71 }
72
73 fn check_snippet(ra_fixture: &str, expect: Expect) {
74 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
75 expect.assert_eq(&actual)
76 }
77
78 #[test]
79 fn completes_enum_variants_and_modules() {
80 check(
81 r#"
82enum E { X }
83use self::E::X;
84const Z: E = E::X;
85mod m {}
86
87static FOO: E = E::X;
88struct Bar { f: u32 }
89
90fn foo() {
91 match E::X { a$0 }
92}
93"#,
94 expect![[r#"
95 en E
96 ct Z
97 st Bar
98 ev X
99 md m
100 "#]],
101 );
102 }
103
104 #[test]
105 fn does_not_complete_non_fn_macros() {
106 check(
107 r#"
108macro_rules! m { ($e:expr) => { $e } }
109enum E { X }
110
111#[rustc_builtin_macro]
112macro Clone {}
113
114fn foo() {
115 match E::X { $0 }
116}
117"#,
118 expect![[r#"
119 ev E::X ()
120 en E
121 ma m!(…) macro_rules! m
122 "#]],
123 );
124 }
125
126 #[test]
127 fn completes_in_simple_macro_call() {
128 check(
129 r#"
130macro_rules! m { ($e:expr) => { $e } }
131enum E { X }
132
133fn foo() {
134 m!(match E::X { a$0 })
135}
136"#,
137 expect![[r#"
138 ev E::X ()
139 en E
140 ma m!(…) macro_rules! m
141 "#]],
142 );
143 }
144
145 #[test]
146 fn completes_in_irrefutable_let() {
147 check(
148 r#"
149enum E { X }
150use self::E::X;
151const Z: E = E::X;
152mod m {}
153
154static FOO: E = E::X;
155struct Bar { f: u32 }
156
157fn foo() {
158 let a$0
159}
160"#,
161 expect![[r#"
162 st Bar
163 "#]],
164 );
165 }
166
167 #[test]
168 fn completes_in_param() {
169 check(
170 r#"
171enum E { X }
172
173static FOO: E = E::X;
174struct Bar { f: u32 }
175
176fn foo(a$0) {
177}
178"#,
179 expect![[r#"
180 st Bar
181 "#]],
182 );
183 }
184
185 #[test]
186 fn completes_pat_in_let() {
187 check_snippet(
188 r#"
189struct Bar { f: u32 }
190
191fn foo() {
192 let a$0
193}
194"#,
195 expect![[r#"
196 bn Bar Bar { f$1 }$0
197 "#]],
198 );
199 }
200
201 #[test]
202 fn completes_param_pattern() {
203 check_snippet(
204 r#"
205struct Foo { bar: String, baz: String }
206struct Bar(String, String);
207struct Baz;
208fn outer(a$0) {}
209"#,
210 expect![[r#"
211 bn Foo Foo { bar$1, baz$2 }: Foo$0
212 bn Bar Bar($1, $2): Bar$0
213 "#]],
214 )
215 }
216
217 #[test]
218 fn completes_let_pattern() {
219 check_snippet(
220 r#"
221struct Foo { bar: String, baz: String }
222struct Bar(String, String);
223struct Baz;
224fn outer() {
225 let a$0
226}
227"#,
228 expect![[r#"
229 bn Foo Foo { bar$1, baz$2 }$0
230 bn Bar Bar($1, $2)$0
231 "#]],
232 )
233 }
234
235 #[test]
236 fn completes_refutable_pattern() {
237 check_snippet(
238 r#"
239struct Foo { bar: i32, baz: i32 }
240struct Bar(String, String);
241struct Baz;
242fn outer() {
243 match () {
244 a$0
245 }
246}
247"#,
248 expect![[r#"
249 bn Foo Foo { bar$1, baz$2 }$0
250 bn Bar Bar($1, $2)$0
251 "#]],
252 )
253 }
254
255 #[test]
256 fn omits_private_fields_pat() {
257 check_snippet(
258 r#"
259mod foo {
260 pub struct Foo { pub bar: i32, baz: i32 }
261 pub struct Bar(pub String, String);
262 pub struct Invisible(String, String);
263}
264use foo::*;
265
266fn outer() {
267 match () {
268 a$0
269 }
270}
271"#,
272 expect![[r#"
273 bn Foo Foo { bar$1, .. }$0
274 bn Bar Bar($1, ..)$0
275 "#]],
276 )
277 }
278
279 #[test]
280 fn only_shows_ident_completion() {
281 check_edit(
282 "Foo",
283 r#"
284struct Foo(i32);
285fn main() {
286 match Foo(92) {
287 a$0(92) => (),
288 }
289}
290"#,
291 r#"
292struct Foo(i32);
293fn main() {
294 match Foo(92) {
295 Foo(92) => (),
296 }
297}
298"#,
299 );
300 }
301
302 #[test]
303 fn completes_self_pats() {
304 check_snippet(
305 r#"
306struct Foo(i32);
307impl Foo {
308 fn foo() {
309 match () {
310 a$0
311 }
312 }
313}
314 "#,
315 expect![[r#"
316 bn Self Self($1)$0
317 bn Foo Foo($1)$0
318 "#]],
319 )
320 }
321
322 #[test]
323 fn completes_qualified_variant() {
324 check_snippet(
325 r#"
326enum Foo {
327 Bar { baz: i32 }
328}
329impl Foo {
330 fn foo() {
331 match {Foo::Bar { baz: 0 }} {
332 B$0
333 }
334 }
335}
336 "#,
337 expect![[r#"
338 bn Self::Bar Self::Bar { baz$1 }$0
339 bn Foo::Bar Foo::Bar { baz$1 }$0
340 "#]],
341 )
342 }
343
344 #[test]
345 fn completes_enum_variant_matcharm() {
346 check(
347 r#"
348enum Foo { Bar, Baz, Quux }
349
350fn main() {
351 let foo = Foo::Quux;
352 match foo { Qu$0 }
353}
354"#,
355 expect![[r#"
356 ev Foo::Bar ()
357 ev Foo::Baz ()
358 ev Foo::Quux ()
359 en Foo
360 "#]],
361 )
362 }
363
364 #[test]
365 fn completes_enum_variant_matcharm_ref() {
366 check(
367 r#"
368enum Foo { Bar, Baz, Quux }
369
370fn main() {
371 let foo = Foo::Quux;
372 match &foo { Qu$0 }
373}
374"#,
375 expect![[r#"
376 ev Foo::Bar ()
377 ev Foo::Baz ()
378 ev Foo::Quux ()
379 en Foo
380 "#]],
381 )
382 }
383
384 #[test]
385 fn completes_enum_variant_iflet() {
386 check(
387 r#"
388enum Foo { Bar, Baz, Quux }
389
390fn main() {
391 let foo = Foo::Quux;
392 if let Qu$0 = foo { }
393}
394"#,
395 expect![[r#"
396 ev Foo::Bar ()
397 ev Foo::Baz ()
398 ev Foo::Quux ()
399 en Foo
400 "#]],
401 )
402 }
403
404 #[test]
405 fn completes_enum_variant_impl() {
406 check(
407 r#"
408enum Foo { Bar, Baz, Quux }
409impl Foo {
410 fn foo() { match Foo::Bar { Q$0 } }
411}
412"#,
413 expect![[r#"
414 ev Self::Bar ()
415 ev Self::Baz ()
416 ev Self::Quux ()
417 ev Foo::Bar ()
418 ev Foo::Baz ()
419 ev Foo::Quux ()
420 sp Self
421 en Foo
422 "#]],
423 )
424 }
425
426 #[test]
427 fn completes_in_record_field_pat() {
428 check_snippet(
429 r#"
430struct Foo { bar: Bar }
431struct Bar(u32);
432fn outer(Foo { bar: $0 }: Foo) {}
433"#,
434 expect![[r#"
435 bn Foo Foo { bar$1 }$0
436 bn Bar Bar($1)$0
437 "#]],
438 )
439 }
440
441 #[test]
442 fn skips_in_record_field_pat_name() {
443 check_snippet(
444 r#"
445struct Foo { bar: Bar }
446struct Bar(u32);
447fn outer(Foo { bar$0 }: Foo) {}
448"#,
449 expect![[r#""#]],
450 )
451 }
452}
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 9f98b21be..4e20ec003 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -307,12 +307,12 @@ mod tests {
307 use expect_test::{expect, Expect}; 307 use expect_test::{expect, Expect};
308 308
309 use crate::{ 309 use crate::{
310 test_utils::{check_edit, completion_list}, 310 tests::{check_edit, filtered_completion_list},
311 CompletionKind, 311 CompletionKind,
312 }; 312 };
313 313
314 fn check(ra_fixture: &str, expect: Expect) { 314 fn check(ra_fixture: &str, expect: Expect) {
315 let actual = completion_list(ra_fixture, CompletionKind::Postfix); 315 let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix);
316 expect.assert_eq(&actual) 316 expect.assert_eq(&actual)
317 } 317 }
318 318
@@ -436,18 +436,15 @@ fn main() {
436 check_edit( 436 check_edit(
437 "ifl", 437 "ifl",
438 r#" 438 r#"
439enum Option<T> { Some(T), None } 439//- minicore: option
440
441fn main() { 440fn main() {
442 let bar = Option::Some(true); 441 let bar = Some(true);
443 bar.$0 442 bar.$0
444} 443}
445"#, 444"#,
446 r#" 445 r#"
447enum Option<T> { Some(T), None }
448
449fn main() { 446fn main() {
450 let bar = Option::Some(true); 447 let bar = Some(true);
451 if let Some($1) = bar { 448 if let Some($1) = bar {
452 $0 449 $0
453} 450}
@@ -461,18 +458,15 @@ fn main() {
461 check_edit( 458 check_edit(
462 "match", 459 "match",
463 r#" 460 r#"
464enum Result<T, E> { Ok(T), Err(E) } 461//- minicore: result
465
466fn main() { 462fn main() {
467 let bar = Result::Ok(true); 463 let bar = Ok(true);
468 bar.$0 464 bar.$0
469} 465}
470"#, 466"#,
471 r#" 467 r#"
472enum Result<T, E> { Ok(T), Err(E) }
473
474fn main() { 468fn main() {
475 let bar = Result::Ok(true); 469 let bar = Ok(true);
476 match bar { 470 match bar {
477 Ok(${1:_}) => {$2}, 471 Ok(${1:_}) => {$2},
478 Err(${3:_}) => {$0}, 472 Err(${3:_}) => {$0},
@@ -515,18 +509,15 @@ fn main() {
515 check_edit( 509 check_edit(
516 "ifl", 510 "ifl",
517 r#" 511 r#"
518enum Option<T> { Some(T), None } 512//- minicore: option
519
520fn main() { 513fn main() {
521 let bar = &Option::Some(true); 514 let bar = &Some(true);
522 bar.$0 515 bar.$0
523} 516}
524"#, 517"#,
525 r#" 518 r#"
526enum Option<T> { Some(T), None }
527
528fn main() { 519fn main() {
529 let bar = &Option::Some(true); 520 let bar = &Some(true);
530 if let Some($1) = bar { 521 if let Some($1) = bar {
531 $0 522 $0
532} 523}
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 6083537b7..1b8997ecf 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -19,6 +19,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
19 Some(res) => res, 19 Some(res) => res,
20 None => return, 20 None => return,
21 }; 21 };
22
22 let context_module = ctx.scope.module(); 23 let context_module = ctx.scope.module();
23 24
24 if ctx.expects_item() || ctx.expects_assoc_item() { 25 if ctx.expects_item() || ctx.expects_assoc_item() {
@@ -48,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
48 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { 49 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
49 let module_scope = module.scope(ctx.db, context_module); 50 let module_scope = module.scope(ctx.db, context_module);
50 for (name, def) in module_scope { 51 for (name, def) in module_scope {
51 if ctx.use_item_syntax.is_some() { 52 if ctx.in_use_tree() {
52 if let hir::ScopeDef::Unknown = def { 53 if let hir::ScopeDef::Unknown = def {
53 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 54 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
54 if name_ref.syntax().text() == name.to_string().as_str() { 55 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -60,21 +61,37 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
60 } 61 }
61 } 62 }
62 63
63 if let hir::ScopeDef::MacroDef(macro_def) = def { 64 let add_resolution = match def {
64 if !macro_def.is_fn_like() { 65 // Don't suggest attribute macros and derives.
65 // Don't suggest attribute macros and derives. 66 hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
66 continue; 67 // no values in type places
68 hir::ScopeDef::ModuleDef(
69 hir::ModuleDef::Function(_)
70 | hir::ModuleDef::Variant(_)
71 | hir::ModuleDef::Static(_),
72 )
73 | hir::ScopeDef::Local(_) => !ctx.expects_type(),
74 // unless its a constant in a generic arg list position
75 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
76 !ctx.expects_type() || ctx.expects_generic_arg()
67 } 77 }
68 } 78 _ => true,
79 };
69 80
70 acc.add_resolution(ctx, name, &def); 81 if add_resolution {
82 acc.add_resolution(ctx, name, &def);
83 }
71 } 84 }
72 } 85 }
73 hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) 86 hir::PathResolution::Def(
74 | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) 87 def
75 | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { 88 @
89 (hir::ModuleDef::Adt(_)
90 | hir::ModuleDef::TypeAlias(_)
91 | hir::ModuleDef::BuiltinType(_)),
92 ) => {
76 if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { 93 if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
77 add_enum_variants(ctx, acc, e); 94 add_enum_variants(acc, ctx, e);
78 } 95 }
79 let ty = match def { 96 let ty = match def {
80 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), 97 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
@@ -82,7 +99,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
82 let ty = a.ty(ctx.db); 99 let ty = a.ty(ctx.db);
83 if let Some(hir::Adt::Enum(e)) = ty.as_adt() { 100 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
84 cov_mark::hit!(completes_variant_through_alias); 101 cov_mark::hit!(completes_variant_through_alias);
85 add_enum_variants(ctx, acc, e); 102 add_enum_variants(acc, ctx, e);
86 } 103 }
87 ty 104 ty
88 } 105 }
@@ -107,11 +124,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
107 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 124 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
108 return None; 125 return None;
109 } 126 }
110 match item { 127 add_assoc_item(acc, ctx, item);
111 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
112 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
113 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
114 }
115 None::<()> 128 None::<()>
116 }); 129 });
117 130
@@ -133,11 +146,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
133 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 146 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
134 continue; 147 continue;
135 } 148 }
136 match item { 149 add_assoc_item(acc, ctx, item);
137 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
138 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
139 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
140 }
141 } 150 }
142 } 151 }
143 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { 152 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
@@ -149,7 +158,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
149 }; 158 };
150 159
151 if let Some(hir::Adt::Enum(e)) = ty.as_adt() { 160 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
152 add_enum_variants(ctx, acc, e); 161 add_enum_variants(acc, ctx, e);
153 } 162 }
154 163
155 let traits_in_scope = ctx.scope.traits_in_scope(); 164 let traits_in_scope = ctx.scope.traits_in_scope();
@@ -162,11 +171,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
162 // We might iterate candidates of a trait multiple times here, so deduplicate 171 // We might iterate candidates of a trait multiple times here, so deduplicate
163 // them. 172 // them.
164 if seen.insert(item) { 173 if seen.insert(item) {
165 match item { 174 add_assoc_item(acc, ctx, item);
166 hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
167 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
168 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
169 }
170 } 175 }
171 None::<()> 176 None::<()>
172 }); 177 });
@@ -176,82 +181,44 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
176 } 181 }
177} 182}
178 183
179fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { 184fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
180 for variant in e.variants(ctx.db) { 185 match item {
181 acc.add_enum_variant(ctx, variant, None); 186 hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
187 hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
188 acc.add_const(ctx, ct)
189 }
190 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
191 _ => (),
182 } 192 }
183} 193}
184 194
195fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
196 if ctx.expects_type() {
197 return;
198 }
199 e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
200}
201
185#[cfg(test)] 202#[cfg(test)]
186mod tests { 203mod tests {
187 use expect_test::{expect, Expect}; 204 use expect_test::{expect, Expect};
188 205
189 use crate::{ 206 use crate::{
190 test_utils::{check_edit, completion_list}, 207 tests::{check_edit, filtered_completion_list},
191 CompletionKind, 208 CompletionKind,
192 }; 209 };
193 210
194 fn check(ra_fixture: &str, expect: Expect) { 211 fn check(ra_fixture: &str, expect: Expect) {
195 let actual = completion_list(ra_fixture, CompletionKind::Reference); 212 let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
196 expect.assert_eq(&actual); 213 expect.assert_eq(&actual);
197 } 214 }
198 215
199 fn check_builtin(ra_fixture: &str, expect: Expect) { 216 fn check_builtin(ra_fixture: &str, expect: Expect) {
200 let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); 217 let actual = filtered_completion_list(ra_fixture, CompletionKind::BuiltinType);
201 expect.assert_eq(&actual); 218 expect.assert_eq(&actual);
202 } 219 }
203 220
204 #[test] 221 #[test]
205 fn dont_complete_current_use() {
206 cov_mark::check!(dont_complete_current_use);
207 check(r#"use self::foo$0;"#, expect![[""]]);
208 }
209
210 #[test]
211 fn dont_complete_values_in_type_pos() {
212 check(
213 r#"
214const FOO: () = ();
215static BAR: () = ();
216struct Baz;
217fn foo() {
218 let _: self::$0;
219}
220"#,
221 expect![[r#"
222 st Baz
223 "#]],
224 );
225 }
226
227 #[test]
228 fn dont_complete_enum_variants_in_type_pos() {
229 check(
230 r#"
231enum Foo { Bar }
232fn foo() {
233 let _: Foo::$0;
234}
235"#,
236 expect![[r#""#]],
237 );
238 }
239
240 #[test]
241 fn dont_complete_current_use_in_braces_with_glob() {
242 check(
243 r#"
244mod foo { pub struct S; }
245use self::{foo::*, bar$0};
246"#,
247 expect![[r#"
248 st S
249 md foo
250 "#]],
251 );
252 }
253
254 #[test]
255 fn dont_complete_primitive_in_use() { 222 fn dont_complete_primitive_in_use() {
256 check_builtin(r#"use self::$0;"#, expect![[""]]); 223 check_builtin(r#"use self::$0;"#, expect![[""]]);
257 } 224 }
@@ -262,134 +229,6 @@ use self::{foo::*, bar$0};
262 } 229 }
263 230
264 #[test] 231 #[test]
265 fn completes_primitives() {
266 check_builtin(
267 r#"fn main() { let _: $0 = 92; }"#,
268 expect![[r#"
269 bt u32
270 bt bool
271 bt u8
272 bt isize
273 bt u16
274 bt u64
275 bt u128
276 bt f32
277 bt i128
278 bt i16
279 bt str
280 bt i64
281 bt char
282 bt f64
283 bt i32
284 bt i8
285 bt usize
286 "#]],
287 );
288 }
289
290 #[test]
291 fn completes_mod_with_same_name_as_function() {
292 check(
293 r#"
294use self::my::$0;
295
296mod my { pub struct Bar; }
297fn my() {}
298"#,
299 expect![[r#"
300 st Bar
301 "#]],
302 );
303 }
304
305 #[test]
306 fn filters_visibility() {
307 check(
308 r#"
309use self::my::$0;
310
311mod my {
312 struct Bar;
313 pub struct Foo;
314 pub use Bar as PublicBar;
315}
316"#,
317 expect![[r#"
318 st Foo
319 st PublicBar
320 "#]],
321 );
322 }
323
324 #[test]
325 fn completes_use_item_starting_with_self() {
326 check(
327 r#"
328use self::m::$0;
329
330mod m { pub struct Bar; }
331"#,
332 expect![[r#"
333 st Bar
334 "#]],
335 );
336 }
337
338 #[test]
339 fn completes_use_item_starting_with_crate() {
340 check(
341 r#"
342//- /lib.rs
343mod foo;
344struct Spam;
345//- /foo.rs
346use crate::Sp$0
347"#,
348 expect![[r#"
349 md foo
350 st Spam
351 "#]],
352 );
353 }
354
355 #[test]
356 fn completes_nested_use_tree() {
357 check(
358 r#"
359//- /lib.rs
360mod foo;
361struct Spam;
362//- /foo.rs
363use crate::{Sp$0};
364"#,
365 expect![[r#"
366 md foo
367 st Spam
368 "#]],
369 );
370 }
371
372 #[test]
373 fn completes_deeply_nested_use_tree() {
374 check(
375 r#"
376//- /lib.rs
377mod foo;
378pub mod bar {
379 pub mod baz {
380 pub struct Spam;
381 }
382}
383//- /foo.rs
384use crate::{bar::{baz::Sp$0}};
385"#,
386 expect![[r#"
387 st Spam
388 "#]],
389 );
390 }
391
392 #[test]
393 fn completes_enum_variant() { 232 fn completes_enum_variant() {
394 check( 233 check(
395 r#" 234 r#"
@@ -486,22 +325,6 @@ fn foo() { let _ = U::$0 }
486 } 325 }
487 326
488 #[test] 327 #[test]
489 fn completes_use_paths_across_crates() {
490 check(
491 r#"
492//- /main.rs crate:main deps:foo
493use foo::$0;
494
495//- /foo/lib.rs crate:foo
496pub mod bar { pub struct S; }
497"#,
498 expect![[r#"
499 md bar
500 "#]],
501 );
502 }
503
504 #[test]
505 fn completes_trait_associated_method_1() { 328 fn completes_trait_associated_method_1() {
506 check( 329 check(
507 r#" 330 r#"
@@ -683,63 +506,6 @@ fn f() {m::$0}
683 } 506 }
684 507
685 #[test] 508 #[test]
686 fn completes_in_assoc_item_list() {
687 check(
688 r#"
689#[macro_export]
690macro_rules! foo { () => {} }
691mod bar {}
692
693struct MyStruct {}
694impl MyStruct {
695 crate::$0
696}
697"#,
698 expect![[r##"
699 md bar
700 ma foo!(…) #[macro_export] macro_rules! foo
701 "##]],
702 );
703 }
704
705 #[test]
706 fn completes_in_item_list() {
707 check(
708 r#"
709struct MyStruct {}
710#[macro_export]
711macro_rules! foo {}
712mod bar {}
713
714crate::$0
715"#,
716 expect![[r#"
717 md bar
718 ma foo!(…) #[macro_export] macro_rules! foo
719 "#]],
720 )
721 }
722
723 #[test]
724 fn test_super_super_completion() {
725 check(
726 r#"
727mod a {
728 const A: usize = 0;
729 mod b {
730 const B: usize = 0;
731 mod c { use super::super::$0 }
732 }
733}
734"#,
735 expect![[r#"
736 md b
737 ct A
738 "#]],
739 );
740 }
741
742 #[test]
743 fn completes_reexported_items_under_correct_name() { 509 fn completes_reexported_items_under_correct_name() {
744 check( 510 check(
745 r#" 511 r#"
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 0ac47cdbe..e876337f1 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -48,44 +48,29 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
48#[cfg(test)] 48#[cfg(test)]
49mod tests { 49mod tests {
50 use expect_test::{expect, Expect}; 50 use expect_test::{expect, Expect};
51 use ide_db::helpers::FamousDefs;
52 51
53 use crate::{ 52 use crate::{
54 test_utils::{self, completion_list}, 53 tests::{check_edit, filtered_completion_list},
55 CompletionKind, 54 CompletionKind,
56 }; 55 };
57 56
58 fn check(ra_fixture: &str, expect: Expect) { 57 fn check(ra_fixture: &str, expect: Expect) {
59 let actual = completion_list(ra_fixture, CompletionKind::Reference); 58 let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
60 expect.assert_eq(&actual); 59 expect.assert_eq(&actual);
61 } 60 }
62 61
63 fn check_snippet(ra_fixture: &str, expect: Expect) { 62 fn check_snippet(ra_fixture: &str, expect: Expect) {
64 let actual = completion_list( 63 let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet);
65 &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE),
66 CompletionKind::Snippet,
67 );
68 expect.assert_eq(&actual); 64 expect.assert_eq(&actual);
69 } 65 }
70 66
71 fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
72 test_utils::check_edit(
73 what,
74 &format!(
75 "//- /main.rs crate:main deps:core{}\n{}",
76 ra_fixture_before,
77 FamousDefs::FIXTURE,
78 ),
79 &(ra_fixture_after.to_owned() + "\n"),
80 );
81 }
82
83 #[test] 67 #[test]
84 fn test_record_literal_field_default() { 68 fn test_record_literal_field_default() {
85 let test_code = r#" 69 let test_code = r#"
70//- minicore: default
86struct S { foo: u32, bar: usize } 71struct S { foo: u32, bar: usize }
87 72
88impl core::default::Default for S { 73impl Default for S {
89 fn default() -> Self { 74 fn default() -> Self {
90 S { 75 S {
91 foo: 0, 76 foo: 0,
@@ -121,9 +106,10 @@ fn process(f: S) {
121 check_edit( 106 check_edit(
122 "..Default::default()", 107 "..Default::default()",
123 r#" 108 r#"
109//- minicore: default
124struct S { foo: u32, bar: usize } 110struct S { foo: u32, bar: usize }
125 111
126impl core::default::Default for S { 112impl Default for S {
127 fn default() -> Self { 113 fn default() -> Self {
128 S { 114 S {
129 foo: 0, 115 foo: 0,
@@ -142,7 +128,7 @@ fn process(f: S) {
142 r#" 128 r#"
143struct S { foo: u32, bar: usize } 129struct S { foo: u32, bar: usize }
144 130
145impl core::default::Default for S { 131impl Default for S {
146 fn default() -> Self { 132 fn default() -> Self {
147 S { 133 S {
148 foo: 0, 134 foo: 0,
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index b9862de67..cbc20cc2c 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -1,6 +1,7 @@
1//! This file provides snippet completions, like `pd` => `eprintln!(...)`. 1//! This file provides snippet completions, like `pd` => `eprintln!(...)`.
2 2
3use ide_db::helpers::SnippetCap; 3use ide_db::helpers::SnippetCap;
4use syntax::T;
4 5
5use crate::{ 6use crate::{
6 context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, 7 context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem,
@@ -35,9 +36,17 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte
35} 36}
36 37
37pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { 38pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
38 if !ctx.expects_item() { 39 if !ctx.expects_item()
40 || ctx.previous_token_is(T![unsafe])
41 || ctx.path_qual().is_some()
42 || ctx.has_impl_or_trait_prev_sibling()
43 {
39 return; 44 return;
40 } 45 }
46 if ctx.has_visibility_prev_sibling() {
47 return; // technically we could do some of these snippet completions if we were to put the
48 // attributes before the vis node.
49 }
41 let cap = match ctx.config.snippet_cap { 50 let cap = match ctx.config.snippet_cap {
42 Some(it) => it, 51 Some(it) => it,
43 None => return, 52 None => return,
@@ -82,10 +91,10 @@ fn ${1:feature}() {
82mod tests { 91mod tests {
83 use expect_test::{expect, Expect}; 92 use expect_test::{expect, Expect};
84 93
85 use crate::{test_utils::completion_list, CompletionKind}; 94 use crate::{tests::filtered_completion_list, CompletionKind};
86 95
87 fn check(ra_fixture: &str, expect: Expect) { 96 fn check(ra_fixture: &str, expect: Expect) {
88 let actual = completion_list(ra_fixture, CompletionKind::Snippet); 97 let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet);
89 expect.assert_eq(&actual) 98 expect.assert_eq(&actual)
90 } 99 }
91 100
@@ -105,21 +114,4 @@ mod tests {
105 check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); 114 check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]);
106 check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); 115 check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]);
107 } 116 }
108
109 #[test]
110 fn completes_snippets_in_items() {
111 check(
112 r#"
113#[cfg(test)]
114mod tests {
115 $0
116}
117"#,
118 expect![[r#"
119 sn tmod (Test module)
120 sn tfn (Test function)
121 sn macro_rules
122 "#]],
123 )
124 }
125} 117}
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index a60e5f43c..65f0f3843 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -32,7 +32,7 @@
32//! ``` 32//! ```
33 33
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::{traits::get_missing_assoc_items, SymbolKind}; 35use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit}, 37 ast::{self, edit},
38 display::function_declaration, 38 display::function_declaration,
@@ -52,24 +52,26 @@ enum ImplCompletionKind {
52 52
53pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 53pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
54 if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { 54 if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) {
55 get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { 55 if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
56 hir::AssocItem::Function(fn_item) 56 get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item {
57 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => 57 hir::AssocItem::Function(fn_item)
58 { 58 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn =>
59 add_function_impl(&trigger, acc, ctx, fn_item) 59 {
60 } 60 add_function_impl(&trigger, acc, ctx, fn_item, hir_impl)
61 hir::AssocItem::TypeAlias(type_item) 61 }
62 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => 62 hir::AssocItem::TypeAlias(type_item)
63 { 63 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias =>
64 add_type_alias_impl(&trigger, acc, ctx, type_item) 64 {
65 } 65 add_type_alias_impl(&trigger, acc, ctx, type_item)
66 hir::AssocItem::Const(const_item) 66 }
67 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => 67 hir::AssocItem::Const(const_item)
68 { 68 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const =>
69 add_const_impl(&trigger, acc, ctx, const_item) 69 {
70 } 70 add_const_impl(&trigger, acc, ctx, const_item, hir_impl)
71 _ => {} 71 }
72 }); 72 _ => {}
73 });
74 }
73 } 75 }
74} 76}
75 77
@@ -129,6 +131,7 @@ fn add_function_impl(
129 acc: &mut Completions, 131 acc: &mut Completions,
130 ctx: &CompletionContext, 132 ctx: &CompletionContext,
131 func: hir::Function, 133 func: hir::Function,
134 impl_def: hir::Impl,
132) { 135) {
133 let fn_name = func.name(ctx.db).to_string(); 136 let fn_name = func.name(ctx.db).to_string();
134 137
@@ -147,23 +150,55 @@ fn add_function_impl(
147 CompletionItemKind::SymbolKind(SymbolKind::Function) 150 CompletionItemKind::SymbolKind(SymbolKind::Function)
148 }; 151 };
149 let range = replacement_range(ctx, fn_def_node); 152 let range = replacement_range(ctx, fn_def_node);
150 if let Some(src) = func.source(ctx.db) { 153
151 let function_decl = function_declaration(&src.value); 154 if let Some(source) = func.source(ctx.db) {
152 match ctx.config.snippet_cap { 155 let assoc_item = ast::AssocItem::Fn(source.value);
153 Some(cap) => { 156 if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
154 let snippet = format!("{} {{\n $0\n}}", function_decl); 157 let transformed_fn = match transformed_item {
155 item.snippet_edit(cap, TextEdit::replace(range, snippet)); 158 ast::AssocItem::Fn(func) => func,
156 } 159 _ => unreachable!(),
157 None => { 160 };
158 let header = format!("{} {{", function_decl); 161
159 item.text_edit(TextEdit::replace(range, header)); 162 let function_decl = function_declaration(&transformed_fn);
160 } 163 match ctx.config.snippet_cap {
161 }; 164 Some(cap) => {
162 item.kind(completion_kind); 165 let snippet = format!("{} {{\n $0\n}}", function_decl);
163 item.add_to(acc); 166 item.snippet_edit(cap, TextEdit::replace(range, snippet));
167 }
168 None => {
169 let header = format!("{} {{", function_decl);
170 item.text_edit(TextEdit::replace(range, header));
171 }
172 };
173 item.kind(completion_kind);
174 item.add_to(acc);
175 }
164 } 176 }
165} 177}
166 178
179/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
180fn get_transformed_assoc_item(
181 ctx: &CompletionContext,
182 assoc_item: ast::AssocItem,
183 impl_def: hir::Impl,
184) -> Option<ast::AssocItem> {
185 let assoc_item = assoc_item.clone_for_update();
186 let trait_ = impl_def.trait_(ctx.db)?;
187 let source_scope = &ctx.sema.scope_for_def(trait_);
188 let target_scope = &ctx.sema.scope(impl_def.source(ctx.db)?.syntax().value);
189 let transform = PathTransform {
190 subst: (trait_, impl_def.source(ctx.db)?.value),
191 source_scope,
192 target_scope,
193 };
194
195 transform.apply(assoc_item.clone());
196 Some(match assoc_item {
197 ast::AssocItem::Fn(func) => ast::AssocItem::Fn(edit::remove_attrs_and_docs(&func)),
198 _ => assoc_item,
199 })
200}
201
167fn add_type_alias_impl( 202fn add_type_alias_impl(
168 type_def_node: &SyntaxNode, 203 type_def_node: &SyntaxNode,
169 acc: &mut Completions, 204 acc: &mut Completions,
@@ -188,21 +223,30 @@ fn add_const_impl(
188 acc: &mut Completions, 223 acc: &mut Completions,
189 ctx: &CompletionContext, 224 ctx: &CompletionContext,
190 const_: hir::Const, 225 const_: hir::Const,
226 impl_def: hir::Impl,
191) { 227) {
192 let const_name = const_.name(ctx.db).map(|n| n.to_string()); 228 let const_name = const_.name(ctx.db).map(|n| n.to_string());
193 229
194 if let Some(const_name) = const_name { 230 if let Some(const_name) = const_name {
195 if let Some(source) = const_.source(ctx.db) { 231 if let Some(source) = const_.source(ctx.db) {
196 let snippet = make_const_compl_syntax(&source.value); 232 let assoc_item = ast::AssocItem::Const(source.value);
197 233 if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
198 let range = replacement_range(ctx, const_def_node); 234 let transformed_const = match transformed_item {
199 let mut item = 235 ast::AssocItem::Const(const_) => const_,
200 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); 236 _ => unreachable!(),
201 item.text_edit(TextEdit::replace(range, snippet)) 237 };
202 .lookup_by(const_name) 238
203 .kind(SymbolKind::Const) 239 let snippet = make_const_compl_syntax(&transformed_const);
204 .set_documentation(const_.docs(ctx.db)); 240
205 item.add_to(acc); 241 let range = replacement_range(ctx, const_def_node);
242 let mut item =
243 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
244 item.text_edit(TextEdit::replace(range, snippet))
245 .lookup_by(const_name)
246 .kind(SymbolKind::Const)
247 .set_documentation(const_.docs(ctx.db));
248 item.add_to(acc);
249 }
206 } 250 }
207 } 251 }
208} 252}
@@ -246,12 +290,12 @@ mod tests {
246 use expect_test::{expect, Expect}; 290 use expect_test::{expect, Expect};
247 291
248 use crate::{ 292 use crate::{
249 test_utils::{check_edit, completion_list}, 293 tests::{check_edit, filtered_completion_list},
250 CompletionKind, 294 CompletionKind,
251 }; 295 };
252 296
253 fn check(ra_fixture: &str, expect: Expect) { 297 fn check(ra_fixture: &str, expect: Expect) {
254 let actual = completion_list(ra_fixture, CompletionKind::Magic); 298 let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic);
255 expect.assert_eq(&actual) 299 expect.assert_eq(&actual)
256 } 300 }
257 301
@@ -779,4 +823,183 @@ impl Foo for T {{
779 test("Type", "type T$0", "type Type = "); 823 test("Type", "type T$0", "type Type = ");
780 test("CONST", "const C$0", "const CONST: i32 = "); 824 test("CONST", "const C$0", "const CONST: i32 = ");
781 } 825 }
826
827 #[test]
828 fn generics_are_inlined_in_return_type() {
829 check_edit(
830 "function",
831 r#"
832trait Foo<T> {
833 fn function() -> T;
834}
835struct Bar;
836
837impl Foo<u32> for Bar {
838 fn f$0
839}
840"#,
841 r#"
842trait Foo<T> {
843 fn function() -> T;
844}
845struct Bar;
846
847impl Foo<u32> for Bar {
848 fn function() -> u32 {
849 $0
850}
851}
852"#,
853 )
854 }
855
856 #[test]
857 fn generics_are_inlined_in_parameter() {
858 check_edit(
859 "function",
860 r#"
861trait Foo<T> {
862 fn function(bar: T);
863}
864struct Bar;
865
866impl Foo<u32> for Bar {
867 fn f$0
868}
869"#,
870 r#"
871trait Foo<T> {
872 fn function(bar: T);
873}
874struct Bar;
875
876impl Foo<u32> for Bar {
877 fn function(bar: u32) {
878 $0
879}
880}
881"#,
882 )
883 }
884
885 #[test]
886 fn generics_are_inlined_when_part_of_other_types() {
887 check_edit(
888 "function",
889 r#"
890trait Foo<T> {
891 fn function(bar: Vec<T>);
892}
893struct Bar;
894
895impl Foo<u32> for Bar {
896 fn f$0
897}
898"#,
899 r#"
900trait Foo<T> {
901 fn function(bar: Vec<T>);
902}
903struct Bar;
904
905impl Foo<u32> for Bar {
906 fn function(bar: Vec<u32>) {
907 $0
908}
909}
910"#,
911 )
912 }
913
914 #[test]
915 fn generics_are_inlined_complex() {
916 check_edit(
917 "function",
918 r#"
919trait Foo<T, U, V> {
920 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
921}
922struct Bar;
923
924impl Foo<u32, Vec<usize>, u8> for Bar {
925 fn f$0
926}
927"#,
928 r#"
929trait Foo<T, U, V> {
930 fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
931}
932struct Bar;
933
934impl Foo<u32, Vec<usize>, u8> for Bar {
935 fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> {
936 $0
937}
938}
939"#,
940 )
941 }
942
943 #[test]
944 fn generics_are_inlined_in_associated_const() {
945 check_edit(
946 "BAR",
947 r#"
948trait Foo<T> {
949 const BAR: T;
950}
951struct Bar;
952
953impl Foo<u32> for Bar {
954 const B$0;
955}
956"#,
957 r#"
958trait Foo<T> {
959 const BAR: T;
960}
961struct Bar;
962
963impl Foo<u32> for Bar {
964 const BAR: u32 = ;
965}
966"#,
967 )
968 }
969
970 #[test]
971 fn generics_are_inlined_in_where_clause() {
972 check_edit(
973 "function",
974 r#"
975trait SomeTrait<T> {}
976
977trait Foo<T> {
978 fn function()
979 where Self: SomeTrait<T>;
980}
981struct Bar;
982
983impl Foo<u32> for Bar {
984 fn f$0
985}
986"#,
987 r#"
988trait SomeTrait<T> {}
989
990trait Foo<T> {
991 fn function()
992 where Self: SomeTrait<T>;
993}
994struct Bar;
995
996impl Foo<u32> for Bar {
997 fn function()
998where Self: SomeTrait<u32> {
999 $0
1000}
1001}
1002"#,
1003 )
1004 }
782} 1005}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 952f052a1..380c1e079 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -6,7 +6,7 @@ use syntax::{ast, AstNode};
6use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; 6use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
7 7
8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
9 if ctx.is_path_disallowed() || !ctx.is_trivial_path() { 9 if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() {
10 return; 10 return;
11 } 11 }
12 12
@@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
25 return; 25 return;
26 } 26 }
27 27
28 if ctx.expects_use_tree() { 28 if ctx.in_use_tree() {
29 // only show modules in a fresh UseTree 29 // only show modules in a fresh UseTree
30 cov_mark::hit!(only_completes_modules_in_import); 30 cov_mark::hit!(only_completes_modules_in_import);
31 ctx.scope.process_all_names(&mut |name, res| { 31 ctx.scope.process_all_names(&mut |name, res| {
@@ -36,12 +36,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
36 return; 36 return;
37 } 37 }
38 38
39 if let Some(hir::Adt::Enum(e)) = 39 if !ctx.expects_type() {
40 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) 40 if let Some(hir::Adt::Enum(e)) =
41 { 41 ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
42 super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { 42 {
43 acc.add_qualified_enum_variant(ctx, variant, path) 43 super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
44 }); 44 acc.add_qualified_enum_variant(ctx, variant, path)
45 });
46 }
45 } 47 }
46 48
47 if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { 49 if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
@@ -59,12 +61,30 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
59 } 61 }
60 62
61 ctx.scope.process_all_names(&mut |name, res| { 63 ctx.scope.process_all_names(&mut |name, res| {
62 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 64 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) =
65 res
66 {
63 cov_mark::hit!(skip_lifetime_completion); 67 cov_mark::hit!(skip_lifetime_completion);
64 return; 68 return;
65 } 69 }
66 let add_resolution = match res { 70 let add_resolution = match res {
71 ScopeDef::ImplSelfType(_) => {
72 !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
73 }
74 // Don't suggest attribute macros and derives.
67 ScopeDef::MacroDef(mac) => mac.is_fn_like(), 75 ScopeDef::MacroDef(mac) => mac.is_fn_like(),
76 // no values in type places
77 ScopeDef::ModuleDef(
78 hir::ModuleDef::Function(_)
79 | hir::ModuleDef::Variant(_)
80 | hir::ModuleDef::Static(_),
81 )
82 | ScopeDef::Local(_) => !ctx.expects_type(),
83 // unless its a constant in a generic arg list position
84 ScopeDef::ModuleDef(hir::ModuleDef::Const(_))
85 | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => {
86 !ctx.expects_type() || ctx.expects_generic_arg()
87 }
68 _ => true, 88 _ => true,
69 }; 89 };
70 if add_resolution { 90 if add_resolution {
@@ -78,7 +98,7 @@ mod tests {
78 use expect_test::{expect, Expect}; 98 use expect_test::{expect, Expect};
79 99
80 use crate::{ 100 use crate::{
81 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, 101 tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG},
82 CompletionConfig, CompletionKind, 102 CompletionConfig, CompletionKind,
83 }; 103 };
84 104
@@ -87,99 +107,12 @@ mod tests {
87 } 107 }
88 108
89 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { 109 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
90 let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); 110 let actual =
111 filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
91 expect.assert_eq(&actual) 112 expect.assert_eq(&actual)
92 } 113 }
93 114
94 #[test] 115 #[test]
95 fn dont_complete_values_in_type_pos() {
96 check(
97 r#"
98const FOO: () = ();
99static BAR: () = ();
100enum Foo {
101 Bar
102}
103struct Baz;
104fn foo() {
105 let local = ();
106 let _: $0;
107}
108"#,
109 expect![[r#"
110 en Foo
111 st Baz
112 "#]],
113 );
114 }
115
116 #[test]
117 fn only_completes_modules_in_import() {
118 cov_mark::check!(only_completes_modules_in_import);
119 check(
120 r#"
121use f$0
122
123struct Foo;
124mod foo {}
125"#,
126 expect![[r#"
127 md foo
128 "#]],
129 );
130 }
131
132 #[test]
133 fn bind_pat_and_path_ignore_at() {
134 check(
135 r#"
136enum Enum { A, B }
137fn quux(x: Option<Enum>) {
138 match x {
139 None => (),
140 Some(en$0 @ Enum::A) => (),
141 }
142}
143"#,
144 expect![[r#""#]],
145 );
146 }
147
148 #[test]
149 fn bind_pat_and_path_ignore_ref() {
150 check(
151 r#"
152enum Enum { A, B }
153fn quux(x: Option<Enum>) {
154 match x {
155 None => (),
156 Some(ref en$0) => (),
157 }
158}
159"#,
160 expect![[r#""#]],
161 );
162 }
163
164 #[test]
165 fn bind_pat_and_path() {
166 check(
167 r#"
168enum Enum { A, B }
169fn quux(x: Option<Enum>) {
170 match x {
171 None => (),
172 Some(En$0) => (),
173 }
174}
175"#,
176 expect![[r#"
177 en Enum
178 "#]],
179 );
180 }
181
182 #[test]
183 fn completes_bindings_from_let() { 116 fn completes_bindings_from_let() {
184 check( 117 check(
185 r#" 118 r#"
@@ -284,29 +217,6 @@ fn main() {
284 } 217 }
285 218
286 #[test] 219 #[test]
287 fn completes_generic_params_in_struct() {
288 check(
289 r#"struct S<T> { x: $0}"#,
290 expect![[r#"
291 sp Self
292 tp T
293 st S<…>
294 "#]],
295 );
296 }
297
298 #[test]
299 fn completes_self_in_enum() {
300 check(
301 r#"enum X { Y($0) }"#,
302 expect![[r#"
303 sp Self
304 en X
305 "#]],
306 );
307 }
308
309 #[test]
310 fn completes_module_items() { 220 fn completes_module_items() {
311 check( 221 check(
312 r#" 222 r#"
@@ -343,22 +253,6 @@ fn _alpha() {}
343 } 253 }
344 254
345 #[test] 255 #[test]
346 fn completes_extern_prelude() {
347 check(
348 r#"
349//- /lib.rs crate:main deps:other_crate
350use $0;
351
352//- /other_crate/lib.rs crate:other_crate
353// nothing here
354"#,
355 expect![[r#"
356 md other_crate
357 "#]],
358 );
359 }
360
361 #[test]
362 fn completes_module_items_in_nested_modules() { 256 fn completes_module_items_in_nested_modules() {
363 check( 257 check(
364 r#" 258 r#"
@@ -376,19 +270,6 @@ mod m {
376 } 270 }
377 271
378 #[test] 272 #[test]
379 fn completes_return_type() {
380 check(
381 r#"
382struct Foo;
383fn x() -> $0
384"#,
385 expect![[r#"
386 st Foo
387 "#]],
388 );
389 }
390
391 #[test]
392 fn dont_show_both_completions_for_shadowing() { 273 fn dont_show_both_completions_for_shadowing() {
393 check( 274 check(
394 r#" 275 r#"
@@ -485,18 +366,6 @@ fn f() {$0}
485 check( 366 check(
486 r#" 367 r#"
487#[rustc_builtin_macro] 368#[rustc_builtin_macro]
488pub macro Clone {}
489
490struct S;
491impl S {
492 $0
493}
494"#,
495 expect![[r#""#]],
496 );
497 check(
498 r#"
499#[rustc_builtin_macro]
500pub macro bench {} 369pub macro bench {}
501 370
502fn f() {$0} 371fn f() {$0}
@@ -582,19 +451,6 @@ fn foo() { $0 }
582 } 451 }
583 452
584 #[test] 453 #[test]
585 fn completes_macros_as_type() {
586 check(
587 r#"
588macro_rules! foo { () => {} }
589fn main() { let x: $0 }
590"#,
591 expect![[r#"
592 ma foo!(…) macro_rules! foo
593 "#]],
594 );
595 }
596
597 #[test]
598 fn completes_macros_as_stmt() { 454 fn completes_macros_as_stmt() {
599 check( 455 check(
600 r#" 456 r#"
@@ -739,74 +595,4 @@ fn f() {}
739 expect![[""]], 595 expect![[""]],
740 ) 596 )
741 } 597 }
742
743 #[test]
744 fn completes_target_type_or_trait_in_impl_block() {
745 check(
746 r#"
747trait MyTrait {}
748struct MyStruct {}
749
750impl My$0
751"#,
752 expect![[r#"
753 sp Self
754 tt MyTrait
755 st MyStruct
756 "#]],
757 )
758 }
759
760 #[test]
761 fn completes_in_assoc_item_list() {
762 check(
763 r#"
764macro_rules! foo {}
765mod bar {}
766
767struct MyStruct {}
768impl MyStruct {
769 $0
770}
771"#,
772 expect![[r#"
773 md bar
774 ma foo!(…) macro_rules! foo
775 "#]],
776 )
777 }
778
779 #[test]
780 fn completes_in_item_list() {
781 check(
782 r#"
783struct MyStruct {}
784macro_rules! foo {}
785mod bar {}
786
787$0
788"#,
789 expect![[r#"
790 md bar
791 ma foo!(…) macro_rules! foo
792 "#]],
793 )
794 }
795
796 #[test]
797 fn completes_assoc_types_in_dynimpl_trait() {
798 check(
799 r#"
800trait Foo {
801 type Bar;
802}
803
804fn foo(_: impl Foo<B$0>) {}
805"#,
806 expect![[r#"
807 ta Bar = type Bar;
808 tt Foo
809 "#]],
810 );
811 }
812} 598}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 4c3929a26..f0da98739 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext {
43 pub(super) is_trivial_path: bool, 43 pub(super) is_trivial_path: bool,
44 /// If not a trivial path, the prefix (qualifier). 44 /// If not a trivial path, the prefix (qualifier).
45 pub(super) qualifier: Option<ast::Path>, 45 pub(super) qualifier: Option<ast::Path>,
46 /// Whether the qualifier comes from a use tree parent or not
47 pub(super) use_tree_parent: bool,
46 pub(super) kind: Option<PathKind>, 48 pub(super) kind: Option<PathKind>,
47 /// Whether the path segment has type args or not. 49 /// Whether the path segment has type args or not.
48 pub(super) has_type_args: bool, 50 pub(super) has_type_args: bool,
@@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> {
79 /// The parent impl of the cursor position if it exists. 81 /// The parent impl of the cursor position if it exists.
80 pub(super) impl_def: Option<ast::Impl>, 82 pub(super) impl_def: Option<ast::Impl>,
81 pub(super) name_ref_syntax: Option<ast::NameRef>, 83 pub(super) name_ref_syntax: Option<ast::NameRef>,
82 pub(super) use_item_syntax: Option<ast::Use>,
83 84
84 // potentially set if we are completing a lifetime 85 // potentially set if we are completing a lifetime
85 pub(super) lifetime_syntax: Option<ast::Lifetime>, 86 pub(super) lifetime_syntax: Option<ast::Lifetime>,
@@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> {
151 function_def: None, 152 function_def: None,
152 impl_def: None, 153 impl_def: None,
153 name_ref_syntax: None, 154 name_ref_syntax: None,
154 use_item_syntax: None,
155 lifetime_syntax: None, 155 lifetime_syntax: None,
156 lifetime_param_syntax: None, 156 lifetime_param_syntax: None,
157 lifetime_allowed: false, 157 lifetime_allowed: false,
@@ -242,32 +242,27 @@ impl<'a> CompletionContext<'a> {
242 } 242 }
243 243
244 pub(crate) fn expects_assoc_item(&self) -> bool { 244 pub(crate) fn expects_assoc_item(&self) -> bool {
245 matches!( 245 matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl))
246 self.completion_location,
247 Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl)
248 )
249 } 246 }
250 247
251 pub(crate) fn has_dot_receiver(&self) -> bool { 248 pub(crate) fn has_dot_receiver(&self) -> bool {
252 matches!( 249 matches!(
253 &self.completion_location, 250 &self.completion_location,
254 Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver,.. }) 251 Some(ImmediateLocation::FieldAccess { receiver, .. } | ImmediateLocation::MethodCall { receiver,.. })
255 if receiver.is_some() 252 if receiver.is_some()
256 ) 253 )
257 } 254 }
258 255
259 pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { 256 pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
260 match &self.completion_location { 257 match &self.completion_location {
261 Some(ImmediateLocation::MethodCall { receiver, .. }) 258 Some(
262 | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), 259 ImmediateLocation::MethodCall { receiver, .. }
260 | ImmediateLocation::FieldAccess { receiver, .. },
261 ) => receiver.as_ref(),
263 _ => None, 262 _ => None,
264 } 263 }
265 } 264 }
266 265
267 pub(crate) fn expects_use_tree(&self) -> bool {
268 matches!(self.completion_location, Some(ImmediateLocation::Use))
269 }
270
271 pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { 266 pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
272 matches!(self.completion_location, Some(ImmediateLocation::Impl)) 267 matches!(self.completion_location, Some(ImmediateLocation::Impl))
273 } 268 }
@@ -276,6 +271,10 @@ impl<'a> CompletionContext<'a> {
276 matches!(self.completion_location, Some(ImmediateLocation::ItemList)) 271 matches!(self.completion_location, Some(ImmediateLocation::ItemList))
277 } 272 }
278 273
274 pub(crate) fn expects_generic_arg(&self) -> bool {
275 matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_)))
276 }
277
279 pub(crate) fn has_block_expr_parent(&self) -> bool { 278 pub(crate) fn has_block_expr_parent(&self) -> bool {
280 matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) 279 matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
281 } 280 }
@@ -283,33 +282,59 @@ impl<'a> CompletionContext<'a> {
283 pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { 282 pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool {
284 matches!( 283 matches!(
285 self.completion_location, 284 self.completion_location,
286 Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefExpr) 285 Some(ImmediateLocation::IdentPat | ImmediateLocation::RefExpr)
287 ) 286 )
288 } 287 }
289 288
290 pub(crate) fn expect_record_field(&self) -> bool { 289 pub(crate) fn expect_field(&self) -> bool {
291 matches!(self.completion_location, Some(ImmediateLocation::RecordField)) 290 matches!(
291 self.completion_location,
292 Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField)
293 )
294 }
295
296 pub(crate) fn in_use_tree(&self) -> bool {
297 matches!(
298 self.completion_location,
299 Some(ImmediateLocation::Use | ImmediateLocation::UseTree)
300 )
292 } 301 }
293 302
294 pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { 303 pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
295 matches!( 304 matches!(
296 self.prev_sibling, 305 self.prev_sibling,
297 Some(ImmediatePrevSibling::ImplDefType) | Some(ImmediatePrevSibling::TraitDefName) 306 Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName)
298 ) 307 )
299 } 308 }
300 309
310 pub(crate) fn has_impl_prev_sibling(&self) -> bool {
311 matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType))
312 }
313
314 pub(crate) fn has_visibility_prev_sibling(&self) -> bool {
315 matches!(self.prev_sibling, Some(ImmediatePrevSibling::Visibility))
316 }
317
301 pub(crate) fn after_if(&self) -> bool { 318 pub(crate) fn after_if(&self) -> bool {
302 matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) 319 matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr))
303 } 320 }
304 321
305 pub(crate) fn is_path_disallowed(&self) -> bool { 322 pub(crate) fn is_path_disallowed(&self) -> bool {
306 matches!( 323 self.attribute_under_caret.is_some()
307 self.completion_location, 324 || self.previous_token_is(T![unsafe])
308 Some(ImmediateLocation::Attribute(_)) 325 || matches!(
309 | Some(ImmediateLocation::ModDeclaration(_)) 326 self.prev_sibling,
310 | Some(ImmediateLocation::RecordPat(_)) 327 Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility)
311 | Some(ImmediateLocation::RecordExpr(_)) 328 )
312 ) || self.attribute_under_caret.is_some() 329 || matches!(
330 self.completion_location,
331 Some(
332 ImmediateLocation::Attribute(_)
333 | ImmediateLocation::ModDeclaration(_)
334 | ImmediateLocation::RecordPat(_)
335 | ImmediateLocation::RecordExpr(_)
336 )
337 )
313 } 338 }
314 339
315 pub(crate) fn expects_expression(&self) -> bool { 340 pub(crate) fn expects_expression(&self) -> bool {
@@ -363,14 +388,19 @@ impl<'a> CompletionContext<'a> {
363 (ty, name) 388 (ty, name)
364 }, 389 },
365 ast::ArgList(_it) => { 390 ast::ArgList(_it) => {
366 cov_mark::hit!(expected_type_fn_param_with_leading_char); 391 cov_mark::hit!(expected_type_fn_param);
367 cov_mark::hit!(expected_type_fn_param_without_leading_char);
368 ActiveParameter::at_token( 392 ActiveParameter::at_token(
369 &self.sema, 393 &self.sema,
370 self.token.clone(), 394 self.token.clone(),
371 ).map(|ap| { 395 ).map(|ap| {
372 let name = ap.ident().map(NameOrNameRef::Name); 396 let name = ap.ident().map(NameOrNameRef::Name);
373 (Some(ap.ty), name) 397 let ty = if has_ref(&self.token) {
398 cov_mark::hit!(expected_type_fn_param_ref);
399 ap.ty.remove_ref()
400 } else {
401 Some(ap.ty)
402 };
403 (ty, name)
374 }) 404 })
375 .unwrap_or((None, None)) 405 .unwrap_or((None, None))
376 }, 406 },
@@ -564,9 +594,6 @@ impl<'a> CompletionContext<'a> {
564 self.name_ref_syntax = 594 self.name_ref_syntax =
565 find_node_at_offset(original_file, name_ref.syntax().text_range().start()); 595 find_node_at_offset(original_file, name_ref.syntax().text_range().start());
566 596
567 self.use_item_syntax =
568 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
569
570 self.function_def = self 597 self.function_def = self
571 .sema 598 .sema
572 .token_ancestors_with_macros(self.token.clone()) 599 .token_ancestors_with_macros(self.token.clone())
@@ -586,6 +613,7 @@ impl<'a> CompletionContext<'a> {
586 has_type_args: false, 613 has_type_args: false,
587 can_be_stmt: false, 614 can_be_stmt: false,
588 in_loop_body: false, 615 in_loop_body: false,
616 use_tree_parent: false,
589 kind: None, 617 kind: None,
590 }); 618 });
591 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); 619 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
@@ -613,7 +641,8 @@ impl<'a> CompletionContext<'a> {
613 } 641 }
614 path_ctx.has_type_args = segment.generic_arg_list().is_some(); 642 path_ctx.has_type_args = segment.generic_arg_list().is_some();
615 643
616 if let Some(path) = path_or_use_tree_qualifier(&path) { 644 if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
645 path_ctx.use_tree_parent = use_tree_parent;
617 path_ctx.qualifier = path 646 path_ctx.qualifier = path
618 .segment() 647 .segment()
619 .and_then(|it| { 648 .and_then(|it| {
@@ -667,13 +696,26 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
667 } 696 }
668} 697}
669 698
670fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { 699fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
671 if let Some(qual) = path.qualifier() { 700 if let Some(qual) = path.qualifier() {
672 return Some(qual); 701 return Some((qual, false));
673 } 702 }
674 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; 703 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
675 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; 704 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
676 use_tree.path() 705 use_tree.path().zip(Some(true))
706}
707
708fn has_ref(token: &SyntaxToken) -> bool {
709 let mut token = token.clone();
710 for skip in [WHITESPACE, IDENT, T![mut]] {
711 if token.kind() == skip {
712 token = match token.prev_token() {
713 Some(it) => it,
714 None => return false,
715 }
716 }
717 }
718 token.kind() == T![&]
677} 719}
678 720
679#[cfg(test)] 721#[cfg(test)]
@@ -681,7 +723,7 @@ mod tests {
681 use expect_test::{expect, Expect}; 723 use expect_test::{expect, Expect};
682 use hir::HirDisplay; 724 use hir::HirDisplay;
683 725
684 use crate::test_utils::{position, TEST_CONFIG}; 726 use crate::tests::{position, TEST_CONFIG};
685 727
686 use super::CompletionContext; 728 use super::CompletionContext;
687 729
@@ -748,14 +790,18 @@ fn foo() {
748 } 790 }
749 791
750 #[test] 792 #[test]
751 fn expected_type_fn_param_without_leading_char() { 793 fn expected_type_fn_param() {
752 cov_mark::check!(expected_type_fn_param_without_leading_char); 794 cov_mark::check!(expected_type_fn_param);
753 check_expected_type_and_name( 795 check_expected_type_and_name(
754 r#" 796 r#"
755fn foo() { 797fn foo() { bar($0); }
756 bar($0); 798fn bar(x: u32) {}
757} 799"#,
758 800 expect![[r#"ty: u32, name: x"#]],
801 );
802 check_expected_type_and_name(
803 r#"
804fn foo() { bar(c$0); }
759fn bar(x: u32) {} 805fn bar(x: u32) {}
760"#, 806"#,
761 expect![[r#"ty: u32, name: x"#]], 807 expect![[r#"ty: u32, name: x"#]],
@@ -763,18 +809,29 @@ fn bar(x: u32) {}
763 } 809 }
764 810
765 #[test] 811 #[test]
766 fn expected_type_fn_param_with_leading_char() { 812 fn expected_type_fn_param_ref() {
767 cov_mark::check!(expected_type_fn_param_with_leading_char); 813 cov_mark::check!(expected_type_fn_param_ref);
768 check_expected_type_and_name( 814 check_expected_type_and_name(
769 r#" 815 r#"
770fn foo() { 816fn foo() { bar(&$0); }
771 bar(c$0); 817fn bar(x: &u32) {}
772} 818"#,
773 819 expect![[r#"ty: u32, name: x"#]],
774fn bar(x: u32) {} 820 );
821 check_expected_type_and_name(
822 r#"
823fn foo() { bar(&mut $0); }
824fn bar(x: &mut u32) {}
775"#, 825"#,
776 expect![[r#"ty: u32, name: x"#]], 826 expect![[r#"ty: u32, name: x"#]],
777 ); 827 );
828 check_expected_type_and_name(
829 r#"
830fn foo() { bar(&c$0); }
831fn bar(x: &u32) {}
832 "#,
833 expect![[r#"ty: u32, name: x"#]],
834 );
778 } 835 }
779 836
780 #[test] 837 #[test]
@@ -921,13 +978,12 @@ fn foo() -> u32 {
921 // FIXME: make this work with `|| $0` 978 // FIXME: make this work with `|| $0`
922 check_expected_type_and_name( 979 check_expected_type_and_name(
923 r#" 980 r#"
981//- minicore: fn
924fn foo() { 982fn foo() {
925 bar(|| a$0); 983 bar(|| a$0);
926} 984}
927 985
928fn bar(f: impl FnOnce() -> u32) {} 986fn bar(f: impl FnOnce() -> u32) {}
929#[lang = "fn_once"]
930trait FnOnce { type Output; }
931"#, 987"#,
932 expect![[r#"ty: u32, name: ?"#]], 988 expect![[r#"ty: u32, name: ?"#]],
933 ); 989 );
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 99edb9499..ae63d132e 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -378,7 +378,7 @@ impl ImportEdit {
378 let _p = profile::span("ImportEdit::to_text_edit"); 378 let _p = profile::span("ImportEdit::to_text_edit");
379 379
380 let new_ast = self.scope.clone_for_update(); 380 let new_ast = self.scope.clone_for_update();
381 insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg); 381 insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg);
382 let mut import_insert = TextEdit::builder(); 382 let mut import_insert = TextEdit::builder();
383 algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) 383 algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node())
384 .into_text_edit(&mut import_insert); 384 .into_text_edit(&mut import_insert);
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 18983aa01..bf73818dc 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -1,14 +1,14 @@
1//! `completions` crate provides utilities for generating completions of user input. 1//! `completions` crate provides utilities for generating completions of user input.
2 2
3mod completions;
3mod config; 4mod config;
4mod item;
5mod context; 5mod context;
6mod item;
6mod patterns; 7mod patterns;
7#[cfg(test)]
8mod test_utils;
9mod render; 8mod render;
10 9
11mod completions; 10#[cfg(test)]
11mod tests;
12 12
13use completions::flyimport::position_for_import; 13use completions::flyimport::position_for_import;
14use ide_db::{ 14use ide_db::{
@@ -141,6 +141,7 @@ pub fn completions(
141 let ctx = CompletionContext::new(db, position, config)?; 141 let ctx = CompletionContext::new(db, position, config)?;
142 142
143 if ctx.no_completion_required() { 143 if ctx.no_completion_required() {
144 cov_mark::hit!(no_completion_required);
144 // No work required here. 145 // No work required here.
145 return None; 146 return None;
146 } 147 }
@@ -200,117 +201,3 @@ pub fn resolve_completion_edits(
200 201
201 ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) 202 ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
202} 203}
203
204#[cfg(test)]
205mod tests {
206 use crate::test_utils::{self, TEST_CONFIG};
207
208 struct DetailAndDocumentation<'a> {
209 detail: &'a str,
210 documentation: &'a str,
211 }
212
213 fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
214 let (db, position) = test_utils::position(ra_fixture);
215 let config = TEST_CONFIG;
216 let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into();
217 for item in completions {
218 if item.detail() == Some(expected.detail) {
219 let opt = item.documentation();
220 let doc = opt.as_ref().map(|it| it.as_str());
221 assert_eq!(doc, Some(expected.documentation));
222 return;
223 }
224 }
225 panic!("completion detail not found: {}", expected.detail)
226 }
227
228 fn check_no_completion(ra_fixture: &str) {
229 let (db, position) = test_utils::position(ra_fixture);
230 let config = TEST_CONFIG;
231
232 let completions: Option<Vec<String>> = crate::completions(&db, &config, position)
233 .and_then(|completions| {
234 let completions: Vec<_> = completions.into();
235 if completions.is_empty() {
236 None
237 } else {
238 Some(completions)
239 }
240 })
241 .map(|completions| {
242 completions.into_iter().map(|completion| format!("{:?}", completion)).collect()
243 });
244
245 // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic.
246 assert_eq!(completions, None, "Completions were generated, but weren't expected");
247 }
248
249 #[test]
250 fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
251 check_detail_and_documentation(
252 r#"
253macro_rules! bar {
254 () => {
255 struct Bar;
256 impl Bar {
257 #[doc = "Do the foo"]
258 fn foo(&self) {}
259 }
260 }
261}
262
263bar!();
264
265fn foo() {
266 let bar = Bar;
267 bar.fo$0;
268}
269"#,
270 DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
271 );
272 }
273
274 #[test]
275 fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
276 check_detail_and_documentation(
277 r#"
278macro_rules! bar {
279 () => {
280 struct Bar;
281 impl Bar {
282 /// Do the foo
283 fn foo(&self) {}
284 }
285 }
286}
287
288bar!();
289
290fn foo() {
291 let bar = Bar;
292 bar.fo$0;
293}
294"#,
295 DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
296 );
297 }
298
299 #[test]
300 fn test_no_completions_required() {
301 // There must be no hint for 'in' keyword.
302 check_no_completion(r#"fn foo() { for i i$0 }"#);
303 // After 'in' keyword hints may be spawned.
304 check_detail_and_documentation(
305 r#"
306/// Do the foo
307fn foo() -> &'static str { "foo" }
308
309fn bar() {
310 for c in fo$0
311}
312"#,
313 DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" },
314 );
315 }
316}
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 72e67e3c4..757c9a3da 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -11,7 +11,7 @@ use syntax::{
11}; 11};
12 12
13#[cfg(test)] 13#[cfg(test)]
14use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; 14use crate::tests::{check_pattern_is_applicable, check_pattern_is_not_applicable};
15 15
16/// Immediate previous node to what we are completing. 16/// Immediate previous node to what we are completing.
17#[derive(Copy, Clone, Debug, PartialEq, Eq)] 17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -19,15 +19,19 @@ pub(crate) enum ImmediatePrevSibling {
19 IfExpr, 19 IfExpr,
20 TraitDefName, 20 TraitDefName,
21 ImplDefType, 21 ImplDefType,
22 Visibility,
23 Attribute,
22} 24}
23 25
24/// Direct parent "thing" of what we are currently completing. 26/// Direct parent "thing" of what we are currently completing.
25#[derive(Clone, Debug, PartialEq, Eq)] 27#[derive(Clone, Debug, PartialEq, Eq)]
26pub(crate) enum ImmediateLocation { 28pub(crate) enum ImmediateLocation {
27 Use, 29 Use,
30 UseTree,
28 Impl, 31 Impl,
29 Trait, 32 Trait,
30 RecordField, 33 RecordField,
34 TupleField,
31 RefExpr, 35 RefExpr,
32 IdentPat, 36 IdentPat,
33 BlockExpr, 37 BlockExpr,
@@ -79,6 +83,17 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi
79 _ => node, 83 _ => node,
80 }; 84 };
81 let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; 85 let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
86 if prev_sibling.kind() == ERROR {
87 let prev_sibling = prev_sibling.first_child()?;
88 let res = match_ast! {
89 match prev_sibling {
90 // vis followed by random ident will always error the parser
91 ast::Visibility(_it) => ImmediatePrevSibling::Visibility,
92 _ => return None,
93 }
94 };
95 return Some(res);
96 }
82 let res = match_ast! { 97 let res = match_ast! {
83 match prev_sibling { 98 match prev_sibling {
84 ast::ExprStmt(it) => { 99 ast::ExprStmt(it) => {
@@ -101,6 +116,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi
101 } else { 116 } else {
102 return None 117 return None
103 }, 118 },
119 ast::Attr(_it) => ImmediatePrevSibling::Attribute,
104 _ => return None, 120 _ => return None,
105 } 121 }
106 }; 122 };
@@ -166,11 +182,19 @@ pub(crate) fn determine_location(
166 match parent { 182 match parent {
167 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 183 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
168 ast::Use(_it) => ImmediateLocation::Use, 184 ast::Use(_it) => ImmediateLocation::Use,
185 ast::UseTree(_it) => ImmediateLocation::UseTree,
186 ast::UseTreeList(_it) => ImmediateLocation::UseTree,
169 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, 187 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr,
170 ast::SourceFile(_it) => ImmediateLocation::ItemList, 188 ast::SourceFile(_it) => ImmediateLocation::ItemList,
171 ast::ItemList(_it) => ImmediateLocation::ItemList, 189 ast::ItemList(_it) => ImmediateLocation::ItemList,
172 ast::RefExpr(_it) => ImmediateLocation::RefExpr, 190 ast::RefExpr(_it) => ImmediateLocation::RefExpr,
173 ast::RecordField(_it) => ImmediateLocation::RecordField, 191 ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) {
192 return None;
193 } else {
194 ImmediateLocation::RecordField
195 },
196 ast::TupleField(_it) => ImmediateLocation::TupleField,
197 ast::TupleFieldList(_it) => ImmediateLocation::TupleField,
174 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { 198 ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) {
175 Some(IMPL) => ImmediateLocation::Impl, 199 Some(IMPL) => ImmediateLocation::Impl,
176 Some(TRAIT) => ImmediateLocation::Trait, 200 Some(TRAIT) => ImmediateLocation::Trait,
@@ -310,7 +334,7 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
310mod tests { 334mod tests {
311 use syntax::algo::find_node_at_offset; 335 use syntax::algo::find_node_at_offset;
312 336
313 use crate::test_utils::position; 337 use crate::tests::position;
314 338
315 use super::*; 339 use super::*;
316 340
@@ -359,8 +383,8 @@ mod tests {
359 fn test_use_loc() { 383 fn test_use_loc() {
360 check_location(r"use f$0", ImmediateLocation::Use); 384 check_location(r"use f$0", ImmediateLocation::Use);
361 check_location(r"use f$0;", ImmediateLocation::Use); 385 check_location(r"use f$0;", ImmediateLocation::Use);
362 check_location(r"use f::{f$0}", None); 386 check_location(r"use f::{f$0}", ImmediateLocation::UseTree);
363 check_location(r"use {f$0}", None); 387 check_location(r"use {f$0}", ImmediateLocation::UseTree);
364 } 388 }
365 389
366 #[test] 390 #[test]
@@ -421,4 +445,14 @@ mod tests {
421 check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); 445 check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr);
422 check_prev_sibling(r"fn foo() { if true {}; w$0", None); 446 check_prev_sibling(r"fn foo() { if true {}; w$0", None);
423 } 447 }
448
449 #[test]
450 fn test_vis_prev_sibling() {
451 check_prev_sibling(r"pub w$0", ImmediatePrevSibling::Visibility);
452 }
453
454 #[test]
455 fn test_attr_prev_sibling() {
456 check_prev_sibling(r"#[attr] w$0", ImmediatePrevSibling::Attribute);
457 }
424} 458}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index d8ca18c73..1a9b6212a 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -23,53 +23,6 @@ use crate::{
23 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, 23 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
25}; 25};
26
27pub(crate) fn render_field(
28 ctx: RenderContext<'_>,
29 receiver: Option<hir::Name>,
30 field: hir::Field,
31 ty: &hir::Type,
32) -> CompletionItem {
33 render_field_(ctx, receiver, field, ty)
34}
35
36pub(crate) fn render_tuple_field(
37 ctx: RenderContext<'_>,
38 receiver: Option<hir::Name>,
39 field: usize,
40 ty: &hir::Type,
41) -> CompletionItem {
42 render_tuple_field_(ctx, receiver, field, ty)
43}
44
45pub(crate) fn render_resolution(
46 ctx: RenderContext<'_>,
47 local_name: hir::Name,
48 resolution: &hir::ScopeDef,
49) -> Option<CompletionItem> {
50 render_resolution_(ctx, local_name, None, resolution)
51}
52
53pub(crate) fn render_resolution_with_import(
54 ctx: RenderContext<'_>,
55 import_edit: ImportEdit,
56) -> Option<CompletionItem> {
57 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
58 if ctx.completion.expects_type() && resolution.is_value_def() {
59 return None;
60 }
61 let local_name = match resolution {
62 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
63 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
64 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
65 _ => item_name(ctx.db(), import_edit.import.original_item)?,
66 };
67 render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
68 item.completion_kind = CompletionKind::Magic;
69 item
70 })
71}
72
73/// Interface for data and methods required for items rendering. 26/// Interface for data and methods required for items rendering.
74#[derive(Debug)] 27#[derive(Debug)]
75pub(crate) struct RenderContext<'a> { 28pub(crate) struct RenderContext<'a> {
@@ -122,7 +75,7 @@ impl<'a> RenderContext<'a> {
122 } 75 }
123} 76}
124 77
125fn render_field_( 78pub(crate) fn render_field(
126 ctx: RenderContext<'_>, 79 ctx: RenderContext<'_>,
127 receiver: Option<hir::Name>, 80 receiver: Option<hir::Name>,
128 field: hir::Field, 81 field: hir::Field,
@@ -135,7 +88,6 @@ fn render_field_(
135 ctx.source_range(), 88 ctx.source_range(),
136 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), 89 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
137 ); 90 );
138
139 item.set_relevance(CompletionRelevance { 91 item.set_relevance(CompletionRelevance {
140 type_match: compute_type_match(ctx.completion, ty), 92 type_match: compute_type_match(ctx.completion, ty),
141 exact_name_match: compute_exact_name_match(ctx.completion, &name), 93 exact_name_match: compute_exact_name_match(ctx.completion, &name),
@@ -146,17 +98,15 @@ fn render_field_(
146 .set_documentation(field.docs(ctx.db())) 98 .set_documentation(field.docs(ctx.db()))
147 .set_deprecated(is_deprecated) 99 .set_deprecated(is_deprecated)
148 .lookup_by(name); 100 .lookup_by(name);
149
150 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { 101 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
151 // FIXME 102 // FIXME
152 // For now we don't properly calculate the edits for ref match 103 // For now we don't properly calculate the edits for ref match
153 // completions on struct fields, so we've disabled them. See #8058. 104 // completions on struct fields, so we've disabled them. See #8058.
154 } 105 }
155
156 item.build() 106 item.build()
157} 107}
158 108
159fn render_tuple_field_( 109pub(crate) fn render_tuple_field(
160 ctx: RenderContext<'_>, 110 ctx: RenderContext<'_>,
161 receiver: Option<hir::Name>, 111 receiver: Option<hir::Name>,
162 field: usize, 112 field: usize,
@@ -167,14 +117,37 @@ fn render_tuple_field_(
167 ctx.source_range(), 117 ctx.source_range(),
168 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), 118 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
169 ); 119 );
170
171 item.kind(SymbolKind::Field) 120 item.kind(SymbolKind::Field)
172 .detail(ty.display(ctx.db()).to_string()) 121 .detail(ty.display(ctx.db()).to_string())
173 .lookup_by(field.to_string()); 122 .lookup_by(field.to_string());
174
175 item.build() 123 item.build()
176} 124}
177 125
126pub(crate) fn render_resolution(
127 ctx: RenderContext<'_>,
128 local_name: hir::Name,
129 resolution: &hir::ScopeDef,
130) -> Option<CompletionItem> {
131 render_resolution_(ctx, local_name, None, resolution)
132}
133
134pub(crate) fn render_resolution_with_import(
135 ctx: RenderContext<'_>,
136 import_edit: ImportEdit,
137) -> Option<CompletionItem> {
138 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
139 let local_name = match resolution {
140 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
141 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
142 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
143 _ => item_name(ctx.db(), import_edit.import.original_item)?,
144 };
145 render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
146 item.completion_kind = CompletionKind::Magic;
147 item
148 })
149}
150
178fn render_resolution_( 151fn render_resolution_(
179 ctx: RenderContext<'_>, 152 ctx: RenderContext<'_>,
180 local_name: hir::Name, 153 local_name: hir::Name,
@@ -362,7 +335,7 @@ mod tests {
362 335
363 use crate::{ 336 use crate::{
364 item::CompletionRelevanceTypeMatch, 337 item::CompletionRelevanceTypeMatch,
365 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, 338 tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
366 CompletionKind, CompletionRelevance, 339 CompletionKind, CompletionRelevance,
367 }; 340 };
368 341
@@ -1084,7 +1057,7 @@ fn f() {
1084 #[test] 1057 #[test]
1085 fn suggest_ref_mut() { 1058 fn suggest_ref_mut() {
1086 cov_mark::check!(suggest_ref); 1059 cov_mark::check!(suggest_ref);
1087 check( 1060 check_relevance(
1088 r#" 1061 r#"
1089struct S; 1062struct S;
1090fn foo(s: &mut S) {} 1063fn foo(s: &mut S) {}
@@ -1094,74 +1067,40 @@ fn main() {
1094} 1067}
1095 "#, 1068 "#,
1096 expect![[r#" 1069 expect![[r#"
1097 [ 1070 lc s [name+local]
1098 CompletionItem { 1071 lc &mut s [type+name+local]
1099 label: "S", 1072 st S []
1100 source_range: 70..70, 1073 fn main() []
1101 delete: 70..70, 1074 fn foo(…) []
1102 insert: "S",
1103 kind: SymbolKind(
1104 Struct,
1105 ),
1106 },
1107 CompletionItem {
1108 label: "foo(…)",
1109 source_range: 70..70,
1110 delete: 70..70,
1111 insert: "foo(${1:&mut s})$0",
1112 kind: SymbolKind(
1113 Function,
1114 ),
1115 lookup: "foo",
1116 detail: "fn(&mut S)",
1117 trigger_call_info: true,
1118 },
1119 CompletionItem {
1120 label: "main()",
1121 source_range: 70..70,
1122 delete: 70..70,
1123 insert: "main()$0",
1124 kind: SymbolKind(
1125 Function,
1126 ),
1127 lookup: "main",
1128 detail: "fn()",
1129 },
1130 CompletionItem {
1131 label: "s",
1132 source_range: 70..70,
1133 delete: 70..70,
1134 insert: "s",
1135 kind: SymbolKind(
1136 Local,
1137 ),
1138 detail: "S",
1139 relevance: CompletionRelevance {
1140 exact_name_match: true,
1141 type_match: None,
1142 is_local: true,
1143 },
1144 ref_match: "&mut ",
1145 },
1146 ]
1147 "#]], 1075 "#]],
1148 ) 1076 );
1077 check_relevance(
1078 r#"
1079struct S;
1080fn foo(s: &mut S) {}
1081fn main() {
1082 let mut s = S;
1083 foo(&mut $0);
1084}
1085 "#,
1086 expect![[r#"
1087 lc s [type+name+local]
1088 st S []
1089 fn main() []
1090 fn foo(…) []
1091 "#]],
1092 );
1149 } 1093 }
1150 1094
1151 #[test] 1095 #[test]
1152 fn suggest_deref() { 1096 fn suggest_deref() {
1153 check_relevance( 1097 check_relevance(
1154 r#" 1098 r#"
1155#[lang = "deref"] 1099//- minicore: deref
1156trait Deref {
1157 type Target;
1158 fn deref(&self) -> &Self::Target;
1159}
1160
1161struct S; 1100struct S;
1162struct T(S); 1101struct T(S);
1163 1102
1164impl Deref for T { 1103impl core::ops::Deref for T {
1165 type Target = S; 1104 type Target = S;
1166 1105
1167 fn deref(&self) -> &Self::Target { 1106 fn deref(&self) -> &Self::Target {
@@ -1185,8 +1124,9 @@ fn main() {
1185 st T [] 1124 st T []
1186 st S [] 1125 st S []
1187 fn main() [] 1126 fn main() []
1188 tt Deref []
1189 fn foo(…) [] 1127 fn foo(…) []
1128 md core []
1129 tt Sized []
1190 "#]], 1130 "#]],
1191 ) 1131 )
1192 } 1132 }
@@ -1195,21 +1135,11 @@ fn main() {
1195 fn suggest_deref_mut() { 1135 fn suggest_deref_mut() {
1196 check_relevance( 1136 check_relevance(
1197 r#" 1137 r#"
1198#[lang = "deref"] 1138//- minicore: deref_mut
1199trait Deref {
1200 type Target;
1201 fn deref(&self) -> &Self::Target;
1202}
1203
1204#[lang = "deref_mut"]
1205pub trait DerefMut: Deref {
1206 fn deref_mut(&mut self) -> &mut Self::Target;
1207}
1208
1209struct S; 1139struct S;
1210struct T(S); 1140struct T(S);
1211 1141
1212impl Deref for T { 1142impl core::ops::Deref for T {
1213 type Target = S; 1143 type Target = S;
1214 1144
1215 fn deref(&self) -> &Self::Target { 1145 fn deref(&self) -> &Self::Target {
@@ -1217,7 +1147,7 @@ impl Deref for T {
1217 } 1147 }
1218} 1148}
1219 1149
1220impl DerefMut for T { 1150impl core::ops::DerefMut for T {
1221 fn deref_mut(&mut self) -> &mut Self::Target { 1151 fn deref_mut(&mut self) -> &mut Self::Target {
1222 &mut self.0 1152 &mut self.0
1223 } 1153 }
@@ -1236,12 +1166,12 @@ fn main() {
1236 lc m [local] 1166 lc m [local]
1237 lc t [local] 1167 lc t [local]
1238 lc &mut t [type+local] 1168 lc &mut t [type+local]
1239 tt DerefMut []
1240 tt Deref []
1241 fn foo(…) []
1242 st T [] 1169 st T []
1243 st S [] 1170 st S []
1244 fn main() [] 1171 fn main() []
1172 fn foo(…) []
1173 md core []
1174 tt Sized []
1245 "#]], 1175 "#]],
1246 ) 1176 )
1247 } 1177 }
@@ -1310,16 +1240,11 @@ fn bar(t: &Foo) {}
1310 fn suggest_deref_fn_ret() { 1240 fn suggest_deref_fn_ret() {
1311 check_relevance( 1241 check_relevance(
1312 r#" 1242 r#"
1313#[lang = "deref"] 1243//- minicore: deref
1314trait Deref {
1315 type Target;
1316 fn deref(&self) -> &Self::Target;
1317}
1318
1319struct S; 1244struct S;
1320struct T(S); 1245struct T(S);
1321 1246
1322impl Deref for T { 1247impl core::ops::Deref for T {
1323 type Target = S; 1248 type Target = S;
1324 1249
1325 fn deref(&self) -> &Self::Target { 1250 fn deref(&self) -> &Self::Target {
@@ -1333,15 +1258,16 @@ fn bar() -> T {}
1333fn main() { 1258fn main() {
1334 foo($0); 1259 foo($0);
1335} 1260}
1336 "#, 1261"#,
1337 expect![[r#" 1262 expect![[r#"
1338 tt Deref []
1339 fn bar() []
1340 fn &bar() [type]
1341 fn foo(…) []
1342 st T [] 1263 st T []
1343 st S [] 1264 st S []
1344 fn main() [] 1265 fn main() []
1266 fn bar() []
1267 fn &bar() [type]
1268 fn foo(…) []
1269 md core []
1270 tt Sized []
1345 "#]], 1271 "#]],
1346 ) 1272 )
1347 } 1273 }
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index c54752d30..33d3a5ee1 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -28,11 +28,11 @@ impl Builder {
28 if !ctx.config.add_call_parenthesis { 28 if !ctx.config.add_call_parenthesis {
29 return false; 29 return false;
30 } 30 }
31 if ctx.use_item_syntax.is_some() { 31 if ctx.in_use_tree() {
32 cov_mark::hit!(no_parens_in_use_item); 32 cov_mark::hit!(no_parens_in_use_item);
33 return false; 33 return false;
34 } 34 }
35 if matches!(ctx.path_call_kind(), Some(CallKind::Expr) | Some(CallKind::Pat)) 35 if matches!(ctx.path_call_kind(), Some(CallKind::Expr | CallKind::Pat))
36 | matches!( 36 | matches!(
37 ctx.completion_location, 37 ctx.completion_location,
38 Some(ImmediateLocation::MethodCall { has_parens: true, .. }) 38 Some(ImmediateLocation::MethodCall { has_parens: true, .. })
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 28f056e77..91dc178f3 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -121,7 +121,7 @@ impl<'a> EnumRender<'a> {
121 121
122#[cfg(test)] 122#[cfg(test)]
123mod tests { 123mod tests {
124 use crate::test_utils::check_edit; 124 use crate::tests::check_edit;
125 125
126 #[test] 126 #[test]
127 fn inserts_parens_for_tuple_enums() { 127 fn inserts_parens_for_tuple_enums() {
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 1357b9f4a..19f2c86e9 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -191,7 +191,7 @@ impl<'a> FunctionRender<'a> {
191#[cfg(test)] 191#[cfg(test)]
192mod tests { 192mod tests {
193 use crate::{ 193 use crate::{
194 test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, 194 tests::{check_edit, check_edit_with_config, TEST_CONFIG},
195 CompletionConfig, 195 CompletionConfig,
196 }; 196 };
197 197
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 429d937c8..4d5179c4f 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> {
69 } 69 }
70 70
71 fn needs_bang(&self) -> bool { 71 fn needs_bang(&self) -> bool {
72 self.ctx.completion.use_item_syntax.is_none() 72 !self.ctx.completion.in_use_tree()
73 && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) 73 && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
74 } 74 }
75 75
@@ -133,7 +133,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s
133 133
134#[cfg(test)] 134#[cfg(test)]
135mod tests { 135mod tests {
136 use crate::test_utils::check_edit; 136 use crate::tests::check_edit;
137 137
138 #[test] 138 #[test]
139 fn dont_insert_macro_call_parens_unncessary() { 139 fn dont_insert_macro_call_parens_unncessary() {
@@ -180,7 +180,7 @@ fn main() { frobnicate!(); }
180/// ``` 180/// ```
181macro_rules! vec { () => {} } 181macro_rules! vec { () => {} }
182 182
183fn fn main() { v$0 } 183fn main() { v$0 }
184"#, 184"#,
185 r#" 185 r#"
186/// Creates a [`Vec`] containing the arguments. 186/// Creates a [`Vec`] containing the arguments.
@@ -193,7 +193,7 @@ fn fn main() { v$0 }
193/// ``` 193/// ```
194macro_rules! vec { () => {} } 194macro_rules! vec { () => {} }
195 195
196fn fn main() { vec![$0] } 196fn main() { vec![$0] }
197"#, 197"#,
198 ); 198 );
199 199
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/tests.rs
index b0a4b2026..97298ff27 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -1,4 +1,16 @@
1//! Runs completion for testing purposes. 1//! Tests and test utilities for completions.
2//!
3//! Most tests live in this module or its submodules unless for very specific completions like
4//! `attributes` or `lifetimes` where the completed concept is a distinct thing.
5//! Notable examples for completions that are being tested in this module's submodule are paths.
6
7mod item_list;
8mod use_tree;
9mod items;
10mod pattern;
11mod type_pos;
12
13use std::mem;
2 14
3use hir::{PrefixKind, Semantics}; 15use hir::{PrefixKind, Semantics};
4use ide_db::{ 16use ide_db::{
@@ -28,9 +40,27 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
28 prefix_kind: PrefixKind::Plain, 40 prefix_kind: PrefixKind::Plain,
29 enforce_granularity: true, 41 enforce_granularity: true,
30 group: true, 42 group: true,
43 skip_glob_imports: true,
31 }, 44 },
32}; 45};
33 46
47pub(crate) fn completion_list(code: &str) -> String {
48 completion_list_with_config(TEST_CONFIG, code)
49}
50
51fn completion_list_with_config(config: CompletionConfig, code: &str) -> String {
52 // filter out all but one builtintype completion for smaller test outputs
53 let items = get_all_items(config, code);
54 let mut bt_seen = false;
55 let items = items
56 .into_iter()
57 .filter(|it| {
58 it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true)
59 })
60 .collect();
61 render_completion_list(items)
62}
63
34/// Creates analysis from a multi-file fixture, returns positions marked with $0. 64/// Creates analysis from a multi-file fixture, returns positions marked with $0.
35pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { 65pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
36 let change_fixture = ChangeFixture::parse(ra_fixture); 66 let change_fixture = ChangeFixture::parse(ra_fixture);
@@ -57,24 +87,27 @@ pub(crate) fn do_completion_with_config(
57 .collect() 87 .collect()
58} 88}
59 89
60pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { 90pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String {
61 completion_list_with_config(TEST_CONFIG, code, kind) 91 filtered_completion_list_with_config(TEST_CONFIG, code, kind)
62} 92}
63 93
64pub(crate) fn completion_list_with_config( 94pub(crate) fn filtered_completion_list_with_config(
65 config: CompletionConfig, 95 config: CompletionConfig,
66 code: &str, 96 code: &str,
67 kind: CompletionKind, 97 kind: CompletionKind,
68) -> String { 98) -> String {
69 let kind_completions: Vec<CompletionItem> = 99 let kind_completions: Vec<CompletionItem> =
70 get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); 100 get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect();
71 let label_width = kind_completions 101 render_completion_list(kind_completions)
72 .iter() 102}
73 .map(|it| monospace_width(it.label())) 103
74 .max() 104fn render_completion_list(completions: Vec<CompletionItem>) -> String {
75 .unwrap_or_default() 105 fn monospace_width(s: &str) -> usize {
76 .min(16); 106 s.chars().count()
77 kind_completions 107 }
108 let label_width =
109 completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(16);
110 completions
78 .into_iter() 111 .into_iter()
79 .map(|it| { 112 .map(|it| {
80 let tag = it.kind().unwrap().tag(); 113 let tag = it.kind().unwrap().tag();
@@ -93,10 +126,6 @@ pub(crate) fn completion_list_with_config(
93 .collect() 126 .collect()
94} 127}
95 128
96fn monospace_width(s: &str) -> usize {
97 s.chars().count()
98}
99
100pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 129pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
101 check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) 130 check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after)
102} 131}
@@ -152,3 +181,18 @@ pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<Complet
152 let (db, position) = position(code); 181 let (db, position) = position(code);
153 crate::completions(&db, &config, position).unwrap().into() 182 crate::completions(&db, &config, position).unwrap().into()
154} 183}
184
185fn check_no_completion(ra_fixture: &str) {
186 let (db, position) = position(ra_fixture);
187
188 assert!(
189 crate::completions(&db, &TEST_CONFIG, position).is_none(),
190 "Completions were generated, but weren't expected"
191 );
192}
193
194#[test]
195fn test_no_completions_required() {
196 cov_mark::check!(no_completion_required);
197 check_no_completion(r#"fn foo() { for i i$0 }"#);
198}
diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs
new file mode 100644
index 000000000..7c124ac37
--- /dev/null
+++ b/crates/ide_completion/src/tests/item_list.rs
@@ -0,0 +1,223 @@
1use expect_test::{expect, Expect};
2
3use crate::tests::completion_list;
4
5fn check(ra_fixture: &str, expect: Expect) {
6 let base = r#"#[rustc_builtin_macro]
7pub macro Clone {}
8enum Enum { Variant }
9struct Struct {}
10#[macro_export]
11macro_rules! foo {}
12mod bar {}
13const CONST: () = ();
14trait Trait {}
15"#;
16 let actual = completion_list(&format!("{}{}", base, ra_fixture));
17 expect.assert_eq(&actual)
18}
19
20#[test]
21fn in_mod_item_list() {
22 check(
23 r#"mod tests { $0 }"#,
24 expect![[r##"
25 kw pub(crate)
26 kw pub
27 kw unsafe
28 kw fn
29 kw const
30 kw type
31 kw impl
32 kw extern
33 kw use
34 kw trait
35 kw static
36 kw mod
37 kw enum
38 kw struct
39 kw union
40 sn tmod (Test module)
41 sn tfn (Test function)
42 sn macro_rules
43 ma foo!(…) #[macro_export] macro_rules! foo
44 "##]],
45 )
46}
47
48#[test]
49fn in_source_file_item_list() {
50 check(
51 r#"$0"#,
52 expect![[r##"
53 kw pub(crate)
54 kw pub
55 kw unsafe
56 kw fn
57 kw const
58 kw type
59 kw impl
60 kw extern
61 kw use
62 kw trait
63 kw static
64 kw mod
65 kw enum
66 kw struct
67 kw union
68 sn tmod (Test module)
69 sn tfn (Test function)
70 sn macro_rules
71 md bar
72 ma foo!(…) #[macro_export] macro_rules! foo
73 ma foo!(…) #[macro_export] macro_rules! foo
74 "##]],
75 )
76}
77
78#[test]
79fn in_item_list_after_attr() {
80 check(
81 r#"#[attr] $0"#,
82 expect![[r#"
83 kw pub(crate)
84 kw pub
85 kw unsafe
86 kw fn
87 kw const
88 kw type
89 kw impl
90 kw extern
91 kw use
92 kw trait
93 kw static
94 kw mod
95 kw enum
96 kw struct
97 kw union
98 sn tmod (Test module)
99 sn tfn (Test function)
100 sn macro_rules
101 "#]],
102 )
103}
104
105#[test]
106fn in_qualified_path() {
107 check(
108 r#"crate::$0"#,
109 expect![[r##"
110 kw pub(crate)
111 kw pub
112 kw unsafe
113 kw fn
114 kw const
115 kw type
116 kw impl
117 kw extern
118 kw use
119 kw trait
120 kw static
121 kw mod
122 kw enum
123 kw struct
124 kw union
125 md bar
126 ma foo!(…) #[macro_export] macro_rules! foo
127 "##]],
128 )
129}
130
131#[test]
132fn after_unsafe_token() {
133 check(
134 r#"unsafe $0"#,
135 expect![[r#"
136 kw fn
137 kw trait
138 kw impl
139 "#]],
140 );
141}
142
143#[test]
144fn after_visibility() {
145 check(
146 r#"pub $0"#,
147 expect![[r#"
148 kw unsafe
149 kw fn
150 kw const
151 kw type
152 kw use
153 kw trait
154 kw static
155 kw mod
156 kw enum
157 kw struct
158 kw union
159 "#]],
160 );
161}
162
163#[test]
164fn after_visibility_unsafe() {
165 // FIXME this shouldn't show `impl`
166 check(
167 r#"pub unsafe $0"#,
168 expect![[r#"
169 kw fn
170 kw trait
171 kw impl
172 "#]],
173 );
174}
175
176#[test]
177fn in_impl_assoc_item_list() {
178 check(
179 r#"impl Struct { $0 }"#,
180 expect![[r##"
181 kw pub(crate)
182 kw pub
183 kw unsafe
184 kw fn
185 kw const
186 kw type
187 md bar
188 ma foo!(…) #[macro_export] macro_rules! foo
189 ma foo!(…) #[macro_export] macro_rules! foo
190 "##]],
191 )
192}
193
194#[test]
195fn in_impl_assoc_item_list_after_attr() {
196 check(
197 r#"impl Struct { #[attr] $0 }"#,
198 expect![[r#"
199 kw pub(crate)
200 kw pub
201 kw unsafe
202 kw fn
203 kw const
204 kw type
205 "#]],
206 )
207}
208
209#[test]
210fn in_trait_assoc_item_list() {
211 check(
212 r"trait Foo { $0 }",
213 expect![[r##"
214 kw unsafe
215 kw fn
216 kw const
217 kw type
218 md bar
219 ma foo!(…) #[macro_export] macro_rules! foo
220 ma foo!(…) #[macro_export] macro_rules! foo
221 "##]],
222 );
223}
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs
new file mode 100644
index 000000000..b98baffd6
--- /dev/null
+++ b/crates/ide_completion/src/tests/items.rs
@@ -0,0 +1,95 @@
1//! Completions tests for item specifics overall.
2//!
3//! Except for use items which are tested in [super::use_tree] and mod declarations with are tested
4//! in [crate::completions::mod_].
5use expect_test::{expect, Expect};
6
7use crate::tests::completion_list;
8
9fn check(ra_fixture: &str, expect: Expect) {
10 let base = r#"#[rustc_builtin_macro]
11pub macro Clone {}
12enum Enum { Variant }
13struct Struct {}
14#[macro_export]
15macro_rules! foo {}
16mod bar {}
17const CONST: () = ();
18trait Trait {}
19"#;
20 let actual = completion_list(&format!("{}{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn target_type_or_trait_in_impl_block() {
26 check(
27 r#"
28impl Tra$0
29"#,
30 expect![[r##"
31 tt Trait
32 en Enum
33 st Struct
34 md bar
35 ma foo!(…) #[macro_export] macro_rules! foo
36 ma foo!(…) #[macro_export] macro_rules! foo
37 bt u32
38 "##]],
39 )
40}
41
42#[test]
43fn target_type_in_trait_impl_block() {
44 check(
45 r#"
46impl Trait for Str$0
47"#,
48 expect![[r##"
49 tt Trait
50 en Enum
51 st Struct
52 md bar
53 ma foo!(…) #[macro_export] macro_rules! foo
54 ma foo!(…) #[macro_export] macro_rules! foo
55 bt u32
56 "##]],
57 )
58}
59
60#[test]
61fn after_trait_name_in_trait_def() {
62 check(
63 r"trait A $0",
64 expect![[r#"
65 kw where
66 "#]],
67 );
68}
69
70#[test]
71fn after_trait_or_target_name_in_impl() {
72 check(
73 r"impl Trait $0",
74 expect![[r#"
75 kw where
76 kw for
77 "#]],
78 );
79}
80
81#[test]
82fn before_record_field() {
83 check(
84 r#"
85struct Foo {
86 $0
87 pub f: i32,
88}
89"#,
90 expect![[r#"
91 kw pub(crate)
92 kw pub
93 "#]],
94 )
95}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
new file mode 100644
index 000000000..1ad5ccd97
--- /dev/null
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -0,0 +1,348 @@
1//! Completions tests for pattern position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check(ra_fixture: &str, expect: Expect) {
7 let actual = completion_list(ra_fixture);
8 expect.assert_eq(&actual)
9}
10
11fn check_with(ra_fixture: &str, expect: Expect) {
12 let base = r#"
13enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
14use self::Enum::TupleV;
15mod module {}
16
17static STATIC: Unit = Unit;
18const CONST: Unit = Unit;
19struct Record { field: u32 }
20struct Tuple(u32);
21struct Unit
22macro_rules! makro {}
23"#;
24 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
25 expect.assert_eq(&actual)
26}
27
28#[test]
29fn ident_rebind_pat() {
30 check(
31 r#"
32fn quux() {
33 let en$0 @ x
34}
35"#,
36 expect![[r#"
37 kw mut
38 "#]],
39 );
40}
41
42#[test]
43fn ident_ref_pat() {
44 check(
45 r#"
46fn quux() {
47 let ref en$0
48}
49"#,
50 expect![[r#"
51 kw mut
52 "#]],
53 );
54 check(
55 r#"
56fn quux() {
57 let ref en$0 @ x
58}
59"#,
60 expect![[r#"
61 kw mut
62 "#]],
63 );
64}
65
66#[test]
67fn ident_ref_mut_pat() {
68 // FIXME mut is already here, don't complete it again
69 check(
70 r#"
71fn quux() {
72 let ref mut en$0
73}
74"#,
75 expect![[r#"
76 kw mut
77 "#]],
78 );
79 check(
80 r#"
81fn quux() {
82 let ref mut en$0 @ x
83}
84"#,
85 expect![[r#"
86 kw mut
87 "#]],
88 );
89}
90
91#[test]
92fn ref_pat() {
93 check(
94 r#"
95fn quux() {
96 let &en$0
97}
98"#,
99 expect![[r#"
100 kw mut
101 "#]],
102 );
103 // FIXME mut is already here, don't complete it again
104 check(
105 r#"
106fn quux() {
107 let &mut en$0
108}
109"#,
110 expect![[r#"
111 kw mut
112 "#]],
113 );
114}
115
116#[test]
117fn refutable() {
118 check_with(
119 r#"
120fn foo() {
121 if let a$0
122}
123"#,
124 expect![[r#"
125 kw mut
126 bn Record Record { field$1 }$0
127 st Record
128 en Enum
129 bn Tuple Tuple($1)$0
130 st Tuple
131 md module
132 bn TupleV TupleV($1)$0
133 ev TupleV
134 st Unit
135 ct CONST
136 ma makro!(…) macro_rules! makro
137 "#]],
138 );
139}
140
141#[test]
142fn irrefutable() {
143 check_with(
144 r#"
145fn foo() {
146 let a$0
147}
148"#,
149 expect![[r#"
150 kw mut
151 bn Record Record { field$1 }$0
152 st Record
153 bn Tuple Tuple($1)$0
154 st Tuple
155 st Unit
156 ma makro!(…) macro_rules! makro
157 "#]],
158 );
159}
160
161#[test]
162fn in_param() {
163 check_with(
164 r#"
165fn foo(a$0) {
166}
167"#,
168 expect![[r#"
169 kw mut
170 bn Record Record { field$1 }: Record$0
171 st Record
172 bn Tuple Tuple($1): Tuple$0
173 st Tuple
174 st Unit
175 ma makro!(…) macro_rules! makro
176 "#]],
177 );
178}
179
180#[test]
181fn only_fn_like_macros() {
182 check(
183 r#"
184macro_rules! m { ($e:expr) => { $e } }
185
186#[rustc_builtin_macro]
187macro Clone {}
188
189fn foo() {
190 let x$0
191}
192"#,
193 expect![[r#"
194 kw mut
195 ma m!(…) macro_rules! m
196 "#]],
197 );
198}
199
200#[test]
201fn in_simple_macro_call() {
202 check(
203 r#"
204macro_rules! m { ($e:expr) => { $e } }
205enum E { X }
206
207fn foo() {
208 m!(match E::X { a$0 })
209}
210"#,
211 expect![[r#"
212 kw mut
213 ev E::X ()
214 en E
215 ma m!(…) macro_rules! m
216 "#]],
217 );
218}
219
220#[test]
221fn omits_private_fields_pat() {
222 check(
223 r#"
224mod foo {
225 pub struct Record { pub field: i32, _field: i32 }
226 pub struct Tuple(pub u32, u32);
227 pub struct Invisible(u32, u32);
228}
229use foo::*;
230
231fn outer() {
232 if let a$0
233}
234"#,
235 expect![[r#"
236 kw mut
237 bn Record Record { field$1, .. }$0
238 st Record
239 bn Tuple Tuple($1, ..)$0
240 st Tuple
241 st Invisible
242 md foo
243 "#]],
244 )
245}
246
247// #[test]
248// fn only_shows_ident_completion() {
249// check_edit(
250// "Foo",
251// r#"
252// struct Foo(i32);
253// fn main() {
254// match Foo(92) {
255// a$0(92) => (),
256// }
257// }
258// "#,
259// r#"
260// struct Foo(i32);
261// fn main() {
262// match Foo(92) {
263// Foo(92) => (),
264// }
265// }
266// "#,
267// );
268// }
269
270#[test]
271fn completes_self_pats() {
272 check(
273 r#"
274struct Foo(i32);
275impl Foo {
276 fn foo() {
277 match Foo(0) {
278 a$0
279 }
280 }
281}
282 "#,
283 expect![[r#"
284 kw mut
285 bn Self Self($1)$0
286 sp Self
287 bn Foo Foo($1)$0
288 st Foo
289 "#]],
290 )
291}
292
293#[test]
294fn completes_qualified_variant() {
295 check(
296 r#"
297enum Foo {
298 Bar { baz: i32 }
299}
300impl Foo {
301 fn foo() {
302 match {Foo::Bar { baz: 0 }} {
303 B$0
304 }
305 }
306}
307 "#,
308 expect![[r#"
309 kw mut
310 bn Self::Bar Self::Bar { baz$1 }$0
311 ev Self::Bar { baz: i32 }
312 bn Foo::Bar Foo::Bar { baz$1 }$0
313 ev Foo::Bar { baz: i32 }
314 sp Self
315 en Foo
316 "#]],
317 )
318}
319
320#[test]
321fn completes_in_record_field_pat() {
322 check(
323 r#"
324struct Foo { bar: Bar }
325struct Bar(u32);
326fn outer(Foo { bar: $0 }: Foo) {}
327"#,
328 expect![[r#"
329 kw mut
330 bn Foo Foo { bar$1 }$0
331 st Foo
332 bn Bar Bar($1)$0
333 st Bar
334 "#]],
335 )
336}
337
338#[test]
339fn skips_in_record_field_pat_name() {
340 check(
341 r#"
342struct Foo { bar: Bar }
343struct Bar(u32);
344fn outer(Foo { bar$0 }: Foo) {}
345"#,
346 expect![[r#""#]],
347 )
348}
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs
new file mode 100644
index 000000000..1ab47b27e
--- /dev/null
+++ b/crates/ide_completion/src/tests/type_pos.rs
@@ -0,0 +1,177 @@
1//! Completions tests for type position.
2use expect_test::{expect, Expect};
3
4use crate::tests::completion_list;
5
6fn check_with(ra_fixture: &str, expect: Expect) {
7 let base = r#"
8enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV }
9use self::Enum::TupleV;
10mod module {}
11
12trait Trait {}
13static STATIC: Unit = Unit;
14const CONST: Unit = Unit;
15struct Record { field: u32 }
16struct Tuple(u32);
17struct Unit
18macro_rules! makro {}
19"#;
20 let actual = completion_list(&format!("{}\n{}", base, ra_fixture));
21 expect.assert_eq(&actual)
22}
23
24#[test]
25fn record_field_ty() {
26 check_with(
27 r#"
28struct Foo<'lt, T, const C: usize> {
29 f: $0
30}
31"#,
32 expect![[r#"
33 sp Self
34 tp T
35 tt Trait
36 en Enum
37 st Record
38 st Tuple
39 md module
40 st Foo<…>
41 st Unit
42 ma makro!(…) macro_rules! makro
43 bt u32
44 "#]],
45 )
46}
47
48#[test]
49fn tuple_struct_field() {
50 check_with(
51 r#"
52struct Foo<'lt, T, const C: usize>(f$0);
53"#,
54 expect![[r#"
55 kw pub(crate)
56 kw pub
57 sp Self
58 tp T
59 tt Trait
60 en Enum
61 st Record
62 st Tuple
63 md module
64 st Foo<…>
65 st Unit
66 ma makro!(…) macro_rules! makro
67 bt u32
68 "#]],
69 )
70}
71
72#[test]
73fn fn_return_type() {
74 check_with(
75 r#"
76fn x<'lt, T, const C: usize>() -> $0
77"#,
78 expect![[r#"
79 tp T
80 tt Trait
81 en Enum
82 st Record
83 st Tuple
84 md module
85 st Unit
86 ma makro!(…) macro_rules! makro
87 bt u32
88 "#]],
89 );
90}
91
92#[test]
93fn body_type_pos() {
94 check_with(
95 r#"
96fn foo<'lt, T, const C: usize>() {
97 let local = ();
98 let _: $0;
99}
100"#,
101 expect![[r#"
102 tp T
103 tt Trait
104 en Enum
105 st Record
106 st Tuple
107 md module
108 st Unit
109 ma makro!(…) macro_rules! makro
110 bt u32
111 "#]],
112 );
113 check_with(
114 r#"
115fn foo<'lt, T, const C: usize>() {
116 let local = ();
117 let _: self::$0;
118}
119"#,
120 expect![[r#"
121 tt Trait
122 en Enum
123 st Record
124 st Tuple
125 md module
126 st Unit
127 "#]],
128 );
129}
130
131#[test]
132fn completes_types_and_const_in_arg_list() {
133 // FIXME: we should complete the lifetime here for now
134 check_with(
135 r#"
136trait Trait2 {
137 type Foo;
138}
139
140fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
141"#,
142 expect![[r#"
143 ta Foo = type Foo;
144 tp T
145 cp CONST_PARAM
146 tt Trait
147 en Enum
148 st Record
149 st Tuple
150 tt Trait2
151 md module
152 st Unit
153 ct CONST
154 ma makro!(…) macro_rules! makro
155 bt u32
156 "#]],
157 );
158 check_with(
159 r#"
160trait Trait2 {
161 type Foo;
162}
163
164fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
165 "#,
166 expect![[r#"
167 tt Trait
168 en Enum
169 st Record
170 st Tuple
171 tt Trait2
172 md module
173 st Unit
174 ct CONST
175 "#]],
176 );
177}
diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs
new file mode 100644
index 000000000..7e6748ccc
--- /dev/null
+++ b/crates/ide_completion/src/tests/use_tree.rs
@@ -0,0 +1,255 @@
1use expect_test::{expect, Expect};
2
3use crate::tests::completion_list;
4
5fn check(ra_fixture: &str, expect: Expect) {
6 let actual = completion_list(ra_fixture);
7 expect.assert_eq(&actual)
8}
9
10#[test]
11fn use_tree_start() {
12 cov_mark::check!(only_completes_modules_in_import);
13 check(
14 r#"
15//- /lib.rs crate:main deps:other_crate
16use f$0
17
18struct Foo;
19mod foo {}
20//- /other_crate/lib.rs crate:other_crate
21// nothing here
22"#,
23 expect![[r#"
24 kw crate::
25 kw self::
26 kw super::
27 md foo
28 md other_crate
29 "#]],
30 );
31}
32
33#[test]
34fn dont_complete_current_use() {
35 cov_mark::check!(dont_complete_current_use);
36 check(r#"use self::foo$0;"#, expect![[r#""#]]);
37 check(
38 r#"
39mod foo { pub struct S; }
40use self::{foo::*, bar$0};
41"#,
42 expect![[r#"
43 kw self
44 st S
45 md foo
46 "#]],
47 );
48}
49
50#[test]
51fn nested_use_tree() {
52 check(
53 r#"
54mod foo {
55 pub mod bar {
56 pub struct FooBar;
57 }
58}
59use foo::{bar::$0}
60"#,
61 expect![[r#"
62 st FooBar
63 "#]],
64 );
65 check(
66 r#"
67mod foo {
68 pub mod bar {
69 pub struct FooBar;
70 }
71}
72use foo::{$0}
73"#,
74 expect![[r#"
75 kw self
76 md bar
77 "#]],
78 );
79}
80
81#[test]
82fn deeply_nested_use_tree() {
83 check(
84 r#"
85mod foo {
86 pub mod bar {
87 pub mod baz {
88 pub struct FooBarBaz;
89 }
90 }
91}
92use foo::{bar::{baz::$0}}
93"#,
94 expect![[r#"
95 st FooBarBaz
96 "#]],
97 );
98 check(
99 r#"
100mod foo {
101 pub mod bar {
102 pub mod baz {
103 pub struct FooBarBaz;
104 }
105 }
106}
107use foo::{bar::{$0}}
108"#,
109 expect![[r#"
110 kw self
111 md baz
112 "#]],
113 );
114}
115
116#[test]
117fn plain_qualified_use_tree() {
118 check(
119 r#"
120use foo::$0
121
122mod foo {
123 struct Private;
124 pub struct Foo;
125}
126struct Bar;
127"#,
128 expect![[r#"
129 st Foo
130 "#]],
131 );
132}
133
134#[test]
135fn self_qualified_use_tree() {
136 check(
137 r#"
138use self::$0
139
140mod foo {}
141struct Bar;
142"#,
143 expect![[r#"
144 md foo
145 st Bar
146 "#]],
147 );
148}
149
150#[test]
151fn super_qualified_use_tree() {
152 check(
153 r#"
154mod bar {
155 use super::$0
156}
157
158mod foo {}
159struct Bar;
160"#,
161 expect![[r#"
162 kw super::
163 st Bar
164 md bar
165 md foo
166 "#]],
167 );
168}
169
170#[test]
171fn super_super_qualified_use_tree() {
172 check(
173 r#"
174mod a {
175 const A: usize = 0;
176 mod b {
177 const B: usize = 0;
178 mod c { use super::super::$0 }
179 }
180}
181"#,
182 expect![[r#"
183 kw super::
184 md b
185 ct A
186 "#]],
187 );
188}
189
190#[test]
191fn crate_qualified_use_tree() {
192 check(
193 r#"
194use crate::$0
195
196mod foo {}
197struct Bar;
198"#,
199 expect![[r#"
200 md foo
201 st Bar
202 "#]],
203 );
204}
205
206#[test]
207fn extern_crate_qualified_use_tree() {
208 check(
209 r#"
210//- /lib.rs crate:main deps:other_crate
211use other_crate::$0
212//- /other_crate/lib.rs crate:other_crate
213pub struct Foo;
214pub mod foo {}
215"#,
216 expect![[r#"
217 st Foo
218 md foo
219 "#]],
220 );
221}
222
223#[test]
224fn pub_use_tree() {
225 check(
226 r#"
227pub struct X;
228pub mod bar {}
229pub use $0;
230"#,
231 expect![[r#"
232 kw crate::
233 kw self::
234 kw super::
235 md bar
236 "#]],
237 );
238}
239
240#[test]
241fn use_tree_braces_at_start() {
242 check(
243 r#"
244struct X;
245mod bar {}
246use {$0};
247"#,
248 expect![[r#"
249 kw crate::
250 kw self::
251 kw super::
252 md bar
253 "#]],
254 );
255}
diff --git a/crates/ide_db/src/assists.rs b/crates/ide_db/src/assists.rs
new file mode 100644
index 000000000..7881d8369
--- /dev/null
+++ b/crates/ide_db/src/assists.rs
@@ -0,0 +1,136 @@
1//! This module defines the `Assist` data structure. The actual assist live in
2//! the `ide_assists` downstream crate. We want to define the data structures in
3//! this low-level crate though, because `ide_diagnostics` also need them
4//! (fixits for diagnostics and assists are the same thing under the hood). We
5//! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so
6//! we pull the common definitions upstream, to this crate.
7
8use std::str::FromStr;
9
10use syntax::TextRange;
11
12use crate::{label::Label, source_change::SourceChange};
13
14#[derive(Debug, Clone)]
15pub struct Assist {
16 pub id: AssistId,
17 /// Short description of the assist, as shown in the UI.
18 pub label: Label,
19 pub group: Option<GroupLabel>,
20 /// Target ranges are used to sort assists: the smaller the target range,
21 /// the more specific assist is, and so it should be sorted first.
22 pub target: TextRange,
23 /// Computing source change sometimes is much more costly then computing the
24 /// other fields. Additionally, the actual change is not required to show
25 /// the lightbulb UI, it only is needed when the user tries to apply an
26 /// assist. So, we compute it lazily: the API allow requesting assists with
27 /// or without source change. We could (and in fact, used to) distinguish
28 /// between resolved and unresolved assists at the type level, but this is
29 /// cumbersome, especially if you want to embed an assist into another data
30 /// structure, such as a diagnostic.
31 pub source_change: Option<SourceChange>,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum AssistKind {
36 // FIXME: does the None variant make sense? Probably not.
37 None,
38
39 QuickFix,
40 Generate,
41 Refactor,
42 RefactorExtract,
43 RefactorInline,
44 RefactorRewrite,
45}
46
47impl AssistKind {
48 pub fn contains(self, other: AssistKind) -> bool {
49 if self == other {
50 return true;
51 }
52
53 match self {
54 AssistKind::None | AssistKind::Generate => true,
55 AssistKind::Refactor => match other {
56 AssistKind::RefactorExtract
57 | AssistKind::RefactorInline
58 | AssistKind::RefactorRewrite => true,
59 _ => false,
60 },
61 _ => false,
62 }
63 }
64
65 pub fn name(&self) -> &str {
66 match self {
67 AssistKind::None => "None",
68 AssistKind::QuickFix => "QuickFix",
69 AssistKind::Generate => "Generate",
70 AssistKind::Refactor => "Refactor",
71 AssistKind::RefactorExtract => "RefactorExtract",
72 AssistKind::RefactorInline => "RefactorInline",
73 AssistKind::RefactorRewrite => "RefactorRewrite",
74 }
75 }
76}
77
78impl FromStr for AssistKind {
79 type Err = String;
80
81 fn from_str(s: &str) -> Result<Self, Self::Err> {
82 match s {
83 "None" => Ok(AssistKind::None),
84 "QuickFix" => Ok(AssistKind::QuickFix),
85 "Generate" => Ok(AssistKind::Generate),
86 "Refactor" => Ok(AssistKind::Refactor),
87 "RefactorExtract" => Ok(AssistKind::RefactorExtract),
88 "RefactorInline" => Ok(AssistKind::RefactorInline),
89 "RefactorRewrite" => Ok(AssistKind::RefactorRewrite),
90 unknown => Err(format!("Unknown AssistKind: '{}'", unknown)),
91 }
92 }
93}
94
95/// Unique identifier of the assist, should not be shown to the user
96/// directly.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct AssistId(pub &'static str, pub AssistKind);
99
100/// A way to control how many asssist to resolve during the assist resolution.
101/// When an assist is resolved, its edits are calculated that might be costly to always do by default.
102#[derive(Debug)]
103pub enum AssistResolveStrategy {
104 /// No assists should be resolved.
105 None,
106 /// All assists should be resolved.
107 All,
108 /// Only a certain assist should be resolved.
109 Single(SingleResolve),
110}
111
112/// Hold the [`AssistId`] data of a certain assist to resolve.
113/// The original id object cannot be used due to a `'static` lifetime
114/// and the requirement to construct this struct dynamically during the resolve handling.
115#[derive(Debug)]
116pub struct SingleResolve {
117 /// The id of the assist.
118 pub assist_id: String,
119 // The kind of the assist.
120 pub assist_kind: AssistKind,
121}
122
123impl AssistResolveStrategy {
124 pub fn should_resolve(&self, id: &AssistId) -> bool {
125 match self {
126 AssistResolveStrategy::None => false,
127 AssistResolveStrategy::All => true,
128 AssistResolveStrategy::Single(single_resolve) => {
129 single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
130 }
131 }
132 }
133}
134
135#[derive(Clone, Debug)]
136pub struct GroupLabel(pub String);
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 00900cdc2..d96028cbc 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -74,12 +74,19 @@ pub fn visit_file_defs(
74/// somewhat similar to the known paths infra inside hir, but it different; We 74/// somewhat similar to the known paths infra inside hir, but it different; We
75/// want to make sure that IDE specific paths don't become interesting inside 75/// want to make sure that IDE specific paths don't become interesting inside
76/// the compiler itself as well. 76/// the compiler itself as well.
77///
78/// Note that, by default, rust-analyzer tests **do not** include core or std
79/// libraries. If you are writing tests for functionality using [`FamousDefs`],
80/// you'd want to include [minicore](test_utils::MiniCore) declaration at the
81/// start of your tests:
82///
83/// ```
84/// //- minicore: iterator, ord, derive
85/// ```
77pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>); 86pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
78 87
79#[allow(non_snake_case)] 88#[allow(non_snake_case)]
80impl FamousDefs<'_, '_> { 89impl FamousDefs<'_, '_> {
81 pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs");
82
83 pub fn std(&self) -> Option<Crate> { 90 pub fn std(&self) -> Option<Crate> {
84 self.find_crate("std") 91 self.find_crate("std")
85 } 92 }
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
deleted file mode 100644
index 312851966..000000000
--- a/crates/ide_db/src/helpers/famous_defs_fixture.rs
+++ /dev/null
@@ -1,153 +0,0 @@
1//- /libcore.rs crate:core
2//! Signatures of traits, types and functions from the core lib for use in tests.
3pub mod cmp {
4
5 pub trait Ord {
6 fn cmp(&self, other: &Self) -> Ordering;
7 fn max(self, other: Self) -> Self;
8 fn min(self, other: Self) -> Self;
9 fn clamp(self, min: Self, max: Self) -> Self;
10 }
11}
12
13pub mod convert {
14 pub trait From<T> {
15 fn from(t: T) -> Self;
16 }
17
18 pub trait Into<T> {
19 pub fn into(self) -> T;
20 }
21}
22
23pub mod default {
24 pub trait Default {
25 fn default() -> Self;
26 }
27}
28
29pub mod iter {
30 pub use self::traits::{collect::IntoIterator, iterator::Iterator};
31 mod traits {
32 pub(crate) mod iterator {
33 use crate::option::Option;
34 pub trait Iterator {
35 type Item;
36 fn next(&mut self) -> Option<Self::Item>;
37 fn by_ref(&mut self) -> &mut Self {
38 self
39 }
40 fn take(self, n: usize) -> crate::iter::Take<Self> {
41 crate::iter::Take { inner: self }
42 }
43 }
44
45 impl<I: Iterator> Iterator for &mut I {
46 type Item = I::Item;
47 fn next(&mut self) -> Option<I::Item> {
48 (**self).next()
49 }
50 }
51 }
52 pub(crate) mod collect {
53 pub trait IntoIterator {
54 type Item;
55 }
56 }
57 }
58
59 pub use self::sources::*;
60 pub(crate) mod sources {
61 use super::Iterator;
62 use crate::option::Option::{self, *};
63 pub struct Repeat<A> {
64 element: A,
65 }
66
67 pub fn repeat<T>(elt: T) -> Repeat<T> {
68 Repeat { element: elt }
69 }
70
71 impl<A> Iterator for Repeat<A> {
72 type Item = A;
73
74 fn next(&mut self) -> Option<A> {
75 None
76 }
77 }
78 }
79
80 pub use self::adapters::*;
81 pub(crate) mod adapters {
82 use super::Iterator;
83 use crate::option::Option::{self, *};
84 pub struct Take<I> {
85 pub(crate) inner: I,
86 }
87 impl<I> Iterator for Take<I>
88 where
89 I: Iterator,
90 {
91 type Item = <I as Iterator>::Item;
92 fn next(&mut self) -> Option<<I as Iterator>::Item> {
93 None
94 }
95 }
96 }
97}
98
99pub mod ops {
100 #[lang = "fn"]
101 pub trait Fn<Args>: FnMut<Args> {
102 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
103 }
104
105 #[lang = "fn_mut"]
106 pub trait FnMut<Args>: FnOnce<Args> {
107 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
108 }
109 #[lang = "fn_once"]
110 pub trait FnOnce<Args> {
111 #[lang = "fn_once_output"]
112 type Output;
113 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
114 }
115
116 #[lang = "deref"]
117 pub trait Deref {
118 type Target: ?Sized;
119 fn deref(&self) -> &Self::Target;
120 }
121}
122
123pub mod option {
124 pub enum Option<T> {
125 None,
126 Some(T),
127 }
128}
129
130pub mod prelude {
131 pub mod rust_2018 {
132 pub use crate::{
133 cmp::Ord,
134 convert::{From, Into},
135 default::Default,
136 iter::{IntoIterator, Iterator},
137 ops::{Fn, FnMut, FnOnce},
138 option::Option::{self, *},
139 };
140 }
141}
142#[prelude_import]
143pub use prelude::rust_2018::*;
144//- /libstd.rs crate:std deps:core
145//! Signatures of traits, types and functions from the std lib for use in tests.
146
147/// Docs for return_keyword
148mod return_keyword {}
149
150/// Docs for prim_str
151mod prim_str {}
152
153pub use core::ops;
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 10bbafe77..e6b4832e7 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -5,7 +5,7 @@ use hir::Semantics;
5use syntax::{ 5use syntax::{
6 algo, 6 algo,
7 ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner}, 7 ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner},
8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, 8 match_ast, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
9}; 9};
10 10
11use crate::{ 11use crate::{
@@ -36,22 +36,39 @@ pub struct InsertUseConfig {
36 pub enforce_granularity: bool, 36 pub enforce_granularity: bool,
37 pub prefix_kind: PrefixKind, 37 pub prefix_kind: PrefixKind,
38 pub group: bool, 38 pub group: bool,
39 pub skip_glob_imports: bool,
39} 40}
40 41
41#[derive(Debug, Clone)] 42#[derive(Debug, Clone)]
42pub enum ImportScope { 43pub enum ImportScope {
43 File(ast::SourceFile), 44 File(ast::SourceFile),
44 Module(ast::ItemList), 45 Module(ast::ItemList),
46 Block(ast::BlockExpr),
45} 47}
46 48
47impl ImportScope { 49impl ImportScope {
48 pub fn from(syntax: SyntaxNode) -> Option<Self> { 50 fn from(syntax: SyntaxNode) -> Option<Self> {
49 if let Some(module) = ast::Module::cast(syntax.clone()) { 51 fn contains_cfg_attr(attrs: &dyn AttrsOwner) -> bool {
50 module.item_list().map(ImportScope::Module) 52 attrs
51 } else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) { 53 .attrs()
52 this.map(ImportScope::File) 54 .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg"))
53 } else { 55 }
54 ast::ItemList::cast(syntax).map(ImportScope::Module) 56 match_ast! {
57 match syntax {
58 ast::Module(module) => module.item_list().map(ImportScope::Module),
59 ast::SourceFile(file) => Some(ImportScope::File(file)),
60 ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().map(ImportScope::Block)).flatten(),
61 ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? {
62 ast::Expr::BlockExpr(block) => Some(block),
63 _ => None,
64 }).flatten().map(ImportScope::Block),
65 ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? {
66 ast::Expr::BlockExpr(block) => Some(block),
67 _ => None,
68 }).flatten().map(ImportScope::Block),
69 _ => None,
70
71 }
55 } 72 }
56 } 73 }
57 74
@@ -72,6 +89,7 @@ impl ImportScope {
72 match self { 89 match self {
73 ImportScope::File(file) => file.syntax(), 90 ImportScope::File(file) => file.syntax(),
74 ImportScope::Module(item_list) => item_list.syntax(), 91 ImportScope::Module(item_list) => item_list.syntax(),
92 ImportScope::Block(block) => block.syntax(),
75 } 93 }
76 } 94 }
77 95
@@ -79,6 +97,7 @@ impl ImportScope {
79 match self { 97 match self {
80 ImportScope::File(file) => ImportScope::File(file.clone_for_update()), 98 ImportScope::File(file) => ImportScope::File(file.clone_for_update()),
81 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), 99 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
100 ImportScope::Block(block) => ImportScope::Block(block.clone_for_update()),
82 } 101 }
83 } 102 }
84 103
@@ -95,6 +114,7 @@ impl ImportScope {
95 let mut use_stmts = match self { 114 let mut use_stmts = match self {
96 ImportScope::File(f) => f.items(), 115 ImportScope::File(f) => f.items(),
97 ImportScope::Module(m) => m.items(), 116 ImportScope::Module(m) => m.items(),
117 ImportScope::Block(b) => b.items(),
98 } 118 }
99 .filter_map(use_stmt); 119 .filter_map(use_stmt);
100 let mut res = ImportGranularityGuess::Unknown; 120 let mut res = ImportGranularityGuess::Unknown;
@@ -153,7 +173,7 @@ enum ImportGranularityGuess {
153} 173}
154 174
155/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 175/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
156pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { 176pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
157 let _p = profile::span("insert_use"); 177 let _p = profile::span("insert_use");
158 let mut mb = match cfg.granularity { 178 let mut mb = match cfg.granularity {
159 ImportGranularity::Crate => Some(MergeBehavior::Crate), 179 ImportGranularity::Crate => Some(MergeBehavior::Crate),
@@ -175,7 +195,10 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig
175 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); 195 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
176 // merge into existing imports if possible 196 // merge into existing imports if possible
177 if let Some(mb) = mb { 197 if let Some(mb) = mb {
178 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 198 let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it));
199 for existing_use in
200 scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter)
201 {
179 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 202 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
180 ted::replace(existing_use.syntax(), merged.syntax()); 203 ted::replace(existing_use.syntax(), merged.syntax());
181 return; 204 return;
@@ -315,28 +338,29 @@ fn insert_use_(
315 ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline()); 338 ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline());
316 return; 339 return;
317 } 340 }
318 match scope { 341 let l_curly = match scope {
319 ImportScope::File(_) => { 342 ImportScope::File(_) => {
320 cov_mark::hit!(insert_group_empty_file); 343 cov_mark::hit!(insert_group_empty_file);
321 ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line()); 344 ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
322 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()) 345 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
346 return;
323 } 347 }
348 // don't insert the imports before the item list/block expr's opening curly brace
349 ImportScope::Module(item_list) => item_list.l_curly_token(),
324 // don't insert the imports before the item list's opening curly brace 350 // don't insert the imports before the item list's opening curly brace
325 ImportScope::Module(item_list) => match item_list.l_curly_token() { 351 ImportScope::Block(block) => block.l_curly_token(),
326 Some(b) => { 352 };
327 cov_mark::hit!(insert_group_empty_module); 353 match l_curly {
328 ted::insert(ted::Position::after(&b), make::tokens::single_newline()); 354 Some(b) => {
329 ted::insert(ted::Position::after(&b), use_item.syntax()); 355 cov_mark::hit!(insert_group_empty_module);
330 } 356 ted::insert(ted::Position::after(&b), make::tokens::single_newline());
331 None => { 357 ted::insert(ted::Position::after(&b), use_item.syntax());
332 // This should never happens, broken module syntax node 358 }
333 ted::insert( 359 None => {
334 ted::Position::first_child_of(scope_syntax), 360 // This should never happens, broken module syntax node
335 make::tokens::blank_line(), 361 ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line());
336 ); 362 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax());
337 ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()); 363 }
338 }
339 },
340 } 364 }
341} 365}
342 366
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 70b11bf81..01894630a 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -1,12 +1,63 @@
1use super::*; 1use super::*;
2 2
3use hir::PrefixKind; 3use hir::PrefixKind;
4use test_utils::assert_eq_text; 4use test_utils::{assert_eq_text, extract_range_or_offset, CURSOR_MARKER};
5
6#[test]
7fn respects_cfg_attr_fn() {
8 check(
9 r"bar::Bar",
10 r#"
11#[cfg(test)]
12fn foo() {$0}
13"#,
14 r#"
15#[cfg(test)]
16fn foo() {
17use bar::Bar;
18}
19"#,
20 ImportGranularity::Crate,
21 );
22}
23
24#[test]
25fn respects_cfg_attr_const() {
26 check(
27 r"bar::Bar",
28 r#"
29#[cfg(test)]
30const FOO: Bar = {$0};
31"#,
32 r#"
33#[cfg(test)]
34const FOO: Bar = {
35use bar::Bar;
36};
37"#,
38 ImportGranularity::Crate,
39 );
40}
41
42#[test]
43fn insert_skips_lone_glob_imports() {
44 check(
45 "use foo::baz::A",
46 r"
47use foo::bar::*;
48",
49 r"
50use foo::bar::*;
51use foo::baz::A;
52",
53 ImportGranularity::Crate,
54 );
55}
5 56
6#[test] 57#[test]
7fn insert_not_group() { 58fn insert_not_group() {
8 cov_mark::check!(insert_no_grouping_last); 59 cov_mark::check!(insert_no_grouping_last);
9 check( 60 check_with_config(
10 "use external_crate2::bar::A", 61 "use external_crate2::bar::A",
11 r" 62 r"
12use std::bar::B; 63use std::bar::B;
@@ -21,24 +72,32 @@ use crate::bar::A;
21use self::bar::A; 72use self::bar::A;
22use super::bar::A; 73use super::bar::A;
23use external_crate2::bar::A;", 74use external_crate2::bar::A;",
24 ImportGranularity::Item, 75 &InsertUseConfig {
25 false, 76 granularity: ImportGranularity::Item,
26 false, 77 enforce_granularity: true,
78 prefix_kind: PrefixKind::Plain,
79 group: false,
80 skip_glob_imports: true,
81 },
27 ); 82 );
28} 83}
29 84
30#[test] 85#[test]
31fn insert_not_group_empty() { 86fn insert_not_group_empty() {
32 cov_mark::check!(insert_no_grouping_last2); 87 cov_mark::check!(insert_no_grouping_last2);
33 check( 88 check_with_config(
34 "use external_crate2::bar::A", 89 "use external_crate2::bar::A",
35 r"", 90 r"",
36 r"use external_crate2::bar::A; 91 r"use external_crate2::bar::A;
37 92
38", 93",
39 ImportGranularity::Item, 94 &InsertUseConfig {
40 false, 95 granularity: ImportGranularity::Item,
41 false, 96 enforce_granularity: true,
97 prefix_kind: PrefixKind::Plain,
98 group: false,
99 skip_glob_imports: true,
100 },
42 ); 101 );
43} 102}
44 103
@@ -277,13 +336,15 @@ fn insert_empty_module() {
277 cov_mark::check!(insert_group_empty_module); 336 cov_mark::check!(insert_group_empty_module);
278 check( 337 check(
279 "foo::bar", 338 "foo::bar",
280 "mod x {}", 339 r"
281 r"{ 340mod x {$0}
341",
342 r"
343mod x {
282 use foo::bar; 344 use foo::bar;
283}", 345}
346",
284 ImportGranularity::Item, 347 ImportGranularity::Item,
285 true,
286 true,
287 ) 348 )
288} 349}
289 350
@@ -511,13 +572,14 @@ use std::io;
511} 572}
512 573
513#[test] 574#[test]
514#[ignore] // FIXME: Support this
515fn split_out_merge() { 575fn split_out_merge() {
576 // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}`
577 // instead.
516 check_module( 578 check_module(
517 "std::fmt::Result", 579 "std::fmt::Result",
518 r"use std::{fmt, io};", 580 r"use std::{fmt, io};",
519 r"use std::fmt::{self, Result}; 581 r"use std::fmt::Result;
520use std::io;", 582use std::{fmt, io};",
521 ) 583 )
522} 584}
523 585
@@ -533,17 +595,35 @@ fn merge_groups_self() {
533 595
534#[test] 596#[test]
535fn merge_mod_into_glob() { 597fn merge_mod_into_glob() {
536 check_crate( 598 check_with_config(
537 "token::TokenKind", 599 "token::TokenKind",
538 r"use token::TokenKind::*;", 600 r"use token::TokenKind::*;",
539 r"use token::TokenKind::{*, self};", 601 r"use token::TokenKind::{*, self};",
602 &InsertUseConfig {
603 granularity: ImportGranularity::Crate,
604 enforce_granularity: true,
605 prefix_kind: PrefixKind::Plain,
606 group: false,
607 skip_glob_imports: false,
608 },
540 ) 609 )
541 // FIXME: have it emit `use token::TokenKind::{self, *}`? 610 // FIXME: have it emit `use token::TokenKind::{self, *}`?
542} 611}
543 612
544#[test] 613#[test]
545fn merge_self_glob() { 614fn merge_self_glob() {
546 check_crate("self", r"use self::*;", r"use self::{*, self};") 615 check_with_config(
616 "self",
617 r"use self::*;",
618 r"use self::{*, self};",
619 &InsertUseConfig {
620 granularity: ImportGranularity::Crate,
621 enforce_granularity: true,
622 prefix_kind: PrefixKind::Plain,
623 group: false,
624 skip_glob_imports: false,
625 },
626 )
547 // FIXME: have it emit `use {self, *}`? 627 // FIXME: have it emit `use {self, *}`?
548} 628}
549 629
@@ -756,19 +836,24 @@ use foo::bar::qux;
756 ); 836 );
757} 837}
758 838
759fn check( 839fn check_with_config(
760 path: &str, 840 path: &str,
761 ra_fixture_before: &str, 841 ra_fixture_before: &str,
762 ra_fixture_after: &str, 842 ra_fixture_after: &str,
763 granularity: ImportGranularity, 843 config: &InsertUseConfig,
764 module: bool,
765 group: bool,
766) { 844) {
767 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); 845 let (text, pos) = if ra_fixture_before.contains(CURSOR_MARKER) {
768 if module { 846 let (range_or_offset, text) = extract_range_or_offset(ra_fixture_before);
769 syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone(); 847 (text, Some(range_or_offset))
770 } 848 } else {
771 let file = super::ImportScope::from(syntax.clone_for_update()).unwrap(); 849 (ra_fixture_before.to_owned(), None)
850 };
851 let syntax = ast::SourceFile::parse(&text).tree().syntax().clone_for_update();
852 let file = pos
853 .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent())
854 .and_then(|it| super::ImportScope::find_insert_use_container(&it))
855 .or_else(|| super::ImportScope::from(syntax))
856 .unwrap();
772 let path = ast::SourceFile::parse(&format!("use {};", path)) 857 let path = ast::SourceFile::parse(&format!("use {};", path))
773 .tree() 858 .tree()
774 .syntax() 859 .syntax()
@@ -776,30 +861,41 @@ fn check(
776 .find_map(ast::Path::cast) 861 .find_map(ast::Path::cast)
777 .unwrap(); 862 .unwrap();
778 863
779 insert_use( 864 insert_use(&file, path, config);
780 &file, 865 let result = file.as_syntax_node().ancestors().last().unwrap().to_string();
866 assert_eq_text!(ra_fixture_after, &result);
867}
868
869fn check(
870 path: &str,
871 ra_fixture_before: &str,
872 ra_fixture_after: &str,
873 granularity: ImportGranularity,
874) {
875 check_with_config(
781 path, 876 path,
782 InsertUseConfig { 877 ra_fixture_before,
878 ra_fixture_after,
879 &InsertUseConfig {
783 granularity, 880 granularity,
784 enforce_granularity: true, 881 enforce_granularity: true,
785 prefix_kind: PrefixKind::Plain, 882 prefix_kind: PrefixKind::Plain,
786 group, 883 group: true,
884 skip_glob_imports: true,
787 }, 885 },
788 ); 886 )
789 let result = file.as_syntax_node().to_string();
790 assert_eq_text!(ra_fixture_after, &result);
791} 887}
792 888
793fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 889fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
794 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate, false, true) 890 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate)
795} 891}
796 892
797fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 893fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
798 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module, false, true) 894 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module)
799} 895}
800 896
801fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 897fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
802 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item, false, true) 898 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item)
803} 899}
804 900
805fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { 901fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 105607dca..bde8767dd 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -3,17 +3,21 @@
3//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. 3//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
4 4
5mod apply_change; 5mod apply_change;
6pub mod assists;
6pub mod label; 7pub mod label;
7pub mod line_index; 8pub mod line_index;
8pub mod symbol_index; 9pub mod symbol_index;
9pub mod defs; 10pub mod defs;
10pub mod search;
11pub mod items_locator; 11pub mod items_locator;
12pub mod source_change; 12pub mod source_change;
13pub mod ty_filter; 13pub mod ty_filter;
14pub mod traits; 14pub mod traits;
15pub mod call_info; 15pub mod call_info;
16pub mod helpers; 16pub mod helpers;
17pub mod path_transform;
18
19pub mod search;
20pub mod rename;
17 21
18use std::{fmt, sync::Arc}; 22use std::{fmt, sync::Arc};
19 23
diff --git a/crates/ide_assists/src/path_transform.rs b/crates/ide_db/src/path_transform.rs
index 48a7fa06a..f3d7aa920 100644
--- a/crates/ide_assists/src/path_transform.rs
+++ b/crates/ide_db/src/path_transform.rs
@@ -1,7 +1,7 @@
1//! See [`PathTransform`]. 1//! See [`PathTransform`].
2 2
3use crate::helpers::mod_path_to_ast;
3use hir::{HirDisplay, SemanticsScope}; 4use hir::{HirDisplay, SemanticsScope};
4use ide_db::helpers::mod_path_to_ast;
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6use syntax::{ 6use syntax::{
7 ast::{self, AstNode}, 7 ast::{self, AstNode},
@@ -31,14 +31,14 @@ use syntax::{
31/// } 31/// }
32/// } 32/// }
33/// ``` 33/// ```
34pub(crate) struct PathTransform<'a> { 34pub struct PathTransform<'a> {
35 pub(crate) subst: (hir::Trait, ast::Impl), 35 pub subst: (hir::Trait, ast::Impl),
36 pub(crate) target_scope: &'a SemanticsScope<'a>, 36 pub target_scope: &'a SemanticsScope<'a>,
37 pub(crate) source_scope: &'a SemanticsScope<'a>, 37 pub source_scope: &'a SemanticsScope<'a>,
38} 38}
39 39
40impl<'a> PathTransform<'a> { 40impl<'a> PathTransform<'a> {
41 pub(crate) fn apply(&self, item: ast::AssocItem) { 41 pub fn apply(&self, item: ast::AssocItem) {
42 if let Some(ctx) = self.build_ctx() { 42 if let Some(ctx) = self.build_ctx() {
43 ctx.apply(item) 43 ctx.apply(item)
44 } 44 }
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs
new file mode 100644
index 000000000..643e67781
--- /dev/null
+++ b/crates/ide_db/src/rename.rs
@@ -0,0 +1,468 @@
1//! Rename infrastructure for rust-analyzer. It is used primarily for the
2//! literal "rename" in the ide (look for tests there), but it is also available
3//! as a general-purpose service. For example, it is used by the fix for the
4//! "incorrect case" diagnostic.
5//!
6//! It leverages the [`crate::search`] functionality to find what needs to be
7//! renamed. The actual renames are tricky -- field shorthands need special
8//! attention, and, when renaming modules, you also want to rename files on the
9//! file system.
10//!
11//! Another can of worms are macros:
12//!
13//! ```
14//! macro_rules! m { () => { fn f() {} } }
15//! m!();
16//! fn main() {
17//! f() // <- rename me
18//! }
19//! ```
20//!
21//! The correct behavior in such cases is probably to show a dialog to the user.
22//! Our current behavior is ¯\_(ツ)_/¯.
23use std::fmt;
24
25use base_db::{AnchoredPathBuf, FileId, FileRange};
26use either::Either;
27use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics};
28use stdx::never;
29use syntax::{
30 ast::{self, NameOwner},
31 lex_single_syntax_kind, AstNode, SyntaxKind, TextRange, T,
32};
33use text_edit::TextEdit;
34
35use crate::{
36 defs::Definition,
37 search::FileReference,
38 source_change::{FileSystemEdit, SourceChange},
39 RootDatabase,
40};
41
42pub type Result<T, E = RenameError> = std::result::Result<T, E>;
43
44#[derive(Debug)]
45pub struct RenameError(pub String);
46
47impl fmt::Display for RenameError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 fmt::Display::fmt(&self.0, f)
50 }
51}
52
53#[macro_export]
54macro_rules! _format_err {
55 ($fmt:expr) => { RenameError(format!($fmt)) };
56 ($fmt:expr, $($arg:tt)+) => { RenameError(format!($fmt, $($arg)+)) }
57}
58pub use _format_err as format_err;
59
60#[macro_export]
61macro_rules! _bail {
62 ($($tokens:tt)*) => { return Err(format_err!($($tokens)*)) }
63}
64pub use _bail as bail;
65
66impl Definition {
67 pub fn rename(&self, sema: &Semantics<RootDatabase>, new_name: &str) -> Result<SourceChange> {
68 match *self {
69 Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
70 rename_mod(sema, module, new_name)
71 }
72 Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
73 bail!("Cannot rename builtin type")
74 }
75 Definition::SelfType(_) => bail!("Cannot rename `Self`"),
76 def => rename_reference(sema, def, new_name),
77 }
78 }
79
80 /// Textual range of the identifier which will change when renaming this
81 /// `Definition`. Note that some definitions, like buitin types, can't be
82 /// renamed.
83 pub fn range_for_rename(self, sema: &Semantics<RootDatabase>) -> Option<FileRange> {
84 // FIXME: the `original_file_range` calls here are wrong -- they never fail,
85 // and _fall back_ to the entirety of the macro call. Such fall back is
86 // incorrect for renames. The safe behavior would be to return an error for
87 // such cases. The correct behavior would be to return an auxiliary list of
88 // "can't rename these occurrences in macros" items, and then show some kind
89 // of a dialog to the user. See:
90 cov_mark::hit!(macros_are_broken_lol);
91
92 let res = match self {
93 Definition::Macro(mac) => {
94 let src = mac.source(sema.db)?;
95 let name = match &src.value {
96 Either::Left(it) => it.name()?,
97 Either::Right(it) => it.name()?,
98 };
99 src.with_value(name.syntax()).original_file_range(sema.db)
100 }
101 Definition::Field(field) => {
102 let src = field.source(sema.db)?;
103
104 match &src.value {
105 FieldSource::Named(record_field) => {
106 let name = record_field.name()?;
107 src.with_value(name.syntax()).original_file_range(sema.db)
108 }
109 FieldSource::Pos(_) => {
110 return None;
111 }
112 }
113 }
114 Definition::ModuleDef(module_def) => match module_def {
115 hir::ModuleDef::Module(module) => {
116 let src = module.declaration_source(sema.db)?;
117 let name = src.value.name()?;
118 src.with_value(name.syntax()).original_file_range(sema.db)
119 }
120 hir::ModuleDef::Function(it) => name_range(it, sema)?,
121 hir::ModuleDef::Adt(adt) => match adt {
122 hir::Adt::Struct(it) => name_range(it, sema)?,
123 hir::Adt::Union(it) => name_range(it, sema)?,
124 hir::Adt::Enum(it) => name_range(it, sema)?,
125 },
126 hir::ModuleDef::Variant(it) => name_range(it, sema)?,
127 hir::ModuleDef::Const(it) => name_range(it, sema)?,
128 hir::ModuleDef::Static(it) => name_range(it, sema)?,
129 hir::ModuleDef::Trait(it) => name_range(it, sema)?,
130 hir::ModuleDef::TypeAlias(it) => name_range(it, sema)?,
131 hir::ModuleDef::BuiltinType(_) => return None,
132 },
133 Definition::SelfType(_) => return None,
134 Definition::Local(local) => {
135 let src = local.source(sema.db);
136 let name = match &src.value {
137 Either::Left(bind_pat) => bind_pat.name()?,
138 Either::Right(_) => return None,
139 };
140 src.with_value(name.syntax()).original_file_range(sema.db)
141 }
142 Definition::GenericParam(generic_param) => match generic_param {
143 hir::GenericParam::TypeParam(type_param) => {
144 let src = type_param.source(sema.db)?;
145 let name = match &src.value {
146 Either::Left(type_param) => type_param.name()?,
147 Either::Right(_trait) => return None,
148 };
149 src.with_value(name.syntax()).original_file_range(sema.db)
150 }
151 hir::GenericParam::LifetimeParam(lifetime_param) => {
152 let src = lifetime_param.source(sema.db)?;
153 let lifetime = src.value.lifetime()?;
154 src.with_value(lifetime.syntax()).original_file_range(sema.db)
155 }
156 hir::GenericParam::ConstParam(it) => name_range(it, sema)?,
157 },
158 Definition::Label(label) => {
159 let src = label.source(sema.db);
160 let lifetime = src.value.lifetime()?;
161 src.with_value(lifetime.syntax()).original_file_range(sema.db)
162 }
163 };
164 return Some(res);
165
166 fn name_range<D>(def: D, sema: &Semantics<RootDatabase>) -> Option<FileRange>
167 where
168 D: HasSource,
169 D::Ast: ast::NameOwner,
170 {
171 let src = def.source(sema.db)?;
172 let name = src.value.name()?;
173 let res = src.with_value(name.syntax()).original_file_range(sema.db);
174 Some(res)
175 }
176 }
177}
178
179fn rename_mod(
180 sema: &Semantics<RootDatabase>,
181 module: hir::Module,
182 new_name: &str,
183) -> Result<SourceChange> {
184 if IdentifierKind::classify(new_name)? != IdentifierKind::Ident {
185 bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
186 }
187
188 let mut source_change = SourceChange::default();
189
190 let InFile { file_id, value: def_source } = module.definition_source(sema.db);
191 let file_id = file_id.original_file(sema.db);
192 if let ModuleSource::SourceFile(..) = def_source {
193 // mod is defined in path/to/dir/mod.rs
194 let path = if module.is_mod_rs(sema.db) {
195 format!("../{}/mod.rs", new_name)
196 } else {
197 format!("{}.rs", new_name)
198 };
199 let dst = AnchoredPathBuf { anchor: file_id, path };
200 let move_file = FileSystemEdit::MoveFile { src: file_id, dst };
201 source_change.push_file_system_edit(move_file);
202 }
203
204 if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) {
205 let file_id = file_id.original_file(sema.db);
206 match decl_source.name() {
207 Some(name) => source_change.insert_source_edit(
208 file_id,
209 TextEdit::replace(name.syntax().text_range(), new_name.to_string()),
210 ),
211 _ => never!("Module source node is missing a name"),
212 }
213 }
214 let def = Definition::ModuleDef(hir::ModuleDef::Module(module));
215 let usages = def.usages(sema).all();
216 let ref_edits = usages.iter().map(|(&file_id, references)| {
217 (file_id, source_edit_from_references(references, def, new_name))
218 });
219 source_change.extend(ref_edits);
220
221 Ok(source_change)
222}
223
224fn rename_reference(
225 sema: &Semantics<RootDatabase>,
226 mut def: Definition,
227 new_name: &str,
228) -> Result<SourceChange> {
229 let ident_kind = IdentifierKind::classify(new_name)?;
230
231 if matches!(
232 def, // is target a lifetime?
233 Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
234 ) {
235 match ident_kind {
236 IdentifierKind::Ident | IdentifierKind::Underscore => {
237 cov_mark::hit!(rename_not_a_lifetime_ident_ref);
238 bail!("Invalid name `{}`: not a lifetime identifier", new_name);
239 }
240 IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
241 }
242 } else {
243 match (ident_kind, def) {
244 (IdentifierKind::Lifetime, _) => {
245 cov_mark::hit!(rename_not_an_ident_ref);
246 bail!("Invalid name `{}`: not an identifier", new_name);
247 }
248 (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local),
249 (IdentifierKind::Underscore, _) => (),
250 }
251 }
252
253 def = match def {
254 // HACK: resolve trait impl items to the item def of the trait definition
255 // so that we properly resolve all trait item references
256 Definition::ModuleDef(mod_def) => mod_def
257 .as_assoc_item(sema.db)
258 .and_then(|it| it.containing_trait_impl(sema.db))
259 .and_then(|it| {
260 it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) {
261 (hir::AssocItem::Function(trait_func), hir::ModuleDef::Function(func))
262 if trait_func.name(sema.db) == func.name(sema.db) =>
263 {
264 Some(Definition::ModuleDef(hir::ModuleDef::Function(trait_func)))
265 }
266 (hir::AssocItem::Const(trait_konst), hir::ModuleDef::Const(konst))
267 if trait_konst.name(sema.db) == konst.name(sema.db) =>
268 {
269 Some(Definition::ModuleDef(hir::ModuleDef::Const(trait_konst)))
270 }
271 (
272 hir::AssocItem::TypeAlias(trait_type_alias),
273 hir::ModuleDef::TypeAlias(type_alias),
274 ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => {
275 Some(Definition::ModuleDef(hir::ModuleDef::TypeAlias(trait_type_alias)))
276 }
277 _ => None,
278 })
279 })
280 .unwrap_or(def),
281 _ => def,
282 };
283 let usages = def.usages(sema).all();
284
285 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
286 cov_mark::hit!(rename_underscore_multiple);
287 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
288 }
289 let mut source_change = SourceChange::default();
290 source_change.extend(usages.iter().map(|(&file_id, references)| {
291 (file_id, source_edit_from_references(references, def, new_name))
292 }));
293
294 let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
295 source_change.insert_source_edit(file_id, edit);
296 Ok(source_change)
297}
298
299pub fn source_edit_from_references(
300 references: &[FileReference],
301 def: Definition,
302 new_name: &str,
303) -> TextEdit {
304 let mut edit = TextEdit::builder();
305 for reference in references {
306 let (range, replacement) = match &reference.name {
307 // if the ranges differ then the node is inside a macro call, we can't really attempt
308 // to make special rewrites like shorthand syntax and such, so just rename the node in
309 // the macro input
310 ast::NameLike::NameRef(name_ref)
311 if name_ref.syntax().text_range() == reference.range =>
312 {
313 source_edit_from_name_ref(name_ref, new_name, def)
314 }
315 ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => {
316 source_edit_from_name(name, new_name)
317 }
318 _ => None,
319 }
320 .unwrap_or_else(|| (reference.range, new_name.to_string()));
321 edit.replace(range, replacement);
322 }
323 edit.finish()
324}
325
326fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> {
327 if let Some(_) = ast::RecordPatField::for_field_name(name) {
328 if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
329 return Some((
330 TextRange::empty(ident_pat.syntax().text_range().start()),
331 [new_name, ": "].concat(),
332 ));
333 }
334 }
335 None
336}
337
338fn source_edit_from_name_ref(
339 name_ref: &ast::NameRef,
340 new_name: &str,
341 def: Definition,
342) -> Option<(TextRange, String)> {
343 if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
344 let rcf_name_ref = record_field.name_ref();
345 let rcf_expr = record_field.expr();
346 match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) {
347 // field: init-expr, check if we can use a field init shorthand
348 (Some(field_name), Some(init)) => {
349 if field_name == *name_ref {
350 if init.text() == new_name {
351 cov_mark::hit!(test_rename_field_put_init_shorthand);
352 // same names, we can use a shorthand here instead.
353 // we do not want to erase attributes hence this range start
354 let s = field_name.syntax().text_range().start();
355 let e = record_field.syntax().text_range().end();
356 return Some((TextRange::new(s, e), new_name.to_owned()));
357 }
358 } else if init == *name_ref {
359 if field_name.text() == new_name {
360 cov_mark::hit!(test_rename_local_put_init_shorthand);
361 // same names, we can use a shorthand here instead.
362 // we do not want to erase attributes hence this range start
363 let s = field_name.syntax().text_range().start();
364 let e = record_field.syntax().text_range().end();
365 return Some((TextRange::new(s, e), new_name.to_owned()));
366 }
367 }
368 None
369 }
370 // init shorthand
371 // FIXME: instead of splitting the shorthand, recursively trigger a rename of the
372 // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
373 (None, Some(_)) if matches!(def, Definition::Field(_)) => {
374 cov_mark::hit!(test_rename_field_in_field_shorthand);
375 let s = name_ref.syntax().text_range().start();
376 Some((TextRange::empty(s), format!("{}: ", new_name)))
377 }
378 (None, Some(_)) if matches!(def, Definition::Local(_)) => {
379 cov_mark::hit!(test_rename_local_in_field_shorthand);
380 let s = name_ref.syntax().text_range().end();
381 Some((TextRange::empty(s), format!(": {}", new_name)))
382 }
383 _ => None,
384 }
385 } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) {
386 let rcf_name_ref = record_field.name_ref();
387 let rcf_pat = record_field.pat();
388 match (rcf_name_ref, rcf_pat) {
389 // field: rename
390 (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => {
391 // field name is being renamed
392 if pat.name().map_or(false, |it| it.text() == new_name) {
393 cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
394 // same names, we can use a shorthand here instead/
395 // we do not want to erase attributes hence this range start
396 let s = field_name.syntax().text_range().start();
397 let e = record_field.syntax().text_range().end();
398 Some((TextRange::new(s, e), pat.to_string()))
399 } else {
400 None
401 }
402 }
403 _ => None,
404 }
405 } else {
406 None
407 }
408}
409
410fn source_edit_from_def(
411 sema: &Semantics<RootDatabase>,
412 def: Definition,
413 new_name: &str,
414) -> Result<(FileId, TextEdit)> {
415 let frange = def
416 .range_for_rename(sema)
417 .ok_or_else(|| format_err!("No identifier available to rename"))?;
418
419 let mut replacement_text = String::new();
420 let mut repl_range = frange.range;
421 if let Definition::Local(local) = def {
422 if let Either::Left(pat) = local.source(sema.db).value {
423 if matches!(
424 pat.syntax().parent().and_then(ast::RecordPatField::cast),
425 Some(pat_field) if pat_field.name_ref().is_none()
426 ) {
427 replacement_text.push_str(": ");
428 replacement_text.push_str(new_name);
429 repl_range = TextRange::new(
430 pat.syntax().text_range().end(),
431 pat.syntax().text_range().end(),
432 );
433 }
434 }
435 }
436 if replacement_text.is_empty() {
437 replacement_text.push_str(new_name);
438 }
439 let edit = TextEdit::replace(repl_range, replacement_text);
440 Ok((frange.file_id, edit))
441}
442
443#[derive(Copy, Clone, Debug, PartialEq)]
444pub enum IdentifierKind {
445 Ident,
446 Lifetime,
447 Underscore,
448}
449
450impl IdentifierKind {
451 pub fn classify(new_name: &str) -> Result<IdentifierKind> {
452 match lex_single_syntax_kind(new_name) {
453 Some(res) => match res {
454 (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident),
455 (T![_], _) => Ok(IdentifierKind::Underscore),
456 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
457 Ok(IdentifierKind::Lifetime)
458 }
459 (SyntaxKind::LIFETIME_IDENT, _) => {
460 bail!("Invalid name `{}`: not a lifetime identifier", new_name)
461 }
462 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
463 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
464 },
465 None => bail!("Invalid name `{}`: not an identifier", new_name),
466 }
467 }
468}
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml
new file mode 100644
index 000000000..fa2adf212
--- /dev/null
+++ b/crates/ide_diagnostics/Cargo.toml
@@ -0,0 +1,29 @@
1[package]
2name = "ide_diagnostics"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0"
15rustc-hash = "1.1.0"
16either = "1.5.3"
17
18profile = { path = "../profile", version = "0.0.0" }
19stdx = { path = "../stdx", version = "0.0.0" }
20syntax = { path = "../syntax", version = "0.0.0" }
21text_edit = { path = "../text_edit", version = "0.0.0" }
22cfg = { path = "../cfg", version = "0.0.0" }
23hir = { path = "../hir", version = "0.0.0" }
24ide_db = { path = "../ide_db", version = "0.0.0" }
25
26[dev-dependencies]
27expect-test = "1.1"
28
29test_utils = { path = "../test_utils" }
diff --git a/crates/ide/src/diagnostics/break_outside_of_loop.rs b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs
index 80e68f3cc..d12594a4c 100644
--- a/crates/ide/src/diagnostics/break_outside_of_loop.rs
+++ b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs
@@ -1,9 +1,9 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: break-outside-of-loop 3// Diagnostic: break-outside-of-loop
4// 4//
5// This diagnostic is triggered if the `break` keyword is used outside of a loop. 5// This diagnostic is triggered if the `break` keyword is used outside of a loop.
6pub(super) fn break_outside_of_loop( 6pub(crate) fn break_outside_of_loop(
7 ctx: &DiagnosticsContext<'_>, 7 ctx: &DiagnosticsContext<'_>,
8 d: &hir::BreakOutsideOfLoop, 8 d: &hir::BreakOutsideOfLoop,
9) -> Diagnostic { 9) -> Diagnostic {
@@ -16,14 +16,14 @@ pub(super) fn break_outside_of_loop(
16 16
17#[cfg(test)] 17#[cfg(test)]
18mod tests { 18mod tests {
19 use crate::diagnostics::tests::check_diagnostics; 19 use crate::tests::check_diagnostics;
20 20
21 #[test] 21 #[test]
22 fn break_outside_of_loop() { 22 fn break_outside_of_loop() {
23 check_diagnostics( 23 check_diagnostics(
24 r#" 24 r#"
25fn foo() { break; } 25fn foo() { break; }
26 //^^^^^ break outside of loop 26 //^^^^^ error: break outside of loop
27"#, 27"#,
28 ); 28 );
29 } 29 }
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
index c7f4dab8e..33152e284 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
@@ -5,9 +5,9 @@ use ide_db::{base_db::FileId, source_change::SourceChange};
5use syntax::{ast, match_ast, AstNode, SyntaxNode}; 5use syntax::{ast, match_ast, AstNode, SyntaxNode};
6use text_edit::TextEdit; 6use text_edit::TextEdit;
7 7
8use crate::{diagnostics::fix, Diagnostic, Severity}; 8use crate::{fix, Diagnostic, Severity};
9 9
10pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { 10pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
11 match_ast! { 11 match_ast! {
12 match node { 12 match node {
13 ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), 13 ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it),
@@ -101,7 +101,7 @@ fn check_pat_field_shorthand(
101 101
102#[cfg(test)] 102#[cfg(test)]
103mod tests { 103mod tests {
104 use crate::diagnostics::tests::{check_diagnostics, check_fix}; 104 use crate::tests::{check_diagnostics, check_fix};
105 105
106 #[test] 106 #[test]
107 fn test_check_expr_field_shorthand() { 107 fn test_check_expr_field_shorthand() {
diff --git a/crates/ide/src/diagnostics/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs
index d9d3e88c1..dfd0e3351 100644
--- a/crates/ide/src/diagnostics/inactive_code.rs
+++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs
@@ -1,15 +1,12 @@
1use cfg::DnfExpr; 1use cfg::DnfExpr;
2use stdx::format_to; 2use stdx::format_to;
3 3
4use crate::{ 4use crate::{Diagnostic, DiagnosticsContext, Severity};
5 diagnostics::{Diagnostic, DiagnosticsContext},
6 Severity,
7};
8 5
9// Diagnostic: inactive-code 6// Diagnostic: inactive-code
10// 7//
11// This diagnostic is shown for code with inactive `#[cfg]` attributes. 8// This diagnostic is shown for code with inactive `#[cfg]` attributes.
12pub(super) fn inactive_code( 9pub(crate) fn inactive_code(
13 ctx: &DiagnosticsContext<'_>, 10 ctx: &DiagnosticsContext<'_>,
14 d: &hir::InactiveCode, 11 d: &hir::InactiveCode,
15) -> Option<Diagnostic> { 12) -> Option<Diagnostic> {
@@ -37,7 +34,7 @@ pub(super) fn inactive_code(
37 34
38#[cfg(test)] 35#[cfg(test)]
39mod tests { 36mod tests {
40 use crate::{diagnostics::tests::check_diagnostics_with_config, DiagnosticsConfig}; 37 use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};
41 38
42 pub(crate) fn check(ra_fixture: &str) { 39 pub(crate) fn check(ra_fixture: &str) {
43 let config = DiagnosticsConfig::default(); 40 let config = DiagnosticsConfig::default();
@@ -52,26 +49,26 @@ fn f() {
52 // The three g̶e̶n̶d̶e̶r̶s̶ statements: 49 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
53 50
54 #[cfg(a)] fn f() {} // Item statement 51 #[cfg(a)] fn f() {} // Item statement
55 //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 52 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
56 #[cfg(a)] {} // Expression statement 53 #[cfg(a)] {} // Expression statement
57 //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 54 //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
58 #[cfg(a)] let x = 0; // let statement 55 #[cfg(a)] let x = 0; // let statement
59 //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 56 //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
60 57
61 abc(#[cfg(a)] 0); 58 abc(#[cfg(a)] 0);
62 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 59 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
63 let x = Struct { 60 let x = Struct {
64 #[cfg(a)] f: 0, 61 #[cfg(a)] f: 0,
65 //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 62 //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
66 }; 63 };
67 match () { 64 match () {
68 () => (), 65 () => (),
69 #[cfg(a)] () => (), 66 #[cfg(a)] () => (),
70 //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 67 //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
71 } 68 }
72 69
73 #[cfg(a)] 0 // Trailing expression of block 70 #[cfg(a)] 0 // Trailing expression of block
74 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 71 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
75} 72}
76 "#, 73 "#,
77 ); 74 );
@@ -84,16 +81,16 @@ fn f() {
84 check( 81 check(
85 r#" 82 r#"
86 #[cfg(no)] pub fn f() {} 83 #[cfg(no)] pub fn f() {}
87 //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 84 //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
88 85
89 #[cfg(no)] #[cfg(no2)] mod m; 86 #[cfg(no)] #[cfg(no2)] mod m;
90 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled 87 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled
91 88
92 #[cfg(all(not(a), b))] enum E {} 89 #[cfg(all(not(a), b))] enum E {}
93 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled 90 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled
94 91
95 #[cfg(feature = "std")] use std; 92 #[cfg(feature = "std")] use std;
96 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled 93 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled
97"#, 94"#,
98 ); 95 );
99 } 96 }
@@ -105,14 +102,14 @@ fn f() {
105 check( 102 check(
106 r#" 103 r#"
107 #[cfg_attr(not(never), cfg(no))] fn f() {} 104 #[cfg_attr(not(never), cfg(no))] fn f() {}
108 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 105 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
109 106
110 #[cfg_attr(not(never), cfg(not(no)))] fn f() {} 107 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
111 108
112 #[cfg_attr(never, cfg(no))] fn g() {} 109 #[cfg_attr(never, cfg(no))] fn g() {}
113 110
114 #[cfg_attr(not(never), inline, cfg(no))] fn h() {} 111 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
115 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
116"#, 113"#,
117 ); 114 );
118 } 115 }
diff --git a/crates/ide/src/diagnostics/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index 832394400..68f25f284 100644
--- a/crates/ide/src/diagnostics/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -1,18 +1,19 @@
1use hir::{db::AstDatabase, InFile}; 1use hir::{db::AstDatabase, InFile};
2use ide_assists::Assist; 2use ide_db::{assists::Assist, defs::NameClass};
3use ide_db::base_db::FilePosition;
4use syntax::AstNode; 3use syntax::AstNode;
5 4
6use crate::{ 5use crate::{
7 diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext}, 6 // references::rename::rename_with_semantics,
8 references::rename::rename_with_semantics, 7 unresolved_fix,
8 Diagnostic,
9 DiagnosticsContext,
9 Severity, 10 Severity,
10}; 11};
11 12
12// Diagnostic: incorrect-ident-case 13// Diagnostic: incorrect-ident-case
13// 14//
14// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. 15// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
15pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { 16pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
16 Diagnostic::new( 17 Diagnostic::new(
17 "incorrect-ident-case", 18 "incorrect-ident-case",
18 format!( 19 format!(
@@ -28,15 +29,15 @@ pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas
28fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { 29fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> {
29 let root = ctx.sema.db.parse_or_expand(d.file)?; 30 let root = ctx.sema.db.parse_or_expand(d.file)?;
30 let name_node = d.ident.to_node(&root); 31 let name_node = d.ident.to_node(&root);
32 let def = NameClass::classify(&ctx.sema, &name_node)?.defined(ctx.sema.db)?;
31 33
32 let name_node = InFile::new(d.file, name_node.syntax()); 34 let name_node = InFile::new(d.file, name_node.syntax());
33 let frange = name_node.original_file_range(ctx.sema.db); 35 let frange = name_node.original_file_range(ctx.sema.db);
34 let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
35 36
36 let label = format!("Rename to {}", d.suggested_text); 37 let label = format!("Rename to {}", d.suggested_text);
37 let mut res = unresolved_fix("change_case", &label, frange.range); 38 let mut res = unresolved_fix("change_case", &label, frange.range);
38 if ctx.resolve.should_resolve(&res.id) { 39 if ctx.resolve.should_resolve(&res.id) {
39 let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text); 40 let source_change = def.rename(&ctx.sema, &d.suggested_text);
40 res.source_change = Some(source_change.ok().unwrap_or_default()); 41 res.source_change = Some(source_change.ok().unwrap_or_default());
41 } 42 }
42 43
@@ -45,10 +46,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
45 46
46#[cfg(test)] 47#[cfg(test)]
47mod change_case { 48mod change_case {
48 use crate::{ 49 use crate::tests::{check_diagnostics, check_fix};
49 diagnostics::tests::{check_diagnostics, check_fix},
50 fixture, AssistResolveStrategy, DiagnosticsConfig,
51 };
52 50
53 #[test] 51 #[test]
54 fn test_rename_incorrect_case() { 52 fn test_rename_incorrect_case() {
@@ -116,7 +114,7 @@ fn some_fn() {
116 check_diagnostics( 114 check_diagnostics(
117 r#" 115 r#"
118fn foo() { 116fn foo() {
119 const ANOTHER_ITEM$0: &str = "some_item"; 117 const ANOTHER_ITEM: &str = "some_item";
120} 118}
121"#, 119"#,
122 ); 120 );
@@ -148,20 +146,13 @@ impl TestStruct {
148 146
149 #[test] 147 #[test]
150 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { 148 fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() {
151 let input = r#"fn FOO$0() {}"#; 149 check_diagnostics(
152 let expected = r#"fn foo() {}"#; 150 r#"
153 151fn FOO() {}
154 let (analysis, file_position) = fixture::position(input); 152// ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo`
155 let diagnostics = analysis 153"#,
156 .diagnostics( 154 );
157 &DiagnosticsConfig::default(), 155 check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#);
158 AssistResolveStrategy::All,
159 file_position.file_id,
160 )
161 .unwrap();
162 assert_eq!(diagnostics.len(), 1);
163
164 check_fix(input, expected);
165 } 156 }
166 157
167 #[test] 158 #[test]
@@ -169,7 +160,7 @@ impl TestStruct {
169 check_diagnostics( 160 check_diagnostics(
170 r#" 161 r#"
171fn NonSnakeCaseName() {} 162fn NonSnakeCaseName() {}
172// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` 163// ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
173"#, 164"#,
174 ); 165 );
175 } 166 }
@@ -179,10 +170,10 @@ fn NonSnakeCaseName() {}
179 check_diagnostics( 170 check_diagnostics(
180 r#" 171 r#"
181fn foo(SomeParam: u8) {} 172fn foo(SomeParam: u8) {}
182 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` 173 // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
183 174
184fn foo2(ok_param: &str, CAPS_PARAM: u8) {} 175fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
185 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` 176 // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
186"#, 177"#,
187 ); 178 );
188 } 179 }
@@ -193,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
193 r#" 184 r#"
194fn foo() { 185fn foo() {
195 let SOME_VALUE = 10; 186 let SOME_VALUE = 10;
196 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` 187 // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
197 let AnotherValue = 20; 188 let AnotherValue = 20;
198 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` 189 // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value`
199} 190}
200"#, 191"#,
201 ); 192 );
@@ -206,10 +197,10 @@ fn foo() {
206 check_diagnostics( 197 check_diagnostics(
207 r#" 198 r#"
208struct non_camel_case_name {} 199struct non_camel_case_name {}
209 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` 200 // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
210 201
211struct SCREAMING_CASE {} 202struct SCREAMING_CASE {}
212 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` 203 // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
213"#, 204"#,
214 ); 205 );
215 } 206 }
@@ -228,7 +219,7 @@ struct AABB {}
228 check_diagnostics( 219 check_diagnostics(
229 r#" 220 r#"
230struct SomeStruct { SomeField: u8 } 221struct SomeStruct { SomeField: u8 }
231 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` 222 // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field`
232"#, 223"#,
233 ); 224 );
234 } 225 }
@@ -238,10 +229,10 @@ struct SomeStruct { SomeField: u8 }
238 check_diagnostics( 229 check_diagnostics(
239 r#" 230 r#"
240enum some_enum { Val(u8) } 231enum some_enum { Val(u8) }
241 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` 232 // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
242 233
243enum SOME_ENUM {} 234enum SOME_ENUM {}
244 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` 235 // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
245"#, 236"#,
246 ); 237 );
247 } 238 }
@@ -260,7 +251,7 @@ enum AABB {}
260 check_diagnostics( 251 check_diagnostics(
261 r#" 252 r#"
262enum SomeEnum { SOME_VARIANT(u8) } 253enum SomeEnum { SOME_VARIANT(u8) }
263 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` 254 // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
264"#, 255"#,
265 ); 256 );
266 } 257 }
@@ -270,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) }
270 check_diagnostics( 261 check_diagnostics(
271 r#" 262 r#"
272const some_weird_const: u8 = 10; 263const some_weird_const: u8 = 10;
273 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` 264 // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
274"#, 265"#,
275 ); 266 );
276 } 267 }
@@ -280,7 +271,7 @@ const some_weird_const: u8 = 10;
280 check_diagnostics( 271 check_diagnostics(
281 r#" 272 r#"
282static some_weird_const: u8 = 10; 273static some_weird_const: u8 = 10;
283 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` 274 // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
284"#, 275"#,
285 ); 276 );
286 } 277 }
@@ -290,13 +281,13 @@ static some_weird_const: u8 = 10;
290 check_diagnostics( 281 check_diagnostics(
291 r#" 282 r#"
292struct someStruct; 283struct someStruct;
293 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` 284 // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
294 285
295impl someStruct { 286impl someStruct {
296 fn SomeFunc(&self) { 287 fn SomeFunc(&self) {
297 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` 288 // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func`
298 let WHY_VAR_IS_CAPS = 10; 289 let WHY_VAR_IS_CAPS = 10;
299 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` 290 // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
300 } 291 }
301} 292}
302"#, 293"#,
@@ -328,7 +319,7 @@ enum Option { Some, None }
328fn main() { 319fn main() {
329 match Option::None { 320 match Option::None {
330 SOME_VAR @ None => (), 321 SOME_VAR @ None => (),
331 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` 322 // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
332 Some => (), 323 Some => (),
333 } 324 }
334} 325}
@@ -350,43 +341,27 @@ mod F {
350 } 341 }
351 342
352 #[test] 343 #[test]
353 #[ignore] 344 fn complex_ignore() {
354 fn bug_trait_inside_fn() { 345 // FIXME: this should trigger errors for the second case.
355 // FIXME:
356 // This is broken, and in fact, should not even be looked at by this
357 // lint in the first place. There's weird stuff going on in the
358 // collection phase.
359 // It's currently being brought in by:
360 // * validate_func on `a` recursing into modules
361 // * then it finds the trait and then the function while iterating
362 // through modules
363 // * then validate_func is called on Dirty
364 // * ... which then proceeds to look at some unknown module taking no
365 // attrs from either the impl or the fn a, and then finally to the root
366 // module
367 //
368 // It should find the attribute on the trait, but it *doesn't even see
369 // the trait* as far as I can tell.
370
371 check_diagnostics( 346 check_diagnostics(
372 r#" 347 r#"
373trait T { fn a(); } 348trait T { fn a(); }
374struct U {} 349struct U {}
375impl T for U { 350impl T for U {
376 fn a() { 351 fn a() {
377 // this comes out of bitflags, mostly
378 #[allow(non_snake_case)] 352 #[allow(non_snake_case)]
379 trait __BitFlags { 353 trait __BitFlagsOk {
380 const HiImAlsoBad: u8 = 2; 354 const HiImAlsoBad: u8 = 2;
381 #[inline] 355 fn Dirty(&self) -> bool { false }
382 fn Dirty(&self) -> bool {
383 false
384 }
385 } 356 }
386 357
358 trait __BitFlagsBad {
359 const HiImAlsoBad: u8 = 2;
360 fn Dirty(&self) -> bool { false }
361 }
387 } 362 }
388} 363}
389 "#, 364"#,
390 ); 365 );
391 } 366 }
392 367
@@ -423,18 +398,14 @@ extern {
423 } 398 }
424 399
425 #[test] 400 #[test]
426 #[ignore]
427 fn bug_traits_arent_checked() { 401 fn bug_traits_arent_checked() {
428 // FIXME: Traits and functions in traits aren't currently checked by 402 // FIXME: Traits and functions in traits aren't currently checked by
429 // r-a, even though rustc will complain about them. 403 // r-a, even though rustc will complain about them.
430 check_diagnostics( 404 check_diagnostics(
431 r#" 405 r#"
432trait BAD_TRAIT { 406trait BAD_TRAIT {
433 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
434 fn BAD_FUNCTION(); 407 fn BAD_FUNCTION();
435 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
436 fn BadFunction(); 408 fn BadFunction();
437 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
438} 409}
439 "#, 410 "#,
440 ); 411 );
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs
index 5f97f190d..356f089b2 100644
--- a/crates/ide/src/diagnostics/macro_error.rs
+++ b/crates/ide_diagnostics/src/handlers/macro_error.rs
@@ -1,9 +1,9 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: macro-error 3// Diagnostic: macro-error
4// 4//
5// This diagnostic is shown for macro expansion errors. 5// This diagnostic is shown for macro expansion errors.
6pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { 6pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
7 Diagnostic::new( 7 Diagnostic::new(
8 "macro-error", 8 "macro-error",
9 d.message.clone(), 9 d.message.clone(),
@@ -15,7 +15,7 @@ pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
15#[cfg(test)] 15#[cfg(test)]
16mod tests { 16mod tests {
17 use crate::{ 17 use crate::{
18 diagnostics::tests::{check_diagnostics, check_diagnostics_with_config}, 18 tests::{check_diagnostics, check_diagnostics_with_config},
19 DiagnosticsConfig, 19 DiagnosticsConfig,
20 }; 20 };
21 21
@@ -27,7 +27,7 @@ mod tests {
27macro_rules! include { () => {} } 27macro_rules! include { () => {} }
28 28
29 include!("doesntexist"); 29 include!("doesntexist");
30//^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` 30//^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist`
31 "#, 31 "#,
32 ); 32 );
33 } 33 }
@@ -66,7 +66,7 @@ macro_rules! env { () => {} }
66macro_rules! concat { () => {} } 66macro_rules! concat { () => {} }
67 67
68 include!(concat!(env!("OUT_DIR"), "/out.rs")); 68 include!(concat!(env!("OUT_DIR"), "/out.rs"));
69//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix 69//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
70"#, 70"#,
71 ); 71 );
72 } 72 }
@@ -108,23 +108,23 @@ fn main() {
108 // Test a handful of built-in (eager) macros: 108 // Test a handful of built-in (eager) macros:
109 109
110 include!(invalid); 110 include!(invalid);
111 //^^^^^^^^^^^^^^^^^ could not convert tokens 111 //^^^^^^^^^^^^^^^^^ error: could not convert tokens
112 include!("does not exist"); 112 include!("does not exist");
113 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` 113 //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
114 114
115 env!(invalid); 115 env!(invalid);
116 //^^^^^^^^^^^^^ could not convert tokens 116 //^^^^^^^^^^^^^ error: could not convert tokens
117 117
118 env!("OUT_DIR"); 118 env!("OUT_DIR");
119 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix 119 //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
120 120
121 compile_error!("compile_error works"); 121 compile_error!("compile_error works");
122 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 122 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works
123 123
124 // Lazy: 124 // Lazy:
125 125
126 format_args!(); 126 format_args!();
127 //^^^^^^^^^^^^^^ no rule matches input tokens 127 //^^^^^^^^^^^^^^ error: no rule matches input tokens
128} 128}
129"#, 129"#,
130 ); 130 );
@@ -141,7 +141,7 @@ fn f() {
141 m!(); 141 m!();
142 142
143 m!(hi); 143 m!(hi);
144 //^^^^^^ leftover tokens 144 //^^^^^^ error: leftover tokens
145} 145}
146 "#, 146 "#,
147 ); 147 );
@@ -166,7 +166,7 @@ macro_rules! outer {
166 166
167fn f() { 167fn f() {
168 outer!(); 168 outer!();
169} //^^^^^^^^ leftover tokens 169} //^^^^^^^^ error: leftover tokens
170"#, 170"#,
171 ) 171 )
172 } 172 }
diff --git a/crates/ide/src/diagnostics/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs
index 08e1cfa5f..a9b6d3870 100644
--- a/crates/ide/src/diagnostics/mismatched_arg_count.rs
+++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs
@@ -1,9 +1,9 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: mismatched-arg-count 3// Diagnostic: mismatched-arg-count
4// 4//
5// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. 5// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
6pub(super) fn mismatched_arg_count( 6pub(crate) fn mismatched_arg_count(
7 ctx: &DiagnosticsContext<'_>, 7 ctx: &DiagnosticsContext<'_>,
8 d: &hir::MismatchedArgCount, 8 d: &hir::MismatchedArgCount,
9) -> Diagnostic { 9) -> Diagnostic {
@@ -18,7 +18,7 @@ pub(super) fn mismatched_arg_count(
18 18
19#[cfg(test)] 19#[cfg(test)]
20mod tests { 20mod tests {
21 use crate::diagnostics::tests::check_diagnostics; 21 use crate::tests::check_diagnostics;
22 22
23 #[test] 23 #[test]
24 fn simple_free_fn_zero() { 24 fn simple_free_fn_zero() {
@@ -26,7 +26,7 @@ mod tests {
26 r#" 26 r#"
27fn zero() {} 27fn zero() {}
28fn f() { zero(1); } 28fn f() { zero(1); }
29 //^^^^^^^ expected 0 arguments, found 1 29 //^^^^^^^ error: expected 0 arguments, found 1
30"#, 30"#,
31 ); 31 );
32 32
@@ -44,7 +44,7 @@ fn f() { zero(); }
44 r#" 44 r#"
45fn one(arg: u8) {} 45fn one(arg: u8) {}
46fn f() { one(); } 46fn f() { one(); }
47 //^^^^^ expected 1 argument, found 0 47 //^^^^^ error: expected 1 argument, found 0
48"#, 48"#,
49 ); 49 );
50 50
@@ -65,7 +65,7 @@ impl S { fn method(&self) {} }
65 65
66fn f() { 66fn f() {
67 S::method(); 67 S::method();
68} //^^^^^^^^^^^ expected 1 argument, found 0 68} //^^^^^^^^^^^ error: expected 1 argument, found 0
69"#, 69"#,
70 ); 70 );
71 71
@@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} }
91 91
92 fn f() { 92 fn f() {
93 S.method(); 93 S.method();
94 } //^^^^^^^^^^ expected 1 argument, found 0 94 } //^^^^^^^^^^ error: expected 1 argument, found 0
95 "#, 95 "#,
96 ); 96 );
97 97
@@ -131,7 +131,7 @@ fn f() {
131struct Tup(u8, u16); 131struct Tup(u8, u16);
132fn f() { 132fn f() {
133 Tup(0); 133 Tup(0);
134} //^^^^^^ expected 2 arguments, found 1 134} //^^^^^^ error: expected 2 arguments, found 1
135"#, 135"#,
136 ) 136 )
137 } 137 }
@@ -143,7 +143,7 @@ fn f() {
143enum En { Variant(u8, u16), } 143enum En { Variant(u8, u16), }
144fn f() { 144fn f() {
145 En::Variant(0); 145 En::Variant(0);
146} //^^^^^^^^^^^^^^ expected 2 arguments, found 1 146} //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1
147"#, 147"#,
148 ) 148 )
149 } 149 }
@@ -162,9 +162,9 @@ impl Foo {
162 fn new() { 162 fn new() {
163 Foo::Bar(0); 163 Foo::Bar(0);
164 Foo::Bar(0, 1); 164 Foo::Bar(0, 1);
165 //^^^^^^^^^^^^^^ expected 1 argument, found 2 165 //^^^^^^^^^^^^^^ error: expected 1 argument, found 2
166 Foo::Bar(); 166 Foo::Bar();
167 //^^^^^^^^^^ expected 1 argument, found 0 167 //^^^^^^^^^^ error: expected 1 argument, found 0
168 } 168 }
169} 169}
170 "#, 170 "#,
@@ -185,7 +185,7 @@ fn f() {
185 unsafe { 185 unsafe {
186 fixed(0); 186 fixed(0);
187 fixed(0, 1); 187 fixed(0, 1);
188 //^^^^^^^^^^^ expected 1 argument, found 2 188 //^^^^^^^^^^^ error: expected 1 argument, found 2
189 varargs(0); 189 varargs(0);
190 varargs(0, 1); 190 varargs(0, 1);
191 varargs2(); 191 varargs2();
@@ -204,10 +204,10 @@ fn f() {
204fn main() { 204fn main() {
205 let f = |()| (); 205 let f = |()| ();
206 f(); 206 f();
207 //^^^ expected 1 argument, found 0 207 //^^^ error: expected 1 argument, found 0
208 f(()); 208 f(());
209 f((), ()); 209 f((), ());
210 //^^^^^^^^^ expected 1 argument, found 2 210 //^^^^^^^^^ error: expected 1 argument, found 2
211} 211}
212"#, 212"#,
213 ) 213 )
diff --git a/crates/ide/src/diagnostics/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index d01f05041..bc56e0342 100644
--- a/crates/ide/src/diagnostics/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -1,12 +1,11 @@
1use either::Either; 1use either::Either;
2use hir::{db::AstDatabase, InFile}; 2use hir::{db::AstDatabase, InFile};
3use ide_assists::Assist; 3use ide_db::{assists::Assist, source_change::SourceChange};
4use ide_db::source_change::SourceChange;
5use stdx::format_to; 4use stdx::format_to;
6use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; 5use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
7use text_edit::TextEdit; 6use text_edit::TextEdit;
8 7
9use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; 8use crate::{fix, Diagnostic, DiagnosticsContext};
10 9
11// Diagnostic: missing-fields 10// Diagnostic: missing-fields
12// 11//
@@ -19,8 +18,8 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext};
19// 18//
20// let a = A { a: 10 }; 19// let a = A { a: 10 };
21// ``` 20// ```
22pub(super) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { 21pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
23 let mut message = String::from("Missing structure fields:\n"); 22 let mut message = String::from("missing structure fields:\n");
24 for field in &d.missed_fields { 23 for field in &d.missed_fields {
25 format_to!(message, "- {}\n", field); 24 format_to!(message, "- {}\n", field);
26 } 25 }
@@ -77,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
77 76
78#[cfg(test)] 77#[cfg(test)]
79mod tests { 78mod tests {
80 use crate::diagnostics::tests::{check_diagnostics, check_fix}; 79 use crate::tests::{check_diagnostics, check_fix};
81 80
82 #[test] 81 #[test]
83 fn missing_record_pat_field_diagnostic() { 82 fn missing_record_pat_field_diagnostic() {
@@ -86,7 +85,7 @@ mod tests {
86struct S { foo: i32, bar: () } 85struct S { foo: i32, bar: () }
87fn baz(s: S) { 86fn baz(s: S) {
88 let S { foo: _ } = s; 87 let S { foo: _ } = s;
89 //^ Missing structure fields: 88 //^ error: missing structure fields:
90 //| - bar 89 //| - bar
91} 90}
92"#, 91"#,
@@ -324,4 +323,33 @@ fn f() {
324"#, 323"#,
325 ); 324 );
326 } 325 }
326
327 #[test]
328 fn import_extern_crate_clash_with_inner_item() {
329 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
330
331 check_diagnostics(
332 r#"
333//- /lib.rs crate:lib deps:jwt
334mod permissions;
335
336use permissions::jwt;
337
338fn f() {
339 fn inner() {}
340 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
341}
342
343//- /permissions.rs
344pub mod jwt {
345 pub struct Claims {}
346}
347
348//- /jwt/lib.rs crate:jwt
349pub struct Claims {
350 field: u8,
351}
352 "#,
353 );
354 }
327} 355}
diff --git a/crates/ide/src/diagnostics/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
index b636489b3..947b0f2e2 100644
--- a/crates/ide/src/diagnostics/missing_match_arms.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
@@ -1,11 +1,11 @@
1use hir::InFile; 1use hir::InFile;
2 2
3use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 3use crate::{Diagnostic, DiagnosticsContext};
4 4
5// Diagnostic: missing-match-arm 5// Diagnostic: missing-match-arm
6// 6//
7// This diagnostic is triggered if `match` block is missing one or more match arms. 7// This diagnostic is triggered if `match` block is missing one or more match arms.
8pub(super) fn missing_match_arms( 8pub(crate) fn missing_match_arms(
9 ctx: &DiagnosticsContext<'_>, 9 ctx: &DiagnosticsContext<'_>,
10 d: &hir::MissingMatchArms, 10 d: &hir::MissingMatchArms,
11) -> Diagnostic { 11) -> Diagnostic {
@@ -17,12 +17,12 @@ pub(super) fn missing_match_arms(
17} 17}
18 18
19#[cfg(test)] 19#[cfg(test)]
20pub(super) mod tests { 20mod tests {
21 use crate::diagnostics::tests::check_diagnostics; 21 use crate::tests::check_diagnostics;
22 22
23 fn check_diagnostics_no_bails(ra_fixture: &str) { 23 fn check_diagnostics_no_bails(ra_fixture: &str) {
24 cov_mark::check_count!(validate_match_bailed_out, 0); 24 cov_mark::check_count!(validate_match_bailed_out, 0);
25 crate::diagnostics::tests::check_diagnostics(ra_fixture) 25 crate::tests::check_diagnostics(ra_fixture)
26 } 26 }
27 27
28 #[test] 28 #[test]
@@ -31,9 +31,9 @@ pub(super) mod tests {
31 r#" 31 r#"
32fn main() { 32fn main() {
33 match () { } 33 match () { }
34 //^^ missing match arm 34 //^^ error: missing match arm
35 match (()) { } 35 match (()) { }
36 //^^^^ missing match arm 36 //^^^^ error: missing match arm
37 37
38 match () { _ => (), } 38 match () { _ => (), }
39 match () { () => (), } 39 match () { () => (), }
@@ -49,7 +49,7 @@ fn main() {
49 r#" 49 r#"
50fn main() { 50fn main() {
51 match ((), ()) { } 51 match ((), ()) { }
52 //^^^^^^^^ missing match arm 52 //^^^^^^^^ error: missing match arm
53 53
54 match ((), ()) { ((), ()) => (), } 54 match ((), ()) { ((), ()) => (), }
55} 55}
@@ -63,21 +63,21 @@ fn main() {
63 r#" 63 r#"
64fn test_main() { 64fn test_main() {
65 match false { } 65 match false { }
66 //^^^^^ missing match arm 66 //^^^^^ error: missing match arm
67 match false { true => (), } 67 match false { true => (), }
68 //^^^^^ missing match arm 68 //^^^^^ error: missing match arm
69 match (false, true) {} 69 match (false, true) {}
70 //^^^^^^^^^^^^^ missing match arm 70 //^^^^^^^^^^^^^ error: missing match arm
71 match (false, true) { (true, true) => (), } 71 match (false, true) { (true, true) => (), }
72 //^^^^^^^^^^^^^ missing match arm 72 //^^^^^^^^^^^^^ error: missing match arm
73 match (false, true) { 73 match (false, true) {
74 //^^^^^^^^^^^^^ missing match arm 74 //^^^^^^^^^^^^^ error: missing match arm
75 (false, true) => (), 75 (false, true) => (),
76 (false, false) => (), 76 (false, false) => (),
77 (true, false) => (), 77 (true, false) => (),
78 } 78 }
79 match (false, true) { (true, _x) => (), } 79 match (false, true) { (true, _x) => (), }
80 //^^^^^^^^^^^^^ missing match arm 80 //^^^^^^^^^^^^^ error: missing match arm
81 81
82 match false { true => (), false => (), } 82 match false { true => (), false => (), }
83 match (false, true) { 83 match (false, true) {
@@ -116,11 +116,11 @@ fn test_main() {
116 r#" 116 r#"
117fn main() { 117fn main() {
118 match (false, ((), false)) {} 118 match (false, ((), false)) {}
119 //^^^^^^^^^^^^^^^^^^^^ missing match arm 119 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
120 match (false, ((), false)) { (true, ((), true)) => (), } 120 match (false, ((), false)) { (true, ((), true)) => (), }
121 //^^^^^^^^^^^^^^^^^^^^ missing match arm 121 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
122 match (false, ((), false)) { (true, _) => (), } 122 match (false, ((), false)) { (true, _) => (), }
123 //^^^^^^^^^^^^^^^^^^^^ missing match arm 123 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
124 124
125 match (false, ((), false)) { 125 match (false, ((), false)) {
126 (true, ((), true)) => (), 126 (true, ((), true)) => (),
@@ -146,12 +146,12 @@ enum Either { A, B, }
146 146
147fn main() { 147fn main() {
148 match Either::A { } 148 match Either::A { }
149 //^^^^^^^^^ missing match arm 149 //^^^^^^^^^ error: missing match arm
150 match Either::B { Either::A => (), } 150 match Either::B { Either::A => (), }
151 //^^^^^^^^^ missing match arm 151 //^^^^^^^^^ error: missing match arm
152 152
153 match &Either::B { 153 match &Either::B {
154 //^^^^^^^^^^ missing match arm 154 //^^^^^^^^^^ error: missing match arm
155 Either::A => (), 155 Either::A => (),
156 } 156 }
157 157
@@ -174,9 +174,9 @@ enum Either { A(bool), B }
174 174
175fn main() { 175fn main() {
176 match Either::B { } 176 match Either::B { }
177 //^^^^^^^^^ missing match arm 177 //^^^^^^^^^ error: missing match arm
178 match Either::B { 178 match Either::B {
179 //^^^^^^^^^ missing match arm 179 //^^^^^^^^^ error: missing match arm
180 Either::A(true) => (), Either::B => () 180 Either::A(true) => (), Either::B => ()
181 } 181 }
182 182
@@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) }
207 207
208fn main() { 208fn main() {
209 match Either::A(false) { 209 match Either::A(false) {
210 //^^^^^^^^^^^^^^^^ missing match arm 210 //^^^^^^^^^^^^^^^^ error: missing match arm
211 Either::A(_) => (), 211 Either::A(_) => (),
212 Either::B(false, _) => (), 212 Either::B(false, _) => (),
213 } 213 }
@@ -352,7 +352,7 @@ fn main() {
352 Either::A => (), 352 Either::A => (),
353 } 353 }
354 match loop { break Foo::A } { 354 match loop { break Foo::A } {
355 //^^^^^^^^^^^^^^^^^^^^^ missing match arm 355 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
356 Either::A => (), 356 Either::A => (),
357 } 357 }
358 match loop { break Foo::A } { 358 match loop { break Foo::A } {
@@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B }
390fn main() { 390fn main() {
391 let a = Either::A { foo: true }; 391 let a = Either::A { foo: true };
392 match a { } 392 match a { }
393 //^ missing match arm 393 //^ error: missing match arm
394 match a { Either::A { foo: true } => () } 394 match a { Either::A { foo: true } => () }
395 //^ missing match arm 395 //^ error: missing match arm
396 match a { 396 match a {
397 Either::A { } => (), 397 Either::A { } => (),
398 //^^^^^^^^^ Missing structure fields: 398 //^^^^^^^^^ error: missing structure fields:
399 // | - foo 399 // | - foo
400 Either::B => (), 400 Either::B => (),
401 } 401 }
402 match a { 402 match a {
403 //^ missing match arm 403 //^ error: missing match arm
404 Either::A { } => (), 404 Either::A { } => (),
405 } //^^^^^^^^^ Missing structure fields: 405 } //^^^^^^^^^ error: missing structure fields:
406 // | - foo 406 // | - foo
407 407
408 match a { 408 match a {
@@ -431,7 +431,7 @@ enum Either {
431fn main() { 431fn main() {
432 let a = Either::A { foo: true, bar: () }; 432 let a = Either::A { foo: true, bar: () };
433 match a { 433 match a {
434 //^ missing match arm 434 //^ error: missing match arm
435 Either::A { bar: (), foo: false } => (), 435 Either::A { bar: (), foo: false } => (),
436 Either::A { foo: true, bar: () } => (), 436 Either::A { foo: true, bar: () } => (),
437 } 437 }
@@ -458,12 +458,12 @@ enum Either {
458fn main() { 458fn main() {
459 let a = Either::B; 459 let a = Either::B;
460 match a { 460 match a {
461 //^ missing match arm 461 //^ error: missing match arm
462 Either::A { foo: true, .. } => (), 462 Either::A { foo: true, .. } => (),
463 Either::B => (), 463 Either::B => (),
464 } 464 }
465 match a { 465 match a {
466 //^ missing match arm 466 //^ error: missing match arm
467 Either::A { .. } => (), 467 Either::A { .. } => (),
468 } 468 }
469 469
@@ -493,14 +493,14 @@ enum Either {
493 493
494fn main() { 494fn main() {
495 match Either::B { 495 match Either::B {
496 //^^^^^^^^^ missing match arm 496 //^^^^^^^^^ error: missing match arm
497 Either::A(true, .., true) => (), 497 Either::A(true, .., true) => (),
498 Either::A(true, .., false) => (), 498 Either::A(true, .., false) => (),
499 Either::A(false, .., false) => (), 499 Either::A(false, .., false) => (),
500 Either::B => (), 500 Either::B => (),
501 } 501 }
502 match Either::B { 502 match Either::B {
503 //^^^^^^^^^ missing match arm 503 //^^^^^^^^^ error: missing match arm
504 Either::A(true, .., true) => (), 504 Either::A(true, .., true) => (),
505 Either::A(true, .., false) => (), 505 Either::A(true, .., false) => (),
506 Either::A(.., true) => (), 506 Either::A(.., true) => (),
@@ -537,7 +537,7 @@ fn enum_(never: Never) {
537} 537}
538fn enum_ref(never: &Never) { 538fn enum_ref(never: &Never) {
539 match never {} 539 match never {}
540 //^^^^^ missing match arm 540 //^^^^^ error: missing match arm
541} 541}
542fn bang(never: !) { 542fn bang(never: !) {
543 match never {} 543 match never {}
@@ -561,7 +561,7 @@ fn main() {
561 Some(never) => match never {}, 561 Some(never) => match never {},
562 } 562 }
563 match Option::<Never>::None { 563 match Option::<Never>::None {
564 //^^^^^^^^^^^^^^^^^^^^^ missing match arm 564 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
565 Option::Some(_never) => {}, 565 Option::Some(_never) => {},
566 } 566 }
567} 567}
@@ -575,7 +575,7 @@ fn main() {
575 r#" 575 r#"
576fn main() { 576fn main() {
577 match (false, true, false) { 577 match (false, true, false) {
578 //^^^^^^^^^^^^^^^^^^^^ missing match arm 578 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
579 (false, ..) => (), 579 (false, ..) => (),
580 } 580 }
581}"#, 581}"#,
@@ -588,7 +588,7 @@ fn main() {
588 r#" 588 r#"
589fn main() { 589fn main() {
590 match (false, true, false) { 590 match (false, true, false) {
591 //^^^^^^^^^^^^^^^^^^^^ missing match arm 591 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
592 (.., false) => (), 592 (.., false) => (),
593 } 593 }
594}"#, 594}"#,
@@ -601,7 +601,7 @@ fn main() {
601 r#" 601 r#"
602fn main() { 602fn main() {
603 match (false, true, false) { 603 match (false, true, false) {
604 //^^^^^^^^^^^^^^^^^^^^ missing match arm 604 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
605 (true, .., false) => (), 605 (true, .., false) => (),
606 } 606 }
607}"#, 607}"#,
@@ -614,11 +614,11 @@ fn main() {
614 r#"struct Foo { a: bool } 614 r#"struct Foo { a: bool }
615fn main(f: Foo) { 615fn main(f: Foo) {
616 match f {} 616 match f {}
617 //^ missing match arm 617 //^ error: missing match arm
618 match f { Foo { a: true } => () } 618 match f { Foo { a: true } => () }
619 //^ missing match arm 619 //^ error: missing match arm
620 match &f { Foo { a: true } => () } 620 match &f { Foo { a: true } => () }
621 //^^ missing match arm 621 //^^ error: missing match arm
622 match f { Foo { a: _ } => () } 622 match f { Foo { a: _ } => () }
623 match f { 623 match f {
624 Foo { a: true } => (), 624 Foo { a: true } => (),
@@ -639,9 +639,9 @@ fn main(f: Foo) {
639 r#"struct Foo(bool); 639 r#"struct Foo(bool);
640fn main(f: Foo) { 640fn main(f: Foo) {
641 match f {} 641 match f {}
642 //^ missing match arm 642 //^ error: missing match arm
643 match f { Foo(true) => () } 643 match f { Foo(true) => () }
644 //^ missing match arm 644 //^ error: missing match arm
645 match f { 645 match f {
646 Foo(true) => (), 646 Foo(true) => (),
647 Foo(false) => (), 647 Foo(false) => (),
@@ -657,7 +657,7 @@ fn main(f: Foo) {
657 r#"struct Foo; 657 r#"struct Foo;
658fn main(f: Foo) { 658fn main(f: Foo) {
659 match f {} 659 match f {}
660 //^ missing match arm 660 //^ error: missing match arm
661 match f { Foo => () } 661 match f { Foo => () }
662} 662}
663"#, 663"#,
@@ -670,9 +670,9 @@ fn main(f: Foo) {
670 r#"struct Foo { foo: bool, bar: bool } 670 r#"struct Foo { foo: bool, bar: bool }
671fn main(f: Foo) { 671fn main(f: Foo) {
672 match f { Foo { foo: true, .. } => () } 672 match f { Foo { foo: true, .. } => () }
673 //^ missing match arm 673 //^ error: missing match arm
674 match f { 674 match f {
675 //^ missing match arm 675 //^ error: missing match arm
676 Foo { foo: true, .. } => (), 676 Foo { foo: true, .. } => (),
677 Foo { bar: false, .. } => () 677 Foo { bar: false, .. } => ()
678 } 678 }
@@ -693,7 +693,7 @@ fn main(f: Foo) {
693fn main() { 693fn main() {
694 enum Either { A(bool), B } 694 enum Either { A(bool), B }
695 match Either::B { 695 match Either::B {
696 //^^^^^^^^^ missing match arm 696 //^^^^^^^^^ error: missing match arm
697 Either::A(true | false) => (), 697 Either::A(true | false) => (),
698 } 698 }
699} 699}
@@ -715,7 +715,7 @@ fn main(v: S) {
715 match v { S{..} => {} } 715 match v { S{..} => {} }
716 match v { _ => {} } 716 match v { _ => {} }
717 match v { } 717 match v { }
718 //^ missing match arm 718 //^ error: missing match arm
719} 719}
720"#, 720"#,
721 ); 721 );
@@ -731,7 +731,7 @@ fn main() {
731 false => {} 731 false => {}
732 } 732 }
733 match true { _x @ true => {} } 733 match true { _x @ true => {} }
734 //^^^^ missing match arm 734 //^^^^ error: missing match arm
735} 735}
736"#, 736"#,
737 ); 737 );
@@ -786,12 +786,12 @@ use lib::E;
786fn main() { 786fn main() {
787 match E::A { _ => {} } 787 match E::A { _ => {} }
788 match E::A { 788 match E::A {
789 //^^^^ missing match arm 789 //^^^^ error: missing match arm
790 E::A => {} 790 E::A => {}
791 E::B => {} 791 E::B => {}
792 } 792 }
793 match E::A { 793 match E::A {
794 //^^^^ missing match arm 794 //^^^^ error: missing match arm
795 E::A | E::B => {} 795 E::A | E::B => {}
796 } 796 }
797} 797}
@@ -810,7 +810,7 @@ fn main() {
810 false => {} 810 false => {}
811 } 811 }
812 match true { 812 match true {
813 //^^^^ missing match arm 813 //^^^^ error: missing match arm
814 true if false => {} 814 true if false => {}
815 false => {} 815 false => {}
816 } 816 }
diff --git a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
index 06005d156..c0edcd7d3 100644
--- a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs
@@ -1,10 +1,9 @@
1use hir::db::AstDatabase; 1use hir::db::AstDatabase;
2use ide_assists::Assist; 2use ide_db::{assists::Assist, source_change::SourceChange};
3use ide_db::source_change::SourceChange;
4use syntax::AstNode; 3use syntax::AstNode;
5use text_edit::TextEdit; 4use text_edit::TextEdit;
6 5
7use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; 6use crate::{fix, Diagnostic, DiagnosticsContext};
8 7
9// Diagnostic: missing-ok-or-some-in-tail-expr 8// Diagnostic: missing-ok-or-some-in-tail-expr
10// 9//
@@ -18,7 +17,7 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext};
18// 10 17// 10
19// } 18// }
20// ``` 19// ```
21pub(super) fn missing_ok_or_some_in_tail_expr( 20pub(crate) fn missing_ok_or_some_in_tail_expr(
22 ctx: &DiagnosticsContext<'_>, 21 ctx: &DiagnosticsContext<'_>,
23 d: &hir::MissingOkOrSomeInTailExpr, 22 d: &hir::MissingOkOrSomeInTailExpr,
24) -> Diagnostic { 23) -> Diagnostic {
@@ -44,32 +43,21 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Op
44 43
45#[cfg(test)] 44#[cfg(test)]
46mod tests { 45mod tests {
47 use crate::diagnostics::tests::{check_diagnostics, check_fix}; 46 use crate::tests::{check_diagnostics, check_fix};
48 47
49 #[test] 48 #[test]
50 fn test_wrap_return_type_option() { 49 fn test_wrap_return_type_option() {
51 check_fix( 50 check_fix(
52 r#" 51 r#"
53//- /main.rs crate:main deps:core 52//- minicore: option, result
54use core::option::Option::{self, Some, None};
55
56fn div(x: i32, y: i32) -> Option<i32> { 53fn div(x: i32, y: i32) -> Option<i32> {
57 if y == 0 { 54 if y == 0 {
58 return None; 55 return None;
59 } 56 }
60 x / y$0 57 x / y$0
61} 58}
62//- /core/lib.rs crate:core
63pub mod result {
64 pub enum Result<T, E> { Ok(T), Err(E) }
65}
66pub mod option {
67 pub enum Option<T> { Some(T), None }
68}
69"#, 59"#,
70 r#" 60 r#"
71use core::option::Option::{self, Some, None};
72
73fn div(x: i32, y: i32) -> Option<i32> { 61fn div(x: i32, y: i32) -> Option<i32> {
74 if y == 0 { 62 if y == 0 {
75 return None; 63 return None;
@@ -84,26 +72,15 @@ fn div(x: i32, y: i32) -> Option<i32> {
84 fn test_wrap_return_type() { 72 fn test_wrap_return_type() {
85 check_fix( 73 check_fix(
86 r#" 74 r#"
87//- /main.rs crate:main deps:core 75//- minicore: option, result
88use core::result::Result::{self, Ok, Err};
89
90fn div(x: i32, y: i32) -> Result<i32, ()> { 76fn div(x: i32, y: i32) -> Result<i32, ()> {
91 if y == 0 { 77 if y == 0 {
92 return Err(()); 78 return Err(());
93 } 79 }
94 x / y$0 80 x / y$0
95} 81}
96//- /core/lib.rs crate:core
97pub mod result {
98 pub enum Result<T, E> { Ok(T), Err(E) }
99}
100pub mod option {
101 pub enum Option<T> { Some(T), None }
102}
103"#, 82"#,
104 r#" 83 r#"
105use core::result::Result::{self, Ok, Err};
106
107fn div(x: i32, y: i32) -> Result<i32, ()> { 84fn div(x: i32, y: i32) -> Result<i32, ()> {
108 if y == 0 { 85 if y == 0 {
109 return Err(()); 86 return Err(());
@@ -118,26 +95,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
118 fn test_wrap_return_type_handles_generic_functions() { 95 fn test_wrap_return_type_handles_generic_functions() {
119 check_fix( 96 check_fix(
120 r#" 97 r#"
121//- /main.rs crate:main deps:core 98//- minicore: option, result
122use core::result::Result::{self, Ok, Err};
123
124fn div<T>(x: T) -> Result<T, i32> { 99fn div<T>(x: T) -> Result<T, i32> {
125 if x == 0 { 100 if x == 0 {
126 return Err(7); 101 return Err(7);
127 } 102 }
128 $0x 103 $0x
129} 104}
130//- /core/lib.rs crate:core
131pub mod result {
132 pub enum Result<T, E> { Ok(T), Err(E) }
133}
134pub mod option {
135 pub enum Option<T> { Some(T), None }
136}
137"#, 105"#,
138 r#" 106 r#"
139use core::result::Result::{self, Ok, Err};
140
141fn div<T>(x: T) -> Result<T, i32> { 107fn div<T>(x: T) -> Result<T, i32> {
142 if x == 0 { 108 if x == 0 {
143 return Err(7); 109 return Err(7);
@@ -152,9 +118,7 @@ fn div<T>(x: T) -> Result<T, i32> {
152 fn test_wrap_return_type_handles_type_aliases() { 118 fn test_wrap_return_type_handles_type_aliases() {
153 check_fix( 119 check_fix(
154 r#" 120 r#"
155//- /main.rs crate:main deps:core 121//- minicore: option, result
156use core::result::Result::{self, Ok, Err};
157
158type MyResult<T> = Result<T, ()>; 122type MyResult<T> = Result<T, ()>;
159 123
160fn div(x: i32, y: i32) -> MyResult<i32> { 124fn div(x: i32, y: i32) -> MyResult<i32> {
@@ -163,17 +127,8 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
163 } 127 }
164 x $0/ y 128 x $0/ y
165} 129}
166//- /core/lib.rs crate:core
167pub mod result {
168 pub enum Result<T, E> { Ok(T), Err(E) }
169}
170pub mod option {
171 pub enum Option<T> { Some(T), None }
172}
173"#, 130"#,
174 r#" 131 r#"
175use core::result::Result::{self, Ok, Err};
176
177type MyResult<T> = Result<T, ()>; 132type MyResult<T> = Result<T, ()>;
178 133
179fn div(x: i32, y: i32) -> MyResult<i32> { 134fn div(x: i32, y: i32) -> MyResult<i32> {
@@ -190,18 +145,8 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
190 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { 145 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
191 check_diagnostics( 146 check_diagnostics(
192 r#" 147 r#"
193//- /main.rs crate:main deps:core 148//- minicore: option, result
194use core::result::Result::{self, Ok, Err};
195
196fn foo() -> Result<(), i32> { 0 } 149fn foo() -> Result<(), i32> { 0 }
197
198//- /core/lib.rs crate:core
199pub mod result {
200 pub enum Result<T, E> { Ok(T), Err(E) }
201}
202pub mod option {
203 pub enum Option<T> { Some(T), None }
204}
205"#, 150"#,
206 ); 151 );
207 } 152 }
@@ -210,20 +155,10 @@ pub mod option {
210 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { 155 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
211 check_diagnostics( 156 check_diagnostics(
212 r#" 157 r#"
213//- /main.rs crate:main deps:core 158//- minicore: option, result
214use core::result::Result::{self, Ok, Err};
215
216enum SomeOtherEnum { Ok(i32), Err(String) } 159enum SomeOtherEnum { Ok(i32), Err(String) }
217 160
218fn foo() -> SomeOtherEnum { 0 } 161fn foo() -> SomeOtherEnum { 0 }
219
220//- /core/lib.rs crate:core
221pub mod result {
222 pub enum Result<T, E> { Ok(T), Err(E) }
223}
224pub mod option {
225 pub enum Option<T> { Some(T), None }
226}
227"#, 162"#,
228 ); 163 );
229 } 164 }
diff --git a/crates/ide/src/diagnostics/missing_unsafe.rs b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs
index 5c47e8d0a..7acd9228a 100644
--- a/crates/ide/src/diagnostics/missing_unsafe.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs
@@ -1,9 +1,9 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: missing-unsafe 3// Diagnostic: missing-unsafe
4// 4//
5// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. 5// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
6pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { 6pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic {
7 Diagnostic::new( 7 Diagnostic::new(
8 "missing-unsafe", 8 "missing-unsafe",
9 "this operation is unsafe and requires an unsafe function or block", 9 "this operation is unsafe and requires an unsafe function or block",
@@ -13,7 +13,7 @@ pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
13 13
14#[cfg(test)] 14#[cfg(test)]
15mod tests { 15mod tests {
16 use crate::diagnostics::tests::check_diagnostics; 16 use crate::tests::check_diagnostics;
17 17
18 #[test] 18 #[test]
19 fn missing_unsafe_diagnostic_with_raw_ptr() { 19 fn missing_unsafe_diagnostic_with_raw_ptr() {
@@ -23,7 +23,7 @@ fn main() {
23 let x = &5 as *const usize; 23 let x = &5 as *const usize;
24 unsafe { let y = *x; } 24 unsafe { let y = *x; }
25 let z = *x; 25 let z = *x;
26} //^^ this operation is unsafe and requires an unsafe function or block 26} //^^ error: this operation is unsafe and requires an unsafe function or block
27"#, 27"#,
28 ) 28 )
29 } 29 }
@@ -48,9 +48,9 @@ unsafe fn unsafe_fn() {
48 48
49fn main() { 49fn main() {
50 unsafe_fn(); 50 unsafe_fn();
51 //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 51 //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
52 HasUnsafe.unsafe_fn(); 52 HasUnsafe.unsafe_fn();
53 //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 53 //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
54 unsafe { 54 unsafe {
55 unsafe_fn(); 55 unsafe_fn();
56 HasUnsafe.unsafe_fn(); 56 HasUnsafe.unsafe_fn();
@@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 };
72 72
73fn main() { 73fn main() {
74 let x = STATIC_MUT.a; 74 let x = STATIC_MUT.a;
75 //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 75 //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
76 unsafe { 76 unsafe {
77 let x = STATIC_MUT.a; 77 let x = STATIC_MUT.a;
78 } 78 }
@@ -93,7 +93,7 @@ extern "rust-intrinsic" {
93fn main() { 93fn main() {
94 let _ = bitreverse(12); 94 let _ = bitreverse(12);
95 let _ = floorf32(12.0); 95 let _ = floorf32(12.0);
96 //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 96 //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
97} 97}
98"#, 98"#,
99 ); 99 );
diff --git a/crates/ide/src/diagnostics/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs
index edc63c246..92e8867f4 100644
--- a/crates/ide/src/diagnostics/no_such_field.rs
+++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs
@@ -6,15 +6,12 @@ use syntax::{
6}; 6};
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
10 diagnostics::{fix, Diagnostic, DiagnosticsContext},
11 Assist,
12};
13 10
14// Diagnostic: no-such-field 11// Diagnostic: no-such-field
15// 12//
16// This diagnostic is triggered if created structure does not have field provided in record. 13// This diagnostic is triggered if created structure does not have field provided in record.
17pub(super) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { 14pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
18 Diagnostic::new( 15 Diagnostic::new(
19 "no-such-field", 16 "no-such-field",
20 "no such field", 17 "no such field",
@@ -112,7 +109,7 @@ fn missing_record_expr_field_fixes(
112 109
113#[cfg(test)] 110#[cfg(test)]
114mod tests { 111mod tests {
115 use crate::diagnostics::tests::{check_diagnostics, check_fix}; 112 use crate::tests::{check_diagnostics, check_fix};
116 113
117 #[test] 114 #[test]
118 fn no_such_field_diagnostics() { 115 fn no_such_field_diagnostics() {
@@ -122,11 +119,11 @@ struct S { foo: i32, bar: () }
122impl S { 119impl S {
123 fn new() -> S { 120 fn new() -> S {
124 S { 121 S {
125 //^ Missing structure fields: 122 //^ 💡 error: missing structure fields:
126 //| - bar 123 //| - bar
127 foo: 92, 124 foo: 92,
128 baz: 62, 125 baz: 62,
129 //^^^^^^^ no such field 126 //^^^^^^^ 💡 error: no such field
130 } 127 }
131 } 128 }
132} 129}
diff --git a/crates/ide/src/diagnostics/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
index 814cb0f8c..4e639f214 100644
--- a/crates/ide/src/diagnostics/remove_this_semicolon.rs
+++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
@@ -3,15 +3,12 @@ use ide_db::source_change::SourceChange;
3use syntax::{ast, AstNode}; 3use syntax::{ast, AstNode};
4use text_edit::TextEdit; 4use text_edit::TextEdit;
5 5
6use crate::{ 6use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
7 diagnostics::{fix, Diagnostic, DiagnosticsContext},
8 Assist,
9};
10 7
11// Diagnostic: remove-this-semicolon 8// Diagnostic: remove-this-semicolon
12// 9//
13// This diagnostic is triggered when there's an erroneous `;` at the end of the block. 10// This diagnostic is triggered when there's an erroneous `;` at the end of the block.
14pub(super) fn remove_this_semicolon( 11pub(crate) fn remove_this_semicolon(
15 ctx: &DiagnosticsContext<'_>, 12 ctx: &DiagnosticsContext<'_>,
16 d: &hir::RemoveThisSemicolon, 13 d: &hir::RemoveThisSemicolon,
17) -> Diagnostic { 14) -> Diagnostic {
@@ -45,14 +42,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<V
45 42
46#[cfg(test)] 43#[cfg(test)]
47mod tests { 44mod tests {
48 use crate::diagnostics::tests::{check_diagnostics, check_fix}; 45 use crate::tests::{check_diagnostics, check_fix};
49 46
50 #[test] 47 #[test]
51 fn missing_semicolon() { 48 fn missing_semicolon() {
52 check_diagnostics( 49 check_diagnostics(
53 r#" 50 r#"
54fn test() -> i32 { 123; } 51fn test() -> i32 { 123; }
55 //^^^ remove this semicolon 52 //^^^ 💡 error: remove this semicolon
56"#, 53"#,
57 ); 54 );
58 } 55 }
diff --git a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index f3b011495..839ceac03 100644
--- a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs
+++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -6,15 +6,12 @@ use syntax::{
6}; 6};
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity};
10 diagnostics::{fix, Diagnostic, DiagnosticsContext},
11 Assist, Severity,
12};
13 10
14// Diagnostic: replace-filter-map-next-with-find-map 11// Diagnostic: replace-filter-map-next-with-find-map
15// 12//
16// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. 13// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
17pub(super) fn replace_filter_map_next_with_find_map( 14pub(crate) fn replace_filter_map_next_with_find_map(
18 ctx: &DiagnosticsContext<'_>, 15 ctx: &DiagnosticsContext<'_>,
19 d: &hir::ReplaceFilterMapNextWithFindMap, 16 d: &hir::ReplaceFilterMapNextWithFindMap,
20) -> Diagnostic { 17) -> Diagnostic {
@@ -58,44 +55,16 @@ fn fixes(
58 55
59#[cfg(test)] 56#[cfg(test)]
60mod tests { 57mod tests {
61 use crate::diagnostics::tests::check_fix; 58 use crate::tests::{check_diagnostics, check_fix};
62
63 // Register the required standard library types to make the tests work
64 #[track_caller]
65 fn check_diagnostics(ra_fixture: &str) {
66 let prefix = r#"
67//- /main.rs crate:main deps:core
68use core::iter::Iterator;
69use core::option::Option::{self, Some, None};
70"#;
71 let suffix = r#"
72//- /core/lib.rs crate:core
73pub mod option {
74 pub enum Option<T> { Some(T), None }
75}
76pub mod iter {
77 pub trait Iterator {
78 type Item;
79 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
80 fn next(&mut self) -> Option<Self::Item>;
81 }
82 pub struct FilterMap {}
83 impl Iterator for FilterMap {
84 type Item = i32;
85 fn next(&mut self) -> i32 { 7 }
86 }
87}
88"#;
89 crate::diagnostics::tests::check_diagnostics(&format!("{}{}{}", prefix, ra_fixture, suffix))
90 }
91 59
92 #[test] 60 #[test]
93 fn replace_filter_map_next_with_find_map2() { 61 fn replace_filter_map_next_with_find_map2() {
94 check_diagnostics( 62 check_diagnostics(
95 r#" 63 r#"
96 fn foo() { 64//- minicore: iterators
97 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); 65fn foo() {
98 } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) 66 let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
67} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
99"#, 68"#,
100 ); 69 );
101 } 70 }
@@ -104,11 +73,11 @@ pub mod iter {
104 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { 73 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
105 check_diagnostics( 74 check_diagnostics(
106 r#" 75 r#"
76//- minicore: iterators
107fn foo() { 77fn foo() {
108 let m = [1, 2, 3] 78 let m = core::iter::repeat(())
109 .iter() 79 .filter_map(|()| Some(92))
110 .filter_map(|x| if *x == 2 { Some (4) } else { None }) 80 .count();
111 .len();
112} 81}
113"#, 82"#,
114 ); 83 );
@@ -118,12 +87,12 @@ fn foo() {
118 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { 87 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
119 check_diagnostics( 88 check_diagnostics(
120 r#" 89 r#"
90//- minicore: iterators
121fn foo() { 91fn foo() {
122 let m = [1, 2, 3] 92 let m = core::iter::repeat(())
123 .iter() 93 .filter_map(|()| Some(92))
124 .filter_map(|x| if *x == 2 { Some (4) } else { None })
125 .map(|x| x + 2) 94 .map(|x| x + 2)
126 .len(); 95 .next();
127} 96}
128"#, 97"#,
129 ); 98 );
@@ -133,10 +102,10 @@ fn foo() {
133 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { 102 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
134 check_diagnostics( 103 check_diagnostics(
135 r#" 104 r#"
105//- minicore: iterators
136fn foo() { 106fn foo() {
137 let m = [1, 2, 3] 107 let m = core::iter::repeat(())
138 .iter() 108 .filter_map(|()| Some(92));
139 .filter_map(|x| if *x == 2 { Some (4) } else { None });
140 let n = m.next(); 109 let n = m.next();
141} 110}
142"#, 111"#,
@@ -147,34 +116,14 @@ fn foo() {
147 fn replace_with_wind_map() { 116 fn replace_with_wind_map() {
148 check_fix( 117 check_fix(
149 r#" 118 r#"
150//- /main.rs crate:main deps:core 119//- minicore: iterators
151use core::iter::Iterator;
152use core::option::Option::{self, Some, None};
153fn foo() { 120fn foo() {
154 let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); 121 let m = core::iter::repeat(()).$0filter_map(|()| Some(92)).next();
155}
156//- /core/lib.rs crate:core
157pub mod option {
158 pub enum Option<T> { Some(T), None }
159}
160pub mod iter {
161 pub trait Iterator {
162 type Item;
163 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
164 fn next(&mut self) -> Option<Self::Item>;
165 }
166 pub struct FilterMap {}
167 impl Iterator for FilterMap {
168 type Item = i32;
169 fn next(&mut self) -> i32 { 7 }
170 }
171} 122}
172"#, 123"#,
173 r#" 124 r#"
174use core::iter::Iterator;
175use core::option::Option::{self, Some, None};
176fn foo() { 125fn foo() {
177 let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None }); 126 let m = core::iter::repeat(()).find_map(|()| Some(92));
178} 127}
179"#, 128"#,
180 ) 129 )
diff --git a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs
index 09faa3bbc..e879de75c 100644
--- a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs
+++ b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs
@@ -1,12 +1,9 @@
1use crate::{ 1use crate::{Diagnostic, DiagnosticsContext, Severity};
2 diagnostics::{Diagnostic, DiagnosticsContext},
3 Severity,
4};
5 2
6// Diagnostic: unimplemented-builtin-macro 3// Diagnostic: unimplemented-builtin-macro
7// 4//
8// This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer 5// This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer
9pub(super) fn unimplemented_builtin_macro( 6pub(crate) fn unimplemented_builtin_macro(
10 ctx: &DiagnosticsContext<'_>, 7 ctx: &DiagnosticsContext<'_>,
11 d: &hir::UnimplementedBuiltinMacro, 8 d: &hir::UnimplementedBuiltinMacro,
12) -> Diagnostic { 9) -> Diagnostic {
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
index a5b2e3399..8e601fa48 100644
--- a/crates/ide/src/diagnostics/unlinked_file.rs
+++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
@@ -12,37 +12,31 @@ use syntax::{
12}; 12};
13use text_edit::TextEdit; 13use text_edit::TextEdit;
14 14
15use crate::{ 15use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
16 diagnostics::{fix, DiagnosticsContext},
17 Assist, Diagnostic,
18};
19
20#[derive(Debug)]
21pub(crate) struct UnlinkedFile {
22 pub(crate) file: FileId,
23}
24 16
25// Diagnostic: unlinked-file 17// Diagnostic: unlinked-file
26// 18//
27// This diagnostic is shown for files that are not included in any crate, or files that are part of 19// This diagnostic is shown for files that are not included in any crate, or files that are part of
28// crates rust-analyzer failed to discover. The file will not have IDE features available. 20// crates rust-analyzer failed to discover. The file will not have IDE features available.
29pub(super) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { 21pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec<Diagnostic>, file_id: FileId) {
30 // Limit diagnostic to the first few characters in the file. This matches how VS Code 22 // Limit diagnostic to the first few characters in the file. This matches how VS Code
31 // renders it with the full span, but on other editors, and is less invasive. 23 // renders it with the full span, but on other editors, and is less invasive.
32 let range = ctx.sema.db.parse(d.file).syntax_node().text_range(); 24 let range = ctx.sema.db.parse(file_id).syntax_node().text_range();
33 // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. 25 // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`.
34 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); 26 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
35 27
36 Diagnostic::new("unlinked-file", "file not included in module tree", range) 28 acc.push(
37 .with_fixes(fixes(ctx, d)) 29 Diagnostic::new("unlinked-file", "file not included in module tree", range)
30 .with_fixes(fixes(ctx, file_id)),
31 );
38} 32}
39 33
40fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { 34fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option<Vec<Assist>> {
41 // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, 35 // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file,
42 // suggest that as a fix. 36 // suggest that as a fix.
43 37
44 let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file)); 38 let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id));
45 let our_path = source_root.path_for_file(&d.file)?; 39 let our_path = source_root.path_for_file(&file_id)?;
46 let module_name = our_path.name_and_extension()?.0; 40 let module_name = our_path.name_and_extension()?.0;
47 41
48 // Candidates to look for: 42 // Candidates to look for:
@@ -71,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> {
71 } 65 }
72 66
73 if module.origin.file_id() == Some(*parent_id) { 67 if module.origin.file_id() == Some(*parent_id) {
74 return make_fixes(ctx.sema.db, *parent_id, module_name, d.file); 68 return make_fixes(ctx.sema.db, *parent_id, module_name, file_id);
75 } 69 }
76 } 70 }
77 } 71 }
@@ -164,7 +158,7 @@ fn make_fixes(
164 158
165#[cfg(test)] 159#[cfg(test)]
166mod tests { 160mod tests {
167 use crate::diagnostics::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; 161 use crate::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix};
168 162
169 #[test] 163 #[test]
170 fn unlinked_file_prepend_first_item() { 164 fn unlinked_file_prepend_first_item() {
diff --git a/crates/ide/src/diagnostics/unresolved_extern_crate.rs b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs
index 2ea79c2ee..74e4a69c6 100644
--- a/crates/ide/src/diagnostics/unresolved_extern_crate.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs
@@ -1,9 +1,9 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: unresolved-extern-crate 3// Diagnostic: unresolved-extern-crate
4// 4//
5// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. 5// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
6pub(super) fn unresolved_extern_crate( 6pub(crate) fn unresolved_extern_crate(
7 ctx: &DiagnosticsContext<'_>, 7 ctx: &DiagnosticsContext<'_>,
8 d: &hir::UnresolvedExternCrate, 8 d: &hir::UnresolvedExternCrate,
9) -> Diagnostic { 9) -> Diagnostic {
@@ -16,7 +16,7 @@ pub(super) fn unresolved_extern_crate(
16 16
17#[cfg(test)] 17#[cfg(test)]
18mod tests { 18mod tests {
19 use crate::diagnostics::tests::check_diagnostics; 19 use crate::tests::check_diagnostics;
20 20
21 #[test] 21 #[test]
22 fn unresolved_extern_crate() { 22 fn unresolved_extern_crate() {
@@ -25,7 +25,7 @@ mod tests {
25//- /main.rs crate:main deps:core 25//- /main.rs crate:main deps:core
26extern crate core; 26extern crate core;
27 extern crate doesnotexist; 27 extern crate doesnotexist;
28//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 28//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
29//- /lib.rs crate:core 29//- /lib.rs crate:core
30"#, 30"#,
31 ); 31 );
@@ -38,7 +38,7 @@ extern crate core;
38 r#" 38 r#"
39//- /lib.rs 39//- /lib.rs
40 extern crate doesnotexist; 40 extern crate doesnotexist;
41//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 41//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
42// Should not error. 42// Should not error.
43extern crate self as foo; 43extern crate self as foo;
44struct Foo; 44struct Foo;
diff --git a/crates/ide/src/diagnostics/unresolved_import.rs b/crates/ide_diagnostics/src/handlers/unresolved_import.rs
index 1cbf96ba1..e52a88459 100644
--- a/crates/ide/src/diagnostics/unresolved_import.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_import.rs
@@ -1,10 +1,10 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 1use crate::{Diagnostic, DiagnosticsContext};
2 2
3// Diagnostic: unresolved-import 3// Diagnostic: unresolved-import
4// 4//
5// This diagnostic is triggered if rust-analyzer is unable to resolve a path in 5// This diagnostic is triggered if rust-analyzer is unable to resolve a path in
6// a `use` declaration. 6// a `use` declaration.
7pub(super) fn unresolved_import( 7pub(crate) fn unresolved_import(
8 ctx: &DiagnosticsContext<'_>, 8 ctx: &DiagnosticsContext<'_>,
9 d: &hir::UnresolvedImport, 9 d: &hir::UnresolvedImport,
10) -> Diagnostic { 10) -> Diagnostic {
@@ -22,7 +22,7 @@ pub(super) fn unresolved_import(
22 22
23#[cfg(test)] 23#[cfg(test)]
24mod tests { 24mod tests {
25 use crate::diagnostics::tests::check_diagnostics; 25 use crate::tests::check_diagnostics;
26 26
27 #[test] 27 #[test]
28 fn unresolved_import() { 28 fn unresolved_import() {
@@ -30,7 +30,7 @@ mod tests {
30 r#" 30 r#"
31use does_exist; 31use does_exist;
32use does_not_exist; 32use does_not_exist;
33 //^^^^^^^^^^^^^^ unresolved import 33 //^^^^^^^^^^^^^^ error: unresolved import
34 34
35mod does_exist {} 35mod does_exist {}
36"#, 36"#,
@@ -43,18 +43,18 @@ mod does_exist {}
43 check_diagnostics( 43 check_diagnostics(
44 r#" 44 r#"
45use does_exist::{Exists, DoesntExist}; 45use does_exist::{Exists, DoesntExist};
46 //^^^^^^^^^^^ unresolved import 46 //^^^^^^^^^^^ error: unresolved import
47 47
48use {does_not_exist::*, does_exist}; 48use {does_not_exist::*, does_exist};
49 //^^^^^^^^^^^^^^^^^ unresolved import 49 //^^^^^^^^^^^^^^^^^ error: unresolved import
50 50
51use does_not_exist::{ 51use does_not_exist::{
52 a, 52 a,
53 //^ unresolved import 53 //^ error: unresolved import
54 b, 54 b,
55 //^ unresolved import 55 //^ error: unresolved import
56 c, 56 c,
57 //^ unresolved import 57 //^ error: unresolved import
58}; 58};
59 59
60mod does_exist { 60mod does_exist {
@@ -71,18 +71,18 @@ mod does_exist {
71//- /main.rs crate:main 71//- /main.rs crate:main
72mod a { 72mod a {
73 extern crate doesnotexist; 73 extern crate doesnotexist;
74 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 74 //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
75 75
76 // Should not error, since we already errored for the missing crate. 76 // Should not error, since we already errored for the missing crate.
77 use doesnotexist::{self, bla, *}; 77 use doesnotexist::{self, bla, *};
78 78
79 use crate::doesnotexist; 79 use crate::doesnotexist;
80 //^^^^^^^^^^^^^^^^^^^ unresolved import 80 //^^^^^^^^^^^^^^^^^^^ error: unresolved import
81} 81}
82 82
83mod m { 83mod m {
84 use super::doesnotexist; 84 use super::doesnotexist;
85 //^^^^^^^^^^^^^^^^^^^ unresolved import 85 //^^^^^^^^^^^^^^^^^^^ error: unresolved import
86} 86}
87"#, 87"#,
88 ); 88 );
diff --git a/crates/ide/src/diagnostics/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
index 15b6a2730..f0f7725db 100644
--- a/crates/ide/src/diagnostics/unresolved_macro_call.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
@@ -1,13 +1,13 @@
1use hir::{db::AstDatabase, InFile}; 1use hir::{db::AstDatabase, InFile};
2use syntax::{AstNode, SyntaxNodePtr}; 2use syntax::{AstNode, SyntaxNodePtr};
3 3
4use crate::diagnostics::{Diagnostic, DiagnosticsContext}; 4use crate::{Diagnostic, DiagnosticsContext};
5 5
6// Diagnostic: unresolved-macro-call 6// Diagnostic: unresolved-macro-call
7// 7//
8// This diagnostic is triggered if rust-analyzer is unable to resolve the path 8// This diagnostic is triggered if rust-analyzer is unable to resolve the path
9// to a macro in a macro invocation. 9// to a macro in a macro invocation.
10pub(super) fn unresolved_macro_call( 10pub(crate) fn unresolved_macro_call(
11 ctx: &DiagnosticsContext<'_>, 11 ctx: &DiagnosticsContext<'_>,
12 d: &hir::UnresolvedMacroCall, 12 d: &hir::UnresolvedMacroCall,
13) -> Diagnostic { 13) -> Diagnostic {
@@ -32,7 +32,7 @@ pub(super) fn unresolved_macro_call(
32 32
33#[cfg(test)] 33#[cfg(test)]
34mod tests { 34mod tests {
35 use crate::diagnostics::tests::check_diagnostics; 35 use crate::tests::check_diagnostics;
36 36
37 #[test] 37 #[test]
38 fn unresolved_macro_diag() { 38 fn unresolved_macro_diag() {
@@ -40,7 +40,7 @@ mod tests {
40 r#" 40 r#"
41fn f() { 41fn f() {
42 m!(); 42 m!();
43} //^ unresolved macro `m!` 43} //^ error: unresolved macro `m!`
44 44
45"#, 45"#,
46 ); 46 );
@@ -51,7 +51,7 @@ fn f() {
51 check_diagnostics( 51 check_diagnostics(
52 r#" 52 r#"
53foo::bar!(92); 53foo::bar!(92);
54 //^^^ unresolved macro `foo::bar!` 54 //^^^ error: unresolved macro `foo::bar!`
55"#, 55"#,
56 ); 56 );
57 } 57 }
@@ -63,7 +63,7 @@ foo::bar!(92);
63macro_rules! m { () => {} } 63macro_rules! m { () => {} }
64 64
65m!(); m2!(); 65m!(); m2!();
66 //^^ unresolved macro `self::m2!` 66 //^^ error: unresolved macro `self::m2!`
67"#, 67"#,
68 ); 68 );
69 } 69 }
@@ -77,7 +77,7 @@ mod mac {
77macro_rules! m { () => {} } } 77macro_rules! m { () => {} } }
78 78
79self::m!(); self::m2!(); 79self::m!(); self::m2!();
80 //^^ unresolved macro `self::m2!` 80 //^^ error: unresolved macro `self::m2!`
81"#, 81"#,
82 ); 82 );
83 } 83 }
diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide_diagnostics/src/handlers/unresolved_module.rs
index 977b46414..61fc43604 100644
--- a/crates/ide/src/diagnostics/unresolved_module.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_module.rs
@@ -1,14 +1,13 @@
1use hir::db::AstDatabase; 1use hir::db::AstDatabase;
2use ide_assists::Assist; 2use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit};
3use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit};
4use syntax::AstNode; 3use syntax::AstNode;
5 4
6use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; 5use crate::{fix, Diagnostic, DiagnosticsContext};
7 6
8// Diagnostic: unresolved-module 7// Diagnostic: unresolved-module
9// 8//
10// This diagnostic is triggered if rust-analyzer is unable to discover referred module. 9// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
11pub(super) fn unresolved_module( 10pub(crate) fn unresolved_module(
12 ctx: &DiagnosticsContext<'_>, 11 ctx: &DiagnosticsContext<'_>,
13 d: &hir::UnresolvedModule, 12 d: &hir::UnresolvedModule,
14) -> Diagnostic { 13) -> Diagnostic {
@@ -42,7 +41,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option<Vec<
42mod tests { 41mod tests {
43 use expect_test::expect; 42 use expect_test::expect;
44 43
45 use crate::diagnostics::tests::{check_diagnostics, check_expect}; 44 use crate::tests::{check_diagnostics, check_expect};
46 45
47 #[test] 46 #[test]
48 fn unresolved_module() { 47 fn unresolved_module() {
@@ -51,7 +50,7 @@ mod tests {
51//- /lib.rs 50//- /lib.rs
52mod foo; 51mod foo;
53 mod bar; 52 mod bar;
54//^^^^^^^^ unresolved module 53//^^^^^^^^ 💡 error: unresolved module
55mod baz {} 54mod baz {}
56//- /foo.rs 55//- /foo.rs
57"#, 56"#,
diff --git a/crates/ide/src/diagnostics/unresolved_proc_macro.rs b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs
index 3dc6ab451..fde1d1323 100644
--- a/crates/ide/src/diagnostics/unresolved_proc_macro.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs
@@ -1,7 +1,4 @@
1use crate::{ 1use crate::{Diagnostic, DiagnosticsContext, Severity};
2 diagnostics::{Diagnostic, DiagnosticsContext},
3 Severity,
4};
5 2
6// Diagnostic: unresolved-proc-macro 3// Diagnostic: unresolved-proc-macro
7// 4//
@@ -12,7 +9,7 @@ use crate::{
12// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the 9// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
13// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can 10// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
14// enable support for procedural macros (see `rust-analyzer.procMacro.enable`). 11// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
15pub(super) fn unresolved_proc_macro( 12pub(crate) fn unresolved_proc_macro(
16 ctx: &DiagnosticsContext<'_>, 13 ctx: &DiagnosticsContext<'_>,
17 d: &hir::UnresolvedProcMacro, 14 d: &hir::UnresolvedProcMacro,
18) -> Diagnostic { 15) -> Diagnostic {
diff --git a/crates/ide_diagnostics/src/handlers/useless_braces.rs b/crates/ide_diagnostics/src/handlers/useless_braces.rs
new file mode 100644
index 000000000..8b9330e04
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/useless_braces.rs
@@ -0,0 +1,148 @@
1use ide_db::{base_db::FileId, source_change::SourceChange};
2use itertools::Itertools;
3use syntax::{ast, AstNode, SyntaxNode, TextRange};
4use text_edit::TextEdit;
5
6use crate::{fix, Diagnostic, Severity};
7
8// Diagnostic: unnecessary-braces
9//
10// Diagnostic for unnecessary braces in `use` items.
11pub(crate) fn useless_braces(
12 acc: &mut Vec<Diagnostic>,
13 file_id: FileId,
14 node: &SyntaxNode,
15) -> Option<()> {
16 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
17 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
18 // If there is a comment inside the bracketed `use`,
19 // assume it is a commented out module path and don't show diagnostic.
20 if use_tree_list.has_inner_comment() {
21 return Some(());
22 }
23
24 let use_range = use_tree_list.syntax().text_range();
25 let edit = remove_braces(&single_use_tree).unwrap_or_else(|| {
26 let to_replace = single_use_tree.syntax().text().to_string();
27 let mut edit_builder = TextEdit::builder();
28 edit_builder.delete(use_range);
29 edit_builder.insert(use_range.start(), to_replace);
30 edit_builder.finish()
31 });
32
33 acc.push(
34 Diagnostic::new(
35 "unnecessary-braces",
36 "Unnecessary braces in use statement".to_string(),
37 use_range,
38 )
39 .severity(Severity::WeakWarning)
40 .with_fixes(Some(vec![fix(
41 "remove_braces",
42 "Remove unnecessary braces",
43 SourceChange::from_text_edit(file_id, edit),
44 use_range,
45 )])),
46 );
47 }
48
49 Some(())
50}
51
52fn remove_braces(single_use_tree: &ast::UseTree) -> Option<TextEdit> {
53 let use_tree_list_node = single_use_tree.syntax().parent()?;
54 if single_use_tree.path()?.segment()?.self_token().is_some() {
55 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
56 let end = use_tree_list_node.text_range().end();
57 return Some(TextEdit::delete(TextRange::new(start, end)));
58 }
59 None
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::tests::{check_diagnostics, check_fix};
65
66 #[test]
67 fn test_check_unnecessary_braces_in_use_statement() {
68 check_diagnostics(
69 r#"
70use a;
71use a::{c, d::e};
72
73mod a {
74 mod c {}
75 mod d {
76 mod e {}
77 }
78}
79"#,
80 );
81 check_diagnostics(
82 r#"
83use a;
84use a::{
85 c,
86 // d::e
87};
88
89mod a {
90 mod c {}
91 mod d {
92 mod e {}
93 }
94}
95"#,
96 );
97 check_fix(
98 r#"
99mod b {}
100use {$0b};
101"#,
102 r#"
103mod b {}
104use b;
105"#,
106 );
107 check_fix(
108 r#"
109mod b {}
110use {b$0};
111"#,
112 r#"
113mod b {}
114use b;
115"#,
116 );
117 check_fix(
118 r#"
119mod a { mod c {} }
120use a::{c$0};
121"#,
122 r#"
123mod a { mod c {} }
124use a::c;
125"#,
126 );
127 check_fix(
128 r#"
129mod a {}
130use a::{self$0};
131"#,
132 r#"
133mod a {}
134use a;
135"#,
136 );
137 check_fix(
138 r#"
139mod a { mod c {} mod d { mod e {} } }
140use a::{c, d::{e$0}};
141"#,
142 r#"
143mod a { mod c {} mod d { mod e {} } }
144use a::{c, d::e};
145"#,
146 );
147 }
148}
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs
new file mode 100644
index 000000000..6ad1b4373
--- /dev/null
+++ b/crates/ide_diagnostics/src/lib.rs
@@ -0,0 +1,374 @@
1//! Diagnostics rendering and fixits.
2//!
3//! Most of the diagnostics originate from the dark depth of the compiler, and
4//! are originally expressed in term of IR. When we emit the diagnostic, we are
5//! usually not in the position to decide how to best "render" it in terms of
6//! user-authored source code. We are especially not in the position to offer
7//! fixits, as the compiler completely lacks the infrastructure to edit the
8//! source code.
9//!
10//! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate,
11//! where we "cook" them so that each diagnostic is formulated in terms of `hir`
12//! types. Well, at least that's the aspiration, the "cooking" is somewhat
13//! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic
14//! structs from hir, and we want to render them to unified serializable
15//! representation (span, level, message) here. If we can, we also provide
16//! fixits. By the way, that's why we want to keep diagnostics structured
17//! internally -- so that we have all the info to make fixes.
18//!
19//! We have one "handler" module per diagnostic code. Such a module contains
20//! rendering, optional fixes and tests. It's OK if some low-level compiler
21//! functionality ends up being tested via a diagnostic.
22//!
23//! There are also a couple of ad-hoc diagnostics implemented directly here, we
24//! don't yet have a great pattern for how to do them properly.
25
26mod handlers {
27 pub(crate) mod break_outside_of_loop;
28 pub(crate) mod inactive_code;
29 pub(crate) mod incorrect_case;
30 pub(crate) mod macro_error;
31 pub(crate) mod mismatched_arg_count;
32 pub(crate) mod missing_fields;
33 pub(crate) mod missing_match_arms;
34 pub(crate) mod missing_ok_or_some_in_tail_expr;
35 pub(crate) mod missing_unsafe;
36 pub(crate) mod no_such_field;
37 pub(crate) mod remove_this_semicolon;
38 pub(crate) mod replace_filter_map_next_with_find_map;
39 pub(crate) mod unimplemented_builtin_macro;
40 pub(crate) mod unresolved_extern_crate;
41 pub(crate) mod unresolved_import;
42 pub(crate) mod unresolved_macro_call;
43 pub(crate) mod unresolved_module;
44 pub(crate) mod unresolved_proc_macro;
45
46 // The handlers bellow are unusual, the implement the diagnostics as well.
47 pub(crate) mod field_shorthand;
48 pub(crate) mod useless_braces;
49 pub(crate) mod unlinked_file;
50}
51
52use hir::{diagnostics::AnyDiagnostic, Semantics};
53use ide_db::{
54 assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
55 base_db::{FileId, SourceDatabase},
56 label::Label,
57 source_change::SourceChange,
58 RootDatabase,
59};
60use rustc_hash::FxHashSet;
61use syntax::{ast::AstNode, TextRange};
62
63#[derive(Copy, Clone, Debug, PartialEq)]
64pub struct DiagnosticCode(pub &'static str);
65
66impl DiagnosticCode {
67 pub fn as_str(&self) -> &str {
68 self.0
69 }
70}
71
72#[derive(Debug)]
73pub struct Diagnostic {
74 pub code: DiagnosticCode,
75 pub message: String,
76 pub range: TextRange,
77 pub severity: Severity,
78 pub unused: bool,
79 pub experimental: bool,
80 pub fixes: Option<Vec<Assist>>,
81}
82
83impl Diagnostic {
84 fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
85 let message = message.into();
86 Diagnostic {
87 code: DiagnosticCode(code),
88 message,
89 range,
90 severity: Severity::Error,
91 unused: false,
92 experimental: false,
93 fixes: None,
94 }
95 }
96
97 fn experimental(mut self) -> Diagnostic {
98 self.experimental = true;
99 self
100 }
101
102 fn severity(mut self, severity: Severity) -> Diagnostic {
103 self.severity = severity;
104 self
105 }
106
107 fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic {
108 self.fixes = fixes;
109 self
110 }
111
112 fn with_unused(mut self, unused: bool) -> Diagnostic {
113 self.unused = unused;
114 self
115 }
116}
117
118#[derive(Debug, Copy, Clone)]
119pub enum Severity {
120 Error,
121 // We don't actually emit this one yet, but we should at some point.
122 // Warning,
123 WeakWarning,
124}
125
126#[derive(Default, Debug, Clone)]
127pub struct DiagnosticsConfig {
128 pub disable_experimental: bool,
129 pub disabled: FxHashSet<String>,
130}
131
132struct DiagnosticsContext<'a> {
133 config: &'a DiagnosticsConfig,
134 sema: Semantics<'a, RootDatabase>,
135 resolve: &'a AssistResolveStrategy,
136}
137
138pub fn diagnostics(
139 db: &RootDatabase,
140 config: &DiagnosticsConfig,
141 resolve: &AssistResolveStrategy,
142 file_id: FileId,
143) -> Vec<Diagnostic> {
144 let _p = profile::span("diagnostics");
145 let sema = Semantics::new(db);
146 let parse = db.parse(file_id);
147 let mut res = Vec::new();
148
149 // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
150 res.extend(
151 parse.errors().iter().take(128).map(|err| {
152 Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range())
153 }),
154 );
155
156 for node in parse.tree().syntax().descendants() {
157 handlers::useless_braces::useless_braces(&mut res, file_id, &node);
158 handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
159 }
160
161 let module = sema.to_module_def(file_id);
162
163 let ctx = DiagnosticsContext { config, sema, resolve };
164 if module.is_none() {
165 handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
166 }
167
168 let mut diags = Vec::new();
169 if let Some(m) = module {
170 m.diagnostics(db, &mut diags)
171 }
172
173 for diag in diags {
174 #[rustfmt::skip]
175 let d = match diag {
176 AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
177 AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
178 AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
179 AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d),
180 AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d),
181 AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
182 AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => handlers::missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
183 AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
184 AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
185 AnyDiagnostic::RemoveThisSemicolon(d) => handlers::remove_this_semicolon::remove_this_semicolon(&ctx, &d),
186 AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
187 AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
188 AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
189 AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
190 AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
191 AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
192 AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
193
194 AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
195 Some(it) => it,
196 None => continue,
197 }
198 };
199 res.push(d)
200 }
201
202 res.retain(|d| {
203 !ctx.config.disabled.contains(d.code.as_str())
204 && !(ctx.config.disable_experimental && d.experimental)
205 });
206
207 res
208}
209
210fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
211 let mut res = unresolved_fix(id, label, target);
212 res.source_change = Some(source_change);
213 res
214}
215
216fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
217 assert!(!id.contains(' '));
218 Assist {
219 id: AssistId(id, AssistKind::QuickFix),
220 label: Label::new(label),
221 group: None,
222 target,
223 source_change: None,
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use expect_test::Expect;
230 use ide_db::{
231 assists::AssistResolveStrategy,
232 base_db::{fixture::WithFixture, SourceDatabaseExt},
233 RootDatabase,
234 };
235 use stdx::trim_indent;
236 use test_utils::{assert_eq_text, extract_annotations};
237
238 use crate::{DiagnosticsConfig, Severity};
239
240 /// Takes a multi-file input fixture with annotated cursor positions,
241 /// and checks that:
242 /// * a diagnostic is produced
243 /// * the first diagnostic fix trigger range touches the input cursor position
244 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
245 #[track_caller]
246 pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
247 check_nth_fix(0, ra_fixture_before, ra_fixture_after);
248 }
249 /// Takes a multi-file input fixture with annotated cursor positions,
250 /// and checks that:
251 /// * a diagnostic is produced
252 /// * every diagnostic fixes trigger range touches the input cursor position
253 /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
254 pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
255 for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
256 check_nth_fix(i, ra_fixture_before, ra_fixture_after)
257 }
258 }
259
260 #[track_caller]
261 fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
262 let after = trim_indent(ra_fixture_after);
263
264 let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
265 let diagnostic = super::diagnostics(
266 &db,
267 &DiagnosticsConfig::default(),
268 &AssistResolveStrategy::All,
269 file_position.file_id,
270 )
271 .pop()
272 .expect("no diagnostics");
273 let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth];
274 let actual = {
275 let source_change = fix.source_change.as_ref().unwrap();
276 let file_id = *source_change.source_file_edits.keys().next().unwrap();
277 let mut actual = db.file_text(file_id).to_string();
278
279 for edit in source_change.source_file_edits.values() {
280 edit.apply(&mut actual);
281 }
282 actual
283 };
284
285 assert_eq_text!(&after, &actual);
286 assert!(
287 fix.target.contains_inclusive(file_position.offset),
288 "diagnostic fix range {:?} does not touch cursor position {:?}",
289 fix.target,
290 file_position.offset
291 );
292 }
293
294 /// Checks that there's a diagnostic *without* fix at `$0`.
295 pub(crate) fn check_no_fix(ra_fixture: &str) {
296 let (db, file_position) = RootDatabase::with_position(ra_fixture);
297 let diagnostic = super::diagnostics(
298 &db,
299 &DiagnosticsConfig::default(),
300 &AssistResolveStrategy::All,
301 file_position.file_id,
302 )
303 .pop()
304 .unwrap();
305 assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic);
306 }
307
308 pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
309 let (db, file_id) = RootDatabase::with_single_file(ra_fixture);
310 let diagnostics = super::diagnostics(
311 &db,
312 &DiagnosticsConfig::default(),
313 &AssistResolveStrategy::All,
314 file_id,
315 );
316 expect.assert_debug_eq(&diagnostics)
317 }
318
319 #[track_caller]
320 pub(crate) fn check_diagnostics(ra_fixture: &str) {
321 let mut config = DiagnosticsConfig::default();
322 config.disabled.insert("inactive-code".to_string());
323 check_diagnostics_with_config(config, ra_fixture)
324 }
325
326 #[track_caller]
327 pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
328 let (db, files) = RootDatabase::with_many_files(ra_fixture);
329 for file_id in files {
330 let diagnostics =
331 super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
332
333 let expected = extract_annotations(&*db.file_text(file_id));
334 let mut actual = diagnostics
335 .into_iter()
336 .map(|d| {
337 let mut annotation = String::new();
338 if let Some(fixes) = &d.fixes {
339 assert!(!fixes.is_empty());
340 annotation.push_str("💡 ")
341 }
342 annotation.push_str(match d.severity {
343 Severity::Error => "error",
344 Severity::WeakWarning => "weak",
345 });
346 annotation.push_str(": ");
347 annotation.push_str(&d.message);
348 (d.range, annotation)
349 })
350 .collect::<Vec<_>>();
351 actual.sort_by_key(|(range, _)| range.start());
352 assert_eq!(expected, actual);
353 }
354 }
355
356 #[test]
357 fn test_disabled_diagnostics() {
358 let mut config = DiagnosticsConfig::default();
359 config.disabled.insert("unresolved-module".into());
360
361 let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#);
362
363 let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
364 assert!(diagnostics.is_empty());
365
366 let diagnostics = super::diagnostics(
367 &db,
368 &DiagnosticsConfig::default(),
369 &AssistResolveStrategy::All,
370 file_id,
371 );
372 assert!(!diagnostics.is_empty());
373 }
374}
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index c2a9a38c9..b4f2fe9a4 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -804,33 +804,17 @@ impl<'a> TtIter<'a> {
804 }; 804 };
805 805
806 match (punct.char, second, third) { 806 match (punct.char, second, third) {
807 ('.', '.', Some('.')) 807 ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => {
808 | ('.', '.', Some('='))
809 | ('<', '<', Some('='))
810 | ('>', '>', Some('=')) => {
811 let tt2 = self.next().unwrap().clone(); 808 let tt2 = self.next().unwrap().clone();
812 let tt3 = self.next().unwrap().clone(); 809 let tt3 = self.next().unwrap().clone();
813 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) 810 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
814 } 811 }
815 ('-', '=', _) 812 ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
816 | ('-', '>', _) 813 | ('-' | '=' | '>', '>', _)
817 | (':', ':', _) 814 | (':', ':', _)
818 | ('!', '=', _)
819 | ('.', '.', _) 815 | ('.', '.', _)
820 | ('*', '=', _)
821 | ('/', '=', _)
822 | ('&', '&', _) 816 | ('&', '&', _)
823 | ('&', '=', _)
824 | ('%', '=', _)
825 | ('^', '=', _)
826 | ('+', '=', _)
827 | ('<', '<', _) 817 | ('<', '<', _)
828 | ('<', '=', _)
829 | ('=', '=', _)
830 | ('=', '>', _)
831 | ('>', '=', _)
832 | ('>', '>', _)
833 | ('|', '=', _)
834 | ('|', '|', _) => { 818 | ('|', '|', _) => {
835 let tt2 = self.next().unwrap().clone(); 819 let tt2 = self.next().unwrap().clone();
836 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) 820 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into())
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs
index 01ee26a53..5a78675fb 100644
--- a/crates/parser/src/grammar/params.rs
+++ b/crates/parser/src/grammar/params.rs
@@ -184,8 +184,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
184 if !matches!( 184 if !matches!(
185 (p.current(), la1, la2, la3), 185 (p.current(), la1, la2, la3),
186 (T![&], T![self], _, _) 186 (T![&], T![self], _, _)
187 | (T![&], T![mut], T![self], _) 187 | (T![&], T![mut] | LIFETIME_IDENT, T![self], _)
188 | (T![&], LIFETIME_IDENT, T![self], _)
189 | (T![&], LIFETIME_IDENT, T![mut], T![self]) 188 | (T![&], LIFETIME_IDENT, T![mut], T![self])
190 ) { 189 ) {
191 return Err(m); 190 return Err(m);
diff --git a/crates/proc_macro_api/src/version.rs b/crates/proc_macro_api/src/version.rs
index 28a4ac086..434decc7e 100644
--- a/crates/proc_macro_api/src/version.rs
+++ b/crates/proc_macro_api/src/version.rs
@@ -28,23 +28,23 @@ pub fn read_dylib_info(dylib_path: &Path) -> io::Result<RustCInfo> {
28 28
29 let ver_str = read_version(dylib_path)?; 29 let ver_str = read_version(dylib_path)?;
30 let mut items = ver_str.split_whitespace(); 30 let mut items = ver_str.split_whitespace();
31 let tag = items.next().ok_or(err!("version format error"))?; 31 let tag = items.next().ok_or_else(|| err!("version format error"))?;
32 if tag != "rustc" { 32 if tag != "rustc" {
33 return Err(err!("version format error (No rustc tag)")); 33 return Err(err!("version format error (No rustc tag)"));
34 } 34 }
35 35
36 let version_part = items.next().ok_or(err!("no version string"))?; 36 let version_part = items.next().ok_or_else(|| err!("no version string"))?;
37 let mut version_parts = version_part.split('-'); 37 let mut version_parts = version_part.split('-');
38 let version = version_parts.next().ok_or(err!("no version"))?; 38 let version = version_parts.next().ok_or_else(|| err!("no version"))?;
39 let channel = version_parts.next().unwrap_or_default().to_string(); 39 let channel = version_parts.next().unwrap_or_default().to_string();
40 40
41 let commit = items.next().ok_or(err!("no commit info"))?; 41 let commit = items.next().ok_or_else(|| err!("no commit info"))?;
42 // remove ( 42 // remove (
43 if commit.len() == 0 { 43 if commit.len() == 0 {
44 return Err(err!("commit format error")); 44 return Err(err!("commit format error"));
45 } 45 }
46 let commit = commit[1..].to_string(); 46 let commit = commit[1..].to_string();
47 let date = items.next().ok_or(err!("no date info"))?; 47 let date = items.next().ok_or_else(|| err!("no date info"))?;
48 // remove ) 48 // remove )
49 if date.len() == 0 { 49 if date.len() == 0 {
50 return Err(err!("date format error")); 50 return Err(err!("date format error"));
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index 53cb4bae7..45bbb08dc 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -187,7 +187,7 @@ impl WorkspaceBuildData {
187 let mut deserializer = serde_json::Deserializer::from_str(line); 187 let mut deserializer = serde_json::Deserializer::from_str(line);
188 deserializer.disable_recursion_limit(); 188 deserializer.disable_recursion_limit();
189 let message = Message::deserialize(&mut deserializer) 189 let message = Message::deserialize(&mut deserializer)
190 .unwrap_or(Message::TextLine(line.to_string())); 190 .unwrap_or_else(|_| Message::TextLine(line.to_string()));
191 191
192 match message { 192 match message {
193 Message::BuildScriptExecuted(BuildScript { 193 Message::BuildScriptExecuted(BuildScript {
@@ -229,7 +229,7 @@ impl WorkspaceBuildData {
229 Message::CompilerArtifact(message) => { 229 Message::CompilerArtifact(message) => {
230 progress(format!("metadata {}", message.target.name)); 230 progress(format!("metadata {}", message.target.name));
231 231
232 if message.target.kind.contains(&"proc-macro".to_string()) { 232 if message.target.kind.iter().any(|k| k == "proc-macro") {
233 let package_id = message.package_id; 233 let package_id = message.package_id;
234 // Skip rmeta file 234 // Skip rmeta file
235 if let Some(filename) = 235 if let Some(filename) =
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index ac079f83e..0935ea967 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -1,5 +1,6 @@
1//! See [`CargoWorkspace`]. 1//! See [`CargoWorkspace`].
2 2
3use std::iter;
3use std::path::PathBuf; 4use std::path::PathBuf;
4use std::{convert::TryInto, ops, process::Command, sync::Arc}; 5use std::{convert::TryInto, ops, process::Command, sync::Arc};
5 6
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap;
12use serde::Deserialize; 13use serde::Deserialize;
13use serde_json::from_value; 14use serde_json::from_value;
14 15
16use crate::CfgOverrides;
15use crate::{build_data::BuildDataConfig, utf8_stdout}; 17use crate::{build_data::BuildDataConfig, utf8_stdout};
16 18
17/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo 19/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
@@ -76,6 +78,21 @@ pub struct CargoConfig {
76 78
77 /// rustc private crate source 79 /// rustc private crate source
78 pub rustc_source: Option<RustcSource>, 80 pub rustc_source: Option<RustcSource>,
81
82 /// crates to disable `#[cfg(test)]` on
83 pub unset_test_crates: Vec<String>,
84}
85
86impl CargoConfig {
87 pub fn cfg_overrides(&self) -> CfgOverrides {
88 self.unset_test_crates
89 .iter()
90 .cloned()
91 .zip(iter::repeat_with(|| {
92 cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap()
93 }))
94 .collect()
95 }
79} 96}
80 97
81pub type Package = Idx<PackageData>; 98pub type Package = Idx<PackageData>;
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs
index 8c6cf94c2..1d408dff2 100644
--- a/crates/project_model/src/lib.rs
+++ b/crates/project_model/src/lib.rs
@@ -41,7 +41,7 @@ pub use crate::{
41 }, 41 },
42 project_json::{ProjectJson, ProjectJsonData}, 42 project_json::{ProjectJson, ProjectJsonData},
43 sysroot::Sysroot, 43 sysroot::Sysroot,
44 workspace::{PackageRoot, ProjectWorkspace}, 44 workspace::{CfgOverrides, PackageRoot, ProjectWorkspace},
45}; 45};
46 46
47pub use proc_macro_api::ProcMacroClient; 47pub use proc_macro_api::ProcMacroClient;
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index a22f79c15..006263da8 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -68,8 +68,9 @@ impl Sysroot {
68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { 68 pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
69 let mut sysroot = Sysroot { crates: Arena::default() }; 69 let mut sysroot = Sysroot { crates: Arena::default() };
70 70
71 for name in SYSROOT_CRATES.trim().lines() { 71 for path in SYSROOT_CRATES.trim().lines() {
72 let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)] 72 let name = path.split('/').last().unwrap();
73 let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
73 .iter() 74 .iter()
74 .map(|it| sysroot_src_dir.join(it)) 75 .map(|it| sysroot_src_dir.join(it))
75 .find(|it| it.exists()); 76 .find(|it| it.exists());
@@ -191,9 +192,8 @@ panic_abort
191panic_unwind 192panic_unwind
192proc_macro 193proc_macro
193profiler_builtins 194profiler_builtins
194rtstartup
195std 195std
196stdarch 196stdarch/crates/std_detect
197term 197term
198test 198test
199unwind"; 199unwind";
@@ -204,9 +204,8 @@ core
204panic_abort 204panic_abort
205panic_unwind 205panic_unwind
206profiler_builtins 206profiler_builtins
207rtstartup
208proc_macro 207proc_macro
209stdarch 208std_detect
210term 209term
211test 210test
212unwind"; 211unwind";
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index ef0f3c9e4..d8217f714 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
7use anyhow::{format_err, Context, Result}; 7use anyhow::{format_err, Context, Result};
8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; 8use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9use cargo_workspace::DepKind; 9use cargo_workspace::DepKind;
10use cfg::CfgOptions; 10use cfg::{CfgDiff, CfgOptions};
11use paths::{AbsPath, AbsPathBuf}; 11use paths::{AbsPath, AbsPathBuf};
12use proc_macro_api::ProcMacroClient; 12use proc_macro_api::ProcMacroClient;
13use rustc_hash::{FxHashMap, FxHashSet}; 13use rustc_hash::{FxHashMap, FxHashSet};
@@ -22,6 +22,8 @@ use crate::{
22 Sysroot, TargetKind, 22 Sysroot, TargetKind,
23}; 23};
24 24
25pub type CfgOverrides = FxHashMap<String, CfgDiff>;
26
25/// `PackageRoot` describes a package root folder. 27/// `PackageRoot` describes a package root folder.
26/// Which may be an external dependency, or a member of 28/// Which may be an external dependency, or a member of
27/// the current workspace. 29/// the current workspace.
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace {
46 /// FIXME: make this a per-crate map, as, eg, build.rs might have a 48 /// FIXME: make this a per-crate map, as, eg, build.rs might have a
47 /// different target. 49 /// different target.
48 rustc_cfg: Vec<CfgFlag>, 50 rustc_cfg: Vec<CfgFlag>,
51 cfg_overrides: CfgOverrides,
49 }, 52 },
50 /// Project workspace was manually specified using a `rust-project.json` file. 53 /// Project workspace was manually specified using a `rust-project.json` file.
51 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, 54 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 // Make sure this isn't too verbose. 71 // Make sure this isn't too verbose.
69 match self { 72 match self {
70 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f 73 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f
71 .debug_struct("Cargo") 74 .debug_struct("Cargo")
72 .field("root", &cargo.workspace_root().file_name()) 75 .field("root", &cargo.workspace_root().file_name())
73 .field("n_packages", &cargo.packages().len()) 76 .field("n_packages", &cargo.packages().len())
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace {
77 &rustc.as_ref().map_or(0, |rc| rc.packages().len()), 80 &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
78 ) 81 )
79 .field("n_rustc_cfg", &rustc_cfg.len()) 82 .field("n_rustc_cfg", &rustc_cfg.len())
83 .field("n_cfg_overrides", &cfg_overrides.len())
80 .finish(), 84 .finish(),
81 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { 85 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
82 let mut debug_struct = f.debug_struct("Json"); 86 let mut debug_struct = f.debug_struct("Json");
@@ -164,7 +168,9 @@ impl ProjectWorkspace {
164 }; 168 };
165 169
166 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); 170 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
167 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } 171
172 let cfg_overrides = config.cfg_overrides();
173 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides }
168 } 174 }
169 }; 175 };
170 176
@@ -213,43 +219,45 @@ impl ProjectWorkspace {
213 }) 219 })
214 })) 220 }))
215 .collect::<Vec<_>>(), 221 .collect::<Vec<_>>(),
216 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo 222 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => {
217 .packages() 223 cargo
218 .map(|pkg| { 224 .packages()
219 let is_member = cargo[pkg].is_member; 225 .map(|pkg| {
220 let pkg_root = cargo[pkg].root().to_path_buf(); 226 let is_member = cargo[pkg].is_member;
221 227 let pkg_root = cargo[pkg].root().to_path_buf();
222 let mut include = vec![pkg_root.clone()]; 228
223 include.extend( 229 let mut include = vec![pkg_root.clone()];
224 build_data 230 include.extend(
225 .and_then(|it| it.get(cargo.workspace_root())) 231 build_data
226 .and_then(|map| map.get(&cargo[pkg].id)) 232 .and_then(|it| it.get(cargo.workspace_root()))
227 .and_then(|it| it.out_dir.clone()), 233 .and_then(|map| map.get(&cargo[pkg].id))
228 ); 234 .and_then(|it| it.out_dir.clone()),
235 );
229 236
230 let mut exclude = vec![pkg_root.join(".git")]; 237 let mut exclude = vec![pkg_root.join(".git")];
231 if is_member { 238 if is_member {
232 exclude.push(pkg_root.join("target")); 239 exclude.push(pkg_root.join("target"));
233 } else { 240 } else {
234 exclude.push(pkg_root.join("tests")); 241 exclude.push(pkg_root.join("tests"));
235 exclude.push(pkg_root.join("examples")); 242 exclude.push(pkg_root.join("examples"));
236 exclude.push(pkg_root.join("benches")); 243 exclude.push(pkg_root.join("benches"));
237 } 244 }
238 PackageRoot { is_member, include, exclude } 245 PackageRoot { is_member, include, exclude }
239 }) 246 })
240 .chain(sysroot.crates().map(|krate| PackageRoot { 247 .chain(sysroot.crates().map(|krate| PackageRoot {
241 is_member: false,
242 include: vec![sysroot[krate].root_dir().to_path_buf()],
243 exclude: Vec::new(),
244 }))
245 .chain(rustc.into_iter().flat_map(|rustc| {
246 rustc.packages().map(move |krate| PackageRoot {
247 is_member: false, 248 is_member: false,
248 include: vec![rustc[krate].root().to_path_buf()], 249 include: vec![sysroot[krate].root_dir().to_path_buf()],
249 exclude: Vec::new(), 250 exclude: Vec::new(),
250 }) 251 }))
251 })) 252 .chain(rustc.into_iter().flat_map(|rustc| {
252 .collect(), 253 rustc.packages().map(move |krate| PackageRoot {
254 is_member: false,
255 include: vec![rustc[krate].root().to_path_buf()],
256 exclude: Vec::new(),
257 })
258 }))
259 .collect()
260 }
253 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files 261 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
254 .into_iter() 262 .into_iter()
255 .map(|detached_file| PackageRoot { 263 .map(|detached_file| PackageRoot {
@@ -299,16 +307,22 @@ impl ProjectWorkspace {
299 project, 307 project,
300 sysroot, 308 sysroot,
301 ), 309 ),
302 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( 310 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => {
303 rustc_cfg.clone(), 311 cargo_to_crate_graph(
304 &proc_macro_loader, 312 rustc_cfg.clone(),
305 load, 313 cfg_overrides,
306 cargo, 314 &proc_macro_loader,
307 build_data.and_then(|it| it.get(cargo.workspace_root())), 315 load,
308 sysroot, 316 cargo,
309 rustc, 317 build_data.and_then(|it| it.get(cargo.workspace_root())),
310 rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), 318 sysroot,
311 ), 319 rustc,
320 rustc
321 .as_ref()
322 .zip(build_data)
323 .and_then(|(it, map)| map.get(it.workspace_root())),
324 )
325 }
312 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { 326 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
313 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) 327 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
314 } 328 }
@@ -398,6 +412,7 @@ fn project_json_to_crate_graph(
398 412
399fn cargo_to_crate_graph( 413fn cargo_to_crate_graph(
400 rustc_cfg: Vec<CfgFlag>, 414 rustc_cfg: Vec<CfgFlag>,
415 override_cfg: &CfgOverrides,
401 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 416 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
402 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 417 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
403 cargo: &CargoWorkspace, 418 cargo: &CargoWorkspace,
@@ -425,6 +440,21 @@ fn cargo_to_crate_graph(
425 let mut has_private = false; 440 let mut has_private = false;
426 // Next, create crates for each package, target pair 441 // Next, create crates for each package, target pair
427 for pkg in cargo.packages() { 442 for pkg in cargo.packages() {
443 let mut cfg_options = &cfg_options;
444 let mut replaced_cfg_options;
445 if let Some(overrides) = override_cfg.get(&cargo[pkg].name) {
446 // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
447 // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
448 // working on rust-lang/rust as that's the only time it appears outside sysroot).
449 //
450 // A more ideal solution might be to reanalyze crates based on where the cursor is and
451 // figure out the set of cfgs that would have to apply to make it active.
452
453 replaced_cfg_options = cfg_options.clone();
454 replaced_cfg_options.apply_diff(overrides.clone());
455 cfg_options = &replaced_cfg_options;
456 };
457
428 has_private |= cargo[pkg].metadata.rustc_private; 458 has_private |= cargo[pkg].metadata.rustc_private;
429 let mut lib_tgt = None; 459 let mut lib_tgt = None;
430 for &tgt in cargo[pkg].targets.iter() { 460 for &tgt in cargo[pkg].targets.iter() {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index fa72a9bfb..3aeca8839 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -44,6 +44,9 @@ config_data! {
44 assist_importPrefix: ImportPrefixDef = "\"plain\"", 44 assist_importPrefix: ImportPrefixDef = "\"plain\"",
45 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 45 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
46 assist_importGroup: bool = "true", 46 assist_importGroup: bool = "true",
47 /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
48 assist_allowMergingIntoGlobImports: bool = "true",
49
47 /// Show function name and docs in parameter hints. 50 /// Show function name and docs in parameter hints.
48 callInfo_full: bool = "true", 51 callInfo_full: bool = "true",
49 52
@@ -52,6 +55,8 @@ config_data! {
52 cargo_autoreload: bool = "true", 55 cargo_autoreload: bool = "true",
53 /// Activate all available features (`--all-features`). 56 /// Activate all available features (`--all-features`).
54 cargo_allFeatures: bool = "false", 57 cargo_allFeatures: bool = "false",
58 /// Unsets `#[cfg(test)]` for the specified crates.
59 cargo_unsetTest: Vec<String> = "[\"core\"]",
55 /// List of features to activate. 60 /// List of features to activate.
56 cargo_features: Vec<String> = "[]", 61 cargo_features: Vec<String> = "[]",
57 /// Run build scripts (`build.rs`) for more precise code analysis. 62 /// Run build scripts (`build.rs`) for more precise code analysis.
@@ -596,8 +601,10 @@ impl Config {
596 target: self.data.cargo_target.clone(), 601 target: self.data.cargo_target.clone(),
597 rustc_source, 602 rustc_source,
598 no_sysroot: self.data.cargo_noSysroot, 603 no_sysroot: self.data.cargo_noSysroot,
604 unset_test_crates: self.data.cargo_unsetTest.clone(),
599 } 605 }
600 } 606 }
607
601 pub fn rustfmt(&self) -> RustfmtConfig { 608 pub fn rustfmt(&self) -> RustfmtConfig {
602 match &self.data.rustfmt_overrideCommand { 609 match &self.data.rustfmt_overrideCommand {
603 Some(args) if !args.is_empty() => { 610 Some(args) if !args.is_empty() => {
@@ -676,6 +683,7 @@ impl Config {
676 ImportPrefixDef::BySelf => PrefixKind::BySelf, 683 ImportPrefixDef::BySelf => PrefixKind::BySelf,
677 }, 684 },
678 group: self.data.assist_importGroup, 685 group: self.data.assist_importGroup,
686 skip_glob_imports: !self.data.assist_allowMergingIntoGlobImports,
679 } 687 }
680 } 688 }
681 pub fn completion(&self) -> CompletionConfig { 689 pub fn completion(&self) -> CompletionConfig {
@@ -806,7 +814,9 @@ enum ImportGranularityDef {
806#[serde(rename_all = "snake_case")] 814#[serde(rename_all = "snake_case")]
807enum ImportPrefixDef { 815enum ImportPrefixDef {
808 Plain, 816 Plain,
817 #[serde(alias = "self")]
809 BySelf, 818 BySelf,
819 #[serde(alias = "crate")]
810 ByCrate, 820 ByCrate,
811} 821}
812 822
@@ -993,13 +1003,13 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
993 "type": "string", 1003 "type": "string",
994 "enum": [ 1004 "enum": [
995 "plain", 1005 "plain",
996 "by_self", 1006 "self",
997 "by_crate" 1007 "crate"
998 ], 1008 ],
999 "enumDescriptions": [ 1009 "enumDescriptions": [
1000 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", 1010 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
1001 "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", 1011 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
1002 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." 1012 "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
1003 ], 1013 ],
1004 }, 1014 },
1005 "Vec<ManifestOrProjectJson>" => set! { 1015 "Vec<ManifestOrProjectJson>" => set! {
@@ -1069,8 +1079,8 @@ mod tests {
1069 let package_json_path = project_root().join("editors/code/package.json"); 1079 let package_json_path = project_root().join("editors/code/package.json");
1070 let mut package_json = fs::read_to_string(&package_json_path).unwrap(); 1080 let mut package_json = fs::read_to_string(&package_json_path).unwrap();
1071 1081
1072 let start_marker = " \"$generated-start\": false,\n"; 1082 let start_marker = " \"$generated-start\": {},\n";
1073 let end_marker = " \"$generated-end\": false\n"; 1083 let end_marker = " \"$generated-end\": {}\n";
1074 1084
1075 let start = package_json.find(start_marker).unwrap() + start_marker.len(); 1085 let start = package_json.find(start_marker).unwrap() + start_marker.len();
1076 let end = package_json.find(end_marker).unwrap(); 1086 let end = package_json.find(end_marker).unwrap();
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
index d5ab03576..a7f936a70 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
@@ -54,7 +54,7 @@
54 source: Some( 54 source: Some(
55 "rustc", 55 "rustc",
56 ), 56 ),
57 message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", 57 message: "can't compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
58 related_information: None, 58 related_information: None,
59 tags: None, 59 tags: None,
60 data: None, 60 data: None,
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
index ada540ea6..afc562a0e 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
@@ -54,7 +54,7 @@
54 source: Some( 54 source: Some(
55 "rustc", 55 "rustc",
56 ), 56 ),
57 message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`", 57 message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`",
58 related_information: None, 58 related_information: None,
59 tags: None, 59 tags: None,
60 data: None, 60 data: None,
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 8ddeb59f7..f8afc930a 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -143,6 +143,7 @@ fn integrated_completion_benchmark() {
143 prefix_kind: hir::PrefixKind::ByCrate, 143 prefix_kind: hir::PrefixKind::ByCrate,
144 enforce_granularity: true, 144 enforce_granularity: true,
145 group: true, 145 group: true,
146 skip_glob_imports: true,
146 }, 147 },
147 }; 148 };
148 let position = 149 let position =
@@ -178,6 +179,7 @@ fn integrated_completion_benchmark() {
178 prefix_kind: hir::PrefixKind::ByCrate, 179 prefix_kind: hir::PrefixKind::ByCrate,
179 enforce_granularity: true, 180 enforce_granularity: true,
180 group: true, 181 group: true,
182 skip_glob_imports: true,
181 }, 183 },
182 }; 184 };
183 let position = 185 let position =
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index e53cd3c7b..310d8c6d2 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1187,6 +1187,7 @@ mod tests {
1187 prefix_kind: PrefixKind::Plain, 1187 prefix_kind: PrefixKind::Plain,
1188 enforce_granularity: true, 1188 enforce_granularity: true,
1189 group: true, 1189 group: true,
1190 skip_glob_imports: true,
1190 }, 1191 },
1191 }, 1192 },
1192 ide_db::base_db::FilePosition { file_id, offset }, 1193 ide_db::base_db::FilePosition { file_id, offset },
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index e22c295f9..260a504e7 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -75,7 +75,9 @@ impl<'a> Project<'a> {
75 profile::init_from(crate::PROFILE); 75 profile::init_from(crate::PROFILE);
76 }); 76 });
77 77
78 for entry in Fixture::parse(self.fixture) { 78 let (mini_core, fixtures) = Fixture::parse(self.fixture);
79 assert!(mini_core.is_none());
80 for entry in fixtures {
79 let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); 81 let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
80 fs::create_dir_all(path.parent().unwrap()).unwrap(); 82 fs::create_dir_all(path.parent().unwrap()).unwrap();
81 fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); 83 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 3d27d2c1a..e33e5bb03 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -8,7 +8,7 @@ use parser::SyntaxKind;
8use rowan::{GreenNodeData, GreenTokenData}; 8use rowan::{GreenNodeData, GreenTokenData};
9 9
10use crate::{ 10use crate::{
11 ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, 11 ast::{self, support, AstChildren, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
12 NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, 12 NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
13}; 13};
14 14
@@ -45,6 +45,12 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
45 } 45 }
46} 46}
47 47
48impl ast::BlockExpr {
49 pub fn items(&self) -> AstChildren<ast::Item> {
50 support::children(self.syntax())
51 }
52}
53
48#[derive(Debug, PartialEq, Eq, Clone)] 54#[derive(Debug, PartialEq, Eq, Clone)]
49pub enum Macro { 55pub enum Macro {
50 MacroRules(ast::MacroRules), 56 MacroRules(ast::MacroRules),
@@ -281,6 +287,15 @@ impl ast::Path {
281 successors(self.qualifier(), |p| p.qualifier()) 287 successors(self.qualifier(), |p| p.qualifier())
282 } 288 }
283} 289}
290
291impl ast::Use {
292 pub fn is_simple_glob(&self) -> bool {
293 self.use_tree()
294 .map(|use_tree| use_tree.use_tree_list().is_none() && use_tree.star_token().is_some())
295 .unwrap_or(false)
296 }
297}
298
284impl ast::UseTree { 299impl ast::UseTree {
285 pub fn is_simple_path(&self) -> bool { 300 pub fn is_simple_path(&self) -> bool {
286 self.use_tree_list().is_none() && self.star_token().is_none() 301 self.use_tree_list().is_none() && self.star_token().is_none()
@@ -325,6 +340,15 @@ impl ast::Impl {
325 let second = types.next(); 340 let second = types.next();
326 (first, second) 341 (first, second)
327 } 342 }
343
344 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
345 let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?;
346 if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() {
347 Some(this)
348 } else {
349 None
350 }
351 }
328} 352}
329 353
330#[derive(Debug, Clone, PartialEq, Eq)] 354#[derive(Debug, Clone, PartialEq, Eq)]
@@ -666,6 +690,14 @@ impl ast::LifetimeParam {
666 } 690 }
667} 691}
668 692
693impl ast::Module {
694 /// Returns the parent ast::Module, this is different than the semantic parent in that this only
695 /// considers parent declarations in the AST
696 pub fn parent(&self) -> Option<ast::Module> {
697 self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
698 }
699}
700
669impl ast::RangePat { 701impl ast::RangePat {
670 pub fn start(&self) -> Option<ast::Pat> { 702 pub fn start(&self) -> Option<ast::Pat> {
671 self.syntax() 703 self.syntax()
diff --git a/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt b/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt
index 4d5ad74df..135f49552 100644
--- a/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt
+++ b/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt
@@ -1,2 +1,2 @@
1CHAR 1 "\'" 1CHAR 1 "'"
2> error0..1 token("\'") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..1 token("'") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt b/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt
index eafdb3c7c..cc3933d95 100644
--- a/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt
+++ b/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt
@@ -1,2 +1,2 @@
1CHAR 5 "\'🦀" 1CHAR 5 "'🦀"
2> error0..5 token("\'🦀") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..5 token("'🦀") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt b/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt
index cc2b4866a..21d990e6f 100644
--- a/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt
+++ b/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt
@@ -1,2 +1,2 @@
1CHAR 5 "\'\\x7f" 1CHAR 5 "'\\x7f"
2> error0..5 token("\'\\x7f") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..5 token("'\\x7f") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt b/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt
index a6d422cb3..055dba64c 100644
--- a/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt
+++ b/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt
@@ -1,2 +1,2 @@
1CHAR 9 "\'\\u{20AA}" 1CHAR 9 "'\\u{20AA}"
2> error0..9 token("\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..9 token("'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt b/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt
index 47e7baa70..9ee5e93fa 100644
--- a/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt
+++ b/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt
@@ -1,2 +1,2 @@
1CHAR 2 "\' " 1CHAR 2 "' "
2> error0..2 token("\' ") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..2 token("' ") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt b/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt
index 511029d80..dc3a596f6 100644
--- a/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt
+++ b/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt
@@ -1,2 +1,2 @@
1CHAR 2 "\'\\" 1CHAR 2 "'\\"
2> error0..2 token("\'\\") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..2 token("'\\") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt b/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt
index d2ba5742c..e46edea98 100644
--- a/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt
+++ b/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt
@@ -1,2 +1,2 @@
1CHAR 3 "\'\\n" 1CHAR 3 "'\\n"
2> error0..3 token("\'\\n") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..3 token("'\\n") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt b/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt
index ae9a7f0e2..8ad1e913a 100644
--- a/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt
+++ b/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt
@@ -1,2 +1,2 @@
1CHAR 3 "\'\\\'" 1CHAR 3 "'\\'"
2> error0..3 token("\'\\\'") msg(Missing trailing `'` symbol to terminate the character literal) 2> error0..3 token("'\\'") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt b/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt
index ff1504592..9d30c7466 100644
--- a/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt
+++ b/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt
@@ -1,2 +1,2 @@
1BYTE 2 "b\'" 1BYTE 2 "b'"
2> error0..2 token("b\'") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..2 token("b'") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt b/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt
index 34f7bd6d4..9dbf4203e 100644
--- a/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt
+++ b/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt
@@ -1,2 +1,2 @@
1BYTE 6 "b\'🦀" 1BYTE 6 "b'🦀"
2> error0..6 token("b\'🦀") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..6 token("b'🦀") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt b/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt
index c964d0f00..d5d9c2ef7 100644
--- a/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt
+++ b/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt
@@ -1,2 +1,2 @@
1BYTE 6 "b\'\\x7f" 1BYTE 6 "b'\\x7f"
2> error0..6 token("b\'\\x7f") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..6 token("b'\\x7f") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt b/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt
index cc65fb86f..a99b9666a 100644
--- a/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt
+++ b/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt
@@ -1,2 +1,2 @@
1BYTE 10 "b\'\\u{20AA}" 1BYTE 10 "b'\\u{20AA}"
2> error0..10 token("b\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..10 token("b'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt b/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt
index 800834a14..8a344f712 100644
--- a/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt
+++ b/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt
@@ -1,2 +1,2 @@
1BYTE 3 "b\' " 1BYTE 3 "b' "
2> error0..3 token("b\' ") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..3 token("b' ") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt b/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt
index 7b85ee646..b78a43c02 100644
--- a/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt
+++ b/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt
@@ -1,2 +1,2 @@
1BYTE 3 "b\'\\" 1BYTE 3 "b'\\"
2> error0..3 token("b\'\\") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..3 token("b'\\") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt b/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt
index 4b9a63117..5147363ba 100644
--- a/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt
+++ b/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt
@@ -1,2 +1,2 @@
1BYTE 4 "b\'\\n" 1BYTE 4 "b'\\n"
2> error0..4 token("b\'\\n") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..4 token("b'\\n") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt b/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt
index fe337f8d3..261c0894f 100644
--- a/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt
+++ b/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt
@@ -1,2 +1,2 @@
1BYTE 4 "b\'\\\'" 1BYTE 4 "b'\\'"
2> error0..4 token("b\'\\\'") msg(Missing trailing `'` symbol to terminate the byte literal) 2> error0..4 token("b'\\'") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt b/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt
index 11e0ae14a..b746404d2 100644
--- a/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt
+++ b/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt
@@ -1,6 +1,6 @@
1LIFETIME_IDENT 2 "\'1" 1LIFETIME_IDENT 2 "'1"
2WHITESPACE 1 "\n" 2WHITESPACE 1 "\n"
3LIFETIME_IDENT 10 "\'1lifetime" 3LIFETIME_IDENT 10 "'1lifetime"
4WHITESPACE 1 "\n" 4WHITESPACE 1 "\n"
5> error0..2 token("\'1") msg(Lifetime name cannot start with a number) 5> error0..2 token("'1") msg(Lifetime name cannot start with a number)
6> error3..13 token("\'1lifetime") msg(Lifetime name cannot start with a number) 6> error3..13 token("'1lifetime") msg(Lifetime name cannot start with a number)
diff --git a/crates/syntax/test_data/lexer/ok/0006_chars.txt b/crates/syntax/test_data/lexer/ok/0006_chars.txt
index 950954fbc..756477dc9 100644
--- a/crates/syntax/test_data/lexer/ok/0006_chars.txt
+++ b/crates/syntax/test_data/lexer/ok/0006_chars.txt
@@ -1,16 +1,16 @@
1CHAR 3 "\'x\'" 1CHAR 3 "'x'"
2WHITESPACE 1 " " 2WHITESPACE 1 " "
3CHAR 3 "\' \'" 3CHAR 3 "' '"
4WHITESPACE 1 " " 4WHITESPACE 1 " "
5CHAR 3 "\'0\'" 5CHAR 3 "'0'"
6WHITESPACE 1 " " 6WHITESPACE 1 " "
7CHAR 7 "\'hello\'" 7CHAR 7 "'hello'"
8WHITESPACE 1 " " 8WHITESPACE 1 " "
9CHAR 6 "\'\\x7f\'" 9CHAR 6 "'\\x7f'"
10WHITESPACE 1 " " 10WHITESPACE 1 " "
11CHAR 4 "\'\\n\'" 11CHAR 4 "'\\n'"
12WHITESPACE 1 " " 12WHITESPACE 1 " "
13CHAR 4 "\'\\\\\'" 13CHAR 4 "'\\\\'"
14WHITESPACE 1 " " 14WHITESPACE 1 " "
15CHAR 4 "\'\\\'\'" 15CHAR 4 "'\\''"
16WHITESPACE 1 "\n" 16WHITESPACE 1 "\n"
diff --git a/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt b/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt
index 4d6625c3a..32ed9ed50 100644
--- a/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt
+++ b/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt
@@ -1,8 +1,8 @@
1LIFETIME_IDENT 2 "\'a" 1LIFETIME_IDENT 2 "'a"
2WHITESPACE 1 " " 2WHITESPACE 1 " "
3LIFETIME_IDENT 4 "\'foo" 3LIFETIME_IDENT 4 "'foo"
4WHITESPACE 1 " " 4WHITESPACE 1 " "
5LIFETIME_IDENT 12 "\'foo_bar_baz" 5LIFETIME_IDENT 12 "'foo_bar_baz"
6WHITESPACE 1 " " 6WHITESPACE 1 " "
7LIFETIME_IDENT 2 "\'_" 7LIFETIME_IDENT 2 "'_"
8WHITESPACE 1 "\n" 8WHITESPACE 1 "\n"
diff --git a/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt b/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt
index e61ad99be..06d6bdd1f 100644
--- a/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt
+++ b/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt
@@ -1,22 +1,22 @@
1BYTE 3 "b\'\'" 1BYTE 3 "b''"
2WHITESPACE 1 " " 2WHITESPACE 1 " "
3BYTE 4 "b\'x\'" 3BYTE 4 "b'x'"
4WHITESPACE 1 " " 4WHITESPACE 1 " "
5BYTE_STRING 6 "b\"foo\"" 5BYTE_STRING 6 "b\"foo\""
6WHITESPACE 1 " " 6WHITESPACE 1 " "
7BYTE_STRING 4 "br\"\"" 7BYTE_STRING 4 "br\"\""
8WHITESPACE 1 "\n" 8WHITESPACE 1 "\n"
9BYTE 6 "b\'\'suf" 9BYTE 6 "b''suf"
10WHITESPACE 1 " " 10WHITESPACE 1 " "
11BYTE_STRING 5 "b\"\"ix" 11BYTE_STRING 5 "b\"\"ix"
12WHITESPACE 1 " " 12WHITESPACE 1 " "
13BYTE_STRING 6 "br\"\"br" 13BYTE_STRING 6 "br\"\"br"
14WHITESPACE 1 "\n" 14WHITESPACE 1 "\n"
15BYTE 5 "b\'\\n\'" 15BYTE 5 "b'\\n'"
16WHITESPACE 1 " " 16WHITESPACE 1 " "
17BYTE 5 "b\'\\\\\'" 17BYTE 5 "b'\\\\'"
18WHITESPACE 1 " " 18WHITESPACE 1 " "
19BYTE 5 "b\'\\\'\'" 19BYTE 5 "b'\\''"
20WHITESPACE 1 " " 20WHITESPACE 1 " "
21BYTE 8 "b\'hello\'" 21BYTE 8 "b'hello'"
22WHITESPACE 1 "\n" 22WHITESPACE 1 "\n"
diff --git a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast
index 4c4ddf5ec..be4a62940 100644
--- a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast
+++ b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast
@@ -43,7 +43,7 @@ [email protected]
43 [email protected] "<" 43 [email protected] "<"
44 [email protected] 44 [email protected]
45 [email protected] 45 [email protected]
46 [email protected] "\'a" 46 [email protected] "'a"
47 [email protected] ">" 47 [email protected] ">"
48 [email protected] " " 48 [email protected] " "
49 [email protected] 49 [email protected]
@@ -55,7 +55,7 @@ [email protected]
55 [email protected] "<" 55 [email protected] "<"
56 [email protected] 56 [email protected]
57 [email protected] 57 [email protected]
58 [email protected] "\'a" 58 [email protected] "'a"
59 [email protected] ">" 59 [email protected] ">"
60 [email protected] ")" 60 [email protected] ")"
61 [email protected] ">" 61 [email protected] ">"
@@ -128,7 +128,7 @@ [email protected]
128 [email protected] "<" 128 [email protected] "<"
129 [email protected] 129 [email protected]
130 [email protected] 130 [email protected]
131 [email protected] "\'a" 131 [email protected] "'a"
132 [email protected] ">" 132 [email protected] ">"
133 [email protected] " " 133 [email protected] " "
134 [email protected] 134 [email protected]
@@ -140,7 +140,7 @@ [email protected]
140 [email protected] "<" 140 [email protected] "<"
141 [email protected] 141 [email protected]
142 [email protected] 142 [email protected]
143 [email protected] "\'a" 143 [email protected] "'a"
144 [email protected] ">" 144 [email protected] ">"
145 [email protected] ")" 145 [email protected] ")"
146 [email protected] 146 [email protected]
@@ -191,7 +191,7 @@ [email protected]
191 [email protected] 191 [email protected]
192 [email protected] "<" 192 [email protected] "<"
193 [email protected] 193 [email protected]
194 [email protected] "\'a" 194 [email protected] "'a"
195 [email protected] ">" 195 [email protected] ">"
196 [email protected] " " 196 [email protected] " "
197 [email protected] 197 [email protected]
@@ -205,7 +205,7 @@ [email protected]
205 [email protected] "Trait" 205 [email protected] "Trait"
206 [email protected] "<" 206 [email protected] "<"
207 [email protected] 207 [email protected]
208 [email protected] "\'a" 208 [email protected] "'a"
209 [email protected] ">" 209 [email protected] ">"
210 [email protected] 210 [email protected]
211 [email protected] ")" 211 [email protected] ")"
@@ -250,7 +250,7 @@ [email protected]
250 [email protected] "<" 250 [email protected] "<"
251 [email protected] 251 [email protected]
252 [email protected] 252 [email protected]
253 [email protected] "\'a" 253 [email protected] "'a"
254 [email protected] ">" 254 [email protected] ">"
255 [email protected] " " 255 [email protected] " "
256 [email protected] 256 [email protected]
@@ -262,7 +262,7 @@ [email protected]
262 [email protected] "<" 262 [email protected] "<"
263 [email protected] 263 [email protected]
264 [email protected] 264 [email protected]
265 [email protected] "\'a" 265 [email protected] "'a"
266 [email protected] ">" 266 [email protected] ">"
267 [email protected] ")" 267 [email protected] ")"
268 [email protected] " " 268 [email protected] " "
diff --git a/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast b/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast
index c5215d6b1..b021783fc 100644
--- a/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast
+++ b/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] "<" 17 [email protected] "<"
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] "\'a" 20 [email protected] "'a"
21 [email protected] ">" 21 [email protected] ">"
22 [email protected] "\n" 22 [email protected] "\n"
23 [email protected] 23 [email protected]
diff --git a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast
index e73bd1aea..e24f01e29 100644
--- a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast
+++ b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast
@@ -55,7 +55,7 @@ [email protected]
55 [email protected] 55 [email protected]
56 [email protected] 56 [email protected]
57 [email protected] 57 [email protected]
58 [email protected] "\'label" 58 [email protected] "'label"
59 [email protected] ":" 59 [email protected] ":"
60 [email protected] " " 60 [email protected] " "
61 [email protected] 61 [email protected]
diff --git a/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast
index cc54185e5..a2460a7ec 100644
--- a/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast
+++ b/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast
@@ -13,13 +13,13 @@ [email protected]
13 [email protected] "<" 13 [email protected] "<"
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "\'a" 16 [email protected] "'a"
17 [email protected] ">" 17 [email protected] ">"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 [email protected]
20 [email protected] "&" 20 [email protected] "&"
21 [email protected] 21 [email protected]
22 [email protected] "\'a" 22 [email protected] "'a"
23 [email protected] " " 23 [email protected] " "
24 [email protected] 24 [email protected]
25 [email protected] 25 [email protected]
@@ -42,7 +42,7 @@ [email protected]
42 [email protected] "<" 42 [email protected] "<"
43 [email protected] 43 [email protected]
44 [email protected] 44 [email protected]
45 [email protected] "\'a" 45 [email protected] "'a"
46 [email protected] ">" 46 [email protected] ">"
47 [email protected] " " 47 [email protected] " "
48 [email protected] 48 [email protected]
@@ -50,7 +50,7 @@ [email protected]
50 [email protected] 50 [email protected]
51 [email protected] "&" 51 [email protected] "&"
52 [email protected] 52 [email protected]
53 [email protected] "\'a" 53 [email protected] "'a"
54 [email protected] " " 54 [email protected] " "
55 [email protected] 55 [email protected]
56 [email protected] 56 [email protected]
@@ -75,7 +75,7 @@ [email protected]
75 [email protected] "<" 75 [email protected] "<"
76 [email protected] 76 [email protected]
77 [email protected] 77 [email protected]
78 [email protected] "\'a" 78 [email protected] "'a"
79 [email protected] ">" 79 [email protected] ">"
80 [email protected] " " 80 [email protected] " "
81 [email protected] 81 [email protected]
@@ -102,7 +102,7 @@ [email protected]
102 [email protected] "<" 102 [email protected] "<"
103 [email protected] 103 [email protected]
104 [email protected] 104 [email protected]
105 [email protected] "\'a" 105 [email protected] "'a"
106 [email protected] ">" 106 [email protected] ">"
107 [email protected] " " 107 [email protected] " "
108 [email protected] 108 [email protected]
@@ -111,7 +111,7 @@ [email protected]
111 [email protected] "<" 111 [email protected] "<"
112 [email protected] 112 [email protected]
113 [email protected] 113 [email protected]
114 [email protected] "\'b" 114 [email protected] "'b"
115 [email protected] ">" 115 [email protected] ">"
116 [email protected] " " 116 [email protected] " "
117 [email protected] 117 [email protected]
@@ -122,7 +122,7 @@ [email protected]
122 [email protected] 122 [email protected]
123 [email protected] "&" 123 [email protected] "&"
124 [email protected] 124 [email protected]
125 [email protected] "\'a" 125 [email protected] "'a"
126 [email protected] " " 126 [email protected] " "
127 [email protected] 127 [email protected]
128 [email protected] 128 [email protected]
@@ -135,7 +135,7 @@ [email protected]
135 [email protected] 135 [email protected]
136 [email protected] "&" 136 [email protected] "&"
137 [email protected] 137 [email protected]
138 [email protected] "\'b" 138 [email protected] "'b"
139 [email protected] " " 139 [email protected] " "
140 [email protected] 140 [email protected]
141 [email protected] 141 [email protected]
@@ -169,7 +169,7 @@ [email protected]
169 [email protected] "<" 169 [email protected] "<"
170 [email protected] 170 [email protected]
171 [email protected] 171 [email protected]
172 [email protected] "\'a" 172 [email protected] "'a"
173 [email protected] ">" 173 [email protected] ">"
174 [email protected] " " 174 [email protected] " "
175 [email protected] 175 [email protected]
@@ -178,7 +178,7 @@ [email protected]
178 [email protected] "<" 178 [email protected] "<"
179 [email protected] 179 [email protected]
180 [email protected] 180 [email protected]
181 [email protected] "\'b" 181 [email protected] "'b"
182 [email protected] ">" 182 [email protected] ">"
183 [email protected] " " 183 [email protected] " "
184 [email protected] 184 [email protected]
@@ -187,7 +187,7 @@ [email protected]
187 [email protected] "<" 187 [email protected] "<"
188 [email protected] 188 [email protected]
189 [email protected] 189 [email protected]
190 [email protected] "\'c" 190 [email protected] "'c"
191 [email protected] ">" 191 [email protected] ">"
192 [email protected] " " 192 [email protected] " "
193 [email protected] 193 [email protected]
@@ -198,7 +198,7 @@ [email protected]
198 [email protected] 198 [email protected]
199 [email protected] "&" 199 [email protected] "&"
200 [email protected] 200 [email protected]
201 [email protected] "\'a" 201 [email protected] "'a"
202 [email protected] " " 202 [email protected] " "
203 [email protected] 203 [email protected]
204 [email protected] 204 [email protected]
@@ -211,7 +211,7 @@ [email protected]
211 [email protected] 211 [email protected]
212 [email protected] "&" 212 [email protected] "&"
213 [email protected] 213 [email protected]
214 [email protected] "\'b" 214 [email protected] "'b"
215 [email protected] " " 215 [email protected] " "
216 [email protected] 216 [email protected]
217 [email protected] 217 [email protected]
@@ -224,7 +224,7 @@ [email protected]
224 [email protected] 224 [email protected]
225 [email protected] "&" 225 [email protected] "&"
226 [email protected] 226 [email protected]
227 [email protected] "\'c" 227 [email protected] "'c"
228 [email protected] " " 228 [email protected] " "
229 [email protected] 229 [email protected]
230 [email protected] 230 [email protected]
diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast
index 7049f4734..6eaa32b96 100644
--- a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast
+++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "\'a" 11 [email protected] "'a"
12 [email protected] ">" 12 [email protected] ">"
13 [email protected] " " 13 [email protected] " "
14 [email protected] "=" 14 [email protected] "="
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "&" 17 [email protected] "&"
18 [email protected] 18 [email protected]
19 [email protected] "\'a" 19 [email protected] "'a"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 [email protected]
22 [email protected] "dyn" 22 [email protected] "dyn"
@@ -104,7 +104,7 @@ [email protected]
104 [email protected] " " 104 [email protected] " "
105 [email protected] 105 [email protected]
106 [email protected] 106 [email protected]
107 [email protected] "\'static" 107 [email protected] "'static"
108 [email protected] ";" 108 [email protected] ";"
109 [email protected] "\n" 109 [email protected] "\n"
110 [email protected] 110 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
index 0adf2cd5a..97bb5059d 100644
--- a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
+++ b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast
@@ -15,7 +15,7 @@ [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "\'loop" 18 [email protected] "'loop"
19 [email protected] ":" 19 [email protected] ":"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
index 6cdfd058b..12f5040f9 100644
--- a/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast
@@ -23,7 +23,7 @@ [email protected]
23 [email protected] "<" 23 [email protected] "<"
24 [email protected] 24 [email protected]
25 [email protected] 25 [email protected]
26 [email protected] "\'a" 26 [email protected] "'a"
27 [email protected] ">" 27 [email protected] ">"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
@@ -46,7 +46,7 @@ [email protected]
46 [email protected] 46 [email protected]
47 [email protected] "&" 47 [email protected] "&"
48 [email protected] 48 [email protected]
49 [email protected] "\'a" 49 [email protected] "'a"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast b/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast
index f0d152d33..d4c8b9d67 100644
--- a/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast
@@ -55,7 +55,7 @@ [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "&" 56 [email protected] "&"
57 [email protected] 57 [email protected]
58 [email protected] "\'a" 58 [email protected] "'a"
59 [email protected] " " 59 [email protected] " "
60 [email protected] 60 [email protected]
61 [email protected] "self" 61 [email protected] "self"
@@ -76,7 +76,7 @@ [email protected]
76 [email protected] 76 [email protected]
77 [email protected] "&" 77 [email protected] "&"
78 [email protected] 78 [email protected]
79 [email protected] "\'a" 79 [email protected] "'a"
80 [email protected] " " 80 [email protected] " "
81 [email protected] "mut" 81 [email protected] "mut"
82 [email protected] " " 82 [email protected] " "
diff --git a/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
index 075b438d2..121c3966a 100644
--- a/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast
@@ -14,7 +14,7 @@ [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "\'a" 17 [email protected] "'a"
18 [email protected] " " 18 [email protected] " "
19 [email protected] "+" 19 [email protected] "+"
20 [email protected] " " 20 [email protected] " "
diff --git a/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast b/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast
index b9e92b57a..b67ea2682 100644
--- a/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast
@@ -27,7 +27,7 @@ [email protected]
27 [email protected] "continue" 27 [email protected] "continue"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
30 [email protected] "\'l" 30 [email protected] "'l"
31 [email protected] ";" 31 [email protected] ";"
32 [email protected] "\n " 32 [email protected] "\n "
33 [email protected] "}" 33 [email protected] "}"
diff --git a/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast b/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
index dad4362b7..b44f46f05 100644
--- a/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] "<" 32 [email protected] "<"
33 [email protected] 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "\'a" 35 [email protected] "'a"
36 [email protected] ">" 36 [email protected] ">"
37 [email protected] ">" 37 [email protected] ">"
38 [email protected] " " 38 [email protected] " "
@@ -40,6 +40,6 @@ [email protected]
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
42 [email protected] 42 [email protected]
43 [email protected] "\'a" 43 [email protected] "'a"
44 [email protected] ";" 44 [email protected] ";"
45 [email protected] "\n" 45 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast b/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast
index ac0299268..7cb288bf0 100644
--- a/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast
@@ -25,7 +25,7 @@ [email protected]
25 [email protected] 25 [email protected]
26 [email protected] "&" 26 [email protected] "&"
27 [email protected] 27 [email protected]
28 [email protected] "\'static" 28 [email protected] "'static"
29 [email protected] " " 29 [email protected] " "
30 [email protected] 30 [email protected]
31 [email protected] "(" 31 [email protected] "("
diff --git a/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast b/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast
index 828013d45..783b25338 100644
--- a/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast
@@ -27,7 +27,7 @@ [email protected]
27 [email protected] "break" 27 [email protected] "break"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
30 [email protected] "\'l" 30 [email protected] "'l"
31 [email protected] ";" 31 [email protected] ";"
32 [email protected] "\n " 32 [email protected] "\n "
33 [email protected] 33 [email protected]
@@ -43,7 +43,7 @@ [email protected]
43 [email protected] "break" 43 [email protected] "break"
44 [email protected] " " 44 [email protected] " "
45 [email protected] 45 [email protected]
46 [email protected] "\'l" 46 [email protected] "'l"
47 [email protected] " " 47 [email protected] " "
48 [email protected] 48 [email protected]
49 [email protected] "92" 49 [email protected] "92"
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
index 68c0f1c66..11efa23a4 100644
--- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] "<" 16 [email protected] "<"
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] "\'static" 19 [email protected] "'static"
20 [email protected] "," 20 [email protected] ","
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast b/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
index b6f5a5689..abc258b33 100644
--- a/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
@@ -34,7 +34,7 @@ [email protected]
34 [email protected] "<" 34 [email protected] "<"
35 [email protected] 35 [email protected]
36 [email protected] 36 [email protected]
37 [email protected] "\'a" 37 [email protected] "'a"
38 [email protected] ">" 38 [email protected] ">"
39 [email protected] ")" 39 [email protected] ")"
40 [email protected] ">" 40 [email protected] ">"
diff --git a/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
index 7df6e190a..e1b88c5db 100644
--- a/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] " " 32 [email protected] " "
33 [email protected] 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "\'f" 35 [email protected] "'f"
36 [email protected] ">" 36 [email protected] ">"
37 [email protected] " " 37 [email protected] " "
38 [email protected] 38 [email protected]
@@ -74,7 +74,7 @@ [email protected]
74 [email protected] " " 74 [email protected] " "
75 [email protected] 75 [email protected]
76 [email protected] 76 [email protected]
77 [email protected] "\'f" 77 [email protected] "'f"
78 [email protected] ">" 78 [email protected] ">"
79 [email protected] " " 79 [email protected] " "
80 [email protected] 80 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast b/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
index 68bb43852..acf18fc2b 100644
--- a/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast
@@ -49,7 +49,7 @@ [email protected]
49 [email protected] 49 [email protected]
50 [email protected] 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] "\'c\'" 52 [email protected] "'c'"
53 [email protected] " " 53 [email protected] " "
54 [email protected] "=>" 54 [email protected] "=>"
55 [email protected] " " 55 [email protected] " "
diff --git a/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast b/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast
index 61dea413d..d42a7e295 100644
--- a/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast
@@ -13,19 +13,19 @@ [email protected]
13 [email protected] "\n " 13 [email protected] "\n "
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "\'a" 16 [email protected] "'a"
17 [email protected] ":" 17 [email protected] ":"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 [email protected]
20 [email protected] 20 [email protected]
21 [email protected] 21 [email protected]
22 [email protected] "\'b" 22 [email protected] "'b"
23 [email protected] " " 23 [email protected] " "
24 [email protected] "+" 24 [email protected] "+"
25 [email protected] " " 25 [email protected] " "
26 [email protected] 26 [email protected]
27 [email protected] 27 [email protected]
28 [email protected] "\'c" 28 [email protected] "'c"
29 [email protected] "," 29 [email protected] ","
30 [email protected] "\n " 30 [email protected] "\n "
31 [email protected] 31 [email protected]
@@ -57,7 +57,7 @@ [email protected]
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
60 [email protected] "\'static" 60 [email protected] "'static"
61 [email protected] "," 61 [email protected] ","
62 [email protected] "\n " 62 [email protected] "\n "
63 [email protected] 63 [email protected]
@@ -76,7 +76,7 @@ [email protected]
76 [email protected] 76 [email protected]
77 [email protected] 77 [email protected]
78 [email protected] 78 [email protected]
79 [email protected] "\'a" 79 [email protected] "'a"
80 [email protected] "," 80 [email protected] ","
81 [email protected] "\n " 81 [email protected] "\n "
82 [email protected] 82 [email protected]
@@ -108,7 +108,7 @@ [email protected]
108 [email protected] 108 [email protected]
109 [email protected] 109 [email protected]
110 [email protected] 110 [email protected]
111 [email protected] "\'a" 111 [email protected] "'a"
112 [email protected] "\n" 112 [email protected] "\n"
113 [email protected] 113 [email protected]
114 [email protected] "{" 114 [email protected] "{"
diff --git a/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast b/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
index 49d26cef4..8f76177d1 100644
--- a/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast
@@ -32,7 +32,7 @@ [email protected]
32 [email protected] "<" 32 [email protected] "<"
33 [email protected] 33 [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "\'a" 35 [email protected] "'a"
36 [email protected] ">" 36 [email protected] ">"
37 [email protected] ">" 37 [email protected] ">"
38 [email protected] " " 38 [email protected] " "
@@ -40,6 +40,6 @@ [email protected]
40 [email protected] " " 40 [email protected] " "
41 [email protected] 41 [email protected]
42 [email protected] 42 [email protected]
43 [email protected] "\'a" 43 [email protected] "'a"
44 [email protected] ";" 44 [email protected] ";"
45 [email protected] "\n" 45 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast
index 8c909b5af..7958e32e5 100644
--- a/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast
@@ -13,7 +13,7 @@ [email protected]
13 [email protected] "<" 13 [email protected] "<"
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "\'a" 16 [email protected] "'a"
17 [email protected] ">" 17 [email protected] ">"
18 [email protected] " " 18 [email protected] " "
19 [email protected] 19 [email protected]
@@ -44,7 +44,7 @@ [email protected]
44 [email protected] "<" 44 [email protected] "<"
45 [email protected] 45 [email protected]
46 [email protected] 46 [email protected]
47 [email protected] "\'a" 47 [email protected] "'a"
48 [email protected] ">" 48 [email protected] ">"
49 [email protected] " " 49 [email protected] " "
50 [email protected] 50 [email protected]
@@ -62,7 +62,7 @@ [email protected]
62 [email protected] 62 [email protected]
63 [email protected] "&" 63 [email protected] "&"
64 [email protected] 64 [email protected]
65 [email protected] "\'a" 65 [email protected] "'a"
66 [email protected] " " 66 [email protected] " "
67 [email protected] 67 [email protected]
68 [email protected] "(" 68 [email protected] "("
@@ -91,7 +91,7 @@ [email protected]
91 [email protected] "<" 91 [email protected] "<"
92 [email protected] 92 [email protected]
93 [email protected] 93 [email protected]
94 [email protected] "\'a" 94 [email protected] "'a"
95 [email protected] ">" 95 [email protected] ">"
96 [email protected] " " 96 [email protected] " "
97 [email protected] 97 [email protected]
@@ -105,7 +105,7 @@ [email protected]
105 [email protected] 105 [email protected]
106 [email protected] "&" 106 [email protected] "&"
107 [email protected] 107 [email protected]
108 [email protected] "\'a" 108 [email protected] "'a"
109 [email protected] " " 109 [email protected] " "
110 [email protected] 110 [email protected]
111 [email protected] 111 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast b/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast
index ae838105d..f784e96e0 100644
--- a/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast
@@ -68,7 +68,7 @@ [email protected]
68 [email protected] "=" 68 [email protected] "="
69 [email protected] " " 69 [email protected] " "
70 [email protected] 70 [email protected]
71 [email protected] "b\'a\'" 71 [email protected] "b'a'"
72 [email protected] ";" 72 [email protected] ";"
73 [email protected] "\n " 73 [email protected] "\n "
74 [email protected] 74 [email protected]
@@ -80,7 +80,7 @@ [email protected]
80 [email protected] "=" 80 [email protected] "="
81 [email protected] " " 81 [email protected] " "
82 [email protected] 82 [email protected]
83 [email protected] "\'b\'" 83 [email protected] "'b'"
84 [email protected] ";" 84 [email protected] ";"
85 [email protected] "\n " 85 [email protected] "\n "
86 [email protected] 86 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0109_label.rast b/crates/syntax/test_data/parser/inline/ok/0109_label.rast
index 860dfe608..8540b8520 100644
--- a/crates/syntax/test_data/parser/inline/ok/0109_label.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0109_label.rast
@@ -15,7 +15,7 @@ [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "\'a" 18 [email protected] "'a"
19 [email protected] ":" 19 [email protected] ":"
20 [email protected] " " 20 [email protected] " "
21 [email protected] "loop" 21 [email protected] "loop"
@@ -28,7 +28,7 @@ [email protected]
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "\'b" 31 [email protected] "'b"
32 [email protected] ":" 32 [email protected] ":"
33 [email protected] " " 33 [email protected] " "
34 [email protected] "while" 34 [email protected] "while"
@@ -44,7 +44,7 @@ [email protected]
44 [email protected] 44 [email protected]
45 [email protected] 45 [email protected]
46 [email protected] 46 [email protected]
47 [email protected] "\'c" 47 [email protected] "'c"
48 [email protected] ":" 48 [email protected] ":"
49 [email protected] " " 49 [email protected] " "
50 [email protected] "for" 50 [email protected] "for"
diff --git a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
index 840181383..5682bd28c 100644
--- a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
@@ -22,7 +22,7 @@ [email protected]
22 [email protected] "]" 22 [email protected] "]"
23 [email protected] " " 23 [email protected] " "
24 [email protected] 24 [email protected]
25 [email protected] "\'a" 25 [email protected] "'a"
26 [email protected] "," 26 [email protected] ","
27 [email protected] " " 27 [email protected] " "
28 [email protected] 28 [email protected]
@@ -53,7 +53,7 @@ [email protected]
53 [email protected] 53 [email protected]
54 [email protected] "&" 54 [email protected] "&"
55 [email protected] 55 [email protected]
56 [email protected] "\'a" 56 [email protected] "'a"
57 [email protected] " " 57 [email protected] " "
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast
index edfcb288c..860684b29 100644
--- a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] "<" 16 [email protected] "<"
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] "\'a" 19 [email protected] "'a"
20 [email protected] ">" 20 [email protected] ">"
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
@@ -28,7 +28,7 @@ [email protected]
28 [email protected] "<" 28 [email protected] "<"
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "\'a" 31 [email protected] "'a"
32 [email protected] ">" 32 [email protected] ">"
33 [email protected] " " 33 [email protected] " "
34 [email protected] "+" 34 [email protected] "+"
diff --git a/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast b/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast
index c2dea1cc1..47e8859ed 100644
--- a/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast
@@ -15,7 +15,7 @@ [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "\'label" 18 [email protected] "'label"
19 [email protected] ":" 19 [email protected] ":"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
index ff5877a7b..31f76589d 100644
--- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
+++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
@@ -21,7 +21,7 @@ [email protected]
21 [email protected] 21 [email protected]
22 [email protected] 22 [email protected]
23 [email protected] 23 [email protected]
24 [email protected] "ignore" 24 [email protected] "Ignore"
25 [email protected] "]" 25 [email protected] "]"
26 [email protected] "\n" 26 [email protected] "\n"
27 [email protected] "fn" 27 [email protected] "fn"
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs
index 3d2e01d5c..6f04cb171 100644
--- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs
+++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs
@@ -1,5 +1,5 @@
1#[cfg(test)] 1#[cfg(test)]
2#[ignore] 2#[Ignore]
3fn foo() {} 3fn foo() {}
4 4
5#[path = "a.rs"] 5#[path = "a.rs"]
diff --git a/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast b/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast
index 83e17757b..f845d5cff 100644
--- a/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast
+++ b/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast
@@ -81,7 +81,7 @@ [email protected]
81 [email protected] "<" 81 [email protected] "<"
82 [email protected] 82 [email protected]
83 [email protected] 83 [email protected]
84 [email protected] "\'a" 84 [email protected] "'a"
85 [email protected] ">" 85 [email protected] ">"
86 [email protected] ";" 86 [email protected] ";"
87 [email protected] "\n" 87 [email protected] "\n"
@@ -94,7 +94,7 @@ [email protected]
94 [email protected] "<" 94 [email protected] "<"
95 [email protected] 95 [email protected]
96 [email protected] 96 [email protected]
97 [email protected] "\'a" 97 [email protected] "'a"
98 [email protected] ":" 98 [email protected] ":"
99 [email protected] ">" 99 [email protected] ">"
100 [email protected] ";" 100 [email protected] ";"
@@ -108,11 +108,11 @@ [email protected]
108 [email protected] "<" 108 [email protected] "<"
109 [email protected] 109 [email protected]
110 [email protected] 110 [email protected]
111 [email protected] "\'a" 111 [email protected] "'a"
112 [email protected] ":" 112 [email protected] ":"
113 [email protected] " " 113 [email protected] " "
114 [email protected] 114 [email protected]
115 [email protected] "\'b" 115 [email protected] "'b"
116 [email protected] ">" 116 [email protected] ">"
117 [email protected] ";" 117 [email protected] ";"
118 [email protected] "\n" 118 [email protected] "\n"
@@ -125,11 +125,11 @@ [email protected]
125 [email protected] "<" 125 [email protected] "<"
126 [email protected] 126 [email protected]
127 [email protected] 127 [email protected]
128 [email protected] "\'a" 128 [email protected] "'a"
129 [email protected] ":" 129 [email protected] ":"
130 [email protected] " " 130 [email protected] " "
131 [email protected] 131 [email protected]
132 [email protected] "\'b" 132 [email protected] "'b"
133 [email protected] " " 133 [email protected] " "
134 [email protected] "+" 134 [email protected] "+"
135 [email protected] " " 135 [email protected] " "
@@ -145,16 +145,16 @@ [email protected]
145 [email protected] "<" 145 [email protected] "<"
146 [email protected] 146 [email protected]
147 [email protected] 147 [email protected]
148 [email protected] "\'a" 148 [email protected] "'a"
149 [email protected] ":" 149 [email protected] ":"
150 [email protected] " " 150 [email protected] " "
151 [email protected] 151 [email protected]
152 [email protected] "\'b" 152 [email protected] "'b"
153 [email protected] " " 153 [email protected] " "
154 [email protected] "+" 154 [email protected] "+"
155 [email protected] " " 155 [email protected] " "
156 [email protected] 156 [email protected]
157 [email protected] "\'c" 157 [email protected] "'c"
158 [email protected] ">" 158 [email protected] ">"
159 [email protected] ";" 159 [email protected] ";"
160 [email protected] "\n" 160 [email protected] "\n"
@@ -167,7 +167,7 @@ [email protected]
167 [email protected] "<" 167 [email protected] "<"
168 [email protected] 168 [email protected]
169 [email protected] 169 [email protected]
170 [email protected] "\'a" 170 [email protected] "'a"
171 [email protected] "," 171 [email protected] ","
172 [email protected] ">" 172 [email protected] ">"
173 [email protected] ";" 173 [email protected] ";"
@@ -181,12 +181,12 @@ [email protected]
181 [email protected] "<" 181 [email protected] "<"
182 [email protected] 182 [email protected]
183 [email protected] 183 [email protected]
184 [email protected] "\'a" 184 [email protected] "'a"
185 [email protected] "," 185 [email protected] ","
186 [email protected] " " 186 [email protected] " "
187 [email protected] 187 [email protected]
188 [email protected] 188 [email protected]
189 [email protected] "\'b" 189 [email protected] "'b"
190 [email protected] ">" 190 [email protected] ">"
191 [email protected] ";" 191 [email protected] ";"
192 [email protected] "\n" 192 [email protected] "\n"
@@ -199,21 +199,21 @@ [email protected]
199 [email protected] "<" 199 [email protected] "<"
200 [email protected] 200 [email protected]
201 [email protected] 201 [email protected]
202 [email protected] "\'a" 202 [email protected] "'a"
203 [email protected] ":" 203 [email protected] ":"
204 [email protected] " " 204 [email protected] " "
205 [email protected] 205 [email protected]
206 [email protected] "\'b" 206 [email protected] "'b"
207 [email protected] "+" 207 [email protected] "+"
208 [email protected] "," 208 [email protected] ","
209 [email protected] " " 209 [email protected] " "
210 [email protected] 210 [email protected]
211 [email protected] 211 [email protected]
212 [email protected] "\'b" 212 [email protected] "'b"
213 [email protected] ":" 213 [email protected] ":"
214 [email protected] " " 214 [email protected] " "
215 [email protected] 215 [email protected]
216 [email protected] "\'c" 216 [email protected] "'c"
217 [email protected] "," 217 [email protected] ","
218 [email protected] ">" 218 [email protected] ">"
219 [email protected] ";" 219 [email protected] ";"
@@ -258,7 +258,7 @@ [email protected]
258 [email protected] "<" 258 [email protected] "<"
259 [email protected] 259 [email protected]
260 [email protected] 260 [email protected]
261 [email protected] "\'a" 261 [email protected] "'a"
262 [email protected] "," 262 [email protected] ","
263 [email protected] " " 263 [email protected] " "
264 [email protected] 264 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast
index 21c564a20..9d4b001ae 100644
--- a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast
+++ b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast
@@ -42,7 +42,7 @@ [email protected]
42 [email protected] 42 [email protected]
43 [email protected] 43 [email protected]
44 [email protected] 44 [email protected]
45 [email protected] "\'a" 45 [email protected] "'a"
46 [email protected] ">" 46 [email protected] ">"
47 [email protected] ";" 47 [email protected] ";"
48 [email protected] "\n" 48 [email protected] "\n"
@@ -61,7 +61,7 @@ [email protected]
61 [email protected] 61 [email protected]
62 [email protected] 62 [email protected]
63 [email protected] 63 [email protected]
64 [email protected] "\'a" 64 [email protected] "'a"
65 [email protected] " " 65 [email protected] " "
66 [email protected] "+" 66 [email protected] "+"
67 [email protected] " " 67 [email protected] " "
@@ -83,13 +83,13 @@ [email protected]
83 [email protected] 83 [email protected]
84 [email protected] 84 [email protected]
85 [email protected] 85 [email protected]
86 [email protected] "\'a" 86 [email protected] "'a"
87 [email protected] " " 87 [email protected] " "
88 [email protected] "+" 88 [email protected] "+"
89 [email protected] " " 89 [email protected] " "
90 [email protected] 90 [email protected]
91 [email protected] 91 [email protected]
92 [email protected] "\'d" 92 [email protected] "'d"
93 [email protected] " " 93 [email protected] " "
94 [email protected] ">" 94 [email protected] ">"
95 [email protected] ";" 95 [email protected] ";"
@@ -109,13 +109,13 @@ [email protected]
109 [email protected] 109 [email protected]
110 [email protected] 110 [email protected]
111 [email protected] 111 [email protected]
112 [email protected] "\'a" 112 [email protected] "'a"
113 [email protected] " " 113 [email protected] " "
114 [email protected] "+" 114 [email protected] "+"
115 [email protected] " " 115 [email protected] " "
116 [email protected] 116 [email protected]
117 [email protected] 117 [email protected]
118 [email protected] "\'d" 118 [email protected] "'d"
119 [email protected] " " 119 [email protected] " "
120 [email protected] "+" 120 [email protected] "+"
121 [email protected] " " 121 [email protected] " "
@@ -198,7 +198,7 @@ [email protected]
198 [email protected] " " 198 [email protected] " "
199 [email protected] 199 [email protected]
200 [email protected] 200 [email protected]
201 [email protected] "\'a" 201 [email protected] "'a"
202 [email protected] ">" 202 [email protected] ">"
203 [email protected] ";" 203 [email protected] ";"
204 [email protected] "\n" 204 [email protected] "\n"
@@ -234,25 +234,25 @@ [email protected]
234 [email protected] "<" 234 [email protected] "<"
235 [email protected] 235 [email protected]
236 [email protected] 236 [email protected]
237 [email protected] "\'a" 237 [email protected] "'a"
238 [email protected] ":" 238 [email protected] ":"
239 [email protected] " " 239 [email protected] " "
240 [email protected] 240 [email protected]
241 [email protected] "\'d" 241 [email protected] "'d"
242 [email protected] "," 242 [email protected] ","
243 [email protected] " " 243 [email protected] " "
244 [email protected] 244 [email protected]
245 [email protected] 245 [email protected]
246 [email protected] "\'d" 246 [email protected] "'d"
247 [email protected] ":" 247 [email protected] ":"
248 [email protected] " " 248 [email protected] " "
249 [email protected] 249 [email protected]
250 [email protected] "\'a" 250 [email protected] "'a"
251 [email protected] " " 251 [email protected] " "
252 [email protected] "+" 252 [email protected] "+"
253 [email protected] " " 253 [email protected] " "
254 [email protected] 254 [email protected]
255 [email protected] "\'b" 255 [email protected] "'b"
256 [email protected] "," 256 [email protected] ","
257 [email protected] " " 257 [email protected] " "
258 [email protected] 258 [email protected]
@@ -263,13 +263,13 @@ [email protected]
263 [email protected] 263 [email protected]
264 [email protected] 264 [email protected]
265 [email protected] 265 [email protected]
266 [email protected] "\'a" 266 [email protected] "'a"
267 [email protected] " " 267 [email protected] " "
268 [email protected] "+" 268 [email protected] "+"
269 [email protected] " " 269 [email protected] " "
270 [email protected] 270 [email protected]
271 [email protected] 271 [email protected]
272 [email protected] "\'d" 272 [email protected] "'d"
273 [email protected] " " 273 [email protected] " "
274 [email protected] "+" 274 [email protected] "+"
275 [email protected] " " 275 [email protected] " "
diff --git a/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast b/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast
index 80f7f5942..115861585 100644
--- a/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast
+++ b/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast
@@ -20,7 +20,7 @@ [email protected]
20 [email protected] "=" 20 [email protected] "="
21 [email protected] " " 21 [email protected] " "
22 [email protected] 22 [email protected]
23 [email protected] "\'c\'u32" 23 [email protected] "'c'u32"
24 [email protected] ";" 24 [email protected] ";"
25 [email protected] "\n " 25 [email protected] "\n "
26 [email protected] 26 [email protected]
@@ -44,7 +44,7 @@ [email protected]
44 [email protected] "=" 44 [email protected] "="
45 [email protected] " " 45 [email protected] " "
46 [email protected] 46 [email protected]
47 [email protected] "b\'b\'_suff" 47 [email protected] "b'b'_suff"
48 [email protected] ";" 48 [email protected] ";"
49 [email protected] "\n " 49 [email protected] "\n "
50 [email protected] 50 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0032_where_for.rast b/crates/syntax/test_data/parser/ok/0032_where_for.rast
index 0cb2eca33..b527cc3ac 100644
--- a/crates/syntax/test_data/parser/ok/0032_where_for.rast
+++ b/crates/syntax/test_data/parser/ok/0032_where_for.rast
@@ -42,7 +42,7 @@ [email protected]
42 [email protected] "<" 42 [email protected] "<"
43 [email protected] 43 [email protected]
44 [email protected] 44 [email protected]
45 [email protected] "\'de" 45 [email protected] "'de"
46 [email protected] ">" 46 [email protected] ">"
47 [email protected] " " 47 [email protected] " "
48 [email protected] 48 [email protected]
@@ -54,7 +54,7 @@ [email protected]
54 [email protected] "<" 54 [email protected] "<"
55 [email protected] 55 [email protected]
56 [email protected] 56 [email protected]
57 [email protected] "\'de" 57 [email protected] "'de"
58 [email protected] ">" 58 [email protected] ">"
59 [email protected] " " 59 [email protected] " "
60 [email protected] "+" 60 [email protected] "+"
diff --git a/crates/syntax/test_data/parser/ok/0033_label_break.rast b/crates/syntax/test_data/parser/ok/0033_label_break.rast
index 487e073ba..4b0f0997e 100644
--- a/crates/syntax/test_data/parser/ok/0033_label_break.rast
+++ b/crates/syntax/test_data/parser/ok/0033_label_break.rast
@@ -17,7 +17,7 @@ [email protected]
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] "\'empty_block" 20 [email protected] "'empty_block"
21 [email protected] ":" 21 [email protected] ":"
22 [email protected] " " 22 [email protected] " "
23 [email protected] 23 [email protected]
@@ -28,7 +28,7 @@ [email protected]
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "\'block" 31 [email protected] "'block"
32 [email protected] ":" 32 [email protected] ":"
33 [email protected] " " 33 [email protected] " "
34 [email protected] 34 [email protected]
@@ -69,7 +69,7 @@ [email protected]
69 [email protected] "break" 69 [email protected] "break"
70 [email protected] " " 70 [email protected] " "
71 [email protected] 71 [email protected]
72 [email protected] "\'block" 72 [email protected] "'block"
73 [email protected] ";" 73 [email protected] ";"
74 [email protected] "\n " 74 [email protected] "\n "
75 [email protected] "}" 75 [email protected] "}"
@@ -109,7 +109,7 @@ [email protected]
109 [email protected] "break" 109 [email protected] "break"
110 [email protected] " " 110 [email protected] " "
111 [email protected] 111 [email protected]
112 [email protected] "\'block" 112 [email protected] "'block"
113 [email protected] ";" 113 [email protected] ";"
114 [email protected] "\n " 114 [email protected] "\n "
115 [email protected] "}" 115 [email protected] "}"
@@ -140,7 +140,7 @@ [email protected]
140 [email protected] 140 [email protected]
141 [email protected] 141 [email protected]
142 [email protected] 142 [email protected]
143 [email protected] "\'block" 143 [email protected] "'block"
144 [email protected] ":" 144 [email protected] ":"
145 [email protected] " " 145 [email protected] " "
146 [email protected] 146 [email protected]
@@ -171,7 +171,7 @@ [email protected]
171 [email protected] "break" 171 [email protected] "break"
172 [email protected] " " 172 [email protected] " "
173 [email protected] 173 [email protected]
174 [email protected] "\'block" 174 [email protected] "'block"
175 [email protected] " " 175 [email protected] " "
176 [email protected] 176 [email protected]
177 [email protected] "1" 177 [email protected] "1"
@@ -204,7 +204,7 @@ [email protected]
204 [email protected] "break" 204 [email protected] "break"
205 [email protected] " " 205 [email protected] " "
206 [email protected] 206 [email protected]
207 [email protected] "\'block" 207 [email protected] "'block"
208 [email protected] " " 208 [email protected] " "
209 [email protected] 209 [email protected]
210 [email protected] "2" 210 [email protected] "2"
diff --git a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
index 20675dbf5..2fa46ad2d 100644
--- a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
+++ b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
@@ -1378,14 +1378,14 @@ [email protected]
1378 [email protected] " " 1378 [email protected] " "
1379 [email protected] "u8" 1379 [email protected] "u8"
1380 [email protected] "<" 1380 [email protected] "<"
1381 [email protected] "\'u8" 1381 [email protected] "'u8"
1382 [email protected] ":" 1382 [email protected] ":"
1383 [email protected] " " 1383 [email protected] " "
1384 [email protected] "\'u8" 1384 [email protected] "'u8"
1385 [email protected] " " 1385 [email protected] " "
1386 [email protected] "+" 1386 [email protected] "+"
1387 [email protected] " " 1387 [email protected] " "
1388 [email protected] "\'u8" 1388 [email protected] "'u8"
1389 [email protected] ">" 1389 [email protected] ">"
1390 [email protected] 1390 [email protected]
1391 [email protected] "(" 1391 [email protected] "("
@@ -1393,7 +1393,7 @@ [email protected]
1393 [email protected] ":" 1393 [email protected] ":"
1394 [email protected] " " 1394 [email protected] " "
1395 [email protected] "&" 1395 [email protected] "&"
1396 [email protected] "\'u8" 1396 [email protected] "'u8"
1397 [email protected] " " 1397 [email protected] " "
1398 [email protected] "u8" 1398 [email protected] "u8"
1399 [email protected] ")" 1399 [email protected] ")"
@@ -1402,7 +1402,7 @@ [email protected]
1402 [email protected] ">" 1402 [email protected] ">"
1403 [email protected] " " 1403 [email protected] " "
1404 [email protected] "&" 1404 [email protected] "&"
1405 [email protected] "\'u8" 1405 [email protected] "'u8"
1406 [email protected] " " 1406 [email protected] " "
1407 [email protected] "u8" 1407 [email protected] "u8"
1408 [email protected] " " 1408 [email protected] " "
@@ -1574,7 +1574,7 @@ [email protected]
1574 [email protected] "<" 1574 [email protected] "<"
1575 [email protected] 1575 [email protected]
1576 [email protected] 1576 [email protected]
1577 [email protected] "\'union" 1577 [email protected] "'union"
1578 [email protected] ">" 1578 [email protected] ">"
1579 [email protected] " " 1579 [email protected] " "
1580 [email protected] 1580 [email protected]
@@ -1588,7 +1588,7 @@ [email protected]
1588 [email protected] 1588 [email protected]
1589 [email protected] "&" 1589 [email protected] "&"
1590 [email protected] 1590 [email protected]
1591 [email protected] "\'union" 1591 [email protected] "'union"
1592 [email protected] " " 1592 [email protected] " "
1593 [email protected] 1593 [email protected]
1594 [email protected] 1594 [email protected]
@@ -1599,7 +1599,7 @@ [email protected]
1599 [email protected] "<" 1599 [email protected] "<"
1600 [email protected] 1600 [email protected]
1601 [email protected] 1601 [email protected]
1602 [email protected] "\'union" 1602 [email protected] "'union"
1603 [email protected] ">" 1603 [email protected] ">"
1604 [email protected] "," 1604 [email protected] ","
1605 [email protected] " " 1605 [email protected] " "
@@ -1681,7 +1681,7 @@ [email protected]
1681 [email protected] "\"\\\\\"" 1681 [email protected] "\"\\\\\""
1682 [email protected] "," 1682 [email protected] ","
1683 [email protected] 1683 [email protected]
1684 [email protected] "\'🤔\'" 1684 [email protected] "'🤔'"
1685 [email protected] ")" 1685 [email protected] ")"
1686 [email protected] "/**/" 1686 [email protected] "/**/"
1687 [email protected] "," 1687 [email protected] ","
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
index f935a0df5..a7f0f7bc6 100644
--- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
+++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
@@ -181,7 +181,7 @@ [email protected]
181 [email protected] "<" 181 [email protected] "<"
182 [email protected] 182 [email protected]
183 [email protected] 183 [email protected]
184 [email protected] "\'a" 184 [email protected] "'a"
185 [email protected] ">" 185 [email protected] ">"
186 [email protected] ")" 186 [email protected] ")"
187 [email protected] ">" 187 [email protected] ">"
@@ -359,7 +359,7 @@ [email protected]
359 [email protected] "<" 359 [email protected] "<"
360 [email protected] 360 [email protected]
361 [email protected] 361 [email protected]
362 [email protected] "\'a" 362 [email protected] "'a"
363 [email protected] ">" 363 [email protected] ">"
364 [email protected] 364 [email protected]
365 [email protected] "(" 365 [email protected] "("
@@ -394,7 +394,7 @@ [email protected]
394 [email protected] "<" 394 [email protected] "<"
395 [email protected] 395 [email protected]
396 [email protected] 396 [email protected]
397 [email protected] "\'a" 397 [email protected] "'a"
398 [email protected] ">" 398 [email protected] ">"
399 [email protected] 399 [email protected]
400 [email protected] "(" 400 [email protected] "("
@@ -411,7 +411,7 @@ [email protected]
411 [email protected] " " 411 [email protected] " "
412 [email protected] "&" 412 [email protected] "&"
413 [email protected] 413 [email protected]
414 [email protected] "\'a" 414 [email protected] "'a"
415 [email protected] " " 415 [email protected] " "
416 [email protected] 416 [email protected]
417 [email protected] "self" 417 [email protected] "self"
@@ -430,7 +430,7 @@ [email protected]
430 [email protected] "<" 430 [email protected] "<"
431 [email protected] 431 [email protected]
432 [email protected] 432 [email protected]
433 [email protected] "\'a" 433 [email protected] "'a"
434 [email protected] ">" 434 [email protected] ">"
435 [email protected] 435 [email protected]
436 [email protected] "(" 436 [email protected] "("
@@ -447,7 +447,7 @@ [email protected]
447 [email protected] " " 447 [email protected] " "
448 [email protected] "&" 448 [email protected] "&"
449 [email protected] 449 [email protected]
450 [email protected] "\'a" 450 [email protected] "'a"
451 [email protected] " " 451 [email protected] " "
452 [email protected] "mut" 452 [email protected] "mut"
453 [email protected] " " 453 [email protected] " "
diff --git a/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast b/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast
index 325e9e655..79e2b2867 100644
--- a/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast
+++ b/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast
@@ -23,7 +23,7 @@ [email protected]
23 [email protected] "<" 23 [email protected] "<"
24 [email protected] 24 [email protected]
25 [email protected] 25 [email protected]
26 [email protected] "\'a" 26 [email protected] "'a"
27 [email protected] ">" 27 [email protected] ">"
28 [email protected] " " 28 [email protected] " "
29 [email protected] 29 [email protected]
@@ -46,7 +46,7 @@ [email protected]
46 [email protected] 46 [email protected]
47 [email protected] "&" 47 [email protected] "&"
48 [email protected] 48 [email protected]
49 [email protected] "\'a" 49 [email protected] "'a"
50 [email protected] " " 50 [email protected] " "
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
@@ -85,13 +85,13 @@ [email protected]
85 [email protected] "<" 85 [email protected] "<"
86 [email protected] 86 [email protected]
87 [email protected] 87 [email protected]
88 [email protected] "\'a" 88 [email protected] "'a"
89 [email protected] ">" 89 [email protected] ">"
90 [email protected] " " 90 [email protected] " "
91 [email protected] 91 [email protected]
92 [email protected] "&" 92 [email protected] "&"
93 [email protected] 93 [email protected]
94 [email protected] "\'a" 94 [email protected] "'a"
95 [email protected] " " 95 [email protected] " "
96 [email protected] 96 [email protected]
97 [email protected] 97 [email protected]
@@ -138,7 +138,7 @@ [email protected]
138 [email protected] "<" 138 [email protected] "<"
139 [email protected] 139 [email protected]
140 [email protected] 140 [email protected]
141 [email protected] "\'a" 141 [email protected] "'a"
142 [email protected] ">" 142 [email protected] ">"
143 [email protected] " " 143 [email protected] " "
144 [email protected] 144 [email protected]
@@ -146,7 +146,7 @@ [email protected]
146 [email protected] 146 [email protected]
147 [email protected] "&" 147 [email protected] "&"
148 [email protected] 148 [email protected]
149 [email protected] "\'a" 149 [email protected] "'a"
150 [email protected] " " 150 [email protected] " "
151 [email protected] 151 [email protected]
152 [email protected] 152 [email protected]
@@ -169,7 +169,7 @@ [email protected]
169 [email protected] 169 [email protected]
170 [email protected] "&" 170 [email protected] "&"
171 [email protected] 171 [email protected]
172 [email protected] "\'a" 172 [email protected] "'a"
173 [email protected] " " 173 [email protected] " "
174 [email protected] 174 [email protected]
175 [email protected] 175 [email protected]
@@ -208,7 +208,7 @@ [email protected]
208 [email protected] "<" 208 [email protected] "<"
209 [email protected] 209 [email protected]
210 [email protected] 210 [email protected]
211 [email protected] "\'a" 211 [email protected] "'a"
212 [email protected] ">" 212 [email protected] ">"
213 [email protected] " " 213 [email protected] " "
214 [email protected] 214 [email protected]
@@ -216,7 +216,7 @@ [email protected]
216 [email protected] 216 [email protected]
217 [email protected] "&" 217 [email protected] "&"
218 [email protected] 218 [email protected]
219 [email protected] "\'a" 219 [email protected] "'a"
220 [email protected] " " 220 [email protected] " "
221 [email protected] 221 [email protected]
222 [email protected] 222 [email protected]
@@ -277,7 +277,7 @@ [email protected]
277 [email protected] "<" 277 [email protected] "<"
278 [email protected] 278 [email protected]
279 [email protected] 279 [email protected]
280 [email protected] "\'a" 280 [email protected] "'a"
281 [email protected] ">" 281 [email protected] ">"
282 [email protected] " " 282 [email protected] " "
283 [email protected] 283 [email protected]
@@ -288,7 +288,7 @@ [email protected]
288 [email protected] 288 [email protected]
289 [email protected] "&" 289 [email protected] "&"
290 [email protected] 290 [email protected]
291 [email protected] "\'a" 291 [email protected] "'a"
292 [email protected] " " 292 [email protected] " "
293 [email protected] 293 [email protected]
294 [email protected] 294 [email protected]
@@ -348,7 +348,7 @@ [email protected]
348 [email protected] "<" 348 [email protected] "<"
349 [email protected] 349 [email protected]
350 [email protected] 350 [email protected]
351 [email protected] "\'a" 351 [email protected] "'a"
352 [email protected] ">" 352 [email protected] ">"
353 [email protected] " " 353 [email protected] " "
354 [email protected] 354 [email protected]
@@ -357,7 +357,7 @@ [email protected]
357 [email protected] "<" 357 [email protected] "<"
358 [email protected] 358 [email protected]
359 [email protected] 359 [email protected]
360 [email protected] "\'b" 360 [email protected] "'b"
361 [email protected] ">" 361 [email protected] ">"
362 [email protected] " " 362 [email protected] " "
363 [email protected] 363 [email protected]
@@ -368,7 +368,7 @@ [email protected]
368 [email protected] 368 [email protected]
369 [email protected] "&" 369 [email protected] "&"
370 [email protected] 370 [email protected]
371 [email protected] "\'a" 371 [email protected] "'a"
372 [email protected] " " 372 [email protected] " "
373 [email protected] 373 [email protected]
374 [email protected] 374 [email protected]
@@ -381,7 +381,7 @@ [email protected]
381 [email protected] 381 [email protected]
382 [email protected] "&" 382 [email protected] "&"
383 [email protected] 383 [email protected]
384 [email protected] "\'b" 384 [email protected] "'b"
385 [email protected] " " 385 [email protected] " "
386 [email protected] 386 [email protected]
387 [email protected] 387 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast
index 8d3e187ae..026c776e2 100644
--- a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast
+++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] "<" 8 [email protected] "<"
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "\'a" 11 [email protected] "'a"
12 [email protected] ">" 12 [email protected] ">"
13 [email protected] " " 13 [email protected] " "
14 [email protected] "=" 14 [email protected] "="
@@ -16,7 +16,7 @@ [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "&" 17 [email protected] "&"
18 [email protected] 18 [email protected]
19 [email protected] "\'a" 19 [email protected] "'a"
20 [email protected] " " 20 [email protected] " "
21 [email protected] 21 [email protected]
22 [email protected] "(" 22 [email protected] "("
@@ -112,7 +112,7 @@ [email protected]
112 [email protected] " " 112 [email protected] " "
113 [email protected] 113 [email protected]
114 [email protected] 114 [email protected]
115 [email protected] "\'static" 115 [email protected] "'static"
116 [email protected] ")" 116 [email protected] ")"
117 [email protected] ";" 117 [email protected] ";"
118 [email protected] "\n" 118 [email protected] "\n"
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index d0bddf7d8..44656267f 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -77,6 +77,11 @@ pub struct Fixture {
77 pub introduce_new_source_root: bool, 77 pub introduce_new_source_root: bool,
78} 78}
79 79
80pub struct MiniCore {
81 activated_flags: Vec<String>,
82 valid_flags: Vec<String>,
83}
84
80impl Fixture { 85impl Fixture {
81 /// Parses text which looks like this: 86 /// Parses text which looks like this:
82 /// 87 ///
@@ -86,12 +91,28 @@ impl Fixture {
86 /// line 2 91 /// line 2
87 /// //- other meta 92 /// //- other meta
88 /// ``` 93 /// ```
89 pub fn parse(ra_fixture: &str) -> Vec<Fixture> { 94 ///
95 /// Fixture can also start with a minicore declaration:
96 ///
97 /// ```
98 /// //- minicore: sized
99 /// ```
100 ///
101 /// That will include a subset of `libcore` into the fixture, see
102 /// `minicore.rs` for what's available.
103 pub fn parse(ra_fixture: &str) -> (Option<MiniCore>, Vec<Fixture>) {
90 let fixture = trim_indent(ra_fixture); 104 let fixture = trim_indent(ra_fixture);
91 105 let mut fixture = fixture.as_str();
106 let mut mini_core = None;
92 let mut res: Vec<Fixture> = Vec::new(); 107 let mut res: Vec<Fixture> = Vec::new();
93 108
94 let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; 109 if fixture.starts_with("//- minicore:") {
110 let first_line = fixture.split_inclusive('\n').next().unwrap();
111 mini_core = Some(MiniCore::parse(first_line));
112 fixture = &fixture[first_line.len()..];
113 }
114
115 let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
95 116
96 for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { 117 for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
97 if line.contains("//-") { 118 if line.contains("//-") {
@@ -108,12 +129,22 @@ impl Fixture {
108 if line.starts_with("//-") { 129 if line.starts_with("//-") {
109 let meta = Fixture::parse_meta_line(line); 130 let meta = Fixture::parse_meta_line(line);
110 res.push(meta) 131 res.push(meta)
111 } else if let Some(entry) = res.last_mut() { 132 } else {
112 entry.text.push_str(line); 133 if line.starts_with("// ")
134 && line.contains(':')
135 && !line.contains("::")
136 && line.chars().all(|it| !it.is_uppercase())
137 {
138 panic!("looks like invalid metadata line: {:?}", line)
139 }
140
141 if let Some(entry) = res.last_mut() {
142 entry.text.push_str(line);
143 }
113 } 144 }
114 } 145 }
115 146
116 res 147 (mini_core, res)
117 } 148 }
118 149
119 //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo 150 //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
@@ -123,7 +154,7 @@ impl Fixture {
123 let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); 154 let components = meta.split_ascii_whitespace().collect::<Vec<_>>();
124 155
125 let path = components[0].to_string(); 156 let path = components[0].to_string();
126 assert!(path.starts_with('/')); 157 assert!(path.starts_with('/'), "fixture path does not start with `/`: {:?}", path);
127 158
128 let mut krate = None; 159 let mut krate = None;
129 let mut deps = Vec::new(); 160 let mut deps = Vec::new();
@@ -133,7 +164,9 @@ impl Fixture {
133 let mut env = FxHashMap::default(); 164 let mut env = FxHashMap::default();
134 let mut introduce_new_source_root = false; 165 let mut introduce_new_source_root = false;
135 for component in components[1..].iter() { 166 for component in components[1..].iter() {
136 let (key, value) = component.split_once(':').unwrap(); 167 let (key, value) = component
168 .split_once(':')
169 .unwrap_or_else(|| panic!("invalid meta line: {:?}", meta));
137 match key { 170 match key {
138 "crate" => krate = Some(value.to_string()), 171 "crate" => krate = Some(value.to_string()),
139 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), 172 "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
@@ -172,6 +205,139 @@ impl Fixture {
172 } 205 }
173} 206}
174 207
208impl MiniCore {
209 fn has_flag(&self, flag: &str) -> bool {
210 self.activated_flags.iter().any(|it| it == flag)
211 }
212
213 #[track_caller]
214 fn assert_valid_flag(&self, flag: &str) {
215 if !self.valid_flags.iter().any(|it| it == flag) {
216 panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags);
217 }
218 }
219
220 fn parse(line: &str) -> MiniCore {
221 let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() };
222
223 let line = line.strip_prefix("//- minicore:").unwrap().trim();
224 for entry in line.split(", ") {
225 if res.has_flag(entry) {
226 panic!("duplicate minicore flag: {:?}", entry)
227 }
228 res.activated_flags.push(entry.to_string())
229 }
230
231 res
232 }
233
234 /// Strips parts of minicore.rs which are flagged by inactive flags.
235 ///
236 /// This is probably over-engineered to support flags dependencies.
237 pub fn source_code(mut self) -> String {
238 let mut buf = String::new();
239 let raw_mini_core = include_str!("./minicore.rs");
240 let mut lines = raw_mini_core.split_inclusive('\n');
241
242 let mut parsing_flags = false;
243 let mut implications = Vec::new();
244
245 // Parse `//!` preamble and extract flags and dependencies.
246 for line in lines.by_ref() {
247 let line = match line.strip_prefix("//!") {
248 Some(it) => it,
249 None => {
250 assert!(line.trim().is_empty());
251 break;
252 }
253 };
254
255 if parsing_flags {
256 let (flag, deps) = line.split_once(':').unwrap();
257 let flag = flag.trim();
258 self.valid_flags.push(flag.to_string());
259 for dep in deps.split(", ") {
260 let dep = dep.trim();
261 if !dep.is_empty() {
262 self.assert_valid_flag(dep);
263 implications.push((flag, dep));
264 }
265 }
266 }
267
268 if line.contains("Available flags:") {
269 parsing_flags = true;
270 }
271 }
272
273 for flag in &self.activated_flags {
274 self.assert_valid_flag(flag);
275 }
276
277 // Fixed point loop to compute transitive closure of flags.
278 loop {
279 let mut changed = false;
280 for &(u, v) in implications.iter() {
281 if self.has_flag(u) && !self.has_flag(v) {
282 self.activated_flags.push(v.to_string());
283 changed = true;
284 }
285 }
286 if !changed {
287 break;
288 }
289 }
290
291 let mut active_regions = Vec::new();
292 let mut seen_regions = Vec::new();
293 for line in lines {
294 let trimmed = line.trim();
295 if let Some(region) = trimmed.strip_prefix("// region:") {
296 active_regions.push(region);
297 continue;
298 }
299 if let Some(region) = trimmed.strip_prefix("// endregion:") {
300 let prev = active_regions.pop().unwrap();
301 assert_eq!(prev, region);
302 continue;
303 }
304
305 let mut line_region = false;
306 if let Some(idx) = trimmed.find("// :") {
307 line_region = true;
308 active_regions.push(&trimmed[idx + "// :".len()..]);
309 }
310
311 let mut keep = true;
312 for &region in &active_regions {
313 assert!(
314 !region.starts_with(' '),
315 "region marker starts with a space: {:?}",
316 region
317 );
318 self.assert_valid_flag(region);
319 seen_regions.push(region);
320 keep &= self.has_flag(region);
321 }
322
323 if keep {
324 buf.push_str(line)
325 }
326 if line_region {
327 active_regions.pop().unwrap();
328 }
329 }
330
331 for flag in &self.valid_flags {
332 if !seen_regions.iter().any(|it| it == flag) {
333 panic!("unused minicore flag: {:?}", flag);
334 }
335 }
336 format!("{}", buf);
337 buf
338 }
339}
340
175#[test] 341#[test]
176#[should_panic] 342#[should_panic]
177fn parse_fixture_checks_further_indented_metadata() { 343fn parse_fixture_checks_further_indented_metadata() {
@@ -189,12 +355,14 @@ fn parse_fixture_checks_further_indented_metadata() {
189 355
190#[test] 356#[test]
191fn parse_fixture_gets_full_meta() { 357fn parse_fixture_gets_full_meta() {
192 let parsed = Fixture::parse( 358 let (mini_core, parsed) = Fixture::parse(
193 r" 359 r#"
194 //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo 360//- minicore: coerce_unsized
195 mod m; 361//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo
196 ", 362mod m;
363"#,
197 ); 364 );
365 assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]);
198 assert_eq!(1, parsed.len()); 366 assert_eq!(1, parsed.len());
199 367
200 let meta = &parsed[0]; 368 let meta = &parsed[0];
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index b2fe25f82..d9c22c180 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -11,6 +11,7 @@ mod fixture;
11mod assert_linear; 11mod assert_linear;
12 12
13use std::{ 13use std::{
14 collections::BTreeMap,
14 convert::{TryFrom, TryInto}, 15 convert::{TryFrom, TryInto},
15 env, fs, 16 env, fs,
16 path::{Path, PathBuf}, 17 path::{Path, PathBuf},
@@ -23,7 +24,10 @@ use text_size::{TextRange, TextSize};
23pub use dissimilar::diff as __diff; 24pub use dissimilar::diff as __diff;
24pub use rustc_hash::FxHashMap; 25pub use rustc_hash::FxHashMap;
25 26
26pub use crate::{assert_linear::AssertLinear, fixture::Fixture}; 27pub use crate::{
28 assert_linear::AssertLinear,
29 fixture::{Fixture, MiniCore},
30};
27 31
28pub const CURSOR_MARKER: &str = "$0"; 32pub const CURSOR_MARKER: &str = "$0";
29pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; 33pub const ESCAPED_CURSOR_MARKER: &str = "\\$0";
@@ -202,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
202/// 206///
203/// // ^^^ first line 207/// // ^^^ first line
204/// // | second line 208/// // | second line
209///
210/// Annotations point to the last line that actually was long enough for the
211/// range, not counting annotations themselves. So overlapping annotations are
212/// possible:
213/// ```no_run
214/// // stuff other stuff
215/// // ^^ 'st'
216/// // ^^^^^ 'stuff'
217/// // ^^^^^^^^^^^ 'other stuff'
218/// ```
205pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { 219pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
206 let mut res = Vec::new(); 220 let mut res = Vec::new();
207 let mut prev_line_start: Option<TextSize> = Some(0.into()); 221 // map from line length to beginning of last line that had that length
222 let mut line_start_map = BTreeMap::new();
208 let mut line_start: TextSize = 0.into(); 223 let mut line_start: TextSize = 0.into();
209 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); 224 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
210 for line in text.split_inclusive('\n') { 225 for line in text.split_inclusive('\n') {
211 let mut this_line_annotations = Vec::new(); 226 let mut this_line_annotations = Vec::new();
212 if let Some(idx) = line.find("//") { 227 let line_length = if let Some(idx) = line.find("//") {
213 let annotation_offset = TextSize::of(&line[..idx + "//".len()]); 228 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
214 for annotation in extract_line_annotations(&line[idx + "//".len()..]) { 229 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
215 match annotation { 230 match annotation {
@@ -219,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
219 let range = if file { 234 let range = if file {
220 TextRange::up_to(TextSize::of(text)) 235 TextRange::up_to(TextSize::of(text))
221 } else { 236 } else {
222 range + prev_line_start.unwrap() 237 let line_start = line_start_map.range(range.end()..).next().unwrap();
238
239 range + line_start.1
223 }; 240 };
224 res.push((range, content)) 241 res.push((range, content))
225 } 242 }
@@ -235,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
235 } 252 }
236 } 253 }
237 } 254 }
238 } 255 idx.try_into().unwrap()
256 } else {
257 TextSize::of(line)
258 };
259
260 line_start_map = line_start_map.split_off(&line_length);
261 line_start_map.insert(line_length, line_start);
239 262
240 prev_line_start = Some(line_start);
241 line_start += TextSize::of(line); 263 line_start += TextSize::of(line);
242 264
243 prev_line_annotations = this_line_annotations; 265 prev_line_annotations = this_line_annotations;
@@ -293,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
293} 315}
294 316
295#[test] 317#[test]
296fn test_extract_annotations() { 318fn test_extract_annotations_1() {
297 let text = stdx::trim_indent( 319 let text = stdx::trim_indent(
298 r#" 320 r#"
299fn main() { 321fn main() {
@@ -318,6 +340,25 @@ fn main() {
318 assert_eq!(res[3].0.len(), 115); 340 assert_eq!(res[3].0.len(), 115);
319} 341}
320 342
343#[test]
344fn test_extract_annotations_2() {
345 let text = stdx::trim_indent(
346 r#"
347fn main() {
348 (x, y);
349 //^ a
350 // ^ b
351 //^^^^^^^^ c
352}"#,
353 );
354 let res = extract_annotations(&text)
355 .into_iter()
356 .map(|(range, ann)| (&text[range], ann))
357 .collect::<Vec<_>>();
358
359 assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]);
360}
361
321/// Returns `false` if slow tests should not run, otherwise returns `true` and 362/// Returns `false` if slow tests should not run, otherwise returns `true` and
322/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag 363/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
323/// that slow tests did run. 364/// that slow tests did run.
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs
new file mode 100644
index 000000000..ce6ad8541
--- /dev/null
+++ b/crates/test_utils/src/minicore.rs
@@ -0,0 +1,549 @@
1//! This is a fixture we use for tests that need lang items.
2//!
3//! We want to include the minimal subset of core for each test, so this file
4//! supports "conditional compilation". Tests use the following syntax to include minicore:
5//!
6//! //- minicore: flag1, flag2
7//!
8//! We then strip all the code marked with other flags.
9//!
10//! Available flags:
11//! sized:
12//! unsize: sized
13//! coerce_unsized: unsize
14//! slice:
15//! range:
16//! deref: sized
17//! deref_mut: deref
18//! index: sized
19//! fn:
20//! pin:
21//! future: pin
22//! option:
23//! result:
24//! iterator: option
25//! iterators: iterator, fn
26//! default: sized
27//! clone: sized
28//! copy: clone
29//! from: sized
30//! eq: sized
31//! ord: eq, option
32//! derive:
33
34pub mod marker {
35 // region:sized
36 #[lang = "sized"]
37 #[fundamental]
38 #[rustc_specialization_trait]
39 pub trait Sized {}
40 // endregion:sized
41
42 // region:unsize
43 #[lang = "unsize"]
44 pub trait Unsize<T: ?Sized> {}
45 // endregion:unsize
46
47 // region:copy
48 #[lang = "copy"]
49 pub trait Copy: Clone {}
50 // region:derive
51 #[rustc_builtin_macro]
52 pub macro Copy($item:item) {}
53 // endregion:derive
54
55 mod copy_impls {
56 use super::Copy;
57
58 macro_rules! impl_copy {
59 ($($t:ty)*) => {
60 $(
61 impl Copy for $t {}
62 )*
63 }
64 }
65
66 impl_copy! {
67 usize u8 u16 u32 u64 u128
68 isize i8 i16 i32 i64 i128
69 f32 f64
70 bool char
71 }
72
73 impl<T: ?Sized> Copy for *const T {}
74 impl<T: ?Sized> Copy for *mut T {}
75 impl<T: ?Sized> Copy for &T {}
76 }
77 // endregion:copy
78}
79
80// region:default
81pub mod default {
82 pub trait Default: Sized {
83 fn default() -> Self;
84 }
85}
86// endregion:default
87
88// region:clone
89pub mod clone {
90 #[lang = "clone"]
91 pub trait Clone: Sized {
92 fn clone(&self) -> Self;
93 }
94 // region:derive
95 #[rustc_builtin_macro]
96 pub macro Clone($item:item) {}
97 // endregion:derive
98}
99// endregion:clone
100
101// region:from
102pub mod convert {
103 pub trait From<T>: Sized {
104 fn from(_: T) -> Self;
105 }
106 pub trait Into<T>: Sized {
107 fn into(self) -> T;
108 }
109
110 impl<T, U> Into<U> for T
111 where
112 U: From<T>,
113 {
114 fn into(self) -> U {
115 U::from(self)
116 }
117 }
118
119 impl<T> From<T> for T {
120 fn from(t: T) -> T {
121 t
122 }
123 }
124}
125// endregion:from
126
127pub mod ops {
128 // region:coerce_unsized
129 mod unsize {
130 use crate::marker::Unsize;
131
132 #[lang = "coerce_unsized"]
133 pub trait CoerceUnsized<T: ?Sized> {}
134
135 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
136 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
137 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
138 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
139
140 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
141 impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
142
143 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
144 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
145 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
146 }
147 pub use self::unsize::CoerceUnsized;
148 // endregion:coerce_unsized
149
150 // region:deref
151 mod deref {
152 #[lang = "deref"]
153 pub trait Deref {
154 #[lang = "deref_target"]
155 type Target: ?Sized;
156 fn deref(&self) -> &Self::Target;
157 }
158 // region:deref_mut
159 #[lang = "deref_mut"]
160 pub trait DerefMut: Deref {
161 fn deref_mut(&mut self) -> &mut Self::Target;
162 }
163 // endregion:deref_mut
164 }
165 pub use self::deref::{
166 Deref,
167 DerefMut, // :deref_mut
168 };
169 // endregion:deref
170
171 // region:index
172 mod index {
173 #[lang = "index"]
174 pub trait Index<Idx: ?Sized> {
175 type Output: ?Sized;
176 fn index(&self, index: Idx) -> &Self::Output;
177 }
178 #[lang = "index_mut"]
179 pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
180 fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
181 }
182
183 // region:slice
184 impl<T, I> Index<I> for [T]
185 where
186 I: SliceIndex<[T]>,
187 {
188 type Output = I::Output;
189 fn index(&self, index: I) -> &I::Output {
190 loop {}
191 }
192 }
193 impl<T, I> IndexMut<I> for [T]
194 where
195 I: SliceIndex<[T]>,
196 {
197 fn index_mut(&mut self, index: I) -> &mut I::Output {
198 loop {}
199 }
200 }
201
202 pub unsafe trait SliceIndex<T: ?Sized> {
203 type Output: ?Sized;
204 }
205 unsafe impl<T> SliceIndex<[T]> for usize {
206 type Output = T;
207 }
208 // endregion:slice
209 }
210 pub use self::index::{Index, IndexMut};
211 // endregion:index
212
213 // region:range
214 mod range {
215 #[lang = "RangeFull"]
216 pub struct RangeFull;
217
218 #[lang = "Range"]
219 pub struct Range<Idx> {
220 pub start: Idx,
221 pub end: Idx,
222 }
223
224 #[lang = "RangeFrom"]
225 pub struct RangeFrom<Idx> {
226 pub start: Idx,
227 }
228
229 #[lang = "RangeTo"]
230 pub struct RangeTo<Idx> {
231 pub end: Idx,
232 }
233
234 #[lang = "RangeInclusive"]
235 pub struct RangeInclusive<Idx> {
236 pub(crate) start: Idx,
237 pub(crate) end: Idx,
238 pub(crate) exhausted: bool,
239 }
240
241 #[lang = "RangeToInclusive"]
242 pub struct RangeToInclusive<Idx> {
243 pub end: Idx,
244 }
245 }
246 pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
247 pub use self::range::{RangeInclusive, RangeToInclusive};
248 // endregion:range
249
250 // region:fn
251 mod function {
252 #[lang = "fn"]
253 #[fundamental]
254 pub trait Fn<Args>: FnMut<Args> {}
255
256 #[lang = "fn_mut"]
257 #[fundamental]
258 pub trait FnMut<Args>: FnOnce<Args> {}
259
260 #[lang = "fn_once"]
261 #[fundamental]
262 pub trait FnOnce<Args> {
263 #[lang = "fn_once_output"]
264 type Output;
265 }
266 }
267 pub use self::function::{Fn, FnMut, FnOnce};
268 // endregion:fn
269}
270
271// region:eq
272pub mod cmp {
273 #[lang = "eq"]
274 pub trait PartialEq<Rhs: ?Sized = Self> {
275 fn eq(&self, other: &Rhs) -> bool;
276 }
277
278 pub trait Eq: PartialEq<Self> {}
279
280 // region:derive
281 #[rustc_builtin_macro]
282 pub macro PartialEq($item:item) {}
283 #[rustc_builtin_macro]
284 pub macro Eq($item:item) {}
285 // endregion:derive
286
287 // region:ord
288 #[lang = "partial_ord"]
289 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
290 fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
291 }
292
293 pub trait Ord: Eq + PartialOrd<Self> {
294 fn cmp(&self, other: &Self) -> Ordering;
295 }
296
297 pub enum Ordering {
298 Less = -1,
299 Equal = 0,
300 Greater = 1,
301 }
302
303 // region:derive
304 #[rustc_builtin_macro]
305 pub macro PartialOrd($item:item) {}
306 #[rustc_builtin_macro]
307 pub macro Ord($item:item) {}
308 // endregion:derive
309
310 // endregion:ord
311}
312// endregion:eq
313
314// region:slice
315pub mod slice {
316 #[lang = "slice"]
317 impl<T> [T] {
318 pub fn len(&self) -> usize {
319 loop {}
320 }
321 }
322}
323// endregion:slice
324
325// region:option
326pub mod option {
327 pub enum Option<T> {
328 #[lang = "None"]
329 None,
330 #[lang = "Some"]
331 Some(T),
332 }
333}
334// endregion:option
335
336// region:result
337pub mod result {
338 pub enum Result<T, E> {
339 #[lang = "Ok"]
340 Ok(T),
341 #[lang = "Err"]
342 Err(E),
343 }
344}
345// endregion:result
346
347// region:pin
348pub mod pin {
349 #[lang = "pin"]
350 #[fundamental]
351 pub struct Pin<P> {
352 pointer: P,
353 }
354}
355// endregion:pin
356
357// region:future
358pub mod future {
359 use crate::{
360 pin::Pin,
361 task::{Context, Poll},
362 };
363
364 #[lang = "future_trait"]
365 pub trait Future {
366 type Output;
367 #[lang = "poll"]
368 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
369 }
370}
371pub mod task {
372 pub enum Poll<T> {
373 #[lang = "Ready"]
374 Ready(T),
375 #[lang = "Pending"]
376 Pending,
377 }
378
379 pub struct Context<'a> {
380 waker: &'a (),
381 }
382}
383// endregion:future
384
385// region:iterator
386pub mod iter {
387 // region:iterators
388 mod adapters {
389 pub struct Take<I> {
390 iter: I,
391 n: usize,
392 }
393 impl<I> Iterator for Take<I>
394 where
395 I: Iterator,
396 {
397 type Item = <I as Iterator>::Item;
398
399 fn next(&mut self) -> Option<<I as Iterator>::Item> {
400 loop {}
401 }
402 }
403
404 pub struct FilterMap<I, F> {
405 iter: I,
406 f: F,
407 }
408 impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
409 where
410 F: FnMut(I::Item) -> Option<B>,
411 {
412 type Item = B;
413
414 #[inline]
415 fn next(&mut self) -> Option<B> {
416 loop {}
417 }
418 }
419 }
420 pub use self::adapters::Take;
421
422 mod sources {
423 mod repeat {
424 pub fn repeat<T>(elt: T) -> Repeat<T> {
425 loop {}
426 }
427
428 pub struct Repeat<A> {
429 element: A,
430 }
431
432 impl<A> Iterator for Repeat<A> {
433 type Item = A;
434
435 fn next(&mut self) -> Option<A> {
436 loop {}
437 }
438 }
439 }
440 pub use self::repeat::{repeat, Repeat};
441 }
442 pub use self::sources::{repeat, Repeat};
443 // endregion:iterators
444
445 mod traits {
446 mod iterator {
447 use super::super::Take;
448
449 pub trait Iterator {
450 type Item;
451 #[lang = "next"]
452 fn next(&mut self) -> Option<Self::Item>;
453 fn nth(&mut self, n: usize) -> Option<Self::Item> {
454 loop {}
455 }
456 fn by_ref(&mut self) -> &mut Self
457 where
458 Self: Sized,
459 {
460 self
461 }
462 // region:iterators
463 fn take(self, n: usize) -> crate::iter::Take<Self> {
464 loop {}
465 }
466 fn filter_map<B, F>(self, f: F) -> crate::iter::FilterMap<Self, F>
467 where
468 Self: Sized,
469 F: FnMut(Self::Item) -> Option<B>,
470 {
471 loop {}
472 }
473 // endregion:iterators
474 }
475 impl<I: Iterator + ?Sized> Iterator for &mut I {
476 type Item = I::Item;
477 fn next(&mut self) -> Option<I::Item> {
478 (**self).next()
479 }
480 }
481 }
482 pub use self::iterator::Iterator;
483
484 mod collect {
485 pub trait IntoIterator {
486 type Item;
487 type IntoIter: Iterator<Item = Self::Item>;
488 #[lang = "into_iter"]
489 fn into_iter(self) -> Self::IntoIter;
490 }
491 impl<I: Iterator> IntoIterator for I {
492 type Item = I::Item;
493 type IntoIter = I;
494 fn into_iter(self) -> I {
495 self
496 }
497 }
498 }
499 pub use self::collect::IntoIterator;
500 }
501 pub use self::traits::{IntoIterator, Iterator};
502}
503// endregion:iterator
504
505// region:derive
506mod macros {
507 pub(crate) mod builtin {
508 #[rustc_builtin_macro]
509 pub macro derive($item:item) {
510 /* compiler built-in */
511 }
512 }
513}
514// endregion:derive
515
516pub mod prelude {
517 pub mod v1 {
518 pub use crate::{
519 clone::Clone, // :clone
520 cmp::{Eq, PartialEq}, // :eq
521 cmp::{Ord, PartialOrd}, // :ord
522 convert::{From, Into}, // :from
523 default::Default, // :default
524 iter::{IntoIterator, Iterator}, // :iterator
525 macros::builtin::derive, // :derive
526 marker::Copy, // :copy
527 marker::Sized, // :sized
528 ops::{Fn, FnMut, FnOnce}, // :fn
529 option::Option::{self, None, Some}, // :option
530 result::Result::{self, Err, Ok}, // :result
531 };
532 }
533
534 pub mod rust_2015 {
535 pub use super::v1::*;
536 }
537
538 pub mod rust_2018 {
539 pub use super::v1::*;
540 }
541
542 pub mod rust_2021 {
543 pub use super::v1::*;
544 }
545}
546
547#[prelude_import]
548#[allow(unused)]
549use prelude::v1::*;
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs
index 2b3d7fd84..ef2d7657a 100644
--- a/crates/vfs/src/vfs_path.rs
+++ b/crates/vfs/src/vfs_path.rs
@@ -389,7 +389,7 @@ impl VirtualPath {
389 389
390 match (file_stem, extension) { 390 match (file_stem, extension) {
391 (None, None) => None, 391 (None, None) => None,
392 (None, Some(_)) | (Some(""), Some(_)) => Some((file_name, None)), 392 (None | Some(""), Some(_)) => Some((file_name, None)),
393 (Some(file_stem), extension) => Some((file_stem, extension)), 393 (Some(file_stem), extension) => Some((file_stem, extension)),
394 } 394 }
395 } 395 }
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md
index 5876e71bc..48caec1d8 100644
--- a/docs/dev/debugging.md
+++ b/docs/dev/debugging.md
@@ -65,6 +65,11 @@ If you need to debug the server from the very beginning, including its initializ
65 } 65 }
66``` 66```
67 67
68However for this to work, you will need to enable debug_assertions in your build
69```rust
70RUSTFLAGS='--cfg debug_assertions' cargo build --release
71```
72
68## Demo 73## Demo
69 74
70- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). 75- [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM).
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 96dd684b3..84485ea28 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -174,6 +174,13 @@ Instead, explicitly check for `None`, `Err`, etc.
174`rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics. 174`rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics.
175Panic messages in the logs from the `#[should_panic]` tests are confusing. 175Panic messages in the logs from the `#[should_panic]` tests are confusing.
176 176
177## `#[ignore]`
178
179Do not `#[ignore]` tests.
180If the test currently does not work, assert the wrong behavior and add a fixme explaining why it is wrong.
181
182**Rationale:** noticing when the behavior is fixed, making sure that even the wrong behavior is acceptable (ie, not a panic).
183
177## Function Preconditions 184## Function Preconditions
178 185
179Express function preconditions in types and force the caller to provide them (rather than checking in callee): 186Express function preconditions in types and force the caller to provide them (rather than checking in callee):
diff --git a/docs/user/.gitignore b/docs/user/.gitignore
new file mode 100644
index 000000000..c32b1bcec
--- /dev/null
+++ b/docs/user/.gitignore
@@ -0,0 +1 @@
manual.html
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 4105d784f..cc7fdd38f 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -18,6 +18,11 @@ The path structure for newly inserted paths to use.
18-- 18--
19Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 19Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
20-- 20--
21[[rust-analyzer.assist.allowMergingIntoGlobImports]]rust-analyzer.assist.allowMergingIntoGlobImports (default: `true`)::
22+
23--
24Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
25--
21[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: 26[[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`)::
22+ 27+
23-- 28--
@@ -34,6 +39,11 @@ Automatically refresh project info via `cargo metadata` on
34-- 39--
35Activate all available features (`--all-features`). 40Activate all available features (`--all-features`).
36-- 41--
42[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
43+
44--
45Unsets `#[cfg(test)]` for the specified crates.
46--
37[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: 47[[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
38+ 48+
39-- 49--
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 9a8d76700..816e094c2 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -201,6 +201,15 @@ $ eselect repository enable guru && emaint sync -r guru
201$ emerge rust-analyzer-bin 201$ emerge rust-analyzer-bin
202---- 202----
203 203
204==== macOS
205
206The `rust-analyzer` binary can be installed via https://brew.sh/[Homebrew].
207
208[source,bash]
209----
210$ brew install rust-analyzer
211----
212
204=== Emacs 213=== Emacs
205 214
206Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm]. 215Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm].
@@ -609,9 +618,14 @@ Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrar
609* VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself. 618* VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself.
610* rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety. 619* rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety.
611 620
612rust-analyzer itself doesn't access the network. 621== Privacy
613The VS Code plugin doesn't access the network unless the nightly channel is selected in the settings. 622
614In that case, the plugin uses the GitHub API to check for and download updates. 623The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies.
624If enabled (the default), build scripts and procedural macros can do anything.
625
626The Code extension automatically connects to GitHub to download updated LSP binaries and, if the nightly channel is selected, to perform update checks using the GitHub API. For `rust-analyzer` developers, using `cargo xtask release` uses the same API to put together the release notes.
627
628Any other editor plugins are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers.
615 629
616== Features 630== Features
617 631
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 52ffc0f9f..d22c80754 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -986,9 +986,9 @@
986 } 986 }
987 }, 987 },
988 "node_modules/css-what": { 988 "node_modules/css-what": {
989 "version": "5.0.0", 989 "version": "5.0.1",
990 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz", 990 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz",
991 "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==", 991 "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==",
992 "dev": true, 992 "dev": true,
993 "engines": { 993 "engines": {
994 "node": ">= 6" 994 "node": ">= 6"
@@ -4345,9 +4345,9 @@
4345 } 4345 }
4346 }, 4346 },
4347 "css-what": { 4347 "css-what": {
4348 "version": "5.0.0", 4348 "version": "5.0.1",
4349 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz", 4349 "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz",
4350 "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==", 4350 "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==",
4351 "dev": true 4351 "dev": true
4352 }, 4352 },
4353 "debug": { 4353 "debug": {
diff --git a/editors/code/package.json b/editors/code/package.json
index 43a5cc2b5..666016ae4 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -313,7 +313,7 @@
313 }, 313 },
314 "rust-analyzer.updates.askBeforeDownload": { 314 "rust-analyzer.updates.askBeforeDownload": {
315 "type": "boolean", 315 "type": "boolean",
316 "default": true, 316 "default": false,
317 "description": "Whether to ask for permission before downloading any files from the Internet." 317 "description": "Whether to ask for permission before downloading any files from the Internet."
318 }, 318 },
319 "rust-analyzer.server.path": { 319 "rust-analyzer.server.path": {
@@ -389,7 +389,7 @@
389 "default": {}, 389 "default": {},
390 "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" 390 "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
391 }, 391 },
392 "$generated-start": false, 392 "$generated-start": {},
393 "rust-analyzer.assist.importGranularity": { 393 "rust-analyzer.assist.importGranularity": {
394 "markdownDescription": "How imports should be grouped into use statements.", 394 "markdownDescription": "How imports should be grouped into use statements.",
395 "default": "crate", 395 "default": "crate",
@@ -418,13 +418,13 @@
418 "type": "string", 418 "type": "string",
419 "enum": [ 419 "enum": [
420 "plain", 420 "plain",
421 "by_self", 421 "self",
422 "by_crate" 422 "crate"
423 ], 423 ],
424 "enumDescriptions": [ 424 "enumDescriptions": [
425 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", 425 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
426 "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", 426 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.",
427 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." 427 "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
428 ] 428 ]
429 }, 429 },
430 "rust-analyzer.assist.importGroup": { 430 "rust-analyzer.assist.importGroup": {
@@ -432,6 +432,11 @@
432 "default": true, 432 "default": true,
433 "type": "boolean" 433 "type": "boolean"
434 }, 434 },
435 "rust-analyzer.assist.allowMergingIntoGlobImports": {
436 "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.",
437 "default": true,
438 "type": "boolean"
439 },
435 "rust-analyzer.callInfo.full": { 440 "rust-analyzer.callInfo.full": {
436 "markdownDescription": "Show function name and docs in parameter hints.", 441 "markdownDescription": "Show function name and docs in parameter hints.",
437 "default": true, 442 "default": true,
@@ -447,6 +452,16 @@
447 "default": false, 452 "default": false,
448 "type": "boolean" 453 "type": "boolean"
449 }, 454 },
455 "rust-analyzer.cargo.unsetTest": {
456 "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
457 "default": [
458 "core"
459 ],
460 "type": "array",
461 "items": {
462 "type": "string"
463 }
464 },
450 "rust-analyzer.cargo.features": { 465 "rust-analyzer.cargo.features": {
451 "markdownDescription": "List of features to activate.", 466 "markdownDescription": "List of features to activate.",
452 "default": [], 467 "default": [],
@@ -846,7 +861,7 @@
846 "Search for all symbols kinds" 861 "Search for all symbols kinds"
847 ] 862 ]
848 }, 863 },
849 "$generated-end": false 864 "$generated-end": {}
850 } 865 }
851 }, 866 },
852 "problemPatterns": [ 867 "problemPatterns": [
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index f58d26215..15f2151ad 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -158,7 +158,7 @@ export async function deactivate() {
158} 158}
159 159
160async function bootstrap(config: Config, state: PersistentState): Promise<string> { 160async function bootstrap(config: Config, state: PersistentState): Promise<string> {
161 await vscode.workspace.fs.createDirectory(config.globalStorageUri); 161 await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
162 162
163 if (!config.currentExtensionIsNightly) { 163 if (!config.currentExtensionIsNightly) {
164 await state.updateNightlyReleaseId(undefined); 164 await state.updateNightlyReleaseId(undefined);
@@ -277,11 +277,11 @@ async function patchelf(dest: vscode.Uri): Promise<void> {
277 ''; 277 '';
278 } 278 }
279 `; 279 `;
280 const origFile = vscode.Uri.file(dest.path + "-orig"); 280 const origFile = vscode.Uri.file(dest.fsPath + "-orig");
281 await vscode.workspace.fs.rename(dest, origFile); 281 await vscode.workspace.fs.rename(dest, origFile);
282 progress.report({ message: "Patching executable", increment: 20 }); 282 progress.report({ message: "Patching executable", increment: 20 });
283 await new Promise((resolve, reject) => { 283 await new Promise((resolve, reject) => {
284 const handle = exec(`nix-build -E - --argstr srcStr '${origFile.path}' -o '${dest.path}'`, 284 const handle = exec(`nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`,
285 (err, stdout, stderr) => { 285 (err, stdout, stderr) => {
286 if (err != null) { 286 if (err != null) {
287 reject(Error(stderr)); 287 reject(Error(stderr));
@@ -338,14 +338,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string
338 await state.updateServerVersion(undefined); 338 await state.updateServerVersion(undefined);
339 } 339 }
340 340
341 if (state.serverVersion === config.package.version) return dest.path; 341 if (state.serverVersion === config.package.version) return dest.fsPath;
342 342
343 if (config.askBeforeDownload) { 343 if (config.askBeforeDownload) {
344 const userResponse = await vscode.window.showInformationMessage( 344 const userResponse = await vscode.window.showInformationMessage(
345 `Language server version ${config.package.version} for rust-analyzer is not installed.`, 345 `Language server version ${config.package.version} for rust-analyzer is not installed.`,
346 "Download now" 346 "Download now"
347 ); 347 );
348 if (userResponse !== "Download now") return dest.path; 348 if (userResponse !== "Download now") return dest.fsPath;
349 } 349 }
350 350
351 const releaseTag = config.package.releaseTag; 351 const releaseTag = config.package.releaseTag;
@@ -372,7 +372,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string
372 } 372 }
373 373
374 await state.updateServerVersion(config.package.version); 374 await state.updateServerVersion(config.package.version);
375 return dest.path; 375 return dest.fsPath;
376} 376}
377 377
378function serverPath(config: Config): string | null { 378function serverPath(config: Config): string | null {
@@ -383,7 +383,7 @@ async function isNixOs(): Promise<boolean> {
383 try { 383 try {
384 const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString(); 384 const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString();
385 return contents.indexOf("ID=nixos") !== -1; 385 return contents.indexOf("ID=nixos") !== -1;
386 } catch (e) { 386 } catch {
387 return false; 387 return false;
388 } 388 }
389} 389}
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index 747c02db9..722dab756 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -91,7 +91,7 @@ export async function download(opts: DownloadOpts) {
91 // to prevent partially downloaded files when user kills vscode 91 // to prevent partially downloaded files when user kills vscode
92 // This also avoids overwriting running executables 92 // This also avoids overwriting running executables
93 const randomHex = crypto.randomBytes(5).toString("hex"); 93 const randomHex = crypto.randomBytes(5).toString("hex");
94 const rawDest = path.parse(opts.dest.path); 94 const rawDest = path.parse(opts.dest.fsPath);
95 const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`); 95 const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`);
96 96
97 await vscode.window.withProgress( 97 await vscode.window.withProgress(
@@ -116,7 +116,7 @@ export async function download(opts: DownloadOpts) {
116 } 116 }
117 ); 117 );
118 118
119 await vscode.workspace.fs.rename(tempFilePath, opts.dest); 119 await vscode.workspace.fs.rename(tempFilePath, opts.dest, { overwrite: true });
120} 120}
121 121
122async function downloadFile( 122async function downloadFile(
@@ -127,17 +127,19 @@ async function downloadFile(
127 httpProxy: string | null | undefined, 127 httpProxy: string | null | undefined,
128 onProgress: (readBytes: number, totalBytes: number) => void 128 onProgress: (readBytes: number, totalBytes: number) => void
129): Promise<void> { 129): Promise<void> {
130 const urlString = url.toString();
131
130 const res = await (() => { 132 const res = await (() => {
131 if (httpProxy) { 133 if (httpProxy) {
132 log.debug(`Downloading ${url.path} via proxy: ${httpProxy}`); 134 log.debug(`Downloading ${urlString} via proxy: ${httpProxy}`);
133 return fetch(url.path, { agent: new HttpsProxyAgent(httpProxy) }); 135 return fetch(urlString, { agent: new HttpsProxyAgent(httpProxy) });
134 } 136 }
135 137
136 return fetch(url.path); 138 return fetch(urlString);
137 })(); 139 })();
138 140
139 if (!res.ok) { 141 if (!res.ok) {
140 log.error("Error", res.status, "while downloading file from", url.path); 142 log.error("Error", res.status, "while downloading file from", urlString);
141 log.error({ body: await res.text(), headers: res.headers }); 143 log.error({ body: await res.text(), headers: res.headers });
142 144
143 throw new Error(`Got response ${res.status} when trying to download a file.`); 145 throw new Error(`Got response ${res.status} when trying to download a file.`);
@@ -146,7 +148,7 @@ async function downloadFile(
146 const totalBytes = Number(res.headers.get('content-length')); 148 const totalBytes = Number(res.headers.get('content-length'));
147 assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); 149 assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol");
148 150
149 log.debug("Downloading file of", totalBytes, "bytes size from", url.path, "to", destFilePath.path); 151 log.debug("Downloading file of", totalBytes, "bytes size from", urlString, "to", destFilePath.fsPath);
150 152
151 let readBytes = 0; 153 let readBytes = 0;
152 res.body.on("data", (chunk: Buffer) => { 154 res.body.on("data", (chunk: Buffer) => {
@@ -154,7 +156,7 @@ async function downloadFile(
154 onProgress(readBytes, totalBytes); 156 onProgress(readBytes, totalBytes);
155 }); 157 });
156 158
157 const destFileStream = fs.createWriteStream(destFilePath.path, { mode }); 159 const destFileStream = fs.createWriteStream(destFilePath.fsPath, { mode });
158 const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; 160 const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
159 161
160 await pipeline(srcStream, destFileStream); 162 await pipeline(srcStream, destFileStream);
diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts
index 902d0ddda..355dd76fe 100644
--- a/editors/code/src/toolchain.ts
+++ b/editors/code/src/toolchain.ts
@@ -159,7 +159,7 @@ export const getPathForExecutable = memoize(
159 // it is not mentioned in docs and cannot be infered by the type signature... 159 // it is not mentioned in docs and cannot be infered by the type signature...
160 const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName); 160 const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName);
161 161
162 if (isFile(standardPath.path)) return standardPath.path; 162 if (isFileAtUri(standardPath)) return standardPath.fsPath;
163 } catch (err) { 163 } catch (err) {
164 log.error("Failed to read the fs info", err); 164 log.error("Failed to read the fs info", err);
165 } 165 }
@@ -177,9 +177,17 @@ function lookupInPath(exec: string): boolean {
177 : [candidate]; 177 : [candidate];
178 }); 178 });
179 179
180 return candidates.some(isFile); 180 return candidates.some(isFileAtPath);
181} 181}
182 182
183async function isFile(path: string): Promise<boolean> { 183async function isFileAtPath(path: string): Promise<boolean> {
184 return ((await vscode.workspace.fs.stat(vscode.Uri.file(path))).type & vscode.FileType.File) !== 0; 184 return isFileAtUri(vscode.Uri.file(path));
185}
186
187async function isFileAtUri(uri: vscode.Uri): Promise<boolean> {
188 try {
189 return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0;
190 } catch {
191 return false;
192 }
185} 193}
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 3a67294c5..c7363688a 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -45,8 +45,8 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
45 patch 45 patch
46 .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) 46 .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
47 .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)) 47 .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
48 .replace(r#""$generated-start": false,"#, "") 48 .replace(r#""$generated-start": {},"#, "")
49 .replace(",\n \"$generated-end\": false", ""); 49 .replace(",\n \"$generated-end\": {}", "");
50 50
51 if nightly { 51 if nightly {
52 patch.replace( 52 patch.replace(
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 7e2dccdfe..64ab12b42 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -8,7 +8,7 @@ use xshell::{cmd, pushd};
8use crate::flags; 8use crate::flags;
9 9
10// Latest stable, feel free to send a PR if this lags behind. 10// Latest stable, feel free to send a PR if this lags behind.
11const REQUIRED_RUST_VERSION: u32 = 52; 11const REQUIRED_RUST_VERSION: u32 = 53;
12 12
13impl flags::Install { 13impl flags::Install {
14 pub(crate) fn run(self) -> Result<()> { 14 pub(crate) fn run(self) -> Result<()> {
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index f2ba8efef..a9d434e20 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -89,6 +89,7 @@ fn rust_files_are_tidy() {
89 let text = read_file(&path).unwrap(); 89 let text = read_file(&path).unwrap();
90 check_todo(&path, &text); 90 check_todo(&path, &text);
91 check_dbg(&path, &text); 91 check_dbg(&path, &text);
92 check_test_attrs(&path, &text);
92 check_trailing_ws(&path, &text); 93 check_trailing_ws(&path, &text);
93 deny_clippy(&path, &text); 94 deny_clippy(&path, &text);
94 tidy_docs.visit(&path, &text); 95 tidy_docs.visit(&path, &text);
@@ -334,13 +335,43 @@ fn check_dbg(path: &Path, text: &str) {
334 } 335 }
335} 336}
336 337
338fn check_test_attrs(path: &Path, text: &str) {
339 let ignore_rule =
340 "https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/style.md#ignore";
341 let need_ignore: &[&str] = &[
342 // Special case to run `#[ignore]` tests
343 "ide/src/runnables.rs",
344 // A legit test which needs to be ignored, as it takes too long to run
345 // :(
346 "hir_def/src/nameres/collector.rs",
347 // Obviously needs ignore.
348 "ide_assists/src/handlers/toggle_ignore.rs",
349 // See above.
350 "ide_assists/src/tests/generated.rs",
351 ];
352 if text.contains("#[ignore") && !need_ignore.iter().any(|p| path.ends_with(p)) {
353 panic!("\ndon't `#[ignore]` tests, see:\n\n {}\n\n {}\n", ignore_rule, path.display(),)
354 }
355
356 let panic_rule =
357 "https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/style.md#should_panic";
358 let need_panic: &[&str] = &["test_utils/src/fixture.rs"];
359 if text.contains("#[should_panic") && !need_panic.iter().any(|p| path.ends_with(p)) {
360 panic!(
361 "\ndon't add `#[should_panic]` tests, see:\n\n {}\n\n {}\n",
362 panic_rule,
363 path.display(),
364 )
365 }
366}
367
337fn check_trailing_ws(path: &Path, text: &str) { 368fn check_trailing_ws(path: &Path, text: &str) {
338 if is_exclude_dir(path, &["test_data"]) { 369 if is_exclude_dir(path, &["test_data"]) {
339 return; 370 return;
340 } 371 }
341 for (line_number, line) in text.lines().enumerate() { 372 for (line_number, line) in text.lines().enumerate() {
342 if line.chars().last().map(char::is_whitespace) == Some(true) { 373 if line.chars().last().map(char::is_whitespace) == Some(true) {
343 panic!("Trailing whitespace in {} at line {}", path.display(), line_number) 374 panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1)
344 } 375 }
345 } 376 }
346} 377}