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.lock64
-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/fill_match_arms.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs6
-rw-r--r--crates/assists/src/handlers/generate_from_impl_for_enum.rs2
-rw-r--r--crates/assists/src/handlers/qualify_path.rs1048
-rw-r--r--crates/assists/src/handlers/replace_string_with_char.rs141
-rw-r--r--crates/assists/src/lib.rs4
-rw-r--r--crates/assists/src/tests/generated.rs36
-rw-r--r--crates/assists/src/utils.rs25
-rw-r--r--crates/assists/src/utils/import_assets.rs40
-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/call_info/Cargo.toml26
-rw-r--r--crates/call_info/src/lib.rs (renamed from crates/ide/src/call_info.rs)47
-rw-r--r--crates/completion/Cargo.toml32
-rw-r--r--crates/completion/src/complete_attribute.rs (renamed from crates/ide/src/completion/complete_attribute.rs)135
-rw-r--r--crates/completion/src/complete_dot.rs (renamed from crates/ide/src/completion/complete_dot.rs)19
-rw-r--r--crates/completion/src/complete_fn_param.rs (renamed from crates/ide/src/completion/complete_fn_param.rs)4
-rw-r--r--crates/completion/src/complete_keyword.rs (renamed from crates/ide/src/completion/complete_keyword.rs)8
-rw-r--r--crates/completion/src/complete_macro_in_item_position.rs (renamed from crates/ide/src/completion/complete_macro_in_item_position.rs)6
-rw-r--r--crates/completion/src/complete_mod.rs (renamed from crates/ide/src/completion/complete_mod.rs)2
-rw-r--r--crates/completion/src/complete_pattern.rs (renamed from crates/ide/src/completion/complete_pattern.rs)6
-rw-r--r--crates/completion/src/complete_postfix.rs (renamed from crates/ide/src/completion/complete_postfix.rs)12
-rw-r--r--crates/completion/src/complete_postfix/format_like.rs (renamed from crates/ide/src/completion/complete_postfix/format_like.rs)2
-rw-r--r--crates/completion/src/complete_qualified_path.rs (renamed from crates/ide/src/completion/complete_qualified_path.rs)4
-rw-r--r--crates/completion/src/complete_record.rs (renamed from crates/ide/src/completion/complete_record.rs)4
-rw-r--r--crates/completion/src/complete_snippet.rs (renamed from crates/ide/src/completion/complete_snippet.rs)6
-rw-r--r--crates/completion/src/complete_trait_impl.rs (renamed from crates/ide/src/completion/complete_trait_impl.rs)13
-rw-r--r--crates/completion/src/complete_unqualified_path.rs (renamed from crates/ide/src/completion/complete_unqualified_path.rs)4
-rw-r--r--crates/completion/src/completion_config.rs (renamed from crates/ide/src/completion/completion_config.rs)0
-rw-r--r--crates/completion/src/completion_context.rs (renamed from crates/ide/src/completion/completion_context.rs)40
-rw-r--r--crates/completion/src/completion_item.rs (renamed from crates/ide/src/completion/completion_item.rs)10
-rw-r--r--crates/completion/src/generated_lint_completions.rs5
-rw-r--r--crates/completion/src/lib.rs (renamed from crates/ide/src/completion.rs)77
-rw-r--r--crates/completion/src/patterns.rs (renamed from crates/ide/src/completion/patterns.rs)48
-rw-r--r--crates/completion/src/presentation.rs (renamed from crates/ide/src/completion/presentation.rs)19
-rw-r--r--crates/completion/src/test_utils.rs (renamed from crates/ide/src/completion/test_utils.rs)55
-rw-r--r--crates/hir/src/code_model.rs6
-rw-r--r--crates/hir/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/body.rs6
-rw-r--r--crates/hir_def/src/diagnostics.rs34
-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/nameres.rs21
-rw-r--r--crates/hir_def/src/nameres/collector.rs13
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_ty/src/diagnostics.rs55
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/call_hierarchy.rs4
-rw-r--r--crates/ide/src/completion/generated_features.rs4
-rw-r--r--crates/ide/src/diagnostics.rs89
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs32
-rw-r--r--crates/ide/src/display.rs81
-rw-r--r--crates/ide/src/doc_links.rs8
-rw-r--r--crates/ide/src/hover.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs24
-rw-r--r--crates/ide/src/lib.rs10
-rw-r--r--crates/ide/src/prime_caches.rs3
-rw-r--r--crates/ide/src/status.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs6
-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.toml2
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs8
-rw-r--r--crates/rust-analyzer/src/handlers.rs14
-rw-r--r--crates/syntax/src/ast/make.rs3
-rw-r--r--crates/syntax/src/display.rs83
-rw-r--r--crates/syntax/src/lib.rs1
-rw-r--r--docs/user/generated_diagnostic.adoc105
-rw-r--r--docs/user/manual.adoc4
-rw-r--r--editors/code/rust.tmGrammar.json45
-rw-r--r--editors/code/src/run.ts4
-rw-r--r--xtask/src/codegen.rs9
-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_lint_completions.rs113
-rw-r--r--xtask/src/codegen/gen_parser_tests.rs2
-rw-r--r--xtask/src/release.rs9
-rw-r--r--xtask/tests/tidy.rs11
86 files changed, 2462 insertions, 551 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 7a77ed722..65c8de719 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,6 +128,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
128checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 128checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
129 129
130[[package]] 130[[package]]
131name = "call_info"
132version = "0.0.0"
133dependencies = [
134 "base_db",
135 "either",
136 "expect-test",
137 "hir",
138 "ide_db",
139 "stdx",
140 "syntax",
141 "test_utils",
142]
143
144[[package]]
131name = "cargo_metadata" 145name = "cargo_metadata"
132version = "0.11.4" 146version = "0.11.4"
133source = "registry+https://github.com/rust-lang/crates.io-index" 147source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -250,6 +264,26 @@ dependencies = [
250] 264]
251 265
252[[package]] 266[[package]]
267name = "completion"
268version = "0.0.0"
269dependencies = [
270 "assists",
271 "base_db",
272 "call_info",
273 "expect-test",
274 "hir",
275 "ide_db",
276 "itertools",
277 "log",
278 "profile",
279 "rustc-hash",
280 "stdx",
281 "syntax",
282 "test_utils",
283 "text_edit",
284]
285
286[[package]]
253name = "const_fn" 287name = "const_fn"
254version = "0.4.2" 288version = "0.4.2"
255source = "registry+https://github.com/rust-lang/crates.io-index" 289source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -362,9 +396,9 @@ dependencies = [
362 396
363[[package]] 397[[package]]
364name = "env_logger" 398name = "env_logger"
365version = "0.7.1" 399version = "0.8.1"
366source = "registry+https://github.com/rust-lang/crates.io-index" 400source = "registry+https://github.com/rust-lang/crates.io-index"
367checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 401checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
368dependencies = [ 402dependencies = [
369 "log", 403 "log",
370] 404]
@@ -609,7 +643,9 @@ version = "0.0.0"
609dependencies = [ 643dependencies = [
610 "assists", 644 "assists",
611 "base_db", 645 "base_db",
646 "call_info",
612 "cfg", 647 "cfg",
648 "completion",
613 "either", 649 "either",
614 "expect-test", 650 "expect-test",
615 "hir", 651 "hir",
@@ -796,9 +832,9 @@ dependencies = [
796 832
797[[package]] 833[[package]]
798name = "lsp-server" 834name = "lsp-server"
799version = "0.4.0" 835version = "0.4.1"
800source = "registry+https://github.com/rust-lang/crates.io-index" 836source = "registry+https://github.com/rust-lang/crates.io-index"
801checksum = "ff7452ee21b8de64f10ceb4e9fee1212e1a9579cd717226613333e751676c86a" 837checksum = "9c85acaf36c53bf15da2b8b35afeea56747707261f59eb0b77229081dd72b04e"
802dependencies = [ 838dependencies = [
803 "crossbeam-channel 0.5.0", 839 "crossbeam-channel 0.5.0",
804 "log", 840 "log",
@@ -1441,18 +1477,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1441 1477
1442[[package]] 1478[[package]]
1443name = "serde" 1479name = "serde"
1444version = "1.0.116" 1480version = "1.0.117"
1445source = "registry+https://github.com/rust-lang/crates.io-index" 1481source = "registry+https://github.com/rust-lang/crates.io-index"
1446checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" 1482checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
1447dependencies = [ 1483dependencies = [
1448 "serde_derive", 1484 "serde_derive",
1449] 1485]
1450 1486
1451[[package]] 1487[[package]]
1452name = "serde_derive" 1488name = "serde_derive"
1453version = "1.0.116" 1489version = "1.0.117"
1454source = "registry+https://github.com/rust-lang/crates.io-index" 1490source = "registry+https://github.com/rust-lang/crates.io-index"
1455checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" 1491checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
1456dependencies = [ 1492dependencies = [
1457 "proc-macro2", 1493 "proc-macro2",
1458 "quote", 1494 "quote",
@@ -1532,9 +1568,9 @@ version = "0.0.0"
1532 1568
1533[[package]] 1569[[package]]
1534name = "syn" 1570name = "syn"
1535version = "1.0.44" 1571version = "1.0.45"
1536source = "registry+https://github.com/rust-lang/crates.io-index" 1572source = "registry+https://github.com/rust-lang/crates.io-index"
1537checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" 1573checksum = "ea9c5432ff16d6152371f808fb5a871cd67368171b09bb21b43df8e4a47a3556"
1538dependencies = [ 1574dependencies = [
1539 "proc-macro2", 1575 "proc-macro2",
1540 "quote", 1576 "quote",
@@ -1916,18 +1952,18 @@ dependencies = [
1916 1952
1917[[package]] 1953[[package]]
1918name = "xshell" 1954name = "xshell"
1919version = "0.1.0" 1955version = "0.1.6"
1920source = "registry+https://github.com/rust-lang/crates.io-index" 1956source = "registry+https://github.com/rust-lang/crates.io-index"
1921checksum = "1f7f756f2faab73adb00db44db716598ab2c9e4bce4a875c053022291bd3cab4" 1957checksum = "3e9bbfccbb2233e6b0473b7870d4b0811a402e9e249a5e8394e768e5a5c9c37d"
1922dependencies = [ 1958dependencies = [
1923 "xshell-macros", 1959 "xshell-macros",
1924] 1960]
1925 1961
1926[[package]] 1962[[package]]
1927name = "xshell-macros" 1963name = "xshell-macros"
1928version = "0.1.0" 1964version = "0.1.6"
1929source = "registry+https://github.com/rust-lang/crates.io-index" 1965source = "registry+https://github.com/rust-lang/crates.io-index"
1930checksum = "51b020c2f3132b34067e2f6ebc58f0f210624898713a8186b8cdb75d3b8c3001" 1966checksum = "b94f1c632d730a1704b21dc551a4c74fbed713cfa59593708f94943548206134"
1931 1967
1932[[package]] 1968[[package]]
1933name = "xtask" 1969name = "xtask"
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/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..66f74150c 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; 1use base_db::FileId;
2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
3use syntax::{ast, AstNode, TextRange, TextSize}; 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/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/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/lib.rs b/crates/assists/src/lib.rs
index a2bec818c..8a664f654 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -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,6 +198,7 @@ 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, 203 raw_string::make_raw_string,
201 raw_string::make_usual_string, 204 raw_string::make_usual_string,
@@ -208,6 +211,7 @@ mod handlers {
208 replace_impl_trait_with_generic::replace_impl_trait_with_generic, 211 replace_impl_trait_with_generic::replace_impl_trait_with_generic,
209 replace_let_with_if_let::replace_let_with_if_let, 212 replace_let_with_if_let::replace_let_with_if_let,
210 replace_qualified_name_with_use::replace_qualified_name_with_use, 213 replace_qualified_name_with_use::replace_qualified_name_with_use,
214 replace_string_with_char::replace_string_with_char,
211 replace_unwrap_with_match::replace_unwrap_with_match, 215 replace_unwrap_with_match::replace_unwrap_with_match,
212 split_import::split_import, 216 split_import::split_import,
213 unwrap_block::unwrap_block, 217 unwrap_block::unwrap_block,
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..1a6b48b45 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -275,7 +275,7 @@ impl TryEnum {
275/// somewhat similar to the known paths infra inside hir, but it different; We 275/// 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 276/// want to make sure that IDE specific paths don't become interesting inside
277/// the compiler itself as well. 277/// the compiler itself as well.
278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate); 278pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
279 279
280#[allow(non_snake_case)] 280#[allow(non_snake_case)]
281impl FamousDefs<'_, '_> { 281impl FamousDefs<'_, '_> {
@@ -362,6 +362,10 @@ pub mod prelude {
362pub use prelude::*; 362pub use prelude::*;
363"#; 363"#;
364 364
365 pub fn core(&self) -> Option<Crate> {
366 self.find_crate("core")
367 }
368
365 pub(crate) fn core_convert_From(&self) -> Option<Trait> { 369 pub(crate) fn core_convert_From(&self) -> Option<Trait> {
366 self.find_trait("core:convert:From") 370 self.find_trait("core:convert:From")
367 } 371 }
@@ -399,21 +403,20 @@ pub use prelude::*;
399 } 403 }
400 } 404 }
401 405
406 fn find_crate(&self, name: &str) -> Option<Crate> {
407 let krate = self.1?;
408 let db = self.0.db;
409 let res =
410 krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
411 Some(res)
412 }
413
402 fn find_def(&self, path: &str) -> Option<ScopeDef> { 414 fn find_def(&self, path: &str) -> Option<ScopeDef> {
403 let db = self.0.db; 415 let db = self.0.db;
404 let mut path = path.split(':'); 416 let mut path = path.split(':');
405 let trait_ = path.next_back()?; 417 let trait_ = path.next_back()?;
406 let std_crate = path.next()?; 418 let std_crate = path.next()?;
407 let std_crate = if self 419 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); 420 let mut module = std_crate.root_module(db);
418 for segment in path { 421 for segment in path {
419 module = module.children(db).find_map(|child| { 422 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/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}
130
131impl ops::Deref for CrateDisplayName {
132 type Target = str;
133 fn deref(&self) -> &str {
134 &*self.crate_name
135 }
136}
137
138impl CrateDisplayName {
139 pub fn from_canonical_name(canonical_name: String) -> CrateDisplayName {
140 let crate_name = CrateName::normalize_dashes(&canonical_name);
141 CrateDisplayName { crate_name, canonical_name }
142 }
143}
144
110#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 145#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
111pub struct ProcMacroId(pub u32); 146pub struct ProcMacroId(pub u32);
112 147
@@ -127,11 +162,13 @@ impl PartialEq for ProcMacro {
127pub struct CrateData { 162pub struct CrateData {
128 pub root_file_id: FileId, 163 pub root_file_id: FileId,
129 pub edition: Edition, 164 pub edition: Edition,
130 /// A name used in the package's project declaration: for Cargo projects, it's [package].name, 165 /// A name used in the package's project declaration: for Cargo projects,
131 /// can be different for other project types or even absent (a dummy crate for the code snippet, for example). 166 /// it's [package].name, can be different for other project types or even
132 /// NOTE: The crate can be referenced as a dependency under a different name, 167 /// absent (a dummy crate for the code snippet, for example).
133 /// this one should be used when working with crate hierarchies. 168 ///
134 pub declaration_name: Option<CrateName>, 169 /// For purposes of analysis, crates are anonymous (only names in
170 /// `Dependency` matters), this name should only be used for UI.
171 pub display_name: Option<CrateDisplayName>,
135 pub cfg_options: CfgOptions, 172 pub cfg_options: CfgOptions,
136 pub env: Env, 173 pub env: Env,
137 pub dependencies: Vec<Dependency>, 174 pub dependencies: Vec<Dependency>,
@@ -160,7 +197,7 @@ impl CrateGraph {
160 &mut self, 197 &mut self,
161 file_id: FileId, 198 file_id: FileId,
162 edition: Edition, 199 edition: Edition,
163 declaration_name: Option<CrateName>, 200 display_name: Option<CrateDisplayName>,
164 cfg_options: CfgOptions, 201 cfg_options: CfgOptions,
165 env: Env, 202 env: Env,
166 proc_macro: Vec<(SmolStr, Arc<dyn tt::TokenExpander>)>, 203 proc_macro: Vec<(SmolStr, Arc<dyn tt::TokenExpander>)>,
@@ -171,7 +208,7 @@ impl CrateGraph {
171 let data = CrateData { 208 let data = CrateData {
172 root_file_id: file_id, 209 root_file_id: file_id,
173 edition, 210 edition,
174 declaration_name, 211 display_name,
175 cfg_options, 212 cfg_options,
176 env, 213 env,
177 proc_macro, 214 proc_macro,
@@ -290,6 +327,29 @@ impl CrateGraph {
290 } 327 }
291 false 328 false
292 } 329 }
330
331 // Work around for https://github.com/rust-analyzer/rust-analyzer/issues/6038.
332 // As hacky as it gets.
333 pub fn patch_cfg_if(&mut self) -> bool {
334 let cfg_if = self.hacky_find_crate("cfg_if");
335 let std = self.hacky_find_crate("std");
336 match (cfg_if, std) {
337 (Some(cfg_if), Some(std)) => {
338 self.arena.get_mut(&cfg_if).unwrap().dependencies.clear();
339 self.arena
340 .get_mut(&std)
341 .unwrap()
342 .dependencies
343 .push(Dependency { crate_id: cfg_if, name: CrateName::new("cfg_if").unwrap() });
344 true
345 }
346 _ => false,
347 }
348 }
349
350 fn hacky_find_crate(&self, display_name: &str) -> Option<CrateId> {
351 self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name))
352 }
293} 353}
294 354
295impl ops::Index<CrateId> for CrateGraph { 355impl ops::Index<CrateId> for CrateGraph {
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index e38aa7257..0804202d6 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -13,8 +13,8 @@ pub use crate::{
13 cancellation::Canceled, 13 cancellation::Canceled,
14 change::Change, 14 change::Change,
15 input::{ 15 input::{
16 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, 16 CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
17 SourceRoot, SourceRootId, 17 FileId, ProcMacroId, SourceRoot, SourceRootId,
18 }, 18 },
19}; 19};
20pub use salsa; 20pub use salsa;
diff --git a/crates/call_info/Cargo.toml b/crates/call_info/Cargo.toml
new file mode 100644
index 000000000..98c0bd6db
--- /dev/null
+++ b/crates/call_info/Cargo.toml
@@ -0,0 +1,26 @@
1[package]
2name = "call_info"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13either = "1.5.3"
14
15stdx = { path = "../stdx", version = "0.0.0" }
16syntax = { path = "../syntax", version = "0.0.0" }
17base_db = { path = "../base_db", version = "0.0.0" }
18ide_db = { path = "../ide_db", version = "0.0.0" }
19test_utils = { path = "../test_utils", version = "0.0.0" }
20
21# call_info crate should depend only on the top-level `hir` package. if you need
22# something from some `hir_xxx` subpackage, reexport the API via `hir`.
23hir = { path = "../hir", version = "0.0.0" }
24
25[dev-dependencies]
26expect-test = "1.0"
diff --git a/crates/ide/src/call_info.rs b/crates/call_info/src/lib.rs
index d7b2b926e..c45406c25 100644
--- a/crates/ide/src/call_info.rs
+++ b/crates/call_info/src/lib.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! This crate provides primitives for tracking the information about a call site.
2use base_db::FilePosition;
2use either::Either; 3use either::Either;
3use hir::{HasAttrs, HirDisplay, Semantics, Type}; 4use hir::{HasAttrs, HirDisplay, Semantics, Type};
4use ide_db::RootDatabase; 5use ide_db::RootDatabase;
@@ -9,8 +10,6 @@ use syntax::{
9}; 10};
10use test_utils::mark; 11use test_utils::mark;
11 12
12use crate::FilePosition;
13
14/// Contains information about a call site. Specifically the 13/// Contains information about a call site. Specifically the
15/// `FunctionSignature`and current parameter. 14/// `FunctionSignature`and current parameter.
16#[derive(Debug)] 15#[derive(Debug)]
@@ -40,7 +39,7 @@ impl CallInfo {
40} 39}
41 40
42/// Computes parameter information for the given call expression. 41/// Computes parameter information for the given call expression.
43pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 42pub fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
44 let sema = Semantics::new(db); 43 let sema = Semantics::new(db);
45 let file = sema.parse(position.file_id); 44 let file = sema.parse(position.file_id);
46 let file = file.syntax(); 45 let file = file.syntax();
@@ -141,13 +140,13 @@ fn call_info_impl(
141} 140}
142 141
143#[derive(Debug)] 142#[derive(Debug)]
144pub(crate) struct ActiveParameter { 143pub struct ActiveParameter {
145 pub(crate) ty: Type, 144 pub ty: Type,
146 pub(crate) name: String, 145 pub name: String,
147} 146}
148 147
149impl ActiveParameter { 148impl ActiveParameter {
150 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 149 pub fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
151 let sema = Semantics::new(db); 150 let sema = Semantics::new(db);
152 let file = sema.parse(position.file_id); 151 let file = sema.parse(position.file_id);
153 let file = file.syntax(); 152 let file = file.syntax();
@@ -156,7 +155,7 @@ impl ActiveParameter {
156 Self::at_token(&sema, token) 155 Self::at_token(&sema, token)
157 } 156 }
158 157
159 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 158 pub fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
160 let (signature, active_parameter) = call_info_impl(&sema, token)?; 159 let (signature, active_parameter) = call_info_impl(&sema, token)?;
161 160
162 let idx = active_parameter?; 161 let idx = active_parameter?;
@@ -172,7 +171,7 @@ impl ActiveParameter {
172} 171}
173 172
174#[derive(Debug)] 173#[derive(Debug)]
175pub(crate) enum FnCallNode { 174pub enum FnCallNode {
176 CallExpr(ast::CallExpr), 175 CallExpr(ast::CallExpr),
177 MethodCallExpr(ast::MethodCallExpr), 176 MethodCallExpr(ast::MethodCallExpr),
178} 177}
@@ -196,7 +195,7 @@ impl FnCallNode {
196 }) 195 })
197 } 196 }
198 197
199 pub(crate) fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> { 198 pub fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> {
200 match_ast! { 199 match_ast! {
201 match node { 200 match node {
202 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 201 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
@@ -206,7 +205,7 @@ impl FnCallNode {
206 } 205 }
207 } 206 }
208 207
209 pub(crate) fn name_ref(&self) -> Option<ast::NameRef> { 208 pub fn name_ref(&self) -> Option<ast::NameRef> {
210 match self { 209 match self {
211 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? { 210 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
212 ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?, 211 ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
@@ -229,14 +228,28 @@ impl FnCallNode {
229 228
230#[cfg(test)] 229#[cfg(test)]
231mod tests { 230mod tests {
231 use base_db::{fixture::ChangeFixture, FilePosition};
232 use expect_test::{expect, Expect}; 232 use expect_test::{expect, Expect};
233 use test_utils::mark; 233 use ide_db::RootDatabase;
234 234 use test_utils::{mark, RangeOrOffset};
235 use crate::fixture; 235
236 /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
237 pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
238 let change_fixture = ChangeFixture::parse(ra_fixture);
239 let mut database = RootDatabase::default();
240 database.apply_change(change_fixture.change);
241 let (file_id, range_or_offset) =
242 change_fixture.file_position.expect("expected a marker (<|>)");
243 let offset = match range_or_offset {
244 RangeOrOffset::Range(_) => panic!(),
245 RangeOrOffset::Offset(it) => it,
246 };
247 (database, FilePosition { file_id, offset })
248 }
236 249
237 fn check(ra_fixture: &str, expect: Expect) { 250 fn check(ra_fixture: &str, expect: Expect) {
238 let (analysis, position) = fixture::position(ra_fixture); 251 let (db, position) = position(ra_fixture);
239 let call_info = analysis.call_info(position).unwrap(); 252 let call_info = crate::call_info(&db, position);
240 let actual = match call_info { 253 let actual = match call_info {
241 Some(call_info) => { 254 Some(call_info) => {
242 let docs = match &call_info.doc { 255 let docs = match &call_info.doc {
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
new file mode 100644
index 000000000..25192456a
--- /dev/null
+++ b/crates/completion/Cargo.toml
@@ -0,0 +1,32 @@
1[package]
2name = "completion"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13itertools = "0.9.0"
14log = "0.4.8"
15rustc-hash = "1.1.0"
16
17stdx = { path = "../stdx", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" }
19text_edit = { path = "../text_edit", version = "0.0.0" }
20base_db = { path = "../base_db", version = "0.0.0" }
21ide_db = { path = "../ide_db", version = "0.0.0" }
22profile = { path = "../profile", version = "0.0.0" }
23test_utils = { path = "../test_utils", version = "0.0.0" }
24assists = { path = "../assists", version = "0.0.0" }
25call_info = { path = "../call_info", version = "0.0.0" }
26
27# completions crate should depend only on the top-level `hir` package. if you need
28# something from some `hir_xxx` subpackage, reexport the API via `hir`.
29hir = { path = "../hir", version = "0.0.0" }
30
31[dev-dependencies]
32expect-test = "1.0"
diff --git a/crates/ide/src/completion/complete_attribute.rs b/crates/completion/src/complete_attribute.rs
index f4a9864d1..f97ab7dd0 100644
--- a/crates/ide/src/completion/complete_attribute.rs
+++ b/crates/completion/src/complete_attribute.rs
@@ -6,10 +6,10 @@
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7use syntax::{ast, AstNode, SyntaxKind}; 7use syntax::{ast, AstNode, SyntaxKind};
8 8
9use crate::completion::{ 9use crate::{
10 completion_context::CompletionContext, 10 completion_context::CompletionContext,
11 completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions}, 11 completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
12 generated_features::FEATURES, 12 generated_lint_completions::{CLIPPY_LINTS, FEATURES},
13}; 13};
14 14
15pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 15pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -23,14 +23,15 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
23 complete_derive(acc, ctx, token_tree) 23 complete_derive(acc, ctx, token_tree)
24 } 24 }
25 (Some(path), Some(token_tree)) if path.to_string() == "feature" => { 25 (Some(path), Some(token_tree)) if path.to_string() == "feature" => {
26 complete_lint(acc, ctx, token_tree, FEATURES) 26 complete_lint(acc, ctx, token_tree, FEATURES);
27 } 27 }
28 (Some(path), Some(token_tree)) 28 (Some(path), Some(token_tree))
29 if ["allow", "warn", "deny", "forbid"] 29 if ["allow", "warn", "deny", "forbid"]
30 .iter() 30 .iter()
31 .any(|lint_level| lint_level == &path.to_string()) => 31 .any(|lint_level| lint_level == &path.to_string()) =>
32 { 32 {
33 complete_lint(acc, ctx, token_tree, DEFAULT_LINT_COMPLETIONS) 33 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
34 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
34 } 35 }
35 (_, Some(_token_tree)) => {} 36 (_, Some(_token_tree)) => {}
36 _ => complete_attribute_start(acc, ctx, attribute), 37 _ => complete_attribute_start(acc, ctx, attribute),
@@ -389,7 +390,7 @@ const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
389mod tests { 390mod tests {
390 use expect_test::{expect, Expect}; 391 use expect_test::{expect, Expect};
391 392
392 use crate::completion::{test_utils::completion_list, CompletionKind}; 393 use crate::{test_utils::completion_list, CompletionKind};
393 394
394 fn check(ra_fixture: &str, expect: Expect) { 395 fn check(ra_fixture: &str, expect: Expect) {
395 let actual = completion_list(ra_fixture, CompletionKind::Attribute); 396 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
@@ -418,130 +419,6 @@ struct Test {}
418 } 419 }
419 420
420 #[test] 421 #[test]
421 fn empty_lint_completion() {
422 check(
423 r#"#[allow(<|>)]"#,
424 expect![[r#"
425 at absolute_paths_not_starting_with_crate fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
426 at ambiguous_associated_items ambiguous associated items
427 at anonymous_parameters detects anonymous parameters
428 at arithmetic_overflow arithmetic operation overflows
429 at array_into_iter detects calling `into_iter` on arrays
430 at asm_sub_register using only a subset of a register for inline asm inputs
431 at bare_trait_objects suggest using `dyn Trait` for trait objects
432 at bindings_with_variant_name detects pattern bindings with the same name as one of the matched variants
433 at box_pointers use of owned (Box type) heap memory
434 at cenum_impl_drop_cast a C-like enum implementing Drop is cast
435 at clashing_extern_declarations detects when an extern fn has been declared with the same name but different types
436 at coherence_leak_check distinct impls distinguished only by the leak-check code
437 at conflicting_repr_hints conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
438 at confusable_idents detects visually confusable pairs between identifiers
439 at const_err constant evaluation detected erroneous expression
440 at dead_code detect unused, unexported items
441 at deprecated detects use of deprecated items
442 at deprecated_in_future detects use of items that will be deprecated in a future version
443 at elided_lifetimes_in_paths hidden lifetime parameters in types are deprecated
444 at ellipsis_inclusive_range_patterns `...` range patterns are deprecated
445 at explicit_outlives_requirements outlives requirements can be inferred
446 at exported_private_dependencies public interface leaks type from a private dependency
447 at ill_formed_attribute_input ill-formed attribute inputs that were previously accepted and used in practice
448 at illegal_floating_point_literal_pattern floating-point literals cannot be used in patterns
449 at improper_ctypes proper use of libc types in foreign modules
450 at improper_ctypes_definitions proper use of libc types in foreign item definitions
451 at incomplete_features incomplete features that may function improperly in some or all cases
452 at incomplete_include trailing content in included file
453 at indirect_structural_match pattern with const indirectly referencing non-structural-match type
454 at inline_no_sanitize detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
455 at intra_doc_link_resolution_failure failures in resolving intra-doc link targets
456 at invalid_codeblock_attributes codeblock attribute looks a lot like a known one
457 at invalid_type_param_default type parameter default erroneously allowed in invalid location
458 at invalid_value an invalid value is being created (such as a NULL reference)
459 at irrefutable_let_patterns detects irrefutable patterns in if-let and while-let statements
460 at keyword_idents detects edition keywords being used as an identifier
461 at late_bound_lifetime_arguments detects generic lifetime arguments in path segments with late bound lifetime parameters
462 at macro_expanded_macro_exports_accessed_by_absolute_paths macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
463 at macro_use_extern_crate the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
464 at meta_variable_misuse possible meta-variable misuse at macro definition
465 at missing_copy_implementations detects potentially-forgotten implementations of `Copy`
466 at missing_crate_level_docs detects crates with no crate-level documentation
467 at missing_debug_implementations detects missing implementations of Debug
468 at missing_doc_code_examples detects publicly-exported items without code samples in their documentation
469 at missing_docs detects missing documentation for public members
470 at missing_fragment_specifier detects missing fragment specifiers in unused `macro_rules!` patterns
471 at mixed_script_confusables detects Unicode scripts whose mixed script confusables codepoints are solely used
472 at mutable_borrow_reservation_conflict reservation of a two-phased borrow conflicts with other shared borrows
473 at mutable_transmutes mutating transmuted &mut T from &T may cause undefined behavior
474 at no_mangle_const_items const items will not have their symbols exported
475 at no_mangle_generic_items generic items must be mangled
476 at non_ascii_idents detects non-ASCII identifiers
477 at non_camel_case_types types, variants, traits and type parameters should have camel case names
478 at non_shorthand_field_patterns using `Struct { x: x }` instead of `Struct { x }` in a pattern
479 at non_snake_case variables, methods, functions, lifetime parameters and modules should have snake case names
480 at non_upper_case_globals static constants should have uppercase identifiers
481 at order_dependent_trait_objects trait-object types were treated as different depending on marker-trait order
482 at overflowing_literals literal out of range for its type
483 at overlapping_patterns detects overlapping patterns
484 at path_statements path statements with no effect
485 at patterns_in_fns_without_body patterns in functions without body were erroneously allowed
486 at private_doc_tests detects code samples in docs of private items not documented by rustdoc
487 at private_in_public detect private items in public interfaces not caught by the old implementation
488 at proc_macro_derive_resolution_fallback detects proc macro derives using inaccessible names from parent modules
489 at pub_use_of_private_extern_crate detect public re-exports of private extern crates
490 at redundant_semicolons detects unnecessary trailing semicolons
491 at renamed_and_removed_lints lints that have been renamed or removed
492 at safe_packed_borrows safe borrows of fields of packed structs were erroneously allowed
493 at single_use_lifetimes detects lifetime parameters that are only used once
494 at soft_unstable a feature gate that doesn't break dependent crates
495 at stable_features stable features found in `#[feature]` directive
496 at trivial_bounds these bounds don't depend on an type parameters
497 at trivial_casts detects trivial casts which could be removed
498 at trivial_numeric_casts detects trivial casts of numeric types which could be removed
499 at type_alias_bounds bounds in type aliases are not enforced
500 at tyvar_behind_raw_pointer raw pointer to an inference variable
501 at unaligned_references detects unaligned references to fields of packed structs
502 at uncommon_codepoints detects uncommon Unicode codepoints in identifiers
503 at unconditional_panic operation will cause a panic at runtime
504 at unconditional_recursion functions that cannot return without calling themselves
505 at unknown_crate_types unknown crate type found in `#[crate_type]` directive
506 at unknown_lints unrecognized lint attribute
507 at unnameable_test_items detects an item that cannot be named being marked as `#[test_case]`
508 at unreachable_code detects unreachable code paths
509 at unreachable_patterns detects unreachable patterns
510 at unreachable_pub `pub` items not reachable from crate root
511 at unsafe_code usage of `unsafe` code
512 at unsafe_op_in_unsafe_fn unsafe operations in unsafe functions without an explicit unsafe block are deprecated
513 at unstable_features enabling unstable features (deprecated. do not use)
514 at unstable_name_collisions detects name collision with an existing but unstable method
515 at unused_allocation detects unnecessary allocations that can be eliminated
516 at unused_assignments detect assignments that will never be read
517 at unused_attributes detects attributes that were not used by the compiler
518 at unused_braces unnecessary braces around an expression
519 at unused_comparisons comparisons made useless by limits of the types involved
520 at unused_crate_dependencies crate dependencies that are never used
521 at unused_doc_comments detects doc comments that aren't used by rustdoc
522 at unused_extern_crates extern crates that are never used
523 at unused_features unused features found in crate-level `#[feature]` directives
524 at unused_import_braces unnecessary braces around an imported item
525 at unused_imports imports that are never used
526 at unused_labels detects labels that are never used
527 at unused_lifetimes detects lifetime parameters that are never used
528 at unused_macros detects macros that were not used
529 at unused_must_use unused result of a type flagged as `#[must_use]`
530 at unused_mut detect mut variables which don't need to be mutable
531 at unused_parens `if`, `match`, `while` and `return` do not need parentheses
532 at unused_qualifications detects unnecessarily qualified names
533 at unused_results unused result of an expression in a statement
534 at unused_unsafe unnecessary use of an `unsafe` block
535 at unused_variables detect variables which are not used in any way
536 at variant_size_differences detects enums with widely varying variant sizes
537 at warnings mass-change the level for lints which produce warnings
538 at where_clauses_object_safety checks the object safety of where clauses
539 at while_true suggest using `loop { }` instead of `while true { }`
540 "#]],
541 )
542 }
543
544 #[test]
545 fn no_completion_for_incorrect_derive() { 422 fn no_completion_for_incorrect_derive() {
546 check( 423 check(
547 r#" 424 r#"
diff --git a/crates/ide/src/completion/complete_dot.rs b/crates/completion/src/complete_dot.rs
index 0b9f1798a..0eabb48ae 100644
--- a/crates/ide/src/completion/complete_dot.rs
+++ b/crates/completion/src/complete_dot.rs
@@ -4,7 +4,7 @@ use hir::{HasVisibility, Type};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::completion::{completion_context::CompletionContext, completion_item::Completions}; 7use crate::{completion_context::CompletionContext, completion_item::Completions};
8 8
9/// Complete dot accesses, i.e. fields or methods. 9/// Complete dot accesses, i.e. fields or methods.
10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -64,7 +64,7 @@ mod tests {
64 use expect_test::{expect, Expect}; 64 use expect_test::{expect, Expect};
65 use test_utils::mark; 65 use test_utils::mark;
66 66
67 use crate::completion::{test_utils::completion_list, CompletionKind}; 67 use crate::{test_utils::completion_list, CompletionKind};
68 68
69 fn check(ra_fixture: &str, expect: Expect) { 69 fn check(ra_fixture: &str, expect: Expect) {
70 let actual = completion_list(ra_fixture, CompletionKind::Reference); 70 let actual = completion_list(ra_fixture, CompletionKind::Reference);
@@ -413,4 +413,19 @@ fn foo() {
413 "#]], 413 "#]],
414 ); 414 );
415 } 415 }
416
417 #[test]
418 fn completes_method_call_when_receiver_is_a_macro_call() {
419 check(
420 r#"
421struct S;
422impl S { fn foo(&self) {} }
423macro_rules! make_s { () => { S }; }
424fn main() { make_s!().f<|>; }
425"#,
426 expect![[r#"
427 me foo() fn foo(&self)
428 "#]],
429 )
430 }
416} 431}
diff --git a/crates/ide/src/completion/complete_fn_param.rs b/crates/completion/src/complete_fn_param.rs
index 9efe25461..918996727 100644
--- a/crates/ide/src/completion/complete_fn_param.rs
+++ b/crates/completion/src/complete_fn_param.rs
@@ -6,7 +6,7 @@ use syntax::{
6 match_ast, AstNode, 6 match_ast, AstNode,
7}; 7};
8 8
9use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::{CompletionContext, CompletionItem, CompletionKind, Completions};
10 10
11/// Complete repeated parameters, both name and type. For example, if all 11/// Complete repeated parameters, both name and type. For example, if all
12/// functions in a file have a `spam: &mut Spam` parameter, a completion with 12/// functions in a file have a `spam: &mut Spam` parameter, a completion with
@@ -68,7 +68,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
68mod tests { 68mod tests {
69 use expect_test::{expect, Expect}; 69 use expect_test::{expect, Expect};
70 70
71 use crate::completion::{test_utils::completion_list, CompletionKind}; 71 use crate::{test_utils::completion_list, CompletionKind};
72 72
73 fn check(ra_fixture: &str, expect: Expect) { 73 fn check(ra_fixture: &str, expect: Expect) {
74 let actual = completion_list(ra_fixture, CompletionKind::Magic); 74 let actual = completion_list(ra_fixture, CompletionKind::Magic);
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/completion/src/complete_keyword.rs
index e59747095..ace914f3f 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/completion/src/complete_keyword.rs
@@ -1,11 +1,9 @@
1//! FIXME: write short doc here 1//! Completes keywords.
2 2
3use syntax::{ast, SyntaxKind}; 3use syntax::{ast, SyntaxKind};
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::completion::{ 6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
7 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
8};
9 7
10pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 8pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
11 // complete keyword "crate" in use stmt 9 // complete keyword "crate" in use stmt
@@ -177,7 +175,7 @@ fn complete_return(
177mod tests { 175mod tests {
178 use expect_test::{expect, Expect}; 176 use expect_test::{expect, Expect};
179 177
180 use crate::completion::{ 178 use crate::{
181 test_utils::{check_edit, completion_list}, 179 test_utils::{check_edit, completion_list},
182 CompletionKind, 180 CompletionKind,
183 }; 181 };
diff --git a/crates/ide/src/completion/complete_macro_in_item_position.rs b/crates/completion/src/complete_macro_in_item_position.rs
index fc8625d8e..d1d8c23d2 100644
--- a/crates/ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/completion/src/complete_macro_in_item_position.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! Completes macro invocations used in item position.
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
@@ -17,7 +17,7 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
17mod tests { 17mod tests {
18 use expect_test::{expect, Expect}; 18 use expect_test::{expect, Expect};
19 19
20 use crate::completion::{test_utils::completion_list, CompletionKind}; 20 use crate::{test_utils::completion_list, CompletionKind};
21 21
22 fn check(ra_fixture: &str, expect: Expect) { 22 fn check(ra_fixture: &str, expect: Expect) {
23 let actual = completion_list(ra_fixture, CompletionKind::Reference); 23 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_mod.rs b/crates/completion/src/complete_mod.rs
index c7a99bdc3..35a57aba3 100644
--- a/crates/ide/src/completion/complete_mod.rs
+++ b/crates/completion/src/complete_mod.rs
@@ -150,7 +150,7 @@ fn module_chain_to_containing_module_file(
150 150
151#[cfg(test)] 151#[cfg(test)]
152mod tests { 152mod tests {
153 use crate::completion::{test_utils::completion_list, CompletionKind}; 153 use crate::{test_utils::completion_list, CompletionKind};
154 use expect_test::{expect, Expect}; 154 use expect_test::{expect, Expect};
155 155
156 fn check(ra_fixture: &str, expect: Expect) { 156 fn check(ra_fixture: &str, expect: Expect) {
diff --git a/crates/ide/src/completion/complete_pattern.rs b/crates/completion/src/complete_pattern.rs
index 5a13574d4..5606dcdd9 100644
--- a/crates/ide/src/completion/complete_pattern.rs
+++ b/crates/completion/src/complete_pattern.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! Completes constats and paths in patterns.
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::{CompletionContext, Completions};
4 4
5/// Completes constats and paths in patterns. 5/// Completes constats and paths in patterns.
6pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
@@ -35,7 +35,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
35mod tests { 35mod tests {
36 use expect_test::{expect, Expect}; 36 use expect_test::{expect, Expect};
37 37
38 use crate::completion::{test_utils::completion_list, CompletionKind}; 38 use crate::{test_utils::completion_list, CompletionKind};
39 39
40 fn check(ra_fixture: &str, expect: Expect) { 40 fn check(ra_fixture: &str, expect: Expect) {
41 let actual = completion_list(ra_fixture, CompletionKind::Reference); 41 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/completion/src/complete_postfix.rs
index db5319618..700573cf2 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/completion/src/complete_postfix.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Postfix completions, like `Ok(10).ifl<|>` => `if let Ok() = Ok(10) { <|> }`.
2 2
3mod format_like; 3mod format_like;
4 4
@@ -11,11 +11,9 @@ use text_edit::TextEdit;
11 11
12use self::format_like::add_format_like_completions; 12use self::format_like::add_format_like_completions;
13use crate::{ 13use crate::{
14 completion::{ 14 completion_config::SnippetCap,
15 completion_config::SnippetCap, 15 completion_context::CompletionContext,
16 completion_context::CompletionContext, 16 completion_item::{Builder, CompletionKind, Completions},
17 completion_item::{Builder, CompletionKind, Completions},
18 },
19 CompletionItem, CompletionItemKind, 17 CompletionItem, CompletionItemKind,
20}; 18};
21 19
@@ -263,7 +261,7 @@ fn postfix_snippet(
263mod tests { 261mod tests {
264 use expect_test::{expect, Expect}; 262 use expect_test::{expect, Expect};
265 263
266 use crate::completion::{ 264 use crate::{
267 test_utils::{check_edit, completion_list}, 265 test_utils::{check_edit, completion_list},
268 CompletionKind, 266 CompletionKind,
269 }; 267 };
diff --git a/crates/ide/src/completion/complete_postfix/format_like.rs b/crates/completion/src/complete_postfix/format_like.rs
index 50d1e5c81..205c384e2 100644
--- a/crates/ide/src/completion/complete_postfix/format_like.rs
+++ b/crates/completion/src/complete_postfix/format_like.rs
@@ -14,7 +14,7 @@
14// + `logw` -> `log::warn!(...)` 14// + `logw` -> `log::warn!(...)`
15// + `loge` -> `log::error!(...)` 15// + `loge` -> `log::error!(...)`
16 16
17use crate::completion::{ 17use crate::{
18 complete_postfix::postfix_snippet, completion_config::SnippetCap, 18 complete_postfix::postfix_snippet, completion_config::SnippetCap,
19 completion_context::CompletionContext, completion_item::Completions, 19 completion_context::CompletionContext, completion_item::Completions,
20}; 20};
diff --git a/crates/ide/src/completion/complete_qualified_path.rs b/crates/completion/src/complete_qualified_path.rs
index 2fafedd47..80b271fdf 100644
--- a/crates/ide/src/completion/complete_qualified_path.rs
+++ b/crates/completion/src/complete_qualified_path.rs
@@ -5,7 +5,7 @@ use rustc_hash::FxHashSet;
5use syntax::AstNode; 5use syntax::AstNode;
6use test_utils::mark; 6use test_utils::mark;
7 7
8use crate::completion::{CompletionContext, Completions}; 8use crate::{CompletionContext, Completions};
9 9
10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 10pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 let path = match &ctx.path_qual { 11 let path = match &ctx.path_qual {
@@ -149,7 +149,7 @@ mod tests {
149 use expect_test::{expect, Expect}; 149 use expect_test::{expect, Expect};
150 use test_utils::mark; 150 use test_utils::mark;
151 151
152 use crate::completion::{ 152 use crate::{
153 test_utils::{check_edit, completion_list}, 153 test_utils::{check_edit, completion_list},
154 CompletionKind, 154 CompletionKind,
155 }; 155 };
diff --git a/crates/ide/src/completion/complete_record.rs b/crates/completion/src/complete_record.rs
index ceb8d16c1..129ddc055 100644
--- a/crates/ide/src/completion/complete_record.rs
+++ b/crates/completion/src/complete_record.rs
@@ -1,5 +1,5 @@
1//! Complete fields in record literals and patterns. 1//! Complete fields in record literals and patterns.
2use crate::completion::{CompletionContext, Completions}; 2use crate::{CompletionContext, Completions};
3 3
4pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 4pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
5 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 5 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
@@ -20,7 +20,7 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
20mod tests { 20mod tests {
21 use expect_test::{expect, Expect}; 21 use expect_test::{expect, Expect};
22 22
23 use crate::completion::{test_utils::completion_list, CompletionKind}; 23 use crate::{test_utils::completion_list, CompletionKind};
24 24
25 fn check(ra_fixture: &str, expect: Expect) { 25 fn check(ra_fixture: &str, expect: Expect) {
26 let actual = completion_list(ra_fixture, CompletionKind::Reference); 26 let actual = completion_list(ra_fixture, CompletionKind::Reference);
diff --git a/crates/ide/src/completion/complete_snippet.rs b/crates/completion/src/complete_snippet.rs
index 4837d2910..06096722b 100644
--- a/crates/ide/src/completion/complete_snippet.rs
+++ b/crates/completion/src/complete_snippet.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! This file provides snippet completions, like `pd` => `eprintln!(...)`.
2 2
3use crate::completion::{ 3use crate::{
4 completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem, 4 completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem,
5 CompletionItemKind, CompletionKind, Completions, 5 CompletionItemKind, CompletionKind, Completions,
6}; 6};
@@ -71,7 +71,7 @@ fn ${1:feature}() {
71mod tests { 71mod tests {
72 use expect_test::{expect, Expect}; 72 use expect_test::{expect, Expect};
73 73
74 use crate::completion::{test_utils::completion_list, CompletionKind}; 74 use crate::{test_utils::completion_list, CompletionKind};
75 75
76 fn check(ra_fixture: &str, expect: Expect) { 76 fn check(ra_fixture: &str, expect: Expect) {
77 let actual = completion_list(ra_fixture, CompletionKind::Snippet); 77 let actual = completion_list(ra_fixture, CompletionKind::Snippet);
diff --git a/crates/ide/src/completion/complete_trait_impl.rs b/crates/completion/src/complete_trait_impl.rs
index ff115df92..c06af99e2 100644
--- a/crates/ide/src/completion/complete_trait_impl.rs
+++ b/crates/completion/src/complete_trait_impl.rs
@@ -35,15 +35,18 @@ use assists::utils::get_missing_assoc_items;
35use hir::{self, HasAttrs, HasSource}; 35use hir::{self, HasAttrs, HasSource};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration,
38 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 39 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39}; 40};
40use text_edit::TextEdit; 41use text_edit::TextEdit;
41 42
42use crate::{ 43use crate::{
43 completion::{ 44 CompletionContext,
44 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 45 CompletionItem,
45 }, 46 CompletionItemKind,
46 display::function_declaration, 47 CompletionKind,
48 Completions,
49 // display::function_declaration,
47}; 50};
48 51
49#[derive(Debug, PartialEq, Eq)] 52#[derive(Debug, PartialEq, Eq)]
@@ -237,7 +240,7 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
237mod tests { 240mod tests {
238 use expect_test::{expect, Expect}; 241 use expect_test::{expect, Expect};
239 242
240 use crate::completion::{ 243 use crate::{
241 test_utils::{check_edit, completion_list}, 244 test_utils::{check_edit, completion_list},
242 CompletionKind, 245 CompletionKind,
243 }; 246 };
diff --git a/crates/ide/src/completion/complete_unqualified_path.rs b/crates/completion/src/complete_unqualified_path.rs
index 8b6757195..5464a160d 100644
--- a/crates/ide/src/completion/complete_unqualified_path.rs
+++ b/crates/completion/src/complete_unqualified_path.rs
@@ -4,7 +4,7 @@ use hir::{Adt, ModuleDef, ScopeDef, Type};
4use syntax::AstNode; 4use syntax::AstNode;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::completion::{CompletionContext, Completions}; 7use crate::{CompletionContext, Completions};
8 8
9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -68,7 +68,7 @@ mod tests {
68 use expect_test::{expect, Expect}; 68 use expect_test::{expect, Expect};
69 use test_utils::mark; 69 use test_utils::mark;
70 70
71 use crate::completion::{ 71 use crate::{
72 test_utils::{check_edit, completion_list}, 72 test_utils::{check_edit, completion_list},
73 CompletionKind, 73 CompletionKind,
74 }; 74 };
diff --git a/crates/ide/src/completion/completion_config.rs b/crates/completion/src/completion_config.rs
index 71b49ace8..71b49ace8 100644
--- a/crates/ide/src/completion/completion_config.rs
+++ b/crates/completion/src/completion_config.rs
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/completion/src/completion_context.rs
index 8dea8a4bf..dc4e136c6 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/completion/src/completion_context.rs
@@ -1,6 +1,7 @@
1//! FIXME: write short doc here 1//! See `CompletionContext` structure.
2 2
3use base_db::SourceDatabase; 3use base_db::{FilePosition, SourceDatabase};
4use call_info::ActiveParameter;
4use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; 5use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
6use syntax::{ 7use syntax::{
@@ -13,17 +14,14 @@ use test_utils::mark;
13use text_edit::Indel; 14use text_edit::Indel;
14 15
15use crate::{ 16use crate::{
16 call_info::ActiveParameter, 17 patterns::{
17 completion::{ 18 fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
18 patterns::{ 19 has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
19 has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, 20 has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
20 has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent, 21 has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm,
21 has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev, 22 unsafe_is_prev,
22 is_in_loop_body, is_match_arm, unsafe_is_prev,
23 },
24 CompletionConfig,
25 }, 23 },
26 FilePosition, 24 CompletionConfig,
27}; 25};
28 26
29/// `CompletionContext` is created early during completion to figure out, where 27/// `CompletionContext` is created early during completion to figure out, where
@@ -86,11 +84,14 @@ pub(crate) struct CompletionContext<'a> {
86 pub(super) in_loop_body: bool, 84 pub(super) in_loop_body: bool,
87 pub(super) has_trait_parent: bool, 85 pub(super) has_trait_parent: bool,
88 pub(super) has_impl_parent: bool, 86 pub(super) has_impl_parent: bool,
87 pub(super) inside_impl_trait_block: bool,
89 pub(super) has_field_list_parent: bool, 88 pub(super) has_field_list_parent: bool,
90 pub(super) trait_as_prev_sibling: bool, 89 pub(super) trait_as_prev_sibling: bool,
91 pub(super) impl_as_prev_sibling: bool, 90 pub(super) impl_as_prev_sibling: bool,
92 pub(super) is_match_arm: bool, 91 pub(super) is_match_arm: bool,
93 pub(super) has_item_list_or_source_file_parent: bool, 92 pub(super) has_item_list_or_source_file_parent: bool,
93 pub(super) for_is_prev2: bool,
94 pub(super) fn_is_prev: bool,
94 pub(super) locals: Vec<(String, Local)>, 95 pub(super) locals: Vec<(String, Local)>,
95} 96}
96 97
@@ -168,12 +169,15 @@ impl<'a> CompletionContext<'a> {
168 block_expr_parent: false, 169 block_expr_parent: false,
169 has_trait_parent: false, 170 has_trait_parent: false,
170 has_impl_parent: false, 171 has_impl_parent: false,
172 inside_impl_trait_block: false,
171 has_field_list_parent: false, 173 has_field_list_parent: false,
172 trait_as_prev_sibling: false, 174 trait_as_prev_sibling: false,
173 impl_as_prev_sibling: false, 175 impl_as_prev_sibling: false,
174 if_is_prev: false, 176 if_is_prev: false,
175 is_match_arm: false, 177 is_match_arm: false,
176 has_item_list_or_source_file_parent: false, 178 has_item_list_or_source_file_parent: false,
179 for_is_prev2: false,
180 fn_is_prev: false,
177 locals, 181 locals,
178 }; 182 };
179 183
@@ -221,6 +225,15 @@ impl<'a> CompletionContext<'a> {
221 Some(ctx) 225 Some(ctx)
222 } 226 }
223 227
228 /// Checks whether completions in that particular case don't make much sense.
229 /// Examples:
230 /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful.
231 /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names.
232 /// - `for _ i<|>` -- obviously, it'll be "in" keyword.
233 pub(crate) fn no_completion_required(&self) -> bool {
234 (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2
235 }
236
224 /// The range of the identifier that is being completed. 237 /// The range of the identifier that is being completed.
225 pub(crate) fn source_range(&self) -> TextRange { 238 pub(crate) fn source_range(&self) -> TextRange {
226 // check kind of macro-expanded token, but use range of original token 239 // check kind of macro-expanded token, but use range of original token
@@ -244,6 +257,7 @@ impl<'a> CompletionContext<'a> {
244 self.in_loop_body = is_in_loop_body(syntax_element.clone()); 257 self.in_loop_body = is_in_loop_body(syntax_element.clone());
245 self.has_trait_parent = has_trait_parent(syntax_element.clone()); 258 self.has_trait_parent = has_trait_parent(syntax_element.clone());
246 self.has_impl_parent = has_impl_parent(syntax_element.clone()); 259 self.has_impl_parent = has_impl_parent(syntax_element.clone());
260 self.inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
247 self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); 261 self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
248 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); 262 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
249 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 263 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
@@ -253,6 +267,8 @@ impl<'a> CompletionContext<'a> {
253 self.mod_declaration_under_caret = 267 self.mod_declaration_under_caret =
254 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) 268 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
255 .filter(|module| module.item_list().is_none()); 269 .filter(|module| module.item_list().is_none());
270 self.for_is_prev2 = for_is_prev2(syntax_element.clone());
271 self.fn_is_prev = fn_is_prev(syntax_element.clone());
256 } 272 }
257 273
258 fn fill( 274 fn fill(
diff --git a/crates/ide/src/completion/completion_item.rs b/crates/completion/src/completion_item.rs
index 9377cdc57..f8be0ad2b 100644
--- a/crates/ide/src/completion/completion_item.rs
+++ b/crates/completion/src/completion_item.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! See `CompletionItem` structure.
2 2
3use std::fmt; 3use std::fmt;
4 4
@@ -6,7 +6,7 @@ use hir::Documentation;
6use syntax::TextRange; 6use syntax::TextRange;
7use text_edit::TextEdit; 7use text_edit::TextEdit;
8 8
9use crate::completion::completion_config::SnippetCap; 9use crate::completion_config::SnippetCap;
10 10
11/// `CompletionItem` describes a single completion variant in the editor pop-up. 11/// `CompletionItem` describes a single completion variant in the editor pop-up.
12/// It is basically a POD with various properties. To construct a 12/// It is basically a POD with various properties. To construct a
@@ -360,15 +360,15 @@ impl<'a> Into<CompletionItem> for Builder {
360 360
361/// Represents an in-progress set of completions being built. 361/// Represents an in-progress set of completions being built.
362#[derive(Debug, Default)] 362#[derive(Debug, Default)]
363pub(crate) struct Completions { 363pub struct Completions {
364 buf: Vec<CompletionItem>, 364 buf: Vec<CompletionItem>,
365} 365}
366 366
367impl Completions { 367impl Completions {
368 pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) { 368 pub fn add(&mut self, item: impl Into<CompletionItem>) {
369 self.buf.push(item.into()) 369 self.buf.push(item.into())
370 } 370 }
371 pub(crate) fn add_all<I>(&mut self, items: I) 371 pub fn add_all<I>(&mut self, items: I)
372 where 372 where
373 I: IntoIterator, 373 I: IntoIterator,
374 I::Item: Into<CompletionItem>, 374 I::Item: Into<CompletionItem>,
diff --git a/crates/completion/src/generated_lint_completions.rs b/crates/completion/src/generated_lint_completions.rs
new file mode 100644
index 000000000..5a7dba1f5
--- /dev/null
+++ b/crates/completion/src/generated_lint_completions.rs
@@ -0,0 +1,5 @@
1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2
3use crate::complete_attribute::LintCompletion;
4pub (super) const FEATURES : & [LintCompletion] = & [LintCompletion { label : "link_args" , description : "# `link_args`\n\nThe tracking issue for this feature is: [#29596]\n\n[#29596]: https://github.com/rust-lang/rust/issues/29596\n\n------------------------\n\nYou can tell `rustc` how to customize linking, and that is via the `link_args`\nattribute. This attribute is applied to `extern` blocks and specifies raw flags\nwhich need to get passed to the linker when producing an artifact. An example\nusage would be:\n\n```rust,no_run\n#![feature(link_args)]\n\n#[link_args = \"-foo -bar -baz\"]\nextern {}\n# fn main() {}\n```\n\nNote that this feature is currently hidden behind the `feature(link_args)` gate\nbecause this is not a sanctioned way of performing linking. Right now `rustc`\nshells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so\nit makes sense to provide extra command line arguments, but this will not\nalways be the case. In the future `rustc` may use LLVM directly to link native\nlibraries, in which case `link_args` will have no meaning. You can achieve the\nsame effect as the `link_args` attribute with the `-C link-args` argument to\n`rustc`.\n\nIt is highly recommended to *not* use this attribute, and rather use the more\nformal `#[link(...)]` attribute on `extern` blocks instead.\n" } , LintCompletion { label : "repr128" , description : "# `repr128`\n\nThe tracking issue for this feature is: [#56071]\n\n[#56071]: https://github.com/rust-lang/rust/issues/56071\n\n------------------------\n\nThe `repr128` feature adds support for `#[repr(u128)]` on `enum`s.\n\n```rust\n#![feature(repr128)]\n\n#[repr(u128)]\nenum Foo {\n Bar(u64),\n}\n```\n" } , LintCompletion { label : "crate_visibility_modifier" , description : "# `crate_visibility_modifier`\n\nThe tracking issue for this feature is: [#53120]\n\n[#53120]: https://github.com/rust-lang/rust/issues/53120\n\n-----\n\nThe `crate_visibility_modifier` feature allows the `crate` keyword to be used\nas a visibility modifier synonymous to `pub(crate)`, indicating that a type\n(function, _&c._) is to be visible to the entire enclosing crate, but not to\nother crates.\n\n```rust\n#![feature(crate_visibility_modifier)]\n\ncrate struct Foo {\n bar: usize,\n}\n```\n" } , LintCompletion { label : "doc_masked" , description : "# `doc_masked`\n\nThe tracking issue for this feature is: [#44027]\n\n-----\n\nThe `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists\nof trait implementations. The specifics of the feature are as follows:\n\n1. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute,\n it marks the crate as being masked.\n\n2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are\n not emitted into the documentation.\n\n3. When listing types that implement a given trait, rustdoc ensures that types from masked crates\n are not emitted into the documentation.\n\nThis feature was introduced in PR [#44026] to ensure that compiler-internal and\nimplementation-specific types and traits were not included in the standard library's documentation.\nSuch types would introduce broken links into the documentation.\n\n[#44026]: https://github.com/rust-lang/rust/pull/44026\n[#44027]: https://github.com/rust-lang/rust/pull/44027\n" } , LintCompletion { label : "cfg_sanitize" , description : "# `cfg_sanitize`\n\nThe tracking issue for this feature is: [#39699]\n\n[#39699]: https://github.com/rust-lang/rust/issues/39699\n\n------------------------\n\nThe `cfg_sanitize` feature makes it possible to execute different code\ndepending on whether a particular sanitizer is enabled or not.\n\n## Examples\n\n```rust\n#![feature(cfg_sanitize)]\n\n#[cfg(sanitize = \"thread\")]\nfn a() {\n // ...\n}\n\n#[cfg(not(sanitize = \"thread\"))]\nfn a() {\n // ...\n}\n\nfn b() {\n if cfg!(sanitize = \"leak\") {\n // ...\n } else {\n // ...\n }\n}\n```\n" } , LintCompletion { label : "generators" , description : "# `generators`\n\nThe tracking issue for this feature is: [#43122]\n\n[#43122]: https://github.com/rust-lang/rust/issues/43122\n\n------------------------\n\nThe `generators` feature gate in Rust allows you to define generator or\ncoroutine literals. A generator is a \"resumable function\" that syntactically\nresembles a closure but compiles to much different semantics in the compiler\nitself. The primary feature of a generator is that it can be suspended during\nexecution to be resumed at a later date. Generators use the `yield` keyword to\n\"return\", and then the caller can `resume` a generator to resume execution just\nafter the `yield` keyword.\n\nGenerators are an extra-unstable feature in the compiler right now. Added in\n[RFC 2033] they're mostly intended right now as a information/constraint\ngathering phase. The intent is that experimentation can happen on the nightly\ncompiler before actual stabilization. A further RFC will be required to\nstabilize generators/coroutines and will likely contain at least a few small\ntweaks to the overall design.\n\n[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033\n\nA syntactical example of a generator is:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n yield 1;\n return \"foo\"\n };\n\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Yielded(1) => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n match Pin::new(&mut generator).resume(()) {\n GeneratorState::Complete(\"foo\") => {}\n _ => panic!(\"unexpected value from resume\"),\n }\n}\n```\n\nGenerators are closure-like literals which can contain a `yield` statement. The\n`yield` statement takes an optional expression of a value to yield out of the\ngenerator. All generator literals implement the `Generator` trait in the\n`std::ops` module. The `Generator` trait has one main method, `resume`, which\nresumes execution of the generator at the previous suspension point.\n\nAn example of the control flow of generators is that the following example\nprints all numbers in order:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let mut generator = || {\n println!(\"2\");\n yield;\n println!(\"4\");\n };\n\n println!(\"1\");\n Pin::new(&mut generator).resume(());\n println!(\"3\");\n Pin::new(&mut generator).resume(());\n println!(\"5\");\n}\n```\n\nAt this time the main intended use case of generators is an implementation\nprimitive for async/await syntax, but generators will likely be extended to\nergonomic implementations of iterators and other primitives in the future.\nFeedback on the design and usage is always appreciated!\n\n### The `Generator` trait\n\nThe `Generator` trait in `std::ops` currently looks like:\n\n```rust\n# #![feature(arbitrary_self_types, generator_trait)]\n# use std::ops::GeneratorState;\n# use std::pin::Pin;\n\npub trait Generator<R = ()> {\n type Yield;\n type Return;\n fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;\n}\n```\n\nThe `Generator::Yield` type is the type of values that can be yielded with the\n`yield` statement. The `Generator::Return` type is the returned type of the\ngenerator. This is typically the last expression in a generator's definition or\nany value passed to `return` in a generator. The `resume` function is the entry\npoint for executing the `Generator` itself.\n\nThe return value of `resume`, `GeneratorState`, looks like:\n\n```rust\npub enum GeneratorState<Y, R> {\n Yielded(Y),\n Complete(R),\n}\n```\n\nThe `Yielded` variant indicates that the generator can later be resumed. This\ncorresponds to a `yield` point in a generator. The `Complete` variant indicates\nthat the generator is complete and cannot be resumed again. Calling `resume`\nafter a generator has returned `Complete` will likely result in a panic of the\nprogram.\n\n### Closure-like semantics\n\nThe closure-like syntax for generators alludes to the fact that they also have\nclosure-like semantics. Namely:\n\n* When created, a generator executes no code. A closure literal does not\n actually execute any of the closure's code on construction, and similarly a\n generator literal does not execute any code inside the generator when\n constructed.\n\n* Generators can capture outer variables by reference or by move, and this can\n be tweaked with the `move` keyword at the beginning of the closure. Like\n closures all generators will have an implicit environment which is inferred by\n the compiler. Outer variables can be moved into a generator for use as the\n generator progresses.\n\n* Generator literals produce a value with a unique type which implements the\n `std::ops::Generator` trait. This allows actual execution of the generator\n through the `Generator::resume` method as well as also naming it in return\n types and such.\n\n* Traits like `Send` and `Sync` are automatically implemented for a `Generator`\n depending on the captured variables of the environment. Unlike closures,\n generators also depend on variables live across suspension points. This means\n that although the ambient environment may be `Send` or `Sync`, the generator\n itself may not be due to internal variables live across `yield` points being\n not-`Send` or not-`Sync`. Note that generators do\n not implement traits like `Copy` or `Clone` automatically.\n\n* Whenever a generator is dropped it will drop all captured environment\n variables.\n\n### Generators as state machines\n\nIn the compiler, generators are currently compiled as state machines. Each\n`yield` expression will correspond to a different state that stores all live\nvariables over that suspension point. Resumption of a generator will dispatch on\nthe current state and then execute internally until a `yield` is reached, at\nwhich point all state is saved off in the generator and a value is returned.\n\nLet's take a look at an example to see what's going on here:\n\n```rust\n#![feature(generators, generator_trait)]\n\nuse std::ops::Generator;\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = move || {\n yield 1;\n return ret\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nThis generator literal will compile down to something similar to:\n\n```rust\n#![feature(arbitrary_self_types, generators, generator_trait)]\n\nuse std::ops::{Generator, GeneratorState};\nuse std::pin::Pin;\n\nfn main() {\n let ret = \"foo\";\n let mut generator = {\n enum __Generator {\n Start(&'static str),\n Yield1(&'static str),\n Done,\n }\n\n impl Generator for __Generator {\n type Yield = i32;\n type Return = &'static str;\n\n fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> {\n use std::mem;\n match mem::replace(&mut *self, __Generator::Done) {\n __Generator::Start(s) => {\n *self = __Generator::Yield1(s);\n GeneratorState::Yielded(1)\n }\n\n __Generator::Yield1(s) => {\n *self = __Generator::Done;\n GeneratorState::Complete(s)\n }\n\n __Generator::Done => {\n panic!(\"generator resumed after completion\")\n }\n }\n }\n }\n\n __Generator::Start(ret)\n };\n\n Pin::new(&mut generator).resume(());\n Pin::new(&mut generator).resume(());\n}\n```\n\nNotably here we can see that the compiler is generating a fresh type,\n`__Generator` in this case. This type has a number of states (represented here\nas an `enum`) corresponding to each of the conceptual states of the generator.\nAt the beginning we're closing over our outer variable `foo` and then that\nvariable is also live over the `yield` point, so it's stored in both states.\n\nWhen the generator starts it'll immediately yield 1, but it saves off its state\njust before it does so indicating that it has reached the yield point. Upon\nresuming again we'll execute the `return ret` which returns the `Complete`\nstate.\n\nHere we can also note that the `Done` state, if resumed, panics immediately as\nit's invalid to resume a completed generator. It's also worth noting that this\nis just a rough desugaring, not a normative specification for what the compiler\ndoes.\n" } , LintCompletion { label : "abi_ptx" , description : "# `abi_ptx`\n\nThe tracking issue for this feature is: [#38788]\n\n[#38788]: https://github.com/rust-lang/rust/issues/38788\n\n------------------------\n\nWhen emitting PTX code, all vanilla Rust functions (`fn`) get translated to\n\"device\" functions. These functions are *not* callable from the host via the\nCUDA API so a crate with only device functions is not too useful!\n\nOTOH, \"global\" functions *can* be called by the host; you can think of them\nas the real public API of your crate. To produce a global function use the\n`\"ptx-kernel\"` ABI.\n\n<!-- NOTE(ignore) this example is specific to the nvptx targets -->\n\n``` rust,ignore\n#![feature(abi_ptx)]\n#![no_std]\n\npub unsafe extern \"ptx-kernel\" fn global_function() {\n device_function();\n}\n\npub fn device_function() {\n // ..\n}\n```\n\n``` text\n$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm\n\n$ cat $(find -name '*.s')\n//\n// Generated by LLVM NVPTX Back-End\n//\n\n.version 3.2\n.target sm_20\n.address_size 64\n\n // .globl _ZN6kernel15global_function17h46111ebe6516b382E\n\n.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E()\n{\n\n\n ret;\n}\n\n // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E\n.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E()\n{\n\n\n ret;\n}\n```\n" } , LintCompletion { label : "unsized_tuple_coercion" , description : "# `unsized_tuple_coercion`\n\nThe tracking issue for this feature is: [#42877]\n\n[#42877]: https://github.com/rust-lang/rust/issues/42877\n\n------------------------\n\nThis is a part of [RFC0401]. According to the RFC, there should be an implementation like this:\n\n```rust,ignore\nimpl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}\n```\n\nThis implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:\n\n```rust\n#![feature(unsized_tuple_coercion)]\n\nfn main() {\n let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);\n let y : &([i32; 3], [i32]) = &x;\n assert_eq!(y.1[0], 4);\n}\n```\n\n[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md\n" } , LintCompletion { label : "const_in_array_repeat_expressions" , description : "# `const_in_array_repeat_expressions`\n\nThe tracking issue for this feature is: [#49147]\n\n[#49147]: https://github.com/rust-lang/rust/issues/49147\n\n------------------------\n\nRelaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly\nspeaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is\n`const` is itself also `const`.\n" } , LintCompletion { label : "impl_trait_in_bindings" , description : "# `impl_trait_in_bindings`\n\nThe tracking issue for this feature is: [#63065]\n\n[#63065]: https://github.com/rust-lang/rust/issues/63065\n\n------------------------\n\nThe `impl_trait_in_bindings` feature gate lets you use `impl Trait` syntax in\n`let`, `static`, and `const` bindings.\n\nA simple example is:\n\n```rust\n#![feature(impl_trait_in_bindings)]\n\nuse std::fmt::Debug;\n\nfn main() {\n let a: impl Debug + Clone = 42;\n let b = a.clone();\n println!(\"{:?}\", b); // prints `42`\n}\n```\n\nNote however that because the types of `a` and `b` are opaque in the above\nexample, calling inherent methods or methods outside of the specified traits\n(e.g., `a.abs()` or `b.abs()`) is not allowed, and yields an error.\n" } , LintCompletion { label : "trait_alias" , description : "# `trait_alias`\n\nThe tracking issue for this feature is: [#41517]\n\n[#41517]: https://github.com/rust-lang/rust/issues/41517\n\n------------------------\n\nThe `trait_alias` feature adds support for trait aliases. These allow aliases\nto be created for one or more traits (currently just a single regular trait plus\nany number of auto-traits), and used wherever traits would normally be used as\neither bounds or trait objects.\n\n```rust\n#![feature(trait_alias)]\n\ntrait Foo = std::fmt::Debug + Send;\ntrait Bar = Foo + Sync;\n\n// Use trait alias as bound on type parameter.\nfn foo<T: Foo>(v: &T) {\n println!(\"{:?}\", v);\n}\n\npub fn main() {\n foo(&1);\n\n // Use trait alias for trait objects.\n let a: &Bar = &123;\n println!(\"{:?}\", a);\n let b = Box::new(456) as Box<dyn Foo>;\n println!(\"{:?}\", b);\n}\n```\n" } , LintCompletion { label : "doc_cfg" , description : "# `doc_cfg`\n\nThe tracking issue for this feature is: [#43781]\n\n------\n\nThe `doc_cfg` feature allows an API be documented as only available in some specific platforms.\nThis attribute has two effects:\n\n1. In the annotated item's documentation, there will be a message saying \"This is supported on\n (platform) only\".\n\n2. The item's doc-tests will only run on the specific platform.\n\nIn addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a\nspecial conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your\ncrate.\n\nThis feature was introduced as part of PR [#43348] to allow the platform-specific parts of the\nstandard library be documented.\n\n```rust\n#![feature(doc_cfg)]\n\n#[cfg(any(windows, doc))]\n#[doc(cfg(windows))]\n/// The application's icon in the notification area (a.k.a. system tray).\n///\n/// # Examples\n///\n/// ```no_run\n/// extern crate my_awesome_ui_library;\n/// use my_awesome_ui_library::current_app;\n/// use my_awesome_ui_library::windows::notification;\n///\n/// let icon = current_app().get::<notification::Icon>();\n/// icon.show();\n/// icon.show_message(\"Hello\");\n/// ```\npub struct Icon {\n // ...\n}\n```\n\n[#43781]: https://github.com/rust-lang/rust/issues/43781\n[#43348]: https://github.com/rust-lang/rust/issues/43348\n" } , LintCompletion { label : "lang_items" , description : "# `lang_items`\n\nThe tracking issue for this feature is: None.\n\n------------------------\n\nThe `rustc` compiler has certain pluggable operations, that is,\nfunctionality that isn't hard-coded into the language, but is\nimplemented in libraries, with a special marker to tell the compiler\nit exists. The marker is the attribute `#[lang = \"...\"]` and there are\nvarious different values of `...`, i.e. various different 'lang\nitems'.\n\nFor example, `Box` pointers require two lang items, one for allocation\nand one for deallocation. A freestanding program that uses the `Box`\nsugar for dynamic allocations via `malloc` and `free`:\n\n```rust,ignore\n#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\nextern crate libc;\n\n#[lang = \"owned_box\"]\npub struct Box<T>(*mut T);\n\n#[lang = \"exchange_malloc\"]\nunsafe fn allocate(size: usize, _align: usize) -> *mut u8 {\n let p = libc::malloc(size as libc::size_t) as *mut u8;\n\n // Check if `malloc` failed:\n if p as usize == 0 {\n intrinsics::abort();\n }\n\n p\n}\n\n#[lang = \"box_free\"]\nunsafe fn box_free<T: ?Sized>(ptr: *mut T) {\n libc::free(ptr as *mut libc::c_void)\n}\n\n#[start]\nfn main(_argc: isize, _argv: *const *const u8) -> isize {\n let _x = box 1;\n\n 0\n}\n\n#[lang = \"eh_personality\"] extern fn rust_eh_personality() {}\n#[lang = \"panic_impl\"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }\n#[no_mangle] pub extern fn rust_eh_register_frames () {}\n#[no_mangle] pub extern fn rust_eh_unregister_frames () {}\n```\n\nNote the use of `abort`: the `exchange_malloc` lang item is assumed to\nreturn a valid pointer, and so needs to do the check internally.\n\nOther features provided by lang items include:\n\n- overloadable operators via traits: the traits corresponding to the\n `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all\n marked with lang items; those specific four are `eq`, `ord`,\n `deref`, and `add` respectively.\n- stack unwinding and general failure; the `eh_personality`,\n `panic` and `panic_bounds_checks` lang items.\n- the traits in `std::marker` used to indicate types of\n various kinds; lang items `send`, `sync` and `copy`.\n- the marker types and variance indicators found in\n `std::marker`; lang items `covariant_type`,\n `contravariant_lifetime`, etc.\n\nLang items are loaded lazily by the compiler; e.g. if one never uses\n`Box` then there is no need to define functions for `exchange_malloc`\nand `box_free`. `rustc` will emit an error when an item is needed\nbut not found in the current crate or any that it depends on.\n\nMost lang items are defined by `libcore`, but if you're trying to build\nan executable without the standard library, you'll run into the need\nfor lang items. The rest of this page focuses on this use-case, even though\nlang items are a bit broader than that.\n\n### Using libc\n\nIn order to build a `#[no_std]` executable we will need libc as a dependency.\nWe can specify this using our `Cargo.toml` file:\n\n```toml\n[dependencies]\nlibc = { version = \"0.2.14\", default-features = false }\n```\n\nNote that the default features have been disabled. This is a critical step -\n**the default features of libc include the standard library and so must be\ndisabled.**\n\n### Writing an executable without stdlib\n\nControlling the entry point is possible in two ways: the `#[start]` attribute,\nor overriding the default shim for the C `main` function with your own.\n\nThe function marked `#[start]` is passed the command line parameters\nin the same format as C:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[start]\nfn start(_argc: isize, _argv: *const *const u8) -> isize {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nTo override the compiler-inserted `main` shim, one has to disable it\nwith `#![no_main]` and then create the appropriate symbol with the\ncorrect ABI and the correct name, which requires overriding the\ncompiler's name mangling too:\n\n```rust,ignore\n#![feature(lang_items, core_intrinsics)]\n#![feature(start)]\n#![no_std]\n#![no_main]\nuse core::intrinsics;\nuse core::panic::PanicInfo;\n\n// Pull in the system libc library for what crt0.o likely requires.\nextern crate libc;\n\n// Entry point for this program.\n#[no_mangle] // ensure that this symbol is called `main` in the output\npub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {\n 0\n}\n\n// These functions are used by the compiler, but not\n// for a bare-bones hello world. These are normally\n// provided by libstd.\n#[lang = \"eh_personality\"]\n#[no_mangle]\npub extern fn rust_eh_personality() {\n}\n\n#[lang = \"panic_impl\"]\n#[no_mangle]\npub extern fn rust_begin_panic(info: &PanicInfo) -> ! {\n unsafe { intrinsics::abort() }\n}\n```\n\nIn many cases, you may need to manually link to the `compiler_builtins` crate\nwhen building a `no_std` binary. You may observe this via linker error messages\nsuch as \"```undefined reference to `__rust_probestack'```\".\n\n## More about the language items\n\nThe compiler currently makes a few assumptions about symbols which are\navailable in the executable to call. Normally these functions are provided by\nthe standard library, but without it you must define your own. These symbols\nare called \"language items\", and they each have an internal name, and then a\nsignature that an implementation must conform to.\n\nThe first of these functions, `rust_eh_personality`, is used by the failure\nmechanisms of the compiler. This is often mapped to GCC's personality function\n(see the [libstd implementation][unwind] for more information), but crates\nwhich do not trigger a panic can be assured that this function is never\ncalled. The language item's name is `eh_personality`.\n\n[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs\n\nThe second function, `rust_begin_panic`, is also used by the failure mechanisms of the\ncompiler. When a panic happens, this controls the message that's displayed on\nthe screen. While the language item's name is `panic_impl`, the symbol name is\n`rust_begin_panic`.\n\nFinally, a `eh_catch_typeinfo` static is needed for certain targets which\nimplement Rust panics on top of C++ exceptions.\n\n## List of all language items\n\nThis is a list of all language items in Rust along with where they are located in\nthe source code.\n\n- Primitives\n - `i8`: `libcore/num/mod.rs`\n - `i16`: `libcore/num/mod.rs`\n - `i32`: `libcore/num/mod.rs`\n - `i64`: `libcore/num/mod.rs`\n - `i128`: `libcore/num/mod.rs`\n - `isize`: `libcore/num/mod.rs`\n - `u8`: `libcore/num/mod.rs`\n - `u16`: `libcore/num/mod.rs`\n - `u32`: `libcore/num/mod.rs`\n - `u64`: `libcore/num/mod.rs`\n - `u128`: `libcore/num/mod.rs`\n - `usize`: `libcore/num/mod.rs`\n - `f32`: `libstd/f32.rs`\n - `f64`: `libstd/f64.rs`\n - `char`: `libcore/char.rs`\n - `slice`: `liballoc/slice.rs`\n - `str`: `liballoc/str.rs`\n - `const_ptr`: `libcore/ptr.rs`\n - `mut_ptr`: `libcore/ptr