aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/actions/github-release/main.js1
-rw-r--r--.github/workflows/release.yaml6
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock244
-rw-r--r--crates/assists/Cargo.toml1
-rw-r--r--crates/assists/src/assist_context.rs2
-rw-r--r--crates/assists/src/handlers/add_missing_impl_members.rs3
-rw-r--r--crates/assists/src/handlers/auto_import.rs4
-rw-r--r--crates/assists/src/handlers/change_visibility.rs18
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/assists/src/handlers/fill_match_arms.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs8
-rw-r--r--crates/assists/src/handlers/generate_from_impl_for_enum.rs2
-rw-r--r--crates/assists/src/handlers/generate_function.rs2
-rw-r--r--crates/assists/src/handlers/generate_impl.rs42
-rw-r--r--crates/assists/src/handlers/move_guard.rs87
-rw-r--r--crates/assists/src/handlers/qualify_path.rs1048
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs87
-rw-r--r--crates/assists/src/handlers/replace_if_let_with_match.rs6
-rw-r--r--crates/assists/src/handlers/replace_let_with_if_let.rs3
-rw-r--r--crates/assists/src/handlers/replace_string_with_char.rs141
-rw-r--r--crates/assists/src/handlers/replace_unwrap_with_match.rs3
-rw-r--r--crates/assists/src/lib.rs9
-rw-r--r--crates/assists/src/tests.rs2
-rw-r--r--crates/assists/src/tests/generated.rs36
-rw-r--r--crates/assists/src/utils.rs146
-rw-r--r--crates/assists/src/utils/import_assets.rs40
-rw-r--r--crates/assists/src/utils/insert_use.rs166
-rw-r--r--crates/base_db/src/fixture.rs4
-rw-r--r--crates/base_db/src/input.rs76
-rw-r--r--crates/base_db/src/lib.rs4
-rw-r--r--crates/cfg/Cargo.toml1
-rw-r--r--crates/cfg/src/cfg_expr.rs113
-rw-r--r--crates/cfg/src/dnf.rs320
-rw-r--r--crates/cfg/src/lib.rs130
-rw-r--r--crates/cfg/src/tests.rs193
-rw-r--r--crates/completion/Cargo.toml30
-rw-r--r--crates/completion/src/completions.rs (renamed from crates/ide/src/completion/presentation.rs)228
-rw-r--r--crates/completion/src/completions/attribute.rs (renamed from crates/ide/src/completion/complete_attribute.rs)185
-rw-r--r--crates/completion/src/completions/dot.rs (renamed from crates/ide/src/completion/complete_dot.rs)27
-rw-r--r--crates/completion/src/completions/fn_param.rs (renamed from crates/ide/src/completion/complete_fn_param.rs)6
-rw-r--r--crates/completion/src/completions/keyword.rs (renamed from crates/ide/src/completion/complete_keyword.rs)12
-rw-r--r--crates/completion/src/completions/macro_in_item_position.rs (renamed from crates/ide/src/completion/complete_macro_in_item_position.rs)8
-rw-r--r--crates/completion/src/completions/mod_.rs (renamed from crates/ide/src/completion/complete_mod.rs)18
-rw-r--r--crates/completion/src/completions/pattern.rs (renamed from crates/ide/src/completion/complete_pattern.rs)8
-rw-r--r--crates/completion/src/completions/postfix.rs (renamed from crates/ide/src/completion/complete_postfix.rs)18
-rw-r--r--crates/completion/src/completions/postfix/format_like.rs (renamed from crates/ide/src/completion/complete_postfix/format_like.rs)10
-rw-r--r--crates/completion/src/completions/qualified_path.rs (renamed from crates/ide/src/completion/complete_qualified_path.rs)18
-rw-r--r--crates/completion/src/completions/record.rs (renamed from crates/ide/src/completion/complete_record.rs)6
-rw-r--r--crates/completion/src/completions/snippet.rs (renamed from crates/ide/src/completion/complete_snippet.rs)14
-rw-r--r--crates/completion/src/completions/trait_impl.rs (renamed from crates/ide/src/completion/complete_trait_impl.rs)15
-rw-r--r--crates/completion/src/completions/unqualified_path.rs (renamed from crates/ide/src/completion/complete_unqualified_path.rs)6
-rw-r--r--crates/completion/src/config.rs (renamed from crates/ide/src/completion/completion_config.rs)0
-rw-r--r--crates/completion/src/context.rs (renamed from crates/ide/src/completion/completion_context.rs)54
-rw-r--r--crates/completion/src/generated_lint_completions.rs5
-rw-r--r--crates/completion/src/item.rs (renamed from crates/ide/src/completion/completion_item.rs)54
-rw-r--r--crates/completion/src/lib.rs (renamed from crates/ide/src/completion.rs)133
-rw-r--r--crates/completion/src/patterns.rs (renamed from crates/ide/src/completion/patterns.rs)48
-rw-r--r--crates/completion/src/test_utils.rs (renamed from crates/ide/src/completion/test_utils.rs)72
-rw-r--r--crates/flycheck/Cargo.toml2
-rw-r--r--crates/hir/src/code_model.rs32
-rw-r--r--crates/hir/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/attr.rs14
-rw-r--r--crates/hir_def/src/body.rs69
-rw-r--r--crates/hir_def/src/body/diagnostics.rs20
-rw-r--r--crates/hir_def/src/body/lower.rs60
-rw-r--r--crates/hir_def/src/body/tests.rs75
-rw-r--r--crates/hir_def/src/diagnostics.rs54
-rw-r--r--crates/hir_def/src/import_map.rs6
-rw-r--r--crates/hir_def/src/item_tree.rs18
-rw-r--r--crates/hir_def/src/item_tree/lower.rs47
-rw-r--r--crates/hir_def/src/nameres.rs29
-rw-r--r--crates/hir_def/src/nameres/collector.rs37
-rw-r--r--crates/hir_def/src/nameres/tests.rs17
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs56
-rw-r--r--crates/hir_def/src/test_db.rs44
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_expand/src/name.rs36
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/diagnostics.rs55
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs28
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/case_conv.rs244
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs18
-rw-r--r--crates/hir_ty/src/traits.rs30
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs17
-rw-r--r--crates/ide/Cargo.toml4
-rw-r--r--crates/ide/src/call_hierarchy.rs6
-rw-r--r--crates/ide/src/completion/generated_features.rs4
-rw-r--r--crates/ide/src/diagnostics.rs93
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs34
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/display.rs81
-rw-r--r--crates/ide/src/display/navigation_target.rs2
-rw-r--r--crates/ide/src/doc_links.rs36
-rw-r--r--crates/ide/src/fixture.rs2
-rw-r--r--crates/ide/src/goto_definition.rs2
-rw-r--r--crates/ide/src/goto_implementation.rs2
-rw-r--r--crates/ide/src/goto_type_definition.rs2
-rw-r--r--crates/ide/src/hover.rs37
-rw-r--r--crates/ide/src/inlay_hints.rs53
-rw-r--r--crates/ide/src/lib.rs20
-rw-r--r--crates/ide/src/parent_module.rs2
-rw-r--r--crates/ide/src/prime_caches.rs5
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/references/rename.rs2
-rw-r--r--crates/ide/src/runnables.rs84
-rw-r--r--crates/ide/src/status.rs8
-rw-r--r--crates/ide/src/syntax_highlighting.rs12
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs6
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html22
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs22
-rw-r--r--crates/ide/src/syntax_tree.rs2
-rw-r--r--crates/ide/src/typing.rs2
-rw-r--r--crates/ide/src/typing/on_enter.rs2
-rw-r--r--crates/ide_db/Cargo.toml5
-rw-r--r--crates/ide_db/src/call_info.rs (renamed from crates/ide/src/call_info.rs)48
-rw-r--r--crates/ide_db/src/lib.rs6
-rw-r--r--crates/ide_db/src/traits.rs227
-rw-r--r--crates/ide_db/src/ty_filter.rs58
-rw-r--r--crates/parser/src/grammar.rs6
-rw-r--r--crates/proc_macro_srv/Cargo.toml2
-rw-r--r--crates/project_model/Cargo.toml2
-rw-r--r--crates/project_model/src/lib.rs16
-rw-r--r--crates/project_model/src/project_json.rs7
-rw-r--r--crates/rust-analyzer/Cargo.toml10
-rw-r--r--crates/rust-analyzer/src/bin/main.rs22
-rw-r--r--crates/rust-analyzer/src/caps.rs3
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs10
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs8
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs8
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs10
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs2
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs10
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt4
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs4
-rw-r--r--crates/rust-analyzer/src/dispatch.rs6
-rw-r--r--crates/rust-analyzer/src/from_proto.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs18
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs8
-rw-r--r--crates/rust-analyzer/src/reload.rs2
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs87
-rw-r--r--crates/ssr/Cargo.toml1
-rw-r--r--crates/ssr/src/lib.rs8
-rw-r--r--crates/ssr/src/matching.rs2
-rw-r--r--crates/ssr/src/resolving.rs2
-rw-r--r--crates/ssr/src/search.rs4
-rw-r--r--crates/ssr/src/tests.rs6
-rw-r--r--crates/stdx/src/panic_context.rs4
-rw-r--r--crates/syntax/Cargo.toml6
-rw-r--r--crates/syntax/src/algo.rs582
-rw-r--r--crates/syntax/src/ast/make.rs3
-rw-r--r--crates/syntax/src/ast/node_ext.rs14
-rw-r--r--crates/syntax/src/display.rs83
-rw-r--r--crates/syntax/src/lib.rs1
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rast54
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0153_pub_parens_typepath.rs2
-rw-r--r--crates/test_utils/src/lib.rs6
-rw-r--r--docs/dev/debugging.md2
-rw-r--r--docs/user/generated_diagnostic.adoc105
-rw-r--r--docs/user/manual.adoc11
-rw-r--r--editors/code/package-lock.json30
-rw-r--r--editors/code/package.json6
-rw-r--r--editors/code/rust.tmGrammar.json120
-rw-r--r--editors/code/src/run.ts4
-rw-r--r--editors/code/src/util.ts5
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/codegen.rs28
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs4
-rw-r--r--xtask/src/codegen/gen_diagnostic_docs.rs74
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs4
-rw-r--r--xtask/src/codegen/gen_features.rs10
-rw-r--r--xtask/src/codegen/gen_lint_completions.rs113
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs2
-rw-r--r--xtask/src/dist.rs33
-rw-r--r--xtask/src/install.rs91
-rw-r--r--xtask/src/lib.rs52
-rw-r--r--xtask/src/main.rs23
-rw-r--r--xtask/src/metrics.rs39
-rw-r--r--xtask/src/not_bash.rs169
-rw-r--r--xtask/src/pre_cache.rs5
-rw-r--r--xtask/src/pre_commit.rs8
-rw-r--r--xtask/src/release.rs71
-rw-r--r--xtask/tests/tidy.rs47
198 files changed, 6076 insertions, 1879 deletions
diff --git a/.github/actions/github-release/main.js b/.github/actions/github-release/main.js
index b499cd0fd..a08e59a91 100644
--- a/.github/actions/github-release/main.js
+++ b/.github/actions/github-release/main.js
@@ -70,6 +70,7 @@ async function runOnce() {
70 repo, 70 repo,
71 name, 71 name,
72 tag_name: name, 72 tag_name: name,
73 target_commitish: sha,
73 prerelease: name === 'nightly', 74 prerelease: name === 'nightly',
74 }); 75 });
75 76
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 1ae8ed1b6..c1d56a8e0 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -79,16 +79,16 @@ jobs:
79 with: 79 with:
80 node-version: 12.x 80 node-version: 12.x
81 81
82 - run: echo "::set-env name=TAG::$(date --iso --utc)" 82 - run: echo "TAG=$(date --iso --utc)" >> $GITHUB_ENV
83 if: github.ref == 'refs/heads/release' 83 if: github.ref == 'refs/heads/release'
84 - run: echo "::set-env name=TAG::nightly" 84 - run: echo "TAG=nightly" >> $GITHUB_ENV
85 if: github.ref != 'refs/heads/release' 85 if: github.ref != 'refs/heads/release'
86 - run: 'echo "TAG: $TAG"' 86 - run: 'echo "TAG: $TAG"'
87 87
88 - name: Checkout repository 88 - name: Checkout repository
89 uses: actions/checkout@v2 89 uses: actions/checkout@v2
90 90
91 - run: echo "::set-env name=HEAD_SHA::$(git rev-parse HEAD)" 91 - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
92 - run: 'echo "HEAD_SHA: $HEAD_SHA"' 92 - run: 'echo "HEAD_SHA: $HEAD_SHA"'
93 93
94 - uses: actions/download-artifact@v1 94 - uses: actions/download-artifact@v1
diff --git a/.gitignore b/.gitignore
index 472fe1a13..b205bf3fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ crates/*/target
9.vscode/settings.json 9.vscode/settings.json
10generated_assists.adoc 10generated_assists.adoc
11generated_features.adoc 11generated_features.adoc
12generated_diagnostic.adoc
diff --git a/Cargo.lock b/Cargo.lock
index d470d84f2..fe211b9b3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -42,15 +42,14 @@ version = "0.0.0"
42 42
43[[package]] 43[[package]]
44name = "arrayvec" 44name = "arrayvec"
45version = "0.5.1" 45version = "0.5.2"
46source = "registry+https://github.com/rust-lang/crates.io-index" 46source = "registry+https://github.com/rust-lang/crates.io-index"
47checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 47checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
48 48
49[[package]] 49[[package]]
50name = "assists" 50name = "assists"
51version = "0.0.0" 51version = "0.0.0"
52dependencies = [ 52dependencies = [
53 "base_db",
54 "either", 53 "either",
55 "hir", 54 "hir",
56 "ide_db", 55 "ide_db",
@@ -129,11 +128,11 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
129 128
130[[package]] 129[[package]]
131name = "cargo_metadata" 130name = "cargo_metadata"
132version = "0.11.4" 131version = "0.12.0"
133source = "registry+https://github.com/rust-lang/crates.io-index" 132source = "registry+https://github.com/rust-lang/crates.io-index"
134checksum = "a3a567c24b86754d629addc2db89e340ac9398d07b5875efcff837e3878e17ec" 133checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
135dependencies = [ 134dependencies = [
136 "semver", 135 "semver 0.11.0",
137 "serde", 136 "serde",
138 "serde_json", 137 "serde_json",
139] 138]
@@ -148,6 +147,7 @@ checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d"
148name = "cfg" 147name = "cfg"
149version = "0.0.0" 148version = "0.0.0"
150dependencies = [ 149dependencies = [
150 "expect-test",
151 "mbe", 151 "mbe",
152 "rustc-hash", 152 "rustc-hash",
153 "syntax", 153 "syntax",
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
168 168
169[[package]] 169[[package]]
170name = "chalk-derive" 170name = "chalk-derive"
171version = "0.33.0" 171version = "0.34.0"
172source = "registry+https://github.com/rust-lang/crates.io-index" 172source = "registry+https://github.com/rust-lang/crates.io-index"
173checksum = "569014cab9084a6b826fe2507cc6d08f7897ba144fb1bc74e71b593dc8a0b952" 173checksum = "0e9f986750ecb4df889d0a95d4586bd921889497b33908cc75bb80eadb4c600a"
174dependencies = [ 174dependencies = [
175 "proc-macro2", 175 "proc-macro2",
176 "quote", 176 "quote",
@@ -180,9 +180,9 @@ dependencies = [
180 180
181[[package]] 181[[package]]
182name = "chalk-ir" 182name = "chalk-ir"
183version = "0.33.0" 183version = "0.34.0"
184source = "registry+https://github.com/rust-lang/crates.io-index" 184source = "registry+https://github.com/rust-lang/crates.io-index"
185checksum = "8d9eab2a6590b696419f89c9ca3616fe8e8266ef676e6a6da8818c94963c9541" 185checksum = "5c352c4649f1408bb3de5d86a248fda78d3d9cd1cbbd9502e7eca1be1e7ac368"
186dependencies = [ 186dependencies = [
187 "chalk-derive", 187 "chalk-derive",
188 "lazy_static", 188 "lazy_static",
@@ -190,9 +190,9 @@ dependencies = [
190 190
191[[package]] 191[[package]]
192name = "chalk-recursive" 192name = "chalk-recursive"
193version = "0.33.0" 193version = "0.34.0"
194source = "registry+https://github.com/rust-lang/crates.io-index" 194source = "registry+https://github.com/rust-lang/crates.io-index"
195checksum = "4a4671bcc70aa2d7e12ff4fe03f91d0c3c9ce387de915915e57fdf0c91dc5abd" 195checksum = "7294bb2ac5446fcb83ec9524b9113f59a8913f174a9c1dea6db60532f17a1579"
196dependencies = [ 196dependencies = [
197 "chalk-derive", 197 "chalk-derive",
198 "chalk-ir", 198 "chalk-ir",
@@ -203,9 +203,9 @@ dependencies = [
203 203
204[[package]] 204[[package]]
205name = "chalk-solve" 205name = "chalk-solve"
206version = "0.33.0" 206version = "0.34.0"
207source = "registry+https://github.com/rust-lang/crates.io-index" 207source = "registry+https://github.com/rust-lang/crates.io-index"
208checksum = "45f75cc603f2fd302576c8b2976437f334e159e26d0afbb108a565b96c52184e" 208checksum = "ffbca06963ed6f3d22faed840847a685f02feefa3825c0b94f9b791d03a0ac6f"
209dependencies = [ 209dependencies = [
210 "chalk-derive", 210 "chalk-derive",
211 "chalk-ir", 211 "chalk-ir",
@@ -250,6 +250,24 @@ dependencies = [
250] 250]
251 251
252[[package]] 252[[package]]
253name = "completion"
254version = "0.0.0"
255dependencies = [
256 "base_db",
257 "expect-test",
258 "hir",
259 "ide_db",
260 "itertools",
261 "log",
262 "profile",
263 "rustc-hash",
264 "stdx",
265 "syntax",
266 "test_utils",
267 "text_edit",
268]
269
270[[package]]
253name = "const_fn" 271name = "const_fn"
254version = "0.4.2" 272version = "0.4.2"
255source = "registry+https://github.com/rust-lang/crates.io-index" 273source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -257,11 +275,11 @@ checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2"
257 275
258[[package]] 276[[package]]
259name = "crc32fast" 277name = "crc32fast"
260version = "1.2.0" 278version = "1.2.1"
261source = "registry+https://github.com/rust-lang/crates.io-index" 279source = "registry+https://github.com/rust-lang/crates.io-index"
262checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 280checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
263dependencies = [ 281dependencies = [
264 "cfg-if 0.1.10", 282 "cfg-if 1.0.0",
265] 283]
266 284
267[[package]] 285[[package]]
@@ -286,26 +304,25 @@ dependencies = [
286 304
287[[package]] 305[[package]]
288name = "crossbeam-deque" 306name = "crossbeam-deque"
289version = "0.7.3" 307version = "0.8.0"
290source = "registry+https://github.com/rust-lang/crates.io-index" 308source = "registry+https://github.com/rust-lang/crates.io-index"
291checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" 309checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
292dependencies = [ 310dependencies = [
311 "cfg-if 1.0.0",
293 "crossbeam-epoch", 312 "crossbeam-epoch",
294 "crossbeam-utils 0.7.2", 313 "crossbeam-utils 0.8.0",
295 "maybe-uninit",
296] 314]
297 315
298[[package]] 316[[package]]
299name = "crossbeam-epoch" 317name = "crossbeam-epoch"
300version = "0.8.2" 318version = "0.9.0"
301source = "registry+https://github.com/rust-lang/crates.io-index" 319source = "registry+https://github.com/rust-lang/crates.io-index"
302checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 320checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
303dependencies = [ 321dependencies = [
304 "autocfg", 322 "cfg-if 1.0.0",
305 "cfg-if 0.1.10", 323 "const_fn",
306 "crossbeam-utils 0.7.2", 324 "crossbeam-utils 0.8.0",
307 "lazy_static", 325 "lazy_static",
308 "maybe-uninit",
309 "memoffset", 326 "memoffset",
310 "scopeguard", 327 "scopeguard",
311] 328]
@@ -362,9 +379,9 @@ dependencies = [
362 379
363[[package]] 380[[package]]
364name = "env_logger" 381name = "env_logger"
365version = "0.7.1" 382version = "0.8.1"
366source = "registry+https://github.com/rust-lang/crates.io-index" 383source = "registry+https://github.com/rust-lang/crates.io-index"
367checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 384checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
368dependencies = [ 385dependencies = [
369 "log", 386 "log",
370] 387]
@@ -422,12 +439,6 @@ dependencies = [
422] 439]
423 440
424[[package]] 441[[package]]
425name = "fs-err"
426version = "2.5.0"
427source = "registry+https://github.com/rust-lang/crates.io-index"
428checksum = "bcd1163ae48bda72a20ae26d66a04d3094135cadab911cff418ae5e33f253431"
429
430[[package]]
431name = "fsevent" 442name = "fsevent"
432version = "2.0.2" 443version = "2.0.2"
433source = "registry+https://github.com/rust-lang/crates.io-index" 444source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -469,6 +480,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
469checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 480checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
470 481
471[[package]] 482[[package]]
483name = "generator"
484version = "0.6.23"
485source = "registry+https://github.com/rust-lang/crates.io-index"
486checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc"
487dependencies = [
488 "cc",
489 "libc",
490 "log",
491 "rustc_version",
492 "winapi 0.3.9",
493]
494
495[[package]]
472name = "gimli" 496name = "gimli"
473version = "0.22.0" 497version = "0.22.0"
474source = "registry+https://github.com/rust-lang/crates.io-index" 498source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -614,8 +638,8 @@ name = "ide"
614version = "0.0.0" 638version = "0.0.0"
615dependencies = [ 639dependencies = [
616 "assists", 640 "assists",
617 "base_db",
618 "cfg", 641 "cfg",
642 "completion",
619 "either", 643 "either",
620 "expect-test", 644 "expect-test",
621 "hir", 645 "hir",
@@ -642,6 +666,7 @@ version = "0.0.0"
642dependencies = [ 666dependencies = [
643 "base_db", 667 "base_db",
644 "either", 668 "either",
669 "expect-test",
645 "fst", 670 "fst",
646 "hir", 671 "hir",
647 "log", 672 "log",
@@ -765,11 +790,11 @@ checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
765 790
766[[package]] 791[[package]]
767name = "libloading" 792name = "libloading"
768version = "0.6.4" 793version = "0.6.5"
769source = "registry+https://github.com/rust-lang/crates.io-index" 794source = "registry+https://github.com/rust-lang/crates.io-index"
770checksum = "3557c9384f7f757f6d139cd3a4c62ef4e850696c16bf27924a5538c8a09717a1" 795checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0"
771dependencies = [ 796dependencies = [
772 "cfg-if 0.1.10", 797 "cfg-if 1.0.0",
773 "winapi 0.3.9", 798 "winapi 0.3.9",
774] 799]
775 800
@@ -801,10 +826,23 @@ dependencies = [
801] 826]
802 827
803[[package]] 828[[package]]
829name = "loom"
830version = "0.3.6"
831source = "registry+https://github.com/rust-lang/crates.io-index"
832checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed"
833dependencies = [
834 "cfg-if 0.1.10",
835 "generator",
836 "scoped-tls",
837 "serde",
838 "serde_json",
839]
840
841[[package]]
804name = "lsp-server" 842name = "lsp-server"
805version = "0.4.0" 843version = "0.4.1"
806source = "registry+https://github.com/rust-lang/crates.io-index" 844source = "registry+https://github.com/rust-lang/crates.io-index"
807checksum = "ff7452ee21b8de64f10ceb4e9fee1212e1a9579cd717226613333e751676c86a" 845checksum = "9c85acaf36c53bf15da2b8b35afeea56747707261f59eb0b77229081dd72b04e"
808dependencies = [ 846dependencies = [
809 "crossbeam-channel 0.5.0", 847 "crossbeam-channel 0.5.0",
810 "log", 848 "log",
@@ -814,9 +852,9 @@ dependencies = [
814 852
815[[package]] 853[[package]]
816name = "lsp-types" 854name = "lsp-types"
817version = "0.82.0" 855version = "0.83.0"
818source = "registry+https://github.com/rust-lang/crates.io-index" 856source = "registry+https://github.com/rust-lang/crates.io-index"
819checksum = "db895abb8527cf59e3de893ab2acf52cf904faeb65e60ea6f373e11fe86464e8" 857checksum = "25e0bd4b95038f2c23bda332ba0ca684e8dda765db1f9bdb63dc4c3e01f3b456"
820dependencies = [ 858dependencies = [
821 "base64", 859 "base64",
822 "bitflags", 860 "bitflags",
@@ -1088,6 +1126,15 @@ dependencies = [
1088] 1126]
1089 1127
1090[[package]] 1128[[package]]
1129name = "pest"
1130version = "2.1.3"
1131source = "registry+https://github.com/rust-lang/crates.io-index"
1132checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
1133dependencies = [
1134 "ucd-trie",
1135]
1136
1137[[package]]
1091name = "petgraph" 1138name = "petgraph"
1092version = "0.5.1" 1139version = "0.5.1"
1093source = "registry+https://github.com/rust-lang/crates.io-index" 1140source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1105,9 +1152,9 @@ checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1"
1105 1152
1106[[package]] 1153[[package]]
1107name = "pin-project-lite" 1154name = "pin-project-lite"
1108version = "0.1.10" 1155version = "0.1.11"
1109source = "registry+https://github.com/rust-lang/crates.io-index" 1156source = "registry+https://github.com/rust-lang/crates.io-index"
1110checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" 1157checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
1111 1158
1112[[package]] 1159[[package]]
1113name = "plain" 1160name = "plain"
@@ -1220,9 +1267,9 @@ dependencies = [
1220 1267
1221[[package]] 1268[[package]]
1222name = "rayon" 1269name = "rayon"
1223version = "1.4.1" 1270version = "1.5.0"
1224source = "registry+https://github.com/rust-lang/crates.io-index" 1271source = "registry+https://github.com/rust-lang/crates.io-index"
1225checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032" 1272checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
1226dependencies = [ 1273dependencies = [
1227 "autocfg", 1274 "autocfg",
1228 "crossbeam-deque", 1275 "crossbeam-deque",
@@ -1232,13 +1279,13 @@ dependencies = [
1232 1279
1233[[package]] 1280[[package]]
1234name = "rayon-core" 1281name = "rayon-core"
1235version = "1.8.1" 1282version = "1.9.0"
1236source = "registry+https://github.com/rust-lang/crates.io-index" 1283source = "registry+https://github.com/rust-lang/crates.io-index"
1237checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" 1284checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
1238dependencies = [ 1285dependencies = [
1239 "crossbeam-channel 0.4.4", 1286 "crossbeam-channel 0.5.0",
1240 "crossbeam-deque", 1287 "crossbeam-deque",
1241 "crossbeam-utils 0.7.2", 1288 "crossbeam-utils 0.8.0",
1242 "lazy_static", 1289 "lazy_static",
1243 "num_cpus", 1290 "num_cpus",
1244] 1291]
@@ -1291,7 +1338,6 @@ name = "rust-analyzer"
1291version = "0.0.0" 1338version = "0.0.0"
1292dependencies = [ 1339dependencies = [
1293 "anyhow", 1340 "anyhow",
1294 "base_db",
1295 "cfg", 1341 "cfg",
1296 "crossbeam-channel 0.5.0", 1342 "crossbeam-channel 0.5.0",
1297 "env_logger", 1343 "env_logger",
@@ -1326,6 +1372,9 @@ dependencies = [
1326 "text_edit", 1372 "text_edit",
1327 "threadpool", 1373 "threadpool",
1328 "toolchain", 1374 "toolchain",
1375 "tracing",
1376 "tracing-subscriber",
1377 "tracing-tree",
1329 "tt", 1378 "tt",
1330 "vfs", 1379 "vfs",
1331 "vfs-notify", 1380 "vfs-notify",
@@ -1334,18 +1383,18 @@ dependencies = [
1334 1383
1335[[package]] 1384[[package]]
1336name = "rustc-ap-rustc_lexer" 1385name = "rustc-ap-rustc_lexer"
1337version = "683.0.0" 1386version = "685.0.0"
1338source = "registry+https://github.com/rust-lang/crates.io-index" 1387source = "registry+https://github.com/rust-lang/crates.io-index"
1339checksum = "c0c9a47e24d4b7d74ec583d8813803b36985ee082fe7debe55f257df92d5fe50" 1388checksum = "4d6465438127d20bf9d0f5148f806c029934a74c9bce1103a42d47e81d3fe89a"
1340dependencies = [ 1389dependencies = [
1341 "unicode-xid", 1390 "unicode-xid",
1342] 1391]
1343 1392
1344[[package]] 1393[[package]]
1345name = "rustc-demangle" 1394name = "rustc-demangle"
1346version = "0.1.17" 1395version = "0.1.18"
1347source = "registry+https://github.com/rust-lang/crates.io-index" 1396source = "registry+https://github.com/rust-lang/crates.io-index"
1348checksum = "b2610b7f643d18c87dff3b489950269617e6601a51f1f05aa5daefee36f64f0b" 1397checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
1349 1398
1350[[package]] 1399[[package]]
1351name = "rustc-hash" 1400name = "rustc-hash"
@@ -1354,6 +1403,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1354checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1403checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
1355 1404
1356[[package]] 1405[[package]]
1406name = "rustc_version"
1407version = "0.2.3"
1408source = "registry+https://github.com/rust-lang/crates.io-index"
1409checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1410dependencies = [
1411 "semver 0.9.0",
1412]
1413
1414[[package]]
1357name = "ryu" 1415name = "ryu"
1358version = "1.0.5" 1416version = "1.0.5"
1359source = "registry+https://github.com/rust-lang/crates.io-index" 1417source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1420,9 +1478,9 @@ dependencies = [
1420 1478
1421[[package]] 1479[[package]]
1422name = "scroll_derive" 1480name = "scroll_derive"
1423version = "0.10.3" 1481version = "0.10.4"
1424source = "registry+https://github.com/rust-lang/crates.io-index" 1482source = "registry+https://github.com/rust-lang/crates.io-index"
1425checksum = "6dfde5d1531034db129e95c76ac857e2baecea3443579d493d02224950b0fb6d" 1483checksum = "b12bd20b94c7cdfda8c7ba9b92ad0d9a56e3fa018c25fca83b51aa664c9b4c0d"
1426dependencies = [ 1484dependencies = [
1427 "proc-macro2", 1485 "proc-macro2",
1428 "quote", 1486 "quote",
@@ -1431,11 +1489,20 @@ dependencies = [
1431 1489
1432[[package]] 1490[[package]]
1433name = "semver" 1491name = "semver"
1434version = "0.10.0" 1492version = "0.9.0"
1493source = "registry+https://github.com/rust-lang/crates.io-index"
1494checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1495dependencies = [
1496 "semver-parser 0.7.0",
1497]
1498
1499[[package]]
1500name = "semver"
1501version = "0.11.0"
1435source = "registry+https://github.com/rust-lang/crates.io-index" 1502source = "registry+https://github.com/rust-lang/crates.io-index"
1436checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" 1503checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
1437dependencies = [ 1504dependencies = [
1438 "semver-parser", 1505 "semver-parser 0.10.1",
1439 "serde", 1506 "serde",
1440] 1507]
1441 1508
@@ -1446,19 +1513,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1446checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1513checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1447 1514
1448[[package]] 1515[[package]]
1516name = "semver-parser"
1517version = "0.10.1"
1518source = "registry+https://github.com/rust-lang/crates.io-index"
1519checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428"
1520dependencies = [
1521 "pest",
1522]
1523
1524[[package]]
1449name = "serde" 1525name = "serde"
1450version = "1.0.116" 1526version = "1.0.117"
1451source = "registry+https://github.com/rust-lang/crates.io-index" 1527source = "registry+https://github.com/rust-lang/crates.io-index"
1452checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" 1528checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
1453dependencies = [ 1529dependencies = [
1454 "serde_derive", 1530 "serde_derive",
1455] 1531]
1456 1532
1457[[package]] 1533[[package]]
1458name = "serde_derive" 1534name = "serde_derive"
1459version = "1.0.116" 1535version = "1.0.117"
1460source = "registry+https://github.com/rust-lang/crates.io-index" 1536source = "registry+https://github.com/rust-lang/crates.io-index"
1461checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" 1537checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
1462dependencies = [ 1538dependencies = [
1463 "proc-macro2", 1539 "proc-macro2",
1464 "quote", 1540 "quote",
@@ -1489,11 +1565,12 @@ dependencies = [
1489 1565
1490[[package]] 1566[[package]]
1491name = "sharded-slab" 1567name = "sharded-slab"
1492version = "0.0.9" 1568version = "0.1.0"
1493source = "registry+https://github.com/rust-lang/crates.io-index" 1569source = "registry+https://github.com/rust-lang/crates.io-index"
1494checksum = "06d5a3f5166fb5b42a5439f2eee8b9de149e235961e3eb21c5808fc3ea17ff3e" 1570checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127"
1495dependencies = [ 1571dependencies = [
1496 "lazy_static", 1572 "lazy_static",
1573 "loom",
1497] 1574]
1498 1575
1499[[package]] 1576[[package]]
@@ -1521,7 +1598,6 @@ dependencies = [
1521name = "ssr" 1598name = "ssr"
1522version = "0.0.0" 1599version = "0.0.0"
1523dependencies = [ 1600dependencies = [
1524 "base_db",
1525 "expect-test", 1601 "expect-test",
1526 "hir", 1602 "hir",
1527 "ide_db", 1603 "ide_db",
@@ -1538,9 +1614,9 @@ version = "0.0.0"
1538 1614
1539[[package]] 1615[[package]]
1540name = "syn" 1616name = "syn"
1541version = "1.0.44" 1617version = "1.0.46"
1542source = "registry+https://github.com/rust-lang/crates.io-index" 1618source = "registry+https://github.com/rust-lang/crates.io-index"
1543checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" 1619checksum = "5ad5de3220ea04da322618ded2c42233d02baca219d6f160a3e9c87cda16c942"
1544dependencies = [ 1620dependencies = [
1545 "proc-macro2", 1621 "proc-macro2",
1546 "quote", 1622 "quote",
@@ -1565,6 +1641,7 @@ version = "0.0.0"
1565dependencies = [ 1641dependencies = [
1566 "arrayvec", 1642 "arrayvec",
1567 "expect-test", 1643 "expect-test",
1644 "indexmap",
1568 "itertools", 1645 "itertools",
1569 "once_cell", 1646 "once_cell",
1570 "parser", 1647 "parser",
@@ -1716,9 +1793,9 @@ dependencies = [
1716 1793
1717[[package]] 1794[[package]]
1718name = "tracing-subscriber" 1795name = "tracing-subscriber"
1719version = "0.2.13" 1796version = "0.2.14"
1720source = "registry+https://github.com/rust-lang/crates.io-index" 1797source = "registry+https://github.com/rust-lang/crates.io-index"
1721checksum = "4ef0a5e15477aa303afbfac3a44cba9b6430fdaad52423b1e6c0dbbe28c3eedd" 1798checksum = "2810660b9d5b18895d140caba6401765749a6a162e5d0736cfc44ea50db9d79d"
1722dependencies = [ 1799dependencies = [
1723 "ansi_term", 1800 "ansi_term",
1724 "chrono", 1801 "chrono",
@@ -1759,6 +1836,12 @@ dependencies = [
1759] 1836]
1760 1837
1761[[package]] 1838[[package]]
1839name = "ucd-trie"
1840version = "0.1.3"
1841source = "registry+https://github.com/rust-lang/crates.io-index"
1842checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1843
1844[[package]]
1762name = "ungrammar" 1845name = "ungrammar"
1763version = "1.1.4" 1846version = "1.1.4"
1764source = "registry+https://github.com/rust-lang/crates.io-index" 1847source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1921,16 +2004,31 @@ dependencies = [
1921] 2004]
1922 2005
1923[[package]] 2006[[package]]
2007name = "xshell"
2008version = "0.1.6"
2009source = "registry+https://github.com/rust-lang/crates.io-index"
2010checksum = "3e9bbfccbb2233e6b0473b7870d4b0811a402e9e249a5e8394e768e5a5c9c37d"
2011dependencies = [
2012 "xshell-macros",
2013]
2014
2015[[package]]
2016name = "xshell-macros"
2017version = "0.1.6"
2018source = "registry+https://github.com/rust-lang/crates.io-index"
2019checksum = "b94f1c632d730a1704b21dc551a4c74fbed713cfa59593708f94943548206134"
2020
2021[[package]]
1924name = "xtask" 2022name = "xtask"
1925version = "0.1.0" 2023version = "0.1.0"
1926dependencies = [ 2024dependencies = [
1927 "anyhow", 2025 "anyhow",
1928 "flate2", 2026 "flate2",
1929 "fs-err",
1930 "pico-args", 2027 "pico-args",
1931 "proc-macro2", 2028 "proc-macro2",
1932 "quote", 2029 "quote",
1933 "ungrammar", 2030 "ungrammar",
1934 "walkdir", 2031 "walkdir",
1935 "write-json", 2032 "write-json",
2033 "xshell",
1936] 2034]
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index 264125651..108f656e9 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -18,7 +18,6 @@ stdx = { path = "../stdx", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" } 18syntax = { path = "../syntax", version = "0.0.0" }
19text_edit = { path = "../text_edit", version = "0.0.0" } 19text_edit = { path = "../text_edit", version = "0.0.0" }
20profile = { path = "../profile", version = "0.0.0" } 20profile = { path = "../profile", version = "0.0.0" }
21base_db = { path = "../base_db", version = "0.0.0" }
22ide_db = { path = "../ide_db", version = "0.0.0" } 21ide_db = { path = "../ide_db", version = "0.0.0" }
23hir = { path = "../hir", version = "0.0.0" } 22hir = { path = "../hir", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" } 23test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index bf520069e..d11fee196 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -3,8 +3,8 @@
3use std::mem; 3use std::mem;
4 4
5use algo::find_covering_element; 5use algo::find_covering_element;
6use base_db::{FileId, FileRange};
7use hir::Semantics; 6use hir::Semantics;
7use ide_db::base_db::{FileId, FileRange};
8use ide_db::{ 8use ide_db::{
9 label::Label, 9 label::Label,
10 source_change::{SourceChange, SourceFileEdit}, 10 source_change::{SourceChange, SourceFileEdit},
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 4c400f287..b82fb30ad 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -1,4 +1,5 @@
1use hir::HasSource; 1use hir::HasSource;
2use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
2use syntax::{ 3use syntax::{
3 ast::{ 4 ast::{
4 self, 5 self,
@@ -11,7 +12,7 @@ use syntax::{
11use crate::{ 12use crate::{
12 assist_context::{AssistContext, Assists}, 13 assist_context::{AssistContext, Assists},
13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 14 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
14 utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, 15 utils::{render_snippet, Cursor},
15 AssistId, AssistKind, 16 AssistId, AssistKind,
16}; 17};
17 18
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index 4a7059c83..e49e641b3 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -6,7 +6,7 @@ use crate::{
6 AssistContext, AssistId, AssistKind, Assists, GroupLabel, 6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
7}; 7};
8 8
9// Feature: Import Insertion 9// Feature: Auto Import
10// 10//
11// Using the `auto-import` assist it is possible to insert missing imports for unresolved items. 11// Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
12// When inserting an import it will do so in a structured manner by keeping imports grouped, 12// When inserting an import it will do so in a structured manner by keeping imports grouped,
@@ -100,7 +100,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
100 let group = import_group_message(import_assets.import_candidate()); 100 let group = import_group_message(import_assets.import_candidate());
101 let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?; 101 let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?;
102 let syntax = scope.as_syntax_node(); 102 let syntax = scope.as_syntax_node();
103 for import in proposed_imports { 103 for (import, _) in proposed_imports {
104 acc.add_group( 104 acc.add_group(
105 &group, 105 &group,
106 AssistId("auto_import", AssistKind::QuickFix), 106 AssistId("auto_import", AssistKind::QuickFix),
diff --git a/crates/assists/src/handlers/change_visibility.rs b/crates/assists/src/handlers/change_visibility.rs
index 32dc05378..22d7c95d9 100644
--- a/crates/assists/src/handlers/change_visibility.rs
+++ b/crates/assists/src/handlers/change_visibility.rs
@@ -1,7 +1,7 @@
1use syntax::{ 1use syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, VISIBILITY}, 4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY},
5 T, 5 T,
6}; 6};
7use test_utils::mark; 7use test_utils::mark;
@@ -30,13 +30,20 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let item_keyword = ctx.token_at_offset().find(|leaf| { 30 let item_keyword = ctx.token_at_offset().find(|leaf| {
31 matches!( 31 matches!(
32 leaf.kind(), 32 leaf.kind(),
33 T![const] | T![static] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] 33 T![const]
34 | T![static]
35 | T![fn]
36 | T![mod]
37 | T![struct]
38 | T![enum]
39 | T![trait]
40 | T![type]
34 ) 41 )
35 }); 42 });
36 43
37 let (offset, target) = if let Some(keyword) = item_keyword { 44 let (offset, target) = if let Some(keyword) = item_keyword {
38 let parent = keyword.parent(); 45 let parent = keyword.parent();
39 let def_kws = vec![CONST, STATIC, FN, MODULE, STRUCT, ENUM, TRAIT]; 46 let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT];
40 // Parent is not a definition, can't add visibility 47 // Parent is not a definition, can't add visibility
41 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 48 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
42 return None; 49 return None;
@@ -160,6 +167,11 @@ mod tests {
160 } 167 }
161 168
162 #[test] 169 #[test]
170 fn change_visibility_type_alias() {
171 check_assist(change_visibility, "<|>type T = ();", "pub(crate) type T = ();");
172 }
173
174 #[test]
163 fn change_visibility_handles_comment_attrs() { 175 fn change_visibility_handles_comment_attrs() {
164 check_assist( 176 check_assist(
165 change_visibility, 177 change_visibility,
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 756aa03a2..178718c5e 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::{EnumVariant, Module, ModuleDef, Name}; 1use hir::{EnumVariant, Module, ModuleDef, Name};
2use ide_db::base_db::FileId;
3use ide_db::{defs::Definition, search::Reference, RootDatabase}; 3use ide_db::{defs::Definition, search::Reference, RootDatabase};
4use itertools::Itertools; 4use itertools::Itertools;
5use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs
index 676f5ad92..eda45f5b3 100644
--- a/crates/assists/src/handlers/fill_match_arms.rs
+++ b/crates/assists/src/handlers/fill_match_arms.rs
@@ -59,7 +59,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
62 if Some(enum_def) == FamousDefs(&ctx.sema, module.krate()).core_option_Option() { 62 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() {
63 // Match `Some` variant first. 63 // Match `Some` variant first.
64 mark::hit!(option_order); 64 mark::hit!(option_order);
65 variants.reverse() 65 variants.reverse()
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index d505e9444..c86720787 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -1,9 +1,11 @@
1use base_db::FileId;
2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
3use syntax::{ast, AstNode, TextRange, TextSize}; 2use ide_db::base_db::FileId;
3use syntax::{
4 ast::{self, VisibilityOwner},
5 AstNode, TextRange, TextSize,
6};
4 7
5use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; 8use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
6use ast::VisibilityOwner;
7 9
8// FIXME: this really should be a fix for diagnostic, rather than an assist. 10// FIXME: this really should be a fix for diagnostic, rather than an assist.
9 11
diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
index 7f04b9572..674e5a175 100644
--- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs
@@ -75,7 +75,7 @@ fn existing_from_impl(
75 let enum_ = variant.parent_enum(sema.db); 75 let enum_ = variant.parent_enum(sema.db);
76 let krate = enum_.module(sema.db).krate(); 76 let krate = enum_.module(sema.db).krate();
77 77
78 let from_trait = FamousDefs(sema, krate).core_convert_From()?; 78 let from_trait = FamousDefs(sema, Some(krate)).core_convert_From()?;
79 79
80 let enum_type = enum_.ty(sema.db); 80 let enum_type = enum_.ty(sema.db);
81 81
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index d23f4293b..758188a42 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::HirDisplay; 1use hir::HirDisplay;
2use ide_db::base_db::FileId;
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4use syntax::{ 4use syntax::{
5 ast::{ 5 ast::{
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs
index 9989109b5..114974465 100644
--- a/crates/assists/src/handlers/generate_impl.rs
+++ b/crates/assists/src/handlers/generate_impl.rs
@@ -1,6 +1,6 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use stdx::format_to; 2use stdx::format_to;
3use syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner}; 3use syntax::ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner};
4 4
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 5use crate::{AssistContext, AssistId, AssistKind, Assists};
6 6
@@ -27,6 +27,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
27 let nominal = ctx.find_node_at_offset::<ast::AdtDef>()?; 27 let nominal = ctx.find_node_at_offset::<ast::AdtDef>()?;
28 let name = nominal.name()?; 28 let name = nominal.name()?;
29 let target = nominal.syntax().text_range(); 29 let target = nominal.syntax().text_range();
30
30 acc.add( 31 acc.add(
31 AssistId("generate_impl", AssistKind::Generate), 32 AssistId("generate_impl", AssistKind::Generate),
32 format!("Generate impl for `{}`", name), 33 format!("Generate impl for `{}`", name),
@@ -35,7 +36,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
35 let type_params = nominal.generic_param_list(); 36 let type_params = nominal.generic_param_list();
36 let start_offset = nominal.syntax().text_range().end(); 37 let start_offset = nominal.syntax().text_range().end();
37 let mut buf = String::new(); 38 let mut buf = String::new();
38 buf.push_str("\n\nimpl"); 39 buf.push_str("\n\n");
40 nominal
41 .attrs()
42 .filter(|attr| {
43 attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)
44 })
45 .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
46
47 buf.push_str("impl");
39 if let Some(type_params) = &type_params { 48 if let Some(type_params) = &type_params {
40 format_to!(buf, "{}", type_params.syntax()); 49 format_to!(buf, "{}", type_params.syntax());
41 } 50 }
@@ -91,6 +100,35 @@ mod tests {
91 "struct Foo<'a, T: Foo<'a>> {<|>}", 100 "struct Foo<'a, T: Foo<'a>> {<|>}",
92 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", 101 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
93 ); 102 );
103 check_assist(
104 generate_impl,
105 r#"
106 #[cfg(feature = "foo")]
107 struct Foo<'a, T: Foo<'a>> {<|>}"#,
108 r#"
109 #[cfg(feature = "foo")]
110 struct Foo<'a, T: Foo<'a>> {}
111
112 #[cfg(feature = "foo")]
113 impl<'a, T: Foo<'a>> Foo<'a, T> {
114 $0
115 }"#,
116 );
117
118 check_assist(
119 generate_impl,
120 r#"
121 #[cfg(not(feature = "foo"))]
122 struct Foo<'a, T: Foo<'a>> {<|>}"#,
123 r#"
124 #[cfg(not(feature = "foo"))]
125 struct Foo<'a, T: Foo<'a>> {}
126
127 #[cfg(not(feature = "foo"))]
128 impl<'a, T: Foo<'a>> Foo<'a, T> {
129 $0
130 }"#,
131 );
94 } 132 }
95 133
96 #[test] 134 #[test]
diff --git a/crates/assists/src/handlers/move_guard.rs b/crates/assists/src/handlers/move_guard.rs
index 452115fe6..e1855b63d 100644
--- a/crates/assists/src/handlers/move_guard.rs
+++ b/crates/assists/src/handlers/move_guard.rs
@@ -1,5 +1,5 @@
1use syntax::{ 1use syntax::{
2 ast::{edit::AstNodeEdit, make, AstNode, IfExpr, MatchArm}, 2 ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, Expr, IfExpr, MatchArm},
3 SyntaxKind::WHITESPACE, 3 SyntaxKind::WHITESPACE,
4}; 4};
5 5
@@ -92,9 +92,20 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext) ->
92pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 92pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
93 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; 93 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
94 let match_pat = match_arm.pat()?; 94 let match_pat = match_arm.pat()?;
95
96 let arm_body = match_arm.expr()?; 95 let arm_body = match_arm.expr()?;
97 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?; 96
97 let mut replace_node = None;
98 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| {
99 let block_expr = BlockExpr::cast(arm_body.syntax().clone())?;
100 if let Expr::IfExpr(e) = block_expr.expr()? {
101 replace_node = Some(block_expr.syntax().clone());
102 Some(e)
103 } else {
104 None
105 }
106 })?;
107 let replace_node = replace_node.unwrap_or_else(|| if_expr.syntax().clone());
108
98 let cond = if_expr.condition()?; 109 let cond = if_expr.condition()?;
99 let then_block = if_expr.then_branch()?; 110 let then_block = if_expr.then_branch()?;
100 111
@@ -109,19 +120,23 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex
109 120
110 let buf = format!(" if {}", cond.syntax().text()); 121 let buf = format!(" if {}", cond.syntax().text());
111 122
112 let target = if_expr.syntax().text_range();
113 acc.add( 123 acc.add(
114 AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite), 124 AssistId("move_arm_cond_to_match_guard", AssistKind::RefactorRewrite),
115 "Move condition to match guard", 125 "Move condition to match guard",
116 target, 126 replace_node.text_range(),
117 |edit| { 127 |edit| {
118 let then_only_expr = then_block.statements().next().is_none(); 128 let then_only_expr = then_block.statements().next().is_none();
119 129
120 match &then_block.expr() { 130 match &then_block.expr() {
121 Some(then_expr) if then_only_expr => { 131 Some(then_expr) if then_only_expr => {
122 edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) 132 edit.replace(replace_node.text_range(), then_expr.syntax().text())
123 } 133 }
124 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()), 134 _ if replace_node != *if_expr.syntax() => {
135 // Dedent because if_expr is in a BlockExpr
136 let replace_with = then_block.dedent(1.into()).syntax().text();
137 edit.replace(replace_node.text_range(), replace_with)
138 }
139 _ => edit.replace(replace_node.text_range(), then_block.syntax().text()),
125 } 140 }
126 141
127 edit.insert(match_pat.syntax().text_range().end(), buf); 142 edit.insert(match_pat.syntax().text_range().end(), buf);
@@ -225,6 +240,33 @@ fn main() {
225 } 240 }
226 241
227 #[test] 242 #[test]
243 fn move_arm_cond_in_block_to_match_guard_works() {
244 check_assist(
245 move_arm_cond_to_match_guard,
246 r#"
247fn main() {
248 match 92 {
249 x => {
250 <|>if x > 10 {
251 false
252 }
253 },
254 _ => true
255 }
256}
257"#,
258 r#"
259fn main() {
260 match 92 {
261 x if x > 10 => false,
262 _ => true
263 }
264}
265"#,
266 );
267 }
268
269 #[test]
228 fn move_arm_cond_to_match_guard_if_let_not_works() { 270 fn move_arm_cond_to_match_guard_if_let_not_works() {
229 check_assist_not_applicable( 271 check_assist_not_applicable(
230 move_arm_cond_to_match_guard, 272 move_arm_cond_to_match_guard,
@@ -290,4 +332,35 @@ fn main() {
290"#, 332"#,
291 ); 333 );
292 } 334 }
335
336 #[test]
337 fn move_arm_cond_in_block_to_match_guard_if_multiline_body_works() {
338 check_assist(
339 move_arm_cond_to_match_guard,
340 r#"
341fn main() {
342 match 92 {
343 x => {
344 if x > 10 {
345 92;<|>
346 false
347 }
348 }
349 _ => true
350 }
351}
352"#,
353 r#"
354fn main() {
355 match 92 {
356 x if x > 10 => {
357 92;
358 false
359 }
360 _ => true
361 }
362}
363"#,
364 )
365 }
293} 366}
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
new file mode 100644
index 000000000..f436bdbbf
--- /dev/null
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -0,0 +1,1048 @@
1use std::iter;
2
3use hir::AsName;
4use ide_db::RootDatabase;
5use syntax::{
6 ast,
7 ast::{make, ArgListOwner},
8 AstNode,
9};
10use test_utils::mark;
11
12use crate::{
13 assist_context::{AssistContext, Assists},
14 utils::import_assets::{ImportAssets, ImportCandidate},
15 utils::mod_path_to_ast,
16 AssistId, AssistKind, GroupLabel,
17};
18
19// Assist: qualify_path
20//
21// If the name is unresolved, provides all possible qualified paths for it.
22//
23// ```
24// fn main() {
25// let map = HashMap<|>::new();
26// }
27// # pub mod std { pub mod collections { pub struct HashMap { } } }
28// ```
29// ->
30// ```
31// fn main() {
32// let map = std::collections::HashMap::new();
33// }
34// # pub mod std { pub mod collections { pub struct HashMap { } } }
35// ```
36pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 let import_assets =
38 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
39 ImportAssets::for_regular_path(path_under_caret, &ctx.sema)
40 } else if let Some(method_under_caret) =
41 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
42 {
43 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
44 } else {
45 None
46 }?;
47 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
48 if proposed_imports.is_empty() {
49 return None;
50 }
51
52 let candidate = import_assets.import_candidate();
53 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
54
55 let qualify_candidate = match candidate {
56 ImportCandidate::QualifierStart(_) => {
57 mark::hit!(qualify_path_qualifier_start);
58 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
59 let segment = path.segment()?;
60 QualifyCandidate::QualifierStart(segment)
61 }
62 ImportCandidate::UnqualifiedName(_) => {
63 mark::hit!(qualify_path_unqualified_name);
64 QualifyCandidate::UnqualifiedName
65 }
66 ImportCandidate::TraitAssocItem(_) => {
67 mark::hit!(qualify_path_trait_assoc_item);
68 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
69 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
70 QualifyCandidate::TraitAssocItem(qualifier, segment)
71 }
72 ImportCandidate::TraitMethod(_) => {
73 mark::hit!(qualify_path_trait_method);
74 let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?;
75 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
76 }
77 };
78
79 let group_label = group_label(candidate);
80 for (import, item) in proposed_imports {
81 acc.add_group(
82 &group_label,
83 AssistId("qualify_path", AssistKind::QuickFix),
84 label(candidate, &import),
85 range,
86 |builder| {
87 qualify_candidate.qualify(
88 |replace_with: String| builder.replace(range, replace_with),
89 import,
90 item,
91 )
92 },
93 );
94 }
95 Some(())
96}
97
98enum QualifyCandidate<'db> {
99 QualifierStart(ast::PathSegment),
100 UnqualifiedName,
101 TraitAssocItem(ast::Path, ast::PathSegment),
102 TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
103}
104
105impl QualifyCandidate<'_> {
106 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) {
107 match self {
108 QualifyCandidate::QualifierStart(segment) => {
109 let import = mod_path_to_ast(&import);
110 replacer(format!("{}::{}", import, segment));
111 }
112 QualifyCandidate::UnqualifiedName => replacer(mod_path_to_ast(&import).to_string()),
113 QualifyCandidate::TraitAssocItem(qualifier, segment) => {
114 let import = mod_path_to_ast(&import);
115 replacer(format!("<{} as {}>::{}", qualifier, import, segment));
116 }
117 &QualifyCandidate::TraitMethod(db, ref mcall_expr) => {
118 Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
119 }
120 }
121 }
122
123 fn qualify_trait_method(
124 db: &RootDatabase,
125 mcall_expr: &ast::MethodCallExpr,
126 mut replacer: impl FnMut(String),
127 import: hir::ModPath,
128 item: hir::ItemInNs,
129 ) -> Option<()> {
130 let receiver = mcall_expr.receiver()?;
131 let trait_method_name = mcall_expr.name_ref()?;
132 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
133 let trait_ = item_as_trait(item)?;
134 let method = find_trait_method(db, trait_, &trait_method_name)?;
135 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
136 let import = mod_path_to_ast(&import);
137 let receiver = match self_access {
138 hir::Access::Shared => make::expr_ref(receiver, false),
139 hir::Access::Exclusive => make::expr_ref(receiver, true),
140 hir::Access::Owned => receiver,
141 };
142 replacer(format!(
143 "{}::{}{}",
144 import,
145 trait_method_name,
146 match arg_list.clone() {
147 Some(args) => make::arg_list(iter::once(receiver).chain(args)),
148 None => make::arg_list(iter::once(receiver)),
149 }
150 ));
151 }
152 Some(())
153 }
154}
155
156fn find_trait_method(
157 db: &RootDatabase,
158 trait_: hir::Trait,
159 trait_method_name: &ast::NameRef,
160) -> Option<hir::Function> {
161 if let Some(hir::AssocItem::Function(method)) =
162 trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
163 item.name(db).map(|name| name == trait_method_name.as_name()).unwrap_or(false)
164 })
165 {
166 Some(method)
167 } else {
168 None
169 }
170}
171
172fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> {
173 if let hir::ModuleDef::Trait(trait_) = hir::ModuleDef::from(item.as_module_def_id()?) {
174 Some(trait_)
175 } else {
176 None
177 }
178}
179
180fn group_label(candidate: &ImportCandidate) -> GroupLabel {
181 let name = match candidate {
182 ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name,
183 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name,
184 };
185 GroupLabel(format!("Qualify {}", name))
186}
187
188fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String {
189 match candidate {
190 ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import),
191 ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import),
192 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import),
193 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import),
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
200
201 use super::*;
202
203 #[test]
204 fn applicable_when_found_an_import_partial() {
205 mark::check!(qualify_path_unqualified_name);
206 check_assist(
207 qualify_path,
208 r"
209 mod std {
210 pub mod fmt {
211 pub struct Formatter;
212 }
213 }
214
215 use std::fmt;
216
217 <|>Formatter
218 ",
219 r"
220 mod std {
221 pub mod fmt {
222 pub struct Formatter;
223 }
224 }
225
226 use std::fmt;
227
228 fmt::Formatter
229 ",
230 );
231 }
232
233 #[test]
234 fn applicable_when_found_an_import() {
235 check_assist(
236 qualify_path,
237 r"
238 <|>PubStruct
239
240 pub mod PubMod {
241 pub struct PubStruct;
242 }
243 ",
244 r"
245 PubMod::PubStruct
246
247 pub mod PubMod {
248 pub struct PubStruct;
249 }
250 ",
251 );
252 }
253
254 #[test]
255 fn applicable_in_macros() {
256 check_assist(
257 qualify_path,
258 r"
259 macro_rules! foo {
260 ($i:ident) => { fn foo(a: $i) {} }
261 }
262 foo!(Pub<|>Struct);
263
264 pub mod PubMod {
265 pub struct PubStruct;
266 }
267 ",
268 r"
269 macro_rules! foo {
270 ($i:ident) => { fn foo(a: $i) {} }
271 }
272 foo!(PubMod::PubStruct);
273
274 pub mod PubMod {
275 pub struct PubStruct;
276 }
277 ",
278 );
279 }
280
281 #[test]
282 fn applicable_when_found_multiple_imports() {
283 check_assist(
284 qualify_path,
285 r"
286 PubSt<|>ruct
287
288 pub mod PubMod1 {
289 pub struct PubStruct;
290 }
291 pub mod PubMod2 {
292 pub struct PubStruct;
293 }
294 pub mod PubMod3 {
295 pub struct PubStruct;
296 }
297 ",
298 r"
299 PubMod3::PubStruct
300
301 pub mod PubMod1 {
302 pub struct PubStruct;
303 }
304 pub mod PubMod2 {
305 pub struct PubStruct;
306 }
307 pub mod PubMod3 {
308 pub struct PubStruct;
309 }
310 ",
311 );
312 }
313
314 #[test]
315 fn not_applicable_for_already_imported_types() {
316 check_assist_not_applicable(
317 qualify_path,
318 r"
319 use PubMod::PubStruct;
320
321 PubStruct<|>
322
323 pub mod PubMod {
324 pub struct PubStruct;
325 }
326 ",
327 );
328 }
329
330 #[test]
331 fn not_applicable_for_types_with_private_paths() {
332 check_assist_not_applicable(
333 qualify_path,
334 r"
335 PrivateStruct<|>
336
337 pub mod PubMod {
338 struct PrivateStruct;
339 }
340 ",
341 );
342 }
343
344 #[test]
345 fn not_applicable_when_no_imports_found() {
346 check_assist_not_applicable(
347 qualify_path,
348 "
349 PubStruct<|>",
350 );
351 }
352
353 #[test]
354 fn not_applicable_in_import_statements() {
355 check_assist_not_applicable(
356 qualify_path,
357 r"
358 use PubStruct<|>;
359
360 pub mod PubMod {
361 pub struct PubStruct;
362 }",
363 );
364 }
365
366 #[test]
367 fn qualify_function() {
368 check_assist(
369 qualify_path,
370 r"
371 test_function<|>
372
373 pub mod PubMod {
374 pub fn test_function() {};
375 }
376 ",
377 r"
378 PubMod::test_function
379
380 pub mod PubMod {
381 pub fn test_function() {};
382 }
383 ",
384 );
385 }
386
387 #[test]
388 fn qualify_macro() {
389 check_assist(
390 qualify_path,
391 r"
392//- /lib.rs crate:crate_with_macro
393#[macro_export]
394macro_rules! foo {
395 () => ()
396}
397
398//- /main.rs crate:main deps:crate_with_macro
399fn main() {
400 foo<|>
401}
402",
403 r"
404fn main() {
405 crate_with_macro::foo
406}
407",
408 );
409 }
410
411 #[test]
412 fn qualify_path_target() {
413 check_assist_target(
414 qualify_path,
415 r"
416 struct AssistInfo {
417 group_label: Option<<|>GroupLabel>,
418 }
419
420 mod m { pub struct GroupLabel; }
421 ",
422 "GroupLabel",
423 )
424 }
425
426 #[test]
427 fn not_applicable_when_path_start_is_imported() {
428 check_assist_not_applicable(
429 qualify_path,
430 r"
431 pub mod mod1 {
432 pub mod mod2 {
433 pub mod mod3 {
434 pub struct TestStruct;
435 }
436 }
437 }
438
439 use mod1::mod2;
440 fn main() {
441 mod2::mod3::TestStruct<|>
442 }
443 ",
444 );
445 }
446
447 #[test]
448 fn not_applicable_for_imported_function() {
449 check_assist_not_applicable(
450 qualify_path,
451 r"
452 pub mod test_mod {
453 pub fn test_function() {}
454 }
455
456 use test_mod::test_function;
457 fn main() {
458 test_function<|>
459 }
460 ",
461 );
462 }
463
464 #[test]
465 fn associated_struct_function() {
466 check_assist(
467 qualify_path,
468 r"
469 mod test_mod {
470 pub struct TestStruct {}
471 impl TestStruct {
472 pub fn test_function() {}
473 }
474 }
475
476 fn main() {
477 TestStruct::test_function<|>
478 }
479 ",
480 r"
481 mod test_mod {
482 pub struct TestStruct {}
483 impl TestStruct {
484 pub fn test_function() {}
485 }
486 }
487
488 fn main() {
489 test_mod::TestStruct::test_function
490 }
491 ",
492 );
493 }
494
495 #[test]
496 fn associated_struct_const() {
497 mark::check!(qualify_path_qualifier_start);
498 check_assist(
499 qualify_path,
500 r"
501 mod test_mod {
502 pub struct TestStruct {}
503 impl TestStruct {
504 const TEST_CONST: u8 = 42;
505 }
506 }
507
508 fn main() {
509 TestStruct::TEST_CONST<|>
510 }
511 ",
512 r"
513 mod test_mod {
514 pub struct TestStruct {}
515 impl TestStruct {
516 const TEST_CONST: u8 = 42;
517 }
518 }
519
520 fn main() {
521 test_mod::TestStruct::TEST_CONST
522 }
523 ",
524 );
525 }
526
527 #[test]
528 fn associated_trait_function() {
529 check_assist(
530 qualify_path,
531 r"
532 mod test_mod {
533 pub trait TestTrait {
534 fn test_function();
535 }
536 pub struct TestStruct {}
537 impl TestTrait for TestStruct {
538 fn test_function() {}
539 }
540 }
541
542 fn main() {
543 test_mod::TestStruct::test_function<|>
544 }
545 ",
546 r"
547 mod test_mod {
548 pub trait TestTrait {
549 fn test_function();
550 }
551 pub struct TestStruct {}
552 impl TestTrait for TestStruct {
553 fn test_function() {}
554 }
555 }
556
557 fn main() {
558 <test_mod::TestStruct as test_mod::TestTrait>::test_function
559 }
560 ",
561 );
562 }
563
564 #[test]
565 fn not_applicable_for_imported_trait_for_function() {
566 check_assist_not_applicable(
567 qualify_path,
568 r"
569 mod test_mod {
570 pub trait TestTrait {
571 fn test_function();
572 }
573 pub trait TestTrait2 {
574 fn test_function();
575 }
576 pub enum TestEnum {
577 One,
578 Two,
579 }
580 impl TestTrait2 for TestEnum {
581 fn test_function() {}
582 }
583 impl TestTrait for TestEnum {
584 fn test_function() {}
585 }
586 }
587
588 use test_mod::TestTrait2;
589 fn main() {
590 test_mod::TestEnum::test_function<|>;
591 }
592 ",
593 )
594 }
595
596 #[test]
597 fn associated_trait_const() {
598 mark::check!(qualify_path_trait_assoc_item);
599 check_assist(
600 qualify_path,
601 r"
602 mod test_mod {
603 pub trait TestTrait {
604 const TEST_CONST: u8;
605 }
606 pub struct TestStruct {}
607 impl TestTrait for TestStruct {
608 const TEST_CONST: u8 = 42;
609 }
610 }
611
612 fn main() {
613 test_mod::TestStruct::TEST_CONST<|>
614 }
615 ",
616 r"
617 mod test_mod {
618 pub trait TestTrait {
619 const TEST_CONST: u8;
620 }
621 pub struct TestStruct {}
622 impl TestTrait for TestStruct {
623 const TEST_CONST: u8 = 42;
624 }
625 }
626
627 fn main() {
628 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
629 }
630 ",
631 );
632 }
633
634 #[test]
635 fn not_applicable_for_imported_trait_for_const() {
636 check_assist_not_applicable(
637 qualify_path,
638 r"
639 mod test_mod {
640 pub trait TestTrait {
641 const TEST_CONST: u8;
642 }
643 pub trait TestTrait2 {
644 const TEST_CONST: f64;
645 }
646 pub enum TestEnum {
647 One,
648 Two,
649 }
650 impl TestTrait2 for TestEnum {
651 const TEST_CONST: f64 = 42.0;
652 }
653 impl TestTrait for TestEnum {
654 const TEST_CONST: u8 = 42;
655 }
656 }
657
658 use test_mod::TestTrait2;
659 fn main() {
660 test_mod::TestEnum::TEST_CONST<|>;
661 }
662 ",
663 )
664 }
665
666 #[test]
667 fn trait_method() {
668 mark::check!(qualify_path_trait_method);
669 check_assist(
670 qualify_path,
671 r"
672 mod test_mod {
673 pub trait TestTrait {
674 fn test_method(&self);
675 }
676 pub struct TestStruct {}
677 impl TestTrait for TestStruct {
678 fn test_method(&self) {}
679 }
680 }
681
682 fn main() {
683 let test_struct = test_mod::TestStruct {};
684 test_struct.test_meth<|>od()
685 }
686 ",
687 r"
688 mod test_mod {
689 pub trait TestTrait {
690 fn test_method(&self);
691 }
692 pub struct TestStruct {}
693 impl TestTrait for TestStruct {
694 fn test_method(&self) {}
695 }
696 }
697
698 fn main() {
699 let test_struct = test_mod::TestStruct {};
700 test_mod::TestTrait::test_method(&test_struct)
701 }
702 ",
703 );
704 }
705
706 #[test]
707 fn trait_method_multi_params() {
708 check_assist(
709 qualify_path,
710 r"
711 mod test_mod {
712 pub trait TestTrait {
713 fn test_method(&self, test: i32);
714 }
715 pub struct TestStruct {}
716 impl TestTrait for TestStruct {
717 fn test_method(&self, test: i32) {}
718 }
719 }
720
721 fn main() {
722 let test_struct = test_mod::TestStruct {};
723 test_struct.test_meth<|>od(42)
724 }
725 ",
726 r"
727 mod test_mod {
728 pub trait TestTrait {
729 fn test_method(&self, test: i32);
730 }
731 pub struct TestStruct {}
732 impl TestTrait for TestStruct {
733 fn test_method(&self, test: i32) {}
734 }
735 }
736
737 fn main() {
738 let test_struct = test_mod::TestStruct {};
739 test_mod::TestTrait::test_method(&test_struct, 42)
740 }
741 ",
742 );
743 }
744
745 #[test]
746 fn trait_method_consume() {
747 check_assist(
748 qualify_path,
749 r"
750 mod test_mod {
751 pub trait TestTrait {
752 fn test_method(self);
753 }
754 pub struct TestStruct {}
755 impl TestTrait for TestStruct {
756 fn test_method(self) {}
757 }
758 }
759
760 fn main() {
761 let test_struct = test_mod::TestStruct {};
762 test_struct.test_meth<|>od()
763 }
764 ",
765 r"
766 mod test_mod {
767 pub trait TestTrait {
768 fn test_method(self);
769 }
770 pub struct TestStruct {}
771 impl TestTrait for TestStruct {
772 fn test_method(self) {}
773 }
774 }
775
776 fn main() {
777 let test_struct = test_mod::TestStruct {};
778 test_mod::TestTrait::test_method(test_struct)
779 }
780 ",
781 );
782 }
783
784 #[test]
785 fn trait_method_cross_crate() {
786 check_assist(
787 qualify_path,
788 r"
789 //- /main.rs crate:main deps:dep
790 fn main() {
791 let test_struct = dep::test_mod::TestStruct {};
792 test_struct.test_meth<|>od()
793 }
794 //- /dep.rs crate:dep
795 pub mod test_mod {
796 pub trait TestTrait {
797 fn test_method(&self);
798 }
799 pub struct TestStruct {}
800 impl TestTrait for TestStruct {
801 fn test_method(&self) {}
802 }
803 }
804 ",
805 r"
806 fn main() {
807 let test_struct = dep::test_mod::TestStruct {};
808 dep::test_mod::TestTrait::test_method(&test_struct)
809 }
810 ",
811 );
812 }
813
814 #[test]
815 fn assoc_fn_cross_crate() {
816 check_assist(
817 qualify_path,
818 r"
819 //- /main.rs crate:main deps:dep
820 fn main() {
821 dep::test_mod::TestStruct::test_func<|>tion
822 }
823 //- /dep.rs crate:dep
824 pub mod test_mod {
825 pub trait TestTrait {
826 fn test_function();
827 }
828 pub struct TestStruct {}
829 impl TestTrait for TestStruct {
830 fn test_function() {}
831 }
832 }
833 ",
834 r"
835 fn main() {
836 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
837 }
838 ",
839 );
840 }
841
842 #[test]
843 fn assoc_const_cross_crate() {
844 check_assist(
845 qualify_path,
846 r"
847 //- /main.rs crate:main deps:dep
848 fn main() {
849 dep::test_mod::TestStruct::CONST<|>
850 }
851 //- /dep.rs crate:dep
852 pub mod test_mod {
853 pub trait TestTrait {
854 const CONST: bool;
855 }
856 pub struct TestStruct {}
857 impl TestTrait for TestStruct {
858 const CONST: bool = true;
859 }
860 }
861 ",
862 r"
863 fn main() {
864 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
865 }
866 ",
867 );
868 }
869
870 #[test]
871 fn assoc_fn_as_method_cross_crate() {
872 check_assist_not_applicable(
873 qualify_path,
874 r"
875 //- /main.rs crate:main deps:dep
876 fn main() {
877 let test_struct = dep::test_mod::TestStruct {};
878 test_struct.test_func<|>tion()
879 }
880 //- /dep.rs crate:dep
881 pub mod test_mod {
882 pub trait TestTrait {
883 fn test_function();
884 }
885 pub struct TestStruct {}
886 impl TestTrait for TestStruct {
887 fn test_function() {}
888 }
889 }
890 ",
891 );
892 }
893
894 #[test]
895 fn private_trait_cross_crate() {
896 check_assist_not_applicable(
897 qualify_path,
898 r"
899 //- /main.rs crate:main deps:dep
900 fn main() {
901 let test_struct = dep::test_mod::TestStruct {};
902 test_struct.test_meth<|>od()
903 }
904 //- /dep.rs crate:dep
905 pub mod test_mod {
906 trait TestTrait {
907 fn test_method(&self);
908 }
909 pub struct TestStruct {}
910 impl TestTrait for TestStruct {
911 fn test_method(&self) {}
912 }
913 }
914 ",
915 );
916 }
917
918 #[test]
919 fn not_applicable_for_imported_trait_for_method() {
920 check_assist_not_applicable(
921 qualify_path,
922 r"
923 mod test_mod {
924 pub trait TestTrait {
925 fn test_method(&self);
926 }
927 pub trait TestTrait2 {
928 fn test_method(&self);
929 }
930 pub enum TestEnum {
931 One,
932 Two,
933 }
934 impl TestTrait2 for TestEnum {
935 fn test_method(&self) {}
936 }
937 impl TestTrait for TestEnum {
938 fn test_method(&self) {}
939 }
940 }
941
942 use test_mod::TestTrait2;
943 fn main() {
944 let one = test_mod::TestEnum::One;
945 one.test<|>_method();
946 }
947 ",
948 )
949 }
950
951 #[test]
952 fn dep_import() {
953 check_assist(
954 qualify_path,
955 r"
956//- /lib.rs crate:dep
957pub struct Struct;
958
959//- /main.rs crate:main deps:dep
960fn main() {
961 Struct<|>
962}
963",
964 r"
965fn main() {
966 dep::Struct
967}
968",
969 );
970 }
971
972 #[test]
973 fn whole_segment() {
974 // Tests that only imports whose last segment matches the identifier get suggested.
975 check_assist(
976 qualify_path,
977 r"
978//- /lib.rs crate:dep
979pub mod fmt {
980 pub trait Display {}
981}
982
983pub fn panic_fmt() {}
984
985//- /main.rs crate:main deps:dep
986struct S;
987
988impl f<|>mt::Display for S {}
989",
990 r"
991struct S;
992
993impl dep::fmt::Display for S {}
994",
995 );
996 }
997
998 #[test]
999 fn macro_generated() {
1000 // Tests that macro-generated items are suggested from external crates.
1001 check_assist(
1002 qualify_path,
1003 r"
1004//- /lib.rs crate:dep
1005macro_rules! mac {
1006 () => {
1007 pub struct Cheese;
1008 };
1009}
1010
1011mac!();
1012
1013//- /main.rs crate:main deps:dep
1014fn main() {
1015 Cheese<|>;
1016}
1017",
1018 r"
1019fn main() {
1020 dep::Cheese;
1021}
1022",
1023 );
1024 }
1025
1026 #[test]
1027 fn casing() {
1028 // Tests that differently cased names don't interfere and we only suggest the matching one.
1029 check_assist(
1030 qualify_path,
1031 r"
1032//- /lib.rs crate:dep
1033pub struct FMT;
1034pub struct fmt;
1035
1036//- /main.rs crate:main deps:dep
1037fn main() {
1038 FMT<|>;
1039}
1040",
1041 r"
1042fn main() {
1043 dep::FMT;
1044}
1045",
1046 );
1047 }
1048}
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs
index e10616779..9731344b8 100644
--- a/crates/assists/src/handlers/remove_dbg.rs
+++ b/crates/assists/src/handlers/remove_dbg.rs
@@ -93,8 +93,9 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
93 if macro_contents.len() < 2 { 93 if macro_contents.len() < 2 {
94 return false; 94 return false;
95 } 95 }
96 let mut macro_contents = macro_contents.into_iter().peekable();
96 let mut unpaired_brackets_in_contents = Vec::new(); 97 let mut unpaired_brackets_in_contents = Vec::new();
97 for element in macro_contents { 98 while let Some(element) = macro_contents.next() {
98 match element.kind() { 99 match element.kind() {
99 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element), 100 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element),
100 T![')'] => { 101 T![')'] => {
@@ -118,8 +119,14 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
118 symbol_kind => { 119 symbol_kind => {
119 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); 120 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
120 if symbol_not_in_bracket 121 if symbol_not_in_bracket
121 && symbol_kind != SyntaxKind::COLON 122 && symbol_kind != SyntaxKind::COLON // paths
122 && symbol_kind.is_punct() 123 && (symbol_kind != SyntaxKind::DOT // field/method access
124 || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations
125 .peek()
126 .map(|element| element.kind() == SyntaxKind::DOT)
127 .unwrap_or(false))
128 && symbol_kind != SyntaxKind::QUESTION // try operator
129 && (symbol_kind.is_punct() || symbol_kind == SyntaxKind::AS_KW)
123 { 130 {
124 return true; 131 return true;
125 } 132 }
@@ -243,6 +250,25 @@ fn main() {
243 } 250 }
244 251
245 #[test] 252 #[test]
253 fn test_remove_dbg_method_chaining() {
254 check_assist(
255 remove_dbg,
256 r#"let res = <|>dbg!(foo().bar()).baz();"#,
257 r#"let res = foo().bar().baz();"#,
258 );
259 check_assist(
260 remove_dbg,
261 r#"let res = <|>dbg!(foo.bar()).baz();"#,
262 r#"let res = foo.bar().baz();"#,
263 );
264 }
265
266 #[test]
267 fn test_remove_dbg_field_chaining() {
268 check_assist(remove_dbg, r#"let res = <|>dbg!(foo.bar).baz;"#, r#"let res = foo.bar.baz;"#);
269 }
270
271 #[test]
246 fn test_remove_dbg_from_inside_fn() { 272 fn test_remove_dbg_from_inside_fn() {
247 check_assist_target( 273 check_assist_target(
248 remove_dbg, 274 remove_dbg,
@@ -280,4 +306,59 @@ fn main() {
280}"#, 306}"#,
281 ); 307 );
282 } 308 }
309
310 #[test]
311 fn test_remove_dbg_try_expr() {
312 check_assist(
313 remove_dbg,
314 r#"let res = <|>dbg!(result?).foo();"#,
315 r#"let res = result?.foo();"#,
316 );
317 }
318
319 #[test]
320 fn test_remove_dbg_await_expr() {
321 check_assist(
322 remove_dbg,
323 r#"let res = <|>dbg!(fut.await).foo();"#,
324 r#"let res = fut.await.foo();"#,
325 );
326 }
327
328 #[test]
329 fn test_remove_dbg_as_cast() {
330 check_assist(
331 remove_dbg,
332 r#"let res = <|>dbg!(3 as usize).foo();"#,
333 r#"let res = (3 as usize).foo();"#,
334 );
335 }
336
337 #[test]
338 fn test_remove_dbg_index_expr() {
339 check_assist(
340 remove_dbg,
341 r#"let res = <|>dbg!(array[3]).foo();"#,
342 r#"let res = array[3].foo();"#,
343 );
344 check_assist(
345 remove_dbg,
346 r#"let res = <|>dbg!(tuple.3).foo();"#,
347 r#"let res = tuple.3.foo();"#,
348 );
349 }
350
351 #[test]
352 fn test_remove_dbg_range_expr() {
353 check_assist(
354 remove_dbg,
355 r#"let res = <|>dbg!(foo..bar).foo();"#,
356 r#"let res = (foo..bar).foo();"#,
357 );
358 check_assist(
359 remove_dbg,
360 r#"let res = <|>dbg!(foo..=bar).foo();"#,
361 r#"let res = (foo..=bar).foo();"#,
362 );
363 }
283} 364}
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs
index 79097621e..9a49c48c1 100644
--- a/crates/assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/assists/src/handlers/replace_if_let_with_match.rs
@@ -7,10 +7,8 @@ use syntax::{
7 AstNode, 7 AstNode,
8}; 8};
9 9
10use crate::{ 10use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
11 utils::{unwrap_trivial_block, TryEnum}, 11use ide_db::ty_filter::TryEnum;
12 AssistContext, AssistId, AssistKind, Assists,
13};
14 12
15// Assist: replace_if_let_with_match 13// Assist: replace_if_let_with_match
16// 14//
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs
index ed6d0c29b..a5bcbda24 100644
--- a/crates/assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/assists/src/handlers/replace_let_with_if_let.rs
@@ -9,7 +9,8 @@ use syntax::{
9 AstNode, T, 9 AstNode, T,
10}; 10};
11 11
12use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; 12use crate::{AssistContext, AssistId, AssistKind, Assists};
13use ide_db::ty_filter::TryEnum;
13 14
14// Assist: replace_let_with_if_let 15// Assist: replace_let_with_if_let
15// 16//
diff --git a/crates/assists/src/handlers/replace_string_with_char.rs b/crates/assists/src/handlers/replace_string_with_char.rs
new file mode 100644
index 000000000..4ca87a8ec
--- /dev/null
+++ b/crates/assists/src/handlers/replace_string_with_char.rs
@@ -0,0 +1,141 @@
1use syntax::{
2 ast::{self, HasStringValue},
3 AstToken,
4 SyntaxKind::STRING,
5};
6
7use crate::{AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: replace_string_with_char
10//
11// Replace string with char.
12//
13// ```
14// fn main() {
15// find("{<|>");
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// find('{');
22// }
23// ```
24pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
26 let value = token.value()?;
27 let target = token.syntax().text_range();
28
29 if value.chars().take(2).count() != 1 {
30 return None;
31 }
32
33 acc.add(
34 AssistId("replace_string_with_char", AssistKind::RefactorRewrite),
35 "Replace string with char",
36 target,
37 |edit| {
38 edit.replace(token.syntax().text_range(), format!("'{}'", value));
39 },
40 )
41}
42
43#[cfg(test)]
44mod tests {
45 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
46
47 use super::*;
48
49 #[test]
50 fn replace_string_with_char_target() {
51 check_assist_target(
52 replace_string_with_char,
53 r#"
54 fn f() {
55 let s = "<|>c";
56 }
57 "#,
58 r#""c""#,
59 );
60 }
61
62 #[test]
63 fn replace_string_with_char_assist() {
64 check_assist(
65 replace_string_with_char,
66 r#"
67 fn f() {
68 let s = "<|>c";
69 }
70 "#,
71 r##"
72 fn f() {
73 let s = 'c';
74 }
75 "##,
76 )
77 }
78
79 #[test]
80 fn replace_string_with_char_assist_with_emoji() {
81 check_assist(
82 replace_string_with_char,
83 r#"
84 fn f() {
85 let s = "<|>😀";
86 }
87 "#,
88 r##"
89 fn f() {
90 let s = '😀';
91 }
92 "##,
93 )
94 }
95
96 #[test]
97 fn replace_string_with_char_assist_not_applicable() {
98 check_assist_not_applicable(
99 replace_string_with_char,
100 r#"
101 fn f() {
102 let s = "<|>test";
103 }
104 "#,
105 )
106 }
107
108 #[test]
109 fn replace_string_with_char_works_inside_macros() {
110 check_assist(
111 replace_string_with_char,
112 r#"
113 fn f() {
114 format!(<|>"x", 92)
115 }
116 "#,
117 r##"
118 fn f() {
119 format!('x', 92)
120 }
121 "##,
122 )
123 }
124
125 #[test]
126 fn replace_string_with_char_works_func_args() {
127 check_assist(
128 replace_string_with_char,
129 r#"
130 fn f() {
131 find(<|>"x");
132 }
133 "#,
134 r##"
135 fn f() {
136 find('x');
137 }
138 "##,
139 )
140 }
141}
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs
index 4043c219c..f547066f0 100644
--- a/crates/assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs
@@ -10,9 +10,10 @@ use syntax::{
10}; 10};
11 11
12use crate::{ 12use crate::{
13 utils::{render_snippet, Cursor, TryEnum}, 13 utils::{render_snippet, Cursor},
14 AssistContext, AssistId, AssistKind, Assists, 14 AssistContext, AssistId, AssistKind, Assists,
15}; 15};
16use ide_db::ty_filter::TryEnum;
16 17
17// Assist: replace_unwrap_with_match 18// Assist: replace_unwrap_with_match
18// 19//
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index a2bec818c..b804e495d 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -17,8 +17,8 @@ mod tests;
17pub mod utils; 17pub mod utils;
18pub mod ast_transform; 18pub mod ast_transform;
19 19
20use base_db::FileRange;
21use hir::Semantics; 20use hir::Semantics;
21use ide_db::base_db::FileRange;
22use ide_db::{label::Label, source_change::SourceChange, RootDatabase}; 22use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
23use syntax::TextRange; 23use syntax::TextRange;
24 24
@@ -150,6 +150,7 @@ mod handlers {
150 mod merge_match_arms; 150 mod merge_match_arms;
151 mod move_bounds; 151 mod move_bounds;
152 mod move_guard; 152 mod move_guard;
153 mod qualify_path;
153 mod raw_string; 154 mod raw_string;
154 mod remove_dbg; 155 mod remove_dbg;
155 mod remove_mut; 156 mod remove_mut;
@@ -159,6 +160,7 @@ mod handlers {
159 mod replace_impl_trait_with_generic; 160 mod replace_impl_trait_with_generic;
160 mod replace_let_with_if_let; 161 mod replace_let_with_if_let;
161 mod replace_qualified_name_with_use; 162 mod replace_qualified_name_with_use;
163 mod replace_string_with_char;
162 mod replace_unwrap_with_match; 164 mod replace_unwrap_with_match;
163 mod split_import; 165 mod split_import;
164 mod unwrap_block; 166 mod unwrap_block;
@@ -196,8 +198,8 @@ mod handlers {
196 move_bounds::move_bounds_to_where_clause, 198 move_bounds::move_bounds_to_where_clause,
197 move_guard::move_arm_cond_to_match_guard, 199 move_guard::move_arm_cond_to_match_guard,
198 move_guard::move_guard_to_arm_body, 200 move_guard::move_guard_to_arm_body,
201 qualify_path::qualify_path,
199 raw_string::add_hash, 202 raw_string::add_hash,
200 raw_string::make_raw_string,
201 raw_string::make_usual_string, 203 raw_string::make_usual_string,
202 raw_string::remove_hash, 204 raw_string::remove_hash,
203 remove_dbg::remove_dbg, 205 remove_dbg::remove_dbg,
@@ -214,6 +216,9 @@ mod handlers {
214 // These are manually sorted for better priorities 216 // These are manually sorted for better priorities
215 add_missing_impl_members::add_missing_impl_members, 217 add_missing_impl_members::add_missing_impl_members,
216 add_missing_impl_members::add_missing_default_members, 218 add_missing_impl_members::add_missing_default_members,
219 //
220 replace_string_with_char::replace_string_with_char,
221 raw_string::make_raw_string,
217 // Are you sure you want to add new assist here, and not to the 222 // Are you sure you want to add new assist here, and not to the
218 // sorted list above? 223 // sorted list above?
219 ] 224 ]
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index 2b687decf..849d85e76 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -1,7 +1,7 @@
1mod generated; 1mod generated;
2 2
3use base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
4use hir::Semantics; 3use hir::Semantics;
4use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::TextRange; 6use syntax::TextRange;
7use test_utils::{assert_eq_text, extract_offset, extract_range}; 7use test_utils::{assert_eq_text, extract_offset, extract_range};
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 41f536574..acbf5b652 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -713,6 +713,25 @@ fn handle(action: Action) {
713} 713}
714 714
715#[test] 715#[test]
716fn doctest_qualify_path() {
717 check_doc_test(
718 "qualify_path",
719 r#####"
720fn main() {
721 let map = HashMap<|>::new();
722}
723pub mod std { pub mod collections { pub struct HashMap { } } }
724"#####,
725 r#####"
726fn main() {
727 let map = std::collections::HashMap::new();
728}
729pub mod std { pub mod collections { pub struct HashMap { } } }
730"#####,
731 )
732}
733
734#[test]
716fn doctest_remove_dbg() { 735fn doctest_remove_dbg() {
717 check_doc_test( 736 check_doc_test(
718 "remove_dbg", 737 "remove_dbg",
@@ -882,6 +901,23 @@ fn process(map: HashMap<String, String>) {}
882} 901}
883 902
884#[test] 903#[test]
904fn doctest_replace_string_with_char() {
905 check_doc_test(
906 "replace_string_with_char",
907 r#####"
908fn main() {
909 find("{<|>");
910}
911"#####,
912 r#####"
913fn main() {
914 find('{');
915}
916"#####,
917 )
918}
919
920#[test]
885fn doctest_replace_unwrap_with_match() { 921fn doctest_replace_unwrap_with_match() {
886 check_doc_test( 922 check_doc_test(
887 "replace_unwrap_with_match", 923 "replace_unwrap_with_match",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index b37b0d2b6..56f925ee6 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -2,14 +2,13 @@
2pub(crate) mod insert_use; 2pub(crate) mod insert_use;
3pub(crate) mod import_assets; 3pub(crate) mod import_assets;
4 4
5use std::{iter, ops}; 5use std::ops;
6 6
7use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type}; 7use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
8use ide_db::RootDatabase; 8use ide_db::RootDatabase;
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::FxHashSet;
11use syntax::{ 10use syntax::{
12 ast::{self, make, ArgListOwner, NameOwner}, 11 ast::{self, make, ArgListOwner},
13 AstNode, Direction, 12 AstNode, Direction,
14 SyntaxKind::*, 13 SyntaxKind::*,
15 SyntaxNode, TextSize, T, 14 SyntaxNode, TextSize, T,
@@ -115,72 +114,6 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
115 } 114 }
116} 115}
117 116
118pub fn get_missing_assoc_items(
119 sema: &Semantics<RootDatabase>,
120 impl_def: &ast::Impl,
121) -> Vec<hir::AssocItem> {
122 // Names must be unique between constants and functions. However, type aliases
123 // may share the same name as a function or constant.
124 let mut impl_fns_consts = FxHashSet::default();
125 let mut impl_type = FxHashSet::default();
126
127 if let Some(item_list) = impl_def.assoc_item_list() {
128 for item in item_list.assoc_items() {
129 match item {
130 ast::AssocItem::Fn(f) => {
131 if let Some(n) = f.name() {
132 impl_fns_consts.insert(n.syntax().to_string());
133 }
134 }
135
136 ast::AssocItem::TypeAlias(t) => {
137 if let Some(n) = t.name() {
138 impl_type.insert(n.syntax().to_string());
139 }
140 }
141
142 ast::AssocItem::Const(c) => {
143 if let Some(n) = c.name() {
144 impl_fns_consts.insert(n.syntax().to_string());
145 }
146 }
147 ast::AssocItem::MacroCall(_) => (),
148 }
149 }
150 }
151
152 resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
153 target_trait
154 .items(sema.db)
155 .iter()
156 .filter(|i| match i {
157 hir::AssocItem::Function(f) => {
158 !impl_fns_consts.contains(&f.name(sema.db).to_string())
159 }
160 hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
161 hir::AssocItem::Const(c) => c
162 .name(sema.db)
163 .map(|n| !impl_fns_consts.contains(&n.to_string()))
164 .unwrap_or_default(),
165 })
166 .cloned()
167 .collect()
168 })
169}
170
171pub(crate) fn resolve_target_trait(
172 sema: &Semantics<RootDatabase>,
173 impl_def: &ast::Impl,
174) -> Option<hir::Trait> {
175 let ast_path =
176 impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
177
178 match sema.resolve_path(&ast_path) {
179 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
180 _ => None,
181 }
182}
183
184pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { 117pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
185 node.children_with_tokens() 118 node.children_with_tokens()
186 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) 119 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@@ -223,59 +156,11 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
223 } 156 }
224} 157}
225 158
226#[derive(Clone, Copy)]
227pub enum TryEnum {
228 Result,
229 Option,
230}
231
232impl TryEnum {
233 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
234
235 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
236 let enum_ = match ty.as_adt() {
237 Some(Adt::Enum(it)) => it,
238 _ => return None,
239 };
240 TryEnum::ALL.iter().find_map(|&var| {
241 if &enum_.name(sema.db).to_string() == var.type_name() {
242 return Some(var);
243 }
244 None
245 })
246 }
247
248 pub(crate) fn happy_case(self) -> &'static str {
249 match self {
250 TryEnum::Result => "Ok",
251 TryEnum::Option => "Some",
252 }
253 }
254
255 pub(crate) fn sad_pattern(self) -> ast::Pat {
256 match self {
257 TryEnum::Result => make::tuple_struct_pat(
258 make::path_unqualified(make::path_segment(make::name_ref("Err"))),
259 iter::once(make::wildcard_pat().into()),
260 )
261 .into(),
262 TryEnum::Option => make::ident_pat(make::name("None")).into(),
263 }
264 }
265
266 fn type_name(self) -> &'static str {
267 match self {
268 TryEnum::Result => "Result",
269 TryEnum::Option => "Option",
270 }
271 }
272}
273
274/// Helps with finding well-know things inside the standard library. This is 159/// Helps with finding well-know things inside the standard library. This is
275/// somewhat similar to the known paths infra inside hir, but it different; We 160/// somewhat similar to the known paths infra inside hir, but it different; We
276/// want to make sure that IDE specific paths don't become interesting inside 161/// want to make sure that IDE specific paths don't become interesting inside
277/// the compiler itself as well. 162/// the compiler itself as well.
278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); 163pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
279 164
280#[allow(non_snake_case)] 165#[allow(non_snake_case)]
281impl FamousDefs<'_, '_> { 166impl FamousDefs<'_, '_> {
@@ -362,6 +247,10 @@ pub mod prelude {
362pub use prelude::*; 247pub use prelude::*;
363"#; 248"#;
364 249
250 pub fn core(&self) -> Option<Crate> {
251 self.find_crate("core")
252 }
253
365 pub(crate) fn core_convert_From(&self) -> Option<Trait> { 254 pub(crate) fn core_convert_From(&self) -> Option<Trait> {
366 self.find_trait("core:convert:From") 255 self.find_trait("core:convert:From")
367 } 256 }
@@ -399,21 +288,20 @@ pub use prelude::*;
399 } 288 }
400 } 289 }
401 290
291 fn find_crate(&self, name: &str) -> Option<Crate> {
292 let krate = self.1?;
293 let db = self.0.db;
294 let res =
295 krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
296 Some(res)
297 }
298
402 fn find_def(&self, path: &str) -> Option<ScopeDef> { 299 fn find_def(&self, path: &str) -> Option<ScopeDef> {
403 let db = self.0.db; 300 let db = self.0.db;
404 let mut path = path.split(':'); 301 let mut path = path.split(':');
405 let trait_ = path.next_back()?; 302 let trait_ = path.next_back()?;
406 let std_crate = path.next()?; 303 let std_crate = path.next()?;
407 let std_crate = if self 304 let std_crate = self.find_crate(std_crate)?;
408 .1
409 .declaration_name(db)
410 .map(|name| name.to_string() == std_crate)
411 .unwrap_or(false)
412 {
413 self.1
414 } else {
415 self.1.dependencies(db).into_iter().find(|dep| dep.name.to_string() == std_crate)?.krate
416 };
417 let mut module = std_crate.root_module(db); 305 let mut module = std_crate.root_module(db);
418 for segment in path { 306 for segment in path {
419 module = module.children(db).find_map(|child| { 307 module = module.children(db).find_map(|child| {
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs
index 601f51098..23db3a74b 100644
--- a/crates/assists/src/utils/import_assets.rs
+++ b/crates/assists/src/utils/import_assets.rs
@@ -1,6 +1,4 @@
1//! Look up accessible paths for items. 1//! Look up accessible paths for items.
2use std::collections::BTreeSet;
3
4use either::Either; 2use either::Either;
5use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics}; 3use hir::{AsAssocItem, AssocItemContainer, ModuleDef, Semantics};
6use ide_db::{imports_locator, RootDatabase}; 4use ide_db::{imports_locator, RootDatabase};
@@ -29,12 +27,12 @@ pub(crate) enum ImportCandidate {
29#[derive(Debug)] 27#[derive(Debug)]
30pub(crate) struct TraitImportCandidate { 28pub(crate) struct TraitImportCandidate {
31 pub ty: hir::Type, 29 pub ty: hir::Type,
32 pub name: String, 30 pub name: ast::NameRef,
33} 31}
34 32
35#[derive(Debug)] 33#[derive(Debug)]
36pub(crate) struct PathImportCandidate { 34pub(crate) struct PathImportCandidate {
37 pub name: String, 35 pub name: ast::NameRef,
38} 36}
39 37
40#[derive(Debug)] 38#[derive(Debug)]
@@ -86,9 +84,9 @@ impl ImportAssets {
86 fn get_search_query(&self) -> &str { 84 fn get_search_query(&self) -> &str {
87 match &self.import_candidate { 85 match &self.import_candidate {
88 ImportCandidate::UnqualifiedName(candidate) 86 ImportCandidate::UnqualifiedName(candidate)
89 | ImportCandidate::QualifierStart(candidate) => &candidate.name, 87 | ImportCandidate::QualifierStart(candidate) => candidate.name.text(),
90 ImportCandidate::TraitAssocItem(candidate) 88 ImportCandidate::TraitAssocItem(candidate)
91 | ImportCandidate::TraitMethod(candidate) => &candidate.name, 89 | ImportCandidate::TraitMethod(candidate) => candidate.name.text(),
92 } 90 }
93 } 91 }
94 92
@@ -96,7 +94,7 @@ impl ImportAssets {
96 &self, 94 &self,
97 sema: &Semantics<RootDatabase>, 95 sema: &Semantics<RootDatabase>,
98 config: &InsertUseConfig, 96 config: &InsertUseConfig,
99 ) -> BTreeSet<hir::ModPath> { 97 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
100 let _p = profile::span("import_assists::search_for_imports"); 98 let _p = profile::span("import_assists::search_for_imports");
101 self.search_for(sema, Some(config.prefix_kind)) 99 self.search_for(sema, Some(config.prefix_kind))
102 } 100 }
@@ -106,7 +104,7 @@ impl ImportAssets {
106 pub(crate) fn search_for_relative_paths( 104 pub(crate) fn search_for_relative_paths(
107 &self, 105 &self,
108 sema: &Semantics<RootDatabase>, 106 sema: &Semantics<RootDatabase>,
109 ) -> BTreeSet<hir::ModPath> { 107 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
110 let _p = profile::span("import_assists::search_for_relative_paths"); 108 let _p = profile::span("import_assists::search_for_relative_paths");
111 self.search_for(sema, None) 109 self.search_for(sema, None)
112 } 110 }
@@ -115,7 +113,7 @@ impl ImportAssets {
115 &self, 113 &self,
116 sema: &Semantics<RootDatabase>, 114 sema: &Semantics<RootDatabase>,
117 prefixed: Option<hir::PrefixKind>, 115 prefixed: Option<hir::PrefixKind>,
118 ) -> BTreeSet<hir::ModPath> { 116 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
119 let db = sema.db; 117 let db = sema.db;
120 let mut trait_candidates = FxHashSet::default(); 118 let mut trait_candidates = FxHashSet::default();
121 let current_crate = self.module_with_name_to_import.krate(); 119 let current_crate = self.module_with_name_to_import.krate();
@@ -181,7 +179,7 @@ impl ImportAssets {
181 } 179 }
182 }; 180 };
183 181
184 imports_locator::find_imports(sema, current_crate, &self.get_search_query()) 182 let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query())
185 .into_iter() 183 .into_iter()
186 .filter_map(filter) 184 .filter_map(filter)
187 .filter_map(|candidate| { 185 .filter_map(|candidate| {
@@ -191,10 +189,13 @@ impl ImportAssets {
191 } else { 189 } else {
192 self.module_with_name_to_import.find_use_path(db, item) 190 self.module_with_name_to_import.find_use_path(db, item)
193 } 191 }
192 .map(|path| (path, item))
194 }) 193 })
195 .filter(|use_path| !use_path.segments.is_empty()) 194 .filter(|(use_path, _)| !use_path.segments.is_empty())
196 .take(20) 195 .take(20)
197 .collect::<BTreeSet<_>>() 196 .collect::<Vec<_>>();
197 res.sort_by_key(|(path, _)| path.clone());
198 res
198 } 199 }
199 200
200 fn assoc_to_trait(assoc: AssocItemContainer) -> Option<hir::Trait> { 201 fn assoc_to_trait(assoc: AssocItemContainer) -> Option<hir::Trait> {
@@ -215,7 +216,7 @@ impl ImportCandidate {
215 Some(_) => None, 216 Some(_) => None,
216 None => Some(Self::TraitMethod(TraitImportCandidate { 217 None => Some(Self::TraitMethod(TraitImportCandidate {
217 ty: sema.type_of_expr(&method_call.receiver()?)?, 218 ty: sema.type_of_expr(&method_call.receiver()?)?,
218 name: method_call.name_ref()?.syntax().to_string(), 219 name: method_call.name_ref()?,
219 })), 220 })),
220 } 221 }
221 } 222 }
@@ -243,24 +244,17 @@ impl ImportCandidate {
243 hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => { 244 hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path)) => {
244 ImportCandidate::TraitAssocItem(TraitImportCandidate { 245 ImportCandidate::TraitAssocItem(TraitImportCandidate {
245 ty: assoc_item_path.ty(sema.db), 246 ty: assoc_item_path.ty(sema.db),
246 name: segment.syntax().to_string(), 247 name: segment.name_ref()?,
247 }) 248 })
248 } 249 }
249 _ => return None, 250 _ => return None,
250 } 251 }
251 } else { 252 } else {
252 ImportCandidate::QualifierStart(PathImportCandidate { 253 ImportCandidate::QualifierStart(PathImportCandidate { name: qualifier_start })
253 name: qualifier_start.syntax().to_string(),
254 })
255 } 254 }
256 } else { 255 } else {
257 ImportCandidate::UnqualifiedName(PathImportCandidate { 256 ImportCandidate::UnqualifiedName(PathImportCandidate {
258 name: segment 257 name: segment.syntax().descendants().find_map(ast::NameRef::cast)?,
259 .syntax()
260 .descendants()
261 .find_map(ast::NameRef::cast)?
262 .syntax()
263 .to_string(),
264 }) 258 })
265 }; 259 };
266 Some(candidate) 260 Some(candidate)
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs
index 409985b3b..033fbcedc 100644
--- a/crates/assists/src/utils/insert_use.rs
+++ b/crates/assists/src/utils/insert_use.rs
@@ -14,6 +14,7 @@ use syntax::{
14 }, 14 },
15 InsertPosition, SyntaxElement, SyntaxNode, 15 InsertPosition, SyntaxElement, SyntaxNode,
16}; 16};
17use test_utils::mark;
17 18
18#[derive(Debug)] 19#[derive(Debug)]
19pub enum ImportScope { 20pub enum ImportScope {
@@ -109,6 +110,12 @@ pub(crate) fn insert_use(
109 // so look for the place we have to insert to 110 // so look for the place we have to insert to
110 let (insert_position, add_blank) = find_insert_position(scope, path); 111 let (insert_position, add_blank) = find_insert_position(scope, path);
111 112
113 let indent = if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize {
114 Some(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into())
115 } else {
116 None
117 };
118
112 let to_insert: Vec<SyntaxElement> = { 119 let to_insert: Vec<SyntaxElement> = {
113 let mut buf = Vec::new(); 120 let mut buf = Vec::new();
114 121
@@ -120,9 +127,13 @@ pub(crate) fn insert_use(
120 _ => (), 127 _ => (),
121 } 128 }
122 129
123 if let ident_level @ 1..=usize::MAX = scope.indent_level().0 as usize { 130 if add_blank.has_before() {
124 buf.push(make::tokens::whitespace(&" ".repeat(4 * ident_level)).into()); 131 if let Some(indent) = indent.clone() {
132 mark::hit!(insert_use_indent_before);
133 buf.push(indent);
134 }
125 } 135 }
136
126 buf.push(use_item.syntax().clone().into()); 137 buf.push(use_item.syntax().clone().into());
127 138
128 match add_blank { 139 match add_blank {
@@ -133,6 +144,16 @@ pub(crate) fn insert_use(
133 _ => (), 144 _ => (),
134 } 145 }
135 146
147 // only add indentation *after* our stuff if there's another node directly after it
148 if add_blank.has_after() && matches!(insert_position, InsertPosition::Before(_)) {
149 if let Some(indent) = indent {
150 mark::hit!(insert_use_indent_after);
151 buf.push(indent);
152 }
153 } else if add_blank.has_after() && matches!(insert_position, InsertPosition::After(_)) {
154 mark::hit!(insert_use_no_indent_after);
155 }
156
136 buf 157 buf
137 }; 158 };
138 159
@@ -470,6 +491,15 @@ enum AddBlankLine {
470 AfterTwice, 491 AfterTwice,
471} 492}
472 493
494impl AddBlankLine {
495 fn has_before(&self) -> bool {
496 matches!(self, AddBlankLine::Before | AddBlankLine::BeforeTwice | AddBlankLine::Around)
497 }
498 fn has_after(&self) -> bool {
499 matches!(self, AddBlankLine::After | AddBlankLine::AfterTwice | AddBlankLine::Around)
500 }
501}
502
473fn find_insert_position( 503fn find_insert_position(
474 scope: &ImportScope, 504 scope: &ImportScope,
475 insert_path: ast::Path, 505 insert_path: ast::Path,
@@ -562,6 +592,21 @@ use std::bar::G;",
562 } 592 }
563 593
564 #[test] 594 #[test]
595 fn insert_start_indent() {
596 mark::check!(insert_use_indent_after);
597 check_none(
598 "std::bar::AA",
599 r"
600 use std::bar::B;
601 use std::bar::D;",
602 r"
603 use std::bar::AA;
604 use std::bar::B;
605 use std::bar::D;",
606 )
607 }
608
609 #[test]
565 fn insert_middle() { 610 fn insert_middle() {
566 check_none( 611 check_none(
567 "std::bar::EE", 612 "std::bar::EE",
@@ -580,6 +625,24 @@ use std::bar::G;",
580 } 625 }
581 626
582 #[test] 627 #[test]
628 fn insert_middle_indent() {
629 check_none(
630 "std::bar::EE",
631 r"
632 use std::bar::A;
633 use std::bar::D;
634 use std::bar::F;
635 use std::bar::G;",
636 r"
637 use std::bar::A;
638 use std::bar::D;
639 use std::bar::EE;
640 use std::bar::F;
641 use std::bar::G;",
642 )
643 }
644
645 #[test]
583 fn insert_end() { 646 fn insert_end() {
584 check_none( 647 check_none(
585 "std::bar::ZZ", 648 "std::bar::ZZ",
@@ -598,6 +661,25 @@ use std::bar::ZZ;",
598 } 661 }
599 662
600 #[test] 663 #[test]
664 fn insert_end_indent() {
665 mark::check!(insert_use_indent_before);
666 check_none(
667 "std::bar::ZZ",
668 r"
669 use std::bar::A;
670 use std::bar::D;
671 use std::bar::F;
672 use std::bar::G;",
673 r"
674 use std::bar::A;
675 use std::bar::D;
676 use std::bar::F;
677 use std::bar::G;
678 use std::bar::ZZ;",
679 )
680 }
681
682 #[test]
601 fn insert_middle_nested() { 683 fn insert_middle_nested() {
602 check_none( 684 check_none(
603 "std::bar::EE", 685 "std::bar::EE",
@@ -620,18 +702,18 @@ use std::bar::G;",
620 check_none( 702 check_none(
621 "foo::bar::GG", 703 "foo::bar::GG",
622 r" 704 r"
623use std::bar::A; 705 use std::bar::A;
624use std::bar::D; 706 use std::bar::D;
625 707
626use foo::bar::F; 708 use foo::bar::F;
627use foo::bar::H;", 709 use foo::bar::H;",
628 r" 710 r"
629use std::bar::A; 711 use std::bar::A;
630use std::bar::D; 712 use std::bar::D;
631 713
632use foo::bar::F; 714 use foo::bar::F;
633use foo::bar::GG; 715 use foo::bar::GG;
634use foo::bar::H;", 716 use foo::bar::H;",
635 ) 717 )
636 } 718 }
637 719
@@ -640,22 +722,22 @@ use foo::bar::H;",
640 check_none( 722 check_none(
641 "foo::bar::GG", 723 "foo::bar::GG",
642 r" 724 r"
643use foo::bar::A; 725 use foo::bar::A;
644use foo::bar::D; 726 use foo::bar::D;
645 727
646use std; 728 use std;
647 729
648use foo::bar::F; 730 use foo::bar::F;
649use foo::bar::H;", 731 use foo::bar::H;",
650 r" 732 r"
651use foo::bar::A; 733 use foo::bar::A;
652use foo::bar::D; 734 use foo::bar::D;
653use foo::bar::GG; 735 use foo::bar::GG;
654 736
655use std; 737 use std;
656 738
657use foo::bar::F; 739 use foo::bar::F;
658use foo::bar::H;", 740 use foo::bar::H;",
659 ) 741 )
660 } 742 }
661 743
@@ -664,13 +746,13 @@ use foo::bar::H;",
664 check_none( 746 check_none(
665 "std::fmt", 747 "std::fmt",
666 r" 748 r"
667use foo::bar::A; 749 use foo::bar::A;
668use foo::bar::D;", 750 use foo::bar::D;",
669 r" 751 r"
670use std::fmt; 752 use std::fmt;
671 753
672use foo::bar::A; 754 use foo::bar::A;
673use foo::bar::D;", 755 use foo::bar::D;",
674 ) 756 )
675 } 757 }
676 758
@@ -714,6 +796,20 @@ fn main() {}",
714 } 796 }
715 797
716 #[test] 798 #[test]
799 fn insert_empty_module() {
800 mark::check!(insert_use_no_indent_after);
801 check(
802 "foo::bar",
803 "mod x {}",
804 r"{
805 use foo::bar;
806}",
807 None,
808 true,
809 )
810 }
811
812 #[test]
717 fn insert_after_inner_attr() { 813 fn insert_after_inner_attr() {
718 check_full( 814 check_full(
719 "foo::bar", 815 "foo::bar",
@@ -991,11 +1087,13 @@ use foo::bar::baz::Qux;",
991 ra_fixture_before: &str, 1087 ra_fixture_before: &str,
992 ra_fixture_after: &str, 1088 ra_fixture_after: &str,
993 mb: Option<MergeBehaviour>, 1089 mb: Option<MergeBehaviour>,
1090 module: bool,
994 ) { 1091 ) {
995 let file = super::ImportScope::from( 1092 let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone();
996 ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(), 1093 if module {
997 ) 1094 syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone();
998 .unwrap(); 1095 }
1096 let file = super::ImportScope::from(syntax).unwrap();
999 let path = ast::SourceFile::parse(&format!("use {};", path)) 1097 let path = ast::SourceFile::parse(&format!("use {};", path))
1000 .tree() 1098 .tree()
1001 .syntax() 1099 .syntax()
@@ -1008,15 +1106,15 @@ use foo::bar::baz::Qux;",
1008 } 1106 }
1009 1107
1010 fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 1108 fn check_full(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1011 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full)) 1109 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Full), false)
1012 } 1110 }
1013 1111
1014 fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 1112 fn check_last(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1015 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last)) 1113 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehaviour::Last), false)
1016 } 1114 }
1017 1115
1018 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 1116 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1019 check(path, ra_fixture_before, ra_fixture_after, None) 1117 check(path, ra_fixture_before, ra_fixture_after, None, false)
1020 } 1118 }
1021 1119
1022 fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) { 1120 fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehaviour) {
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 72f1fd667..66e6443cb 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -158,7 +158,7 @@ impl ChangeFixture {
158 let crate_id = crate_graph.add_crate_root( 158 let crate_id = crate_graph.add_crate_root(
159 file_id, 159 file_id,
160 meta.edition, 160 meta.edition,
161 Some(crate_name.clone()), 161 Some(crate_name.clone().into()),
162 meta.cfg, 162 meta.cfg,
163 meta.env, 163 meta.env,
164 Default::default(), 164 Default::default(),
@@ -187,7 +187,7 @@ impl ChangeFixture {
187 crate_graph.add_crate_root( 187 crate_graph.add_crate_root(
188 crate_root, 188 crate_root,
189 Edition::Edition2018, 189 Edition::Edition2018,
190 Some(CrateName::new("test").unwrap()), 190 Some(CrateName::new("test").unwrap().into()),
191 default_cfg, 191 default_cfg,
192 Env::default(), 192 Env::default(),
193 Default::default(), 193 Default::default(),
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 215ac4b41..87f0a0ce5 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -102,11 +102,46 @@ impl fmt::Display for CrateName {
102 102
103impl ops::Deref for CrateName { 103impl ops::Deref for CrateName {
104 type Target = str; 104 type Target = str;
105 fn deref(&self) -> &Self::Target { 105 fn deref(&self) -> &str {
106 &*self.0 106 &*self.0
107 } 107 }
108} 108}
109 109
110#[derive(Debug, Clone, PartialEq, Eq, Hash)]
111pub struct CrateDisplayName {
112 // The name we use to display various paths (with `_`).
113 crate_name: CrateName,
114 // The name as specified in Cargo.toml (with `-`).
115 canonical_name: String,
116}
117
118impl From<CrateName> for CrateDisplayName {
119 fn from(crate_name: CrateName) -> CrateDisplayName {
120 let canonical_name = crate_name.to_string();
121 CrateDisplayName { crate_name, canonical_name }
122 }
123}
124
125impl fmt::Display for CrateDisplayName {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 write!(f, "{}", self.crate_name)
128 }
129}