diff options
244 files changed, 8815 insertions, 8083 deletions
diff --git a/Cargo.lock b/Cargo.lock index e47b87964..238c21f52 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -37,9 +37,9 @@ dependencies = [ | |||
37 | 37 | ||
38 | [[package]] | 38 | [[package]] |
39 | name = "anyhow" | 39 | name = "anyhow" |
40 | version = "1.0.40" | 40 | version = "1.0.41" |
41 | source = "registry+https://github.com/rust-lang/crates.io-index" | 41 | source = "registry+https://github.com/rust-lang/crates.io-index" |
42 | checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" | 42 | checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" |
43 | 43 | ||
44 | [[package]] | 44 | [[package]] |
45 | name = "anymap" | 45 | name = "anymap" |
@@ -49,9 +49,9 @@ checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" | |||
49 | 49 | ||
50 | [[package]] | 50 | [[package]] |
51 | name = "arrayvec" | 51 | name = "arrayvec" |
52 | version = "0.7.0" | 52 | version = "0.7.1" |
53 | source = "registry+https://github.com/rust-lang/crates.io-index" | 53 | source = "registry+https://github.com/rust-lang/crates.io-index" |
54 | checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7" | 54 | checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" |
55 | 55 | ||
56 | [[package]] | 56 | [[package]] |
57 | name = "atty" | 57 | name = "atty" |
@@ -216,20 +216,6 @@ dependencies = [ | |||
216 | "petgraph", | 216 | "petgraph", |
217 | "rustc-hash", | 217 | "rustc-hash", |
218 | "tracing", | 218 | "tracing", |
219 | "tracing-subscriber", | ||
220 | "tracing-tree", | ||
221 | ] | ||
222 | |||
223 | [[package]] | ||
224 | name = "chrono" | ||
225 | version = "0.4.19" | ||
226 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
227 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" | ||
228 | dependencies = [ | ||
229 | "libc", | ||
230 | "num-integer", | ||
231 | "num-traits", | ||
232 | "winapi", | ||
233 | ] | 219 | ] |
234 | 220 | ||
235 | [[package]] | 221 | [[package]] |
@@ -347,9 +333,9 @@ dependencies = [ | |||
347 | 333 | ||
348 | [[package]] | 334 | [[package]] |
349 | name = "env_logger" | 335 | name = "env_logger" |
350 | version = "0.8.3" | 336 | version = "0.8.4" |
351 | source = "registry+https://github.com/rust-lang/crates.io-index" | 337 | source = "registry+https://github.com/rust-lang/crates.io-index" |
352 | checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" | 338 | checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" |
353 | dependencies = [ | 339 | dependencies = [ |
354 | "log", | 340 | "log", |
355 | ] | 341 | ] |
@@ -435,9 +421,9 @@ dependencies = [ | |||
435 | 421 | ||
436 | [[package]] | 422 | [[package]] |
437 | name = "fst" | 423 | name = "fst" |
438 | version = "0.4.6" | 424 | version = "0.4.7" |
439 | source = "registry+https://github.com/rust-lang/crates.io-index" | 425 | source = "registry+https://github.com/rust-lang/crates.io-index" |
440 | checksum = "e398fae362f4124bbe630d99519fb2d68a03e2e3a23b441028cdcdc4f4895687" | 426 | checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" |
441 | 427 | ||
442 | [[package]] | 428 | [[package]] |
443 | name = "gimli" | 429 | name = "gimli" |
@@ -591,6 +577,7 @@ dependencies = [ | |||
591 | "ide_assists", | 577 | "ide_assists", |
592 | "ide_completion", | 578 | "ide_completion", |
593 | "ide_db", | 579 | "ide_db", |
580 | "ide_diagnostics", | ||
594 | "ide_ssr", | 581 | "ide_ssr", |
595 | "indexmap", | 582 | "indexmap", |
596 | "itertools", | 583 | "itertools", |
@@ -669,6 +656,25 @@ dependencies = [ | |||
669 | ] | 656 | ] |
670 | 657 | ||
671 | [[package]] | 658 | [[package]] |
659 | name = "ide_diagnostics" | ||
660 | version = "0.0.0" | ||
661 | dependencies = [ | ||
662 | "cfg", | ||
663 | "cov-mark", | ||
664 | "either", | ||
665 | "expect-test", | ||
666 | "hir", | ||
667 | "ide_db", | ||
668 | "itertools", | ||
669 | "profile", | ||
670 | "rustc-hash", | ||
671 | "stdx", | ||
672 | "syntax", | ||
673 | "test_utils", | ||
674 | "text_edit", | ||
675 | ] | ||
676 | |||
677 | [[package]] | ||
672 | name = "ide_ssr" | 678 | name = "ide_ssr" |
673 | version = "0.0.0" | 679 | version = "0.0.0" |
674 | dependencies = [ | 680 | dependencies = [ |
@@ -735,9 +741,9 @@ dependencies = [ | |||
735 | 741 | ||
736 | [[package]] | 742 | [[package]] |
737 | name = "itertools" | 743 | name = "itertools" |
738 | version = "0.10.0" | 744 | version = "0.10.1" |
739 | source = "registry+https://github.com/rust-lang/crates.io-index" | 745 | source = "registry+https://github.com/rust-lang/crates.io-index" |
740 | checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" | 746 | checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" |
741 | dependencies = [ | 747 | dependencies = [ |
742 | "either", | 748 | "either", |
743 | ] | 749 | ] |
@@ -782,9 +788,9 @@ dependencies = [ | |||
782 | 788 | ||
783 | [[package]] | 789 | [[package]] |
784 | name = "libmimalloc-sys" | 790 | name = "libmimalloc-sys" |
785 | version = "0.1.21" | 791 | version = "0.1.22" |
786 | source = "registry+https://github.com/rust-lang/crates.io-index" | 792 | source = "registry+https://github.com/rust-lang/crates.io-index" |
787 | checksum = "2396cf99d2f58611cd69f0efeee4af3d2e2c7b61bed433515029163aa567e65c" | 793 | checksum = "1d1b8479c593dba88c2741fc50b92e13dbabbbe0bd504d979f244ccc1a5b1c01" |
788 | dependencies = [ | 794 | dependencies = [ |
789 | "cc", | 795 | "cc", |
790 | ] | 796 | ] |
@@ -821,9 +827,9 @@ dependencies = [ | |||
821 | 827 | ||
822 | [[package]] | 828 | [[package]] |
823 | name = "lsp-types" | 829 | name = "lsp-types" |
824 | version = "0.89.1" | 830 | version = "0.89.2" |
825 | source = "registry+https://github.com/rust-lang/crates.io-index" | 831 | source = "registry+https://github.com/rust-lang/crates.io-index" |
826 | checksum = "48b8a871b0a450bcec0e26d74a59583c8173cb9fb7d7f98889e18abb84838e0f" | 832 | checksum = "852e0dedfd52cc32325598b2631e0eba31b7b708959676a9f837042f276b09a2" |
827 | dependencies = [ | 833 | dependencies = [ |
828 | "bitflags", | 834 | "bitflags", |
829 | "serde", | 835 | "serde", |
@@ -889,9 +895,9 @@ dependencies = [ | |||
889 | 895 | ||
890 | [[package]] | 896 | [[package]] |
891 | name = "mimalloc" | 897 | name = "mimalloc" |
892 | version = "0.1.25" | 898 | version = "0.1.26" |
893 | source = "registry+https://github.com/rust-lang/crates.io-index" | 899 | source = "registry+https://github.com/rust-lang/crates.io-index" |
894 | checksum = "1e7c6b11afd1e5e689ac96b6d18b1fc763398fe3d7eed99e8773426bc2033dfb" | 900 | checksum = "fb74897ce508e6c49156fd1476fc5922cbc6e75183c65e399c765a09122e5130" |
895 | dependencies = [ | 901 | dependencies = [ |
896 | "libmimalloc-sys", | 902 | "libmimalloc-sys", |
897 | ] | 903 | ] |
@@ -955,25 +961,6 @@ dependencies = [ | |||
955 | ] | 961 | ] |
956 | 962 | ||
957 | [[package]] | 963 | [[package]] |
958 | name = "num-integer" | ||
959 | version = "0.1.44" | ||
960 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
961 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" | ||
962 | dependencies = [ | ||
963 | "autocfg", | ||
964 | "num-traits", | ||
965 | ] | ||
966 | |||
967 | [[package]] | ||
968 | name = "num-traits" | ||
969 | version = "0.2.14" | ||
970 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
971 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" | ||
972 | dependencies = [ | ||
973 | "autocfg", | ||
974 | ] | ||
975 | |||
976 | [[package]] | ||
977 | name = "num_cpus" | 964 | name = "num_cpus" |
978 | version = "1.13.0" | 965 | version = "1.13.0" |
979 | source = "registry+https://github.com/rust-lang/crates.io-index" | 966 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -991,9 +978,9 @@ checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" | |||
991 | 978 | ||
992 | [[package]] | 979 | [[package]] |
993 | name = "once_cell" | 980 | name = "once_cell" |
994 | version = "1.7.2" | 981 | version = "1.8.0" |
995 | source = "registry+https://github.com/rust-lang/crates.io-index" | 982 | source = "registry+https://github.com/rust-lang/crates.io-index" |
996 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" | 983 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" |
997 | 984 | ||
998 | [[package]] | 985 | [[package]] |
999 | name = "oorandom" | 986 | name = "oorandom" |
@@ -1217,9 +1204,9 @@ dependencies = [ | |||
1217 | 1204 | ||
1218 | [[package]] | 1205 | [[package]] |
1219 | name = "pulldown-cmark-to-cmark" | 1206 | name = "pulldown-cmark-to-cmark" |
1220 | version = "6.0.0" | 1207 | version = "6.0.1" |
1221 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1222 | checksum = "e8f2b9878102358ec65434fdd1a9a161f8648bb2f531acc9260e4d094c96de23" | 1209 | checksum = "6a95f396125c68d833fc40cca35532c49ab7394382f7b0e46144a4761896ce80" |
1223 | dependencies = [ | 1210 | dependencies = [ |
1224 | "pulldown-cmark", | 1211 | "pulldown-cmark", |
1225 | ] | 1212 | ] |
@@ -1742,35 +1729,18 @@ dependencies = [ | |||
1742 | ] | 1729 | ] |
1743 | 1730 | ||
1744 | [[package]] | 1731 | [[package]] |
1745 | name = "tracing-serde" | ||
1746 | version = "0.1.2" | ||
1747 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1748 | checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" | ||
1749 | dependencies = [ | ||
1750 | "serde", | ||
1751 | "tracing-core", | ||
1752 | ] | ||
1753 | |||
1754 | [[package]] | ||
1755 | name = "tracing-subscriber" | 1732 | name = "tracing-subscriber" |
1756 | version = "0.2.18" | 1733 | version = "0.2.18" |
1757 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1734 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1758 | checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5" | 1735 | checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5" |
1759 | dependencies = [ | 1736 | dependencies = [ |
1760 | "ansi_term", | ||
1761 | "chrono", | ||
1762 | "lazy_static", | 1737 | "lazy_static", |
1763 | "matchers", | 1738 | "matchers", |
1764 | "regex", | 1739 | "regex", |
1765 | "serde", | ||
1766 | "serde_json", | ||
1767 | "sharded-slab", | 1740 | "sharded-slab", |
1768 | "smallvec", | ||
1769 | "thread_local", | 1741 | "thread_local", |
1770 | "tracing", | 1742 | "tracing", |
1771 | "tracing-core", | 1743 | "tracing-core", |
1772 | "tracing-log", | ||
1773 | "tracing-serde", | ||
1774 | ] | 1744 | ] |
1775 | 1745 | ||
1776 | [[package]] | 1746 | [[package]] |
@@ -1939,18 +1909,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3" | |||
1939 | 1909 | ||
1940 | [[package]] | 1910 | [[package]] |
1941 | name = "xflags" | 1911 | name = "xflags" |
1942 | version = "0.2.1" | 1912 | version = "0.2.2" |
1943 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1913 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1944 | checksum = "59ad6ce6a0b7224130015b4ebac796478ac04e0079f5d222a690efea06a9208a" | 1914 | checksum = "a25b85ca0fcf2d003f2b0cfdce73897c54ec3d793dfe008a64de5040209363c9" |
1945 | dependencies = [ | 1915 | dependencies = [ |
1946 | "xflags-macros", | 1916 | "xflags-macros", |
1947 | ] | 1917 | ] |
1948 | 1918 | ||
1949 | [[package]] | 1919 | [[package]] |
1950 | name = "xflags-macros" | 1920 | name = "xflags-macros" |
1951 | version = "0.2.1" | 1921 | version = "0.2.2" |
1952 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1953 | checksum = "c8037d3ca14996158b03c0fa905d0834906ef0fc7044df72c1f5ff690e5e62c9" | 1923 | checksum = "00055208d8839f11689012fecb42bbc024e25bf3af91b3b9879739d3cda65bf0" |
1954 | dependencies = [ | 1924 | dependencies = [ |
1955 | "proc-macro2", | 1925 | "proc-macro2", |
1956 | ] | 1926 | ] |
diff --git a/PRIVACY.md b/PRIVACY.md index 27e39ca60..718fbed12 100644 --- a/PRIVACY.md +++ b/PRIVACY.md | |||
@@ -1,17 +1 @@ | |||
1 | # Privacy Notes | See the [Privacy](https://rust-analyzer.github.io/manual.html#security) section of the user manual. | |
2 | |||
3 | ## LSP server binary | ||
4 | |||
5 | The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies. | ||
6 | |||
7 | ## Visual Studio Code extension | ||
8 | |||
9 | The Code extension connects to GitHub to download updated LSP binaries and, if the nightly channel is selected, to perform update checks. | ||
10 | |||
11 | ## Other editor plugins | ||
12 | |||
13 | Any other editor plugins that integrate with `rust-analyzer` are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers. | ||
14 | |||
15 | ## Others | ||
16 | |||
17 | If `cargo check` is enabled (the default), any build scripts or procedural macros used by the project or its dependencies will be executed. This is also the case when `cargo check` is disabled, but build script or procedural macro support is enabled in `rust-analyzer` (on by default). | ||
@@ -27,6 +27,10 @@ If you want to **use** rust-analyzer's language server with your editor of | |||
27 | choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. | 27 | choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder. |
28 | It also contains some tips & tricks to help you be more productive when using rust-analyzer. | 28 | It also contains some tips & tricks to help you be more productive when using rust-analyzer. |
29 | 29 | ||
30 | ## Security and Privacy | ||
31 | |||
32 | See the corresponding sections of [the manual](https://rust-analyzer.github.io/manual.html#security). | ||
33 | |||
30 | ## Communication | 34 | ## Communication |
31 | 35 | ||
32 | For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum: | 36 | For usage and troubleshooting requests, please use "IDEs and Editors" category of the Rust forum: |
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index da4afb5eb..6ce377710 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -9,8 +9,8 @@ use test_utils::{ | |||
9 | use vfs::{file_set::FileSet, VfsPath}; | 9 | use vfs::{file_set::FileSet, VfsPath}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | input::CrateName, Change, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, FileRange, | 12 | input::CrateName, Change, CrateDisplayName, CrateGraph, CrateId, Edition, Env, FileId, |
13 | SourceDatabaseExt, SourceRoot, SourceRootId, | 13 | FilePosition, FileRange, SourceDatabaseExt, SourceRoot, SourceRootId, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 16 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
@@ -24,6 +24,14 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
24 | (db, fixture.files[0]) | 24 | (db, fixture.files[0]) |
25 | } | 25 | } |
26 | 26 | ||
27 | fn with_many_files(ra_fixture: &str) -> (Self, Vec<FileId>) { | ||
28 | let fixture = ChangeFixture::parse(ra_fixture); | ||
29 | let mut db = Self::default(); | ||
30 | fixture.change.apply(&mut db); | ||
31 | assert!(fixture.file_position.is_none()); | ||
32 | (db, fixture.files) | ||
33 | } | ||
34 | |||
27 | fn with_files(ra_fixture: &str) -> Self { | 35 | fn with_files(ra_fixture: &str) -> Self { |
28 | let fixture = ChangeFixture::parse(ra_fixture); | 36 | let fixture = ChangeFixture::parse(ra_fixture); |
29 | let mut db = Self::default(); | 37 | let mut db = Self::default(); |
@@ -73,7 +81,7 @@ pub struct ChangeFixture { | |||
73 | 81 | ||
74 | impl ChangeFixture { | 82 | impl ChangeFixture { |
75 | pub fn parse(ra_fixture: &str) -> ChangeFixture { | 83 | pub fn parse(ra_fixture: &str) -> ChangeFixture { |
76 | let fixture = Fixture::parse(ra_fixture); | 84 | let (mini_core, fixture) = Fixture::parse(ra_fixture); |
77 | let mut change = Change::new(); | 85 | let mut change = Change::new(); |
78 | 86 | ||
79 | let mut files = Vec::new(); | 87 | let mut files = Vec::new(); |
@@ -98,7 +106,7 @@ impl ChangeFixture { | |||
98 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); | 106 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
99 | assert!(file_position.is_none()); | 107 | assert!(file_position.is_none()); |
100 | file_position = Some((file_id, range_or_offset)); | 108 | file_position = Some((file_id, range_or_offset)); |
101 | text.to_string() | 109 | text |
102 | } | 110 | } |
103 | } else { | 111 | } else { |
104 | entry.text.clone() | 112 | entry.text.clone() |
@@ -106,6 +114,9 @@ impl ChangeFixture { | |||
106 | 114 | ||
107 | let meta = FileMeta::from(entry); | 115 | let meta = FileMeta::from(entry); |
108 | assert!(meta.path.starts_with(&source_root_prefix)); | 116 | assert!(meta.path.starts_with(&source_root_prefix)); |
117 | if !meta.deps.is_empty() { | ||
118 | assert!(meta.krate.is_some(), "can't specify deps without naming the crate") | ||
119 | } | ||
109 | 120 | ||
110 | if meta.introduce_new_source_root { | 121 | if meta.introduce_new_source_root { |
111 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); | 122 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); |
@@ -158,6 +169,31 @@ impl ChangeFixture { | |||
158 | } | 169 | } |
159 | } | 170 | } |
160 | 171 | ||
172 | if let Some(mini_core) = mini_core { | ||
173 | let core_file = file_id; | ||
174 | file_id.0 += 1; | ||
175 | |||
176 | let mut fs = FileSet::default(); | ||
177 | fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string())); | ||
178 | roots.push(SourceRoot::new_library(fs)); | ||
179 | |||
180 | change.change_file(core_file, Some(Arc::new(mini_core.source_code()))); | ||
181 | |||
182 | let all_crates = crate_graph.crates_in_topological_order(); | ||
183 | |||
184 | let core_crate = crate_graph.add_crate_root( | ||
185 | core_file, | ||
186 | Edition::Edition2021, | ||
187 | Some(CrateDisplayName::from_canonical_name("core".to_string())), | ||
188 | CfgOptions::default(), | ||
189 | Env::default(), | ||
190 | Vec::new(), | ||
191 | ); | ||
192 | |||
193 | for krate in all_crates { | ||
194 | crate_graph.add_dep(krate, CrateName::new("core").unwrap(), core_crate).unwrap(); | ||
195 | } | ||
196 | } | ||
161 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); | 197 | roots.push(SourceRoot::new_local(mem::take(&mut file_set))); |
162 | change.set_roots(roots); | 198 | change.set_roots(roots); |
163 | change.set_crate_graph(crate_graph); | 199 | change.set_crate_graph(crate_graph); |
@@ -166,6 +202,7 @@ impl ChangeFixture { | |||
166 | } | 202 | } |
167 | } | 203 | } |
168 | 204 | ||
205 | #[derive(Debug)] | ||
169 | struct FileMeta { | 206 | struct FileMeta { |
170 | path: String, | 207 | path: String, |
171 | krate: Option<String>, | 208 | krate: Option<String>, |
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 03b8dd767..916d39a0b 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! cfg defines conditional compiling options, `cfg` attibute parser and evaluator | 1 | //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator |
2 | 2 | ||
3 | mod cfg_expr; | 3 | mod cfg_expr; |
4 | mod dnf; | 4 | mod dnf; |
@@ -52,6 +52,7 @@ impl CfgOptions { | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
55 | pub struct CfgDiff { | 56 | pub struct CfgDiff { |
56 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. | 57 | // Invariants: No duplicates, no atom that's both in `enable` and `disable`. |
57 | enable: Vec<CfgAtom>, | 58 | enable: Vec<CfgAtom>, |
@@ -59,6 +60,20 @@ pub struct CfgDiff { | |||
59 | } | 60 | } |
60 | 61 | ||
61 | impl CfgDiff { | 62 | impl CfgDiff { |
63 | /// Create a new CfgDiff. Will return None if the same item appears more than once in the set | ||
64 | /// of both. | ||
65 | pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> { | ||
66 | let mut occupied = FxHashSet::default(); | ||
67 | for item in enable.iter().chain(disable.iter()) { | ||
68 | if !occupied.insert(item) { | ||
69 | // was present | ||
70 | return None; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | Some(CfgDiff { enable, disable }) | ||
75 | } | ||
76 | |||
62 | /// Returns the total number of atoms changed by this diff. | 77 | /// Returns the total number of atoms changed by this diff. |
63 | pub fn len(&self) -> usize { | 78 | pub fn len(&self) -> usize { |
64 | self.enable.len() + self.disable.len() | 79 | self.enable.len() + self.disable.len() |
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index dc10a4d0f..197149c5e 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -127,7 +127,7 @@ impl HasSource for Impl { | |||
127 | } | 127 | } |
128 | 128 | ||
129 | impl HasSource for TypeParam { | 129 | impl HasSource for TypeParam { |
130 | type Ast = Either<ast::Trait, ast::TypeParam>; | 130 | type Ast = Either<ast::TypeParam, ast::Trait>; |
131 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | 131 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
132 | let child_source = self.id.parent.child_source(db.upcast()); | 132 | let child_source = self.id.parent.child_source(db.upcast()); |
133 | Some(child_source.map(|it| it[self.id.local_id].clone())) | 133 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5bc0b2338..b7eabaabb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -2688,18 +2688,6 @@ impl ScopeDef { | |||
2688 | 2688 | ||
2689 | items | 2689 | items |
2690 | } | 2690 | } |
2691 | |||
2692 | pub fn is_value_def(&self) -> bool { | ||
2693 | matches!( | ||
2694 | self, | ||
2695 | ScopeDef::ModuleDef(ModuleDef::Function(_)) | ||
2696 | | ScopeDef::ModuleDef(ModuleDef::Variant(_)) | ||
2697 | | ScopeDef::ModuleDef(ModuleDef::Const(_)) | ||
2698 | | ScopeDef::ModuleDef(ModuleDef::Static(_)) | ||
2699 | | ScopeDef::GenericParam(GenericParam::ConstParam(_)) | ||
2700 | | ScopeDef::Local(_) | ||
2701 | ) | ||
2702 | } | ||
2703 | } | 2691 | } |
2704 | 2692 | ||
2705 | impl From<ItemInNs> for ScopeDef { | 2693 | impl From<ItemInNs> for ScopeDef { |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 613266e07..43162797e 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -51,12 +51,14 @@ impl PathResolution { | |||
51 | PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { | 51 | PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { |
52 | Some(TypeNs::BuiltinType((*builtin).into())) | 52 | Some(TypeNs::BuiltinType((*builtin).into())) |
53 | } | 53 | } |
54 | PathResolution::Def(ModuleDef::Const(_)) | 54 | PathResolution::Def( |
55 | | PathResolution::Def(ModuleDef::Variant(_)) | 55 | ModuleDef::Const(_) |
56 | | PathResolution::Def(ModuleDef::Function(_)) | 56 | | ModuleDef::Variant(_) |
57 | | PathResolution::Def(ModuleDef::Module(_)) | 57 | | ModuleDef::Function(_) |
58 | | PathResolution::Def(ModuleDef::Static(_)) | 58 | | ModuleDef::Module(_) |
59 | | PathResolution::Def(ModuleDef::Trait(_)) => None, | 59 | | ModuleDef::Static(_) |
60 | | ModuleDef::Trait(_), | ||
61 | ) => None, | ||
60 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | 62 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { |
61 | Some(TypeNs::TypeAliasId((*alias).into())) | 63 | Some(TypeNs::TypeAliasId((*alias).into())) |
62 | } | 64 | } |
@@ -65,8 +67,7 @@ impl PathResolution { | |||
65 | } | 67 | } |
66 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | 68 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), |
67 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | 69 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), |
68 | PathResolution::AssocItem(AssocItem::Const(_)) | 70 | PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None, |
69 | | PathResolution::AssocItem(AssocItem::Function(_)) => None, | ||
70 | PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => { | 71 | PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => { |
71 | Some(TypeNs::TypeAliasId((*alias).into())) | 72 | Some(TypeNs::TypeAliasId((*alias).into())) |
72 | } | 73 | } |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 6933f6e3c..0f04b2bae 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -92,7 +92,7 @@ pub enum WherePredicateTypeTarget { | |||
92 | 92 | ||
93 | #[derive(Default)] | 93 | #[derive(Default)] |
94 | pub(crate) struct SourceMap { | 94 | pub(crate) struct SourceMap { |
95 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, | 95 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::TypeParam, ast::Trait>>, |
96 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, | 96 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, |
97 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, | 97 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, |
98 | } | 98 | } |
@@ -199,7 +199,7 @@ impl GenericParams { | |||
199 | default: None, | 199 | default: None, |
200 | provenance: TypeParamProvenance::TraitSelf, | 200 | provenance: TypeParamProvenance::TraitSelf, |
201 | }); | 201 | }); |
202 | sm.type_params.insert(self_param_id, Either::Left(src.value.clone())); | 202 | sm.type_params.insert(self_param_id, Either::Right(src.value.clone())); |
203 | // add super traits as bounds on Self | 203 | // add super traits as bounds on Self |
204 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 204 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
205 | let self_param = TypeRef::Path(name![Self].into()); | 205 | let self_param = TypeRef::Path(name![Self].into()); |
@@ -277,7 +277,7 @@ impl GenericParams { | |||
277 | provenance: TypeParamProvenance::TypeParamList, | 277 | provenance: TypeParamProvenance::TypeParamList, |
278 | }; | 278 | }; |
279 | let param_id = self.types.alloc(param); | 279 | let param_id = self.types.alloc(param); |
280 | sm.type_params.insert(param_id, Either::Right(type_param.clone())); | 280 | sm.type_params.insert(param_id, Either::Left(type_param.clone())); |
281 | 281 | ||
282 | let type_ref = TypeRef::Path(name.into()); | 282 | let type_ref = TypeRef::Path(name.into()); |
283 | self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); | 283 | self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); |
@@ -413,7 +413,7 @@ impl GenericParams { | |||
413 | } | 413 | } |
414 | 414 | ||
415 | impl HasChildSource<LocalTypeParamId> for GenericDefId { | 415 | impl HasChildSource<LocalTypeParamId> for GenericDefId { |
416 | type Value = Either<ast::Trait, ast::TypeParam>; | 416 | type Value = Either<ast::TypeParam, ast::Trait>; |
417 | fn child_source( | 417 | fn child_source( |
418 | &self, | 418 | &self, |
419 | db: &dyn DefDatabase, | 419 | db: &dyn DefDatabase, |
@@ -449,7 +449,7 @@ impl ChildBySource for GenericDefId { | |||
449 | let sm = sm.as_ref(); | 449 | let sm = sm.as_ref(); |
450 | for (local_id, src) in sm.value.type_params.iter() { | 450 | for (local_id, src) in sm.value.type_params.iter() { |
451 | let id = TypeParamId { parent: *self, local_id }; | 451 | let id = TypeParamId { parent: *self, local_id }; |
452 | if let Either::Right(type_param) = src { | 452 | if let Either::Left(type_param) = src { |
453 | res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) | 453 | res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id) |
454 | } | 454 | } |
455 | } | 455 | } |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3f90bda74..5b1386406 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -674,7 +674,7 @@ impl<'a> Ctx<'a> { | |||
674 | default: None, | 674 | default: None, |
675 | provenance: TypeParamProvenance::TraitSelf, | 675 | provenance: TypeParamProvenance::TraitSelf, |
676 | }); | 676 | }); |
677 | sm.type_params.insert(self_param_id, Either::Left(trait_def.clone())); | 677 | sm.type_params.insert(self_param_id, Either::Right(trait_def.clone())); |
678 | // add super traits as bounds on Self | 678 | // add super traits as bounds on Self |
679 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 679 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
680 | let self_param = TypeRef::Path(name![Self].into()); | 680 | let self_param = TypeRef::Path(name![Self].into()); |
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index b1e1b70d0..e63bc8232 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs | |||
@@ -63,7 +63,7 @@ impl<'a> Printer<'a> { | |||
63 | fn blank(&mut self) { | 63 | fn blank(&mut self) { |
64 | let mut iter = self.buf.chars().rev().fuse(); | 64 | let mut iter = self.buf.chars().rev().fuse(); |
65 | match (iter.next(), iter.next()) { | 65 | match (iter.next(), iter.next()) { |
66 | (Some('\n'), Some('\n')) | (Some('\n'), None) | (None, None) => {} | 66 | (Some('\n'), Some('\n') | None) | (None, None) => {} |
67 | (Some('\n'), Some(_)) => { | 67 | (Some('\n'), Some(_)) => { |
68 | self.buf.push('\n'); | 68 | self.buf.push('\n'); |
69 | } | 69 | } |
@@ -77,7 +77,7 @@ impl<'a> Printer<'a> { | |||
77 | 77 | ||
78 | fn whitespace(&mut self) { | 78 | fn whitespace(&mut self) { |
79 | match self.buf.chars().next_back() { | 79 | match self.buf.chars().next_back() { |
80 | None | Some('\n') | Some(' ') => {} | 80 | None | Some('\n' | ' ') => {} |
81 | _ => self.buf.push(' '), | 81 | _ => self.buf.push(' '), |
82 | } | 82 | } |
83 | } | 83 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 6fab58f15..927a7b6e8 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -1260,7 +1260,7 @@ impl DefCollector<'_> { | |||
1260 | for directive in &self.unresolved_imports { | 1260 | for directive in &self.unresolved_imports { |
1261 | if let ImportSource::Import { id: import, use_tree } = &directive.import.source { | 1261 | if let ImportSource::Import { id: import, use_tree } = &directive.import.source { |
1262 | match (directive.import.path.segments().first(), &directive.import.path.kind) { | 1262 | match (directive.import.path.segments().first(), &directive.import.path.kind) { |
1263 | (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { | 1263 | (Some(krate), PathKind::Plain | PathKind::Abs) => { |
1264 | if diagnosed_extern_crates.contains(krate) { | 1264 | if diagnosed_extern_crates.contains(krate) { |
1265 | continue; | 1265 | continue; |
1266 | } | 1266 | } |
@@ -1992,8 +1992,8 @@ mod tests { | |||
1992 | collector.def_map | 1992 | collector.def_map |
1993 | } | 1993 | } |
1994 | 1994 | ||
1995 | fn do_resolve(code: &str) -> DefMap { | 1995 | fn do_resolve(not_ra_fixture: &str) -> DefMap { |
1996 | let (db, _file_id) = TestDB::with_single_file(code); | 1996 | let (db, _file_id) = TestDB::with_single_file(not_ra_fixture); |
1997 | let krate = db.test_crate(); | 1997 | let krate = db.test_crate(); |
1998 | 1998 | ||
1999 | let edition = db.crate_graph()[krate].edition; | 1999 | let edition = db.crate_graph()[krate].edition; |
@@ -2005,24 +2005,37 @@ mod tests { | |||
2005 | fn test_macro_expand_will_stop_1() { | 2005 | fn test_macro_expand_will_stop_1() { |
2006 | do_resolve( | 2006 | do_resolve( |
2007 | r#" | 2007 | r#" |
2008 | macro_rules! foo { | 2008 | macro_rules! foo { |
2009 | ($($ty:ty)*) => { foo!($($ty)*); } | 2009 | ($($ty:ty)*) => { foo!($($ty)*); } |
2010 | } | 2010 | } |
2011 | foo!(KABOOM); | 2011 | foo!(KABOOM); |
2012 | "#, | 2012 | "#, |
2013 | ); | ||
2014 | do_resolve( | ||
2015 | r#" | ||
2016 | macro_rules! foo { | ||
2017 | ($($ty:ty)*) => { foo!(() $($ty)*); } | ||
2018 | } | ||
2019 | foo!(KABOOM); | ||
2020 | "#, | ||
2013 | ); | 2021 | ); |
2014 | } | 2022 | } |
2015 | 2023 | ||
2016 | #[ignore] // this test does succeed, but takes quite a while :/ | 2024 | #[ignore] |
2017 | #[test] | 2025 | #[test] |
2018 | fn test_macro_expand_will_stop_2() { | 2026 | fn test_macro_expand_will_stop_2() { |
2027 | // FIXME: this test does succeed, but takes quite a while: 90 seconds in | ||
2028 | // the release mode. That's why the argument is not an ra_fixture -- | ||
2029 | // otherwise injection highlighting gets stuck. | ||
2030 | // | ||
2031 | // We need to find a way to fail this faster. | ||
2019 | do_resolve( | 2032 | do_resolve( |
2020 | r#" | 2033 | r#" |
2021 | macro_rules! foo { | 2034 | macro_rules! foo { |
2022 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } | 2035 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } |
2023 | } | 2036 | } |
2024 | foo!(KABOOM); | 2037 | foo!(KABOOM); |
2025 | "#, | 2038 | "#, |
2026 | ); | 2039 | ); |
2027 | } | 2040 | } |
2028 | } | 2041 | } |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index d4681fa3e..49c573087 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -605,8 +605,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> { | |||
605 | ModuleDefId::ConstId(it) => ValueNs::ConstId(it), | 605 | ModuleDefId::ConstId(it) => ValueNs::ConstId(it), |
606 | ModuleDefId::StaticId(it) => ValueNs::StaticId(it), | 606 | ModuleDefId::StaticId(it) => ValueNs::StaticId(it), |
607 | 607 | ||
608 | ModuleDefId::AdtId(AdtId::EnumId(_)) | 608 | ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) |
609 | | ModuleDefId::AdtId(AdtId::UnionId(_)) | ||
610 | | ModuleDefId::TraitId(_) | 609 | | ModuleDefId::TraitId(_) |
611 | | ModuleDefId::TypeAliasId(_) | 610 | | ModuleDefId::TypeAliasId(_) |
612 | | ModuleDefId::BuiltinType(_) | 611 | | ModuleDefId::BuiltinType(_) |
@@ -641,8 +640,7 @@ pub trait HasResolver: Copy { | |||
641 | impl HasResolver for ModuleId { | 640 | impl HasResolver for ModuleId { |
642 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { | 641 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { |
643 | let mut def_map = self.def_map(db); | 642 | let mut def_map = self.def_map(db); |
644 | let mut modules = Vec::new(); | 643 | let mut modules = vec![(def_map.clone(), self.local_id)]; |
645 | modules.push((def_map.clone(), self.local_id)); | ||
646 | while let Some(parent) = def_map.parent() { | 644 | while let Some(parent) = def_map.parent() { |
647 | def_map = parent.def_map(db); | 645 | def_map = parent.def_map(db); |
648 | modules.push((def_map.clone(), parent.local_id)); | 646 | modules.push((def_map.clone(), parent.local_id)); |
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index 83500f54e..aeb1e7726 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -172,9 +172,8 @@ impl Visibility { | |||
172 | /// visible in unrelated modules). | 172 | /// visible in unrelated modules). |
173 | pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { | 173 | pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> { |
174 | match (self, other) { | 174 | match (self, other) { |
175 | (Visibility::Module(_), Visibility::Public) | 175 | (Visibility::Module(_) | Visibility::Public, Visibility::Public) |
176 | | (Visibility::Public, Visibility::Module(_)) | 176 | | (Visibility::Public, Visibility::Module(_)) => Some(Visibility::Public), |
177 | | (Visibility::Public, Visibility::Public) => Some(Visibility::Public), | ||
178 | (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { | 177 | (Visibility::Module(mod_a), Visibility::Module(mod_b)) => { |
179 | if mod_a.krate != mod_b.krate { | 178 | if mod_a.krate != mod_b.krate { |
180 | return None; | 179 | return None; |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index f24d1d919..4c83a2efe 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -202,7 +202,7 @@ fn assert_expand( | |||
202 | 202 | ||
203 | let arg_tts = args.into_iter().flat_map(|arg| { | 203 | let arg_tts = args.into_iter().flat_map(|arg| { |
204 | quote! { &(#arg), } | 204 | quote! { &(#arg), } |
205 | }.token_trees).collect::<Vec<_>>(); | 205 | }.token_trees); |
206 | 206 | ||
207 | let expanded = quote! { | 207 | let expanded = quote! { |
208 | { { (##arg_tts); } } | 208 | { { (##arg_tts); } } |
@@ -254,7 +254,7 @@ fn format_args_expand( | |||
254 | let _format_string = args.remove(0); | 254 | let _format_string = args.remove(0); |
255 | let arg_tts = args.into_iter().flat_map(|arg| { | 255 | let arg_tts = args.into_iter().flat_map(|arg| { |
256 | quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), } | 256 | quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), } |
257 | }.token_trees).collect::<Vec<_>>(); | 257 | }.token_trees); |
258 | let expanded = quote! { | 258 | let expanded = quote! { |
259 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) | 259 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) |
260 | }; | 260 | }; |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 05c6c3fb1..848522411 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -146,10 +146,11 @@ impl HygieneInfo { | |||
146 | (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) | 146 | (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) |
147 | } | 147 | } |
148 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { | 148 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { |
149 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) | 149 | ( |
150 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { | 150 | TokenExpander::MacroDef { def_site_token_map, .. } |
151 | (def_site_token_map, tt) | 151 | | TokenExpander::MacroRules { def_site_token_map, .. }, |
152 | } | 152 | Some(tt), |
153 | ) => (def_site_token_map, tt), | ||
153 | _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), | 154 | _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), |
154 | }, | 155 | }, |
155 | }; | 156 | }; |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 33107aa24..c31426d7c 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -368,10 +368,11 @@ impl ExpansionInfo { | |||
368 | let (token_map, tt) = match origin { | 368 | let (token_map, tt) = match origin { |
369 | mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), | 369 | mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), |
370 | mbe::Origin::Def => match (&*self.macro_def, self.def.as_ref()) { | 370 | mbe::Origin::Def => match (&*self.macro_def, self.def.as_ref()) { |
371 | (db::TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) | 371 | ( |
372 | | (db::TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) => { | 372 | db::TokenExpander::MacroRules { def_site_token_map, .. } |
373 | (def_site_token_map, tt.as_ref().map(|tt| tt.syntax().clone())) | 373 | | db::TokenExpander::MacroDef { def_site_token_map, .. }, |
374 | } | 374 | Some(tt), |
375 | ) => (def_site_token_map, tt.as_ref().map(|tt| tt.syntax().clone())), | ||
375 | _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), | 376 | _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"), |
376 | }, | 377 | }, |
377 | }; | 378 | }; |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index a1894e8d8..74129eb21 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -20,7 +20,7 @@ rustc-hash = "1.1.0" | |||
20 | scoped-tls = "1" | 20 | scoped-tls = "1" |
21 | chalk-solve = { version = "0.68", default-features = false } | 21 | chalk-solve = { version = "0.68", default-features = false } |
22 | chalk-ir = "0.68" | 22 | chalk-ir = "0.68" |
23 | chalk-recursive = "0.68" | 23 | chalk-recursive = { version = "0.68", default-features = false } |
24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
25 | once_cell = { version = "1.5.0" } | 25 | once_cell = { version = "1.5.0" } |
26 | 26 | ||
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs index a4c09c742..a55b99de0 100644 --- a/crates/hir_ty/src/chalk_db.rs +++ b/crates/hir_ty/src/chalk_db.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | //! about the code that Chalk needs. | 2 | //! about the code that Chalk needs. |
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use cov_mark::hit; | ||
5 | use log::debug; | 6 | use log::debug; |
6 | 7 | ||
7 | use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; | 8 | use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; |
@@ -106,7 +107,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
106 | }; | 107 | }; |
107 | 108 | ||
108 | fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> { | 109 | fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> { |
109 | db.trait_impls_in_block(module.containing_block()?) | 110 | let block = module.containing_block()?; |
111 | hit!(block_local_impls); | ||
112 | db.trait_impls_in_block(block) | ||
110 | } | 113 | } |
111 | 114 | ||
112 | // Note: Since we're using impls_for_trait, only impls where the trait | 115 | // Note: Since we're using impls_for_trait, only impls where the trait |
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs index 6f0bf8f8c..ab1afce08 100644 --- a/crates/hir_ty/src/consteval.rs +++ b/crates/hir_ty/src/consteval.rs | |||
@@ -38,8 +38,7 @@ impl ConstExt for Const { | |||
38 | // FIXME: support more than just evaluating literals | 38 | // FIXME: support more than just evaluating literals |
39 | pub fn eval_usize(expr: &Expr) -> Option<u64> { | 39 | pub fn eval_usize(expr: &Expr) -> Option<u64> { |
40 | match expr { | 40 | match expr { |
41 | Expr::Literal(Literal::Uint(v, None)) | 41 | Expr::Literal(Literal::Uint(v, None | Some(BuiltinUint::Usize))) => (*v).try_into().ok(), |
42 | | Expr::Literal(Literal::Uint(v, Some(BuiltinUint::Usize))) => (*v).try_into().ok(), | ||
43 | _ => None, | 42 | _ => None, |
44 | } | 43 | } |
45 | } | 44 | } |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index b809b96a0..dc8f20138 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -56,7 +56,7 @@ impl BodyValidationDiagnostic { | |||
56 | pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> { | 56 | pub fn collect(db: &dyn HirDatabase, owner: DefWithBodyId) -> Vec<BodyValidationDiagnostic> { |
57 | let _p = profile::span("BodyValidationDiagnostic::collect"); | 57 | let _p = profile::span("BodyValidationDiagnostic::collect"); |
58 | let infer = db.infer(owner); | 58 | let infer = db.infer(owner); |
59 | let mut validator = ExprValidator::new(owner, infer.clone()); | 59 | let mut validator = ExprValidator::new(owner, infer); |
60 | validator.validate_body(db); | 60 | validator.validate_body(db); |
61 | validator.diagnostics | 61 | validator.diagnostics |
62 | } | 62 | } |
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs index 471cd4921..e3d640a79 100644 --- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs | |||
@@ -84,10 +84,7 @@ impl IntRange { | |||
84 | #[inline] | 84 | #[inline] |
85 | fn is_integral(ty: &Ty) -> bool { | 85 | fn is_integral(ty: &Ty) -> bool { |
86 | match ty.kind(&Interner) { | 86 | match ty.kind(&Interner) { |
87 | TyKind::Scalar(Scalar::Char) | 87 | TyKind::Scalar(Scalar::Char | Scalar::Int(_) | Scalar::Uint(_) | Scalar::Bool) => true, |
88 | | TyKind::Scalar(Scalar::Int(_)) | ||
89 | | TyKind::Scalar(Scalar::Uint(_)) | ||
90 | | TyKind::Scalar(Scalar::Bool) => true, | ||
91 | _ => false, | 88 | _ => false, |
92 | } | 89 | } |
93 | } | 90 | } |
@@ -381,7 +378,7 @@ impl Constructor { | |||
381 | // Wildcards cover anything | 378 | // Wildcards cover anything |
382 | (_, Wildcard) => true, | 379 | (_, Wildcard) => true, |
383 | // The missing ctors are not covered by anything in the matrix except wildcards. | 380 | // The missing ctors are not covered by anything in the matrix except wildcards. |
384 | (Missing, _) | (Wildcard, _) => false, | 381 | (Missing | Wildcard, _) => false, |
385 | 382 | ||
386 | (Single, Single) => true, | 383 | (Single, Single) => true, |
387 | (Variant(self_id), Variant(other_id)) => self_id == other_id, | 384 | (Variant(self_id), Variant(other_id)) => self_id == other_id, |
@@ -523,7 +520,7 @@ impl SplitWildcard { | |||
523 | } | 520 | } |
524 | } | 521 | } |
525 | TyKind::Scalar(Scalar::Char) => unhandled(), | 522 | TyKind::Scalar(Scalar::Char) => unhandled(), |
526 | TyKind::Scalar(Scalar::Int(..)) | TyKind::Scalar(Scalar::Uint(..)) => unhandled(), | 523 | TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), |
527 | TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => { | 524 | TyKind::Never if !cx.feature_exhaustive_patterns() && !pcx.is_top_level => { |
528 | smallvec![NonExhaustive] | 525 | smallvec![NonExhaustive] |
529 | } | 526 | } |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 4b7f31521..7be914451 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -47,10 +47,7 @@ impl<'a> InferenceContext<'a> { | |||
47 | // pointers to have a chance at getting a match. See | 47 | // pointers to have a chance at getting a match. See |
48 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 48 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
49 | let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) { | 49 | let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) { |
50 | (TyKind::FnDef(..), TyKind::FnDef(..)) | 50 | (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => { |
51 | | (TyKind::Closure(..), TyKind::FnDef(..)) | ||
52 | | (TyKind::FnDef(..), TyKind::Closure(..)) | ||
53 | | (TyKind::Closure(..), TyKind::Closure(..)) => { | ||
54 | // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, | 51 | // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, |
55 | // we should be coercing the closure to a fn pointer of the safety of the FnDef | 52 | // we should be coercing the closure to a fn pointer of the safety of the FnDef |
56 | cov_mark::hit!(coerce_fn_reification); | 53 | cov_mark::hit!(coerce_fn_reification); |
@@ -448,8 +445,7 @@ fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer { | |||
448 | 445 | ||
449 | fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { | 446 | fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { |
450 | match (from, to) { | 447 | match (from, to) { |
451 | (Mutability::Mut, Mutability::Mut) | 448 | (Mutability::Mut, Mutability::Mut | Mutability::Not) |
452 | | (Mutability::Mut, Mutability::Not) | ||
453 | | (Mutability::Not, Mutability::Not) => Ok(()), | 449 | | (Mutability::Not, Mutability::Not) => Ok(()), |
454 | (Mutability::Not, Mutability::Mut) => Err(TypeError), | 450 | (Mutability::Not, Mutability::Mut) => Err(TypeError), |
455 | } | 451 | } |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 5ea2e5934..c3a5b979f 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -367,7 +367,7 @@ impl<'a> InferenceContext<'a> { | |||
367 | Expr::Path(p) => { | 367 | Expr::Path(p) => { |
368 | // FIXME this could be more efficient... | 368 | // FIXME this could be more efficient... |
369 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); | 369 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); |
370 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(self.err_ty()) | 370 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()) |
371 | } | 371 | } |
372 | Expr::Continue { .. } => TyKind::Never.intern(&Interner), | 372 | Expr::Continue { .. } => TyKind::Never.intern(&Interner), |
373 | Expr::Break { expr, label } => { | 373 | Expr::Break { expr, label } => { |
@@ -511,7 +511,7 @@ impl<'a> InferenceContext<'a> { | |||
511 | _ => None, | 511 | _ => None, |
512 | } | 512 | } |
513 | }) | 513 | }) |
514 | .unwrap_or(self.err_ty()); | 514 | .unwrap_or_else(|| self.err_ty()); |
515 | let ty = self.insert_type_vars(ty); | 515 | let ty = self.insert_type_vars(ty); |
516 | self.normalize_associated_types_in(ty) | 516 | self.normalize_associated_types_in(ty) |
517 | } | 517 | } |
@@ -593,11 +593,11 @@ impl<'a> InferenceContext<'a> { | |||
593 | UnaryOp::Neg => { | 593 | UnaryOp::Neg => { |
594 | match inner_ty.kind(&Interner) { | 594 | match inner_ty.kind(&Interner) { |
595 | // Fast path for builtins | 595 | // Fast path for builtins |
596 | TyKind::Scalar(Scalar::Int(_)) | 596 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) |
597 | | TyKind::Scalar(Scalar::Uint(_)) | 597 | | TyKind::InferenceVar( |
598 | | TyKind::Scalar(Scalar::Float(_)) | 598 | _, |
599 | | TyKind::InferenceVar(_, TyVariableKind::Integer) | 599 | TyVariableKind::Integer | TyVariableKind::Float, |
600 | | TyKind::InferenceVar(_, TyVariableKind::Float) => inner_ty, | 600 | ) => inner_ty, |
601 | // Otherwise we resolve via the std::ops::Neg trait | 601 | // Otherwise we resolve via the std::ops::Neg trait |
602 | _ => self | 602 | _ => self |
603 | .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), | 603 | .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), |
@@ -606,9 +606,7 @@ impl<'a> InferenceContext<'a> { | |||
606 | UnaryOp::Not => { | 606 | UnaryOp::Not => { |
607 | match inner_ty.kind(&Interner) { | 607 | match inner_ty.kind(&Interner) { |
608 | // Fast path for builtins | 608 | // Fast path for builtins |
609 | TyKind::Scalar(Scalar::Bool) | 609 | TyKind::Scalar(Scalar::Bool | Scalar::Int(_) | Scalar::Uint(_)) |
610 | | TyKind::Scalar(Scalar::Int(_)) | ||
611 | | TyKind::Scalar(Scalar::Uint(_)) | ||
612 | | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty, | 610 | | TyKind::InferenceVar(_, TyVariableKind::Integer) => inner_ty, |
613 | // Otherwise we resolve via the std::ops::Not trait | 611 | // Otherwise we resolve via the std::ops::Not trait |
614 | _ => self | 612 | _ => self |
@@ -735,7 +733,7 @@ impl<'a> InferenceContext<'a> { | |||
735 | Expr::Array(array) => { | 733 | Expr::Array(array) => { |
736 | let elem_ty = | 734 | let elem_ty = |
737 | match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) { | 735 | match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) { |
738 | Some(TyKind::Array(st, _)) | Some(TyKind::Slice(st)) => st.clone(), | 736 | Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(), |
739 | _ => self.table.new_type_var(), | 737 | _ => self.table.new_type_var(), |
740 | }; | 738 | }; |
741 | 739 | ||
@@ -820,8 +818,10 @@ impl<'a> InferenceContext<'a> { | |||
820 | for stmt in statements { | 818 | for stmt in statements { |
821 | match stmt { | 819 | match stmt { |
822 | Statement::Let { pat, type_ref, initializer } => { | 820 | Statement::Let { pat, type_ref, initializer } => { |
823 | let decl_ty = | 821 | let decl_ty = type_ref |
824 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(self.err_ty()); | 822 | .as_ref() |
823 | .map(|tr| self.make_ty(tr)) | ||
824 | .unwrap_or_else(|| self.err_ty()); | ||
825 | 825 | ||
826 | // Always use the declared type when specified | 826 | // Always use the declared type when specified |
827 | let mut ty = decl_ty.clone(); | 827 | let mut ty = decl_ty.clone(); |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 035f4ded6..c79ed91ea 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -192,7 +192,7 @@ impl<'a> InferenceContext<'a> { | |||
192 | Pat::Path(path) => { | 192 | Pat::Path(path) => { |
193 | // FIXME use correct resolver for the surrounding expression | 193 | // FIXME use correct resolver for the surrounding expression |
194 | let resolver = self.resolver.clone(); | 194 | let resolver = self.resolver.clone(); |
195 | self.infer_path(&resolver, path, pat.into()).unwrap_or(self.err_ty()) | 195 | self.infer_path(&resolver, path, pat.into()).unwrap_or_else(|| self.err_ty()) |
196 | } | 196 | } |
197 | Pat::Bind { mode, name: _, subpat } => { | 197 | Pat::Bind { mode, name: _, subpat } => { |
198 | let mode = if mode == &BindingAnnotation::Unannotated { | 198 | let mode = if mode == &BindingAnnotation::Unannotated { |
@@ -297,10 +297,11 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | |||
297 | Expr::Literal(Literal::String(..)) => false, | 297 | Expr::Literal(Literal::String(..)) => false, |
298 | _ => true, | 298 | _ => true, |
299 | }, | 299 | }, |
300 | Pat::Bind { mode: BindingAnnotation::Mutable, subpat: Some(subpat), .. } | 300 | Pat::Bind { |
301 | | Pat::Bind { mode: BindingAnnotation::Unannotated, subpat: Some(subpat), .. } => { | 301 | mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated, |
302 | is_non_ref_pat(body, *subpat) | 302 | subpat: Some(subpat), |
303 | } | 303 | .. |
304 | } => is_non_ref_pat(body, *subpat), | ||
304 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, | 305 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, |
305 | } | 306 | } |
306 | } | 307 | } |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 817a65c20..ea03b6a6c 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -562,7 +562,7 @@ impl<'a> TyLoweringContext<'a> { | |||
562 | }, | 562 | }, |
563 | ); | 563 | ); |
564 | 564 | ||
565 | ty.unwrap_or(TyKind::Error.intern(&Interner)) | 565 | ty.unwrap_or_else(|| TyKind::Error.intern(&Interner)) |
566 | } else { | 566 | } else { |
567 | TyKind::Error.intern(&Interner) | 567 | TyKind::Error.intern(&Interner) |
568 | } | 568 | } |
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs index 0222de2bc..5ef6342d5 100644 --- a/crates/hir_ty/src/op.rs +++ b/crates/hir_ty/src/op.rs | |||
@@ -8,17 +8,15 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { | |||
8 | match op { | 8 | match op { |
9 | BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), | 9 | BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), |
10 | BinaryOp::Assignment { .. } => TyBuilder::unit(), | 10 | BinaryOp::Assignment { .. } => TyBuilder::unit(), |
11 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { | 11 | BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => { |
12 | // all integer combinations are valid here | 12 | // all integer combinations are valid here |
13 | if matches!( | 13 | if matches!( |
14 | lhs_ty.kind(&Interner), | 14 | lhs_ty.kind(&Interner), |
15 | TyKind::Scalar(Scalar::Int(_)) | 15 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) |
16 | | TyKind::Scalar(Scalar::Uint(_)) | ||
17 | | TyKind::InferenceVar(_, TyVariableKind::Integer) | 16 | | TyKind::InferenceVar(_, TyVariableKind::Integer) |
18 | ) && matches!( | 17 | ) && matches!( |
19 | rhs_ty.kind(&Interner), | 18 | rhs_ty.kind(&Interner), |
20 | TyKind::Scalar(Scalar::Int(_)) | 19 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) |
21 | | TyKind::Scalar(Scalar::Uint(_)) | ||
22 | | TyKind::InferenceVar(_, TyVariableKind::Integer) | 20 | | TyKind::InferenceVar(_, TyVariableKind::Integer) |
23 | ) { | 21 | ) { |
24 | lhs_ty | 22 | lhs_ty |
@@ -32,15 +30,15 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { | |||
32 | | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_))) | 30 | | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_))) |
33 | | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty, | 31 | | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty, |
34 | // ({int}, int) | ({int}, uint) | 32 | // ({int}, int) | ({int}, uint) |
35 | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Int(_))) | 33 | ( |
36 | | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Uint(_))) => { | 34 | TyKind::InferenceVar(_, TyVariableKind::Integer), |
37 | rhs_ty | 35 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)), |
38 | } | 36 | ) => rhs_ty, |
39 | // (int, {int}) | (uint, {int}) | 37 | // (int, {int}) | (uint, {int}) |
40 | (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) | 38 | ( |
41 | | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => { | 39 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)), |
42 | lhs_ty | 40 | TyKind::InferenceVar(_, TyVariableKind::Integer), |
43 | } | 41 | ) => lhs_ty, |
44 | // ({float} | float) | 42 | // ({float} | float) |
45 | (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => { | 43 | (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => { |
46 | rhs_ty | 44 | rhs_ty |
@@ -69,21 +67,15 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { | |||
69 | BinaryOp::Assignment { op: None } => lhs_ty, | 67 | BinaryOp::Assignment { op: None } => lhs_ty, |
70 | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) { | 68 | BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) { |
71 | TyKind::Scalar(_) | TyKind::Str => lhs_ty, | 69 | TyKind::Scalar(_) | TyKind::Str => lhs_ty, |
72 | TyKind::InferenceVar(_, TyVariableKind::Integer) | 70 | TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty, |
73 | | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, | ||
74 | _ => TyKind::Error.intern(&Interner), | 71 | _ => TyKind::Error.intern(&Interner), |
75 | }, | 72 | }, |
76 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { | 73 | BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) => TyKind::Error.intern(&Interner), |
77 | TyKind::Error.intern(&Interner) | ||
78 | } | ||
79 | BinaryOp::CmpOp(CmpOp::Ord { .. }) | 74 | BinaryOp::CmpOp(CmpOp::Ord { .. }) |
80 | | BinaryOp::Assignment { op: Some(_) } | 75 | | BinaryOp::Assignment { op: Some(_) } |
81 | | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) { | 76 | | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) { |
82 | TyKind::Scalar(Scalar::Int(_)) | 77 | TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_)) => lhs_ty, |
83 | | TyKind::Scalar(Scalar::Uint(_)) | 78 | TyKind::InferenceVar(_, TyVariableKind::Integer | TyVariableKind::Float) => lhs_ty, |
84 | | TyKind::Scalar(Scalar::Float(_)) => lhs_ty, | ||
85 | TyKind::InferenceVar(_, TyVariableKind::Integer) | ||
86 | | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, | ||
87 | _ => TyKind::Error.intern(&Interner), | 79 | _ => TyKind::Error.intern(&Interner), |
88 | }, | 80 | }, |
89 | } | 81 | } |
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs index 4640ea821..b99a03492 100644 --- a/crates/hir_ty/src/test_db.rs +++ b/crates/hir_ty/src/test_db.rs | |||
@@ -86,16 +86,20 @@ impl FileLoader for TestDB { | |||
86 | } | 86 | } |
87 | 87 | ||
88 | impl TestDB { | 88 | impl TestDB { |
89 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { | 89 | pub(crate) fn module_for_file_opt(&self, file_id: FileId) -> Option<ModuleId> { |
90 | for &krate in self.relevant_crates(file_id).iter() { | 90 | for &krate in self.relevant_crates(file_id).iter() { |
91 | let crate_def_map = self.crate_def_map(krate); | 91 | let crate_def_map = self.crate_def_map(krate); |
92 | for (local_id, data) in crate_def_map.modules() { | 92 | for (local_id, data) in crate_def_map.modules() { |
93 | if data.origin.file_id() == Some(file_id) { | 93 | if data.origin.file_id() == Some(file_id) { |
94 | return crate_def_map.module_id(local_id); | 94 | return Some(crate_def_map.module_id(local_id)); |
95 | } | 95 | } |
96 | } | 96 | } |
97 | } | 97 | } |
98 | panic!("Can't find module for file") | 98 | None |
99 | } | ||
100 | |||
101 | pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { | ||
102 | self.module_for_file_opt(file_id).unwrap() | ||
99 | } | 103 | } |
100 | 104 | ||
101 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | 105 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index b873585c4..0651f34ae 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -11,23 +11,21 @@ mod incremental; | |||
11 | 11 | ||
12 | use std::{collections::HashMap, env, sync::Arc}; | 12 | use std::{collections::HashMap, env, sync::Arc}; |
13 | 13 | ||
14 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; | 14 | use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt}; |
15 | use expect_test::Expect; | 15 | use expect_test::Expect; |
16 | use hir_def::{ | 16 | use hir_def::{ |
17 | body::{Body, BodySourceMap, SyntheticSyntax}, | 17 | body::{Body, BodySourceMap, SyntheticSyntax}, |
18 | child_by_source::ChildBySource, | ||
19 | db::DefDatabase, | 18 | db::DefDatabase, |
19 | expr::{ExprId, PatId}, | ||
20 | item_scope::ItemScope, | 20 | item_scope::ItemScope, |
21 | keys, | ||
22 | nameres::DefMap, | 21 | nameres::DefMap, |
23 | src::HasSource, | 22 | src::HasSource, |
24 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 23 | AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, |
25 | }; | 24 | }; |
26 | use hir_expand::{db::AstDatabase, InFile}; | 25 | use hir_expand::{db::AstDatabase, InFile}; |
27 | use once_cell::race::OnceBool; | 26 | use once_cell::race::OnceBool; |
28 | use stdx::format_to; | 27 | use stdx::format_to; |
29 | use syntax::{ | 28 | use syntax::{ |
30 | algo, | ||
31 | ast::{self, AstNode, NameOwner}, | 29 | ast::{self, AstNode, NameOwner}, |
32 | SyntaxNode, | 30 | SyntaxNode, |
33 | }; | 31 | }; |
@@ -59,51 +57,55 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { | |||
59 | } | 57 | } |
60 | 58 | ||
61 | fn check_types(ra_fixture: &str) { | 59 | fn check_types(ra_fixture: &str) { |
62 | check_types_impl(ra_fixture, false) | 60 | check_impl(ra_fixture, false, true, false) |
63 | } | 61 | } |
64 | 62 | ||
65 | fn check_types_source_code(ra_fixture: &str) { | 63 | fn check_types_source_code(ra_fixture: &str) { |
66 | check_types_impl(ra_fixture, true) | 64 | check_impl(ra_fixture, false, true, true) |
67 | } | ||
68 | |||
69 | fn check_types_impl(ra_fixture: &str, display_source: bool) { | ||
70 | let _tracing = setup_tracing(); | ||
71 | let db = TestDB::with_files(ra_fixture); | ||
72 | let mut checked_one = false; | ||
73 | for (file_id, annotations) in db.extract_annotations() { | ||
74 | for (range, expected) in annotations { | ||
75 | let ty = type_at_range(&db, FileRange { file_id, range }); | ||
76 | let actual = if display_source { | ||
77 | let module = db.module_for_file(file_id); | ||
78 | ty.display_source_code(&db, module).unwrap() | ||
79 | } else { | ||
80 | ty.display_test(&db).to_string() | ||
81 | }; | ||
82 | assert_eq!(expected, actual); | ||
83 | checked_one = true; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | assert!(checked_one, "no `//^` annotations found"); | ||
88 | } | 65 | } |
89 | 66 | ||
90 | fn check_no_mismatches(ra_fixture: &str) { | 67 | fn check_no_mismatches(ra_fixture: &str) { |
91 | check_mismatches_impl(ra_fixture, true) | 68 | check_impl(ra_fixture, true, false, false) |
92 | } | 69 | } |
93 | 70 | ||
94 | #[allow(unused)] | 71 | fn check(ra_fixture: &str) { |
95 | fn check_mismatches(ra_fixture: &str) { | 72 | check_impl(ra_fixture, false, false, false) |
96 | check_mismatches_impl(ra_fixture, false) | ||
97 | } | 73 | } |
98 | 74 | ||
99 | fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { | 75 | fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) { |
100 | let _tracing = setup_tracing(); | 76 | let _tracing = setup_tracing(); |
101 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | 77 | let (db, files) = TestDB::with_many_files(ra_fixture); |
102 | let module = db.module_for_file(file_id); | 78 | |
103 | let def_map = module.def_map(&db); | 79 | let mut had_annotations = false; |
80 | let mut mismatches = HashMap::new(); | ||
81 | let mut types = HashMap::new(); | ||
82 | for (file_id, annotations) in db.extract_annotations() { | ||
83 | for (range, expected) in annotations { | ||
84 | let file_range = FileRange { file_id, range }; | ||
85 | if only_types { | ||
86 | types.insert(file_range, expected); | ||
87 | } else if expected.starts_with("type: ") { | ||
88 | types.insert(file_range, expected.trim_start_matches("type: ").to_string()); | ||
89 | } else if expected.starts_with("expected") { | ||
90 | mismatches.insert(file_range, expected); | ||
91 | } else { | ||
92 | panic!("unexpected annotation: {}", expected); | ||
93 | } | ||
94 | had_annotations = true; | ||
95 | } | ||
96 | } | ||
97 | assert!(had_annotations || allow_none, "no `//^` annotations found"); | ||
104 | 98 | ||
105 | let mut defs: Vec<DefWithBodyId> = Vec::new(); | 99 | let mut defs: Vec<DefWithBodyId> = Vec::new(); |
106 | visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); | 100 | for file_id in files { |
101 | let module = db.module_for_file_opt(file_id); | ||
102 | let module = match module { | ||
103 | Some(m) => m, | ||
104 | None => continue, | ||
105 | }; | ||
106 | let def_map = module.def_map(&db); | ||
107 | visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it)); | ||
108 | } | ||
107 | defs.sort_by_key(|def| match def { | 109 | defs.sort_by_key(|def| match def { |
108 | DefWithBodyId::FunctionId(it) => { | 110 | DefWithBodyId::FunctionId(it) => { |
109 | let loc = it.lookup(&db); | 111 | let loc = it.lookup(&db); |
@@ -118,37 +120,59 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { | |||
118 | loc.source(&db).value.syntax().text_range().start() | 120 | loc.source(&db).value.syntax().text_range().start() |
119 | } | 121 | } |
120 | }); | 122 | }); |
121 | let mut mismatches = HashMap::new(); | 123 | let mut unexpected_type_mismatches = String::new(); |
122 | let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| { | ||
123 | let range = src_ptr.value.text_range(); | ||
124 | if src_ptr.file_id.call_node(&db).is_some() { | ||
125 | panic!("type mismatch in macro expansion"); | ||
126 | } | ||
127 | let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range }; | ||
128 | let actual = format!( | ||
129 | "expected {}, got {}", | ||
130 | mismatch.expected.display_test(&db), | ||
131 | mismatch.actual.display_test(&db) | ||
132 | ); | ||
133 | mismatches.insert(file_range, actual); | ||
134 | }; | ||
135 | for def in defs { | 124 | for def in defs { |
136 | let (_body, body_source_map) = db.body_with_source_map(def); | 125 | let (_body, body_source_map) = db.body_with_source_map(def); |
137 | let inference_result = db.infer(def); | 126 | let inference_result = db.infer(def); |
127 | |||
128 | for (pat, ty) in inference_result.type_of_pat.iter() { | ||
129 | let node = match pat_node(&body_source_map, pat, &db) { | ||
130 | Some(value) => value, | ||
131 | None => continue, | ||
132 | }; | ||
133 | let range = node.as_ref().original_file_range(&db); | ||
134 | if let Some(expected) = types.remove(&range) { | ||
135 | let actual = if display_source { | ||
136 | ty.display_source_code(&db, def.module(&db)).unwrap() | ||
137 | } else { | ||
138 | ty.display_test(&db).to_string() | ||
139 | }; | ||
140 | assert_eq!(actual, expected); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | for (expr, ty) in inference_result.type_of_expr.iter() { | ||
145 | let node = match expr_node(&body_source_map, expr, &db) { | ||
146 | Some(value) => value, | ||
147 | None => continue, | ||
148 | }; | ||
149 | let range = node.as_ref().original_file_range(&db); | ||
150 | if let Some(expected) = types.remove(&range) { | ||
151 | let actual = if display_source { | ||
152 | ty.display_source_code(&db, def.module(&db)).unwrap() | ||
153 | } else { | ||
154 | ty.display_test(&db).to_string() | ||
155 | }; | ||
156 | assert_eq!(actual, expected); | ||
157 | } | ||
158 | } | ||
159 | |||
138 | for (pat, mismatch) in inference_result.pat_type_mismatches() { | 160 | for (pat, mismatch) in inference_result.pat_type_mismatches() { |
139 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 161 | let node = match pat_node(&body_source_map, pat, &db) { |
140 | Ok(sp) => { | 162 | Some(value) => value, |
141 | let root = db.parse_or_expand(sp.file_id).unwrap(); | 163 | None => continue, |
142 | sp.map(|ptr| { | ||
143 | ptr.either( | ||
144 | |it| it.to_node(&root).syntax().clone(), | ||
145 | |it| it.to_node(&root).syntax().clone(), | ||
146 | ) | ||
147 | }) | ||
148 | } | ||
149 | Err(SyntheticSyntax) => continue, | ||
150 | }; | 164 | }; |
151 | push_mismatch(syntax_ptr, mismatch.clone()); | 165 | let range = node.as_ref().original_file_range(&db); |
166 | let actual = format!( | ||
167 | "expected {}, got {}", | ||
168 | mismatch.expected.display_test(&db), | ||
169 | mismatch.actual.display_test(&db) | ||
170 | ); | ||
171 | if let Some(annotation) = mismatches.remove(&range) { | ||
172 | assert_eq!(actual, annotation); | ||
173 | } else { | ||
174 | format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual); | ||
175 | } | ||
152 | } | 176 | } |
153 | for (expr, mismatch) in inference_result.expr_type_mismatches() { | 177 | for (expr, mismatch) in inference_result.expr_type_mismatches() { |
154 | let node = match body_source_map.expr_syntax(expr) { | 178 | let node = match body_source_map.expr_syntax(expr) { |
@@ -158,45 +182,70 @@ fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) { | |||
158 | } | 182 | } |
159 | Err(SyntheticSyntax) => continue, | 183 | Err(SyntheticSyntax) => continue, |
160 | }; | 184 | }; |
161 | push_mismatch(node, mismatch.clone()); | 185 | let range = node.as_ref().original_file_range(&db); |
162 | } | 186 | let actual = format!( |
163 | } | 187 | "expected {}, got {}", |
164 | let mut checked_one = false; | 188 | mismatch.expected.display_test(&db), |
165 | for (file_id, annotations) in db.extract_annotations() { | 189 | mismatch.actual.display_test(&db) |
166 | for (range, expected) in annotations { | 190 | ); |
167 | let file_range = FileRange { file_id, range }; | 191 | if let Some(annotation) = mismatches.remove(&range) { |
168 | if let Some(mismatch) = mismatches.remove(&file_range) { | 192 | assert_eq!(actual, annotation); |
169 | assert_eq!(mismatch, expected); | ||
170 | } else { | 193 | } else { |
171 | assert!(false, "Expected mismatch not encountered: {}\n", expected); | 194 | format_to!(unexpected_type_mismatches, "{:?}: {}\n", range.range, actual); |
172 | } | 195 | } |
173 | checked_one = true; | ||
174 | } | 196 | } |
175 | } | 197 | } |
198 | |||
176 | let mut buf = String::new(); | 199 | let mut buf = String::new(); |
177 | for (range, mismatch) in mismatches { | 200 | if !unexpected_type_mismatches.is_empty() { |
178 | format_to!(buf, "{:?}: {}\n", range.range, mismatch,); | 201 | format_to!(buf, "Unexpected type mismatches:\n{}", unexpected_type_mismatches); |
202 | } | ||
203 | if !mismatches.is_empty() { | ||
204 | format_to!(buf, "Unchecked mismatch annotations:\n"); | ||
205 | for m in mismatches { | ||
206 | format_to!(buf, "{:?}: {}\n", m.0.range, m.1); | ||
207 | } | ||
179 | } | 208 | } |
180 | assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf); | 209 | if !types.is_empty() { |
210 | format_to!(buf, "Unchecked type annotations:\n"); | ||
211 | for t in types { | ||
212 | format_to!(buf, "{:?}: type {}\n", t.0.range, t.1); | ||
213 | } | ||
214 | } | ||
215 | assert!(buf.is_empty(), "{}", buf); | ||
216 | } | ||
181 | 217 | ||
182 | assert!(checked_one || allow_none, "no `//^` annotations found"); | 218 | fn expr_node( |
219 | body_source_map: &BodySourceMap, | ||
220 | expr: ExprId, | ||
221 | db: &TestDB, | ||
222 | ) -> Option<InFile<SyntaxNode>> { | ||
223 | Some(match body_source_map.expr_syntax(expr) { | ||
224 | Ok(sp) => { | ||
225 | let root = db.parse_or_expand(sp.file_id).unwrap(); | ||
226 | sp.map(|ptr| ptr.to_node(&root).syntax().clone()) | ||
227 | } | ||
228 | Err(SyntheticSyntax) => return None, | ||
229 | }) | ||
183 | } | 230 | } |
184 | 231 | ||
185 | fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { | 232 | fn pat_node( |
186 | let file = db.parse(pos.file_id).ok().unwrap(); | 233 | body_source_map: &BodySourceMap, |
187 | let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); | 234 | pat: PatId, |
188 | let fn_def = expr.syntax().ancestors().find_map(ast::Fn::cast).unwrap(); | 235 | db: &TestDB, |
189 | let module = db.module_for_file(pos.file_id); | 236 | ) -> Option<InFile<SyntaxNode>> { |
190 | let func = *module.child_by_source(db)[keys::FUNCTION] | 237 | Some(match body_source_map.pat_syntax(pat) { |
191 | .get(&InFile::new(pos.file_id.into(), fn_def)) | 238 | Ok(sp) => { |
192 | .unwrap(); | 239 | let root = db.parse_or_expand(sp.file_id).unwrap(); |
193 | 240 | sp.map(|ptr| { | |
194 | let (_body, source_map) = db.body_with_source_map(func.into()); | 241 | ptr.either( |
195 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { | 242 | |it| it.to_node(&root).syntax().clone(), |
196 | let infer = db.infer(func.into()); | 243 | |it| it.to_node(&root).syntax().clone(), |
197 | return infer[expr_id].clone(); | 244 | ) |
198 | } | 245 | }) |
199 | panic!("Can't find expression") | 246 | } |
247 | Err(SyntheticSyntax) => return None, | ||
248 | }) | ||
200 | } | 249 | } |
201 | 250 | ||
202 | fn infer(ra_fixture: &str) -> String { | 251 | fn infer(ra_fixture: &str) -> String { |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 71047703d..87089f09d 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -1,380 +1,157 @@ | |||
1 | use expect_test::expect; | 1 | use super::{check, check_no_mismatches, check_types}; |
2 | |||
3 | use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; | ||
4 | 2 | ||
5 | #[test] | 3 | #[test] |
6 | fn infer_block_expr_type_mismatch() { | 4 | fn block_expr_type_mismatch() { |
7 | check_infer( | 5 | // FIXME fix double type mismatch |
6 | check( | ||
8 | r" | 7 | r" |
9 | fn test() { | 8 | fn test() { |
10 | let a: i32 = { 1i64 }; | 9 | let a: i32 = { 1i64 }; |
11 | } | 10 | // ^^^^^^^^ expected i32, got i64 |
11 | // ^^^^ expected i32, got i64 | ||
12 | } | ||
12 | ", | 13 | ", |
13 | expect![[r" | ||
14 | 10..40 '{ ...4 }; }': () | ||
15 | 20..21 'a': i32 | ||
16 | 29..37 '{ 1i64 }': i64 | ||
17 | 31..35 '1i64': i64 | ||
18 | "]], | ||
19 | ); | 14 | ); |
20 | } | 15 | } |
21 | 16 | ||
22 | #[test] | 17 | #[test] |
23 | fn coerce_places() { | 18 | fn coerce_places() { |
24 | check_infer( | 19 | check_no_mismatches( |
25 | r#" | 20 | r#" |
26 | struct S<T> { a: T } | 21 | //- minicore: coerce_unsized |
22 | struct S<T> { a: T } | ||
27 | 23 | ||
28 | fn f<T>(_: &[T]) -> T { loop {} } | 24 | fn f<T>(_: &[T]) -> T { loop {} } |
29 | fn g<T>(_: S<&[T]>) -> T { loop {} } | 25 | fn g<T>(_: S<&[T]>) -> T { loop {} } |
30 | 26 | ||
31 | fn gen<T>() -> *mut [T; 2] { loop {} } | 27 | fn gen<T>() -> *mut [T; 2] { loop {} } |
32 | fn test1<U>() -> *mut [U] { | 28 | fn test1<U>() -> *mut [U] { |
33 | gen() | 29 | gen() |
34 | } | 30 | } |
35 | |||
36 | fn test2() { | ||
37 | let arr: &[u8; 1] = &[1]; | ||
38 | |||
39 | let a: &[_] = arr; | ||
40 | let b = f(arr); | ||
41 | let c: &[_] = { arr }; | ||
42 | let d = g(S { a: arr }); | ||
43 | let e: [&[_]; 1] = [arr]; | ||
44 | let f: [&[_]; 2] = [arr; 2]; | ||
45 | let g: (&[_], &[_]) = (arr, arr); | ||
46 | } | ||
47 | 31 | ||
48 | #[lang = "sized"] | 32 | fn test2() { |
49 | pub trait Sized {} | 33 | let arr: &[u8; 1] = &[1]; |
50 | #[lang = "unsize"] | ||
51 | pub trait Unsize<T: ?Sized> {} | ||
52 | #[lang = "coerce_unsized"] | ||
53 | pub trait CoerceUnsized<T> {} | ||
54 | 34 | ||
55 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | 35 | let a: &[_] = arr; |
56 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | 36 | let b = f(arr); |
57 | "#, | 37 | let c: &[_] = { arr }; |
58 | expect![[r#" | 38 | let d = g(S { a: arr }); |
59 | 30..31 '_': &[T] | 39 | let e: [&[_]; 1] = [arr]; |
60 | 44..55 '{ loop {} }': T | 40 | let f: [&[_]; 2] = [arr; 2]; |
61 | 46..53 'loop {}': ! | 41 | let g: (&[_], &[_]) = (arr, arr); |
62 | 51..53 '{}': () | 42 | } |
63 | 64..65 '_': S<&[T]> | 43 | "#, |
64 | 81..92 '{ loop {} }': T | ||
65 | 83..90 'loop {}': ! | ||
66 | 88..90 '{}': () | ||
67 | 121..132 '{ loop {} }': *mut [T; 2] | ||
68 | 123..130 'loop {}': ! | ||
69 | 128..130 '{}': () | ||
70 | 159..172 '{ gen() }': *mut [U] | ||
71 | 165..168 'gen': fn gen<U>() -> *mut [U; 2] | ||
72 | 165..170 'gen()': *mut [U; 2] | ||
73 | 185..419 '{ ...rr); }': () | ||
74 | 195..198 'arr': &[u8; 1] | ||
75 | 211..215 '&[1]': &[u8; 1] | ||
76 | 212..215 '[1]': [u8; 1] | ||
77 | 213..214 '1': u8 | ||
78 | 226..227 'a': &[u8] | ||
79 | 236..239 'arr': &[u8; 1] | ||
80 | 249..250 'b': u8 | ||
81 | 253..254 'f': fn f<u8>(&[u8]) -> u8 | ||
82 | 253..259 'f(arr)': u8 | ||
83 | 255..258 'arr': &[u8; 1] | ||
84 | 269..270 'c': &[u8] | ||
85 | 279..286 '{ arr }': &[u8] | ||
86 | 281..284 'arr': &[u8; 1] | ||
87 | 296..297 'd': u8 | ||
88 | 300..301 'g': fn g<u8>(S<&[u8]>) -> u8 | ||
89 | 300..315 'g(S { a: arr })': u8 | ||
90 | 302..314 'S { a: arr }': S<&[u8]> | ||
91 | 309..312 'arr': &[u8; 1] | ||
92 | 325..326 'e': [&[u8]; 1] | ||
93 | 340..345 '[arr]': [&[u8]; 1] | ||
94 | 341..344 'arr': &[u8; 1] | ||
95 | 355..356 'f': [&[u8]; 2] | ||
96 | 370..378 '[arr; 2]': [&[u8]; 2] | ||
97 | 371..374 'arr': &[u8; 1] | ||
98 | 376..377 '2': usize | ||
99 | 388..389 'g': (&[u8], &[u8]) | ||
100 | 406..416 '(arr, arr)': (&[u8], &[u8]) | ||
101 | 407..410 'arr': &[u8; 1] | ||
102 | 412..415 'arr': &[u8; 1] | ||
103 | "#]], | ||
104 | ); | 44 | ); |
105 | } | 45 | } |
106 | 46 | ||
107 | #[test] | 47 | #[test] |
108 | fn infer_let_stmt_coerce() { | 48 | fn let_stmt_coerce() { |
109 | check_infer( | 49 | check_no_mismatches( |
110 | r" | 50 | r" |
111 | fn test() { | 51 | //- minicore: coerce_unsized |
112 | let x: &[isize] = &[1]; | 52 | fn test() { |
113 | let x: *const [isize] = &[1]; | 53 | let x: &[isize] = &[1]; |
114 | } | 54 | let x: *const [isize] = &[1]; |
115 | ", | 55 | } |
116 | expect![[r#" | 56 | ", |
117 | 10..75 '{ ...[1]; }': () | ||
118 | 20..21 'x': &[isize] | ||
119 | 34..38 '&[1]': &[isize; 1] | ||
120 | 35..38 '[1]': [isize; 1] | ||
121 | 36..37 '1': isize | ||
122 | 48..49 'x': *const [isize] | ||
123 | 68..72 '&[1]': &[isize; 1] | ||
124 | 69..72 '[1]': [isize; 1] | ||
125 | 70..71 '1': isize | ||
126 | "#]], | ||
127 | ); | 57 | ); |
128 | } | 58 | } |
129 | 59 | ||
130 | #[test] | 60 | #[test] |
131 | fn infer_custom_coerce_unsized() { | 61 | fn custom_coerce_unsized() { |
132 | check_infer( | 62 | check( |
133 | r#" | 63 | r#" |
134 | struct A<T: ?Sized>(*const T); | 64 | //- minicore: coerce_unsized |
135 | struct B<T: ?Sized>(*const T); | 65 | use core::{marker::Unsize, ops::CoerceUnsized}; |
136 | struct C<T: ?Sized> { inner: *const T } | ||
137 | 66 | ||
138 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | 67 | struct A<T: ?Sized>(*const T); |
139 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | 68 | struct B<T: ?Sized>(*const T); |
69 | struct C<T: ?Sized> { inner: *const T } | ||
140 | 70 | ||
141 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | 71 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} |
142 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | 72 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} |
143 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | ||
144 | 73 | ||
145 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | 74 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } |
146 | let d = foo1(a); | 75 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } |
147 | let e = foo2(b); | 76 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } |
148 | let f = foo3(c); | ||
149 | } | ||
150 | 77 | ||
151 | 78 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | |
152 | #[lang = "sized"] | 79 | let d = foo1(a); |
153 | pub trait Sized {} | 80 | // ^ expected A<[{unknown}]>, got A<[u8; 2]> |
154 | #[lang = "unsize"] | 81 | let e = foo2(b); |
155 | pub trait Unsize<T: ?Sized> {} | 82 | // ^ type: B<[u8]> |
156 | #[lang = "coerce_unsized"] | 83 | let f = foo3(c); |
157 | pub trait CoerceUnsized<T> {} | 84 | // ^ type: C<[u8]> |
158 | 85 | } | |
159 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | 86 | "#, |
160 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
161 | "#, | ||
162 | expect![[r#" | ||
163 | 257..258 'x': A<[T]> | ||
164 | 278..283 '{ x }': A<[T]> | ||
165 | 280..281 'x': A<[T]> | ||
166 | 295..296 'x': B<[T]> | ||
167 | 316..321 '{ x }': B<[T]> | ||
168 | 318..319 'x': B<[T]> | ||
169 | 333..334 'x': C<[T]> | ||
170 | 354..359 '{ x }': C<[T]> | ||
171 | 356..357 'x': C<[T]> | ||
172 | 369..370 'a': A<[u8; 2]> | ||
173 | 384..385 'b': B<[u8; 2]> | ||
174 | 399..400 'c': C<[u8; 2]> | ||
175 | 414..480 '{ ...(c); }': () | ||
176 | 424..425 'd': A<[{unknown}]> | ||
177 | 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> | ||
178 | 428..435 'foo1(a)': A<[{unknown}]> | ||
179 | 433..434 'a': A<[u8; 2]> | ||
180 | 445..446 'e': B<[u8]> | ||
181 | 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> | ||
182 | 449..456 'foo2(b)': B<[u8]> | ||
183 | 454..455 'b': B<[u8; 2]> | ||
184 | 466..467 'f': C<[u8]> | ||
185 | 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> | ||
186 | 470..477 'foo3(c)': C<[u8]> | ||
187 | 475..476 'c': C<[u8; 2]> | ||
188 | "#]], | ||
189 | ); | 87 | ); |
190 | } | 88 | } |
191 | 89 | ||
192 | #[test] | 90 | #[test] |
193 | fn infer_if_coerce() { | 91 | fn if_coerce() { |
194 | check_infer( | 92 | check_no_mismatches( |
195 | r#" | 93 | r#" |
196 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 94 | //- minicore: coerce_unsized |
197 | fn test() { | 95 | fn foo<T>(x: &[T]) -> &[T] { x } |
198 | let x = if true { | 96 | fn test() { |
199 | foo(&[1]) | 97 | let x = if true { |
200 | } else { | 98 | foo(&[1]) |
201 | &[1] | 99 | } else { |
202 | }; | 100 | &[1] |
203 | } | 101 | }; |
204 | 102 | } | |
205 | 103 | "#, | |
206 | #[lang = "sized"] | ||
207 | pub trait Sized {} | ||
208 | #[lang = "unsize"] | ||
209 | pub trait Unsize<T: ?Sized> {} | ||
210 | "#, | ||
211 | expect![[r#" | ||
212 | 10..11 'x': &[T] | ||
213 | 27..38 '{ loop {} }': &[T] | ||
214 | 29..36 'loop {}': ! | ||
215 | 34..36 '{}': () | ||
216 | 49..125 '{ ... }; }': () | ||
217 | 59..60 'x': &[i32] | ||
218 | 63..122 'if tru... }': &[i32] | ||
219 | 66..70 'true': bool | ||
220 | 71..96 '{ ... }': &[i32] | ||
221 | 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
222 | 81..90 'foo(&[1])': &[i32] | ||
223 | 85..89 '&[1]': &[i32; 1] | ||
224 | 86..89 '[1]': [i32; 1] | ||
225 | 87..88 '1': i32 | ||
226 | 102..122 '{ ... }': &[i32; 1] | ||
227 | 112..116 '&[1]': &[i32; 1] | ||
228 | 113..116 '[1]': [i32; 1] | ||
229 | 114..115 '1': i32 | ||
230 | "#]], | ||
231 | ); | 104 | ); |
232 | } | 105 | } |
233 | 106 | ||
234 | #[test] | 107 | #[test] |
235 | fn infer_if_else_coerce() { | 108 | fn if_else_coerce() { |
236 | check_infer( | 109 | check_no_mismatches( |
237 | r#" | 110 | r#" |
238 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 111 | //- minicore: coerce_unsized |
239 | fn test() { | 112 | fn foo<T>(x: &[T]) -> &[T] { x } |
240 | let x = if true { | 113 | fn test() { |
241 | &[1] | 114 | let x = if true { |
242 | } else { | 115 | &[1] |
243 | foo(&[1]) | 116 | } else { |
244 | }; | 117 | foo(&[1]) |
245 | } | 118 | }; |
246 | 119 | } | |
247 | #[lang = "sized"] | 120 | "#, |
248 | pub trait Sized {} | ||
249 | #[lang = "unsize"] | ||
250 | pub trait Unsize<T: ?Sized> {} | ||
251 | #[lang = "coerce_unsized"] | ||
252 | pub trait CoerceUnsized<T> {} | ||
253 | |||
254 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
255 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
256 | "#, | ||
257 | expect![[r#" | ||
258 | 10..11 'x': &[T] | ||
259 | 27..38 '{ loop {} }': &[T] | ||
260 | 29..36 'loop {}': ! | ||
261 | 34..36 '{}': () | ||
262 | 49..125 '{ ... }; }': () | ||
263 | 59..60 'x': &[i32] | ||
264 | 63..122 'if tru... }': &[i32] | ||
265 | 66..70 'true': bool | ||
266 | 71..91 '{ ... }': &[i32; 1] | ||
267 | 81..85 '&[1]': &[i32; 1] | ||
268 | 82..85 '[1]': [i32; 1] | ||
269 | 83..84 '1': i32 | ||
270 | 97..122 '{ ... }': &[i32] | ||
271 | 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
272 | 107..116 'foo(&[1])': &[i32] | ||
273 | 111..115 '&[1]': &[i32; 1] | ||
274 | 112..115 '[1]': [i32; 1] | ||
275 | 113..114 '1': i32 | ||
276 | "#]], | ||
277 | ) | 121 | ) |
278 | } | 122 | } |
279 | 123 | ||
280 | #[test] | 124 | #[test] |
281 | fn infer_match_first_coerce() { | 125 | fn match_first_coerce() { |
282 | check_infer( | 126 | check_no_mismatches( |
283 | r#" | 127 | r#" |
284 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 128 | //- minicore: coerce_unsized |
285 | fn test(i: i32) { | 129 | fn foo<T>(x: &[T]) -> &[T] { x } |
286 | let x = match i { | 130 | fn test(i: i32) { |
287 | 2 => foo(&[2]), | 131 | let x = match i { |
288 | 1 => &[1], | 132 | 2 => foo(&[2]), |
289 | _ => &[3], | 133 | 1 => &[1], |
290 | }; | 134 | _ => &[3], |
291 | } | 135 | }; |
292 | 136 | } | |
293 | #[lang = "sized"] | 137 | "#, |
294 | pub trait Sized {} | ||
295 | #[lang = "unsize"] | ||
296 | pub trait Unsize<T: ?Sized> {} | ||
297 | "#, | ||
298 | expect![[r#" | ||
299 | 10..11 'x': &[T] | ||
300 | 27..38 '{ loop {} }': &[T] | ||
301 | 29..36 'loop {}': ! | ||
302 | 34..36 '{}': () | ||
303 | 47..48 'i': i32 | ||
304 | 55..149 '{ ... }; }': () | ||
305 | 65..66 'x': &[i32] | ||
306 | 69..146 'match ... }': &[i32] | ||
307 | 75..76 'i': i32 | ||
308 | 87..88 '2': i32 | ||
309 | 87..88 '2': i32 | ||
310 | 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
311 | 92..101 'foo(&[2])': &[i32] | ||
312 | 96..100 '&[2]': &[i32; 1] | ||
313 | 97..100 '[2]': [i32; 1] | ||
314 | 98..99 '2': i32 | ||
315 | 111..112 '1': i32 | ||
316 | 111..112 '1': i32 | ||
317 | 116..120 '&[1]': &[i32; 1] | ||
318 | 117..120 '[1]': [i32; 1] | ||
319 | 118..119 '1': i32 | ||
320 | 130..131 '_': i32 | ||
321 | 135..139 '&[3]': &[i32; 1] | ||
322 | 136..139 '[3]': [i32; 1] | ||
323 | 137..138 '3': i32 | ||
324 | "#]], | ||
325 | ); | 138 | ); |
326 | } | 139 | } |
327 | 140 | ||
328 | #[test] | 141 | #[test] |
329 | fn infer_match_second_coerce() { | 142 | fn match_second_coerce() { |
330 | check_infer( | 143 | check_no_mismatches( |
331 | r#" | 144 | r#" |
332 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | 145 | //- minicore: coerce_unsized |
333 | fn test(i: i32) { | 146 | fn foo<T>(x: &[T]) -> &[T] { loop {} } |
334 | let x = match i { | 147 | fn test(i: i32) { |
335 | 1 => &[1], | 148 | let x = match i { |
336 | 2 => foo(&[2]), | 149 | 1 => &[1], |
337 | _ => &[3], | 150 | 2 => foo(&[2]), |
338 | }; | 151 | _ => &[3], |
339 | } | 152 | }; |
340 | 153 | } | |
341 | #[lang = "sized"] | 154 | "#, |
342 | pub trait Sized {} | ||
343 | #[lang = "unsize"] | ||
344 | pub trait Unsize<T: ?Sized> {} | ||
345 | #[lang = "coerce_unsized"] | ||
346 | pub trait CoerceUnsized<T> {} | ||
347 | |||
348 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
349 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
350 | "#, | ||
351 | expect![[r#" | ||
352 | 10..11 'x': &[T] | ||
353 | 27..38 '{ loop {} }': &[T] | ||
354 | 29..36 'loop {}': ! | ||
355 | 34..36 '{}': () | ||
356 | 47..48 'i': i32 | ||
357 | 55..149 '{ ... }; }': () | ||
358 | 65..66 'x': &[i32] | ||
359 | 69..146 'match ... }': &[i32] | ||
360 | 75..76 'i': i32 | ||
361 | 87..88 '1': i32 | ||
362 | 87..88 '1': i32 | ||
363 | 92..96 '&[1]': &[i32; 1] | ||
364 | 93..96 '[1]': [i32; 1] | ||
365 | 94..95 '1': i32 | ||
366 | 106..107 '2': i32 | ||
367 | 106..107 '2': i32 | ||
368 | 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] | ||
369 | 111..120 'foo(&[2])': &[i32] | ||
370 | 115..119 '&[2]': &[i32; 1] | ||
371 | 116..119 '[2]': [i32; 1] | ||
372 | 117..118 '2': i32 | ||
373 | 130..131 '_': i32 | ||
374 | 135..139 '&[3]': &[i32; 1] | ||
375 | 136..139 '[3]': [i32; 1] | ||
376 | 137..138 '3': i32 | ||
377 | "#]], | ||
378 | ); | 155 | ); |
379 | } | 156 | } |
380 | 157 | ||
@@ -382,207 +159,103 @@ fn infer_match_second_coerce() { | |||
382 | fn coerce_merge_one_by_one1() { | 159 | fn coerce_merge_one_by_one1() { |
383 | cov_mark::check!(coerce_merge_fail_fallback); | 160 | cov_mark::check!(coerce_merge_fail_fallback); |
384 | 161 | ||
385 | check_infer( | 162 | check( |
386 | r" | 163 | r" |
387 | fn test() { | 164 | fn test() { |
388 | let t = &mut 1; | 165 | let t = &mut 1; |
389 | let x = match 1 { | 166 | let x = match 1 { |
390 | 1 => t as *mut i32, | 167 | 1 => t as *mut i32, |
391 | 2 => t as &i32, | 168 | 2 => t as &i32, |
392 | _ => t as *const i32, | 169 | //^^^^^^^^^ expected *mut i32, got &i32 |
393 | }; | 170 | _ => t as *const i32, |
394 | } | 171 | }; |
172 | x; | ||
173 | //^ type: *const i32 | ||
174 | } | ||
395 | ", | 175 | ", |
396 | expect![[r" | ||
397 | 10..144 '{ ... }; }': () | ||
398 | 20..21 't': &mut i32 | ||
399 | 24..30 '&mut 1': &mut i32 | ||
400 | 29..30 '1': i32 | ||
401 | 40..41 'x': *const i32 | ||
402 | 44..141 'match ... }': *const i32 | ||
403 | 50..51 '1': i32 | ||
404 | 62..63 '1': i32 | ||
405 | 62..63 '1': i32 | ||
406 | 67..68 't': &mut i32 | ||
407 | 67..80 't as *mut i32': *mut i32 | ||
408 | 90..91 '2': i32 | ||
409 | 90..91 '2': i32 | ||
410 | 95..96 't': &mut i32 | ||
411 | 95..104 't as &i32': &i32 | ||
412 | 114..115 '_': i32 | ||
413 | 119..120 't': &mut i32 | ||
414 | 119..134 't as *const i32': *const i32 | ||
415 | "]], | ||
416 | ); | 176 | ); |
417 | } | 177 | } |
418 | 178 | ||
419 | #[test] | 179 | #[test] |
420 | fn return_coerce_unknown() { | 180 | fn return_coerce_unknown() { |
421 | check_infer_with_mismatches( | 181 | check_types( |
422 | r" | 182 | r" |
423 | fn foo() -> u32 { | 183 | fn foo() -> u32 { |
424 | return unknown; | 184 | return unknown; |
425 | } | 185 | //^^^^^^^ u32 |
186 | } | ||
426 | ", | 187 | ", |
427 | expect![[r" | ||
428 | 16..39 '{ ...own; }': u32 | ||
429 | 22..36 'return unknown': ! | ||
430 | 29..36 'unknown': u32 | ||
431 | "]], | ||
432 | ); | 188 | ); |
433 | } | 189 | } |
434 | 190 | ||
435 | #[test] | 191 | #[test] |
436 | fn coerce_autoderef() { | 192 | fn coerce_autoderef() { |
437 | check_infer_with_mismatches( | 193 | check_no_mismatches( |
438 | r" | 194 | r" |
439 | struct Foo; | 195 | struct Foo; |
440 | fn takes_ref_foo(x: &Foo) {} | 196 | fn takes_ref_foo(x: &Foo) {} |
441 | fn test() { | 197 | fn test() { |
442 | takes_ref_foo(&Foo); | 198 | takes_ref_foo(&Foo); |
443 | takes_ref_foo(&&Foo); | 199 | takes_ref_foo(&&Foo); |
444 | takes_ref_foo(&&&Foo); | 200 | takes_ref_foo(&&&Foo); |
445 | } | 201 | }", |
446 | ", | ||
447 | expect![[r" | ||
448 | 29..30 'x': &Foo | ||
449 | 38..40 '{}': () | ||
450 | 51..132 '{ ...oo); }': () | ||
451 | 57..70 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
452 | 57..76 'takes_...(&Foo)': () | ||
453 | 71..75 '&Foo': &Foo | ||
454 | 72..75 'Foo': Foo | ||
455 | 82..95 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
456 | 82..102 'takes_...&&Foo)': () | ||
457 | 96..101 '&&Foo': &&Foo | ||
458 | 97..101 '&Foo': &Foo | ||
459 | 98..101 'Foo': Foo | ||
460 | 108..121 'takes_ref_foo': fn takes_ref_foo(&Foo) | ||
461 | 108..129 'takes_...&&Foo)': () | ||
462 | 122..128 '&&&Foo': &&&Foo | ||
463 | 123..128 '&&Foo': &&Foo | ||
464 | 124..128 '&Foo': &Foo | ||
465 | 125..128 'Foo': Foo | ||
466 | "]], | ||
467 | ); | 202 | ); |
468 | } | 203 | } |
469 | 204 | ||
470 | #[test] | 205 | #[test] |
471 | fn coerce_autoderef_generic() { | 206 | fn coerce_autoderef_generic() { |
472 | check_infer_with_mismatches( | 207 | check_no_mismatches( |
473 | r" | 208 | r#" |
474 | struct Foo; | 209 | struct Foo; |
475 | fn takes_ref<T>(x: &T) -> T { *x } | 210 | fn takes_ref<T>(x: &T) -> T { *x } |
476 | fn test() { | 211 | fn test() { |
477 | takes_ref(&Foo); | 212 | takes_ref(&Foo); |
478 | takes_ref(&&Foo); | 213 | takes_ref(&&Foo); |
479 | takes_ref(&&&Foo); | 214 | takes_ref(&&&Foo); |
480 | } | 215 | } |
481 | ", | 216 | "#, |
482 | expect![[r" | ||
483 | 28..29 'x': &T | ||
484 | 40..46 '{ *x }': T | ||
485 | 42..44 '*x': T | ||
486 | 43..44 'x': &T | ||
487 | 57..126 '{ ...oo); }': () | ||
488 | 63..72 'takes_ref': fn takes_ref<Foo>(&Foo) -> Foo | ||
489 | 63..78 'takes_ref(&Foo)': Foo | ||
490 | 73..77 '&Foo': &Foo | ||
491 | 74..77 'Foo': Foo | ||
492 | 84..93 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo | ||
493 | 84..100 'takes_...&&Foo)': &Foo | ||
494 | 94..99 '&&Foo': &&Foo | ||
495 | 95..99 '&Foo': &Foo | ||
496 | 96..99 'Foo': Foo | ||
497 | 106..115 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo | ||
498 | 106..123 'takes_...&&Foo)': &&Foo | ||
499 | 116..122 '&&&Foo': &&&Foo | ||
500 | 117..122 '&&Foo': &&Foo | ||
501 | 118..122 '&Foo': &Foo | ||
502 | 119..122 'Foo': Foo | ||
503 | "]], | ||
504 | ); | 217 | ); |
505 | } | 218 | } |
506 | 219 | ||
507 | #[test] | 220 | #[test] |
508 | fn coerce_autoderef_block() { | 221 | fn coerce_autoderef_block() { |
509 | check_infer_with_mismatches( | 222 | check_no_mismatches( |
510 | r#" | 223 | r#" |
511 | struct String {} | 224 | //- minicore: deref |
512 | #[lang = "deref"] | 225 | struct String {} |
513 | trait Deref { type Target; } | 226 | impl core::ops::Deref for String { type Target = str; } |
514 | impl Deref for String { type Target = str; } | 227 | fn takes_ref_str(x: &str) {} |
515 | fn takes_ref_str(x: &str) {} | 228 | fn returns_string() -> String { loop {} } |
516 | fn returns_string() -> String { loop {} } | 229 | fn test() { |
517 | fn test() { | 230 | takes_ref_str(&{ returns_string() }); |
518 | takes_ref_str(&{ returns_string() }); | 231 | } |
519 | } | 232 | "#, |
520 | "#, | ||
521 | expect![[r" | ||
522 | 126..127 'x': &str | ||
523 | 135..137 '{}': () | ||
524 | 168..179 '{ loop {} }': String | ||
525 | 170..177 'loop {}': ! | ||
526 | 175..177 '{}': () | ||
527 | 190..235 '{ ... }); }': () | ||
528 | 196..209 'takes_ref_str': fn takes_ref_str(&str) | ||
529 | 196..232 'takes_...g() })': () | ||
530 | 210..231 '&{ ret...ng() }': &String | ||
531 | 211..231 '{ retu...ng() }': String | ||
532 | 213..227 'returns_string': fn returns_string() -> String | ||
533 | 213..229 'return...ring()': String | ||
534 | "]], | ||
535 | ); | 233 | ); |
536 | } | 234 | } |
537 | 235 | ||
538 | #[test] | 236 | #[test] |
539 | fn closure_return_coerce() { | 237 | fn closure_return_coerce() { |
540 | check_infer_with_mismatches( | 238 | check_no_mismatches( |
541 | r" | 239 | r" |
542 | fn foo() { | 240 | fn foo() { |
543 | let x = || { | 241 | let x = || { |
544 | if true { | 242 | if true { |
545 | return &1u32; | 243 | return &1u32; |
546 | } | ||
547 | &&1u32 | ||
548 | }; | ||
549 | } | 244 | } |
550 | ", | 245 | &&1u32 |
551 | expect![[r" | 246 | }; |
552 | 9..105 '{ ... }; }': () | 247 | }", |
553 | 19..20 'x': || -> &u32 | ||
554 | 23..102 '|| { ... }': || -> &u32 | ||
555 | 26..102 '{ ... }': &u32 | ||
556 | 36..81 'if tru... }': () | ||
557 | 39..43 'true': bool | ||
558 | 44..81 '{ ... }': () | ||
559 | 58..70 'return &1u32': ! | ||
560 | 65..70 '&1u32': &u32 | ||
561 | 66..70 '1u32': u32 | ||
562 | 90..96 '&&1u32': &&u32 | ||
563 | 91..96 '&1u32': &u32 | ||
564 | 92..96 '1u32': u32 | ||
565 | "]], | ||
566 | ); | 248 | ); |
567 | } | 249 | } |
568 | 250 | ||
569 | #[test] | 251 | #[test] |
570 | fn coerce_fn_item_to_fn_ptr() { | 252 | fn coerce_fn_item_to_fn_ptr() { |
571 | check_infer_with_mismatches( | 253 | check_no_mismatches( |
572 | r" | 254 | r" |
573 | fn foo(x: u32) -> isize { 1 } | 255 | fn foo(x: u32) -> isize { 1 } |
574 | fn test() { | 256 | fn test() { |
575 | let f: fn(u32) -> isize = foo; | 257 | let f: fn(u32) -> isize = foo; |
576 | } | 258 | }", |
577 | ", | ||
578 | expect![[r" | ||
579 | 7..8 'x': u32 | ||
580 | 24..29 '{ 1 }': isize | ||
581 | 26..27 '1': isize | ||
582 | 40..78 '{ ...foo; }': () | ||
583 | 50..51 'f': fn(u32) -> isize | ||
584 | 72..75 'foo': fn foo(u32) -> isize | ||
585 | "]], | ||
586 | ); | 259 | ); |
587 | } | 260 | } |
588 | 261 | ||
@@ -590,340 +263,160 @@ fn coerce_fn_item_to_fn_ptr() { | |||
590 | fn coerce_fn_items_in_match_arms() { | 263 | fn coerce_fn_items_in_match_arms() { |
591 | cov_mark::check!(coerce_fn_reification); | 264 | cov_mark::check!(coerce_fn_reification); |
592 | 265 | ||
593 | check_infer_with_mismatches( | 266 | check_types( |
594 | r" | 267 | r" |
595 | fn foo1(x: u32) -> isize { 1 } | 268 | fn foo1(x: u32) -> isize { 1 } |
596 | fn foo2(x: u32) -> isize { 2 } | 269 | fn foo2(x: u32) -> isize { 2 } |
597 | fn foo3(x: u32) -> isize { 3 } | 270 | fn foo3(x: u32) -> isize { 3 } |
598 | fn test() { | 271 | fn test() { |
599 | let x = match 1 { | 272 | let x = match 1 { |
600 | 1 => foo1, | 273 | 1 => foo1, |
601 | 2 => foo2, | 274 | 2 => foo2, |
602 | _ => foo3, | 275 | _ => foo3, |
603 | }; | 276 | }; |
604 | } | 277 | x; |
605 | ", | 278 | //^ fn(u32) -> isize |
606 | expect![[r" | 279 | }", |
607 | 8..9 'x': u32 | ||
608 | 25..30 '{ 1 }': isize | ||
609 | 27..28 '1': isize | ||
610 | 39..40 'x': u32 | ||
611 | 56..61 '{ 2 }': isize | ||
612 | 58..59 '2': isize | ||
613 | 70..71 'x': u32 | ||
614 | 87..92 '{ 3 }': isize | ||
615 | 89..90 '3': isize | ||
616 | 103..192 '{ ... }; }': () | ||
617 | 113..114 'x': fn(u32) -> isize | ||
618 | 117..189 'match ... }': fn(u32) -> isize | ||
619 | 123..124 '1': i32 | ||
620 | 135..136 '1': i32 | ||
621 | 135..136 '1': i32 | ||
622 | 140..144 'foo1': fn foo1(u32) -> isize | ||
623 | 154..155 '2': i32 | ||
624 | 154..155 '2': i32 | ||
625 | 159..163 'foo2': fn foo2(u32) -> isize | ||
626 | 173..174 '_': i32 | ||
627 | 178..182 'foo3': fn foo3(u32) -> isize | ||
628 | "]], | ||
629 | ); | 280 | ); |
630 | } | 281 | } |
631 | 282 | ||
632 | #[test] | 283 | #[test] |
633 | fn coerce_closure_to_fn_ptr() { | 284 | fn coerce_closure_to_fn_ptr() { |
634 | check_infer_with_mismatches( | 285 | check_no_mismatches( |
635 | r" | 286 | r" |
636 | fn test() { | 287 | fn test() { |
637 | let f: fn(u32) -> isize = |x| { 1 }; | 288 | let f: fn(u32) -> isize = |x| { 1 }; |
638 | } | 289 | }", |
639 | ", | ||
640 | expect![[r" | ||
641 | 10..54 '{ ...1 }; }': () | ||
642 | 20..21 'f': fn(u32) -> isize | ||
643 | 42..51 '|x| { 1 }': |u32| -> isize | ||
644 | 43..44 'x': u32 | ||
645 | 46..51 '{ 1 }': isize | ||
646 | 48..49 '1': isize | ||
647 | "]], | ||
648 | ); | 290 | ); |
649 | } | 291 | } |
650 | 292 | ||
651 | #[test] | 293 | #[test] |
652 | fn coerce_placeholder_ref() { | 294 | fn coerce_placeholder_ref() { |
653 | // placeholders should unify, even behind references | 295 | // placeholders should unify, even behind references |
654 | check_infer_with_mismatches( | 296 | check_no_mismatches( |
655 | r" | 297 | r" |
656 | struct S<T> { t: T } | 298 | struct S<T> { t: T } |
657 | impl<TT> S<TT> { | 299 | impl<TT> S<TT> { |
658 | fn get(&self) -> &TT { | 300 | fn get(&self) -> &TT { |
659 | &self.t | 301 | &self.t |
660 | } | 302 | } |
661 | } | 303 | }", |
662 | ", | ||
663 | expect![[r" | ||
664 | 50..54 'self': &S<TT> | ||
665 | 63..86 '{ ... }': &TT | ||
666 | 73..80 '&self.t': &TT | ||
667 | 74..78 'self': &S<TT> | ||
668 | 74..80 'self.t': TT | ||
669 | "]], | ||
670 | ); | 304 | ); |
671 | } | 305 | } |
672 | 306 | ||
673 | #[test] | 307 | #[test] |
674 | fn coerce_unsize_array() { | 308 | fn coerce_unsize_array() { |
675 | check_infer_with_mismatches( | 309 | check_types( |
676 | r#" | 310 | r#" |
677 | #[lang = "unsize"] | 311 | //- minicore: coerce_unsized |
678 | pub trait Unsize<T> {} | 312 | fn test() { |
679 | #[lang = "coerce_unsized"] | 313 | let f: &[usize] = &[1, 2, 3]; |
680 | pub trait CoerceUnsized<T> {} | 314 | //^ usize |
681 | 315 | }"#, | |
682 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
683 | |||
684 | fn test() { | ||
685 | let f: &[usize] = &[1, 2, 3]; | ||
686 | } | ||
687 | "#, | ||
688 | expect![[r#" | ||
689 | 161..198 '{ ... 3]; }': () | ||
690 | 171..172 'f': &[usize] | ||
691 | 185..195 '&[1, 2, 3]': &[usize; 3] | ||
692 | 186..195 '[1, 2, 3]': [usize; 3] | ||
693 | 187..188 '1': usize | ||
694 | 190..191 '2': usize | ||
695 | 193..194 '3': usize | ||
696 | "#]], | ||
697 | ); | 316 | ); |
698 | } | 317 | } |
699 | 318 | ||
700 | #[test] | 319 | #[test] |
701 | fn coerce_unsize_trait_object_simple() { | 320 | fn coerce_unsize_trait_object_simple() { |
702 | check_infer_with_mismatches( | 321 | check_types( |
703 | r#" | ||
704 | #[lang = "sized"] | ||
705 | pub trait Sized {} | ||
706 | #[lang = "unsize"] | ||
707 | pub trait Unsize<T> {} | ||
708 | #[lang = "coerce_unsized"] | ||
709 | pub trait CoerceUnsized<T> {} | ||
710 | |||
711 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
712 | |||
713 | trait Foo<T, U> {} | ||
714 | trait Bar<U, T, X>: Foo<T, U> {} | ||
715 | trait Baz<T, X>: Bar<usize, T, X> {} | ||
716 | |||
717 | struct S<T, X>; | ||
718 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
719 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
720 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
721 | |||
722 | fn test() { | ||
723 | let obj: &dyn Baz<i8, i16> = &S; | ||
724 | let obj: &dyn Bar<_, i8, i16> = &S; | ||
725 | let obj: &dyn Foo<i8, _> = &S; | ||
726 | } | ||
727 | "#, | ||
728 | expect![[r" | ||
729 | 424..539 '{ ... &S; }': () | ||
730 | 434..437 'obj': &dyn Baz<i8, i16> | ||
731 | 459..461 '&S': &S<i8, i16> | ||
732 | 460..461 'S': S<i8, i16> | ||
733 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
734 | 499..501 '&S': &S<i8, i16> | ||
735 | 500..501 'S': S<i8, i16> | ||
736 | 511..514 'obj': &dyn Foo<i8, usize> | ||
737 | 534..536 '&S': &S<i8, {unknown}> | ||
738 | 535..536 'S': S<i8, {unknown}> | ||
739 | "]], | ||
740 | ); | ||
741 | } | ||
742 | |||
743 | #[test] | ||
744 | // The rust reference says this should be possible, but rustc doesn't implement | ||
745 | // it. We used to support it, but Chalk doesn't. | ||
746 | #[ignore] | ||
747 | fn coerce_unsize_trait_object_to_trait_object() { | ||
748 | check_infer_with_mismatches( | ||
749 | r#" | 322 | r#" |
750 | #[lang = "sized"] | 323 | //- minicore: coerce_unsized |
751 | pub trait Sized {} | 324 | trait Foo<T, U> {} |
752 | #[lang = "unsize"] | 325 | trait Bar<U, T, X>: Foo<T, U> {} |
753 | pub trait Unsize<T> {} | 326 | trait Baz<T, X>: Bar<usize, T, X> {} |
754 | #[lang = "coerce_unsized"] | 327 | |
755 | pub trait CoerceUnsized<T> {} | 328 | struct S<T, X>; |
756 | 329 | impl<T, X> Foo<T, usize> for S<T, X> {} | |
757 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 330 | impl<T, X> Bar<usize, T, X> for S<T, X> {} |
758 | 331 | impl<T, X> Baz<T, X> for S<T, X> {} | |
759 | trait Foo<T, U> {} | 332 | |
760 | trait Bar<U, T, X>: Foo<T, U> {} | 333 | fn test() { |
761 | trait Baz<T, X>: Bar<usize, T, X> {} | 334 | let obj: &dyn Baz<i8, i16> = &S; |
762 | 335 | //^ S<i8, i16> | |
763 | struct S<T, X>; | 336 | let obj: &dyn Bar<_, i8, i16> = &S; |
764 | impl<T, X> Foo<T, usize> for S<T, X> {} | 337 | //^ S<i8, i16> |
765 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | 338 | let obj: &dyn Foo<i8, _> = &S; |
766 | impl<T, X> Baz<T, X> for S<T, X> {} | 339 | //^ S<i8, {unknown}> |
767 | 340 | }"#, | |
768 | fn test() { | ||
769 | let obj: &dyn Baz<i8, i16> = &S; | ||
770 | let obj: &dyn Bar<_, _, _> = obj; | ||
771 | let obj: &dyn Foo<_, _> = obj; | ||
772 | let obj2: &dyn Baz<i8, i16> = &S; | ||
773 | let _: &dyn Foo<_, _> = obj2; | ||
774 | } | ||
775 | "#, | ||
776 | expect![[r" | ||
777 | 424..609 '{ ...bj2; }': () | ||
778 | 434..437 'obj': &dyn Baz<i8, i16> | ||
779 | 459..461 '&S': &S<i8, i16> | ||
780 | 460..461 'S': S<i8, i16> | ||
781 | 471..474 'obj': &dyn Bar<usize, i8, i16> | ||
782 | 496..499 'obj': &dyn Baz<i8, i16> | ||
783 | 509..512 'obj': &dyn Foo<i8, usize> | ||
784 | 531..534 'obj': &dyn Bar<usize, i8, i16> | ||
785 | 544..548 'obj2': &dyn Baz<i8, i16> | ||
786 | 570..572 '&S': &S<i8, i16> | ||
787 | 571..572 'S': S<i8, i16> | ||
788 | 582..583 '_': &dyn Foo<i8, usize> | ||
789 | 602..606 'obj2': &dyn Baz<i8, i16> | ||
790 | "]], | ||
791 | ); | 341 | ); |
792 | } | 342 | } |
793 | 343 | ||
794 | #[test] | 344 | #[test] |
795 | fn coerce_unsize_super_trait_cycle() { | 345 | fn coerce_unsize_super_trait_cycle() { |
796 | check_infer_with_mismatches( | 346 | check_no_mismatches( |
797 | r#" | 347 | r#" |
798 | #[lang = "sized"] | 348 | //- minicore: coerce_unsized |
799 | pub trait Sized {} | 349 | trait A {} |
800 | #[lang = "unsize"] | 350 | trait B: C + A {} |
801 | pub trait Unsize<T> {} | 351 | trait C: B {} |
802 | #[lang = "coerce_unsized"] | 352 | trait D: C |
803 | pub trait CoerceUnsized<T> {} | 353 | |
804 | 354 | struct S; | |
805 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 355 | impl A for S {} |
806 | 356 | impl B for S {} | |
807 | trait A {} | 357 | impl C for S {} |
808 | trait B: C + A {} | 358 | impl D for S {} |
809 | trait C: B {} | 359 | |
810 | trait D: C | 360 | fn test() { |
811 | 361 | let obj: &dyn D = &S; | |
812 | struct S; | 362 | let obj: &dyn A = &S; |
813 | impl A for S {} | 363 | } |
814 | impl B for S {} | 364 | "#, |
815 | impl C for S {} | ||
816 | impl D for S {} | ||
817 | |||
818 | fn test() { | ||
819 | let obj: &dyn D = &S; | ||
820 | let obj: &dyn A = &S; | ||
821 | } | ||
822 | "#, | ||
823 | expect![[r" | ||
824 | 328..383 '{ ... &S; }': () | ||
825 | 338..341 'obj': &dyn D | ||
826 | 352..354 '&S': &S | ||
827 | 353..354 'S': S | ||
828 | 364..367 'obj': &dyn A | ||
829 | 378..380 '&S': &S | ||
830 | 379..380 'S': S | ||
831 | "]], | ||
832 | ); | 365 | ); |
833 | } | 366 | } |
834 | 367 | ||
835 | #[test] | 368 | #[test] |
836 | fn coerce_unsize_generic() { | 369 | fn coerce_unsize_generic() { |
837 | // FIXME: fix the type mismatches here | 370 | // FIXME: fix the type mismatches here |
838 | check_infer_with_mismatches( | 371 | check( |
839 | r#" | 372 | r#" |
840 | #[lang = "unsize"] | 373 | //- minicore: coerce_unsized |
841 | pub trait Unsize<T> {} | 374 | struct Foo<T> { t: T }; |
842 | #[lang = "coerce_unsized"] | 375 | struct Bar<T>(Foo<T>); |
843 | pub trait CoerceUnsized<T> {} | ||
844 | |||
845 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
846 | |||
847 | struct Foo<T> { t: T }; | ||
848 | struct Bar<T>(Foo<T>); | ||
849 | 376 | ||
850 | fn test() { | 377 | fn test() { |
851 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | 378 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; |
852 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | 379 | //^^^^^^^^^ expected [usize], got [usize; 3] |
853 | } | 380 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); |
854 | "#, | 381 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]> |
855 | expect![[r#" | 382 | } |
856 | 209..317 '{ ... }); }': () | 383 | "#, |
857 | 219..220 '_': &Foo<[usize]> | ||
858 | 238..259 '&Foo {..., 3] }': &Foo<[usize]> | ||
859 | 239..259 'Foo { ..., 3] }': Foo<[usize]> | ||
860 | 248..257 '[1, 2, 3]': [usize; 3] | ||
861 | 249..250 '1': usize | ||
862 | 252..253 '2': usize | ||
863 | 255..256 '3': usize | ||
864 | 269..270 '_': &Bar<[usize]> | ||
865 | 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]> | ||
866 | 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]> | ||
867 | 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]> | ||
868 | 293..313 'Foo { ..., 3] }': Foo<[i32; 3]> | ||
869 | 302..311 '[1, 2, 3]': [i32; 3] | ||
870 | 303..304 '1': i32 | ||
871 | 306..307 '2': i32 | ||
872 | 309..310 '3': i32 | ||
873 | 248..257: expected [usize], got [usize; 3] | ||
874 | 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]> | ||
875 | "#]], | ||
876 | ); | 384 | ); |
877 | } | 385 | } |
878 | 386 | ||
879 | #[test] | 387 | #[test] |
880 | fn coerce_unsize_apit() { | 388 | fn coerce_unsize_apit() { |
881 | // FIXME: #8984 | 389 | // FIXME: #8984 |
882 | check_infer_with_mismatches( | 390 | check( |
883 | r#" | 391 | r#" |
884 | #[lang = "sized"] | 392 | //- minicore: coerce_unsized |
885 | pub trait Sized {} | ||
886 | #[lang = "unsize"] | ||
887 | pub trait Unsize<T> {} | ||
888 | #[lang = "coerce_unsized"] | ||
889 | pub trait CoerceUnsized<T> {} | ||
890 | |||
891 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
892 | |||
893 | trait Foo {} | 393 | trait Foo {} |
894 | 394 | ||
895 | fn test(f: impl Foo) { | 395 | fn test(f: impl Foo) { |
896 | let _: &dyn Foo = &f; | 396 | let _: &dyn Foo = &f; |
397 | //^^ expected &dyn Foo, got &impl Foo | ||
897 | } | 398 | } |
898 | "#, | 399 | "#, |
899 | expect![[r#" | ||
900 | 210..211 'f': impl Foo | ||
901 | 223..252 '{ ... &f; }': () | ||
902 | 233..234 '_': &dyn Foo | ||
903 | 247..249 '&f': &impl Foo | ||
904 | 248..249 'f': impl Foo | ||
905 | 247..249: expected &dyn Foo, got &impl Foo | ||
906 | "#]], | ||
907 | ); | 400 | ); |
908 | } | 401 | } |
909 | 402 | ||
910 | #[test] | 403 | #[test] |
911 | fn infer_two_closures_lub() { | 404 | fn two_closures_lub() { |
912 | check_types( | 405 | check_types( |
913 | r#" | 406 | r#" |
914 | fn foo(c: i32) { | 407 | fn foo(c: i32) { |
915 | let add = |a: i32, b: i32| a + b; | 408 | let add = |a: i32, b: i32| a + b; |
916 | let sub = |a, b| a - b; | 409 | let sub = |a, b| a - b; |
917 | //^ |i32, i32| -> i32 | 410 | //^^^^^^^^^^^^ |i32, i32| -> i32 |
918 | if c > 42 { add } else { sub }; | 411 | if c > 42 { add } else { sub }; |
919 | //^ fn(i32, i32) -> i32 | 412 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32 |
920 | } | 413 | } |
921 | "#, | 414 | "#, |
922 | ) | 415 | ) |
923 | } | 416 | } |
924 | 417 | ||
925 | #[test] | 418 | #[test] |
926 | fn infer_match_diverging_branch_1() { | 419 | fn match_diverging_branch_1() { |
927 | check_types( | 420 | check_types( |
928 | r#" | 421 | r#" |
929 | enum Result<T> { Ok(T), Err } | 422 | enum Result<T> { Ok(T), Err } |
@@ -942,7 +435,7 @@ fn test() -> i32 { | |||
942 | } | 435 | } |
943 | 436 | ||
944 | #[test] | 437 | #[test] |
945 | fn infer_match_diverging_branch_2() { | 438 | fn match_diverging_branch_2() { |
946 | // same as 1 except for order of branches | 439 | // same as 1 except for order of branches |
947 | check_types( | 440 | check_types( |
948 | r#" | 441 | r#" |
@@ -998,15 +491,7 @@ fn main() { | |||
998 | fn coerce_unsize_expected_type() { | 491 | fn coerce_unsize_expected_type() { |
999 | check_no_mismatches( | 492 | check_no_mismatches( |
1000 | r#" | 493 | r#" |
1001 | #[lang = "sized"] | 494 | //- minicore: coerce_unsized |
1002 | pub trait Sized {} | ||
1003 | #[lang = "unsize"] | ||
1004 | pub trait Unsize<T> {} | ||
1005 | #[lang = "coerce_unsized"] | ||
1006 | pub trait CoerceUnsized<T> {} | ||
1007 | |||
1008 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
1009 | |||
1010 | fn main() { | 495 | fn main() { |
1011 | let foo: &[u32] = &[1, 2]; | 496 | let foo: &[u32] = &[1, 2]; |
1012 | let foo: &[u32] = match true { | 497 | let foo: &[u32] = match true { |
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs index 3d29021aa..058cd02d7 100644 --- a/crates/hir_ty/src/tests/display_source_code.rs +++ b/crates/hir_ty/src/tests/display_source_code.rs | |||
@@ -10,8 +10,8 @@ mod foo { | |||
10 | 10 | ||
11 | fn bar() { | 11 | fn bar() { |
12 | let foo: foo::Foo = foo::Foo; | 12 | let foo: foo::Foo = foo::Foo; |
13 | foo | 13 | foo; |
14 | } //^ foo::Foo | 14 | } //^^^ foo::Foo |
15 | 15 | ||
16 | "#, | 16 | "#, |
17 | ); | 17 | ); |
@@ -25,7 +25,7 @@ struct Foo<T = u8> { t: T } | |||
25 | fn main() { | 25 | fn main() { |
26 | let foo = Foo { t: 5u8 }; | 26 | let foo = Foo { t: 5u8 }; |
27 | foo; | 27 | foo; |
28 | } //^ Foo | 28 | } //^^^ Foo |
29 | "#, | 29 | "#, |
30 | ); | 30 | ); |
31 | 31 | ||
@@ -35,7 +35,7 @@ struct Foo<K, T = u8> { k: K, t: T } | |||
35 | fn main() { | 35 | fn main() { |
36 | let foo = Foo { k: 400, t: 5u8 }; | 36 | let foo = Foo { k: 400, t: 5u8 }; |
37 | foo; | 37 | foo; |
38 | } //^ Foo<i32> | 38 | } //^^^ Foo<i32> |
39 | "#, | 39 | "#, |
40 | ); | 40 | ); |
41 | } | 41 | } |
@@ -50,7 +50,7 @@ fn foo() -> *const (impl Unpin + Sized) { loop {} } | |||
50 | fn main() { | 50 | fn main() { |
51 | let foo = foo(); | 51 | let foo = foo(); |
52 | foo; | 52 | foo; |
53 | } //^ *const (impl Unpin + Sized) | 53 | } //^^^ *const (impl Unpin + Sized) |
54 | "#, | 54 | "#, |
55 | ); | 55 | ); |
56 | } | 56 | } |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index d14103aab..2cf41e49e 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -435,11 +435,11 @@ fn processes_impls_generated_by_macros() { | |||
435 | macro_rules! m { | 435 | macro_rules! m { |
436 | ($ident:ident) => (impl Trait for $ident {}) | 436 | ($ident:ident) => (impl Trait for $ident {}) |
437 | } | 437 | } |
438 | trait Trait { fn foo(self) -> u128 {} } | 438 | trait Trait { fn foo(self) -> u128 { 0 } } |
439 | struct S; | 439 | struct S; |
440 | m!(S); | 440 | m!(S); |
441 | fn test() { S.foo(); } | 441 | fn test() { S.foo(); } |
442 | //^ u128 | 442 | //^^^^^^^ u128 |
443 | "#, | 443 | "#, |
444 | ); | 444 | ); |
445 | } | 445 | } |
@@ -457,7 +457,7 @@ impl S { | |||
457 | } | 457 | } |
458 | 458 | ||
459 | fn test() { S.foo(); } | 459 | fn test() { S.foo(); } |
460 | //^ u128 | 460 | //^^^^^^^ u128 |
461 | "#, | 461 | "#, |
462 | ); | 462 | ); |
463 | } | 463 | } |
@@ -479,7 +479,7 @@ impl S { | |||
479 | } | 479 | } |
480 | 480 | ||
481 | fn test() { S.foo(); } | 481 | fn test() { S.foo(); } |
482 | //^ u128 | 482 | //^^^^^^^ u128 |
483 | "#, | 483 | "#, |
484 | ); | 484 | ); |
485 | } | 485 | } |
@@ -743,7 +743,7 @@ include!("foo.rs"); | |||
743 | 743 | ||
744 | fn main() { | 744 | fn main() { |
745 | bar(); | 745 | bar(); |
746 | } //^ u32 | 746 | } //^^^^^ u32 |
747 | 747 | ||
748 | //- /foo.rs | 748 | //- /foo.rs |
749 | fn bar() -> u32 {0} | 749 | fn bar() -> u32 {0} |
@@ -781,7 +781,7 @@ include!("f/foo.rs"); | |||
781 | 781 | ||
782 | fn main() { | 782 | fn main() { |
783 | bar::bar(); | 783 | bar::bar(); |
784 | } //^ u32 | 784 | } //^^^^^^^^^^ u32 |
785 | 785 | ||
786 | //- /f/foo.rs | 786 | //- /f/foo.rs |
787 | pub mod bar; | 787 | pub mod bar; |
@@ -853,7 +853,7 @@ include!("foo.rs"); | |||
853 | 853 | ||
854 | fn main() { | 854 | fn main() { |
855 | RegisterBlock { }; | 855 | RegisterBlock { }; |
856 | //^ RegisterBlock | 856 | //^^^^^^^^^^^^^^^^^ RegisterBlock |
857 | } | 857 | } |
858 | "#; | 858 | "#; |
859 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); | 859 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, data); |
@@ -879,7 +879,7 @@ include!(concat!("f", "oo.rs")); | |||
879 | 879 | ||
880 | fn main() { | 880 | fn main() { |
881 | bar(); | 881 | bar(); |
882 | } //^ u32 | 882 | } //^^^^^ u32 |
883 | 883 | ||
884 | //- /foo.rs | 884 | //- /foo.rs |
885 | fn bar() -> u32 {0} | 885 | fn bar() -> u32 {0} |
@@ -905,7 +905,7 @@ include!(concat!(env!("OUT_DIR"), "/foo.rs")); | |||
905 | 905 | ||
906 | fn main() { | 906 | fn main() { |
907 | bar(); | 907 | bar(); |
908 | } //^ {unknown} | 908 | } //^^^^^ {unknown} |
909 | 909 | ||
910 | //- /foo.rs | 910 | //- /foo.rs |
911 | fn bar() -> u32 {0} | 911 | fn bar() -> u32 {0} |
@@ -923,7 +923,7 @@ macro_rules! include {() => {}} | |||
923 | include!("main.rs"); | 923 | include!("main.rs"); |
924 | 924 | ||
925 | fn main() { | 925 | fn main() { |
926 | 0 | 926 | 0; |
927 | } //^ i32 | 927 | } //^ i32 |
928 | "#, | 928 | "#, |
929 | ); | 929 | ); |
@@ -979,7 +979,7 @@ fn infer_derive_clone_simple() { | |||
979 | struct S; | 979 | struct S; |
980 | fn test() { | 980 | fn test() { |
981 | S.clone(); | 981 | S.clone(); |
982 | } //^ S | 982 | } //^^^^^^^^^ S |
983 | 983 | ||
984 | //- /lib.rs crate:core | 984 | //- /lib.rs crate:core |
985 | pub mod prelude { | 985 | pub mod prelude { |
@@ -1028,7 +1028,7 @@ pub struct S; | |||
1028 | use core::S; | 1028 | use core::S; |
1029 | fn test() { | 1029 | fn test() { |
1030 | S.clone(); | 1030 | S.clone(); |
1031 | } //^ S | 1031 | } //^^^^^^^^^ S |
1032 | "#, | 1032 | "#, |
1033 | ); | 1033 | ); |
1034 | } | 1034 | } |
@@ -1044,7 +1044,8 @@ struct S; | |||
1044 | struct Wrapper<T>(T); | 1044 | struct Wrapper<T>(T); |
1045 | struct NonClone; | 1045 | struct NonClone; |
1046 | fn test() { | 1046 | fn test() { |
1047 | (Wrapper(S).clone(), Wrapper(NonClone).clone()); | 1047 | let x = (Wrapper(S).clone(), Wrapper(NonClone).clone()); |
1048 | x; | ||
1048 | //^ (Wrapper<S>, {unknown}) | 1049 | //^ (Wrapper<S>, {unknown}) |
1049 | } | 1050 | } |
1050 | 1051 | ||
@@ -1079,7 +1080,7 @@ struct S{} | |||
1079 | 1080 | ||
1080 | fn test() { | 1081 | fn test() { |
1081 | S{}; | 1082 | S{}; |
1082 | } //^ S | 1083 | } //^^^ S |
1083 | "#, | 1084 | "#, |
1084 | ); | 1085 | ); |
1085 | } | 1086 | } |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index f26b2c8a7..3f7a37295 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -257,7 +257,7 @@ fn test() { | |||
257 | mod foo { | 257 | mod foo { |
258 | struct S; | 258 | struct S; |
259 | impl S { | 259 | impl S { |
260 | fn thing() -> i128 {} | 260 | fn thing() -> i128 { 0 } |
261 | } | 261 | } |
262 | } | 262 | } |
263 | "#, | 263 | "#, |
@@ -267,164 +267,128 @@ mod foo { | |||
267 | #[test] | 267 | #[test] |
268 | fn infer_trait_method_simple() { | 268 | fn infer_trait_method_simple() { |
269 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 269 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
270 | check_infer( | 270 | check_types( |
271 | r#" | 271 | r#" |
272 | trait Trait1 { | 272 | trait Trait1 { |
273 | fn method(&self) -> u32; | 273 | fn method(&self) -> u32; |
274 | } | 274 | } |
275 | struct S1; | 275 | struct S1; |
276 | impl Trait1 for S1 {} | 276 | impl Trait1 for S1 {} |
277 | trait Trait2 { | 277 | trait Trait2 { |
278 | fn method(&self) -> i128; | 278 | fn method(&self) -> i128; |
279 | } | 279 | } |
280 | struct S2; | 280 | struct S2; |
281 | impl Trait2 for S2 {} | 281 | impl Trait2 for S2 {} |
282 | fn test() { | 282 | fn test() { |
283 | S1.method(); // -> u32 | 283 | S1.method(); |
284 | S2.method(); // -> i128 | 284 | //^^^^^^^^^^^ u32 |
285 | } | 285 | S2.method(); // -> i128 |
286 | //^^^^^^^^^^^ i128 | ||
287 | } | ||
286 | "#, | 288 | "#, |
287 | expect![[r#" | ||
288 | 30..34 'self': &Self | ||
289 | 109..113 'self': &Self | ||
290 | 169..227 '{ ...i128 }': () | ||
291 | 175..177 'S1': S1 | ||
292 | 175..186 'S1.method()': u32 | ||
293 | 202..204 'S2': S2 | ||
294 | 202..213 'S2.method()': i128 | ||
295 | "#]], | ||
296 | ); | 289 | ); |
297 | } | 290 | } |
298 | 291 | ||
299 | #[test] | 292 | #[test] |
300 | fn infer_trait_method_scoped() { | 293 | fn infer_trait_method_scoped() { |
301 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 294 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
302 | check_infer( | 295 | check_types( |
303 | r#" | 296 | r#" |
304 | struct S; | 297 | struct S; |
305 | mod foo { | 298 | mod foo { |
306 | pub trait Trait1 { | 299 | pub trait Trait1 { |
307 | fn method(&self) -> u32; | 300 | fn method(&self) -> u32; |
308 | } | 301 | } |
309 | impl Trait1 for super::S {} | 302 | impl Trait1 for super::S {} |
310 | } | 303 | } |
311 | mod bar { | 304 | mod bar { |
312 | pub trait Trait2 { | 305 | pub trait Trait2 { |
313 | fn method(&self) -> i128; | 306 | fn method(&self) -> i128; |
314 | } | 307 | } |
315 | impl Trait2 for super::S {} | 308 | impl Trait2 for super::S {} |
316 | } | 309 | } |
317 | 310 | ||
318 | mod foo_test { | 311 | mod foo_test { |
319 | use super::S; | 312 | use super::S; |
320 | use super::foo::Trait1; | 313 | use super::foo::Trait1; |
321 | fn test() { | 314 | fn test() { |
322 | S.method(); // -> u32 | 315 | S.method(); |
323 | } | 316 | //^^^^^^^^^^ u32 |
324 | } | 317 | } |
318 | } | ||
325 | 319 | ||
326 | mod bar_test { | 320 | mod bar_test { |
327 | use super::S; | 321 | use super::S; |
328 | use super::bar::Trait2; | 322 | use super::bar::Trait2; |
329 | fn test() { | 323 | fn test() { |
330 | S.method(); // -> i128 | 324 | S.method(); |
331 | } | 325 | //^^^^^^^^^^ i128 |
332 | } | 326 | } |
327 | } | ||
333 | "#, | 328 | "#, |
334 | expect![[r#" | ||
335 | 62..66 'self': &Self | ||
336 | 168..172 'self': &Self | ||
337 | 299..336 '{ ... }': () | ||
338 | 309..310 'S': S | ||
339 | 309..319 'S.method()': u32 | ||
340 | 415..453 '{ ... }': () | ||
341 | 425..426 'S': S | ||
342 | 425..435 'S.method()': i128 | ||
343 | "#]], | ||
344 | ); | 329 | ); |
345 | } | 330 | } |
346 | 331 | ||
347 | #[test] | 332 | #[test] |
348 | fn infer_trait_method_generic_1() { | 333 | fn infer_trait_method_generic_1() { |
349 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 334 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
350 | check_infer( | 335 | check_types( |
351 | r#" | 336 | r#" |
352 | trait Trait<T> { | 337 | trait Trait<T> { |
353 | fn method(&self) -> T; | 338 | fn method(&self) -> T; |
354 | } | 339 | } |
355 | struct S; | 340 | struct S; |
356 | impl Trait<u32> for S {} | 341 | impl Trait<u32> for S {} |
357 | fn test() { | 342 | fn test() { |
358 | S.method(); | 343 | S.method(); |
359 | } | 344 | //^^^^^^^^^^ u32 |
345 | } | ||
360 | "#, | 346 | "#, |
361 | expect![[r#" | ||
362 | 32..36 'self': &Self | ||
363 | 91..110 '{ ...d(); }': () | ||
364 | 97..98 'S': S | ||
365 | 97..107 'S.method()': u32 | ||
366 | "#]], | ||
367 | ); | 347 | ); |
368 | } | 348 | } |
369 | 349 | ||
370 | #[test] | 350 | #[test] |
371 | fn infer_trait_method_generic_more_params() { | 351 | fn infer_trait_method_generic_more_params() { |
372 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 352 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
373 | check_infer( | 353 | check_types( |
374 | r#" | 354 | r#" |
375 | trait Trait<T1, T2, T3> { | 355 | trait Trait<T1, T2, T3> { |
376 | fn method1(&self) -> (T1, T2, T3); | 356 | fn method1(&self) -> (T1, T2, T3); |
377 | fn method2(&self) -> (T3, T2, T1); | 357 | fn method2(&self) -> (T3, T2, T1); |
378 | } | 358 | } |
379 | struct S1; | 359 | struct S1; |
380 | impl Trait<u8, u16, u32> for S1 {} | 360 | impl Trait<u8, u16, u32> for S1 {} |
381 | struct S2; | 361 | struct S2; |
382 | impl<T> Trait<i8, i16, T> for S2 {} | 362 | impl<T> Trait<i8, i16, T> for S2 {} |
383 | fn test() { | 363 | fn test() { |
384 | S1.method1(); // u8, u16, u32 | 364 | S1.method1(); |
385 | S1.method2(); // u32, u16, u8 | 365 | //^^^^^^^^^^^^ (u8, u16, u32) |
386 | S2.method1(); // i8, i16, {unknown} | 366 | S1.method2(); |
387 | S2.method2(); // {unknown}, i16, i8 | 367 | //^^^^^^^^^^^^ (u32, u16, u8) |
388 | } | 368 | S2.method1(); |
369 | //^^^^^^^^^^^^ (i8, i16, {unknown}) | ||
370 | S2.method2(); | ||
371 | //^^^^^^^^^^^^ ({unknown}, i16, i8) | ||
372 | } | ||
389 | "#, | 373 | "#, |
390 | expect![[r#" | ||
391 | 42..46 'self': &Self | ||
392 | 81..85 'self': &Self | ||
393 | 209..360 '{ ..., i8 }': () | ||
394 | 215..217 'S1': S1 | ||
395 | 215..227 'S1.method1()': (u8, u16, u32) | ||
396 | 249..251 'S1': S1 | ||
397 | 249..261 'S1.method2()': (u32, u16, u8) | ||
398 | 283..285 'S2': S2 | ||
399 | 283..295 'S2.method1()': (i8, i16, {unknown}) | ||
400 | 323..325 'S2': S2 | ||
401 | 323..335 'S2.method2()': ({unknown}, i16, i8) | ||
402 | "#]], | ||
403 | ); | 374 | ); |
404 | } | 375 | } |
405 | 376 | ||
406 | #[test] | 377 | #[test] |
407 | fn infer_trait_method_generic_2() { | 378 | fn infer_trait_method_generic_2() { |
408 | // the trait implementation is intentionally incomplete -- it shouldn't matter | 379 | // the trait implementation is intentionally incomplete -- it shouldn't matter |
409 | check_infer( | 380 | check_types( |
410 | r#" | 381 | r#" |
411 | trait Trait<T> { | 382 | trait Trait<T> { |
412 | fn method(&self) -> T; | 383 | fn method(&self) -> T; |
413 | } | 384 | } |
414 | struct S<T>(T); | 385 | struct S<T>(T); |
415 | impl<U> Trait<U> for S<U> {} | 386 | impl<U> Trait<U> for S<U> {} |
416 | fn test() { | 387 | fn test() { |
417 | S(1u32).method(); | 388 | S(1u32).method(); |
418 | } | 389 | //^^^^^^^^^^^^^^^^ u32 |
390 | } | ||
419 | "#, | 391 | "#, |
420 | expect![[r#" | ||
421 | 32..36 'self': &Self | ||
422 | 101..126 '{ ...d(); }': () | ||
423 | 107..108 'S': S<u32>(u32) -> S<u32> | ||
424 | 107..114 'S(1u32)': S<u32> | ||
425 | 107..123 'S(1u32...thod()': u32 | ||
426 | 109..113 '1u32': u32 | ||
427 | "#]], | ||
428 | ); | 392 | ); |
429 | } | 393 | } |
430 | 394 | ||
@@ -685,10 +649,10 @@ fn method_resolution_unify_impl_self_type() { | |||
685 | check_types( | 649 | check_types( |
686 | r#" | 650 | r#" |
687 | struct S<T>; | 651 | struct S<T>; |
688 | impl S<u32> { fn foo(&self) -> u8 {} } | 652 | impl S<u32> { fn foo(&self) -> u8 { 0 } } |
689 | impl S<i32> { fn foo(&self) -> i8 {} } | 653 | impl S<i32> { fn foo(&self) -> i8 { 0 } } |
690 | fn test() { (S::<u32>.foo(), S::<i32>.foo()); } | 654 | fn test() { (S::<u32>.foo(), S::<i32>.foo()); } |
691 | //^ (u8, i8) | 655 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8) |
692 | "#, | 656 | "#, |
693 | ); | 657 | ); |
694 | } | 658 | } |
@@ -702,7 +666,7 @@ struct S; | |||
702 | impl S { fn foo(&self) -> i8 { 0 } } | 666 | impl S { fn foo(&self) -> i8 { 0 } } |
703 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 667 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
704 | fn test() { S.foo(); } | 668 | fn test() { S.foo(); } |
705 | //^ u128 | 669 | //^^^^^^^ u128 |
706 | "#, | 670 | "#, |
707 | ); | 671 | ); |
708 | } | 672 | } |
@@ -716,7 +680,7 @@ struct S; | |||
716 | impl Clone for S {} | 680 | impl Clone for S {} |
717 | impl Clone for &S {} | 681 | impl Clone for &S {} |
718 | fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } | 682 | fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } |
719 | //^ (S, S, &S) | 683 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S) |
720 | "#, | 684 | "#, |
721 | ); | 685 | ); |
722 | } | 686 | } |
@@ -730,7 +694,7 @@ struct S; | |||
730 | impl S { fn foo(self) -> i8 { 0 } } | 694 | impl S { fn foo(self) -> i8 { 0 } } |
731 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 695 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
732 | fn test() { (&S).foo(); } | 696 | fn test() { (&S).foo(); } |
733 | //^ u128 | 697 | //^^^^^^^^^^ u128 |
734 | "#, | 698 | "#, |
735 | ); | 699 | ); |
736 | } | 700 | } |
@@ -744,7 +708,7 @@ struct S; | |||
744 | impl S { fn foo(self) -> i8 { 0 } } | 708 | impl S { fn foo(self) -> i8 { 0 } } |
745 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 709 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
746 | fn test() { S.foo(); } | 710 | fn test() { S.foo(); } |
747 | //^ i8 | 711 | //^^^^^^^ i8 |
748 | "#, | 712 | "#, |
749 | ); | 713 | ); |
750 | } | 714 | } |
@@ -758,7 +722,7 @@ struct S; | |||
758 | impl S { fn foo(&self) -> i8 { 0 } } | 722 | impl S { fn foo(&self) -> i8 { 0 } } |
759 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | 723 | impl Trait for &S { fn foo(self) -> u128 { 0 } } |
760 | fn test() { S.foo(); } | 724 | fn test() { S.foo(); } |
761 | //^ i8 | 725 | //^^^^^^^ i8 |
762 | "#, | 726 | "#, |
763 | ); | 727 | ); |
764 | } | 728 | } |
@@ -771,7 +735,7 @@ trait Trait { fn foo(self) -> u128; } | |||
771 | struct S; | 735 | struct S; |
772 | impl Trait for S { fn foo(self) -> u128 { 0 } } | 736 | impl Trait for S { fn foo(self) -> u128 { 0 } } |
773 | fn test() { (&S).foo(); } | 737 | fn test() { (&S).foo(); } |
774 | //^ u128 | 738 | //^^^^^^^^^^ u128 |
775 | "#, | 739 | "#, |
776 | ); | 740 | ); |
777 | } | 741 | } |
@@ -780,14 +744,11 @@ fn test() { (&S).foo(); } | |||
780 | fn method_resolution_unsize_array() { | 744 | fn method_resolution_unsize_array() { |
781 | check_types( | 745 | check_types( |
782 | r#" | 746 | r#" |
783 | #[lang = "slice"] | 747 | //- minicore: slice |
784 | impl<T> [T] { | ||
785 | fn len(&self) -> usize { loop {} } | ||
786 | } | ||
787 | fn test() { | 748 | fn test() { |
788 | let a = [1, 2, 3]; | 749 | let a = [1, 2, 3]; |
789 | a.len(); | 750 | a.len(); |
790 | } //^ usize | 751 | } //^^^^^^^ usize |
791 | "#, | 752 | "#, |
792 | ); | 753 | ); |
793 | } | 754 | } |
@@ -802,7 +763,7 @@ impl Clone for S {} | |||
802 | 763 | ||
803 | fn test() { | 764 | fn test() { |
804 | S.clone(); | 765 | S.clone(); |
805 | //^ S | 766 | //^^^^^^^^^ S |
806 | } | 767 | } |
807 | 768 | ||
808 | //- /lib.rs crate:core | 769 | //- /lib.rs crate:core |
@@ -826,7 +787,7 @@ trait Trait { fn foo(self) -> u128; } | |||
826 | struct S; | 787 | struct S; |
827 | impl<T> Trait for T where T: UnknownTrait {} | 788 | impl<T> Trait for T where T: UnknownTrait {} |
828 | fn test() { (&S).foo(); } | 789 | fn test() { (&S).foo(); } |
829 | //^ u128 | 790 | //^^^^^^^^^^ u128 |
830 | "#, | 791 | "#, |
831 | ); | 792 | ); |
832 | } | 793 | } |
@@ -844,7 +805,7 @@ trait Trait { fn foo(self) -> u128; } | |||
844 | struct S; | 805 | struct S; |
845 | impl<T> Trait for T where T: Clone {} | 806 | impl<T> Trait for T where T: Clone {} |
846 | fn test() { (&S).foo(); } | 807 | fn test() { (&S).foo(); } |
847 | //^ {unknown} | 808 | //^^^^^^^^^^ {unknown} |
848 | "#, | 809 | "#, |
849 | ); | 810 | ); |
850 | } | 811 | } |
@@ -859,7 +820,7 @@ trait Trait { fn foo(self) -> u128; } | |||
859 | struct S; | 820 | struct S; |
860 | impl<T: Clone> Trait for T {} | 821 | impl<T: Clone> Trait for T {} |
861 | fn test() { (&S).foo(); } | 822 | fn test() { (&S).foo(); } |
862 | //^ {unknown} | 823 | //^^^^^^^^^^ {unknown} |
863 | "#, | 824 | "#, |
864 | ); | 825 | ); |
865 | } | 826 | } |
@@ -874,7 +835,7 @@ struct S; | |||
874 | impl Clone for S {} | 835 | impl Clone for S {} |
875 | impl<T> Trait for T where T: Clone {} | 836 | impl<T> Trait for T where T: Clone {} |
876 | fn test() { S.foo(); } | 837 | fn test() { S.foo(); } |
877 | //^ u128 | 838 | //^^^^^^^ u128 |
878 | "#, | 839 | "#, |
879 | ); | 840 | ); |
880 | } | 841 | } |
@@ -890,7 +851,7 @@ struct S2; | |||
890 | impl From<S2> for S1 {} | 851 | impl From<S2> for S1 {} |
891 | impl<T, U> Into<U> for T where U: From<T> {} | 852 | impl<T, U> Into<U> for T where U: From<T> {} |
892 | fn test() { S2.into(); } | 853 | fn test() { S2.into(); } |
893 | //^ {unknown} | 854 | //^^^^^^^^^ {unknown} |
894 | "#, | 855 | "#, |
895 | ); | 856 | ); |
896 | } | 857 | } |
@@ -906,7 +867,7 @@ struct S2; | |||
906 | impl From<S2> for S1 {} | 867 | impl From<S2> for S1 {} |
907 | impl<T, U: From<T>> Into<U> for T {} | 868 | impl<T, U: From<T>> Into<U> for T {} |
908 | fn test() { S2.into(); } | 869 | fn test() { S2.into(); } |
909 | //^ {unknown} | 870 | //^^^^^^^^^ {unknown} |
910 | "#, | 871 | "#, |
911 | ); | 872 | ); |
912 | } | 873 | } |
@@ -936,7 +897,7 @@ fn main() { | |||
936 | let a = Wrapper::<Foo<f32>>::new(1.0); | 897 | let a = Wrapper::<Foo<f32>>::new(1.0); |
937 | let b = Wrapper::<Bar<f32>>::new(1.0); | 898 | let b = Wrapper::<Bar<f32>>::new(1.0); |
938 | (a, b); | 899 | (a, b); |
939 | //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) | 900 | //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) |
940 | } | 901 | } |
941 | "#, | 902 | "#, |
942 | ); | 903 | ); |
@@ -950,7 +911,7 @@ fn method_resolution_encountering_fn_type() { | |||
950 | fn foo() {} | 911 | fn foo() {} |
951 | trait FnOnce { fn call(self); } | 912 | trait FnOnce { fn call(self); } |
952 | fn test() { foo.call(); } | 913 | fn test() { foo.call(); } |
953 | //^ {unknown} | 914 | //^^^^^^^^^^ {unknown} |
954 | "#, | 915 | "#, |
955 | ); | 916 | ); |
956 | } | 917 | } |
@@ -1016,7 +977,7 @@ where | |||
1016 | Wrapper<T>: a::Foo, | 977 | Wrapper<T>: a::Foo, |
1017 | { | 978 | { |
1018 | t.foo(); | 979 | t.foo(); |
1019 | } //^ {unknown} | 980 | } //^^^^^^^ {unknown} |
1020 | "#, | 981 | "#, |
1021 | ); | 982 | ); |
1022 | } | 983 | } |
@@ -1033,7 +994,7 @@ impl A<i32> { | |||
1033 | 994 | ||
1034 | fn main() { | 995 | fn main() { |
1035 | A::from(3); | 996 | A::from(3); |
1036 | } //^ A<i32> | 997 | } //^^^^^^^^^^ A<i32> |
1037 | "#, | 998 | "#, |
1038 | ); | 999 | ); |
1039 | } | 1000 | } |
@@ -1061,7 +1022,7 @@ trait FnX {} | |||
1061 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} | 1022 | impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} |
1062 | 1023 | ||
1063 | fn test() { (S {}).method(); } | 1024 | fn test() { (S {}).method(); } |
1064 | //^ () | 1025 | //^^^^^^^^^^^^^^^ () |
1065 | "#, | 1026 | "#, |
1066 | ); | 1027 | ); |
1067 | } | 1028 | } |
@@ -1146,8 +1107,8 @@ impl<T> Slice<T> { | |||
1146 | 1107 | ||
1147 | fn main() { | 1108 | fn main() { |
1148 | let foo: Slice<u32>; | 1109 | let foo: Slice<u32>; |
1149 | (foo.into_vec()); // we don't actually support arbitrary self types, but we shouldn't crash at least | 1110 | foo.into_vec(); // we shouldn't crash on this at least |
1150 | } //^ {unknown} | 1111 | } //^^^^^^^^^^^^^^ {unknown} |
1151 | "#, | 1112 | "#, |
1152 | ); | 1113 | ); |
1153 | } | 1114 | } |
@@ -1168,7 +1129,7 @@ impl dyn Foo + '_ { | |||
1168 | fn main() { | 1129 | fn main() { |
1169 | let f = &42u32 as &dyn Foo; | 1130 | let f = &42u32 as &dyn Foo; |
1170 | f.dyn_foo(); | 1131 | f.dyn_foo(); |
1171 | // ^u32 | 1132 | // ^^^^^^^^^^^ u32 |
1172 | } | 1133 | } |
1173 | "#, | 1134 | "#, |
1174 | ); | 1135 | ); |
@@ -1178,11 +1139,7 @@ fn main() { | |||
1178 | fn autoderef_visibility_field() { | 1139 | fn autoderef_visibility_field() { |
1179 | check_infer( | 1140 | check_infer( |
1180 | r#" | 1141 | r#" |
1181 | #[lang = "deref"] | 1142 | //- minicore: deref |
1182 | pub trait Deref { | ||
1183 | type Target; | ||
1184 | fn deref(&self) -> &Self::Target; | ||
1185 | } | ||
1186 | mod a { | 1143 | mod a { |
1187 | pub struct Foo(pub char); | 1144 | pub struct Foo(pub char); |
1188 | pub struct Bar(i32); | 1145 | pub struct Bar(i32); |
@@ -1191,7 +1148,7 @@ mod a { | |||
1191 | Self(0) | 1148 | Self(0) |
1192 | } | 1149 | } |
1193 | } | 1150 | } |
1194 | impl super::Deref for Bar { | 1151 | impl core::ops::Deref for Bar { |
1195 | type Target = Foo; | 1152 | type Target = Foo; |
1196 | fn deref(&self) -> &Foo { | 1153 | fn deref(&self) -> &Foo { |
1197 | &Foo('z') | 1154 | &Foo('z') |
@@ -1205,22 +1162,21 @@ mod b { | |||
1205 | } | 1162 | } |
1206 | "#, | 1163 | "#, |
1207 | expect![[r#" | 1164 | expect![[r#" |
1208 | 67..71 'self': &Self | 1165 | 107..138 '{ ... }': Bar |
1209 | 200..231 '{ ... }': Bar | 1166 | 121..125 'Self': Bar(i32) -> Bar |
1210 | 214..218 'Self': Bar(i32) -> Bar | 1167 | 121..128 'Self(0)': Bar |
1211 | 214..221 'Self(0)': Bar | 1168 | 126..127 '0': i32 |
1212 | 219..220 '0': i32 | 1169 | 226..230 'self': &Bar |
1213 | 315..319 'self': &Bar | 1170 | 240..273 '{ ... }': &Foo |
1214 | 329..362 '{ ... }': &Foo | 1171 | 254..263 '&Foo('z')': &Foo |
1215 | 343..352 '&Foo('z')': &Foo | 1172 | 255..258 'Foo': Foo(char) -> Foo |
1216 | 344..347 'Foo': Foo(char) -> Foo | 1173 | 255..263 'Foo('z')': Foo |
1217 | 344..352 'Foo('z')': Foo | 1174 | 259..262 ''z'': char |
1218 | 348..351 ''z'': char | 1175 | 303..350 '{ ... }': () |
1219 | 392..439 '{ ... }': () | 1176 | 317..318 'x': char |
1220 | 406..407 'x': char | 1177 | 321..339 'super:...r::new': fn new() -> Bar |
1221 | 410..428 'super:...r::new': fn new() -> Bar | 1178 | 321..341 'super:...:new()': Bar |
1222 | 410..430 'super:...:new()': Bar | 1179 | 321..343 'super:...ew().0': char |
1223 | 410..432 'super:...ew().0': char | ||
1224 | "#]], | 1180 | "#]], |
1225 | ) | 1181 | ) |
1226 | } | 1182 | } |
@@ -1230,11 +1186,7 @@ fn autoderef_visibility_method() { | |||
1230 | cov_mark::check!(autoderef_candidate_not_visible); | 1186 | cov_mark::check!(autoderef_candidate_not_visible); |
1231 | check_infer( | 1187 | check_infer( |
1232 | r#" | 1188 | r#" |
1233 | #[lang = "deref"] | 1189 | //- minicore: deref |
1234 | pub trait Deref { | ||
1235 | type Target; | ||
1236 | fn deref(&self) -> &Self::Target; | ||
1237 | } | ||
1238 | mod a { | 1190 | mod a { |
1239 | pub struct Foo(pub char); | 1191 | pub struct Foo(pub char); |
1240 | impl Foo { | 1192 | impl Foo { |
@@ -1251,7 +1203,7 @@ mod a { | |||
1251 | self.0 | 1203 | self.0 |
1252 | } | 1204 | } |
1253 | } | 1205 | } |
1254 | impl super::Deref for Bar { | 1206 | impl core::ops::Deref for Bar { |
1255 | type Target = Foo; | 1207 | type Target = Foo; |
1256 | fn deref(&self) -> &Foo { | 1208 | fn deref(&self) -> &Foo { |
1257 | &Foo('z') | 1209 | &Foo('z') |
@@ -1265,30 +1217,29 @@ mod b { | |||
1265 | } | 1217 | } |
1266 | "#, | 1218 | "#, |
1267 | expect![[r#" | 1219 | expect![[r#" |
1268 | 67..71 'self': &Self | 1220 | 75..79 'self': &Foo |
1269 | 168..172 'self': &Foo | 1221 | 89..119 '{ ... }': char |
1270 | 182..212 '{ ... }': char | 1222 | 103..107 'self': &Foo |
1271 | 196..200 'self': &Foo | 1223 | 103..109 'self.0': char |
1272 | 196..202 'self.0': char | 1224 | 195..226 '{ ... }': Bar |
1273 | 288..319 '{ ... }': Bar | 1225 | 209..213 'Self': Bar(i32) -> Bar |
1274 | 302..306 'Self': Bar(i32) -> Bar | 1226 | 209..216 'Self(0)': Bar |
1275 | 302..309 'Self(0)': Bar | 1227 | 214..215 '0': i32 |
1276 | 307..308 '0': i32 | 1228 | 245..249 'self': &Bar |
1277 | 338..342 'self': &Bar | 1229 | 258..288 '{ ... }': i32 |
1278 | 351..381 '{ ... }': i32 | 1230 | 272..276 'self': &Bar |
1279 | 365..369 'self': &Bar | 1231 | 272..278 'self.0': i32 |
1280 | 365..371 'self.0': i32 | 1232 | 376..380 'self': &Bar |
1281 | 465..469 'self': &Bar | 1233 | 390..423 '{ ... }': &Foo |
1282 | 479..512 '{ ... }': &Foo | 1234 | 404..413 '&Foo('z')': &Foo |
1283 | 493..502 '&Foo('z')': &Foo | 1235 | 405..408 'Foo': Foo(char) -> Foo |
1284 | 494..497 'Foo': Foo(char) -> Foo | 1236 | 405..413 'Foo('z')': Foo |
1285 | 494..502 'Foo('z')': Foo | 1237 | 409..412 ''z'': char |
1286 | 498..501 ''z'': char | 1238 | 453..506 '{ ... }': () |
1287 | 542..595 '{ ... }': () | 1239 | 467..468 'x': char |
1288 | 556..557 'x': char | 1240 | 471..489 'super:...r::new': fn new() -> Bar |
1289 | 560..578 'super:...r::new': fn new() -> Bar | 1241 | 471..491 'super:...:new()': Bar |
1290 | 560..580 'super:...:new()': Bar | 1242 | 471..499 'super:...ango()': char |
1291 | 560..588 'super:...ango()': char | ||
1292 | "#]], | 1243 | "#]], |
1293 | ) | 1244 | ) |
1294 | } | 1245 | } |
@@ -1389,11 +1340,11 @@ pub trait IntoIterator { | |||
1389 | 1340 | ||
1390 | impl<T> IntoIterator for [T; 1] { | 1341 | impl<T> IntoIterator for [T; 1] { |
1391 | type Out = T; | 1342 | type Out = T; |
1392 | fn into_iter(self) -> Self::Out {} | 1343 | fn into_iter(self) -> Self::Out { loop {} } |
1393 | } | 1344 | } |
1394 | impl<'a, T> IntoIterator for &'a [T] { | 1345 | impl<'a, T> IntoIterator for &'a [T] { |
1395 | type Out = &'a T; | 1346 | type Out = &'a T; |
1396 | fn into_iter(self) -> Self::Out {} | 1347 | fn into_iter(self) -> Self::Out { loop {} } |
1397 | } | 1348 | } |
1398 | "#, | 1349 | "#, |
1399 | ); | 1350 | ); |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index aa513c56d..47aa30d2e 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | 2 | ||
3 | use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types}; | 3 | use super::{check, check_infer, check_infer_with_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn infer_pattern() { | 6 | fn infer_pattern() { |
@@ -518,7 +518,7 @@ fn infer_generics_in_patterns() { | |||
518 | 518 | ||
519 | #[test] | 519 | #[test] |
520 | fn infer_const_pattern() { | 520 | fn infer_const_pattern() { |
521 | check_mismatches( | 521 | check( |
522 | r#" | 522 | r#" |
523 | enum Option<T> { None } | 523 | enum Option<T> { None } |
524 | use Option::None; | 524 | use Option::None; |
@@ -571,48 +571,44 @@ fn main() { | |||
571 | fn match_ergonomics_in_closure_params() { | 571 | fn match_ergonomics_in_closure_params() { |
572 | check_infer( | 572 | check_infer( |
573 | r#" | 573 | r#" |
574 | #[lang = "fn_once"] | 574 | //- minicore: fn |
575 | trait FnOnce<Args> { | 575 | fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} } |
576 | type Output; | ||
577 | } | ||
578 | |||
579 | fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} } | ||
580 | 576 | ||
581 | fn test() { | 577 | fn test() { |
582 | foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics | 578 | foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics |
583 | foo(&(1, "a"), |(x, y)| x); | 579 | foo(&(1, "a"), |(x, y)| x); |
584 | } | 580 | } |
585 | "#, | 581 | "#, |
586 | expect![[r#" | 582 | expect![[r#" |
587 | 93..94 't': T | 583 | 32..33 't': T |
588 | 99..100 'f': F | 584 | 38..39 'f': F |
589 | 110..121 '{ loop {} }': U | 585 | 49..60 '{ loop {} }': U |
590 | 112..119 'loop {}': ! | 586 | 51..58 'loop {}': ! |
591 | 117..119 '{}': () | 587 | 56..58 '{}': () |
592 | 133..232 '{ ... x); }': () | 588 | 72..171 '{ ... x); }': () |
593 | 139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 | 589 | 78..81 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 |
594 | 139..166 'foo(&(...y)| x)': i32 | 590 | 78..105 'foo(&(...y)| x)': i32 |
595 | 143..152 '&(1, "a")': &(i32, &str) | 591 | 82..91 '&(1, "a")': &(i32, &str) |
596 | 144..152 '(1, "a")': (i32, &str) | 592 | 83..91 '(1, "a")': (i32, &str) |
597 | 145..146 '1': i32 | 593 | 84..85 '1': i32 |
598 | 148..151 '"a"': &str | 594 | 87..90 '"a"': &str |
599 | 154..165 '|&(x, y)| x': |&(i32, &str)| -> i32 | 595 | 93..104 '|&(x, y)| x': |&(i32, &str)| -> i32 |
600 | 155..162 '&(x, y)': &(i32, &str) | 596 | 94..101 '&(x, y)': &(i32, &str) |
601 | 156..162 '(x, y)': (i32, &str) | 597 | 95..101 '(x, y)': (i32, &str) |
602 | 157..158 'x': i32 | 598 | 96..97 'x': i32 |
603 | 160..161 'y': &str | 599 | 99..100 'y': &str |
604 | 164..165 'x': i32 | 600 | 103..104 'x': i32 |
605 | 203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 | 601 | 142..145 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 |
606 | 203..229 'foo(&(...y)| x)': &i32 | 602 | 142..168 'foo(&(...y)| x)': &i32 |
607 | 207..216 '&(1, "a")': &(i32, &str) | 603 | 146..155 '&(1, "a")': &(i32, &str) |
608 | 208..216 '(1, "a")': (i32, &str) | 604 | 147..155 '(1, "a")': (i32, &str) |
609 | 209..210 '1': i32 | 605 | 148..149 '1': i32 |
610 | 212..215 '"a"': &str | 606 | 151..154 '"a"': &str |
611 | 218..228 '|(x, y)| x': |&(i32, &str)| -> &i32 | 607 | 157..167 '|(x, y)| x': |&(i32, &str)| -> &i32 |
612 | 219..225 '(x, y)': (i32, &str) | 608 | 158..164 '(x, y)': (i32, &str) |
613 | 220..221 'x': &i32 | 609 | 159..160 'x': &i32 |
614 | 223..224 'y': &&str | 610 | 162..163 'y': &&str |
615 | 227..228 'x': &i32 | 611 | 166..167 'x': &i32 |
616 | "#]], | 612 | "#]], |
617 | ); | 613 | ); |
618 | } | 614 | } |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 1019e783b..8c5e8954c 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | 2 | ||
3 | use super::{check_infer, check_types}; | 3 | use super::{check_infer, check_no_mismatches, check_types}; |
4 | 4 | ||
5 | #[test] | 5 | #[test] |
6 | fn bug_484() { | 6 | fn bug_484() { |
@@ -418,55 +418,24 @@ fn issue_2705() { | |||
418 | fn issue_2683_chars_impl() { | 418 | fn issue_2683_chars_impl() { |
419 | check_types( | 419 | check_types( |
420 | r#" | 420 | r#" |
421 | //- /main.rs crate:main deps:std | 421 | //- minicore: iterator |
422 | fn test() { | 422 | pub struct Chars<'a> {} |
423 | let chars: std::str::Chars<'_>; | 423 | impl<'a> Iterator for Chars<'a> { |
424 | (chars.next(), chars.nth(1)); | 424 | type Item = char; |
425 | } //^ (Option<char>, Option<char>) | 425 | fn next(&mut self) -> Option<char> { loop {} } |
426 | |||
427 | //- /std.rs crate:std | ||
428 | #[prelude_import] | ||
429 | use self::prelude::rust_2018::*; | ||
430 | pub mod prelude { | ||
431 | pub mod rust_2018 { | ||
432 | pub use crate::iter::Iterator; | ||
433 | pub use crate::option::Option; | ||
434 | } | ||
435 | } | 426 | } |
436 | 427 | ||
437 | pub mod iter { | 428 | fn test() { |
438 | pub use self::traits::Iterator; | 429 | let chars: Chars<'_>; |
439 | pub mod traits { | 430 | (chars.next(), chars.nth(1)); |
440 | pub use self::iterator::Iterator; | 431 | } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Option<char>, Option<char>) |
441 | |||
442 | pub mod iterator { | ||
443 | pub trait Iterator { | ||
444 | type Item; | ||
445 | fn next(&mut self) -> Option<Self::Item>; | ||
446 | fn nth(&mut self, n: usize) -> Option<Self::Item> {} | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | pub mod option { | ||
453 | pub enum Option<T> {} | ||
454 | } | ||
455 | |||
456 | pub mod str { | ||
457 | pub struct Chars<'a> {} | ||
458 | impl<'a> Iterator for Chars<'a> { | ||
459 | type Item = char; | ||
460 | fn next(&mut self) -> Option<char> {} | ||
461 | } | ||
462 | } | ||
463 | "#, | 432 | "#, |
464 | ); | 433 | ); |
465 | } | 434 | } |
466 | 435 | ||
467 | #[test] | 436 | #[test] |
468 | fn issue_3642_bad_macro_stackover() { | 437 | fn issue_3642_bad_macro_stackover() { |
469 | check_types( | 438 | check_no_mismatches( |
470 | r#" | 439 | r#" |
471 | #[macro_export] | 440 | #[macro_export] |
472 | macro_rules! match_ast { | 441 | macro_rules! match_ast { |
@@ -483,7 +452,6 @@ macro_rules! match_ast { | |||
483 | 452 | ||
484 | fn main() { | 453 | fn main() { |
485 | let anchor = match_ast! { | 454 | let anchor = match_ast! { |
486 | //^ () | ||
487 | match parent { | 455 | match parent { |
488 | as => {}, | 456 | as => {}, |
489 | _ => return None | 457 | _ => return None |
@@ -736,12 +704,8 @@ fn issue_4931() { | |||
736 | fn issue_4885() { | 704 | fn issue_4885() { |
737 | check_infer( | 705 | check_infer( |
738 | r#" | 706 | r#" |
739 | #[lang = "coerce_unsized"] | 707 | //- minicore: coerce_unsized, future |
740 | pub trait CoerceUnsized<T> {} | 708 | use core::future::Future; |
741 | |||
742 | trait Future { | ||
743 | type Output; | ||
744 | } | ||
745 | trait Foo<R> { | 709 | trait Foo<R> { |
746 | type Bar; | 710 | type Bar; |
747 | } | 711 | } |
@@ -758,13 +722,13 @@ fn issue_4885() { | |||
758 | } | 722 | } |
759 | "#, | 723 | "#, |
760 | expect![[r#" | 724 | expect![[r#" |
761 | 136..139 'key': &K | 725 | 70..73 'key': &K |
762 | 198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> | 726 | 132..148 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> |
763 | 204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> | 727 | 138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> |
764 | 204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> | 728 | 138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> |
765 | 208..211 'key': &K | 729 | 142..145 'key': &K |
766 | 228..231 'key': &K | 730 | 162..165 'key': &K |
767 | 290..293 '{ }': () | 731 | 224..227 '{ }': () |
768 | "#]], | 732 | "#]], |
769 | ); | 733 | ); |
770 | } | 734 | } |
@@ -827,6 +791,7 @@ fn issue_4800() { | |||
827 | fn issue_4966() { | 791 | fn issue_4966() { |
828 | check_infer( | 792 | check_infer( |
829 | r#" | 793 | r#" |
794 | //- minicore: deref | ||
830 | pub trait IntoIterator { | 795 | pub trait IntoIterator { |
831 | type Item; | 796 | type Item; |
832 | } | 797 | } |
@@ -837,12 +802,7 @@ fn issue_4966() { | |||
837 | 802 | ||
838 | struct Vec<T> {} | 803 | struct Vec<T> {} |
839 | 804 | ||
840 | #[lang = "deref"] | 805 | impl<T> core::ops::Deref for Vec<T> { |
841 | pub trait Deref { | ||
842 | type Target; | ||
843 | } | ||
844 | |||
845 | impl<T> Deref for Vec<T> { | ||
846 | type Target = [T]; | 806 | type Target = [T]; |
847 | } | 807 | } |
848 | 808 | ||
@@ -859,23 +819,23 @@ fn issue_4966() { | |||
859 | } | 819 | } |
860 | "#, | 820 | "#, |
861 | expect![[r#" | 821 | expect![[r#" |
862 | 270..274 'iter': T | 822 | 225..229 'iter': T |
863 | 289..291 '{}': () | 823 | 244..246 '{}': () |
864 | 303..447 '{ ...r(); }': () | 824 | 258..402 '{ ...r(); }': () |
865 | 313..318 'inner': Map<|&f64| -> f64> | 825 | 268..273 'inner': Map<|&f64| -> f64> |
866 | 321..345 'Map { ... 0.0 }': Map<|&f64| -> f64> | 826 | 276..300 'Map { ... 0.0 }': Map<|&f64| -> f64> |
867 | 330..343 '|_: &f64| 0.0': |&f64| -> f64 | 827 | 285..298 '|_: &f64| 0.0': |&f64| -> f64 |
868 | 331..332 '_': &f64 | 828 | 286..287 '_': &f64 |
869 | 340..343 '0.0': f64 | 829 | 295..298 '0.0': f64 |
870 | 356..362 'repeat': Repeat<Map<|&f64| -> f64>> | 830 | 311..317 'repeat': Repeat<Map<|&f64| -> f64>> |
871 | 365..390 'Repeat...nner }': Repeat<Map<|&f64| -> f64>> | 831 | 320..345 'Repeat...nner }': Repeat<Map<|&f64| -> f64>> |
872 | 383..388 'inner': Map<|&f64| -> f64> | 832 | 338..343 'inner': Map<|&f64| -> f64> |
873 | 401..404 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | 833 | 356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> |
874 | 407..416 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | 834 | 362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> |
875 | 407..424 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | 835 | 362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> |
876 | 417..423 'repeat': Repeat<Map<|&f64| -> f64>> | 836 | 372..378 'repeat': Repeat<Map<|&f64| -> f64>> |
877 | 431..434 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> | 837 | 386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>> |
878 | 431..444 'vec.foo_bar()': {unknown} | 838 | 386..399 'vec.foo_bar()': {unknown} |
879 | "#]], | 839 | "#]], |
880 | ); | 840 | ); |
881 | } | 841 | } |
@@ -884,41 +844,37 @@ fn issue_4966() { | |||
884 | fn issue_6628() { | 844 | fn issue_6628() { |
885 | check_infer( | 845 | check_infer( |
886 | r#" | 846 | r#" |
887 | #[lang = "fn_once"] | 847 | //- minicore: fn |
888 | pub trait FnOnce<Args> { | 848 | struct S<T>(); |
889 | type Output; | 849 | impl<T> S<T> { |
890 | } | 850 | fn f(&self, _t: T) {} |
891 | 851 | fn g<F: FnOnce(&T)>(&self, _f: F) {} | |
892 | struct S<T>(); | 852 | } |
893 | impl<T> S<T> { | 853 | fn main() { |
894 | fn f(&self, _t: T) {} | 854 | let s = S(); |
895 | fn g<F: FnOnce(&T)>(&self, _f: F) {} | 855 | s.g(|_x| {}); |
896 | } | 856 | s.f(10); |
897 | fn main() { | 857 | } |
898 | let s = S(); | 858 | "#, |
899 | s.g(|_x| {}); | ||
900 | s.f(10); | ||
901 | } | ||
902 | "#, | ||
903 | expect![[r#" | 859 | expect![[r#" |
904 | 105..109 'self': &S<T> | 860 | 40..44 'self': &S<T> |
905 | 111..113 '_t': T | 861 | 46..48 '_t': T |
906 | 118..120 '{}': () | 862 | 53..55 '{}': () |
907 | 146..150 'self': &S<T> | 863 | 81..85 'self': &S<T> |
908 | 152..154 '_f': F | 864 | 87..89 '_f': F |
909 | 159..161 '{}': () | 865 | 94..96 '{}': () |
910 | 174..225 '{ ...10); }': () | 866 | 109..160 '{ ...10); }': () |
911 | 184..185 's': S<i32> | 867 | 119..120 's': S<i32> |
912 | 188..189 'S': S<i32>() -> S<i32> | 868 | 123..124 'S': S<i32>() -> S<i32> |
913 | 188..191 'S()': S<i32> | 869 | 123..126 'S()': S<i32> |
914 | 197..198 's': S<i32> | 870 | 132..133 's': S<i32> |
915 | 197..209 's.g(|_x| {})': () | 871 | 132..144 's.g(|_x| {})': () |
916 | 201..208 '|_x| {}': |&i32| -> () | 872 | 136..143 '|_x| {}': |&i32| -> () |
917 | 202..204 '_x': &i32 | 873 | 137..139 '_x': &i32 |
918 | 206..208 '{}': () | 874 | 141..143 '{}': () |
919 | 215..216 's': S<i32> | 875 | 150..151 's': S<i32> |
920 | 215..222 's.f(10)': () | 876 | 150..157 's.f(10)': () |
921 | 219..221 '10': i32 | 877 | 154..156 '10': i32 |
922 | "#]], | 878 | "#]], |
923 | ); | 879 | ); |
924 | } | 880 | } |
@@ -927,35 +883,33 @@ fn issue_6628() { | |||
927 | fn issue_6852() { | 883 | fn issue_6852() { |
928 | check_infer( | 884 | check_infer( |
929 | r#" | 885 | r#" |
930 | #[lang = "deref"] | 886 | //- minicore: deref |
931 | pub trait Deref { | 887 | use core::ops::Deref; |
932 | type Target; | ||
933 | } | ||
934 | 888 | ||
935 | struct BufWriter {} | 889 | struct BufWriter {} |
936 | 890 | ||
937 | struct Mutex<T> {} | 891 | struct Mutex<T> {} |
938 | struct MutexGuard<'a, T> {} | 892 | struct MutexGuard<'a, T> {} |
939 | impl<T> Mutex<T> { | 893 | impl<T> Mutex<T> { |
940 | fn lock(&self) -> MutexGuard<'_, T> {} | 894 | fn lock(&self) -> MutexGuard<'_, T> {} |
941 | } | 895 | } |
942 | impl<'a, T: 'a> Deref for MutexGuard<'a, T> { | 896 | impl<'a, T: 'a> Deref for MutexGuard<'a, T> { |
943 | type Target = T; | 897 | type Target = T; |
944 | } | 898 | } |
945 | fn flush(&self) { | 899 | fn flush(&self) { |
946 | let w: &Mutex<BufWriter>; | 900 | let w: &Mutex<BufWriter>; |
947 | *(w.lock()); | 901 | *(w.lock()); |
948 | } | 902 | } |
949 | "#, | 903 | "#, |
950 | expect![[r#" | 904 | expect![[r#" |
951 | 156..160 'self': &Mutex<T> | 905 | 123..127 'self': &Mutex<T> |
952 | 183..185 '{}': () | 906 | 150..152 '{}': () |
953 | 267..271 'self': &{unknown} | 907 | 234..238 'self': &{unknown} |
954 | 273..323 '{ ...()); }': () | 908 | 240..290 '{ ...()); }': () |
955 | 283..284 'w': &Mutex<BufWriter> | 909 | 250..251 'w': &Mutex<BufWriter> |
956 | 309..320 '*(w.lock())': BufWriter | 910 | 276..287 '*(w.lock())': BufWriter |
957 | 311..312 'w': &Mutex<BufWriter> | 911 | 278..279 'w': &Mutex<BufWriter> |
958 | 311..319 'w.lock()': MutexGuard<BufWriter> | 912 | 278..286 'w.lock()': MutexGuard<BufWriter> |
959 | "#]], | 913 | "#]], |
960 | ); | 914 | ); |
961 | } | 915 | } |
@@ -977,37 +931,33 @@ fn param_overrides_fn() { | |||
977 | fn lifetime_from_chalk_during_deref() { | 931 | fn lifetime_from_chalk_during_deref() { |
978 | check_types( | 932 | check_types( |
979 | r#" | 933 | r#" |
980 | #[lang = "deref"] | 934 | //- minicore: deref |
981 | pub trait Deref { | 935 | struct Box<T: ?Sized> {} |
982 | type Target; | 936 | impl<T> core::ops::Deref for Box<T> { |
983 | } | 937 | type Target = T; |
984 | |||
985 | struct Box<T: ?Sized> {} | ||
986 | impl<T> Deref for Box<T> { | ||
987 | type Target = T; | ||
988 | 938 | ||
989 | fn deref(&self) -> &Self::Target { | 939 | fn deref(&self) -> &Self::Target { |
990 | loop {} | 940 | loop {} |
991 | } | 941 | } |
992 | } | 942 | } |
993 | 943 | ||
994 | trait Iterator { | 944 | trait Iterator { |
995 | type Item; | 945 | type Item; |
996 | } | 946 | } |
997 | 947 | ||
998 | pub struct Iter<'a, T: 'a> { | 948 | pub struct Iter<'a, T: 'a> { |
999 | inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, | 949 | inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, |
1000 | } | 950 | } |
1001 | 951 | ||
1002 | trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { | 952 | trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> { |
1003 | fn clone_box(&self); | 953 | fn clone_box(&self); |
1004 | } | 954 | } |
1005 | 955 | ||
1006 | fn clone_iter<T>(s: Iter<T>) { | 956 | fn clone_iter<T>(s: Iter<T>) { |
1007 | s.inner.clone_box(); | 957 | s.inner.clone_box(); |
1008 | //^^^^^^^^^^^^^^^^^^^ () | 958 | //^^^^^^^^^^^^^^^^^^^ () |
1009 | } | 959 | } |
1010 | "#, | 960 | "#, |
1011 | ) | 961 | ) |
1012 | } | 962 | } |
1013 | 963 | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 3418ed21e..b4bcc6d95 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -60,7 +60,7 @@ enum Nat { Succ(Self), Demo(Nat), Zero } | |||
60 | fn test() { | 60 | fn test() { |
61 | let foo: Nat = Nat::Zero; | 61 | let foo: Nat = Nat::Zero; |
62 | if let Nat::Succ(x) = foo { | 62 | if let Nat::Succ(x) = foo { |
63 | x | 63 | x; |
64 | } //^ Nat | 64 | } //^ Nat |
65 | } | 65 | } |
66 | "#, | 66 | "#, |
@@ -113,7 +113,7 @@ fn type_alias_in_struct_lit() { | |||
113 | fn infer_ranges() { | 113 | fn infer_ranges() { |
114 | check_types( | 114 | check_types( |
115 | r#" | 115 | r#" |
116 | //- /main.rs crate:main deps:core | 116 | //- minicore: range |
117 | fn test() { | 117 | fn test() { |
118 | let a = ..; | 118 | let a = ..; |
119 | let b = 1..; | 119 | let b = 1..; |
@@ -125,32 +125,6 @@ fn test() { | |||
125 | let t = (a, b, c, d, e, f); | 125 | let t = (a, b, c, d, e, f); |
126 | t; | 126 | t; |
127 | } //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) | 127 | } //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>) |
128 | |||
129 | //- /core.rs crate:core | ||
130 | #[prelude_import] use prelude::*; | ||
131 | mod prelude {} | ||
132 | |||
133 | pub mod ops { | ||
134 | pub struct Range<Idx> { | ||
135 | pub start: Idx, | ||
136 | pub end: Idx, | ||
137 | } | ||
138 | pub struct RangeFrom<Idx> { | ||
139 | pub start: Idx, | ||
140 | } | ||
141 | struct RangeFull; | ||
142 | pub struct RangeInclusive<Idx> { | ||
143 | start: Idx, | ||
144 | end: Idx, | ||
145 | is_empty: u8, | ||
146 | } | ||
147 | pub struct RangeTo<Idx> { | ||
148 | pub end: Idx, | ||
149 | } | ||
150 | pub struct RangeToInclusive<Idx> { | ||
151 | pub end: Idx, | ||
152 | } | ||
153 | } | ||
154 | "#, | 128 | "#, |
155 | ); | 129 | ); |
156 | } | 130 | } |
@@ -164,7 +138,7 @@ enum Option<T> { Some(T), None } | |||
164 | fn test() { | 138 | fn test() { |
165 | let foo: Option<f32> = None; | 139 | let foo: Option<f32> = None; |
166 | while let Option::Some(x) = foo { | 140 | while let Option::Some(x) = foo { |
167 | x | 141 | x; |
168 | } //^ f32 | 142 | } //^ f32 |
169 | } | 143 | } |
170 | "#, | 144 | "#, |
@@ -175,16 +149,17 @@ fn test() { | |||
175 | fn infer_basics() { | 149 | fn infer_basics() { |
176 | check_infer( | 150 | check_infer( |
177 | r#" | 151 | r#" |
178 | fn test(a: u32, b: isize, c: !, d: &str) { | 152 | fn test(a: u32, b: isize, c: !, d: &str) { |
179 | a; | 153 | a; |
180 | b; | 154 | b; |
181 | c; | 155 | c; |
182 | d; | 156 | d; |
183 | 1usize; | 157 | 1usize; |
184 | 1isize; | 158 | 1isize; |
185 | "test"; | 159 | "test"; |
186 | 1.0f32; | 160 | 1.0f32; |
187 | }"#, | 161 | } |
162 | "#, | ||
188 | expect![[r#" | 163 | expect![[r#" |
189 | 8..9 'a': u32 | 164 | 8..9 'a': u32 |
190 | 16..17 'b': isize | 165 | 16..17 'b': isize |
@@ -207,15 +182,15 @@ fn infer_basics() { | |||
207 | fn infer_let() { | 182 | fn infer_let() { |
208 | check_infer( | 183 | check_infer( |
209 | r#" | 184 | r#" |
210 | fn test() { | 185 | fn test() { |
211 | let a = 1isize; | 186 | let a = 1isize; |
212 | let b: usize = 1; | 187 | let b: usize = 1; |
213 | let c = b; | 188 | let c = b; |
214 | let d: u32; | 189 | let d: u32; |
215 | let e; | 190 | let e; |
216 | let f: i32 = e; | 191 | let f: i32 = e; |
217 | } | 192 | } |
218 | "#, | 193 | "#, |
219 | expect![[r#" | 194 | expect![[r#" |
220 | 10..117 '{ ...= e; }': () | 195 | 10..117 '{ ...= e; }': () |
221 | 20..21 'a': isize | 196 | 20..21 'a': isize |
@@ -236,17 +211,17 @@ fn infer_let() { | |||
236 | fn infer_paths() { | 211 | fn infer_paths() { |
237 | check_infer( | 212 | check_infer( |
238 | r#" | 213 | r#" |
239 | fn a() -> u32 { 1 } | 214 | fn a() -> u32 { 1 } |
240 | 215 | ||
241 | mod b { | 216 | mod b { |
242 | fn c() -> u32 { 1 } | 217 | fn c() -> u32 { 1 } |
243 | } | 218 | } |
244 | 219 | ||
245 | fn test() { | 220 | fn test() { |
246 | a(); | 221 | a(); |
247 | b::c(); | 222 | b::c(); |
248 | } | 223 | } |
249 | "#, | 224 | "#, |
250 | expect![[r#" | 225 | expect![[r#" |
251 | 14..19 '{ 1 }': u32 | 226 | 14..19 '{ 1 }': u32 |
252 | 16..17 '1': u32 | 227 | 16..17 '1': u32 |
@@ -265,17 +240,17 @@ fn infer_paths() { | |||
265 | fn infer_path_type() { | 240 | fn infer_path_type() { |
266 | check_infer( | 241 | check_infer( |
267 | r#" | 242 | r#" |
268 | struct S; | 243 | struct S; |
269 | 244 | ||
270 | impl S { | 245 | impl S { |
271 | fn foo() -> i32 { 1 } | 246 | fn foo() -> i32 { 1 } |
272 | } | 247 | } |
273 | 248 | ||
274 | fn test() { | 249 | fn test() { |
275 | S::foo(); | 250 | S::foo(); |
276 | <S>::foo(); | 251 | <S>::foo(); |
277 | } | 252 | } |
278 | "#, | 253 | "#, |
279 | expect![[r#" | 254 | expect![[r#" |
280 | 40..45 '{ 1 }': i32 | 255 | 40..45 '{ 1 }': i32 |
281 | 42..43 '1': i32 | 256 | 42..43 '1': i32 |
@@ -292,21 +267,21 @@ fn infer_path_type() { | |||
292 | fn infer_struct() { | 267 | fn infer_struct() { |
293 | check_infer( | 268 | check_infer( |
294 | r#" | 269 | r#" |
295 | struct A { | 270 | struct A { |
296 | b: B, | 271 | b: B, |
297 | c: C, | 272 | c: C, |
298 | } | 273 | } |
299 | struct B; | 274 | struct B; |
300 | struct C(usize); | 275 | struct C(usize); |
301 | 276 | ||
302 | fn test() { | 277 | fn test() { |
303 | let c = C(1); | 278 | let c = C(1); |
304 | B; | 279 | B; |
305 | let a: A = A { b: B, c: C(1) }; | 280 | let a: A = A { b: B, c: C(1) }; |
306 | a.b; | 281 | a.b; |
307 | a.c; | 282 | a.c; |
308 | } | 283 | } |
309 | "#, | 284 | "#, |
310 | expect![[r#" | 285 | expect![[r#" |
311 | 71..153 '{ ...a.c; }': () | 286 | 71..153 '{ ...a.c; }': () |
312 | 81..82 'c': C | 287 | 81..82 'c': C |
@@ -332,14 +307,15 @@ fn infer_struct() { | |||
332 | fn infer_enum() { | 307 | fn infer_enum() { |
333 | check_infer( | 308 | check_infer( |
334 | r#" | 309 | r#" |
335 | enum E { | 310 | enum E { |
336 | V1 { field: u32 }, | 311 | V1 { field: u32 }, |
337 | V2 | 312 | V2 |
338 | } | 313 | } |
339 | fn test() { | 314 | fn test() { |
340 | E::V1 { field: 1 }; | 315 | E::V1 { field: 1 }; |
341 | E::V2; | 316 | E::V2; |
342 | }"#, | 317 | } |
318 | "#, | ||
343 | expect![[r#" | 319 | expect![[r#" |
344 | 51..89 '{ ...:V2; }': () | 320 | 51..89 '{ ...:V2; }': () |
345 | 57..75 'E::V1 ...d: 1 }': E | 321 | 57..75 'E::V1 ...d: 1 }': E |
@@ -353,23 +329,23 @@ fn infer_enum() { | |||
353 | fn infer_union() { | 329 | fn infer_union() { |
354 | check_infer( | 330 | check_infer( |
355 | r#" | 331 | r#" |
356 | union MyUnion { | 332 | union MyUnion { |
357 | foo: u32, | 333 | foo: u32, |
358 | bar: f32, | 334 | bar: f32, |
359 | } | 335 | } |
360 | 336 | ||
361 | fn test() { | 337 | fn test() { |
362 | let u = MyUnion { foo: 0 }; | 338 | let u = MyUnion { foo: 0 }; |
363 | unsafe { baz(u); } | 339 | unsafe { baz(u); } |
364 | let u = MyUnion { bar: 0.0 }; | 340 | let u = MyUnion { bar: 0.0 }; |
365 | unsafe { baz(u); } | 341 | unsafe { baz(u); } |
366 | } | 342 | } |
367 | 343 | ||
368 | unsafe fn baz(u: MyUnion) { | 344 | unsafe fn baz(u: MyUnion) { |
369 | let inner = u.foo; | 345 | let inner = u.foo; |
370 | let inner = u.bar; | 346 | let inner = u.bar; |
371 | } | 347 | } |
372 | "#, | 348 | "#, |
373 | expect![[r#" | 349 | expect![[r#" |
374 | 57..172 '{ ...); } }': () | 350 | 57..172 '{ ...); } }': () |
375 | 67..68 'u': MyUnion | 351 | 67..68 'u': MyUnion |
@@ -404,19 +380,19 @@ fn infer_union() { | |||
404 | fn infer_refs() { | 380 | fn infer_refs() { |
405 | check_infer( | 381 | check_infer( |
406 | r#" | 382 | r#" |
407 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | 383 | fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { |
408 | a; | 384 | a; |
409 | *a; | 385 | *a; |
410 | &a; | 386 | &a; |
411 | &mut a; | 387 | &mut a; |
412 | b; | 388 | b; |
413 | *b; | 389 | *b; |
414 | &b; | 390 | &b; |
415 | c; | 391 | c; |
416 | *c; | 392 | *c; |
417 | d; | 393 | d; |
418 | *d; | 394 | *d; |
419 | } | 395 | } |
420 | "#, | 396 | "#, |
421 | expect![[r#" | 397 | expect![[r#" |
422 | 8..9 'a': &u32 | 398 | 8..9 'a': &u32 |
@@ -450,11 +426,11 @@ fn infer_refs() { | |||
450 | fn infer_raw_ref() { | 426 | fn infer_raw_ref() { |
451 | check_infer( | 427 | check_infer( |
452 | r#" | 428 | r#" |
453 | fn test(a: i32) { | 429 | fn test(a: i32) { |
454 | &raw mut a; | 430 | &raw mut a; |
455 | &raw const a; | 431 | &raw const a; |
456 | } | 432 | } |
457 | "#, | 433 | "#, |
458 | expect![[r#" | 434 | expect![[r#" |
459 | 8..9 'a': i32 | 435 | 8..9 'a': i32 |
460 | 16..53 '{ ...t a; }': () | 436 | 16..53 '{ ...t a; }': () |
@@ -524,26 +500,26 @@ h"; | |||
524 | fn infer_unary_op() { | 500 | fn infer_unary_op() { |
525 | check_infer( | 501 | check_infer( |
526 | r#" | 502 | r#" |
527 | enum SomeType {} | 503 | enum SomeType {} |
528 | 504 | ||
529 | fn test(x: SomeType) { | 505 | fn test(x: SomeType) { |
530 | let b = false; | 506 | let b = false; |
531 | let c = !b; | 507 | let c = !b; |
532 | let a = 100; | 508 | let a = 100; |
533 | let d: i128 = -a; | 509 | let d: i128 = -a; |
534 | let e = -100; | 510 | let e = -100; |
535 | let f = !!!true; | 511 | let f = !!!true; |
536 | let g = !42; | 512 | let g = !42; |
537 | let h = !10u32; | 513 | let h = !10u32; |
538 | let j = !a; | 514 | let j = !a; |
539 | -3.14; | 515 | -3.14; |
540 | !3; | 516 | !3; |
541 | -x; | 517 | -x; |
542 | !x; | 518 | !x; |
543 | -"hello"; | 519 | -"hello"; |
544 | !"hello"; | 520 | !"hello"; |
545 | } | 521 | } |
546 | "#, | 522 | "#, |
547 | expect![[r#" | 523 | expect![[r#" |
548 | 26..27 'x': SomeType | 524 | 26..27 'x': SomeType |
549 | 39..271 '{ ...lo"; }': () | 525 | 39..271 '{ ...lo"; }': () |
@@ -594,19 +570,19 @@ fn infer_unary_op() { | |||
594 | fn infer_backwards() { | 570 | fn infer_backwards() { |
595 | check_infer( | 571 | check_infer( |
596 | r#" | 572 | r#" |
597 | fn takes_u32(x: u32) {} | 573 | fn takes_u32(x: u32) {} |
598 | 574 | ||
599 | struct S { i32_field: i32 } | 575 | struct S { i32_field: i32 } |
600 | 576 | ||
601 | fn test() -> &mut &f64 { | 577 | fn test() -> &mut &f64 { |
602 | let a = unknown_function(); | 578 | let a = unknown_function(); |
603 | takes_u32(a); | 579 | takes_u32(a); |
604 | let b = unknown_function(); | 580 | let b = unknown_function(); |
605 | S { i32_field: b }; | 581 | S { i32_field: b }; |
606 | let c = unknown_function(); | 582 | let c = unknown_function(); |
607 | &mut &c | 583 | &mut &c |
608 | } | 584 | } |
609 | "#, | 585 | "#, |
610 | expect![[r#" | 586 | expect![[r#" |
611 | 13..14 'x': u32 | 587 | 13..14 'x': u32 |
612 | 21..23 '{}': () | 588 | 21..23 '{}': () |
@@ -636,23 +612,23 @@ fn infer_backwards() { | |||
636 | fn infer_self() { | 612 | fn infer_self() { |
637 | check_infer( | 613 | check_infer( |
638 | r#" | 614 | r#" |
639 | struct S; | 615 | struct S; |
640 | 616 | ||
641 | impl S { | 617 | impl S { |
642 | fn test(&self) { | 618 | fn test(&self) { |
643 | self; | 619 | self; |
644 | } | 620 | } |
645 | fn test2(self: &Self) { | 621 | fn test2(self: &Self) { |
646 | self; | 622 | self; |
647 | } | 623 | } |
648 | fn test3() -> Self { | 624 | fn test3() -> Self { |
649 | S {} | 625 | S {} |
650 | } | 626 | } |
651 | fn test4() -> Self { | 627 | fn test4() -> Self { |
652 | Self {} | 628 | Self {} |
653 | } | 629 | } |
654 | } | 630 | } |
655 | "#, | 631 | "#, |
656 | expect![[r#" | 632 | expect![[r#" |
657 | 33..37 'self': &S | 633 | 33..37 'self': &S |
658 | 39..60 '{ ... }': () | 634 | 39..60 '{ ... }': () |
@@ -672,30 +648,30 @@ fn infer_self() { | |||
672 | fn infer_self_as_path() { | 648 | fn infer_self_as_path() { |
673 | check_infer( | 649 | check_infer( |
674 | r#" | 650 | r#" |
675 | struct S1; | 651 | struct S1; |
676 | struct S2(isize); | 652 | struct S2(isize); |
677 | enum E { | 653 | enum E { |
678 | V1, | 654 | V1, |
679 | V2(u32), | 655 | V2(u32), |
680 | } | 656 | } |
681 | 657 | ||
682 | impl S1 { | 658 | impl S1 { |
683 | fn test() { | 659 | fn test() { |
684 | Self; | 660 | Self; |
685 | } | 661 | } |
686 | } | 662 | } |
687 | impl S2 { | 663 | impl S2 { |
688 | fn test() { | 664 | fn test() { |
689 | Self(1); | 665 | Self(1); |
690 | } | 666 | } |
691 | } | 667 | } |
692 | impl E { | 668 | impl E { |
693 | fn test() { | 669 | fn test() { |
694 | Self::V1; | 670 | Self::V1; |
695 | Self::V2(1); | 671 | Self::V2(1); |
696 | } | 672 | } |
697 | } | 673 | } |
698 | "#, | 674 | "#, |
699 | expect![[r#" | 675 | expect![[r#" |
700 | 86..107 '{ ... }': () | 676 | 86..107 '{ ... }': () |
701 | 96..100 'Self': S1 | 677 | 96..100 'Self': S1 |
@@ -716,26 +692,26 @@ fn infer_self_as_path() { | |||
716 | fn infer_binary_op() { | 692 | fn infer_binary_op() { |
717 | check_infer( | 693 | check_infer( |
718 | r#" | 694 | r#" |
719 | fn f(x: bool) -> i32 { | 695 | fn f(x: bool) -> i32 { |
720 | 0i32 | 696 | 0i32 |
721 | } | 697 | } |
722 | 698 | ||
723 | fn test() -> bool { | 699 | fn test() -> bool { |
724 | let x = a && b; | 700 | let x = a && b; |
725 | let y = true || false; | 701 | let y = true || false; |
726 | let z = x == y; | 702 | let z = x == y; |
727 | let t = x != y; | 703 | let t = x != y; |
728 | let minus_forty: isize = -40isize; | 704 | let minus_forty: isize = -40isize; |
729 | let h = minus_forty <= CONST_2; | 705 | let h = minus_forty <= CONST_2; |
730 | let c = f(z || y) + 5; | 706 | let c = f(z || y) + 5; |
731 | let d = b; | 707 | let d = b; |
732 | let g = minus_forty ^= i; | 708 | let g = minus_forty ^= i; |
733 | let ten: usize = 10; | 709 | let ten: usize = 10; |
734 | let ten_is_eleven = ten == some_num; | 710 | let ten_is_eleven = ten == some_num; |
735 | 711 | ||
736 | ten < 3 | 712 | ten < 3 |
737 | } | 713 | } |
738 | "#, | 714 | "#, |
739 | expect![[r#" | 715 | expect![[r#" |
740 | 5..6 'x': bool | 716 | 5..6 'x': bool |
741 | 21..33 '{ 0i32 }': i32 | 717 | 21..33 '{ 0i32 }': i32 |
@@ -795,11 +771,11 @@ fn infer_binary_op() { | |||
795 | fn infer_shift_op() { | 771 | fn infer_shift_op() { |
796 | check_infer( | 772 | check_infer( |
797 | r#" | 773 | r#" |
798 | fn test() { | 774 | fn test() { |
799 | 1u32 << 5u8; | 775 | 1u32 << 5u8; |
800 | 1u32 >> 5u8; | 776 | 1u32 >> 5u8; |
801 | } | 777 | } |
802 | "#, | 778 | "#, |
803 | expect![[r#" | 779 | expect![[r#" |
804 | 10..47 '{ ...5u8; }': () | 780 | 10..47 '{ ...5u8; }': () |
805 | 16..20 '1u32': u32 | 781 | 16..20 '1u32': u32 |
@@ -816,29 +792,29 @@ fn infer_shift_op() { | |||
816 | fn infer_field_autoderef() { | 792 | fn infer_field_autoderef() { |
817 | check_infer( | 793 | check_infer( |
818 | r#" | 794 | r#" |
819 | struct A { | 795 | struct A { |
820 | b: B, | 796 | b: B, |
821 | } | 797 | } |
822 | struct B; | 798 | struct B; |
823 | |||
824 | fn test1(a: A) { | ||
825 | let a1 = a; | ||
826 | a1.b; | ||
827 | let a2 = &a; | ||
828 | a2.b; | ||
829 | let a3 = &mut a; | ||
830 | a3.b; | ||
831 | let a4 = &&&&&&&a; | ||
832 | a4.b; | ||
833 | let a5 = &mut &&mut &&mut a; | ||
834 | a5.b; | ||
835 | } | ||
836 | 799 | ||
837 | fn test2(a1: *const A, a2: *mut A) { | 800 | fn test1(a: A) { |
838 | a1.b; | 801 | let a1 = a; |
839 | a2.b; | 802 | a1.b; |
840 | } | 803 | let a2 = &a; |
841 | "#, | 804 | a2.b; |
805 | let a3 = &mut a; | ||
806 | a3.b; | ||
807 | let a4 = &&&&&&&a; | ||
808 | a4.b; | ||
809 | let a5 = &mut &&mut &&mut a; | ||
810 | a5.b; | ||
811 | } | ||
812 | |||
813 | fn test2(a1: *const A, a2: *mut A) { | ||
814 | a1.b; | ||
815 | a2.b; | ||
816 | } | ||
817 | "#, | ||
842 | expect![[r#" | 818 | expect![[r#" |
843 | 43..44 'a': A | 819 | 43..44 'a': A |
844 | 49..212 '{ ...5.b; }': () | 820 | 49..212 '{ ...5.b; }': () |
@@ -891,58 +867,53 @@ fn infer_field_autoderef() { | |||
891 | fn infer_argument_autoderef() { | 867 | fn infer_argument_autoderef() { |
892 | check_infer( | 868 | check_infer( |
893 | r#" | 869 | r#" |
894 | #[lang = "deref"] | 870 | //- minicore: deref |
895 | pub trait Deref { | 871 | use core::ops::Deref; |
896 | type Target; | 872 | struct A<T>(T); |
897 | fn deref(&self) -> &Self::Target; | ||
898 | } | ||
899 | 873 | ||
900 | struct A<T>(T); | 874 | impl<T> A<T> { |
901 | 875 | fn foo(&self) -> &T { | |
902 | impl<T> A<T> { | 876 | &self.0 |
903 | fn foo(&self) -> &T { | 877 | } |
904 | &self.0 | 878 | } |
905 | } | ||
906 | } | ||
907 | 879 | ||
908 | struct B<T>(T); | 880 | struct B<T>(T); |
909 | 881 | ||
910 | impl<T> Deref for B<T> { | 882 | impl<T> Deref for B<T> { |
911 | type Target = T; | 883 | type Target = T; |
912 | fn deref(&self) -> &Self::Target { | 884 | fn deref(&self) -> &Self::Target { |
913 | &self.0 | 885 | &self.0 |
914 | } | 886 | } |
915 | } | 887 | } |
916 | 888 | ||
917 | fn test() { | 889 | fn test() { |
918 | let t = A::foo(&&B(B(A(42)))); | 890 | let t = A::foo(&&B(B(A(42)))); |
919 | } | 891 | } |
920 | "#, | 892 | "#, |
921 | expect![[r#" | 893 | expect![[r#" |
922 | 67..71 'self': &Self | 894 | 66..70 'self': &A<T> |
923 | 138..142 'self': &A<T> | 895 | 78..101 '{ ... }': &T |
924 | 150..173 '{ ... }': &T | 896 | 88..95 '&self.0': &T |
925 | 160..167 '&self.0': &T | 897 | 89..93 'self': &A<T> |
926 | 161..165 'self': &A<T> | 898 | 89..95 'self.0': T |
927 | 161..167 'self.0': T | 899 | 182..186 'self': &B<T> |
928 | 254..258 'self': &B<T> | 900 | 205..228 '{ ... }': &T |
929 | 277..300 '{ ... }': &T | 901 | 215..222 '&self.0': &T |
930 | 287..294 '&self.0': &T | 902 | 216..220 'self': &B<T> |
931 | 288..292 'self': &B<T> | 903 | 216..222 'self.0': T |
932 | 288..294 'self.0': T | 904 | 242..280 '{ ...))); }': () |
933 | 314..352 '{ ...))); }': () | 905 | 252..253 't': &i32 |
934 | 324..325 't': &i32 | 906 | 256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32 |
935 | 328..334 'A::foo': fn foo<i32>(&A<i32>) -> &i32 | 907 | 256..277 'A::foo...42))))': &i32 |
936 | 328..349 'A::foo...42))))': &i32 | 908 | 263..276 '&&B(B(A(42)))': &&B<B<A<i32>>> |
937 | 335..348 '&&B(B(A(42)))': &&B<B<A<i32>>> | 909 | 264..276 '&B(B(A(42)))': &B<B<A<i32>>> |
938 | 336..348 '&B(B(A(42)))': &B<B<A<i32>>> | 910 | 265..266 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> |
939 | 337..338 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | 911 | 265..276 'B(B(A(42)))': B<B<A<i32>>> |
940 | 337..348 'B(B(A(42)))': B<B<A<i32>>> | 912 | 267..268 'B': B<A<i32>>(A<i32>) -> B<A<i32>> |
941 | 339..340 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | 913 | 267..275 'B(A(42))': B<A<i32>> |
942 | 339..347 'B(A(42))': B<A<i32>> | 914 | 269..270 'A': A<i32>(i32) -> A<i32> |
943 | 341..342 'A': A<i32>(i32) -> A<i32> | 915 | 269..274 'A(42)': A<i32> |
944 | 341..346 'A(42)': A<i32> | 916 | 271..273 '42': i32 |
945 | 343..345 '42': i32 | ||
946 | "#]], | 917 | "#]], |
947 | ); | 918 | ); |
948 | } | 919 | } |
@@ -951,62 +922,57 @@ fn infer_argument_autoderef() { | |||
951 | fn infer_method_argument_autoderef() { | 922 | fn infer_method_argument_autoderef() { |
952 | check_infer( | 923 | check_infer( |
953 | r#" | 924 | r#" |
954 | #[lang = "deref"] | 925 | //- minicore: deref |
955 | pub trait Deref { | 926 | use core::ops::Deref; |
956 | type Target; | 927 | struct A<T>(*mut T); |
957 | fn deref(&self) -> &Self::Target; | ||
958 | } | ||
959 | 928 | ||
960 | struct A<T>(*mut T); | 929 | impl<T> A<T> { |
961 | 930 | fn foo(&self, x: &A<T>) -> &T { | |
962 | impl<T> A<T> { | 931 | &*x.0 |
963 | fn foo(&self, x: &A<T>) -> &T { | 932 | } |
964 | &*x.0 | 933 | } |
965 | } | ||
966 | } | ||
967 | 934 | ||
968 | struct B<T>(T); | 935 | struct B<T>(T); |
969 | 936 | ||
970 | impl<T> Deref for B<T> { | 937 | impl<T> Deref for B<T> { |
971 | type Target = T; | 938 | type Target = T; |
972 | fn deref(&self) -> &Self::Target { | 939 | fn deref(&self) -> &Self::Target { |
973 | &self.0 | 940 | &self.0 |
974 | } | 941 | } |
975 | } | 942 | } |
976 | 943 | ||
977 | fn test(a: A<i32>) { | 944 | fn test(a: A<i32>) { |
978 | let t = A(0 as *mut _).foo(&&B(B(a))); | 945 | let t = A(0 as *mut _).foo(&&B(B(a))); |
979 | } | 946 | } |
980 | "#, | 947 | "#, |
981 | expect![[r#" | 948 | expect![[r#" |
982 | 67..71 'self': &Self | 949 | 71..75 'self': &A<T> |
983 | 143..147 'self': &A<T> | 950 | 77..78 'x': &A<T> |
984 | 149..150 'x': &A<T> | 951 | 93..114 '{ ... }': &T |
985 | 165..186 '{ ... }': &T | 952 | 103..108 '&*x.0': &T |
986 | 175..180 '&*x.0': &T | 953 | 104..108 '*x.0': T |
987 | 176..180 '*x.0': T | 954 | 105..106 'x': &A<T> |
988 | 177..178 'x': &A<T> | 955 | 105..108 'x.0': *mut T |
989 | 177..180 'x.0': *mut T | 956 | 195..199 'self': &B<T> |
990 | 267..271 'self': &B<T> | 957 | 218..241 '{ ... }': &T |
991 | 290..313 '{ ... }': &T | 958 | 228..235 '&self.0': &T |
992 | 300..307 '&self.0': &T | 959 | 229..233 'self': &B<T> |
993 | 301..305 'self': &B<T> | 960 | 229..235 'self.0': T |
994 | 301..307 'self.0': T | 961 | 253..254 'a': A<i32> |
995 | 325..326 'a': A<i32> | 962 | 264..310 '{ ...))); }': () |
996 | 336..382 '{ ...))); }': () | 963 | 274..275 't': &i32 |
997 | 346..347 't': &i32 | 964 | 278..279 'A': A<i32>(*mut i32) -> A<i32> |
998 | 350..351 'A': A<i32>(*mut i32) -> A<i32> | 965 | 278..292 'A(0 as *mut _)': A<i32> |
999 | 350..364 'A(0 as *mut _)': A<i32> | 966 | 278..307 'A(0 as...B(a)))': &i32 |
1000 | 350..379 'A(0 as...B(a)))': &i32 | 967 | 280..281 '0': i32 |
1001 | 352..353 '0': i32 | 968 | 280..291 '0 as *mut _': *mut i32 |
1002 | 352..363 '0 as *mut _': *mut i32 | 969 | 297..306 '&&B(B(a))': &&B<B<A<i32>>> |
1003 | 369..378 '&&B(B(a))': &&B<B<A<i32>>> | 970 | 298..306 '&B(B(a))': &B<B<A<i32>>> |
1004 | 370..378 '&B(B(a))': &B<B<A<i32>>> | 971 | 299..300 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> |
1005 | 371..372 'B': B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>> | 972 | 299..306 'B(B(a))': B<B<A<i32>>> |
1006 | 371..378 'B(B(a))': B<B<A<i32>>> | 973 | 301..302 'B': B<A<i32>>(A<i32>) -> B<A<i32>> |
1007 | 373..374 'B': B<A<i32>>(A<i32>) -> B<A<i32>> | 974 | 301..305 'B(a)': B<A<i32>> |
1008 | 373..377 'B(a)': B<A<i32>> | 975 | 303..304 'a': A<i32> |
1009 | 375..376 'a': A<i32> | ||
1010 | "#]], | 976 | "#]], |
1011 | ); | 977 | ); |
1012 | } | 978 | } |
@@ -1015,15 +981,15 @@ fn infer_method_argument_autoderef() { | |||
1015 | fn infer_in_elseif() { | 981 | fn infer_in_elseif() { |
1016 | check_infer( | 982 | check_infer( |
1017 | r#" | 983 | r#" |
1018 | struct Foo { field: i32 } | 984 | struct Foo { field: i32 } |
1019 | fn main(foo: Foo) { | 985 | fn main(foo: Foo) { |
1020 | if true { | 986 | if true { |
1021 | 987 | ||
1022 | } else if false { | 988 | } else if false { |
1023 | foo.field | 989 | foo.field |
1024 | } | 990 | } |
1025 | } | 991 | } |
1026 | "#, | 992 | "#, |
1027 | expect![[r#" | 993 | expect![[r#" |
1028 | 34..37 'foo': Foo | 994 | 34..37 'foo': Foo |
1029 | 44..108 '{ ... } }': () | 995 | 44..108 '{ ... } }': () |
@@ -1043,28 +1009,29 @@ fn infer_in_elseif() { | |||
1043 | fn infer_if_match_with_return() { | 1009 | fn infer_if_match_with_return() { |
1044 | check_infer( | 1010 | check_infer( |
1045 | r#" | 1011 | r#" |
1046 | fn foo() { | 1012 | fn foo() { |
1047 | let _x1 = if true { | 1013 | let _x1 = if true { |
1048 | 1 | 1014 | 1 |
1049 | } else { | 1015 | } else { |
1050 | return; | 1016 | return; |
1051 | }; | 1017 | }; |
1052 | let _x2 = if true { | 1018 | let _x2 = if true { |
1053 | 2 | 1019 | 2 |
1054 | } else { | 1020 | } else { |
1055 | return | 1021 | return |
1056 | }; | 1022 | }; |
1057 | let _x3 = match true { | 1023 | let _x3 = match true { |
1058 | true => 3, | 1024 | true => 3, |
1059 | _ => { | 1025 | _ => { |
1060 | return; | 1026 | return; |
1061 | } | 1027 | } |
1062 | }; | 1028 | }; |
1063 | let _x4 = match true { | 1029 | let _x4 = match true { |
1064 | true => 4, | 1030 | true => 4, |
1065 | _ => return | 1031 | _ => return |
1066 | }; | 1032 | }; |
1067 | }"#, | 1033 | } |
1034 | "#, | ||
1068 | expect![[r#" | 1035 | expect![[r#" |
1069 | 9..322 '{ ... }; }': () | 1036 | 9..322 '{ ... }; }': () |
1070 | 19..22 '_x1': i32 | 1037 | 19..22 '_x1': i32 |
@@ -1778,7 +1745,7 @@ impl i32 { fn foo(&self) -> Foo { Foo } } | |||
1778 | fn main() { | 1745 | fn main() { |
1779 | let x: i32 = i32; | 1746 | let x: i32 = i32; |
1780 | x.foo(); | 1747 | x.foo(); |
1781 | //^ Foo | 1748 | //^^^^^^^ Foo |
1782 | }"#, | 1749 | }"#, |
1783 | ); | 1750 | ); |
1784 | } | 1751 | } |
@@ -1796,7 +1763,7 @@ fn main() { | |||
1796 | fn inner() {} | 1763 | fn inner() {} |
1797 | let x: i32 = i32; | 1764 | let x: i32 = i32; |
1798 | x.foo(); | 1765 | x.foo(); |
1799 | //^ Foo | 1766 | //^^^^^^^ Foo |
1800 | }"#, | 1767 | }"#, |
1801 | ); | 1768 | ); |
1802 | } | 1769 | } |
@@ -1814,7 +1781,7 @@ fn foo() -> &'static str { "" } | |||
1814 | 1781 | ||
1815 | fn main() { | 1782 | fn main() { |
1816 | foo(); | 1783 | foo(); |
1817 | //^ &str | 1784 | //^^^^^ &str |
1818 | }"#, | 1785 | }"#, |
1819 | ); | 1786 | ); |
1820 | } | 1787 | } |
@@ -1832,7 +1799,7 @@ fn foo() -> &'static str { "" } | |||
1832 | 1799 | ||
1833 | fn main() { | 1800 | fn main() { |
1834 | str::foo(); | 1801 | str::foo(); |
1835 | //^ u32 | 1802 | //^^^^^^^^^^ u32 |
1836 | }"#, | 1803 | }"#, |
1837 | ); | 1804 | ); |
1838 | } | 1805 | } |
@@ -1858,9 +1825,9 @@ mod d { | |||
1858 | 1825 | ||
1859 | fn main() { | 1826 | fn main() { |
1860 | d::foo(); | 1827 | d::foo(); |
1861 | //^ u8 | 1828 | //^^^^^^^^ u8 |
1862 | d::foo{a:0}; | 1829 | d::foo{a:0}; |
1863 | //^ u8 | 1830 | //^^^^^^^^^^^ foo |
1864 | }"#, | 1831 | }"#, |
1865 | ); | 1832 | ); |
1866 | } | 1833 | } |
@@ -1950,6 +1917,7 @@ fn fn_pointer_return() { | |||
1950 | fn effects_smoke_test() { | 1917 | fn effects_smoke_test() { |
1951 | check_infer( | 1918 | check_infer( |
1952 | r#" | 1919 | r#" |
1920 | //- minicore: future | ||
1953 | async fn main() { | 1921 | async fn main() { |
1954 | let x = unsafe { 92 }; | 1922 | let x = unsafe { 92 }; |
1955 | let y = async { async { () }.await }; | 1923 | let y = async { async { () }.await }; |
@@ -1957,13 +1925,6 @@ fn effects_smoke_test() { | |||
1957 | let w = const { 92 }; | 1925 | let w = const { 92 }; |
1958 | let t = 'a: { 92 }; | 1926 | let t = 'a: { 92 }; |
1959 | } | 1927 | } |
1960 | |||
1961 | #[prelude_import] use future::*; | ||
1962 | |||
1963 | mod future { | ||
1964 | #[lang = "future_trait"] | ||
1965 | pub trait Future { type Output; } | ||
1966 | } | ||
1967 | "#, | 1928 | "#, |
1968 | expect![[r#" | 1929 | expect![[r#" |
1969 | 16..162 '{ ...2 }; }': () | 1930 | 16..162 '{ ...2 }; }': () |
@@ -2639,11 +2600,8 @@ fn f() { | |||
2639 | fn infer_boxed_self_receiver() { | 2600 | fn infer_boxed_self_receiver() { |
2640 | check_infer( | 2601 | check_infer( |
2641 | r#" | 2602 | r#" |
2642 | #[lang = "deref"] | 2603 | //- minicore: deref |
2643 | pub trait Deref { | 2604 | use core::ops::Deref; |
2644 | type Target; | ||
2645 | fn deref(&self) -> &Self::Target; | ||
2646 | } | ||
2647 | 2605 | ||
2648 | struct Box<T>(T); | 2606 | struct Box<T>(T); |
2649 | 2607 | ||
@@ -2675,40 +2633,39 @@ fn main() { | |||
2675 | } | 2633 | } |
2676 | "#, | 2634 | "#, |
2677 | expect![[r#" | 2635 | expect![[r#" |
2678 | 67..71 'self': &Self | 2636 | 104..108 'self': &Box<T> |
2679 | 175..179 'self': &Box<T> | 2637 | 188..192 'self': &Box<Foo<T>> |
2680 | 259..263 'self': &Box<Foo<T>> | 2638 | 218..220 '{}': () |
2681 | 289..291 '{}': () | 2639 | 242..246 'self': &Box<Foo<T>> |
2682 | 313..317 'self': &Box<Foo<T>> | 2640 | 275..277 '{}': () |
2683 | 346..348 '{}': () | 2641 | 297..301 'self': Box<Foo<T>> |
2684 | 368..372 'self': Box<Foo<T>> | 2642 | 322..324 '{}': () |
2685 | 393..395 '{}': () | 2643 | 338..559 '{ ...r(); }': () |
2686 | 409..630 '{ ...r(); }': () | 2644 | 348..353 'boxed': Box<Foo<i32>> |
2687 | 419..424 'boxed': Box<Foo<i32>> | 2645 | 356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> |
2688 | 427..430 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>> | 2646 | 356..371 'Box(Foo(0_i32))': Box<Foo<i32>> |
2689 | 427..442 'Box(Foo(0_i32))': Box<Foo<i32>> | 2647 | 360..363 'Foo': Foo<i32>(i32) -> Foo<i32> |
2690 | 431..434 'Foo': Foo<i32>(i32) -> Foo<i32> | 2648 | 360..370 'Foo(0_i32)': Foo<i32> |
2691 | 431..441 'Foo(0_i32)': Foo<i32> | 2649 | 364..369 '0_i32': i32 |
2692 | 435..440 '0_i32': i32 | 2650 | 382..386 'bad1': &i32 |
2693 | 453..457 'bad1': &i32 | 2651 | 389..394 'boxed': Box<Foo<i32>> |
2694 | 460..465 'boxed': Box<Foo<i32>> | 2652 | 389..406 'boxed....nner()': &i32 |
2695 | 460..477 'boxed....nner()': &i32 | 2653 | 416..421 'good1': &i32 |
2696 | 487..492 'good1': &i32 | 2654 | 424..438 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 |
2697 | 495..509 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32 | 2655 | 424..446 'Foo::g...boxed)': &i32 |
2698 | 495..517 'Foo::g...boxed)': &i32 | 2656 | 439..445 '&boxed': &Box<Foo<i32>> |
2699 | 510..516 '&boxed': &Box<Foo<i32>> | 2657 | 440..445 'boxed': Box<Foo<i32>> |
2700 | 511..516 'boxed': Box<Foo<i32>> | 2658 | 457..461 'bad2': &Foo<i32> |
2701 | 528..532 'bad2': &Foo<i32> | 2659 | 464..469 'boxed': Box<Foo<i32>> |
2702 | 535..540 'boxed': Box<Foo<i32>> | 2660 | 464..480 'boxed....self()': &Foo<i32> |
2703 | 535..551 'boxed....self()': &Foo<i32> | 2661 | 490..495 'good2': &Foo<i32> |
2704 | 561..566 'good2': &Foo<i32> | 2662 | 498..511 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> |
2705 | 569..582 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32> | 2663 | 498..519 'Foo::g...boxed)': &Foo<i32> |
2706 | 569..590 'Foo::g...boxed)': &Foo<i32> | 2664 | 512..518 '&boxed': &Box<Foo<i32>> |
2707 | 583..589 '&boxed': &Box<Foo<i32>> | 2665 | 513..518 'boxed': Box<Foo<i32>> |
2708 | 584..589 'boxed': Box<Foo<i32>> | 2666 | 530..535 'inner': Foo<i32> |
2709 | 601..606 'inner': Foo<i32> | 2667 | 538..543 'boxed': Box<Foo<i32>> |
2710 | 609..614 'boxed': Box<Foo<i32>> | 2668 | 538..556 'boxed....nner()': Foo<i32> |
2711 | 609..627 'boxed....nner()': Foo<i32> | ||
2712 | "#]], | 2669 | "#]], |
2713 | ); | 2670 | ); |
2714 | } | 2671 | } |
@@ -2720,7 +2677,7 @@ fn prelude_2015() { | |||
2720 | //- /main.rs edition:2015 crate:main deps:core | 2677 | //- /main.rs edition:2015 crate:main deps:core |
2721 | fn f() { | 2678 | fn f() { |
2722 | Rust; | 2679 | Rust; |
2723 | //^ Rust | 2680 | //^^^^ Rust |
2724 | } | 2681 | } |
2725 | 2682 | ||
2726 | //- /core.rs crate:core | 2683 | //- /core.rs crate:core |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 6bcede4c4..a0ddad570 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -1,15 +1,16 @@ | |||
1 | use cov_mark::check; | ||
1 | use expect_test::expect; | 2 | use expect_test::expect; |
2 | 3 | ||
3 | use super::{check_infer, check_infer_with_mismatches, check_types}; | 4 | use super::{check, check_infer, check_infer_with_mismatches, check_types}; |
4 | 5 | ||
5 | #[test] | 6 | #[test] |
6 | fn infer_await() { | 7 | fn infer_await() { |
7 | check_types( | 8 | check_types( |
8 | r#" | 9 | r#" |
9 | //- /main.rs crate:main deps:core | 10 | //- minicore: future |
10 | struct IntFuture; | 11 | struct IntFuture; |
11 | 12 | ||
12 | impl Future for IntFuture { | 13 | impl core::future::Future for IntFuture { |
13 | type Output = u64; | 14 | type Output = u64; |
14 | } | 15 | } |
15 | 16 | ||
@@ -18,16 +19,6 @@ fn test() { | |||
18 | let v = r.await; | 19 | let v = r.await; |
19 | v; | 20 | v; |
20 | } //^ u64 | 21 | } //^ u64 |
21 | |||
22 | //- /core.rs crate:core | ||
23 | pub mod prelude { | ||
24 | pub mod rust_2018 { | ||
25 | #[lang = "future_trait"] | ||
26 | pub trait Future { | ||
27 | type Output; | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | "#, | 22 | "#, |
32 | ); | 23 | ); |
33 | } | 24 | } |
@@ -36,25 +27,14 @@ pub mod prelude { | |||
36 | fn infer_async() { | 27 | fn infer_async() { |
37 | check_types( | 28 | check_types( |
38 | r#" | 29 | r#" |
39 | //- /main.rs crate:main deps:core | 30 | //- minicore: future |
40 | async fn foo() -> u64 { | 31 | async fn foo() -> u64 { 128 } |
41 | 128 | ||
42 | } | ||
43 | 32 | ||
44 | fn test() { | 33 | fn test() { |
45 | let r = foo(); | 34 | let r = foo(); |
46 | let v = r.await; | 35 | let v = r.await; |
47 | v; | 36 | v; |
48 | } //^ u64 | 37 | } //^ u64 |
49 | |||
50 | //- /core.rs crate:core | ||
51 | #[prelude_import] use future::*; | ||
52 | mod future { | ||
53 | #[lang = "future_trait"] | ||
54 | trait Future { | ||
55 | type Output; | ||
56 | } | ||
57 | } | ||
58 | "#, | 38 | "#, |
59 | ); | 39 | ); |
60 | } | 40 | } |
@@ -63,24 +43,13 @@ mod future { | |||
63 | fn infer_desugar_async() { | 43 | fn infer_desugar_async() { |
64 | check_types( | 44 | check_types( |
65 | r#" | 45 | r#" |
66 | //- /main.rs crate:main deps:core | 46 | //- minicore: future |
67 | async fn foo() -> u64 { | 47 | async fn foo() -> u64 { 128 } |
68 | 128 | ||
69 | } | ||
70 | 48 | ||
71 | fn test() { | 49 | fn test() { |
72 | let r = foo(); | 50 | let r = foo(); |
73 | r; | 51 | r; |
74 | } //^ impl Future<Output = u64> | 52 | } //^ impl Future<Output = u64> |
75 | |||
76 | //- /core.rs crate:core | ||
77 | #[prelude_import] use future::*; | ||
78 | mod future { | ||
79 | trait Future { | ||
80 | type Output; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | "#, | 53 | "#, |
85 | ); | 54 | ); |
86 | } | 55 | } |
@@ -89,7 +58,7 @@ mod future { | |||
89 | fn infer_async_block() { | 58 | fn infer_async_block() { |
90 | check_types( | 59 | check_types( |
91 | r#" | 60 | r#" |
92 | //- /main.rs crate:main deps:core | 61 | //- minicore: future, option |
93 | async fn test() { | 62 | async fn test() { |
94 | let a = async { 42 }; | 63 | let a = async { 42 }; |
95 | a; | 64 | a; |
@@ -101,7 +70,7 @@ async fn test() { | |||
101 | b; | 70 | b; |
102 | // ^ () | 71 | // ^ () |
103 | let c = async { | 72 | let c = async { |
104 | let y = Option::None; | 73 | let y = None; |
105 | y | 74 | y |
106 | // ^ Option<u64> | 75 | // ^ Option<u64> |
107 | }; | 76 | }; |
@@ -109,18 +78,6 @@ async fn test() { | |||
109 | c; | 78 | c; |
110 | // ^ impl Future<Output = Option<u64>> | 79 | // ^ impl Future<Output = Option<u64>> |
111 | } | 80 | } |
112 | |||
113 | enum Option<T> { None, Some(T) } | ||
114 | |||
115 | //- /core.rs crate:core | ||
116 | #[prelude_import] use future::*; | ||
117 | mod future { | ||
118 | #[lang = "future_trait"] | ||
119 | trait Future { | ||
120 | type Output; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | "#, | 81 | "#, |
125 | ); | 82 | ); |
126 | } | 83 | } |
@@ -329,7 +286,7 @@ mod ops { | |||
329 | 286 | ||
330 | #[test] | 287 | #[test] |
331 | fn infer_from_bound_1() { | 288 | fn infer_from_bound_1() { |
332 | check_infer( | 289 | check_types( |
333 | r#" | 290 | r#" |
334 | trait Trait<T> {} | 291 | trait Trait<T> {} |
335 | struct S<T>(T); | 292 | struct S<T>(T); |
@@ -337,99 +294,62 @@ impl<U> Trait<U> for S<U> {} | |||
337 | fn foo<T: Trait<u32>>(t: T) {} | 294 | fn foo<T: Trait<u32>>(t: T) {} |
338 | fn test() { | 295 | fn test() { |
339 | let s = S(unknown); | 296 | let s = S(unknown); |
297 | // ^^^^^^^ u32 | ||
340 | foo(s); | 298 | foo(s); |
341 | }"#, | 299 | }"#, |
342 | expect![[r#" | ||
343 | 85..86 't': T | ||
344 | 91..93 '{}': () | ||
345 | 104..143 '{ ...(s); }': () | ||
346 | 114..115 's': S<u32> | ||
347 | 118..119 'S': S<u32>(u32) -> S<u32> | ||
348 | 118..128 'S(unknown)': S<u32> | ||
349 | 120..127 'unknown': u32 | ||
350 | 134..137 'foo': fn foo<S<u32>>(S<u32>) | ||
351 | 134..140 'foo(s)': () | ||
352 | 138..139 's': S<u32> | ||
353 | "#]], | ||
354 | ); | 300 | ); |
355 | } | 301 | } |
356 | 302 | ||
357 | #[test] | 303 | #[test] |
358 | fn infer_from_bound_2() { | 304 | fn infer_from_bound_2() { |
359 | check_infer( | 305 | check_types( |
360 | r#" | 306 | r#" |
361 | trait Trait<T> {} | 307 | trait Trait<T> {} |
362 | struct S<T>(T); | 308 | struct S<T>(T); |
363 | impl<U> Trait<U> for S<U> {} | 309 | impl<U> Trait<U> for S<U> {} |
364 | fn foo<U, T: Trait<U>>(t: T) -> U {} | 310 | fn foo<U, T: Trait<U>>(t: T) -> U { loop {} } |
365 | fn test() { | 311 | fn test() { |
366 | let s = S(unknown); | 312 | let s = S(unknown); |
313 | // ^^^^^^^ u32 | ||
367 | let x: u32 = foo(s); | 314 | let x: u32 = foo(s); |
368 | }"#, | 315 | }"#, |
369 | expect![[r#" | ||
370 | 86..87 't': T | ||
371 | 97..99 '{}': () | ||
372 | 110..162 '{ ...(s); }': () | ||
373 | 120..121 's': S<u32> | ||
374 | 124..125 'S': S<u32>(u32) -> S<u32> | ||
375 | 124..134 'S(unknown)': S<u32> | ||
376 | 126..133 'unknown': u32 | ||
377 | 144..145 'x': u32 | ||
378 | 153..156 'foo': fn foo<u32, S<u32>>(S<u32>) -> u32 | ||
379 | 153..159 'foo(s)': u32 | ||
380 | 157..158 's': S<u32> | ||
381 | "#]], | ||
382 | ); | 316 | ); |
383 | } | 317 | } |
384 | 318 | ||
385 | #[test] | 319 | #[test] |
386 | fn trait_default_method_self_bound_implements_trait() { | 320 | fn trait_default_method_self_bound_implements_trait() { |
387 | cov_mark::check!(trait_self_implements_self); | 321 | cov_mark::check!(trait_self_implements_self); |
388 | check_infer( | 322 | check( |
389 | r#" | 323 | r#" |
390 | trait Trait { | 324 | trait Trait { |
391 | fn foo(&self) -> i64; | 325 | fn foo(&self) -> i64; |
392 | fn bar(&self) -> { | 326 | fn bar(&self) -> () { |
393 | let x = self.foo(); | 327 | self.foo(); |
328 | // ^^^^^^^^^^ type: i64 | ||
394 | } | 329 | } |
395 | }"#, | 330 | }"#, |
396 | expect![[r#" | ||
397 | 26..30 'self': &Self | ||
398 | 52..56 'self': &Self | ||
399 | 61..96 '{ ... }': () | ||
400 | 75..76 'x': i64 | ||
401 | 79..83 'self': &Self | ||
402 | 79..89 'self.foo()': i64 | ||
403 | "#]], | ||
404 | ); | 331 | ); |
405 | } | 332 | } |
406 | 333 | ||
407 | #[test] | 334 | #[test] |
408 | fn trait_default_method_self_bound_implements_super_trait() { | 335 | fn trait_default_method_self_bound_implements_super_trait() { |
409 | check_infer( | 336 | check( |
410 | r#" | 337 | r#" |
411 | trait SuperTrait { | 338 | trait SuperTrait { |
412 | fn foo(&self) -> i64; | 339 | fn foo(&self) -> i64; |
413 | } | 340 | } |
414 | trait Trait: SuperTrait { | 341 | trait Trait: SuperTrait { |
415 | fn bar(&self) -> { | 342 | fn bar(&self) -> () { |
416 | let x = self.foo(); | 343 | self.foo(); |
344 | // ^^^^^^^^^^ type: i64 | ||
417 | } | 345 | } |
418 | }"#, | 346 | }"#, |
419 | expect![[r#" | ||
420 | 31..35 'self': &Self | ||
421 | 85..89 'self': &Self | ||
422 | 94..129 '{ ... }': () | ||
423 | 108..109 'x': i64 | ||
424 | 112..116 'self': &Self | ||
425 | 112..122 'self.foo()': i64 | ||
426 | "#]], | ||
427 | ); | 347 | ); |
428 | } | 348 | } |
429 | 349 | ||
430 | #[test] | 350 | #[test] |
431 | fn infer_project_associated_type() { | 351 | fn infer_project_associated_type() { |
432 | check_infer( | 352 | check_types( |
433 | r#" | 353 | r#" |
434 | trait Iterable { | 354 | trait Iterable { |
435 | type Item; | 355 | type Item; |
@@ -438,89 +358,62 @@ struct S; | |||
438 | impl Iterable for S { type Item = u32; } | 358 | impl Iterable for S { type Item = u32; } |
439 | fn test<T: Iterable>() { | 359 | fn test<T: Iterable>() { |
440 | let x: <S as Iterable>::Item = 1; | 360 | let x: <S as Iterable>::Item = 1; |
441 | let y: <T as Iterable>::Item = no_matter; | 361 | // ^ u32 |
442 | let z: T::Item = no_matter; | 362 | let y: <T as Iterable>::Item = u; |
443 | let a: <T>::Item = no_matter; | 363 | // ^ Iterable::Item<T> |
364 | let z: T::Item = u; | ||
365 | // ^ Iterable::Item<T> | ||
366 | let a: <T>::Item = u; | ||
367 | // ^ Iterable::Item<T> | ||
444 | }"#, | 368 | }"#, |
445 | expect![[r#" | ||
446 | 108..261 '{ ...ter; }': () | ||
447 | 118..119 'x': u32 | ||
448 | 145..146 '1': u32 | ||
449 | 156..157 'y': Iterable::Item<T> | ||
450 | 183..192 'no_matter': Iterable::Item<T> | ||
451 | 202..203 'z': Iterable::Item<T> | ||
452 | 215..224 'no_matter': Iterable::Item<T> | ||
453 | 234..235 'a': Iterable::Item<T> | ||
454 | 249..258 'no_matter': Iterable::Item<T> | ||
455 | "#]], | ||
456 | ); | 369 | ); |
457 | } | 370 | } |
458 | 371 | ||
459 | #[test] | 372 | #[test] |
460 | fn infer_return_associated_type() { | 373 | fn infer_return_associated_type() { |
461 | check_infer( | 374 | check_types( |
462 | r#" | 375 | r#" |
463 | trait Iterable { | 376 | trait Iterable { |
464 | type Item; | 377 | type Item; |
465 | } | 378 | } |
466 | struct S; | 379 | struct S; |
467 | impl Iterable for S { type Item = u32; } | 380 | impl Iterable for S { type Item = u32; } |
468 | fn foo1<T: Iterable>(t: T) -> T::Item {} | 381 | fn foo1<T: Iterable>(t: T) -> T::Item { loop {} } |
469 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} | 382 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item { loop {} } |
470 | fn foo3<T: Iterable>(t: T) -> <T>::Item {} | 383 | fn foo3<T: Iterable>(t: T) -> <T>::Item { loop {} } |
471 | fn test() { | 384 | fn test() { |
472 | let x = foo1(S); | 385 | foo1(S); |
473 | let y = foo2(S); | 386 | // ^^^^^^^ u32 |
474 | let z = foo3(S); | 387 | foo2(S); |
388 | // ^^^^^^^ u32 | ||
389 | foo3(S); | ||
390 | // ^^^^^^^ u32 | ||
475 | }"#, | 391 | }"#, |
476 | expect![[r#" | ||
477 | 106..107 't': T | ||
478 | 123..125 '{}': () | ||
479 | 147..148 't': T | ||
480 | 178..180 '{}': () | ||
481 | 202..203 't': T | ||
482 | 221..223 '{}': () | ||
483 | 234..300 '{ ...(S); }': () | ||
484 | 244..245 'x': u32 | ||
485 | 248..252 'foo1': fn foo1<S>(S) -> <S as Iterable>::Item | ||
486 | 248..255 'foo1(S)': u32 | ||
487 | 253..254 'S': S | ||
488 | 265..266 'y': u32 | ||
489 | 269..273 'foo2': fn foo2<S>(S) -> <S as Iterable>::Item | ||
490 | 269..276 'foo2(S)': u32 | ||
491 | 274..275 'S': S | ||
492 | 286..287 'z': u32 | ||
493 | 290..294 'foo3': fn foo3<S>(S) -> <S as Iterable>::Item | ||
494 | 290..297 'foo3(S)': u32 | ||
495 | 295..296 'S': S | ||
496 | "#]], | ||
497 | ); | 392 | ); |
498 | } | 393 | } |
499 | 394 | ||
500 | #[test] | 395 | #[test] |
501 | fn infer_associated_type_bound() { | 396 | fn infer_associated_type_bound() { |
502 | check_infer( | 397 | check_types( |
503 | r#" | 398 | r#" |
504 | trait Iterable { | 399 | trait Iterable { |
505 | type Item; | 400 | type Item; |
506 | } | 401 | } |
507 | fn test<T: Iterable<Item=u32>>() { | 402 | fn test<T: Iterable<Item=u32>>() { |
508 | let y: T::Item = unknown; | 403 | let y: T::Item = unknown; |
404 | // ^^^^^^^ u32 | ||
509 | }"#, | 405 | }"#, |
510 | expect![[r#" | ||
511 | 67..100 '{ ...own; }': () | ||
512 | 77..78 'y': u32 | ||
513 | 90..97 'unknown': u32 | ||
514 | "#]], | ||
515 | ); | 406 | ); |
516 | } | 407 | } |
517 | 408 | ||
518 | #[test] | 409 | #[test] |
519 | fn infer_const_body() { | 410 | fn infer_const_body() { |
411 | // FIXME make check_types work with other bodies | ||
520 | check_infer( | 412 | check_infer( |
521 | r#" | 413 | r#" |
522 | const A: u32 = 1 + 1; | 414 | const A: u32 = 1 + 1; |
523 | static B: u64 = { let x = 1; x };"#, | 415 | static B: u64 = { let x = 1; x }; |
416 | "#, | ||
524 | expect![[r#" | 417 | expect![[r#" |
525 | 15..16 '1': u32 | 418 | 15..16 '1': u32 |
526 | 15..20 '1 + 1': u32 | 419 | 15..20 '1 + 1': u32 |
@@ -611,11 +504,11 @@ fn indexing_arrays() { | |||
611 | fn infer_ops_index() { | 504 | fn infer_ops_index() { |
612 | check_types( | 505 | check_types( |
613 | r#" | 506 | r#" |
614 | //- /main.rs crate:main deps:std | 507 | //- minicore: index |
615 | struct Bar; | 508 | struct Bar; |
616 | struct Foo; | 509 | struct Foo; |
617 | 510 | ||
618 | impl std::ops::Index<u32> for Bar { | 511 | impl core::ops::Index<u32> for Bar { |
619 | type Output = Foo; | 512 | type Output = Foo; |
620 | } | 513 | } |
621 | 514 | ||
@@ -624,15 +517,6 @@ fn test() { | |||
624 | let b = a[1u32]; | 517 | let b = a[1u32]; |
625 | b; | 518 | b; |
626 | } //^ Foo | 519 | } //^ Foo |
627 | |||
628 | //- /std.rs crate:std | ||
629 | #[prelude_import] use ops::*; | ||
630 | mod ops { | ||
631 | #[lang = "index"] | ||
632 | pub trait Index<Idx> { | ||
633 | type Output; | ||
634 | } | ||
635 | } | ||
636 | "#, | 520 | "#, |
637 | ); | 521 | ); |
638 | } | 522 | } |
@@ -641,16 +525,16 @@ mod ops { | |||
641 | fn infer_ops_index_int() { | 525 | fn infer_ops_index_int() { |
642 | check_types( | 526 | check_types( |
643 | r#" | 527 | r#" |
644 | //- /main.rs crate:main deps:std | 528 | //- minicore: index |
645 | struct Bar; | 529 | struct Bar; |
646 | struct Foo; | 530 | struct Foo; |
647 | 531 | ||
648 | impl std::ops::Index<u32> for Bar { | 532 | impl core::ops::Index<u32> for Bar { |
649 | type Output = Foo; | 533 | type Output = Foo; |
650 | } | 534 | } |
651 | 535 | ||
652 | struct Range; | 536 | struct Range; |
653 | impl std::ops::Index<Range> for Bar { | 537 | impl core::ops::Index<Range> for Bar { |
654 | type Output = Bar; | 538 | type Output = Bar; |
655 | } | 539 | } |
656 | 540 | ||
@@ -660,15 +544,6 @@ fn test() { | |||
660 | b; | 544 | b; |
661 | //^ Foo | 545 | //^ Foo |
662 | } | 546 | } |
663 | |||
664 | //- /std.rs crate:std | ||
665 | #[prelude_import] use ops::*; | ||
666 | mod ops { | ||
667 | #[lang = "index"] | ||
668 | pub trait Index<Idx> { | ||
669 | type Output; | ||
670 | } | ||
671 | } | ||
672 | "#, | 547 | "#, |
673 | ); | 548 | ); |
674 | } | 549 | } |
@@ -677,25 +552,12 @@ mod ops { | |||
677 | fn infer_ops_index_autoderef() { | 552 | fn infer_ops_index_autoderef() { |
678 | check_types( | 553 | check_types( |
679 | r#" | 554 | r#" |
680 | //- /main.rs crate:main deps:std | 555 | //- minicore: index, slice |
681 | fn test() { | 556 | fn test() { |
682 | let a = &[1u32, 2, 3]; | 557 | let a = &[1u32, 2, 3]; |
683 | let b = a[1u32]; | 558 | let b = a[1]; |
684 | b; | 559 | b; |
685 | } //^ u32 | 560 | } //^ u32 |
686 | |||
687 | //- /std.rs crate:std | ||
688 | impl<T> ops::Index<u32> for [T] { | ||
689 | type Output = T; | ||
690 | } | ||
691 | |||
692 | #[prelude_import] use ops::*; | ||
693 | mod ops { | ||
694 | #[lang = "index"] | ||
695 | pub trait Index<Idx> { | ||
696 | type Output; | ||
697 | } | ||
698 | } | ||
699 | "#, | 561 | "#, |
700 | ); | 562 | ); |
701 | } | 563 | } |
@@ -704,25 +566,20 @@ mod ops { | |||
704 | fn deref_trait() { | 566 | fn deref_trait() { |
705 | check_types( | 567 | check_types( |
706 | r#" | 568 | r#" |
707 | #[lang = "deref"] | 569 | //- minicore: deref |
708 | trait Deref { | ||
709 | type Target; | ||
710 | fn deref(&self) -> &Self::Target; | ||
711 | } | ||
712 | |||
713 | struct Arc<T>; | 570 | struct Arc<T>; |
714 | impl<T> Deref for Arc<T> { | 571 | impl<T> core::ops::Deref for Arc<T> { |
715 | type Target = T; | 572 | type Target = T; |
716 | } | 573 | } |
717 | 574 | ||
718 | struct S; | 575 | struct S; |
719 | impl S { | 576 | impl S { |
720 | fn foo(&self) -> u128 {} | 577 | fn foo(&self) -> u128 { 0 } |
721 | } | 578 | } |
722 | 579 | ||
723 | fn test(s: Arc<S>) { | 580 | fn test(s: Arc<S>) { |
724 | (*s, s.foo()); | 581 | (*s, s.foo()); |
725 | } //^ (S, u128) | 582 | } //^^^^^^^^^^^^^ (S, u128) |
726 | "#, | 583 | "#, |
727 | ); | 584 | ); |
728 | } | 585 | } |
@@ -731,16 +588,10 @@ fn test(s: Arc<S>) { | |||
731 | fn deref_trait_with_inference_var() { | 588 | fn deref_trait_with_inference_var() { |
732 | check_types( | 589 | check_types( |
733 | r#" | 590 | r#" |
734 | //- /main.rs | 591 | //- minicore: deref |
735 | #[lang = "deref"] | ||
736 | trait Deref { | ||
737 | type Target; | ||
738 | fn deref(&self) -> &Self::Target; | ||
739 | } | ||
740 | |||
741 | struct Arc<T>; | 592 | struct Arc<T>; |
742 | fn new_arc<T>() -> Arc<T> {} | 593 | fn new_arc<T>() -> Arc<T> { Arc } |
743 | impl<T> Deref for Arc<T> { | 594 | impl<T> core::ops::Deref for Arc<T> { |
744 | type Target = T; | 595 | type Target = T; |
745 | } | 596 | } |
746 | 597 | ||
@@ -749,8 +600,8 @@ fn foo(a: Arc<S>) {} | |||
749 | 600 | ||
750 | fn test() { | 601 | fn test() { |
751 | let a = new_arc(); | 602 | let a = new_arc(); |
752 | let b = (*a); | 603 | let b = *a; |
753 | //^ S | 604 | //^^ S |
754 | foo(a); | 605 | foo(a); |
755 | } | 606 | } |
756 | "#, | 607 | "#, |
@@ -761,21 +612,16 @@ fn test() { | |||
761 | fn deref_trait_infinite_recursion() { | 612 | fn deref_trait_infinite_recursion() { |
762 | check_types( | 613 | check_types( |
763 | r#" | 614 | r#" |
764 | #[lang = "deref"] | 615 | //- minicore: deref |
765 | trait Deref { | ||
766 | type Target; | ||
767 | fn deref(&self) -> &Self::Target; | ||
768 | } | ||
769 | |||
770 | struct S; | 616 | struct S; |
771 | 617 | ||
772 | impl Deref for S { | 618 | impl core::ops::Deref for S { |
773 | type Target = S; | 619 | type Target = S; |
774 | } | 620 | } |
775 | 621 | ||
776 | fn test(s: S) { | 622 | fn test(s: S) { |
777 | s.foo(); | 623 | s.foo(); |
778 | } //^ {unknown} | 624 | } //^^^^^^^ {unknown} |
779 | "#, | 625 | "#, |
780 | ); | 626 | ); |
781 | } | 627 | } |
@@ -784,25 +630,20 @@ fn test(s: S) { | |||
784 | fn deref_trait_with_question_mark_size() { | 630 | fn deref_trait_with_question_mark_size() { |
785 | check_types( | 631 | check_types( |
786 | r#" | 632 | r#" |
787 | #[lang = "deref"] | 633 | //- minicore: deref |
788 | trait Deref { | ||
789 | type Target; | ||
790 | fn deref(&self) -> &Self::Target; | ||
791 | } | ||
792 | |||
793 | struct Arc<T>; | 634 | struct Arc<T>; |
794 | impl<T> Deref for Arc<T> { | 635 | impl<T: ?Sized> core::ops::Deref for Arc<T> { |
795 | type Target = T; | 636 | type Target = T; |
796 | } | 637 | } |
797 | 638 | ||
798 | struct S; | 639 | struct S; |
799 | impl S { | 640 | impl S { |
800 | fn foo(&self) -> u128 {} | 641 | fn foo(&self) -> u128 { 0 } |
801 | } | 642 | } |
802 | 643 | ||
803 | fn test(s: Arc<S>) { | 644 | fn test(s: Arc<S>) { |
804 | (*s, s.foo()); | 645 | (*s, s.foo()); |
805 | } //^ (S, u128) | 646 | } //^^^^^^^^^^^^^ (S, u128) |
806 | "#, | 647 | "#, |
807 | ); | 648 | ); |
808 | } | 649 | } |
@@ -816,11 +657,11 @@ struct S; | |||
816 | trait Trait<T> {} | 657 | trait Trait<T> {} |
817 | impl Trait<u32> for S {} | 658 | impl Trait<u32> for S {} |
818 | 659 | ||
819 | fn foo<T: Trait<U>, U>(t: T) -> U {} | 660 | fn foo<T: Trait<U>, U>(t: T) -> U { loop {} } |
820 | 661 | ||
821 | fn test(s: S) { | 662 | fn test(s: S) { |
822 | (foo(s)); | 663 | foo(s); |
823 | } //^ u32 | 664 | } //^^^^^^ u32 |
824 | "#, | 665 | "#, |
825 | ); | 666 | ); |
826 | } | 667 | } |
@@ -837,12 +678,12 @@ impl Trait<isize> for S {} | |||
837 | 678 | ||
838 | struct O; | 679 | struct O; |
839 | impl O { | 680 | impl O { |
840 | fn foo<T: Trait<U>, U>(&self, t: T) -> U {} | 681 | fn foo<T: Trait<U>, U>(&self, t: T) -> U { loop {} } |
841 | } | 682 | } |
842 | 683 | ||
843 | fn test() { | 684 | fn test() { |
844 | O.foo(S); | 685 | O.foo(S); |
845 | } //^ isize | 686 | } //^^^^^^^^ isize |
846 | "#, | 687 | "#, |
847 | ); | 688 | ); |
848 | } | 689 | } |
@@ -857,12 +698,12 @@ trait Trait<T> {} | |||
857 | impl Trait<i64> for S {} | 698 | impl Trait<i64> for S {} |
858 | 699 | ||
859 | impl S { | 700 | impl S { |
860 | fn foo<U>(&self) -> U where Self: Trait<U> {} | 701 | fn foo<U>(&self) -> U where Self: Trait<U> { loop {} } |
861 | } | 702 | } |
862 | 703 | ||
863 | fn test() { | 704 | fn test() { |
864 | S.foo(); | 705 | S.foo(); |
865 | } //^ i64 | 706 | } //^^^^^^^ i64 |
866 | "#, | 707 | "#, |
867 | ); | 708 | ); |
868 | } | 709 | } |
@@ -878,12 +719,12 @@ impl Trait<&str> for S {} | |||
878 | 719 | ||
879 | struct O<T>; | 720 | struct O<T>; |
880 | impl<U, T: Trait<U>> O<T> { | 721 | impl<U, T: Trait<U>> O<T> { |
881 | fn foo(&self) -> U {} | 722 | fn foo(&self) -> U { loop {} } |
882 | } | 723 | } |
883 | 724 | ||
884 | fn test(o: O<S>) { | 725 | fn test(o: O<S>) { |
885 | o.foo(); | 726 | o.foo(); |
886 | } //^ &str | 727 | } //^^^^^^^ &str |
887 | "#, | 728 | "#, |
888 | ); | 729 | ); |
889 | } | 730 | } |
@@ -898,7 +739,7 @@ struct S; | |||
898 | impl Clone for S {} | 739 | impl Clone for S {} |
899 | impl<T> Trait for T where T: Clone {} | 740 | impl<T> Trait for T where T: Clone {} |
900 | fn test<T: Clone>(t: T) { t.foo(); } | 741 | fn test<T: Clone>(t: T) { t.foo(); } |
901 | //^ u128 | 742 | //^^^^^^^ u128 |
902 | "#, | 743 | "#, |
903 | ); | 744 | ); |
904 | } | 745 | } |
@@ -914,7 +755,7 @@ struct S; | |||
914 | impl Clone for S {} | 755 | impl Clone for S {} |
915 | impl<T> Trait for T where T: Clone {} | 756 | impl<T> Trait for T where T: Clone {} |
916 | fn test<T>(t: T) { t.foo(); } | 757 | fn test<T>(t: T) { t.foo(); } |
917 | //^ {unknown} | 758 | //^^^^^^^ {unknown} |
918 | "#, | 759 | "#, |
919 | ); | 760 | ); |
920 | } | 761 | } |
@@ -927,7 +768,7 @@ trait Trait { fn foo(self) -> u128; } | |||
927 | struct S; | 768 | struct S; |
928 | impl Trait for S {} | 769 | impl Trait for S {} |
929 | fn test<T: Trait>(t: T) { t.foo(); } | 770 | fn test<T: Trait>(t: T) { t.foo(); } |
930 | //^ u128 | 771 | //^^^^^^^ u128 |
931 | "#, | 772 | "#, |
932 | ); | 773 | ); |
933 | } | 774 | } |
@@ -940,7 +781,7 @@ trait Trait { fn foo(self) -> u128; } | |||
940 | struct S; | 781 | struct S; |
941 | impl Trait for S {} | 782 | impl Trait for S {} |
942 | fn test<T>(t: T) { t.foo(); } | 783 | fn test<T>(t: T) { t.foo(); } |
943 | //^ {unknown} | 784 | //^^^^^^^ {unknown} |
944 | "#, | 785 | "#, |
945 | ); | 786 | ); |
946 | } | 787 | } |
@@ -949,16 +790,13 @@ fn test<T>(t: T) { t.foo(); } | |||
949 | fn generic_param_env_deref() { | 790 | fn generic_param_env_deref() { |
950 | check_types( | 791 | check_types( |
951 | r#" | 792 | r#" |
952 | #[lang = "deref"] | 793 | //- minicore: deref |
953 | trait Deref { | ||
954 | type Target; | ||
955 | } | ||
956 | trait Trait {} | 794 | trait Trait {} |
957 | impl<T> Deref for T where T: Trait { | 795 | impl<T> core::ops::Deref for T where T: Trait { |
958 | type Target = i128; | 796 | type Target = i128; |
959 | } | 797 | } |
960 | fn test<T: Trait>(t: T) { (*t); } | 798 | fn test<T: Trait>(t: T) { *t; } |
961 | //^ i128 | 799 | //^^ i128 |
962 | "#, | 800 | "#, |
963 | ); | 801 | ); |
964 | } | 802 | } |
@@ -1475,17 +1313,16 @@ fn test( | |||
1475 | } | 1313 | } |
1476 | 1314 | ||
1477 | #[test] | 1315 | #[test] |
1478 | #[ignore] | ||
1479 | fn error_bound_chalk() { | 1316 | fn error_bound_chalk() { |
1480 | check_types( | 1317 | check_types( |
1481 | r#" | 1318 | r#" |
1482 | trait Trait { | 1319 | trait Trait { |
1483 | fn foo(&self) -> u32 {} | 1320 | fn foo(&self) -> u32 { 0 } |
1484 | } | 1321 | } |
1485 | 1322 | ||
1486 | fn test(x: (impl Trait + UnknownTrait)) { | 1323 | fn test(x: (impl Trait + UnknownTrait)) { |
1487 | x.foo(); | 1324 | x.foo(); |
1488 | } //^ u32 | 1325 | } //^^^^^^^ u32 |
1489 | "#, | 1326 | "#, |
1490 | ); | 1327 | ); |
1491 | } | 1328 | } |
@@ -1558,7 +1395,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
1558 | fn impl_trait_assoc_binding_projection_bug() { | 1395 | fn impl_trait_assoc_binding_projection_bug() { |
1559 | check_types( | 1396 | check_types( |
1560 | r#" | 1397 | r#" |
1561 | //- /main.rs crate:main deps:std | 1398 | //- minicore: iterator |
1562 | pub trait Language { | 1399 | pub trait Language { |
1563 | type Kind; | 1400 | type Kind; |
1564 | } | 1401 | } |
@@ -1576,21 +1413,7 @@ trait Clone { | |||
1576 | fn api_walkthrough() { | 1413 | fn api_walkthrough() { |
1577 | for node in foo() { | 1414 | for node in foo() { |
1578 | node.clone(); | 1415 | node.clone(); |
1579 | } //^ {unknown} | 1416 | } //^^^^^^^^^^^^ {unknown} |
1580 | } | ||
1581 | |||
1582 | //- /std.rs crate:std | ||
1583 | #[prelude_import] use iter::*; | ||
1584 | mod iter { | ||
1585 | trait IntoIterator { | ||
1586 | type Item; | ||
1587 | } | ||
1588 | trait Iterator { | ||
1589 | type Item; | ||
1590 | } | ||
1591 | impl<T: Iterator> IntoIterator for T { | ||
1592 | type Item = <T as Iterator>::Item; | ||
1593 | } | ||
1594 | } | 1417 | } |
1595 | "#, | 1418 | "#, |
1596 | ); | 1419 | ); |
@@ -1627,13 +1450,13 @@ fn where_clause_trait_in_scope_for_method_resolution() { | |||
1627 | r#" | 1450 | r#" |
1628 | mod foo { | 1451 | mod foo { |
1629 | trait Trait { | 1452 | trait Trait { |
1630 | fn foo(&self) -> u32 {} | 1453 | fn foo(&self) -> u32 { 0 } |
1631 | } | 1454 | } |
1632 | } | 1455 | } |
1633 | 1456 | ||
1634 | fn test<T: foo::Trait>(x: T) { | 1457 | fn test<T: foo::Trait>(x: T) { |
1635 | x.foo(); | 1458 | x.foo(); |
1636 | } //^ u32 | 1459 | } //^^^^^^^ u32 |
1637 | "#, | 1460 | "#, |
1638 | ); | 1461 | ); |
1639 | } | 1462 | } |
@@ -1838,20 +1661,7 @@ fn test() { | |||
1838 | fn fn_trait_deref_with_ty_default() { | 1661 | fn fn_trait_deref_with_ty_default() { |
1839 | check_infer( | 1662 | check_infer( |
1840 | r#" | 1663 | r#" |
1841 | #[lang = "deref"] | 1664 | //- minicore: deref, fn |
1842 | trait Deref { | ||
1843 | type Target; | ||
1844 | |||
1845 | fn deref(&self) -> &Self::Target; | ||
1846 | } | ||
1847 | |||
1848 | #[lang="fn_once"] | ||
1849 | trait FnOnce<Args> { | ||
1850 | type Output; | ||
1851 | |||
1852 | fn call_once(self, args: Args) -> Self::Output; | ||
1853 | } | ||
1854 | |||
1855 | struct Foo; | 1665 | struct Foo; |
1856 | 1666 | ||
1857 | impl Foo { | 1667 | impl Foo { |
@@ -1864,7 +1674,7 @@ impl<T, F> Lazy<T, F> { | |||
1864 | pub fn new(f: F) -> Lazy<T, F> {} | 1674 | pub fn new(f: F) -> Lazy<T, F> {} |
1865 | } | 1675 | } |
1866 | 1676 | ||
1867 | impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { | 1677 | impl<T, F: FnOnce() -> T> core::ops::Deref for Lazy<T, F> { |
1868 | type Target = T; | 1678 | type Target = T; |
1869 | } | 1679 | } |
1870 | 1680 | ||
@@ -1878,32 +1688,29 @@ fn test() { | |||
1878 | let r2 = lazy2.foo(); | 1688 | let r2 = lazy2.foo(); |
1879 | }"#, | 1689 | }"#, |
1880 | expect![[r#" | 1690 | expect![[r#" |
1881 | 64..68 'self': &Self | 1691 | 36..40 'self': &Foo |
1882 | 165..169 'self': Self | 1692 | 51..53 '{}': () |
1883 | 171..175 'args': Args | 1693 | 131..132 'f': F |
1884 | 239..243 'self': &Foo | 1694 | 151..153 '{}': () |
1885 | 254..256 '{}': () | 1695 | 251..497 '{ ...o(); }': () |
1886 | 334..335 'f': F | 1696 | 261..266 'lazy1': Lazy<Foo, || -> Foo> |
1887 | 354..356 '{}': () | 1697 | 283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> |
1888 | 443..689 '{ ...o(); }': () | 1698 | 283..300 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> |
1889 | 453..458 'lazy1': Lazy<Foo, || -> Foo> | 1699 | 293..299 '|| Foo': || -> Foo |
1890 | 475..484 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo> | 1700 | 296..299 'Foo': Foo |
1891 | 475..492 'Lazy::...| Foo)': Lazy<Foo, || -> Foo> | 1701 | 310..312 'r1': usize |
1892 | 485..491 '|| Foo': || -> Foo | 1702 | 315..320 'lazy1': Lazy<Foo, || -> Foo> |
1893 | 488..491 'Foo': Foo | 1703 | 315..326 'lazy1.foo()': usize |
1894 | 502..504 'r1': usize | 1704 | 368..383 'make_foo_fn_ptr': fn() -> Foo |
1895 | 507..512 'lazy1': Lazy<Foo, || -> Foo> | 1705 | 399..410 'make_foo_fn': fn make_foo_fn() -> Foo |
1896 | 507..518 'lazy1.foo()': usize | 1706 | 420..425 'lazy2': Lazy<Foo, fn() -> Foo> |
1897 | 560..575 'make_foo_fn_ptr': fn() -> Foo | 1707 | 442..451 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> |
1898 | 591..602 'make_foo_fn': fn make_foo_fn() -> Foo | 1708 | 442..468 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> |
1899 | 612..617 'lazy2': Lazy<Foo, fn() -> Foo> | 1709 | 452..467 'make_foo_fn_ptr': fn() -> Foo |
1900 | 634..643 'Lazy::new': fn new<Foo, fn() -> Foo>(fn() -> Foo) -> Lazy<Foo, fn() -> Foo> | 1710 | 478..480 'r2': usize |
1901 | 634..660 'Lazy::...n_ptr)': Lazy<Foo, fn() -> Foo> | 1711 | 483..488 'lazy2': Lazy<Foo, fn() -> Foo> |
1902 | 644..659 'make_foo_fn_ptr': fn() -> Foo | 1712 | 483..494 'lazy2.foo()': usize |
1903 | 670..672 'r2': usize | 1713 | 357..359 '{}': () |
1904 | 675..680 'lazy2': Lazy<Foo, fn() -> Foo> | ||
1905 | 675..686 'lazy2.foo()': usize | ||
1906 | 549..551 '{}': () | ||
1907 | "#]], | 1714 | "#]], |
1908 | ); | 1715 | ); |
1909 | } | 1716 | } |
@@ -1912,11 +1719,7 @@ fn test() { | |||
1912 | fn closure_1() { | 1719 | fn closure_1() { |
1913 | check_infer_with_mismatches( | 1720 | check_infer_with_mismatches( |
1914 | r#" | 1721 | r#" |
1915 | #[lang = "fn_once"] | 1722 | //- minicore: fn |
1916 | trait FnOnce<Args> { | ||
1917 | type Output; | ||
1918 | } | ||
1919 | |||
1920 | enum Option<T> { Some(T), None } | 1723 | enum Option<T> { Some(T), None } |
1921 | impl<T> Option<T> { | 1724 | impl<T> Option<T> { |
1922 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } | 1725 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } |
@@ -1929,34 +1732,34 @@ fn test() { | |||
1929 | let y: Option<i64> = x.map(|_v| 1); | 1732 | let y: Option<i64> = x.map(|_v| 1); |
1930 | }"#, | 1733 | }"#, |
1931 | expect![[r#" | 1734 | expect![[r#" |
1932 | 147..151 'self': Option<T> | 1735 | 86..90 'self': Option<T> |
1933 | 153..154 'f': F | 1736 | 92..93 'f': F |
1934 | 172..183 '{ loop {} }': Option<U> | 1737 | 111..122 '{ loop {} }': Option<U> |
1935 | 174..181 'loop {}': ! | 1738 | 113..120 'loop {}': ! |
1936 | 179..181 '{}': () | 1739 | 118..120 '{}': () |
1937 | 197..316 '{ ... 1); }': () | 1740 | 136..255 '{ ... 1); }': () |
1938 | 207..208 'x': Option<u32> | 1741 | 146..147 'x': Option<u32> |
1939 | 211..223 'Option::Some': Some<u32>(u32) -> Option<u32> | 1742 | 150..162 'Option::Some': Some<u32>(u32) -> Option<u32> |
1940 | 211..229 'Option...(1u32)': Option<u32> | 1743 | 150..168 'Option...(1u32)': Option<u32> |
1941 | 224..228 '1u32': u32 | 1744 | 163..167 '1u32': u32 |
1942 | 235..236 'x': Option<u32> | 1745 | 174..175 'x': Option<u32> |
1943 | 235..251 'x.map(...v + 1)': Option<u32> | 1746 | 174..190 'x.map(...v + 1)': Option<u32> |
1944 | 241..250 '|v| v + 1': |u32| -> u32 | 1747 | 180..189 '|v| v + 1': |u32| -> u32 |
1945 | 242..243 'v': u32 | 1748 | 181..182 'v': u32 |
1946 | 245..246 'v': u32 | 1749 | 184..185 'v': u32 |
1947 | 245..250 'v + 1': u32 | 1750 | 184..189 'v + 1': u32 |
1948 | 249..250 '1': u32 | 1751 | 188..189 '1': u32 |
1949 | 257..258 'x': Option<u32> | 1752 | 196..197 'x': Option<u32> |
1950 | 257..273 'x.map(... 1u64)': Option<u64> | 1753 | 196..212 'x.map(... 1u64)': Option<u64> |
1951 | 263..272 '|_v| 1u64': |u32| -> u64 | 1754 | 202..211 '|_v| 1u64': |u32| -> u64 |
1952 | 264..266 '_v': u32 | 1755 | 203..205 '_v': u32 |
1953 | 268..272 '1u64': u64 | 1756 | 207..211 '1u64': u64 |
1954 | 283..284 'y': Option<i64> | 1757 | 222..223 'y': Option<i64> |
1955 | 300..301 'x': Option<u32> | 1758 | 239..240 'x': Option<u32> |
1956 | 300..313 'x.map(|_v| 1)': Option<i64> | 1759 | 239..252 'x.map(|_v| 1)': Option<i64> |
1957 | 306..312 '|_v| 1': |u32| -> i64 | 1760 | 245..251 '|_v| 1': |u32| -> i64 |
1958 | 307..309 '_v': u32 | 1761 | 246..248 '_v': u32 |
1959 | 311..312 '1': i64 | 1762 | 250..251 '1': i64 |
1960 | "#]], | 1763 | "#]], |
1961 | ); | 1764 | ); |
1962 | } | 1765 | } |
@@ -2030,11 +1833,7 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
2030 | fn closure_as_argument_inference_order() { | 1833 | fn closure_as_argument_inference_order() { |
2031 | check_infer_with_mismatches( | 1834 | check_infer_with_mismatches( |
2032 | r#" | 1835 | r#" |
2033 | #[lang = "fn_once"] | 1836 | //- minicore: fn |
2034 | trait FnOnce<Args> { | ||
2035 | type Output; | ||
2036 | } | ||
2037 | |||
2038 | fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } | 1837 | fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } |
2039 | fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } | 1838 | fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } |
2040 | 1839 | ||
@@ -2053,62 +1852,62 @@ fn test() { | |||
2053 | let x4 = S.foo2(|s| s.method(), S); | 1852 | let x4 = S.foo2(|s| s.method(), S); |
2054 | }"#, | 1853 | }"#, |
2055 | expect![[r#" | 1854 | expect![[r#" |
2056 | 94..95 'x': T | 1855 | 33..34 'x': T |
2057 | 100..101 'f': F | 1856 | 39..40 'f': F |
2058 | 111..122 '{ loop {} }': U | 1857 | 50..61 '{ loop {} }': U |
2059 | 113..120 'loop {}': ! | 1858 | 52..59 'loop {}': ! |
2060 | 118..120 '{}': () | 1859 | 57..59 '{}': () |
2061 | 156..157 'f': F | 1860 | 95..96 'f': F |
2062 | 162..163 'x': T | 1861 | 101..102 'x': T |
2063 | 173..184 '{ loop {} }': U | 1862 | 112..123 '{ loop {} }': U |
2064 | 175..182 'loop {}': ! | 1863 | 114..121 'loop {}': ! |
2065 | 180..182 '{}': () | 1864 | 119..121 '{}': () |
2066 | 219..223 'self': S | 1865 | 158..162 'self': S |
2067 | 271..275 'self': S | 1866 | 210..214 'self': S |
2068 | 277..278 'x': T | 1867 | 216..217 'x': T |
2069 | 283..284 'f': F | 1868 | 222..223 'f': F |
2070 | 294..305 '{ loop {} }': U | 1869 | 233..244 '{ loop {} }': U |
2071 | 296..303 'loop {}': ! | 1870 | 235..242 'loop {}': ! |
2072 | 301..303 '{}': () | 1871 | 240..242 '{}': () |
2073 | 343..347 'self': S | 1872 | 282..286 'self': S |
2074 | 349..350 'f': F | 1873 | 288..289 'f': F |
2075 | 355..356 'x': T | 1874 | 294..295 'x': T |
2076 | 366..377 '{ loop {} }': U | 1875 | 305..316 '{ loop {} }': U |
2077 | 368..375 'loop {}': ! | 1876 | 307..314 'loop {}': ! |
2078 | 373..375 '{}': () | 1877 | 312..314 '{}': () |
2079 | 391..550 '{ ... S); }': () | 1878 | 330..489 '{ ... S); }': () |
2080 | 401..403 'x1': u64 | 1879 | 340..342 'x1': u64 |
2081 | 406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 | 1880 | 345..349 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64 |
2082 | 406..429 'foo1(S...hod())': u64 | 1881 | 345..368 'foo1(S...hod())': u64 |
2083 | 411..412 'S': S | 1882 | 350..351 'S': S |
2084 | 414..428 '|s| s.method()': |S| -> u64 | 1883 | 353..367 '|s| s.method()': |S| -> u64 |
2085 | 415..416 's': S | 1884 | 354..355 's': S |
2086 | 418..419 's': S | 1885 | 357..358 's': S |
2087 | 418..428 's.method()': u64 | 1886 | 357..367 's.method()': u64 |
2088 | 439..441 'x2': u64 | 1887 | 378..380 'x2': u64 |
2089 | 444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 | 1888 | 383..387 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64 |
2090 | 444..467 'foo2(|...(), S)': u64 | 1889 | 383..406 'foo2(|...(), S)': u64 |
2091 | 449..463 '|s| s.method()': |S| -> u64 | 1890 | 388..402 '|s| s.method()': |S| -> u64 |
2092 | 450..451 's': S | 1891 | 389..390 's': S |
2093 | 453..454 's': S | 1892 | 392..393 's': S |
2094 | 453..463 's.method()': u64 | 1893 | 392..402 's.method()': u64 |
2095 | 465..466 'S': S | 1894 | 404..405 'S': S |
2096 | 477..479 'x3': u64 | 1895 | 416..418 'x3': u64 |
2097 | 482..483 'S': S | 1896 | 421..422 'S': S |
2098 | 482..507 'S.foo1...hod())': u64 | 1897 | 421..446 'S.foo1...hod())': u64 |
2099 | 489..490 'S': S | 1898 | 428..429 'S': S |
2100 | 492..506 '|s| s.method()': |S| -> u64 | 1899 | 431..445 '|s| s.method()': |S| -> u64 |
2101 | 493..494 's': S | 1900 | 432..433 's': S |
2102 | 496..497 's': S | 1901 | 435..436 's': S |
2103 | 496..506 's.method()': u64 | 1902 | 435..445 's.method()': u64 |
2104 | 517..519 'x4': u64 | 1903 | 456..458 'x4': u64 |
2105 | 522..523 'S': S | 1904 | 461..462 'S': S |
2106 | 522..547 'S.foo2...(), S)': u64 | 1905 | 461..486 'S.foo2...(), S)': u64 |
2107 | 529..543 '|s| s.method()': |S| -> u64 | 1906 | 468..482 '|s| s.method()': |S| -> u64 |
2108 | 530..531 's': S | 1907 | 469..470 's': S |
2109 | 533..534 's': S | 1908 | 472..473 's': S |
2110 | 533..543 's.method()': u64 | 1909 | 472..482 's.method()': u64 |
2111 | 545..546 'S': S | 1910 | 484..485 'S': S |
2112 | "#]], | 1911 | "#]], |
2113 | ); | 1912 | ); |
2114 | } | 1913 | } |
@@ -2117,14 +1916,10 @@ fn test() { | |||
2117 | fn fn_item_fn_trait() { | 1916 | fn fn_item_fn_trait() { |
2118 | check_types( | 1917 | check_types( |
2119 | r#" | 1918 | r#" |
2120 | #[lang = "fn_once"] | 1919 | //- minicore: fn |
2121 | trait FnOnce<Args> { | ||
2122 | type Output; | ||
2123 | } | ||
2124 | |||
2125 | struct S; | 1920 | struct S; |
2126 | 1921 | ||
2127 | fn foo() -> S {} | 1922 | fn foo() -> S { S } |
2128 | 1923 | ||
2129 | fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } | 1924 | fn takes_closure<U, F: FnOnce() -> U>(f: F) -> U { f() } |
2130 | 1925 | ||
@@ -2151,7 +1946,7 @@ trait Trait2 { | |||
2151 | fn test<T: Trait>() where T::Item: Trait2 { | 1946 | fn test<T: Trait>() where T::Item: Trait2 { |
2152 | let x: T::Item = no_matter; | 1947 | let x: T::Item = no_matter; |
2153 | x.foo(); | 1948 | x.foo(); |
2154 | } //^ u32 | 1949 | } //^^^^^^^ u32 |
2155 | "#, | 1950 | "#, |
2156 | ); | 1951 | ); |
2157 | } | 1952 | } |
@@ -2171,7 +1966,7 @@ trait Trait2 { | |||
2171 | fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | 1966 | fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { |
2172 | let x: T::Item = no_matter; | 1967 | let x: T::Item = no_matter; |
2173 | x.foo(); | 1968 | x.foo(); |
2174 | } //^ u32 | 1969 | } //^^^^^^^ u32 |
2175 | "#, | 1970 | "#, |
2176 | ); | 1971 | ); |
2177 | } | 1972 | } |
@@ -2234,7 +2029,7 @@ impl Trait for S { | |||
2234 | 2029 | ||
2235 | fn test() { | 2030 | fn test() { |
2236 | S.f(); | 2031 | S.f(); |
2237 | } //^ u32 | 2032 | } //^^^^^ u32 |
2238 | "#, | 2033 | "#, |
2239 | ); | 2034 | ); |
2240 | } | 2035 | } |
@@ -2262,7 +2057,7 @@ where | |||
2262 | 2057 | ||
2263 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { | 2058 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { |
2264 | fold(interner, t); | 2059 | fold(interner, t); |
2265 | } //^ Ty<I> | 2060 | } //^^^^^^^^^^^^^^^^^ Ty<I> |
2266 | "#, | 2061 | "#, |
2267 | ); | 2062 | ); |
2268 | } | 2063 | } |
@@ -2281,7 +2076,7 @@ impl Trait<Self> for S {} | |||
2281 | 2076 | ||
2282 | fn test() { | 2077 | fn test() { |
2283 | S.foo(); | 2078 | S.foo(); |
2284 | } //^ () | 2079 | } //^^^^^^^ () |
2285 | "#, | 2080 | "#, |
2286 | ); | 2081 | ); |
2287 | } | 2082 | } |
@@ -2300,7 +2095,7 @@ impl Trait for S<Self> {} | |||
2300 | 2095 | ||
2301 | fn test() { | 2096 | fn test() { |
2302 | S.foo(); | 2097 | S.foo(); |
2303 | } //^ {unknown} | 2098 | } //^^^^^^^ {unknown} |
2304 | "#, | 2099 | "#, |
2305 | ); | 2100 | ); |
2306 | } | 2101 | } |
@@ -2318,7 +2113,7 @@ trait Trait2<T> {} | |||
2318 | 2113 | ||
2319 | fn test<T: Trait>() where T: Trait2<T::Item> { | 2114 | fn test<T: Trait>() where T: Trait2<T::Item> { |
2320 | let x: T::Item = no_matter; | 2115 | let x: T::Item = no_matter; |
2321 | } //^ {unknown} | 2116 | } //^^^^^^^^^ {unknown} |
2322 | "#, | 2117 | "#, |
2323 | ); | 2118 | ); |
2324 | } | 2119 | } |
@@ -2335,7 +2130,7 @@ trait Trait<T> { | |||
2335 | 2130 | ||
2336 | fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | 2131 | fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { |
2337 | let x: T::Item = no_matter; | 2132 | let x: T::Item = no_matter; |
2338 | } //^ {unknown} | 2133 | } //^^^^^^^^^ {unknown} |
2339 | "#, | 2134 | "#, |
2340 | ); | 2135 | ); |
2341 | } | 2136 | } |
@@ -2353,7 +2148,7 @@ trait Trait { | |||
2353 | 2148 | ||
2354 | fn test<T>() where T: Trait<OtherItem = T::Item> { | 2149 | fn test<T>() where T: Trait<OtherItem = T::Item> { |
2355 | let x: T::Item = no_matter; | 2150 | let x: T::Item = no_matter; |
2356 | } //^ Trait::Item<T> | 2151 | } //^^^^^^^^^ Trait::Item<T> |
2357 | "#, | 2152 | "#, |
2358 | ); | 2153 | ); |
2359 | } | 2154 | } |
@@ -2385,7 +2180,7 @@ fn test<T>(t: T) where T: UnificationStoreMut { | |||
2385 | t.push(x); | 2180 | t.push(x); |
2386 | let y: Key<T>; | 2181 | let y: Key<T>; |
2387 | (x, y); | 2182 | (x, y); |
2388 | } //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) | 2183 | } //^^^^^^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) |
2389 | "#, | 2184 | "#, |
2390 | ); | 2185 | ); |
2391 | } | 2186 | } |
@@ -2410,7 +2205,7 @@ impl<T: Iterator> Iterator for S<T> { | |||
2410 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { | 2205 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { |
2411 | let x: <S<I> as Iterator>::Item; | 2206 | let x: <S<I> as Iterator>::Item; |
2412 | x.foo(); | 2207 | x.foo(); |
2413 | } //^ u32 | 2208 | } //^^^^^^^ u32 |
2414 | "#, | 2209 | "#, |
2415 | ); | 2210 | ); |
2416 | } | 2211 | } |
@@ -2560,12 +2355,7 @@ fn test() -> impl Trait<i32> { | |||
2560 | fn assoc_types_from_bounds() { | 2355 | fn assoc_types_from_bounds() { |
2561 | check_infer( | 2356 | check_infer( |
2562 | r#" | 2357 | r#" |
2563 | //- /main.rs | 2358 | //- minicore: fn |
2564 | #[lang = "fn_once"] | ||
2565 | trait FnOnce<Args> { | ||
2566 | type Output; | ||
2567 | } | ||
2568 | |||
2569 | trait T { | 2359 | trait T { |
2570 | type O; | 2360 | type O; |
2571 | } | 2361 | } |
@@ -2584,15 +2374,15 @@ fn main() { | |||
2584 | f::<(), _>(|z| { z; }); | 2374 | f::<(), _>(|z| { z; }); |
2585 | }"#, | 2375 | }"#, |
2586 | expect![[r#" | 2376 | expect![[r#" |
2587 | 133..135 '_v': F | 2377 | 72..74 '_v': F |
2588 | 178..181 '{ }': () | 2378 | 117..120 '{ }': () |
2589 | 193..224 '{ ... }); }': () | 2379 | 132..163 '{ ... }); }': () |
2590 | 199..209 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) | 2380 | 138..148 'f::<(), _>': fn f<(), |&()| -> ()>(|&()| -> ()) |
2591 | 199..221 'f::<()... z; })': () | 2381 | 138..160 'f::<()... z; })': () |
2592 | 210..220 '|z| { z; }': |&()| -> () | 2382 | 149..159 '|z| { z; }': |&()| -> () |
2593 | 211..212 'z': &() | 2383 | 150..151 'z': &() |
2594 | 214..220 '{ z; }': () | 2384 | 153..159 '{ z; }': () |
2595 | 216..217 'z': &() | 2385 | 155..156 'z': &() |
2596 | "#]], | 2386 | "#]], |
2597 | ); | 2387 | ); |
2598 | } | 2388 | } |
@@ -2617,7 +2407,7 @@ impl<T: Trait> Trait for S<T> { | |||
2617 | fn test<T: Trait>() { | 2407 | fn test<T: Trait>() { |
2618 | let y: <S<T> as Trait>::Item = no_matter; | 2408 | let y: <S<T> as Trait>::Item = no_matter; |
2619 | y.foo(); | 2409 | y.foo(); |
2620 | } //^ u32 | 2410 | } //^^^^^^^ u32 |
2621 | "#, | 2411 | "#, |
2622 | ); | 2412 | ); |
2623 | } | 2413 | } |
@@ -2626,12 +2416,9 @@ fn test<T: Trait>() { | |||
2626 | fn dyn_trait_through_chalk() { | 2416 | fn dyn_trait_through_chalk() { |
2627 | check_types( | 2417 | check_types( |
2628 | r#" | 2418 | r#" |
2419 | //- minicore: deref | ||
2629 | struct Box<T> {} | 2420 | struct Box<T> {} |
2630 | #[lang = "deref"] | 2421 | impl<T> core::ops::Deref for Box<T> { |
2631 | trait Deref { | ||
2632 | type Target; | ||
2633 | } | ||
2634 | impl<T> Deref for Box<T> { | ||
2635 | type Target = T; | 2422 | type Target = T; |
2636 | } | 2423 | } |
2637 | trait Trait { | 2424 | trait Trait { |
@@ -2640,7 +2427,7 @@ trait Trait { | |||
2640 | 2427 | ||
2641 | fn test(x: Box<dyn Trait>) { | 2428 | fn test(x: Box<dyn Trait>) { |
2642 | x.foo(); | 2429 | x.foo(); |
2643 | } //^ () | 2430 | } //^^^^^^^ () |
2644 | "#, | 2431 | "#, |
2645 | ); | 2432 | ); |
2646 | } | 2433 | } |
@@ -2659,7 +2446,7 @@ impl ToOwned for str { | |||
2659 | } | 2446 | } |
2660 | fn test() { | 2447 | fn test() { |
2661 | "foo".to_owned(); | 2448 | "foo".to_owned(); |
2662 | } //^ String | 2449 | } //^^^^^^^^^^^^^^^^ String |
2663 | "#, | 2450 | "#, |
2664 | ); | 2451 | ); |
2665 | } | 2452 | } |
@@ -2668,17 +2455,7 @@ fn test() { | |||
2668 | fn iterator_chain() { | 2455 | fn iterator_chain() { |
2669 | check_infer_with_mismatches( | 2456 | check_infer_with_mismatches( |
2670 | r#" | 2457 | r#" |
2671 | //- /main.rs | 2458 | //- minicore: fn, option |
2672 | #[lang = "fn_once"] | ||
2673 | trait FnOnce<Args> { | ||
2674 | type Output; | ||
2675 | } | ||
2676 | #[lang = "fn_mut"] | ||
2677 | trait FnMut<Args>: FnOnce<Args> { } | ||
2678 | |||
2679 | enum Option<T> { Some(T), None } | ||
2680 | use Option::*; | ||
2681 | |||
2682 | pub trait Iterator { | 2459 | pub trait Iterator { |
2683 | type Item; | 2460 | type Item; |
2684 | 2461 | ||
@@ -2738,46 +2515,46 @@ fn main() { | |||
2738 | .for_each(|y| { y; }); | 2515 | .for_each(|y| { y; }); |
2739 | }"#, | 2516 | }"#, |
2740 | expect![[r#" | 2517 | expect![[r#" |
2741 | 226..230 'self': Self | 2518 | 61..65 'self': Self |
2742 | 232..233 'f': F | 2519 | 67..68 'f': F |
2743 | 317..328 '{ loop {} }': FilterMap<Self, F> | 2520 | 152..163 '{ loop {} }': FilterMap<Self, F> |
2744 | 319..326 'loop {}': ! | 2521 | 154..161 'loop {}': ! |
2745 | 324..326 '{}': () | 2522 | 159..161 '{}': () |
2746 | 349..353 'self': Self | 2523 | 184..188 'self': Self |
2747 | 355..356 'f': F | 2524 | 190..191 'f': F |
2748 | 405..416 '{ loop {} }': () | 2525 | 240..251 '{ loop {} }': () |
2749 | 407..414 'loop {}': ! | 2526 | 242..249 'loop {}': ! |
2750 | 412..414 '{}': () | 2527 | 247..249 '{}': () |
2751 | 525..529 'self': Self | 2528 | 360..364 'self': Self |
2752 | 854..858 'self': I | 2529 | 689..693 'self': I |
2753 | 865..885 '{ ... }': I | 2530 | 700..720 '{ ... }': I |
2754 | 875..879 'self': I | 2531 | 710..714 'self': I |
2755 | 944..955 '{ loop {} }': Vec<T> | 2532 | 779..790 '{ loop {} }': Vec<T> |
2756 | 946..953 'loop {}': ! | 2533 | 781..788 'loop {}': ! |
2757 | 951..953 '{}': () | 2534 | 786..788 '{}': () |
2758 | 1142..1269 '{ ... }); }': () | 2535 | 977..1104 '{ ... }); }': () |
2759 | 1148..1163 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> | 2536 | 983..998 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> |
2760 | 1148..1165 'Vec::<...:new()': Vec<i32> | 2537 | 983..1000 'Vec::<...:new()': Vec<i32> |
2761 | 1148..1177 'Vec::<...iter()': IntoIter<i32> | 2538 | 983..1012 'Vec::<...iter()': IntoIter<i32> |
2762 | 1148..1240 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> | 2539 | 983..1075 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> |
2763 | 1148..1266 'Vec::<... y; })': () | 2540 | 983..1101 'Vec::<... y; })': () |
2764 | 1194..1239 '|x| if...None }': |i32| -> Option<u32> | 2541 | 1029..1074 '|x| if...None }': |i32| -> Option<u32> |
2765 | 1195..1196 'x': i32 | 2542 | 1030..1031 'x': i32 |
2766 | 1198..1239 'if x >...None }': Option<u32> | 2543 | 1033..1074 'if x >...None }': Option<u32> |
2767 | 1201..1202 'x': i32 | 2544 | 1036..1037 'x': i32 |
2768 | 1201..1206 'x > 0': bool | 2545 | 1036..1041 'x > 0': bool |
2769 | 1205..1206 '0': i32 | 2546 | 1040..1041 '0': i32 |
2770 | 1207..1225 '{ Some...u32) }': Option<u32> | 2547 | 1042..1060 '{ Some...u32) }': Option<u32> |
2771 | 1209..1213 'Some': Some<u32>(u32) -> Option<u32> | 2548 | 1044..1048 'Some': Some<u32>(u32) -> Option<u32> |
2772 | 1209..1223 'Some(x as u32)': Option<u32> | 2549 | 1044..1058 'Some(x as u32)': Option<u32> |
2773 | 1214..1215 'x': i32 | 2550 | 1049..1050 'x': i32 |
2774 | 1214..1222 'x as u32': u32 | 2551 | 1049..1057 'x as u32': u32 |
2775 | 1231..1239 '{ None }': Option<u32> | 2552 | 1066..1074 '{ None }': Option<u32> |
2776 | 1233..1237 'None': Option<u32> | 2553 | 1068..1072 'None': Option<u32> |
2777 | 1255..1265 '|y| { y; }': |u32| -> () | 2554 | 1090..1100 '|y| { y; }': |u32| -> () |
2778 | 1256..1257 'y': u32 | 2555 | 1091..1092 'y': u32 |
2779 | 1259..1265 '{ y; }': () | 2556 | 1094..1100 '{ y; }': () |
2780 | 1261..1262 'y': u32 | 2557 | 1096..1097 'y': u32 |
2781 | "#]], | 2558 | "#]], |
2782 | ); | 2559 | ); |
2783 | } | 2560 | } |
@@ -2809,7 +2586,7 @@ impl<T:A> B for T { | |||
2809 | 2586 | ||
2810 | fn main() { | 2587 | fn main() { |
2811 | Bar::foo(); | 2588 | Bar::foo(); |
2812 | } //^ Foo | 2589 | } //^^^^^^^^^^ Foo |
2813 | "#, | 2590 | "#, |
2814 | ); | 2591 | ); |
2815 | } | 2592 | } |
@@ -2841,9 +2618,7 @@ fn test(x: &dyn Foo) { | |||
2841 | fn builtin_copy() { | 2618 | fn builtin_copy() { |
2842 | check_infer_with_mismatches( | 2619 | check_infer_with_mismatches( |
2843 | r#" | 2620 | r#" |
2844 | #[lang = "copy"] | 2621 | //- minicore: copy |
2845 | trait Copy {} | ||
2846 | |||
2847 | struct IsCopy; | 2622 | struct IsCopy; |
2848 | impl Copy for IsCopy {} | 2623 | impl Copy for IsCopy {} |
2849 | struct NotCopy; | 2624 | struct NotCopy; |
@@ -2858,20 +2633,20 @@ fn test() { | |||
2858 | (IsCopy, NotCopy).test(); | 2633 | (IsCopy, NotCopy).test(); |
2859 | }"#, | 2634 | }"#, |
2860 | expect![[r#" | 2635 | expect![[r#" |
2861 | 110..114 'self': &Self | 2636 | 78..82 'self': &Self |
2862 | 166..267 '{ ...t(); }': () | 2637 | 134..235 '{ ...t(); }': () |
2863 | 172..178 'IsCopy': IsCopy | 2638 | 140..146 'IsCopy': IsCopy |
2864 | 172..185 'IsCopy.test()': bool | 2639 | 140..153 'IsCopy.test()': bool |
2865 | 191..198 'NotCopy': NotCopy | 2640 | 159..166 'NotCopy': NotCopy |
2866 | 191..205 'NotCopy.test()': {unknown} | 2641 | 159..173 'NotCopy.test()': {unknown} |
2867 | 211..227 '(IsCop...sCopy)': (IsCopy, IsCopy) | 2642 | 179..195 '(IsCop...sCopy)': (IsCopy, IsCopy) |
2868 | 211..234 '(IsCop...test()': bool | 2643 | 179..202 '(IsCop...test()': bool |
2869 | 212..218 'IsCopy': IsCopy | 2644 | 180..186 'IsCopy': IsCopy |
2870 | 220..226 'IsCopy': IsCopy | 2645 | 188..194 'IsCopy': IsCopy |
2871 | 240..257 '(IsCop...tCopy)': (IsCopy, NotCopy) | 2646 | 208..225 '(IsCop...tCopy)': (IsCopy, NotCopy) |
2872 | 240..264 '(IsCop...test()': {unknown} | 2647 | 208..232 '(IsCop...test()': {unknown} |
2873 | 241..247 'IsCopy': IsCopy | 2648 | 209..215 'IsCopy': IsCopy |
2874 | 249..256 'NotCopy': NotCopy | 2649 | 217..224 'NotCopy': NotCopy |
2875 | "#]], | 2650 | "#]], |
2876 | ); | 2651 | ); |
2877 | } | 2652 | } |
@@ -2880,9 +2655,7 @@ fn test() { | |||
2880 | fn builtin_fn_def_copy() { | 2655 | fn builtin_fn_def_copy() { |
2881 | check_infer_with_mismatches( | 2656 | check_infer_with_mismatches( |
2882 | r#" | 2657 | r#" |
2883 | #[lang = "copy"] | 2658 | //- minicore: copy |
2884 | trait Copy {} | ||
2885 | |||
2886 | fn foo() {} | 2659 | fn foo() {} |
2887 | fn bar<T: Copy>(T) -> T {} | 2660 | fn bar<T: Copy>(T) -> T {} |
2888 | struct Struct(usize); | 2661 | struct Struct(usize); |
@@ -2898,20 +2671,20 @@ fn test() { | |||
2898 | Enum::Variant.test(); | 2671 | Enum::Variant.test(); |
2899 | }"#, | 2672 | }"#, |
2900 | expect![[r#" | 2673 | expect![[r#" |
2901 | 41..43 '{}': () | 2674 | 9..11 '{}': () |
2902 | 60..61 'T': {unknown} | 2675 | 28..29 'T': {unknown} |
2903 | 68..70 '{}': () | 2676 | 36..38 '{}': () |
2904 | 68..70: expected T, got () | 2677 | 36..38: expected T, got () |
2905 | 145..149 'self': &Self | 2678 | 113..117 'self': &Self |
2906 | 201..281 '{ ...t(); }': () | 2679 | 169..249 '{ ...t(); }': () |
2907 | 207..210 'foo': fn foo() | 2680 | 175..178 'foo': fn foo() |
2908 | 207..217 'foo.test()': bool | 2681 | 175..185 'foo.test()': bool |
2909 | 223..226 'bar': fn bar<{unknown}>({unknown}) -> {unknown} | 2682 | 191..194 'bar': fn bar<{unknown}>({unknown}) -> {unknown} |
2910 | 223..233 'bar.test()': bool | 2683 | 191..201 'bar.test()': bool |
2911 | 239..245 'Struct': Struct(usize) -> Struct | 2684 | 207..213 'Struct': Struct(usize) -> Struct |
2912 | 239..252 'Struct.test()': bool | 2685 | 207..220 'Struct.test()': bool |
2913 | 258..271 'Enum::Variant': Variant(usize) -> Enum | 2686 | 226..239 'Enum::Variant': Variant(usize) -> Enum |
2914 | 258..278 'Enum::...test()': bool | 2687 | 226..246 'Enum::...test()': bool |
2915 | "#]], | 2688 | "#]], |
2916 | ); | 2689 | ); |
2917 | } | 2690 | } |
@@ -2920,9 +2693,7 @@ fn test() { | |||
2920 | fn builtin_fn_ptr_copy() { | 2693 | fn builtin_fn_ptr_copy() { |
2921 | check_infer_with_mismatches( | 2694 | check_infer_with_mismatches( |
2922 | r#" | 2695 | r#" |
2923 | #[lang = "copy"] | 2696 | //- minicore: copy |
2924 | trait Copy {} | ||
2925 | |||
2926 | trait Test { fn test(&self) -> bool; } | 2697 | trait Test { fn test(&self) -> bool; } |
2927 | impl<T: Copy> Test for T {} | 2698 | impl<T: Copy> Test for T {} |
2928 | 2699 | ||
@@ -2932,17 +2703,17 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | |||
2932 | f3.test(); | 2703 | f3.test(); |
2933 | }"#, | 2704 | }"#, |
2934 | expect![[r#" | 2705 | expect![[r#" |
2935 | 54..58 'self': &Self | 2706 | 22..26 'self': &Self |
2936 | 108..110 'f1': fn() | 2707 | 76..78 'f1': fn() |
2937 | 118..120 'f2': fn(usize) -> u8 | 2708 | 86..88 'f2': fn(usize) -> u8 |
2938 | 139..141 'f3': fn(u8, u8) -> &u8 | 2709 | 107..109 'f3': fn(u8, u8) -> &u8 |
2939 | 162..210 '{ ...t(); }': () | 2710 | 130..178 '{ ...t(); }': () |
2940 | 168..170 'f1': fn() | 2711 | 136..138 'f1': fn() |
2941 | 168..177 'f1.test()': bool | 2712 | 136..145 'f1.test()': bool |
2942 | 183..185 'f2': fn(usize) -> u8 | 2713 | 151..153 'f2': fn(usize) -> u8 |
2943 | 183..192 'f2.test()': bool | 2714 | 151..160 'f2.test()': bool |
2944 | 198..200 'f3': fn(u8, u8) -> &u8 | 2715 | 166..168 'f3': fn(u8, u8) -> &u8 |
2945 | 198..207 'f3.test()': bool | 2716 | 166..175 'f3.test()': bool |
2946 | "#]], | 2717 | "#]], |
2947 | ); | 2718 | ); |
2948 | } | 2719 | } |
@@ -2951,9 +2722,7 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | |||
2951 | fn builtin_sized() { | 2722 | fn builtin_sized() { |
2952 | check_infer_with_mismatches( | 2723 | check_infer_with_mismatches( |
2953 | r#" | 2724 | r#" |
2954 | #[lang = "sized"] | 2725 | //- minicore: sized |
2955 | trait Sized {} | ||
2956 | |||
2957 | trait Test { fn test(&self) -> bool; } | 2726 | trait Test { fn test(&self) -> bool; } |
2958 | impl<T: Sized> Test for T {} | 2727 | impl<T: Sized> Test for T {} |
2959 | 2728 | ||
@@ -2964,22 +2733,22 @@ fn test() { | |||
2964 | (1u8, *"foo").test(); // not Sized | 2733 | (1u8, *"foo").test(); // not Sized |
2965 | }"#, | 2734 | }"#, |
2966 | expect![[r#" | 2735 | expect![[r#" |
2967 | 56..60 'self': &Self | 2736 | 22..26 'self': &Self |
2968 | 113..228 '{ ...ized }': () | 2737 | 79..194 '{ ...ized }': () |
2969 | 119..122 '1u8': u8 | 2738 | 85..88 '1u8': u8 |
2970 | 119..129 '1u8.test()': bool | 2739 | 85..95 '1u8.test()': bool |
2971 | 135..150 '(*"foo").test()': {unknown} | 2740 | 101..116 '(*"foo").test()': {unknown} |
2972 | 136..142 '*"foo"': str | 2741 | 102..108 '*"foo"': str |
2973 | 137..142 '"foo"': &str | 2742 | 103..108 '"foo"': &str |
2974 | 169..179 '(1u8, 1u8)': (u8, u8) | 2743 | 135..145 '(1u8, 1u8)': (u8, u8) |
2975 | 169..186 '(1u8, ...test()': bool | 2744 | 135..152 '(1u8, ...test()': bool |
2976 | 170..173 '1u8': u8 | 2745 | 136..139 '1u8': u8 |
2977 | 175..178 '1u8': u8 | 2746 | 141..144 '1u8': u8 |
2978 | 192..205 '(1u8, *"foo")': (u8, str) | 2747 | 158..171 '(1u8, *"foo")': (u8, str) |
2979 | 192..212 '(1u8, ...test()': {unknown} | 2748 | 158..178 '(1u8, ...test()': {unknown} |
2980 | 193..196 '1u8': u8 | 2749 | 159..162 '1u8': u8 |
2981 | 198..204 '*"foo"': str | 2750 | 164..170 '*"foo"': str |
2982 | 199..204 '"foo"': &str | 2751 | 165..170 '"foo"': &str |
2983 | "#]], | 2752 | "#]], |
2984 | ); | 2753 | ); |
2985 | } | 2754 | } |
@@ -3064,45 +2833,23 @@ fn foo() { | |||
3064 | fn infer_fn_trait_arg() { | 2833 | fn infer_fn_trait_arg() { |
3065 | check_infer_with_mismatches( | 2834 | check_infer_with_mismatches( |
3066 | r#" | 2835 | r#" |
3067 | //- /lib.rs deps:std | 2836 | //- minicore: fn, option |
3068 | 2837 | fn foo<F, T>(f: F) -> T | |
3069 | #[lang = "fn_once"] | 2838 | where |
3070 | pub trait FnOnce<Args> { | 2839 | F: Fn(Option<i32>) -> T, |
3071 | type Output; | 2840 | { |
3072 | 2841 | let s = None; | |
3073 | extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; | 2842 | f(s) |
3074 | } | 2843 | } |
3075 | 2844 | "#, | |
3076 | #[lang = "fn"] | ||
3077 | pub trait Fn<Args>:FnOnce<Args> { | ||
3078 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
3079 | } | ||
3080 | |||
3081 | enum Option<T> { | ||
3082 | None, | ||
3083 | Some(T) | ||
3084 | } | ||
3085 | |||
3086 | fn foo<F, T>(f: F) -> T | ||
3087 | where | ||
3088 | F: Fn(Option<i32>) -> T, | ||
3089 | { | ||
3090 | let s = None; | ||
3091 | f(s) | ||
3092 | } | ||
3093 | "#, | ||
3094 | expect![[r#" | 2845 | expect![[r#" |
3095 | 101..105 'self': &Self | 2846 | 13..14 'f': F |
3096 | 107..111 'args': Args | 2847 | 59..89 '{ ...f(s) }': T |
3097 | 220..224 'self': &Self | 2848 | 69..70 's': Option<i32> |
3098 | 226..230 'args': Args | 2849 | 73..77 'None': Option<i32> |
3099 | 313..314 'f': F | 2850 | 83..84 'f': F |
3100 | 359..389 '{ ...f(s) }': T | 2851 | 83..87 'f(s)': T |
3101 | 369..370 's': Option<i32> | 2852 | 85..86 's': Option<i32> |
3102 | 373..377 'None': Option<i32> | ||
3103 | 383..384 'f': F | ||
3104 | 383..387 'f(s)': T | ||
3105 | 385..386 's': Option<i32> | ||
3106 | "#]], | 2853 | "#]], |
3107 | ); | 2854 | ); |
3108 | } | 2855 | } |
@@ -3112,28 +2859,13 @@ fn infer_box_fn_arg() { | |||
3112 | // The type mismatch is because we don't define Unsize and CoerceUnsized | 2859 | // The type mismatch is because we don't define Unsize and CoerceUnsized |
3113 | check_infer_with_mismatches( | 2860 | check_infer_with_mismatches( |
3114 | r#" | 2861 | r#" |
3115 | //- /lib.rs deps:std | 2862 | //- minicore: fn, deref, option |
3116 | |||
3117 | #[lang = "fn_once"] | ||
3118 | pub trait FnOnce<Args> { | ||
3119 | type Output; | ||
3120 | |||
3121 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3122 | } | ||
3123 | |||
3124 | #[lang = "deref"] | ||
3125 | pub trait Deref { | ||
3126 | type Target: ?Sized; | ||
3127 | |||
3128 | fn deref(&self) -> &Self::Target; | ||
3129 | } | ||
3130 | |||
3131 | #[lang = "owned_box"] | 2863 | #[lang = "owned_box"] |
3132 | pub struct Box<T: ?Sized> { | 2864 | pub struct Box<T: ?Sized> { |
3133 | inner: *mut T, | 2865 | inner: *mut T, |
3134 | } | 2866 | } |
3135 | 2867 | ||
3136 | impl<T: ?Sized> Deref for Box<T> { | 2868 | impl<T: ?Sized> core::ops::Deref for Box<T> { |
3137 | type Target = T; | 2869 | type Target = T; |
3138 | 2870 | ||
3139 | fn deref(&self) -> &T { | 2871 | fn deref(&self) -> &T { |
@@ -3141,38 +2873,30 @@ impl<T: ?Sized> Deref for Box<T> { | |||
3141 | } | 2873 | } |
3142 | } | 2874 | } |
3143 | 2875 | ||
3144 | enum Option<T> { | ||
3145 | None, | ||
3146 | Some(T) | ||
3147 | } | ||
3148 | |||
3149 | fn foo() { | 2876 | fn foo() { |
3150 | let s = Option::None; | 2877 | let s = None; |
3151 | let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); | 2878 | let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); |
3152 | f(&s); | 2879 | f(&s); |
3153 | }"#, | 2880 | }"#, |
3154 | expect![[r#" | 2881 | expect![[r#" |
3155 | 100..104 'self': Self | 2882 | 154..158 'self': &Box<T> |
3156 | 106..110 'args': Args | 2883 | 166..193 '{ ... }': &T |
3157 | 214..218 'self': &Self | 2884 | 176..187 '&self.inner': &*mut T |
3158 | 384..388 'self': &Box<T> | 2885 | 177..181 'self': &Box<T> |
3159 | 396..423 '{ ... }': &T | 2886 | 177..187 'self.inner': *mut T |
3160 | 406..417 '&self.inner': &*mut T | 2887 | 206..296 '{ ...&s); }': () |
3161 | 407..411 'self': &Box<T> | 2888 | 216..217 's': Option<i32> |
3162 | 407..417 'self.inner': *mut T | 2889 | 220..224 'None': Option<i32> |
3163 | 478..576 '{ ...&s); }': () | 2890 | 234..235 'f': Box<dyn FnOnce(&Option<i32>)> |
3164 | 488..489 's': Option<i32> | 2891 | 269..282 'box (|ps| {})': Box<|{unknown}| -> ()> |
3165 | 492..504 'Option::None': Option<i32> | 2892 | 274..281 '|ps| {}': |{unknown}| -> () |
3166 | 514..515 'f': Box<dyn FnOnce(&Option<i32>)> | 2893 | 275..277 'ps': {unknown} |
3167 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> | 2894 | 279..281 '{}': () |
3168 | 554..561 '|ps| {}': |{unknown}| -> () | 2895 | 288..289 'f': Box<dyn FnOnce(&Option<i32>)> |
3169 | 555..557 'ps': {unknown} | 2896 | 288..293 'f(&s)': () |
3170 | 559..561 '{}': () | 2897 | 290..292 '&s': &Option<i32> |
3171 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> | 2898 | 291..292 's': Option<i32> |
3172 | 568..573 'f(&s)': () | 2899 | 269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> |
3173 | 570..572 '&s': &Option<i32> | ||
3174 | 571..572 's': Option<i32> | ||
3175 | 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()> | ||
3176 | "#]], | 2900 | "#]], |
3177 | ); | 2901 | ); |
3178 | } | 2902 | } |
@@ -3181,17 +2905,7 @@ fn foo() { | |||
3181 | fn infer_dyn_fn_output() { | 2905 | fn infer_dyn_fn_output() { |
3182 | check_types( | 2906 | check_types( |
3183 | r#" | 2907 | r#" |
3184 | #[lang = "fn_once"] | 2908 | //- minicore: fn |
3185 | pub trait FnOnce<Args> { | ||
3186 | type Output; | ||
3187 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3188 | } | ||
3189 | |||
3190 | #[lang = "fn"] | ||
3191 | pub trait Fn<Args>: FnOnce<Args> { | ||
3192 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
3193 | } | ||
3194 | |||
3195 | fn foo() { | 2909 | fn foo() { |
3196 | let f: &dyn Fn() -> i32; | 2910 | let f: &dyn Fn() -> i32; |
3197 | f(); | 2911 | f(); |
@@ -3204,12 +2918,7 @@ fn foo() { | |||
3204 | fn infer_dyn_fn_once_output() { | 2918 | fn infer_dyn_fn_once_output() { |
3205 | check_types( | 2919 | check_types( |
3206 | r#" | 2920 | r#" |
3207 | #[lang = "fn_once"] | 2921 | //- minicore: fn |
3208 | pub trait FnOnce<Args> { | ||
3209 | type Output; | ||
3210 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3211 | } | ||
3212 | |||
3213 | fn foo() { | 2922 | fn foo() { |
3214 | let f: dyn FnOnce() -> i32; | 2923 | let f: dyn FnOnce() -> i32; |
3215 | f(); | 2924 | f(); |
@@ -3230,7 +2939,7 @@ fn test() { | |||
3230 | S.get(1); | 2939 | S.get(1); |
3231 | //^^^^^^^^ u128 | 2940 | //^^^^^^^^ u128 |
3232 | S.get(1.); | 2941 | S.get(1.); |
3233 | //^^^^^^^^ f32 | 2942 | //^^^^^^^^^ f32 |
3234 | } | 2943 | } |
3235 | "#, | 2944 | "#, |
3236 | ); | 2945 | ); |
@@ -3644,20 +3353,16 @@ fn main() { | |||
3644 | fn fn_returning_unit() { | 3353 | fn fn_returning_unit() { |
3645 | check_infer_with_mismatches( | 3354 | check_infer_with_mismatches( |
3646 | r#" | 3355 | r#" |
3647 | #[lang = "fn_once"] | 3356 | //- minicore: fn |
3648 | trait FnOnce<Args> { | ||
3649 | type Output; | ||
3650 | } | ||
3651 | |||
3652 | fn test<F: FnOnce()>(f: F) { | 3357 | fn test<F: FnOnce()>(f: F) { |
3653 | let _: () = f(); | 3358 | let _: () = f(); |
3654 | }"#, | 3359 | }"#, |
3655 | expect![[r#" | 3360 | expect![[r#" |
3656 | 82..83 'f': F | 3361 | 21..22 'f': F |
3657 | 88..112 '{ ...f(); }': () | 3362 | 27..51 '{ ...f(); }': () |
3658 | 98..99 '_': () | 3363 | 37..38 '_': () |
3659 | 106..107 'f': F | 3364 | 45..46 'f': F |
3660 | 106..109 'f()': () | 3365 | 45..48 'f()': () |
3661 | "#]], | 3366 | "#]], |
3662 | ); | 3367 | ); |
3663 | } | 3368 | } |
@@ -3696,16 +3401,7 @@ impl foo::Foo for u32 { | |||
3696 | fn infer_async_ret_type() { | 3401 | fn infer_async_ret_type() { |
3697 | check_types( | 3402 | check_types( |
3698 | r#" | 3403 | r#" |
3699 | //- /main.rs crate:main deps:core | 3404 | //- minicore: future, result |
3700 | |||
3701 | enum Result<T, E> { | ||
3702 | Ok(T), | ||
3703 | Err(E), | ||
3704 | } | ||
3705 | |||
3706 | use Result::*; | ||
3707 | |||
3708 | |||
3709 | struct Fooey; | 3405 | struct Fooey; |
3710 | 3406 | ||
3711 | impl Fooey { | 3407 | impl Fooey { |
@@ -3718,31 +3414,21 @@ trait Convert { | |||
3718 | fn new() -> Self; | 3414 | fn new() -> Self; |
3719 | } | 3415 | } |
3720 | impl Convert for u32 { | 3416 | impl Convert for u32 { |
3721 | fn new() -> Self { | 3417 | fn new() -> Self { 0 } |
3722 | 0 | ||
3723 | } | ||
3724 | } | 3418 | } |
3725 | 3419 | ||
3726 | async fn get_accounts() -> Result<u32, ()> { | 3420 | async fn get_accounts() -> Result<u32, ()> { |
3727 | let ret = Fooey.collect(); | 3421 | let ret = Fooey.collect(); |
3728 | // ^ u32 | 3422 | // ^^^^^^^^^^^^^^^ u32 |
3729 | Ok(ret) | 3423 | Ok(ret) |
3730 | } | 3424 | } |
3731 | |||
3732 | //- /core.rs crate:core | ||
3733 | #[prelude_import] use future::*; | ||
3734 | mod future { | ||
3735 | #[lang = "future_trait"] | ||
3736 | trait Future { | ||
3737 | type Output; | ||
3738 | } | ||
3739 | } | ||
3740 | "#, | 3425 | "#, |
3741 | ); | 3426 | ); |
3742 | } | 3427 | } |
3743 | 3428 | ||
3744 | #[test] | 3429 | #[test] |
3745 | fn local_impl_1() { | 3430 | fn local_impl_1() { |
3431 | check!(block_local_impls); | ||
3746 | check_types( | 3432 | check_types( |
3747 | r#" | 3433 | r#" |
3748 | trait Trait<T> { | 3434 | trait Trait<T> { |
@@ -3752,7 +3438,7 @@ trait Trait<T> { | |||
3752 | fn test() { | 3438 | fn test() { |
3753 | struct S; | 3439 | struct S; |
3754 | impl Trait<u32> for S { | 3440 | impl Trait<u32> for S { |
3755 | fn foo(&self) { 0 } | 3441 | fn foo(&self) -> u32 { 0 } |
3756 | } | 3442 | } |
3757 | 3443 | ||
3758 | S.foo(); | 3444 | S.foo(); |
@@ -3764,6 +3450,7 @@ fn test() { | |||
3764 | 3450 | ||
3765 | #[test] | 3451 | #[test] |
3766 | fn local_impl_2() { | 3452 | fn local_impl_2() { |
3453 | check!(block_local_impls); | ||
3767 | check_types( | 3454 | check_types( |
3768 | r#" | 3455 | r#" |
3769 | struct S; | 3456 | struct S; |
@@ -3773,7 +3460,7 @@ fn test() { | |||
3773 | fn foo(&self) -> T; | 3460 | fn foo(&self) -> T; |
3774 | } | 3461 | } |
3775 | impl Trait<u32> for S { | 3462 | impl Trait<u32> for S { |
3776 | fn foo(&self) { 0 } | 3463 | fn foo(&self) -> u32 { 0 } |
3777 | } | 3464 | } |
3778 | 3465 | ||
3779 | S.foo(); | 3466 | S.foo(); |
@@ -3785,6 +3472,7 @@ fn test() { | |||
3785 | 3472 | ||
3786 | #[test] | 3473 | #[test] |
3787 | fn local_impl_3() { | 3474 | fn local_impl_3() { |
3475 | check!(block_local_impls); | ||
3788 | check_types( | 3476 | check_types( |
3789 | r#" | 3477 | r#" |
3790 | trait Trait<T> { | 3478 | trait Trait<T> { |
@@ -3797,7 +3485,7 @@ fn test() { | |||
3797 | struct S2; | 3485 | struct S2; |
3798 | 3486 | ||
3799 | impl Trait<S1> for S2 { | 3487 | impl Trait<S1> for S2 { |
3800 | fn foo(&self) { S1 } | 3488 | fn foo(&self) -> S1 { S1 } |
3801 | } | 3489 | } |
3802 | 3490 | ||
3803 | S2.foo(); | 3491 | S2.foo(); |
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f12928225..0e8447394 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -29,6 +29,7 @@ ide_db = { path = "../ide_db", version = "0.0.0" } | |||
29 | cfg = { path = "../cfg", version = "0.0.0" } | 29 | cfg = { path = "../cfg", version = "0.0.0" } |
30 | profile = { path = "../profile", version = "0.0.0" } | 30 | profile = { path = "../profile", version = "0.0.0" } |
31 | ide_assists = { path = "../ide_assists", version = "0.0.0" } | 31 | ide_assists = { path = "../ide_assists", version = "0.0.0" } |
32 | ide_diagnostics = { path = "../ide_diagnostics", version = "0.0.0" } | ||
32 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } | 33 | ide_ssr = { path = "../ide_ssr", version = "0.0.0" } |
33 | ide_completion = { path = "../ide_completion", version = "0.0.0" } | 34 | ide_completion = { path = "../ide_completion", version = "0.0.0" } |
34 | 35 | ||
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs deleted file mode 100644 index 815a633e5..000000000 --- a/crates/ide/src/diagnostics.rs +++ /dev/null | |||
@@ -1,498 +0,0 @@ | |||
1 | //! Collects diagnostics & fixits for a single file. | ||
2 | //! | ||
3 | //! The tricky bit here is that diagnostics are produced by hir in terms of | ||
4 | //! macro-expanded files, but we need to present them to the users in terms of | ||
5 | //! original files. So we need to map the ranges. | ||
6 | |||
7 | mod break_outside_of_loop; | ||
8 | mod inactive_code; | ||
9 | mod incorrect_case; | ||
10 | mod macro_error; | ||
11 | mod mismatched_arg_count; | ||
12 | mod missing_fields; | ||
13 | mod missing_match_arms; | ||
14 | mod missing_ok_or_some_in_tail_expr; | ||
15 | mod missing_unsafe; | ||
16 | mod no_such_field; | ||
17 | mod remove_this_semicolon; | ||
18 | mod replace_filter_map_next_with_find_map; | ||
19 | mod unimplemented_builtin_macro; | ||
20 | mod unlinked_file; | ||
21 | mod unresolved_extern_crate; | ||
22 | mod unresolved_import; | ||
23 | mod unresolved_macro_call; | ||
24 | mod unresolved_module; | ||
25 | mod unresolved_proc_macro; | ||
26 | |||
27 | mod field_shorthand; | ||
28 | |||
29 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | ||
30 | use ide_assists::AssistResolveStrategy; | ||
31 | use ide_db::{base_db::SourceDatabase, RootDatabase}; | ||
32 | use itertools::Itertools; | ||
33 | use rustc_hash::FxHashSet; | ||
34 | use syntax::{ | ||
35 | ast::{self, AstNode}, | ||
36 | SyntaxNode, TextRange, | ||
37 | }; | ||
38 | use text_edit::TextEdit; | ||
39 | use unlinked_file::UnlinkedFile; | ||
40 | |||
41 | use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange}; | ||
42 | |||
43 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
44 | pub struct DiagnosticCode(pub &'static str); | ||
45 | |||
46 | impl DiagnosticCode { | ||
47 | pub fn as_str(&self) -> &str { | ||
48 | self.0 | ||
49 | } | ||
50 | } | ||
51 | |||
52 | #[derive(Debug)] | ||
53 | pub struct Diagnostic { | ||
54 | pub code: DiagnosticCode, | ||
55 | pub message: String, | ||
56 | pub range: TextRange, | ||
57 | pub severity: Severity, | ||
58 | pub unused: bool, | ||
59 | pub experimental: bool, | ||
60 | pub fixes: Option<Vec<Assist>>, | ||
61 | } | ||
62 | |||
63 | impl Diagnostic { | ||
64 | fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic { | ||
65 | let message = message.into(); | ||
66 | Diagnostic { | ||
67 | code: DiagnosticCode(code), | ||
68 | message, | ||
69 | range, | ||
70 | severity: Severity::Error, | ||
71 | unused: false, | ||
72 | experimental: false, | ||
73 | fixes: None, | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn experimental(mut self) -> Diagnostic { | ||
78 | self.experimental = true; | ||
79 | self | ||
80 | } | ||
81 | |||
82 | fn severity(mut self, severity: Severity) -> Diagnostic { | ||
83 | self.severity = severity; | ||
84 | self | ||
85 | } | ||
86 | |||
87 | fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic { | ||
88 | self.fixes = fixes; | ||
89 | self | ||
90 | } | ||
91 | |||
92 | fn with_unused(mut self, unused: bool) -> Diagnostic { | ||
93 | self.unused = unused; | ||
94 | self | ||
95 | } | ||
96 | } | ||
97 | |||
98 | #[derive(Debug, Copy, Clone)] | ||
99 | pub enum Severity { | ||
100 | Error, | ||
101 | WeakWarning, | ||
102 | } | ||
103 | |||
104 | #[derive(Default, Debug, Clone)] | ||
105 | pub struct DiagnosticsConfig { | ||
106 | pub disable_experimental: bool, | ||
107 | pub disabled: FxHashSet<String>, | ||
108 | } | ||
109 | |||
110 | struct DiagnosticsContext<'a> { | ||
111 | config: &'a DiagnosticsConfig, | ||
112 | sema: Semantics<'a, RootDatabase>, | ||
113 | resolve: &'a AssistResolveStrategy, | ||
114 | } | ||
115 | |||
116 | pub(crate) fn diagnostics( | ||
117 | db: &RootDatabase, | ||
118 | config: &DiagnosticsConfig, | ||
119 | resolve: &AssistResolveStrategy, | ||
120 | file_id: FileId, | ||
121 | ) -> Vec<Diagnostic> { | ||
122 | let _p = profile::span("diagnostics"); | ||
123 | let sema = Semantics::new(db); | ||
124 | let parse = db.parse(file_id); | ||
125 | let mut res = Vec::new(); | ||
126 | |||
127 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||
128 | res.extend( | ||
129 | parse.errors().iter().take(128).map(|err| { | ||
130 | Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range()) | ||
131 | }), | ||
132 | ); | ||
133 | |||
134 | for node in parse.tree().syntax().descendants() { | ||
135 | check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); | ||
136 | field_shorthand::check(&mut res, file_id, &node); | ||
137 | } | ||
138 | |||
139 | let mut diags = Vec::new(); | ||
140 | let module = sema.to_module_def(file_id); | ||
141 | if let Some(m) = module { | ||
142 | m.diagnostics(db, &mut diags) | ||
143 | } | ||
144 | |||
145 | let ctx = DiagnosticsContext { config, sema, resolve }; | ||
146 | if module.is_none() { | ||
147 | let d = UnlinkedFile { file: file_id }; | ||
148 | let d = unlinked_file::unlinked_file(&ctx, &d); | ||
149 | res.push(d) | ||
150 | } | ||
151 | |||
152 | for diag in diags { | ||
153 | #[rustfmt::skip] | ||
154 | let d = match diag { | ||
155 | AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), | ||
156 | AnyDiagnostic::IncorrectCase(d) => incorrect_case::incorrect_case(&ctx, &d), | ||
157 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | ||
158 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
159 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | ||
160 | AnyDiagnostic::MissingMatchArms(d) => missing_match_arms::missing_match_arms(&ctx, &d), | ||
161 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), | ||
162 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | ||
163 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | ||
164 | AnyDiagnostic::RemoveThisSemicolon(d) => remove_this_semicolon::remove_this_semicolon(&ctx, &d), | ||
165 | AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), | ||
166 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | ||
167 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | ||
168 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), | ||
169 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), | ||
170 | AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d), | ||
171 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | ||
172 | |||
173 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { | ||
174 | Some(it) => it, | ||
175 | None => continue, | ||
176 | } | ||
177 | }; | ||
178 | res.push(d) | ||
179 | } | ||
180 | |||
181 | res.retain(|d| { | ||
182 | !ctx.config.disabled.contains(d.code.as_str()) | ||
183 | && !(ctx.config.disable_experimental && d.experimental) | ||
184 | }); | ||
185 | |||
186 | res | ||
187 | } | ||
188 | |||
189 | fn check_unnecessary_braces_in_use_statement( | ||
190 | acc: &mut Vec<Diagnostic>, | ||
191 | file_id: FileId, | ||
192 | node: &SyntaxNode, | ||
193 | ) -> Option<()> { | ||
194 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | ||
195 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | ||
196 | // If there is a comment inside the bracketed `use`, | ||
197 | // assume it is a commented out module path and don't show diagnostic. | ||
198 | if use_tree_list.has_inner_comment() { | ||
199 | return Some(()); | ||
200 | } | ||
201 | |||
202 | let use_range = use_tree_list.syntax().text_range(); | ||
203 | let edit = | ||
204 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) | ||
205 | .unwrap_or_else(|| { | ||
206 | let to_replace = single_use_tree.syntax().text().to_string(); | ||
207 | let mut edit_builder = TextEdit::builder(); | ||
208 | edit_builder.delete(use_range); | ||
209 | edit_builder.insert(use_range.start(), to_replace); | ||
210 | edit_builder.finish() | ||
211 | }); | ||
212 | |||
213 | acc.push( | ||
214 | Diagnostic::new( | ||
215 | "unnecessary-braces", | ||
216 | "Unnecessary braces in use statement".to_string(), | ||
217 | use_range, | ||
218 | ) | ||
219 | .severity(Severity::WeakWarning) | ||
220 | .with_fixes(Some(vec![fix( | ||
221 | "remove_braces", | ||
222 | "Remove unnecessary braces", | ||
223 | SourceChange::from_text_edit(file_id, edit), | ||
224 | use_range, | ||
225 | )])), | ||
226 | ); | ||
227 | } | ||
228 | |||
229 | Some(()) | ||
230 | } | ||
231 | |||
232 | fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | ||
233 | single_use_tree: &ast::UseTree, | ||
234 | ) -> Option<TextEdit> { | ||
235 | let use_tree_list_node = single_use_tree.syntax().parent()?; | ||
236 | if single_use_tree.path()?.segment()?.self_token().is_some() { | ||
237 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | ||
238 | let end = use_tree_list_node.text_range().end(); | ||
239 | return Some(TextEdit::delete(TextRange::new(start, end))); | ||
240 | } | ||
241 | None | ||
242 | } | ||
243 | |||
244 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | ||
245 | let mut res = unresolved_fix(id, label, target); | ||
246 | res.source_change = Some(source_change); | ||
247 | res | ||
248 | } | ||
249 | |||
250 | fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | ||
251 | assert!(!id.contains(' ')); | ||
252 | Assist { | ||
253 | id: AssistId(id, AssistKind::QuickFix), | ||
254 | label: Label::new(label), | ||
255 | group: None, | ||
256 | target, | ||
257 | source_change: None, | ||
258 | } | ||
259 | } | ||
260 | |||
261 | #[cfg(test)] | ||
262 | mod tests { | ||
263 | use expect_test::Expect; | ||
264 | use ide_assists::AssistResolveStrategy; | ||
265 | use stdx::trim_indent; | ||
266 | use test_utils::{assert_eq_text, extract_annotations}; | ||
267 | |||
268 | use crate::{fixture, DiagnosticsConfig}; | ||
269 | |||
270 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
271 | /// and checks that: | ||
272 | /// * a diagnostic is produced | ||
273 | /// * the first diagnostic fix trigger range touches the input cursor position | ||
274 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | ||
275 | #[track_caller] | ||
276 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
277 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | ||
278 | } | ||
279 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
280 | /// and checks that: | ||
281 | /// * a diagnostic is produced | ||
282 | /// * every diagnostic fixes trigger range touches the input cursor position | ||
283 | /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied | ||
284 | pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { | ||
285 | for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { | ||
286 | check_nth_fix(i, ra_fixture_before, ra_fixture_after) | ||
287 | } | ||
288 | } | ||
289 | |||
290 | #[track_caller] | ||
291 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
292 | let after = trim_indent(ra_fixture_after); | ||
293 | |||
294 | let (analysis, file_position) = fixture::position(ra_fixture_before); | ||
295 | let diagnostic = analysis | ||
296 | .diagnostics( | ||
297 | &DiagnosticsConfig::default(), | ||
298 | AssistResolveStrategy::All, | ||
299 | file_position.file_id, | ||
300 | ) | ||
301 | .unwrap() | ||
302 | .pop() | ||
303 | .expect("no diagnostics"); | ||
304 | let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; | ||
305 | let actual = { | ||
306 | let source_change = fix.source_change.as_ref().unwrap(); | ||
307 | let file_id = *source_change.source_file_edits.keys().next().unwrap(); | ||
308 | let mut actual = analysis.file_text(file_id).unwrap().to_string(); | ||
309 | |||
310 | for edit in source_change.source_file_edits.values() { | ||
311 | edit.apply(&mut actual); | ||
312 | } | ||
313 | actual | ||
314 | }; | ||
315 | |||
316 | assert_eq_text!(&after, &actual); | ||
317 | assert!( | ||
318 | fix.target.contains_inclusive(file_position.offset), | ||
319 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
320 | fix.target, | ||
321 | file_position.offset | ||
322 | ); | ||
323 | } | ||
324 | |||
325 | /// Checks that there's a diagnostic *without* fix at `$0`. | ||
326 | pub(crate) fn check_no_fix(ra_fixture: &str) { | ||
327 | let (analysis, file_position) = fixture::position(ra_fixture); | ||
328 | let diagnostic = analysis | ||
329 | .diagnostics( | ||
330 | &DiagnosticsConfig::default(), | ||
331 | AssistResolveStrategy::All, | ||
332 | file_position.file_id, | ||
333 | ) | ||
334 | .unwrap() | ||
335 | .pop() | ||
336 | .unwrap(); | ||
337 | assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic); | ||
338 | } | ||
339 | |||
340 | pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { | ||
341 | let (analysis, file_id) = fixture::file(ra_fixture); | ||
342 | let diagnostics = analysis | ||
343 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
344 | .unwrap(); | ||
345 | expect.assert_debug_eq(&diagnostics) | ||
346 | } | ||
347 | |||
348 | #[track_caller] | ||
349 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
350 | let mut config = DiagnosticsConfig::default(); | ||
351 | config.disabled.insert("inactive-code".to_string()); | ||
352 | check_diagnostics_with_config(config, ra_fixture) | ||
353 | } | ||
354 | |||
355 | #[track_caller] | ||
356 | pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { | ||
357 | let (analysis, files) = fixture::files(ra_fixture); | ||
358 | for file_id in files { | ||
359 | let diagnostics = | ||
360 | analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap(); | ||
361 | |||
362 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | ||
363 | let mut actual = | ||
364 | diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); | ||
365 | actual.sort_by_key(|(range, _)| range.start()); | ||
366 | assert_eq!(expected, actual); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | #[test] | ||
371 | fn test_check_unnecessary_braces_in_use_statement() { | ||
372 | check_diagnostics( | ||
373 | r#" | ||
374 | use a; | ||
375 | use a::{c, d::e}; | ||
376 | |||
377 | mod a { | ||
378 | mod c {} | ||
379 | mod d { | ||
380 | mod e {} | ||
381 | } | ||
382 | } | ||
383 | "#, | ||
384 | ); | ||
385 | check_diagnostics( | ||
386 | r#" | ||
387 | use a; | ||
388 | use a::{ | ||
389 | c, | ||
390 | // d::e | ||
391 | }; | ||
392 | |||
393 | mod a { | ||
394 | mod c {} | ||
395 | mod d { | ||
396 | mod e {} | ||
397 | } | ||
398 | } | ||
399 | "#, | ||
400 | ); | ||
401 | check_fix( | ||
402 | r" | ||
403 | mod b {} | ||
404 | use {$0b}; | ||
405 | ", | ||
406 | r" | ||
407 | mod b {} | ||
408 | use b; | ||
409 | ", | ||
410 | ); | ||
411 | check_fix( | ||
412 | r" | ||
413 | mod b {} | ||
414 | use {b$0}; | ||
415 | ", | ||
416 | r" | ||
417 | mod b {} | ||
418 | use b; | ||
419 | ", | ||
420 | ); | ||
421 | check_fix( | ||
422 | r" | ||
423 | mod a { mod c {} } | ||
424 | use a::{c$0}; | ||
425 | ", | ||
426 | r" | ||
427 | mod a { mod c {} } | ||
428 | use a::c; | ||
429 | ", | ||
430 | ); | ||
431 | check_fix( | ||
432 | r" | ||
433 | mod a {} | ||
434 | use a::{self$0}; | ||
435 | ", | ||
436 | r" | ||
437 | mod a {} | ||
438 | use a; | ||
439 | ", | ||
440 | ); | ||
441 | check_fix( | ||
442 | r" | ||
443 | mod a { mod c {} mod d { mod e {} } } | ||
444 | use a::{c, d::{e$0}}; | ||
445 | ", | ||
446 | r" | ||
447 | mod a { mod c {} mod d { mod e {} } } | ||
448 | use a::{c, d::e}; | ||
449 | ", | ||
450 | ); | ||
451 | } | ||
452 | |||
453 | #[test] | ||
454 | fn test_disabled_diagnostics() { | ||
455 | let mut config = DiagnosticsConfig::default(); | ||
456 | config.disabled.insert("unresolved-module".into()); | ||
457 | |||
458 | let (analysis, file_id) = fixture::file(r#"mod foo;"#); | ||
459 | |||
460 | let diagnostics = | ||
461 | analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap(); | ||
462 | assert!(diagnostics.is_empty()); | ||
463 | |||
464 | let diagnostics = analysis | ||
465 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | ||
466 | .unwrap(); | ||
467 | assert!(!diagnostics.is_empty()); | ||
468 | } | ||
469 | |||
470 | #[test] | ||
471 | fn import_extern_crate_clash_with_inner_item() { | ||
472 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
473 | |||
474 | check_diagnostics( | ||
475 | r#" | ||
476 | //- /lib.rs crate:lib deps:jwt | ||
477 | mod permissions; | ||
478 | |||
479 | use permissions::jwt; | ||
480 | |||
481 | fn f() { | ||
482 | fn inner() {} | ||
483 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
484 | } | ||
485 | |||
486 | //- /permissions.rs | ||
487 | pub mod jwt { | ||
488 | pub struct Claims {} | ||
489 | } | ||
490 | |||
491 | //- /jwt/lib.rs crate:jwt | ||
492 | pub struct Claims { | ||
493 | field: u8, | ||
494 | } | ||
495 | "#, | ||
496 | ); | ||
497 | } | ||
498 | } | ||
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index b75ec411c..455b32456 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -442,10 +442,10 @@ impl TryToNav for hir::TypeParam { | |||
442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
443 | let src = self.source(db)?; | 443 | let src = self.source(db)?; |
444 | let full_range = match &src.value { | 444 | let full_range = match &src.value { |
445 | Either::Left(it) => it | 445 | Either::Left(type_param) => type_param.syntax().text_range(), |
446 | Either::Right(trait_) => trait_ | ||
446 | .name() | 447 | .name() |
447 | .map_or_else(|| it.syntax().text_range(), |name| name.syntax().text_range()), | 448 | .map_or_else(|| trait_.syntax().text_range(), |name| name.syntax().text_range()), |
448 | Either::Right(it) => it.syntax().text_range(), | ||
449 | }; | 449 | }; |
450 | let focus_range = match &src.value { | 450 | let focus_range = match &src.value { |
451 | Either::Left(it) => it.name(), | 451 | Either::Left(it) => it.name(), |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 57ae9455b..7ac0118fe 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -241,6 +241,10 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
241 | Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), | 241 | Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), |
242 | _ => definition.module(db)?.krate(), | 242 | _ => definition.module(db)?.krate(), |
243 | }; | 243 | }; |
244 | // FIXME: using import map doesn't make sense here. What we want here is | ||
245 | // canonical path. What import map returns is the shortest path suitable for | ||
246 | // import. See this test: | ||
247 | cov_mark::hit!(test_reexport_order); | ||
244 | let import_map = db.import_map(krate.into()); | 248 | let import_map = db.import_map(krate.into()); |
245 | 249 | ||
246 | let mut base = krate.display_name(db)?.to_string(); | 250 | let mut base = krate.display_name(db)?.to_string(); |
@@ -642,13 +646,15 @@ pub mod foo { | |||
642 | ) | 646 | ) |
643 | } | 647 | } |
644 | 648 | ||
645 | // FIXME: ImportMap will return re-export paths instead of public module | ||
646 | // paths. The correct path to documentation will never be a re-export. | ||
647 | // This problem stops us from resolving stdlib items included in the prelude | ||
648 | // such as `Option::Some` correctly. | ||
649 | #[ignore = "ImportMap may return re-exports"] | ||
650 | #[test] | 649 | #[test] |
651 | fn test_reexport_order() { | 650 | fn test_reexport_order() { |
651 | cov_mark::check!(test_reexport_order); | ||
652 | // FIXME: This should return | ||
653 | // | ||
654 | // https://docs.rs/test/*/test/wrapper/modulestruct.Item.html | ||
655 | // | ||
656 | // That is, we should point inside the module, rather than at the | ||
657 | // re-export. | ||
652 | check( | 658 | check( |
653 | r#" | 659 | r#" |
654 | pub mod wrapper { | 660 | pub mod wrapper { |
@@ -663,7 +669,7 @@ fn foo() { | |||
663 | let bar: wrapper::It$0em; | 669 | let bar: wrapper::It$0em; |
664 | } | 670 | } |
665 | "#, | 671 | "#, |
666 | expect![[r#"https://docs.rs/test/*/test/wrapper/module/struct.Item.html"#]], | 672 | expect![[r#"https://docs.rs/test/*/test/wrapper/struct.Item.html"#]], |
667 | ) | 673 | ) |
668 | } | 674 | } |
669 | } | 675 | } |
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index 38e2e866b..cf679edd3 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs | |||
@@ -12,14 +12,6 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { | |||
12 | (host.analysis(), change_fixture.files[0]) | 12 | (host.analysis(), change_fixture.files[0]) |
13 | } | 13 | } |
14 | 14 | ||
15 | /// Creates analysis for many files. | ||
16 | pub(crate) fn files(ra_fixture: &str) -> (Analysis, Vec<FileId>) { | ||
17 | let mut host = AnalysisHost::default(); | ||
18 | let change_fixture = ChangeFixture::parse(ra_fixture); | ||
19 | host.db.apply_change(change_fixture.change); | ||
20 | (host.analysis(), change_fixture.files) | ||
21 | } | ||
22 | |||
23 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 15 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
24 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { | 16 | pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { |
25 | let mut host = AnalysisHost::default(); | 17 | let mut host = AnalysisHost::default(); |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 8dd643a0f..d8e0dc4d5 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1130,15 +1130,15 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | #[test] | 1132 | #[test] |
1133 | #[ignore] // requires the HIR to somehow track these hrtb lifetimes | ||
1134 | fn goto_lifetime_hrtb() { | 1133 | fn goto_lifetime_hrtb() { |
1135 | check( | 1134 | // FIXME: requires the HIR to somehow track these hrtb lifetimes |
1135 | check_unresolved( | ||
1136 | r#"trait Foo<T> {} | 1136 | r#"trait Foo<T> {} |
1137 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} | 1137 | fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {} |
1138 | //^^ | 1138 | //^^ |
1139 | "#, | 1139 | "#, |
1140 | ); | 1140 | ); |
1141 | check( | 1141 | check_unresolved( |
1142 | r#"trait Foo<T> {} | 1142 | r#"trait Foo<T> {} |
1143 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} | 1143 | fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} |
1144 | //^^ | 1144 | //^^ |
@@ -1147,9 +1147,9 @@ fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {} | |||
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | #[test] | 1149 | #[test] |
1150 | #[ignore] // requires ForTypes to be implemented | ||
1151 | fn goto_lifetime_hrtb_for_type() { | 1150 | fn goto_lifetime_hrtb_for_type() { |
1152 | check( | 1151 | // FIXME: requires ForTypes to be implemented |
1152 | check_unresolved( | ||
1153 | r#"trait Foo<T> {} | 1153 | r#"trait Foo<T> {} |
1154 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} | 1154 | fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {} |
1155 | //^^ | 1155 | //^^ |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 0013820b4..07686017d 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -236,15 +236,10 @@ impl T for &Foo {} | |||
236 | fn goto_implementation_to_builtin_derive() { | 236 | fn goto_implementation_to_builtin_derive() { |
237 | check( | 237 | check( |
238 | r#" | 238 | r#" |
239 | //- minicore: copy, derive | ||
239 | #[derive(Copy)] | 240 | #[derive(Copy)] |
240 | //^^^^^^^^^^^^^^^ | 241 | //^^^^^^^^^^^^^^^ |
241 | struct Foo$0; | 242 | struct Foo$0; |
242 | |||
243 | mod marker { | ||
244 | trait Copy {} | ||
245 | } | ||
246 | #[rustc_builtin_macro] | ||
247 | macro Copy {} | ||
248 | "#, | 243 | "#, |
249 | ); | 244 | ); |
250 | } | 245 | } |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index 004d9cb68..43cffefe5 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -33,13 +33,23 @@ pub(crate) fn goto_type_definition( | |||
33 | ast::SelfParam(it) => sema.type_of_self(&it)?, | 33 | ast::SelfParam(it) => sema.type_of_self(&it)?, |
34 | ast::Type(it) => sema.resolve_type(&it)?, | 34 | ast::Type(it) => sema.resolve_type(&it)?, |
35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | 35 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, |
36 | ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?, | ||
37 | // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise | ||
38 | ast::NameRef(it) => { | ||
39 | if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) { | ||
40 | let (_, _, ty) = sema.resolve_record_field(&record_field)?; | ||
41 | ty | ||
42 | } else { | ||
43 | let record_field = ast::RecordPatField::for_field_name_ref(&it)?; | ||
44 | sema.resolve_record_pat_field(&record_field)?.ty(db) | ||
45 | } | ||
46 | }, | ||
36 | _ => return None, | 47 | _ => return None, |
37 | } | 48 | } |
38 | }; | 49 | }; |
39 | 50 | ||
40 | Some((ty, node)) | 51 | Some((ty, node)) |
41 | })?; | 52 | })?; |
42 | |||
43 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; | 53 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
44 | 54 | ||
45 | let nav = adt_def.try_to_nav(db)?; | 55 | let nav = adt_def.try_to_nav(db)?; |
@@ -88,6 +98,54 @@ fn foo() { | |||
88 | } | 98 | } |
89 | 99 | ||
90 | #[test] | 100 | #[test] |
101 | fn goto_type_definition_record_expr_field() { | ||
102 | check( | ||
103 | r#" | ||
104 | struct Bar; | ||
105 | // ^^^ | ||
106 | struct Foo { foo: Bar } | ||
107 | fn foo() { | ||
108 | Foo { foo$0 } | ||
109 | } | ||
110 | "#, | ||
111 | ); | ||
112 | check( | ||
113 | r#" | ||
114 | struct Bar; | ||
115 | // ^^^ | ||
116 | struct Foo { foo: Bar } | ||
117 | fn foo() { | ||
118 | Foo { foo$0: Bar } | ||
119 | } | ||
120 | "#, | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn goto_type_definition_record_pat_field() { | ||
126 | check( | ||
127 | r#" | ||
128 | struct Bar; | ||
129 | // ^^^ | ||
130 | struct Foo { foo: Bar } | ||
131 | fn foo() { | ||
132 | let Foo { foo$0 }; | ||
133 | } | ||
134 | "#, | ||
135 | ); | ||
136 | check( | ||
137 | r#" | ||
138 | struct Bar; | ||
139 | // ^^^ | ||
140 | struct Foo { foo: Bar } | ||
141 | fn foo() { | ||
142 | let Foo { foo$0: bar }; | ||
143 | } | ||
144 | "#, | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
91 | fn goto_type_definition_works_simple_ref() { | 149 | fn goto_type_definition_works_simple_ref() { |
92 | check( | 150 | check( |
93 | r#" | 151 | r#" |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 4e1ab534b..0c1da8774 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -563,8 +563,6 @@ mod tests { | |||
563 | 563 | ||
564 | use crate::fixture; | 564 | use crate::fixture; |
565 | 565 | ||
566 | use super::*; | ||
567 | |||
568 | fn check_hover_no_result(ra_fixture: &str) { | 566 | fn check_hover_no_result(ra_fixture: &str) { |
569 | let (analysis, position) = fixture::position(ra_fixture); | 567 | let (analysis, position) = fixture::position(ra_fixture); |
570 | assert!(analysis.hover(position, true, true, true).unwrap().is_none()); | 568 | assert!(analysis.hover(position, true, true, true).unwrap().is_none()); |
@@ -1816,9 +1814,10 @@ pub struct B$0ar | |||
1816 | ); | 1814 | ); |
1817 | } | 1815 | } |
1818 | 1816 | ||
1819 | #[ignore = "path based links currently only support documentation on ModuleDef items"] | ||
1820 | #[test] | 1817 | #[test] |
1821 | fn test_hover_path_link_field() { | 1818 | fn test_hover_path_link_field() { |
1819 | // FIXME: Should be | ||
1820 | // [Foo](https://docs.rs/test/*/test/struct.Foo.html) | ||
1822 | check( | 1821 | check( |
1823 | r#" | 1822 | r#" |
1824 | pub struct Foo; | 1823 | pub struct Foo; |
@@ -1840,7 +1839,7 @@ pub struct Bar { | |||
1840 | 1839 | ||
1841 | --- | 1840 | --- |
1842 | 1841 | ||
1843 | [Foo](https://docs.rs/test/*/test/struct.Foo.html) | 1842 | [Foo](struct.Foo.html) |
1844 | "#]], | 1843 | "#]], |
1845 | ); | 1844 | ); |
1846 | } | 1845 | } |
@@ -2254,7 +2253,7 @@ pub fn fo$0o() {} | |||
2254 | case 13. collapsed link: foo | 2253 | case 13. collapsed link: foo |
2255 | case 14. shortcut link: foo | 2254 | case 14. shortcut link: foo |
2256 | case 15. inline without URL: foo | 2255 | case 15. inline without URL: foo |
2257 | case 16. just escaped text: \[foo] | 2256 | case 16. just escaped text: \[foo\] |
2258 | case 17. inline link: Foo | 2257 | case 17. inline link: Foo |
2259 | 2258 | ||
2260 | [^example]: https://www.example.com/ | 2259 | [^example]: https://www.example.com/ |
@@ -2994,29 +2993,24 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} | |||
2994 | fn test_hover_async_block_impl_trait_has_goto_type_action() { | 2993 | fn test_hover_async_block_impl_trait_has_goto_type_action() { |
2995 | check_actions( | 2994 | check_actions( |
2996 | r#" | 2995 | r#" |
2996 | //- minicore: future | ||
2997 | struct S; | 2997 | struct S; |
2998 | fn foo() { | 2998 | fn foo() { |
2999 | let fo$0o = async { S }; | 2999 | let fo$0o = async { S }; |
3000 | } | 3000 | } |
3001 | |||
3002 | #[prelude_import] use future::*; | ||
3003 | mod future { | ||
3004 | #[lang = "future_trait"] | ||
3005 | pub trait Future { type Output; } | ||
3006 | } | ||
3007 | "#, | 3001 | "#, |
3008 | expect![[r#" | 3002 | expect![[r#" |
3009 | [ | 3003 | [ |
3010 | GoToType( | 3004 | GoToType( |
3011 | [ | 3005 | [ |
3012 | HoverGotoTypeData { | 3006 | HoverGotoTypeData { |
3013 | mod_path: "test::future::Future", | 3007 | mod_path: "core::future::Future", |
3014 | nav: NavigationTarget { | 3008 | nav: NavigationTarget { |
3015 | file_id: FileId( | 3009 | file_id: FileId( |
3016 | 0, | 3010 | 1, |
3017 | ), | 3011 | ), |
3018 | full_range: 101..163, | 3012 | full_range: 251..433, |
3019 | focus_range: 140..146, | 3013 | focus_range: 290..296, |
3020 | name: "Future", | 3014 | name: "Future", |
3021 | kind: Trait, | 3015 | kind: Trait, |
3022 | description: "pub trait Future", | 3016 | description: "pub trait Future", |
@@ -3812,11 +3806,14 @@ use foo::bar::{self$0}; | |||
3812 | 3806 | ||
3813 | #[test] | 3807 | #[test] |
3814 | fn hover_keyword() { | 3808 | fn hover_keyword() { |
3815 | let ra_fixture = r#"//- /main.rs crate:main deps:std | ||
3816 | fn f() { retur$0n; }"#; | ||
3817 | let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
3818 | check( | 3809 | check( |
3819 | &fixture, | 3810 | r#" |
3811 | //- /main.rs crate:main deps:std | ||
3812 | fn f() { retur$0n; } | ||
3813 | //- /libstd.rs crate:std | ||
3814 | /// Docs for return_keyword | ||
3815 | mod return_keyword {} | ||
3816 | "#, | ||
3820 | expect![[r#" | 3817 | expect![[r#" |
3821 | *return* | 3818 | *return* |
3822 | 3819 | ||
@@ -3833,11 +3830,15 @@ fn f() { retur$0n; }"#; | |||
3833 | 3830 | ||
3834 | #[test] | 3831 | #[test] |
3835 | fn hover_builtin() { | 3832 | fn hover_builtin() { |
3836 | let ra_fixture = r#"//- /main.rs crate:main deps:std | ||
3837 | cosnt _: &str$0 = ""; }"#; | ||
3838 | let fixture = format!("{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
3839 | check( | 3833 | check( |
3840 | &fixture, | 3834 | r#" |
3835 | //- /main.rs crate:main deps:std | ||
3836 | cosnt _: &str$0 = ""; } | ||
3837 | |||
3838 | //- /libstd.rs crate:std | ||
3839 | /// Docs for prim_str | ||
3840 | mod prim_str {} | ||
3841 | "#, | ||
3841 | expect![[r#" | 3842 | expect![[r#" |
3842 | *str* | 3843 | *str* |
3843 | 3844 | ||
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 9cd33d0e4..95f9edce4 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -434,7 +434,6 @@ fn get_callable( | |||
434 | #[cfg(test)] | 434 | #[cfg(test)] |
435 | mod tests { | 435 | mod tests { |
436 | use expect_test::{expect, Expect}; | 436 | use expect_test::{expect, Expect}; |
437 | use ide_db::helpers::FamousDefs; | ||
438 | use test_utils::extract_annotations; | 437 | use test_utils::extract_annotations; |
439 | 438 | ||
440 | use crate::{fixture, inlay_hints::InlayHintsConfig}; | 439 | use crate::{fixture, inlay_hints::InlayHintsConfig}; |
@@ -487,8 +486,6 @@ mod tests { | |||
487 | } | 486 | } |
488 | 487 | ||
489 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { | 488 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { |
490 | let ra_fixture = | ||
491 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
492 | let (analysis, file_id) = fixture::file(&ra_fixture); | 489 | let (analysis, file_id) = fixture::file(&ra_fixture); |
493 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | 490 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); |
494 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 491 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
@@ -498,8 +495,6 @@ mod tests { | |||
498 | } | 495 | } |
499 | 496 | ||
500 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { | 497 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { |
501 | let ra_fixture = | ||
502 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
503 | let (analysis, file_id) = fixture::file(&ra_fixture); | 498 | let (analysis, file_id) = fixture::file(&ra_fixture); |
504 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 499 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
505 | expect.assert_debug_eq(&inlay_hints) | 500 | expect.assert_debug_eq(&inlay_hints) |
@@ -666,9 +661,7 @@ fn main() { | |||
666 | fn function_call_parameter_hint() { | 661 | fn function_call_parameter_hint() { |
667 | check_params( | 662 | check_params( |
668 | r#" | 663 | r#" |
669 | enum Option<T> { None, Some(T) } | 664 | //- minicore: option |
670 | use Option::*; | ||
671 | |||
672 | struct FileId {} | 665 | struct FileId {} |
673 | struct SmolStr {} | 666 | struct SmolStr {} |
674 | 667 | ||
@@ -823,6 +816,7 @@ fn main() { | |||
823 | fn shorten_iterators_in_associated_params() { | 816 | fn shorten_iterators_in_associated_params() { |
824 | check_types( | 817 | check_types( |
825 | r#" | 818 | r#" |
819 | //- minicore: iterators | ||
826 | use core::iter; | 820 | use core::iter; |
827 | 821 | ||
828 | pub struct SomeIter<T> {} | 822 | pub struct SomeIter<T> {} |
@@ -875,8 +869,7 @@ fn main() { | |||
875 | fn fn_hints() { | 869 | fn fn_hints() { |
876 | check_types( | 870 | check_types( |
877 | r#" | 871 | r#" |
878 | trait Sized {} | 872 | //- minicore: fn, sized |
879 | |||
880 | fn foo() -> impl Fn() { loop {} } | 873 | fn foo() -> impl Fn() { loop {} } |
881 | fn foo1() -> impl Fn(f64) { loop {} } | 874 | fn foo1() -> impl Fn(f64) { loop {} } |
882 | fn foo2() -> impl Fn(f64, f64) { loop {} } | 875 | fn foo2() -> impl Fn(f64, f64) { loop {} } |
@@ -912,9 +905,7 @@ fn main() { | |||
912 | fn unit_structs_have_no_type_hints() { | 905 | fn unit_structs_have_no_type_hints() { |
913 | check_types( | 906 | check_types( |
914 | r#" | 907 | r#" |
915 | enum Result<T, E> { Ok(T), Err(E) } | 908 | //- minicore: result |
916 | use Result::*; | ||
917 | |||
918 | struct SyntheticSyntax; | 909 | struct SyntheticSyntax; |
919 | 910 | ||
920 | fn main() { | 911 | fn main() { |
@@ -966,9 +957,7 @@ fn main() { | |||
966 | fn if_expr() { | 957 | fn if_expr() { |
967 | check_types( | 958 | check_types( |
968 | r#" | 959 | r#" |
969 | enum Option<T> { None, Some(T) } | 960 | //- minicore: option |
970 | use Option::*; | ||
971 | |||
972 | struct Test { a: Option<u32>, b: u8 } | 961 | struct Test { a: Option<u32>, b: u8 } |
973 | 962 | ||
974 | fn main() { | 963 | fn main() { |
@@ -998,9 +987,7 @@ fn main() { | |||
998 | fn while_expr() { | 987 | fn while_expr() { |
999 | check_types( | 988 | check_types( |
1000 | r#" | 989 | r#" |
1001 | enum Option<T> { None, Some(T) } | 990 | //- minicore: option |
1002 | use Option::*; | ||
1003 | |||
1004 | struct Test { a: Option<u32>, b: u8 } | 991 | struct Test { a: Option<u32>, b: u8 } |
1005 | 992 | ||
1006 | fn main() { | 993 | fn main() { |
@@ -1016,9 +1003,7 @@ fn main() { | |||
1016 | fn match_arm_list() { | 1003 | fn match_arm_list() { |
1017 | check_types( | 1004 | check_types( |
1018 | r#" | 1005 | r#" |
1019 | enum Option<T> { None, Some(T) } | 1006 | //- minicore: option |
1020 | use Option::*; | ||
1021 | |||
1022 | struct Test { a: Option<u32>, b: u8 } | 1007 | struct Test { a: Option<u32>, b: u8 } |
1023 | 1008 | ||
1024 | fn main() { | 1009 | fn main() { |
@@ -1073,6 +1058,7 @@ fn main() { | |||
1073 | fn complete_for_hint() { | 1058 | fn complete_for_hint() { |
1074 | check_types( | 1059 | check_types( |
1075 | r#" | 1060 | r#" |
1061 | //- minicore: iterator | ||
1076 | pub struct Vec<T> {} | 1062 | pub struct Vec<T> {} |
1077 | 1063 | ||
1078 | impl<T> Vec<T> { | 1064 | impl<T> Vec<T> { |
@@ -1129,6 +1115,7 @@ fn main() { | |||
1129 | fn shorten_iterator_hints() { | 1115 | fn shorten_iterator_hints() { |
1130 | check_types( | 1116 | check_types( |
1131 | r#" | 1117 | r#" |
1118 | //- minicore: iterators | ||
1132 | use core::iter; | 1119 | use core::iter; |
1133 | 1120 | ||
1134 | struct MyIter; | 1121 | struct MyIter; |
@@ -1230,12 +1217,12 @@ fn main() { | |||
1230 | expect![[r#" | 1217 | expect![[r#" |
1231 | [ | 1218 | [ |
1232 | InlayHint { | 1219 | InlayHint { |
1233 | range: 148..173, | 1220 | range: 147..172, |
1234 | kind: ChainingHint, | 1221 | kind: ChainingHint, |
1235 | label: "B", | 1222 | label: "B", |
1236 | }, | 1223 | }, |
1237 | InlayHint { | 1224 | InlayHint { |
1238 | range: 148..155, | 1225 | range: 147..154, |
1239 | kind: ChainingHint, | 1226 | kind: ChainingHint, |
1240 | label: "A", | 1227 | label: "A", |
1241 | }, | 1228 | }, |
@@ -1290,12 +1277,12 @@ fn main() { | |||
1290 | expect![[r#" | 1277 | expect![[r#" |
1291 | [ | 1278 | [ |
1292 | InlayHint { | 1279 | InlayHint { |
1293 | range: 144..191, | 1280 | range: 143..190, |
1294 | kind: ChainingHint, | 1281 | kind: ChainingHint, |
1295 | label: "C", | 1282 | label: "C", |
1296 | }, | 1283 | }, |
1297 | InlayHint { | 1284 | InlayHint { |
1298 | range: 144..180, | 1285 | range: 143..179, |
1299 | kind: ChainingHint, | 1286 | kind: ChainingHint, |
1300 | label: "B", | 1287 | label: "B", |
1301 | }, | 1288 | }, |
@@ -1335,12 +1322,12 @@ fn main() { | |||
1335 | expect![[r#" | 1322 | expect![[r#" |
1336 | [ | 1323 | [ |
1337 | InlayHint { | 1324 | InlayHint { |
1338 | range: 247..284, | 1325 | range: 246..283, |
1339 | kind: ChainingHint, | 1326 | kind: ChainingHint, |
1340 | label: "B<X<i32, bool>>", | 1327 | label: "B<X<i32, bool>>", |
1341 | }, | 1328 | }, |
1342 | InlayHint { | 1329 | InlayHint { |
1343 | range: 247..266, | 1330 | range: 246..265, |
1344 | kind: ChainingHint, | 1331 | kind: ChainingHint, |
1345 | label: "A<X<i32, bool>>", | 1332 | label: "A<X<i32, bool>>", |
1346 | }, | 1333 | }, |
@@ -1359,6 +1346,7 @@ fn main() { | |||
1359 | max_length: None, | 1346 | max_length: None, |
1360 | }, | 1347 | }, |
1361 | r#" | 1348 | r#" |
1349 | //- minicore: iterators | ||
1362 | use core::iter; | 1350 | use core::iter; |
1363 | 1351 | ||
1364 | struct MyIter; | 1352 | struct MyIter; |
@@ -1381,22 +1369,22 @@ fn main() { | |||
1381 | expect![[r#" | 1369 | expect![[r#" |
1382 | [ | 1370 | [ |
1383 | InlayHint { | 1371 | InlayHint { |
1384 | range: 175..242, | 1372 | range: 174..241, |
1385 | kind: ChainingHint, | 1373 | kind: ChainingHint, |
1386 | label: "impl Iterator<Item = ()>", | 1374 | label: "impl Iterator<Item = ()>", |
1387 | }, | 1375 | }, |
1388 | InlayHint { | 1376 | InlayHint { |
1389 | range: 175..225, | 1377 | range: 174..224, |
1390 | kind: ChainingHint, | 1378 | kind: ChainingHint, |
1391 | label: "impl Iterator<Item = ()>", | 1379 | label: "impl Iterator<Item = ()>", |
1392 | }, | 1380 | }, |
1393 | InlayHint { | 1381 | InlayHint { |
1394 | range: 175..207, | 1382 | range: 174..206, |
1395 | kind: ChainingHint, | 1383 | kind: ChainingHint, |
1396 | label: "impl Iterator<Item = ()>", | 1384 | label: "impl Iterator<Item = ()>", |
1397 | }, | 1385 | }, |
1398 | InlayHint { | 1386 | InlayHint { |
1399 | range: 175..190, | 1387 | range: 174..189, |
1400 | kind: ChainingHint, | 1388 | kind: ChainingHint, |
1401 | label: "&mut MyIter", | 1389 | label: "&mut MyIter", |
1402 | }, | 1390 | }, |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 93d3760bf..ffa8bd182 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -197,7 +197,7 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti | |||
197 | } | 197 | } |
198 | 198 | ||
199 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { | 199 | fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool { |
200 | matches!((left, right), (T![,], T![')']) | (T![,], T![']'])) | 200 | matches!((left, right), (T![,], T![')'] | T![']'])) |
201 | } | 201 | } |
202 | 202 | ||
203 | fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { | 203 | fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 8d0270319..3798f32cc 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -24,7 +24,6 @@ mod display; | |||
24 | 24 | ||
25 | mod annotations; | 25 | mod annotations; |
26 | mod call_hierarchy; | 26 | mod call_hierarchy; |
27 | mod diagnostics; | ||
28 | mod expand_macro; | 27 | mod expand_macro; |
29 | mod extend_selection; | 28 | mod extend_selection; |
30 | mod file_structure; | 29 | mod file_structure; |
@@ -40,6 +39,7 @@ mod matching_brace; | |||
40 | mod move_item; | 39 | mod move_item; |
41 | mod parent_module; | 40 | mod parent_module; |
42 | mod references; | 41 | mod references; |
42 | mod rename; | ||
43 | mod fn_references; | 43 | mod fn_references; |
44 | mod runnables; | 44 | mod runnables; |
45 | mod ssr; | 45 | mod ssr; |
@@ -71,7 +71,6 @@ use crate::display::ToNav; | |||
71 | pub use crate::{ | 71 | pub use crate::{ |
72 | annotations::{Annotation, AnnotationConfig, AnnotationKind}, | 72 | annotations::{Annotation, AnnotationConfig, AnnotationKind}, |
73 | call_hierarchy::CallItem, | 73 | call_hierarchy::CallItem, |
74 | diagnostics::{Diagnostic, DiagnosticsConfig, Severity}, | ||
75 | display::navigation_target::NavigationTarget, | 74 | display::navigation_target::NavigationTarget, |
76 | expand_macro::ExpandedMacro, | 75 | expand_macro::ExpandedMacro, |
77 | file_structure::{StructureNode, StructureNodeKind}, | 76 | file_structure::{StructureNode, StructureNodeKind}, |
@@ -81,7 +80,8 @@ pub use crate::{ | |||
81 | markup::Markup, | 80 | markup::Markup, |
82 | move_item::Direction, | 81 | move_item::Direction, |
83 | prime_caches::PrimeCachesProgress, | 82 | prime_caches::PrimeCachesProgress, |
84 | references::{rename::RenameError, ReferenceSearchResult}, | 83 | references::ReferenceSearchResult, |
84 | rename::RenameError, | ||
85 | runnables::{Runnable, RunnableKind, TestId}, | 85 | runnables::{Runnable, RunnableKind, TestId}, |
86 | syntax_highlighting::{ | 86 | syntax_highlighting::{ |
87 | tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, | 87 | tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag}, |
@@ -109,6 +109,7 @@ pub use ide_db::{ | |||
109 | symbol_index::Query, | 109 | symbol_index::Query, |
110 | RootDatabase, SymbolKind, | 110 | RootDatabase, SymbolKind, |
111 | }; | 111 | }; |
112 | pub use ide_diagnostics::{Diagnostic, DiagnosticsConfig, Severity}; | ||
112 | pub use ide_ssr::SsrError; | 113 | pub use ide_ssr::SsrError; |
113 | pub use syntax::{TextRange, TextSize}; | 114 | pub use syntax::{TextRange, TextSize}; |
114 | pub use text_edit::{Indel, TextEdit}; | 115 | pub use text_edit::{Indel, TextEdit}; |
@@ -537,7 +538,7 @@ impl Analysis { | |||
537 | ) -> Cancellable<Vec<Assist>> { | 538 | ) -> Cancellable<Vec<Assist>> { |
538 | self.with_db(|db| { | 539 | self.with_db(|db| { |
539 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | 540 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); |
540 | let mut acc = Assist::get(db, config, resolve, frange); | 541 | let mut acc = ide_assists::assists(db, config, resolve, frange); |
541 | acc.extend(ssr_assists.into_iter()); | 542 | acc.extend(ssr_assists.into_iter()); |
542 | acc | 543 | acc |
543 | }) | 544 | }) |
@@ -550,7 +551,7 @@ impl Analysis { | |||
550 | resolve: AssistResolveStrategy, | 551 | resolve: AssistResolveStrategy, |
551 | file_id: FileId, | 552 | file_id: FileId, |
552 | ) -> Cancellable<Vec<Diagnostic>> { | 553 | ) -> Cancellable<Vec<Diagnostic>> { |
553 | self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id)) | 554 | self.with_db(|db| ide_diagnostics::diagnostics(db, config, &resolve, file_id)) |
554 | } | 555 | } |
555 | 556 | ||
556 | /// Convenience function to return assists + quick fixes for diagnostics | 557 | /// Convenience function to return assists + quick fixes for diagnostics |
@@ -567,9 +568,8 @@ impl Analysis { | |||
567 | }; | 568 | }; |
568 | 569 | ||
569 | self.with_db(|db| { | 570 | self.with_db(|db| { |
570 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | ||
571 | let diagnostic_assists = if include_fixes { | 571 | let diagnostic_assists = if include_fixes { |
572 | diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) | 572 | ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) |
573 | .into_iter() | 573 | .into_iter() |
574 | .flat_map(|it| it.fixes.unwrap_or_default()) | 574 | .flat_map(|it| it.fixes.unwrap_or_default()) |
575 | .filter(|it| it.target.intersect(frange.range).is_some()) | 575 | .filter(|it| it.target.intersect(frange.range).is_some()) |
@@ -577,10 +577,12 @@ impl Analysis { | |||
577 | } else { | 577 | } else { |
578 | Vec::new() | 578 | Vec::new() |
579 | }; | 579 | }; |
580 | let ssr_assists = ssr::ssr_assists(db, &resolve, frange); | ||
581 | let assists = ide_assists::assists(db, assist_config, resolve, frange); | ||
580 | 582 | ||
581 | let mut res = Assist::get(db, assist_config, resolve, frange); | 583 | let mut res = diagnostic_assists; |
582 | res.extend(ssr_assists.into_iter()); | 584 | res.extend(ssr_assists.into_iter()); |
583 | res.extend(diagnostic_assists.into_iter()); | 585 | res.extend(assists.into_iter()); |
584 | 586 | ||
585 | res | 587 | res |
586 | }) | 588 | }) |
@@ -593,14 +595,14 @@ impl Analysis { | |||
593 | position: FilePosition, | 595 | position: FilePosition, |
594 | new_name: &str, | 596 | new_name: &str, |
595 | ) -> Cancellable<Result<SourceChange, RenameError>> { | 597 | ) -> Cancellable<Result<SourceChange, RenameError>> { |
596 | self.with_db(|db| references::rename::rename(db, position, new_name)) | 598 | self.with_db(|db| rename::rename(db, position, new_name)) |
597 | } | 599 | } |
598 | 600 | ||
599 | pub fn prepare_rename( | 601 | pub fn prepare_rename( |
600 | &self, | 602 | &self, |
601 | position: FilePosition, | 603 | position: FilePosition, |
602 | ) -> Cancellable<Result<RangeInfo<()>, RenameError>> { | 604 | ) -> Cancellable<Result<RangeInfo<()>, RenameError>> { |
603 | self.with_db(|db| references::rename::prepare_rename(db, position)) | 605 | self.with_db(|db| rename::prepare_rename(db, position)) |
604 | } | 606 | } |
605 | 607 | ||
606 | pub fn will_rename_file( | 608 | pub fn will_rename_file( |
@@ -608,7 +610,7 @@ impl Analysis { | |||
608 | file_id: FileId, | 610 | file_id: FileId, |
609 | new_name_stem: &str, | 611 | new_name_stem: &str, |
610 | ) -> Cancellable<Option<SourceChange>> { | 612 | ) -> Cancellable<Option<SourceChange>> { |
611 | self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem)) | 613 | self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem)) |
612 | } | 614 | } |
613 | 615 | ||
614 | pub fn structural_search_replace( | 616 | pub fn structural_search_replace( |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index a0fdead2c..5808562a7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -9,8 +9,6 @@ | |||
9 | //! at the index that the match starts at and its tree parent is | 9 | //! at the index that the match starts at and its tree parent is |
10 | //! resolved to the search element definition, we get a reference. | 10 | //! resolved to the search element definition, we get a reference. |
11 | 11 | ||
12 | pub(crate) mod rename; | ||
13 | |||
14 | use hir::{PathResolution, Semantics}; | 12 | use hir::{PathResolution, Semantics}; |
15 | use ide_db::{ | 13 | use ide_db::{ |
16 | base_db::FileId, | 14 | base_db::FileId, |
@@ -81,8 +79,7 @@ pub(crate) fn find_all_refs( | |||
81 | }); | 79 | }); |
82 | usages.references.retain(|_, it| !it.is_empty()); | 80 | usages.references.retain(|_, it| !it.is_empty()); |
83 | } | 81 | } |
84 | Definition::ModuleDef(hir::ModuleDef::Adt(_)) | 82 | Definition::ModuleDef(hir::ModuleDef::Adt(_) | hir::ModuleDef::Variant(_)) => { |
85 | | Definition::ModuleDef(hir::ModuleDef::Variant(_)) => { | ||
86 | refs.for_each(|it| { | 83 | refs.for_each(|it| { |
87 | it.retain(|reference| { | 84 | it.retain(|reference| { |
88 | reference.name.as_name_ref().map_or(false, is_lit_name_ref) | 85 | reference.name.as_name_ref().map_or(false, is_lit_name_ref) |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/rename.rs index 50cc1f963..96bd07708 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/rename.rs | |||
@@ -1,45 +1,25 @@ | |||
1 | //! Renaming functionality | 1 | //! Renaming functionality. |
2 | //! | 2 | //! |
3 | //! All reference and file rename requests go through here where the corresponding [`SourceChange`]s | 3 | //! This is mostly front-end for [`ide_db::rename`], but it also includes the |
4 | //! will be calculated. | 4 | //! tests. This module also implements a couple of magic tricks, like renaming |
5 | use std::fmt::{self, Display}; | 5 | //! `self` and to `self` (to switch between associated function and method). |
6 | 6 | use hir::{AsAssocItem, InFile, Semantics}; | |
7 | use either::Either; | ||
8 | use hir::{AsAssocItem, InFile, Module, ModuleDef, ModuleSource, Semantics}; | ||
9 | use ide_db::{ | 7 | use ide_db::{ |
10 | base_db::{AnchoredPathBuf, FileId}, | 8 | base_db::FileId, |
11 | defs::{Definition, NameClass, NameRefClass}, | 9 | defs::{Definition, NameClass, NameRefClass}, |
12 | search::FileReference, | 10 | rename::{bail, format_err, source_edit_from_references, IdentifierKind}, |
13 | RootDatabase, | 11 | RootDatabase, |
14 | }; | 12 | }; |
15 | use stdx::never; | 13 | use stdx::{always, never}; |
16 | use syntax::{ | 14 | use syntax::{ast, AstNode, SyntaxNode}; |
17 | ast::{self, NameOwner}, | ||
18 | lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, | ||
19 | }; | ||
20 | 15 | ||
21 | use text_edit::TextEdit; | 16 | use text_edit::TextEdit; |
22 | 17 | ||
23 | use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; | 18 | use crate::{FilePosition, RangeInfo, SourceChange}; |
24 | 19 | ||
25 | type RenameResult<T> = Result<T, RenameError>; | 20 | pub use ide_db::rename::RenameError; |
26 | #[derive(Debug)] | ||
27 | pub struct RenameError(String); | ||
28 | 21 | ||
29 | impl fmt::Display for RenameError { | 22 | type RenameResult<T> = Result<T, RenameError>; |
30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
31 | Display::fmt(&self.0, f) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | macro_rules! format_err { | ||
36 | ($fmt:expr) => {RenameError(format!($fmt))}; | ||
37 | ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} | ||
38 | } | ||
39 | |||
40 | macro_rules! bail { | ||
41 | ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))} | ||
42 | } | ||
43 | 23 | ||
44 | /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is | 24 | /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is |
45 | /// being targeted for a rename. | 25 | /// being targeted for a rename. |
@@ -51,27 +31,14 @@ pub(crate) fn prepare_rename( | |||
51 | let source_file = sema.parse(position.file_id); | 31 | let source_file = sema.parse(position.file_id); |
52 | let syntax = source_file.syntax(); | 32 | let syntax = source_file.syntax(); |
53 | 33 | ||
54 | let def = find_definition(&sema, syntax, position)?; | 34 | let (name_like, def) = find_definition(&sema, syntax, position)?; |
55 | match def { | 35 | if def.range_for_rename(&sema).is_none() { |
56 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | 36 | bail!("No references found at position") |
57 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), | 37 | } |
58 | Definition::ModuleDef(ModuleDef::Module(_)) => (), | 38 | |
59 | _ => { | 39 | let frange = sema.original_range(name_like.syntax()); |
60 | let nav = def | 40 | always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id); |
61 | .try_to_nav(sema.db) | 41 | Ok(RangeInfo::new(frange.range, ())) |
62 | .ok_or_else(|| format_err!("No references found at position"))?; | ||
63 | nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
64 | } | ||
65 | }; | ||
66 | let name_like = sema | ||
67 | .find_node_at_offset_with_descend(syntax, position.offset) | ||
68 | .ok_or_else(|| format_err!("No references found at position"))?; | ||
69 | let node = match &name_like { | ||
70 | ast::NameLike::Name(it) => it.syntax(), | ||
71 | ast::NameLike::NameRef(it) => it.syntax(), | ||
72 | ast::NameLike::Lifetime(it) => it.syntax(), | ||
73 | }; | ||
74 | Ok(RangeInfo::new(sema.original_range(node).range, ())) | ||
75 | } | 42 | } |
76 | 43 | ||
77 | // Feature: Rename | 44 | // Feature: Rename |
@@ -91,24 +58,23 @@ pub(crate) fn rename( | |||
91 | new_name: &str, | 58 | new_name: &str, |
92 | ) -> RenameResult<SourceChange> { | 59 | ) -> RenameResult<SourceChange> { |
93 | let sema = Semantics::new(db); | 60 | let sema = Semantics::new(db); |
94 | rename_with_semantics(&sema, position, new_name) | ||
95 | } | ||
96 | |||
97 | pub(crate) fn rename_with_semantics( | ||
98 | sema: &Semantics<RootDatabase>, | ||
99 | position: FilePosition, | ||
100 | new_name: &str, | ||
101 | ) -> RenameResult<SourceChange> { | ||
102 | let source_file = sema.parse(position.file_id); | 61 | let source_file = sema.parse(position.file_id); |
103 | let syntax = source_file.syntax(); | 62 | let syntax = source_file.syntax(); |
104 | 63 | ||
105 | let def = find_definition(sema, syntax, position)?; | 64 | let (_name_like, def) = find_definition(&sema, syntax, position)?; |
106 | match def { | 65 | |
107 | Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(sema, module, new_name), | 66 | if let Definition::Local(local) = def { |
108 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | 67 | if let Some(self_param) = local.as_self_param(sema.db) { |
109 | Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), | 68 | cov_mark::hit!(rename_self_to_param); |
110 | def => rename_reference(sema, def, new_name), | 69 | return rename_self_to_param(&sema, local, self_param, new_name); |
70 | } | ||
71 | if new_name == "self" { | ||
72 | cov_mark::hit!(rename_to_self); | ||
73 | return rename_to_self(&sema, local); | ||
74 | } | ||
111 | } | 75 | } |
76 | |||
77 | def.rename(&sema, new_name) | ||
112 | } | 78 | } |
113 | 79 | ||
114 | /// Called by the client when it is about to rename a file. | 80 | /// Called by the client when it is about to rename a file. |
@@ -119,47 +85,22 @@ pub(crate) fn will_rename_file( | |||
119 | ) -> Option<SourceChange> { | 85 | ) -> Option<SourceChange> { |
120 | let sema = Semantics::new(db); | 86 | let sema = Semantics::new(db); |
121 | let module = sema.to_module_def(file_id)?; | 87 | let module = sema.to_module_def(file_id)?; |
122 | let mut change = rename_mod(&sema, module, new_name_stem).ok()?; | 88 | let def = Definition::ModuleDef(module.into()); |
89 | let mut change = def.rename(&sema, new_name_stem).ok()?; | ||
123 | change.file_system_edits.clear(); | 90 | change.file_system_edits.clear(); |
124 | Some(change) | 91 | Some(change) |
125 | } | 92 | } |
126 | 93 | ||
127 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
128 | enum IdentifierKind { | ||
129 | Ident, | ||
130 | Lifetime, | ||
131 | ToSelf, | ||
132 | Underscore, | ||
133 | } | ||
134 | |||
135 | fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> { | ||
136 | match lex_single_syntax_kind(new_name) { | ||
137 | Some(res) => match res { | ||
138 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
139 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
140 | (T![self], _) => Ok(IdentifierKind::ToSelf), | ||
141 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
142 | Ok(IdentifierKind::Lifetime) | ||
143 | } | ||
144 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
145 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) | ||
146 | } | ||
147 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
148 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
149 | }, | ||
150 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fn find_definition( | 94 | fn find_definition( |
155 | sema: &Semantics<RootDatabase>, | 95 | sema: &Semantics<RootDatabase>, |
156 | syntax: &SyntaxNode, | 96 | syntax: &SyntaxNode, |
157 | position: FilePosition, | 97 | position: FilePosition, |
158 | ) -> RenameResult<Definition> { | 98 | ) -> RenameResult<(ast::NameLike, Definition)> { |
159 | match sema | 99 | let name_like = sema |
160 | .find_node_at_offset_with_descend(syntax, position.offset) | 100 | .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset) |
161 | .ok_or_else(|| format_err!("No references found at position"))? | 101 | .ok_or_else(|| format_err!("No references found at position"))?; |
162 | { | 102 | |
103 | let def = match &name_like { | ||
163 | // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet | 104 | // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet |
164 | ast::NameLike::Name(name) | 105 | ast::NameLike::Name(name) |
165 | if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => | 106 | if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => |
@@ -189,146 +130,9 @@ fn find_definition( | |||
189 | .map(|it| it.referenced_or_defined(sema.db)) | 130 | .map(|it| it.referenced_or_defined(sema.db)) |
190 | }), | 131 | }), |
191 | } | 132 | } |
192 | .ok_or_else(|| format_err!("No references found at position")) | 133 | .ok_or_else(|| format_err!("No references found at position"))?; |
193 | } | ||
194 | |||
195 | fn rename_mod( | ||
196 | sema: &Semantics<RootDatabase>, | ||
197 | module: Module, | ||
198 | new_name: &str, | ||
199 | ) -> RenameResult<SourceChange> { | ||
200 | if IdentifierKind::Ident != check_identifier(new_name)? { | ||
201 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | ||
202 | } | ||
203 | |||
204 | let mut source_change = SourceChange::default(); | ||
205 | |||
206 | let InFile { file_id, value: def_source } = module.definition_source(sema.db); | ||
207 | let file_id = file_id.original_file(sema.db); | ||
208 | if let ModuleSource::SourceFile(..) = def_source { | ||
209 | // mod is defined in path/to/dir/mod.rs | ||
210 | let path = if module.is_mod_rs(sema.db) { | ||
211 | format!("../{}/mod.rs", new_name) | ||
212 | } else { | ||
213 | format!("{}.rs", new_name) | ||
214 | }; | ||
215 | let dst = AnchoredPathBuf { anchor: file_id, path }; | ||
216 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | ||
217 | source_change.push_file_system_edit(move_file); | ||
218 | } | ||
219 | |||
220 | if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) { | ||
221 | let file_id = file_id.original_file(sema.db); | ||
222 | match decl_source.name() { | ||
223 | Some(name) => source_change.insert_source_edit( | ||
224 | file_id, | ||
225 | TextEdit::replace(name.syntax().text_range(), new_name.to_string()), | ||
226 | ), | ||
227 | _ => never!("Module source node is missing a name"), | ||
228 | } | ||
229 | } | ||
230 | let def = Definition::ModuleDef(ModuleDef::Module(module)); | ||
231 | let usages = def.usages(sema).all(); | ||
232 | let ref_edits = usages.iter().map(|(&file_id, references)| { | ||
233 | (file_id, source_edit_from_references(references, def, new_name)) | ||
234 | }); | ||
235 | source_change.extend(ref_edits); | ||
236 | 134 | ||
237 | Ok(source_change) | 135 | Ok((name_like, def)) |
238 | } | ||
239 | |||
240 | fn rename_reference( | ||
241 | sema: &Semantics<RootDatabase>, | ||
242 | mut def: Definition, | ||
243 | new_name: &str, | ||
244 | ) -> RenameResult<SourceChange> { | ||
245 | let ident_kind = check_identifier(new_name)?; | ||
246 | |||
247 | if matches!( | ||
248 | def, // is target a lifetime? | ||
249 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
250 | ) { | ||
251 | match ident_kind { | ||
252 | IdentifierKind::Ident | IdentifierKind::ToSelf | IdentifierKind::Underscore => { | ||
253 | cov_mark::hit!(rename_not_a_lifetime_ident_ref); | ||
254 | bail!("Invalid name `{}`: not a lifetime identifier", new_name); | ||
255 | } | ||
256 | IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime), | ||
257 | } | ||
258 | } else { | ||
259 | match (ident_kind, def) { | ||
260 | (IdentifierKind::Lifetime, _) => { | ||
261 | cov_mark::hit!(rename_not_an_ident_ref); | ||
262 | bail!("Invalid name `{}`: not an identifier", new_name); | ||
263 | } | ||
264 | (IdentifierKind::ToSelf, Definition::Local(local)) => { | ||
265 | if local.is_self(sema.db) { | ||
266 | // no-op | ||
267 | cov_mark::hit!(rename_self_to_self); | ||
268 | return Ok(SourceChange::default()); | ||
269 | } else { | ||
270 | cov_mark::hit!(rename_to_self); | ||
271 | return rename_to_self(sema, local); | ||
272 | } | ||
273 | } | ||
274 | (ident_kind, Definition::Local(local)) => { | ||
275 | if let Some(self_param) = local.as_self_param(sema.db) { | ||
276 | cov_mark::hit!(rename_self_to_param); | ||
277 | return rename_self_to_param(sema, local, self_param, new_name, ident_kind); | ||
278 | } else { | ||
279 | cov_mark::hit!(rename_local); | ||
280 | } | ||
281 | } | ||
282 | (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
283 | (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local), | ||
284 | (IdentifierKind::Underscore, _) => (), | ||
285 | } | ||
286 | } | ||
287 | |||
288 | def = match def { | ||
289 | // HACK: resolve trait impl items to the item def of the trait definition | ||
290 | // so that we properly resolve all trait item references | ||
291 | Definition::ModuleDef(mod_def) => mod_def | ||
292 | .as_assoc_item(sema.db) | ||
293 | .and_then(|it| it.containing_trait_impl(sema.db)) | ||
294 | .and_then(|it| { | ||
295 | it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) { | ||
296 | (hir::AssocItem::Function(trait_func), ModuleDef::Function(func)) | ||
297 | if trait_func.name(sema.db) == func.name(sema.db) => | ||
298 | { | ||
299 | Some(Definition::ModuleDef(ModuleDef::Function(trait_func))) | ||
300 | } | ||
301 | (hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst)) | ||
302 | if trait_konst.name(sema.db) == konst.name(sema.db) => | ||
303 | { | ||
304 | Some(Definition::ModuleDef(ModuleDef::Const(trait_konst))) | ||
305 | } | ||
306 | ( | ||
307 | hir::AssocItem::TypeAlias(trait_type_alias), | ||
308 | ModuleDef::TypeAlias(type_alias), | ||
309 | ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { | ||
310 | Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias))) | ||
311 | } | ||
312 | _ => None, | ||
313 | }) | ||
314 | }) | ||
315 | .unwrap_or(def), | ||
316 | _ => def, | ||
317 | }; | ||
318 | let usages = def.usages(sema).all(); | ||
319 | |||
320 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | ||
321 | cov_mark::hit!(rename_underscore_multiple); | ||
322 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
323 | } | ||
324 | let mut source_change = SourceChange::default(); | ||
325 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
326 | (file_id, source_edit_from_references(references, def, new_name)) | ||
327 | })); | ||
328 | |||
329 | let (file_id, edit) = source_edit_from_def(sema, def, new_name)?; | ||
330 | source_change.insert_source_edit(file_id, edit); | ||
331 | Ok(source_change) | ||
332 | } | 136 | } |
333 | 137 | ||
334 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { | 138 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { |
@@ -398,8 +202,15 @@ fn rename_self_to_param( | |||
398 | local: hir::Local, | 202 | local: hir::Local, |
399 | self_param: hir::SelfParam, | 203 | self_param: hir::SelfParam, |
400 | new_name: &str, | 204 | new_name: &str, |
401 | identifier_kind: IdentifierKind, | ||
402 | ) -> RenameResult<SourceChange> { | 205 | ) -> RenameResult<SourceChange> { |
206 | if new_name == "self" { | ||
207 | // Let's do nothing rather than complain. | ||
208 | cov_mark::hit!(rename_self_to_self); | ||
209 | return Ok(SourceChange::default()); | ||
210 | } | ||
211 | |||
212 | let identifier_kind = IdentifierKind::classify(new_name)?; | ||
213 | |||
403 | let InFile { file_id, value: self_param } = | 214 | let InFile { file_id, value: self_param } = |
404 | self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?; | 215 | self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?; |
405 | 216 | ||
@@ -441,150 +252,6 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt | |||
441 | Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) | 252 | Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) |
442 | } | 253 | } |
443 | 254 | ||
444 | fn source_edit_from_references( | ||
445 | references: &[FileReference], | ||
446 | def: Definition, | ||
447 | new_name: &str, | ||
448 | ) -> TextEdit { | ||
449 | let mut edit = TextEdit::builder(); | ||
450 | for reference in references { | ||
451 | let (range, replacement) = match &reference.name { | ||
452 | // if the ranges differ then the node is inside a macro call, we can't really attempt | ||
453 | // to make special rewrites like shorthand syntax and such, so just rename the node in | ||
454 | // the macro input | ||
455 | ast::NameLike::NameRef(name_ref) | ||
456 | if name_ref.syntax().text_range() == reference.range => | ||
457 | { | ||
458 | source_edit_from_name_ref(name_ref, new_name, def) | ||
459 | } | ||
460 | ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { | ||
461 | source_edit_from_name(name, new_name) | ||
462 | } | ||
463 | _ => None, | ||
464 | } | ||
465 | .unwrap_or_else(|| (reference.range, new_name.to_string())); | ||
466 | edit.replace(range, replacement); | ||
467 | } | ||
468 | edit.finish() | ||
469 | } | ||
470 | |||
471 | fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> { | ||
472 | if let Some(_) = ast::RecordPatField::for_field_name(name) { | ||
473 | if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
474 | return Some(( | ||
475 | TextRange::empty(ident_pat.syntax().text_range().start()), | ||
476 | [new_name, ": "].concat(), | ||
477 | )); | ||
478 | } | ||
479 | } | ||
480 | None | ||
481 | } | ||
482 | |||
483 | fn source_edit_from_name_ref( | ||
484 | name_ref: &ast::NameRef, | ||
485 | new_name: &str, | ||
486 | def: Definition, | ||
487 | ) -> Option<(TextRange, String)> { | ||
488 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { | ||
489 | let rcf_name_ref = record_field.name_ref(); | ||
490 | let rcf_expr = record_field.expr(); | ||
491 | match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) { | ||
492 | // field: init-expr, check if we can use a field init shorthand | ||
493 | (Some(field_name), Some(init)) => { | ||
494 | if field_name == *name_ref { | ||
495 | if init.text() == new_name { | ||
496 | cov_mark::hit!(test_rename_field_put_init_shorthand); | ||
497 | // same names, we can use a shorthand here instead. | ||
498 | // we do not want to erase attributes hence this range start | ||
499 | let s = field_name.syntax().text_range().start(); | ||
500 | let e = record_field.syntax().text_range().end(); | ||
501 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
502 | } | ||
503 | } else if init == *name_ref { | ||
504 | if field_name.text() == new_name { | ||
505 | cov_mark::hit!(test_rename_local_put_init_shorthand); | ||
506 | // same names, we can use a shorthand here instead. | ||
507 | // we do not want to erase attributes hence this range start | ||
508 | let s = field_name.syntax().text_range().start(); | ||
509 | let e = record_field.syntax().text_range().end(); | ||
510 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
511 | } | ||
512 | } | ||
513 | None | ||
514 | } | ||
515 | // init shorthand | ||
516 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | ||
517 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | ||
518 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { | ||
519 | cov_mark::hit!(test_rename_field_in_field_shorthand); | ||
520 | let s = name_ref.syntax().text_range().start(); | ||
521 | Some((TextRange::empty(s), format!("{}: ", new_name))) | ||
522 | } | ||
523 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { | ||
524 | cov_mark::hit!(test_rename_local_in_field_shorthand); | ||
525 | let s = name_ref.syntax().text_range().end(); | ||
526 | Some((TextRange::empty(s), format!(": {}", new_name))) | ||
527 | } | ||
528 | _ => None, | ||
529 | } | ||
530 | } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { | ||
531 | let rcf_name_ref = record_field.name_ref(); | ||
532 | let rcf_pat = record_field.pat(); | ||
533 | match (rcf_name_ref, rcf_pat) { | ||
534 | // field: rename | ||
535 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { | ||
536 | // field name is being renamed | ||
537 | if pat.name().map_or(false, |it| it.text() == new_name) { | ||
538 | cov_mark::hit!(test_rename_field_put_init_shorthand_pat); | ||
539 | // same names, we can use a shorthand here instead/ | ||
540 | // we do not want to erase attributes hence this range start | ||
541 | let s = field_name.syntax().text_range().start(); | ||
542 | let e = record_field.syntax().text_range().end(); | ||
543 | Some((TextRange::new(s, e), pat.to_string())) | ||
544 | } else { | ||
545 | None | ||
546 | } | ||
547 | } | ||
548 | _ => None, | ||
549 | } | ||
550 | } else { | ||
551 | None | ||
552 | } | ||
553 | } | ||
554 | |||
555 | fn source_edit_from_def( | ||
556 | sema: &Semantics<RootDatabase>, | ||
557 | def: Definition, | ||
558 | new_name: &str, | ||
559 | ) -> RenameResult<(FileId, TextEdit)> { | ||
560 | let nav = | ||
561 | def.try_to_nav(sema.db).ok_or_else(|| format_err!("No references found at position"))?; | ||
562 | |||
563 | let mut replacement_text = String::new(); | ||
564 | let mut repl_range = | ||
565 | nav.focus_range.ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
566 | if let Definition::Local(local) = def { | ||
567 | if let Either::Left(pat) = local.source(sema.db).value { | ||
568 | if matches!( | ||
569 | pat.syntax().parent().and_then(ast::RecordPatField::cast), | ||
570 | Some(pat_field) if pat_field.name_ref().is_none() | ||
571 | ) { | ||
572 | replacement_text.push_str(": "); | ||
573 | replacement_text.push_str(new_name); | ||
574 | repl_range = TextRange::new( | ||
575 | pat.syntax().text_range().end(), | ||
576 | pat.syntax().text_range().end(), | ||
577 | ); | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | if replacement_text.is_empty() { | ||
582 | replacement_text.push_str(new_name); | ||
583 | } | ||
584 | let edit = TextEdit::replace(repl_range, replacement_text); | ||
585 | Ok((nav.file_id, edit)) | ||
586 | } | ||
587 | |||
588 | #[cfg(test)] | 255 | #[cfg(test)] |
589 | mod tests { | 256 | mod tests { |
590 | use expect_test::{expect, Expect}; | 257 | use expect_test::{expect, Expect}; |
@@ -691,7 +358,7 @@ fn baz() { | |||
691 | x.0$0 = 5; | 358 | x.0$0 = 5; |
692 | } | 359 | } |
693 | "#, | 360 | "#, |
694 | expect![[r#"No identifier available to rename"#]], | 361 | expect![[r#"No references found at position"#]], |
695 | ); | 362 | ); |
696 | } | 363 | } |
697 | 364 | ||
@@ -703,7 +370,7 @@ fn foo() { | |||
703 | let x: i32$0 = 0; | 370 | let x: i32$0 = 0; |
704 | } | 371 | } |
705 | "#, | 372 | "#, |
706 | expect![[r#"Cannot rename builtin type"#]], | 373 | expect![[r#"No references found at position"#]], |
707 | ); | 374 | ); |
708 | } | 375 | } |
709 | 376 | ||
@@ -719,7 +386,7 @@ impl Foo { | |||
719 | } | 386 | } |
720 | } | 387 | } |
721 | "#, | 388 | "#, |
722 | expect![[r#"Cannot rename `Self`"#]], | 389 | expect![[r#"No references found at position"#]], |
723 | ); | 390 | ); |
724 | } | 391 | } |
725 | 392 | ||
@@ -801,7 +468,6 @@ impl Foo { | |||
801 | 468 | ||
802 | #[test] | 469 | #[test] |
803 | fn test_rename_for_local() { | 470 | fn test_rename_for_local() { |
804 | cov_mark::check!(rename_local); | ||
805 | check( | 471 | check( |
806 | "k", | 472 | "k", |
807 | r#" | 473 | r#" |
@@ -2101,4 +1767,22 @@ fn f() { <()>::BAR$0; }"#, | |||
2101 | res, | 1767 | res, |
2102 | ); | 1768 | ); |
2103 | } | 1769 | } |
1770 | |||
1771 | #[test] | ||
1772 | fn macros_are_broken_lol() { | ||
1773 | cov_mark::check!(macros_are_broken_lol); | ||
1774 | check( | ||
1775 | "lol", | ||
1776 | r#" | ||
1777 | macro_rules! m { () => { fn f() {} } } | ||
1778 | m!(); | ||
1779 | fn main() { f$0() } | ||
1780 | "#, | ||
1781 | r#" | ||
1782 | macro_rules! m { () => { fn f() {} } } | ||
1783 | lol | ||
1784 | fn main() { lol() } | ||
1785 | "#, | ||
1786 | ) | ||
1787 | } | ||
2104 | } | 1788 | } |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index e186b82b7..d44a1b45f 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -294,7 +294,7 @@ fn traverse( | |||
294 | Some(parent) => { | 294 | Some(parent) => { |
295 | // We only care Name and Name_ref | 295 | // We only care Name and Name_ref |
296 | match (token.kind(), parent.kind()) { | 296 | match (token.kind(), parent.kind()) { |
297 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 297 | (IDENT, NAME | NAME_REF) => parent.into(), |
298 | _ => token.into(), | 298 | _ => token.into(), |
299 | } | 299 | } |
300 | } | 300 | } |
@@ -310,7 +310,7 @@ fn traverse( | |||
310 | Some(parent) => { | 310 | Some(parent) => { |
311 | // We only care Name and Name_ref | 311 | // We only care Name and Name_ref |
312 | match (token.kind(), parent.kind()) { | 312 | match (token.kind(), parent.kind()) { |
313 | (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(), | 313 | (IDENT, NAME | NAME_REF) => parent.into(), |
314 | _ => token.into(), | 314 | _ => token.into(), |
315 | } | 315 | } |
316 | } | 316 | } |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 7a53268e8..6834fe11a 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -48,7 +48,13 @@ pub(super) fn element( | |||
48 | match name_kind { | 48 | match name_kind { |
49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), | 49 | Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), |
50 | Some(NameClass::Definition(def)) => { | 50 | Some(NameClass::Definition(def)) => { |
51 | highlight_def(db, krate, def) | HlMod::Definition | 51 | let mut h = highlight_def(db, krate, def) | HlMod::Definition; |
52 | if let Definition::ModuleDef(hir::ModuleDef::Trait(trait_)) = &def { | ||
53 | if trait_.is_unsafe(db) { | ||
54 | h |= HlMod::Unsafe; | ||
55 | } | ||
56 | } | ||
57 | h | ||
52 | } | 58 | } |
53 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), | 59 | Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def), |
54 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { | 60 | Some(NameClass::PatFieldShorthand { field_ref, .. }) => { |
@@ -87,20 +93,34 @@ pub(super) fn element( | |||
87 | 93 | ||
88 | let mut h = highlight_def(db, krate, def); | 94 | let mut h = highlight_def(db, krate, def); |
89 | 95 | ||
90 | if let Definition::Local(local) = &def { | 96 | match def { |
91 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | 97 | Definition::Local(local) |
98 | if is_consumed_lvalue( | ||
99 | name_ref.syntax().clone().into(), | ||
100 | &local, | ||
101 | db, | ||
102 | ) => | ||
103 | { | ||
92 | h |= HlMod::Consuming; | 104 | h |= HlMod::Consuming; |
93 | } | 105 | } |
94 | } | 106 | Definition::ModuleDef(hir::ModuleDef::Trait(trait_)) |
95 | 107 | if trait_.is_unsafe(db) => | |
96 | if let Some(parent) = name_ref.syntax().parent() { | 108 | { |
97 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | 109 | if ast::Impl::for_trait_name_ref(&name_ref).is_some() { |
98 | if let Definition::Field(field) = def { | 110 | h |= HlMod::Unsafe; |
99 | if let hir::VariantDef::Union(_) = field.parent_def(db) { | 111 | } |
100 | h |= HlMod::Unsafe; | 112 | } |
113 | Definition::Field(field) => { | ||
114 | if let Some(parent) = name_ref.syntax().parent() { | ||
115 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | ||
116 | if let hir::VariantDef::Union(_) = field.parent_def(db) | ||
117 | { | ||
118 | h |= HlMod::Unsafe; | ||
119 | } | ||
101 | } | 120 | } |
102 | } | 121 | } |
103 | } | 122 | } |
123 | _ => (), | ||
104 | } | 124 | } |
105 | 125 | ||
106 | h | 126 | h |
@@ -354,15 +374,7 @@ fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) | |||
354 | 374 | ||
355 | h | 375 | h |
356 | } | 376 | } |
357 | hir::ModuleDef::Trait(trait_) => { | 377 | hir::ModuleDef::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)), |
358 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); | ||
359 | |||
360 | if trait_.is_unsafe(db) { | ||
361 | h |= HlMod::Unsafe; | ||
362 | } | ||
363 | |||
364 | h | ||
365 | } | ||
366 | hir::ModuleDef::TypeAlias(type_) => { | 378 | hir::ModuleDef::TypeAlias(type_) => { |
367 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); | 379 | let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); |
368 | 380 | ||
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 478facfee..21376a7ae 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -67,6 +67,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
67 | .field { color: #94BFF3; } | 67 | .field { color: #94BFF3; } |
68 | .function { color: #93E0E3; } | 68 | .function { color: #93E0E3; } |
69 | .function.unsafe { color: #BC8383; } | 69 | .function.unsafe { color: #BC8383; } |
70 | .trait.unsafe { color: #BC8383; } | ||
70 | .operator.unsafe { color: #BC8383; } | 71 | .operator.unsafe { color: #BC8383; } |
71 | .parameter { color: #94BFF3; } | 72 | .parameter { color: #94BFF3; } |
72 | .text { color: #DCDCCC; } | 73 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index a0ea1db34..4e85f7c0b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 921a956e6..79a285107 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index ca9bb1e7d..13f589cc0 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 6202a03ce..50df376ae 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index e860d713e..96cb09642 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 68165bdbf..55453468b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
@@ -61,6 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
61 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> | 62 | <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span> |
62 | <span class="brace">}</span> | 63 | <span class="brace">}</span> |
63 | 64 | ||
65 | <span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">UnsafeTrait</span> <span class="brace">{</span><span class="brace">}</span> | ||
66 | <span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="struct">Packed</span> <span class="brace">{</span><span class="brace">}</span> | ||
67 | |||
68 | <span class="keyword">fn</span> <span class="function declaration">require_unsafe_trait</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">></span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
69 | |||
64 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> | 70 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> |
65 | <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> | 71 | <span class="keyword">fn</span> <span class="function associated declaration trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> |
66 | <span class="brace">}</span> | 72 | <span class="brace">}</span> |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 59f1e8e4c..9232cf905 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html index 9ab46d05c..082837328 100644 --- a/crates/ide/src/syntax_highlighting/test_data/injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index 666b0b228..763917714 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -15,6 +15,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
15 | .field { color: #94BFF3; } | 15 | .field { color: #94BFF3; } |
16 | .function { color: #93E0E3; } | 16 | .function { color: #93E0E3; } |
17 | .function.unsafe { color: #BC8383; } | 17 | .function.unsafe { color: #BC8383; } |
18 | .trait.unsafe { color: #BC8383; } | ||
18 | .operator.unsafe { color: #BC8383; } | 19 | .operator.unsafe { color: #BC8383; } |
19 | .parameter { color: #94BFF3; } | 20 | .parameter { color: #94BFF3; } |
20 | .text { color: #DCDCCC; } | 21 | .text { color: #DCDCCC; } |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index f7d8334a0..4f0b1ce85 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -527,6 +527,11 @@ struct Packed { | |||
527 | a: u16, | 527 | a: u16, |
528 | } | 528 | } |
529 | 529 | ||
530 | unsafe trait UnsafeTrait {} | ||
531 | unsafe impl UnsafeTrait for Packed {} | ||
532 | |||
533 | fn require_unsafe_trait<T: UnsafeTrait>(_: T) {} | ||
534 | |||
530 | trait DoTheAutoref { | 535 | trait DoTheAutoref { |
531 | fn calls_autoref(&self); | 536 | fn calls_autoref(&self); |
532 | } | 537 | } |
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 4ad49eca0..37ae92350 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs | |||
@@ -23,7 +23,7 @@ use syntax::{ | |||
23 | algo::find_node_at_offset, | 23 | algo::find_node_at_offset, |
24 | ast::{self, edit::IndentLevel, AstToken}, | 24 | ast::{self, edit::IndentLevel, AstToken}, |
25 | AstNode, Parse, SourceFile, | 25 | AstNode, Parse, SourceFile, |
26 | SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, | 26 | SyntaxKind::{self, FIELD_EXPR, METHOD_CALL_EXPR}, |
27 | TextRange, TextSize, | 27 | TextRange, TextSize, |
28 | }; | 28 | }; |
29 | 29 | ||
@@ -95,9 +95,16 @@ fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option< | |||
95 | } | 95 | } |
96 | 96 | ||
97 | let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; | 97 | let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; |
98 | if brace_token.kind() != SyntaxKind::L_CURLY { | ||
99 | return None; | ||
100 | } | ||
98 | 101 | ||
99 | // Remove the `{` to get a better parse tree, and reparse | 102 | // Remove the `{` to get a better parse tree, and reparse. |
100 | let file = file.reparse(&Indel::delete(brace_token.text_range())); | 103 | let range = brace_token.text_range(); |
104 | if !stdx::always!(range.len() == TextSize::of('{')) { | ||
105 | return None; | ||
106 | } | ||
107 | let file = file.reparse(&Indel::delete(range)); | ||
101 | 108 | ||
102 | if let Some(edit) = brace_expr(&file.tree(), offset) { | 109 | if let Some(edit) = brace_expr(&file.tree(), offset) { |
103 | return Some(edit); | 110 | return Some(edit); |
@@ -550,6 +557,29 @@ fn f() { | |||
550 | } | 557 | } |
551 | 558 | ||
552 | #[test] | 559 | #[test] |
560 | fn noop_in_string_literal() { | ||
561 | // Regression test for #9351 | ||
562 | type_char_noop( | ||
563 | '{', | ||
564 | r##" | ||
565 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
566 | let base = r#" | ||
567 | enum E { T(), R$0, C } | ||
568 | use self::E::X; | ||
569 | const Z: E = E::C; | ||
570 | mod m {} | ||
571 | asdasdasdasdasdasda | ||
572 | sdasdasdasdasdasda | ||
573 | sdasdasdasdasd | ||
574 | "#; | ||
575 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
576 | expect.assert_eq(&actual) | ||
577 | } | ||
578 | "##, | ||
579 | ); | ||
580 | } | ||
581 | |||
582 | #[test] | ||
553 | fn adds_closing_brace_for_use_tree() { | 583 | fn adds_closing_brace_for_use_tree() { |
554 | type_char( | 584 | type_char( |
555 | '{', | 585 | '{', |
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs index c93959e66..e2bd6e456 100644 --- a/crates/ide_assists/src/handlers/apply_demorgan.rs +++ b/crates/ide_assists/src/handlers/apply_demorgan.rs | |||
@@ -147,74 +147,92 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | |||
147 | 147 | ||
148 | #[cfg(test)] | 148 | #[cfg(test)] |
149 | mod tests { | 149 | mod tests { |
150 | use ide_db::helpers::FamousDefs; | ||
151 | |||
152 | use super::*; | ||
153 | |||
154 | use crate::tests::{check_assist, check_assist_not_applicable}; | 150 | use crate::tests::{check_assist, check_assist_not_applicable}; |
155 | 151 | ||
156 | const ORDABLE_FIXTURE: &'static str = r" | 152 | use super::*; |
157 | //- /lib.rs deps:core crate:ordable | ||
158 | struct NonOrderable; | ||
159 | struct Orderable; | ||
160 | impl core::cmp::Ord for Orderable {} | ||
161 | "; | ||
162 | |||
163 | fn check(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
164 | let before = &format!( | ||
165 | "//- /main.rs crate:main deps:core,ordable\n{}\n{}{}", | ||
166 | ra_fixture_before, | ||
167 | FamousDefs::FIXTURE, | ||
168 | ORDABLE_FIXTURE | ||
169 | ); | ||
170 | check_assist(apply_demorgan, before, &format!("{}\n", ra_fixture_after)); | ||
171 | } | ||
172 | 153 | ||
173 | #[test] | 154 | #[test] |
174 | fn demorgan_handles_leq() { | 155 | fn demorgan_handles_leq() { |
175 | check( | 156 | check_assist( |
176 | r"use ordable::Orderable; | 157 | apply_demorgan, |
158 | r#" | ||
159 | //- minicore: ord, derive | ||
160 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | ||
161 | struct S; | ||
162 | |||
177 | fn f() { | 163 | fn f() { |
178 | Orderable < Orderable &&$0 Orderable <= Orderable | 164 | S < S &&$0 S <= S |
179 | }", | 165 | } |
180 | r"use ordable::Orderable; | 166 | "#, |
167 | r#" | ||
168 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | ||
169 | struct S; | ||
170 | |||
181 | fn f() { | 171 | fn f() { |
182 | !(Orderable >= Orderable || Orderable > Orderable) | 172 | !(S >= S || S > S) |
183 | }", | 173 | } |
174 | "#, | ||
184 | ); | 175 | ); |
185 | check( | 176 | |
186 | r"use ordable::NonOrderable; | 177 | check_assist( |
178 | apply_demorgan, | ||
179 | r#" | ||
180 | //- minicore: ord, derive | ||
181 | struct S; | ||
182 | |||
187 | fn f() { | 183 | fn f() { |
188 | NonOrderable < NonOrderable &&$0 NonOrderable <= NonOrderable | 184 | S < S &&$0 S <= S |
189 | }", | 185 | } |
190 | r"use ordable::NonOrderable; | 186 | "#, |
187 | r#" | ||
188 | struct S; | ||
189 | |||
191 | fn f() { | 190 | fn f() { |
192 | !(!(NonOrderable < NonOrderable) || !(NonOrderable <= NonOrderable)) | 191 | !(!(S < S) || !(S <= S)) |
193 | }", | 192 | } |
193 | "#, | ||
194 | ); | 194 | ); |
195 | } | 195 | } |
196 | 196 | ||
197 | #[test] | 197 | #[test] |
198 | fn demorgan_handles_geq() { | 198 | fn demorgan_handles_geq() { |
199 | check( | 199 | check_assist( |
200 | r"use ordable::Orderable; | 200 | apply_demorgan, |
201 | r#" | ||
202 | //- minicore: ord, derive | ||
203 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | ||
204 | struct S; | ||
205 | |||
201 | fn f() { | 206 | fn f() { |
202 | Orderable > Orderable &&$0 Orderable >= Orderable | 207 | S > S &&$0 S >= S |
203 | }", | 208 | } |
204 | r"use ordable::Orderable; | 209 | "#, |
210 | r#" | ||
211 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | ||
212 | struct S; | ||
213 | |||
205 | fn f() { | 214 | fn f() { |
206 | !(Orderable <= Orderable || Orderable < Orderable) | 215 | !(S <= S || S < S) |
207 | }", | 216 | } |
217 | "#, | ||
208 | ); | 218 | ); |
209 | check( | 219 | check_assist( |
210 | r"use ordable::NonOrderable; | 220 | apply_demorgan, |
221 | r#" | ||
222 | //- minicore: ord, derive | ||
223 | struct S; | ||
224 | |||
211 | fn f() { | 225 | fn f() { |
212 | Orderable > Orderable &&$0 Orderable >= Orderable | 226 | S > S &&$0 S >= S |
213 | }", | 227 | } |
214 | r"use ordable::NonOrderable; | 228 | "#, |
229 | r#" | ||
230 | struct S; | ||
231 | |||
215 | fn f() { | 232 | fn f() { |
216 | !(!(Orderable > Orderable) || !(Orderable >= Orderable)) | 233 | !(!(S > S) || !(S >= S)) |
217 | }", | 234 | } |
235 | "#, | ||
218 | ); | 236 | ); |
219 | } | 237 | } |
220 | 238 | ||
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index d4748ef3a..accc345fc 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs | |||
@@ -103,8 +103,9 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
103 | let scope = match scope.clone() { | 103 | let scope = match scope.clone() { |
104 | ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), | 104 | ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), |
105 | ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), | 105 | ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), |
106 | ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), | ||
106 | }; | 107 | }; |
107 | insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); | 108 | insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use); |
108 | }, | 109 | }, |
109 | ); | 110 | ); |
110 | } | 111 | } |
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs index 199e1ad5c..2d8b936cd 100644 --- a/crates/ide_assists/src/handlers/convert_into_to_from.rs +++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs | |||
@@ -6,15 +6,14 @@ use syntax::ast::{self, AstNode, NameOwner}; | |||
6 | 6 | ||
7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
8 | 8 | ||
9 | // FIXME: this should be a diagnostic | ||
10 | |||
9 | // Assist: convert_into_to_from | 11 | // Assist: convert_into_to_from |
10 | // | 12 | // |
11 | // Converts an Into impl to an equivalent From impl. | 13 | // Converts an Into impl to an equivalent From impl. |
12 | // | 14 | // |
13 | // ``` | 15 | // ``` |
14 | // # //- /lib.rs crate:core | 16 | // # //- minicore: from |
15 | // # pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } } | ||
16 | // # //- /lib.rs crate:main deps:core | ||
17 | // # use core::convert::Into; | ||
18 | // impl $0Into<Thing> for usize { | 17 | // impl $0Into<Thing> for usize { |
19 | // fn into(self) -> Thing { | 18 | // fn into(self) -> Thing { |
20 | // Thing { | 19 | // Thing { |
@@ -26,7 +25,6 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
26 | // ``` | 25 | // ``` |
27 | // -> | 26 | // -> |
28 | // ``` | 27 | // ``` |
29 | // # use core::convert::Into; | ||
30 | // impl From<usize> for Thing { | 28 | // impl From<usize> for Thing { |
31 | // fn from(val: usize) -> Self { | 29 | // fn from(val: usize) -> Self { |
32 | // Thing { | 30 | // Thing { |
@@ -114,12 +112,14 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Op | |||
114 | mod tests { | 112 | mod tests { |
115 | use super::*; | 113 | use super::*; |
116 | 114 | ||
117 | use crate::tests::check_assist; | 115 | use crate::tests::{check_assist, check_assist_not_applicable}; |
118 | 116 | ||
119 | #[test] | 117 | #[test] |
120 | fn convert_into_to_from_converts_a_struct() { | 118 | fn convert_into_to_from_converts_a_struct() { |
121 | check_convert_into_to_from( | 119 | check_assist( |
120 | convert_into_to_from, | ||
122 | r#" | 121 | r#" |
122 | //- minicore: from | ||
123 | struct Thing { | 123 | struct Thing { |
124 | a: String, | 124 | a: String, |
125 | b: usize | 125 | b: usize |
@@ -154,8 +154,10 @@ impl From<usize> for Thing { | |||
154 | 154 | ||
155 | #[test] | 155 | #[test] |
156 | fn convert_into_to_from_converts_enums() { | 156 | fn convert_into_to_from_converts_enums() { |
157 | check_convert_into_to_from( | 157 | check_assist( |
158 | convert_into_to_from, | ||
158 | r#" | 159 | r#" |
160 | //- minicore: from | ||
159 | enum Thing { | 161 | enum Thing { |
160 | Foo(String), | 162 | Foo(String), |
161 | Bar(String) | 163 | Bar(String) |
@@ -190,8 +192,10 @@ impl From<Thing> for String { | |||
190 | 192 | ||
191 | #[test] | 193 | #[test] |
192 | fn convert_into_to_from_on_enum_with_lifetimes() { | 194 | fn convert_into_to_from_on_enum_with_lifetimes() { |
193 | check_convert_into_to_from( | 195 | check_assist( |
196 | convert_into_to_from, | ||
194 | r#" | 197 | r#" |
198 | //- minicore: from | ||
195 | enum Thing<'a> { | 199 | enum Thing<'a> { |
196 | Foo(&'a str), | 200 | Foo(&'a str), |
197 | Bar(&'a str) | 201 | Bar(&'a str) |
@@ -226,8 +230,10 @@ impl<'a> From<Thing<'a>> for &'a str { | |||
226 | 230 | ||
227 | #[test] | 231 | #[test] |
228 | fn convert_into_to_from_works_on_references() { | 232 | fn convert_into_to_from_works_on_references() { |
229 | check_convert_into_to_from( | 233 | check_assist( |
234 | convert_into_to_from, | ||
230 | r#" | 235 | r#" |
236 | //- minicore: from | ||
231 | struct Thing(String); | 237 | struct Thing(String); |
232 | 238 | ||
233 | impl $0core::convert::Into<String> for &Thing { | 239 | impl $0core::convert::Into<String> for &Thing { |
@@ -250,8 +256,10 @@ impl From<&Thing> for String { | |||
250 | 256 | ||
251 | #[test] | 257 | #[test] |
252 | fn convert_into_to_from_works_on_qualified_structs() { | 258 | fn convert_into_to_from_works_on_qualified_structs() { |
253 | check_convert_into_to_from( | 259 | check_assist( |
260 | convert_into_to_from, | ||
254 | r#" | 261 | r#" |
262 | //- minicore: from | ||
255 | mod things { | 263 | mod things { |
256 | pub struct Thing(String); | 264 | pub struct Thing(String); |
257 | pub struct BetterThing(String); | 265 | pub struct BetterThing(String); |
@@ -280,8 +288,10 @@ impl From<&things::Thing> for things::BetterThing { | |||
280 | 288 | ||
281 | #[test] | 289 | #[test] |
282 | fn convert_into_to_from_works_on_qualified_enums() { | 290 | fn convert_into_to_from_works_on_qualified_enums() { |
283 | check_convert_into_to_from( | 291 | check_assist( |
292 | convert_into_to_from, | ||
284 | r#" | 293 | r#" |
294 | //- minicore: from | ||
285 | mod things { | 295 | mod things { |
286 | pub enum Thing { | 296 | pub enum Thing { |
287 | A(String) | 297 | A(String) |
@@ -323,10 +333,12 @@ impl From<&things::Thing> for things::BetterThing { | |||
323 | #[test] | 333 | #[test] |
324 | fn convert_into_to_from_not_applicable_on_any_trait_named_into() { | 334 | fn convert_into_to_from_not_applicable_on_any_trait_named_into() { |
325 | check_assist_not_applicable( | 335 | check_assist_not_applicable( |
336 | convert_into_to_from, | ||
326 | r#" | 337 | r#" |
327 | pub trait Into<T> {{ | 338 | //- minicore: from |
339 | pub trait Into<T> { | ||
328 | pub fn into(self) -> T; | 340 | pub fn into(self) -> T; |
329 | }} | 341 | } |
330 | 342 | ||
331 | struct Thing { | 343 | struct Thing { |
332 | a: String, | 344 | a: String, |
@@ -342,14 +354,4 @@ impl $0Into<Thing> for String { | |||
342 | "#, | 354 | "#, |
343 | ); | 355 | ); |
344 | } | 356 | } |
345 | |||
346 | fn check_convert_into_to_from(before: &str, after: &str) { | ||
347 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
348 | check_assist(convert_into_to_from, before, after); | ||
349 | } | ||
350 | |||
351 | fn check_assist_not_applicable(before: &str) { | ||
352 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
353 | crate::tests::check_assist_not_applicable(convert_into_to_from, before); | ||
354 | } | ||
355 | } | 357 | } |
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs index 4e75a7b14..70754adf9 100644 --- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs | |||
@@ -11,14 +11,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
11 | // Converts an Iterator::for_each function into a for loop. | 11 | // Converts an Iterator::for_each function into a for loop. |
12 | // | 12 | // |
13 | // ``` | 13 | // ``` |
14 | // # //- /lib.rs crate:core | 14 | // # //- minicore: iterators |
15 | // # pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } } | 15 | // # use core::iter; |
16 | // # pub struct SomeIter; | ||
17 | // # impl self::iter::traits::iterator::Iterator for SomeIter {} | ||
18 | // # //- /lib.rs crate:main deps:core | ||
19 | // # use core::SomeIter; | ||
20 | // fn main() { | 16 | // fn main() { |
21 | // let iter = SomeIter; | 17 | // let iter = iter::repeat((9, 2)); |
22 | // iter.for_each$0(|(x, y)| { | 18 | // iter.for_each$0(|(x, y)| { |
23 | // println!("x: {}, y: {}", x, y); | 19 | // println!("x: {}, y: {}", x, y); |
24 | // }); | 20 | // }); |
@@ -26,9 +22,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
26 | // ``` | 22 | // ``` |
27 | // -> | 23 | // -> |
28 | // ``` | 24 | // ``` |
29 | // # use core::SomeIter; | 25 | // # use core::iter; |
30 | // fn main() { | 26 | // fn main() { |
31 | // let iter = SomeIter; | 27 | // let iter = iter::repeat((9, 2)); |
32 | // for (x, y) in iter { | 28 | // for (x, y) in iter { |
33 | // println!("x: {}, y: {}", x, y); | 29 | // println!("x: {}, y: {}", x, y); |
34 | // } | 30 | // } |
@@ -77,9 +73,11 @@ fn validate_method_call_expr( | |||
77 | expr: ast::MethodCallExpr, | 73 | expr: ast::MethodCallExpr, |
78 | ) -> Option<(ast::Expr, ast::Expr)> { | 74 | ) -> Option<(ast::Expr, ast::Expr)> { |
79 | let name_ref = expr.name_ref()?; | 75 | let name_ref = expr.name_ref()?; |
80 | if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() | 76 | if name_ref.syntax().text_range().intersect(ctx.frange.range).is_none() { |
81 | || name_ref.text() != "for_each" | 77 | cov_mark::hit!(test_for_each_not_applicable_invalid_cursor_pos); |
82 | { | 78 | return None; |
79 | } | ||
80 | if name_ref.text() != "for_each" { | ||
83 | return None; | 81 | return None; |
84 | } | 82 | } |
85 | 83 | ||
@@ -98,59 +96,27 @@ fn validate_method_call_expr( | |||
98 | 96 | ||
99 | #[cfg(test)] | 97 | #[cfg(test)] |
100 | mod tests { | 98 | mod tests { |
101 | use crate::tests::{self, check_assist}; | 99 | use crate::tests::{check_assist, check_assist_not_applicable}; |
102 | 100 | ||
103 | use super::*; | 101 | use super::*; |
104 | 102 | ||
105 | const EMPTY_ITER_FIXTURE: &'static str = r" | ||
106 | //- /lib.rs deps:core crate:empty_iter | ||
107 | pub struct EmptyIter; | ||
108 | impl Iterator for EmptyIter { | ||
109 | type Item = usize; | ||
110 | fn next(&mut self) -> Option<Self::Item> { None } | ||
111 | } | ||
112 | pub struct Empty; | ||
113 | impl Empty { | ||
114 | pub fn iter(&self) -> EmptyIter { EmptyIter } | ||
115 | } | ||
116 | "; | ||
117 | |||
118 | fn check_assist_with_fixtures(before: &str, after: &str) { | ||
119 | let before = &format!( | ||
120 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
121 | before, | ||
122 | EMPTY_ITER_FIXTURE, | ||
123 | FamousDefs::FIXTURE, | ||
124 | ); | ||
125 | check_assist(convert_iter_for_each_to_for, before, after); | ||
126 | } | ||
127 | |||
128 | fn check_assist_not_applicable(before: &str) { | ||
129 | let before = &format!( | ||
130 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
131 | before, | ||
132 | EMPTY_ITER_FIXTURE, | ||
133 | FamousDefs::FIXTURE, | ||
134 | ); | ||
135 | tests::check_assist_not_applicable(convert_iter_for_each_to_for, before); | ||
136 | } | ||
137 | |||
138 | #[test] | 103 | #[test] |
139 | fn test_for_each_in_method_stmt() { | 104 | fn test_for_each_in_method_stmt() { |
140 | check_assist_with_fixtures( | 105 | check_assist( |
106 | convert_iter_for_each_to_for, | ||
141 | r#" | 107 | r#" |
142 | use empty_iter::*; | 108 | //- minicore: iterators |
143 | fn main() { | 109 | fn main() { |
144 | let x = Empty; | 110 | let it = core::iter::repeat(92); |
145 | x.iter().$0for_each(|(x, y)| { | 111 | it.$0for_each(|(x, y)| { |
146 | println!("x: {}, y: {}", x, y); | 112 | println!("x: {}, y: {}", x, y); |
147 | }); | 113 | }); |
148 | }"#, | 114 | } |
115 | "#, | ||
149 | r#" | 116 | r#" |
150 | use empty_iter::*; | ||
151 | fn main() { | 117 | fn main() { |
152 | let x = Empty; | 118 | let it = core::iter::repeat(92); |
153 | for (x, y) in x.iter() { | 119 | for (x, y) in it { |
154 | println!("x: {}, y: {}", x, y); | 120 | println!("x: {}, y: {}", x, y); |
155 | } | 121 | } |
156 | } | 122 | } |
@@ -160,43 +126,21 @@ fn main() { | |||
160 | 126 | ||
161 | #[test] | 127 | #[test] |
162 | fn test_for_each_in_method() { | 128 | fn test_for_each_in_method() { |
163 | check_assist_with_fixtures( | 129 | check_assist( |
130 | convert_iter_for_each_to_for, | ||
164 | r#" | 131 | r#" |
165 | use empty_iter::*; | 132 | //- minicore: iterators |
166 | fn main() { | 133 | fn main() { |
167 | let x = Empty; | 134 | let it = core::iter::repeat(92); |
168 | x.iter().$0for_each(|(x, y)| { | 135 | it.$0for_each(|(x, y)| { |
169 | println!("x: {}, y: {}", x, y); | 136 | println!("x: {}, y: {}", x, y); |
170 | }) | 137 | }) |
171 | }"#, | ||
172 | r#" | ||
173 | use empty_iter::*; | ||
174 | fn main() { | ||
175 | let x = Empty; | ||
176 | for (x, y) in x.iter() { | ||
177 | println!("x: {}, y: {}", x, y); | ||
178 | } | ||
179 | } | 138 | } |
180 | "#, | 139 | "#, |
181 | ) | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn test_for_each_in_iter_stmt() { | ||
186 | check_assist_with_fixtures( | ||
187 | r#" | ||
188 | use empty_iter::*; | ||
189 | fn main() { | ||
190 | let x = Empty.iter(); | ||
191 | x.$0for_each(|(x, y)| { | ||
192 | println!("x: {}, y: {}", x, y); | ||
193 | }); | ||
194 | }"#, | ||
195 | r#" | 140 | r#" |
196 | use empty_iter::*; | ||
197 | fn main() { | 141 | fn main() { |
198 | let x = Empty.iter(); | 142 | let it = core::iter::repeat(92); |
199 | for (x, y) in x { | 143 | for (x, y) in it { |
200 | println!("x: {}, y: {}", x, y); | 144 | println!("x: {}, y: {}", x, y); |
201 | } | 145 | } |
202 | } | 146 | } |
@@ -206,18 +150,19 @@ fn main() { | |||
206 | 150 | ||
207 | #[test] | 151 | #[test] |
208 | fn test_for_each_without_braces_stmt() { | 152 | fn test_for_each_without_braces_stmt() { |
209 | check_assist_with_fixtures( | 153 | check_assist( |
154 | convert_iter_for_each_to_for, | ||
210 | r#" | 155 | r#" |
211 | use empty_iter::*; | 156 | //- minicore: iterators |
212 | fn main() { | 157 | fn main() { |
213 | let x = Empty; | 158 | let it = core::iter::repeat(92); |
214 | x.iter().$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); | 159 | it.$0for_each(|(x, y)| println!("x: {}, y: {}", x, y)); |
215 | }"#, | 160 | } |
161 | "#, | ||
216 | r#" | 162 | r#" |
217 | use empty_iter::*; | ||
218 | fn main() { | 163 | fn main() { |
219 | let x = Empty; | 164 | let it = core::iter::repeat(92); |
220 | for (x, y) in x.iter() { | 165 | for (x, y) in it { |
221 | println!("x: {}, y: {}", x, y) | 166 | println!("x: {}, y: {}", x, y) |
222 | } | 167 | } |
223 | } | 168 | } |
@@ -228,7 +173,9 @@ fn main() { | |||
228 | #[test] | 173 | #[test] |
229 | fn test_for_each_not_applicable() { | 174 | fn test_for_each_not_applicable() { |
230 | check_assist_not_applicable( | 175 | check_assist_not_applicable( |
176 | convert_iter_for_each_to_for, | ||
231 | r#" | 177 | r#" |
178 | //- minicore: iterators | ||
232 | fn main() { | 179 | fn main() { |
233 | ().$0for_each(|x| println!("{}", x)); | 180 | ().$0for_each(|x| println!("{}", x)); |
234 | }"#, | 181 | }"#, |
@@ -237,11 +184,13 @@ fn main() { | |||
237 | 184 | ||
238 | #[test] | 185 | #[test] |
239 | fn test_for_each_not_applicable_invalid_cursor_pos() { | 186 | fn test_for_each_not_applicable_invalid_cursor_pos() { |
187 | cov_mark::check!(test_for_each_not_applicable_invalid_cursor_pos); | ||
240 | check_assist_not_applicable( | 188 | check_assist_not_applicable( |
189 | convert_iter_for_each_to_for, | ||
241 | r#" | 190 | r#" |
242 | use empty_iter::*; | 191 | //- minicore: iterators |
243 | fn main() { | 192 | fn main() { |
244 | Empty.iter().for_each(|(x, y)| $0println!("x: {}, y: {}", x, y)); | 193 | core::iter::repeat(92).for_each(|(x, y)| $0println!("x: {}, y: {}", x, y)); |
245 | }"#, | 194 | }"#, |
246 | ) | 195 | ) |
247 | } | 196 | } |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index f2be091f4..870d4f665 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -109,10 +109,15 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
109 | 109 | ||
110 | let new_indent = IndentLevel::from_node(&insert_after); | 110 | let new_indent = IndentLevel::from_node(&insert_after); |
111 | let old_indent = fun.body.indent_level(); | 111 | let old_indent = fun.body.indent_level(); |
112 | let body_contains_await = body_contains_await(&fun.body); | ||
112 | 113 | ||
113 | builder.replace(target_range, format_replacement(ctx, &fun, old_indent)); | 114 | builder.replace( |
115 | target_range, | ||
116 | format_replacement(ctx, &fun, old_indent, body_contains_await), | ||
117 | ); | ||
114 | 118 | ||
115 | let fn_def = format_function(ctx, module, &fun, old_indent, new_indent); | 119 | let fn_def = |
120 | format_function(ctx, module, &fun, old_indent, new_indent, body_contains_await); | ||
116 | let insert_offset = insert_after.text_range().end(); | 121 | let insert_offset = insert_after.text_range().end(); |
117 | match ctx.config.snippet_cap { | 122 | match ctx.config.snippet_cap { |
118 | Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), | 123 | Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def), |
@@ -954,7 +959,12 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode, anchor: Anchor) -> Option<Synt | |||
954 | last_ancestor | 959 | last_ancestor |
955 | } | 960 | } |
956 | 961 | ||
957 | fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String { | 962 | fn format_replacement( |
963 | ctx: &AssistContext, | ||
964 | fun: &Function, | ||
965 | indent: IndentLevel, | ||
966 | body_contains_await: bool, | ||
967 | ) -> String { | ||
958 | let ret_ty = fun.return_type(ctx); | 968 | let ret_ty = fun.return_type(ctx); |
959 | 969 | ||
960 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); | 970 | let args = fun.params.iter().map(|param| param.to_arg(ctx)); |
@@ -994,6 +1004,9 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel) | |||
994 | } | 1004 | } |
995 | } | 1005 | } |
996 | format_to!(buf, "{}", expr); | 1006 | format_to!(buf, "{}", expr); |
1007 | if body_contains_await { | ||
1008 | buf.push_str(".await"); | ||
1009 | } | ||
997 | if fun.ret_ty.is_unit() | 1010 | if fun.ret_ty.is_unit() |
998 | && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) | 1011 | && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) |
999 | { | 1012 | { |
@@ -1122,12 +1135,13 @@ fn format_function( | |||
1122 | fun: &Function, | 1135 | fun: &Function, |
1123 | old_indent: IndentLevel, | 1136 | old_indent: IndentLevel, |
1124 | new_indent: IndentLevel, | 1137 | new_indent: IndentLevel, |
1138 | body_contains_await: bool, | ||
1125 | ) -> String { | 1139 | ) -> String { |
1126 | let mut fn_def = String::new(); | 1140 | let mut fn_def = String::new(); |
1127 | let params = make_param_list(ctx, module, fun); | 1141 | let params = make_param_list(ctx, module, fun); |
1128 | let ret_ty = make_ret_ty(ctx, module, fun); | 1142 | let ret_ty = make_ret_ty(ctx, module, fun); |
1129 | let body = make_body(ctx, old_indent, new_indent, fun); | 1143 | let body = make_body(ctx, old_indent, new_indent, fun); |
1130 | let async_kw = if body_contains_await(&fun.body) { "async " } else { "" }; | 1144 | let async_kw = if body_contains_await { "async " } else { "" }; |
1131 | match ctx.config.snippet_cap { | 1145 | match ctx.config.snippet_cap { |
1132 | Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), | 1146 | Some(_) => format_to!(fn_def, "\n\n{}{}fn $0{}{}", new_indent, async_kw, fun.name, params), |
1133 | None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), | 1147 | None => format_to!(fn_def, "\n\n{}{}fn {}{}", new_indent, async_kw, fun.name, params), |
@@ -1384,7 +1398,7 @@ fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) | |||
1384 | for (param, usages) in usages_for_param { | 1398 | for (param, usages) in usages_for_param { |
1385 | for usage in usages { | 1399 | for usage in usages { |
1386 | match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { | 1400 | match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { |
1387 | Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => { | 1401 | Some(ast::Expr::MethodCallExpr(_) | ast::Expr::FieldExpr(_)) => { |
1388 | // do nothing | 1402 | // do nothing |
1389 | } | 1403 | } |
1390 | Some(ast::Expr::RefExpr(node)) | 1404 | Some(ast::Expr::RefExpr(node)) |
@@ -1501,7 +1515,8 @@ mod tests { | |||
1501 | r#" | 1515 | r#" |
1502 | fn foo() { | 1516 | fn foo() { |
1503 | foo($01 + 1$0); | 1517 | foo($01 + 1$0); |
1504 | }"#, | 1518 | } |
1519 | "#, | ||
1505 | r#" | 1520 | r#" |
1506 | fn foo() { | 1521 | fn foo() { |
1507 | foo(fun_name()); | 1522 | foo(fun_name()); |
@@ -1509,7 +1524,8 @@ fn foo() { | |||
1509 | 1524 | ||
1510 | fn $0fun_name() -> i32 { | 1525 | fn $0fun_name() -> i32 { |
1511 | 1 + 1 | 1526 | 1 + 1 |
1512 | }"#, | 1527 | } |
1528 | "#, | ||
1513 | ); | 1529 | ); |
1514 | } | 1530 | } |
1515 | 1531 | ||
@@ -1522,7 +1538,8 @@ mod bar { | |||
1522 | fn foo() { | 1538 | fn foo() { |
1523 | foo($01 + 1$0); | 1539 | foo($01 + 1$0); |
1524 | } | 1540 | } |
1525 | }"#, | 1541 | } |
1542 | "#, | ||
1526 | r#" | 1543 | r#" |
1527 | mod bar { | 1544 | mod bar { |
1528 | fn foo() { | 1545 | fn foo() { |
@@ -1532,7 +1549,8 @@ mod bar { | |||
1532 | fn $0fun_name() -> i32 { | 1549 | fn $0fun_name() -> i32 { |
1533 | 1 + 1 | 1550 | 1 + 1 |
1534 | } | 1551 | } |
1535 | }"#, | 1552 | } |
1553 | "#, | ||
1536 | ); | 1554 | ); |
1537 | } | 1555 | } |
1538 | 1556 | ||
@@ -1543,7 +1561,8 @@ mod bar { | |||
1543 | r#" | 1561 | r#" |
1544 | fn foo() { | 1562 | fn foo() { |
1545 | $0{ 1 + 1 }$0; | 1563 | $0{ 1 + 1 }$0; |
1546 | }"#, | 1564 | } |
1565 | "#, | ||
1547 | r#" | 1566 | r#" |
1548 | fn foo() { | 1567 | fn foo() { |
1549 | fun_name(); | 1568 | fun_name(); |
@@ -1551,7 +1570,8 @@ fn foo() { | |||
1551 | 1570 | ||
1552 | fn $0fun_name() -> i32 { | 1571 | fn $0fun_name() -> i32 { |
1553 | 1 + 1 | 1572 | 1 + 1 |
1554 | }"#, | 1573 | } |
1574 | "#, | ||
1555 | ); | 1575 | ); |
1556 | } | 1576 | } |
1557 | 1577 | ||
@@ -1564,7 +1584,8 @@ fn foo() -> i32 { | |||
1564 | let k = 1; | 1584 | let k = 1; |
1565 | $0let m = 1; | 1585 | $0let m = 1; |
1566 | m + 1$0 | 1586 | m + 1$0 |
1567 | }"#, | 1587 | } |
1588 | "#, | ||
1568 | r#" | 1589 | r#" |
1569 | fn foo() -> i32 { | 1590 | fn foo() -> i32 { |
1570 | let k = 1; | 1591 | let k = 1; |
@@ -1574,7 +1595,8 @@ fn foo() -> i32 { | |||
1574 | fn $0fun_name() -> i32 { | 1595 | fn $0fun_name() -> i32 { |
1575 | let m = 1; | 1596 | let m = 1; |
1576 | m + 1 | 1597 | m + 1 |
1577 | }"#, | 1598 | } |
1599 | "#, | ||
1578 | ); | 1600 | ); |
1579 | } | 1601 | } |
1580 | 1602 | ||
@@ -1588,7 +1610,8 @@ fn foo() { | |||
1588 | $0let m = 1; | 1610 | $0let m = 1; |
1589 | let n = m + 1;$0 | 1611 | let n = m + 1;$0 |
1590 | let g = 5; | 1612 | let g = 5; |
1591 | }"#, | 1613 | } |
1614 | "#, | ||
1592 | r#" | 1615 | r#" |
1593 | fn foo() { | 1616 | fn foo() { |
1594 | let k = 3; | 1617 | let k = 3; |
@@ -1599,7 +1622,8 @@ fn foo() { | |||
1599 | fn $0fun_name() { | 1622 | fn $0fun_name() { |
1600 | let m = 1; | 1623 | let m = 1; |
1601 | let n = m + 1; | 1624 | let n = m + 1; |
1602 | }"#, | 1625 | } |
1626 | "#, | ||
1603 | ); | 1627 | ); |
1604 | } | 1628 | } |
1605 | 1629 | ||
@@ -1610,7 +1634,8 @@ fn $0fun_name() { | |||
1610 | r#" | 1634 | r#" |
1611 | fn foo() { | 1635 | fn foo() { |
1612 | $0if true { }$0 | 1636 | $0if true { }$0 |
1613 | }"#, | 1637 | } |
1638 | "#, | ||
1614 | r#" | 1639 | r#" |
1615 | fn foo() { | 1640 | fn foo() { |
1616 | fun_name(); | 1641 | fun_name(); |
@@ -1618,7 +1643,8 @@ fn foo() { | |||
1618 | 1643 | ||
1619 | fn $0fun_name() { | 1644 | fn $0fun_name() { |
1620 | if true { } | 1645 | if true { } |
1621 | }"#, | 1646 | } |
1647 | "#, | ||
1622 | ); | 1648 | ); |
1623 | } | 1649 | } |
1624 | 1650 | ||
@@ -1629,7 +1655,8 @@ fn $0fun_name() { | |||
1629 | r#" | 1655 | r#" |
1630 | fn foo() -> i32 { | 1656 | fn foo() -> i32 { |
1631 | $0if true { 1 } else { 2 }$0 | 1657 | $0if true { 1 } else { 2 }$0 |
1632 | }"#, | 1658 | } |
1659 | "#, | ||
1633 | r#" | 1660 | r#" |
1634 | fn foo() -> i32 { | 1661 | fn foo() -> i32 { |
1635 | fun_name() | 1662 | fun_name() |
@@ -1637,7 +1664,8 @@ fn foo() -> i32 { | |||
1637 | 1664 | ||
1638 | fn $0fun_name() -> i32 { | 1665 | fn $0fun_name() -> i32 { |
1639 | if true { 1 } else { 2 } | 1666 | if true { 1 } else { 2 } |
1640 | }"#, | 1667 | } |
1668 | "#, | ||
1641 | ); | 1669 | ); |
1642 | } | 1670 | } |
1643 | 1671 | ||
@@ -1648,7 +1676,8 @@ fn $0fun_name() -> i32 { | |||
1648 | r#" | 1676 | r#" |
1649 | fn foo() -> i32 { | 1677 | fn foo() -> i32 { |
1650 | $0if let true = false { 1 } else { 2 }$0 | 1678 | $0if let true = false { 1 } else { 2 }$0 |
1651 | }"#, | 1679 | } |
1680 | "#, | ||
1652 | r#" | 1681 | r#" |
1653 | fn foo() -> i32 { | 1682 | fn foo() -> i32 { |
1654 | fun_name() | 1683 | fun_name() |
@@ -1656,7 +1685,8 @@ fn foo() -> i32 { | |||
1656 | 1685 | ||
1657 | fn $0fun_name() -> i32 { | 1686 | fn $0fun_name() -> i32 { |
1658 | if let true = false { 1 } else { 2 } | 1687 | if let true = false { 1 } else { 2 } |
1659 | }"#, | 1688 | } |
1689 | "#, | ||
1660 | ); | 1690 | ); |
1661 | } | 1691 | } |
1662 | 1692 | ||
@@ -1670,7 +1700,8 @@ fn foo() -> i32 { | |||
1670 | true => 1, | 1700 | true => 1, |
1671 | false => 2, | 1701 | false => 2, |
1672 | }$0 | 1702 | }$0 |
1673 | }"#, | 1703 | } |
1704 | "#, | ||
1674 | r#" | 1705 | r#" |
1675 | fn foo() -> i32 { | 1706 | fn foo() -> i32 { |
1676 | fun_name() | 1707 | fun_name() |
@@ -1681,7 +1712,8 @@ fn $0fun_name() -> i32 { | |||
1681 | true => 1, | 1712 | true => 1, |
1682 | false => 2, | 1713 | false => 2, |
1683 | } | 1714 | } |
1684 | }"#, | 1715 | } |
1716 | "#, | ||
1685 | ); | 1717 | ); |
1686 | } | 1718 | } |
1687 | 1719 | ||
@@ -1692,7 +1724,8 @@ fn $0fun_name() -> i32 { | |||
1692 | r#" | 1724 | r#" |
1693 | fn foo() { | 1725 | fn foo() { |
1694 | $0while true { }$0 | 1726 | $0while true { }$0 |
1695 | }"#, | 1727 | } |
1728 | "#, | ||
1696 | r#" | 1729 | r#" |
1697 | fn foo() { | 1730 | fn foo() { |
1698 | fun_name(); | 1731 | fun_name(); |
@@ -1700,7 +1733,8 @@ fn foo() { | |||
1700 | 1733 | ||
1701 | fn $0fun_name() { | 1734 | fn $0fun_name() { |
1702 | while true { } | 1735 | while true { } |
1703 | }"#, | 1736 | } |
1737 | "#, | ||
1704 | ); | 1738 | ); |
1705 | } | 1739 | } |
1706 | 1740 | ||
@@ -1711,7 +1745,8 @@ fn $0fun_name() { | |||
1711 | r#" | 1745 | r#" |
1712 | fn foo() { | 1746 | fn foo() { |
1713 | $0for v in &[0, 1] { }$0 | 1747 | $0for v in &[0, 1] { }$0 |
1714 | }"#, | 1748 | } |
1749 | "#, | ||
1715 | r#" | 1750 | r#" |
1716 | fn foo() { | 1751 | fn foo() { |
1717 | fun_name(); | 1752 | fun_name(); |
@@ -1719,7 +1754,8 @@ fn foo() { | |||
1719 | 1754 | ||
1720 | fn $0fun_name() { | 1755 | fn $0fun_name() { |
1721 | for v in &[0, 1] { } | 1756 | for v in &[0, 1] { } |
1722 | }"#, | 1757 | } |
1758 | "#, | ||
1723 | ); | 1759 | ); |
1724 | } | 1760 | } |
1725 | 1761 | ||
@@ -1732,7 +1768,8 @@ fn foo() { | |||
1732 | $0loop { | 1768 | $0loop { |
1733 | let m = 1; | 1769 | let m = 1; |
1734 | }$0 | 1770 | }$0 |
1735 | }"#, | 1771 | } |
1772 | "#, | ||
1736 | r#" | 1773 | r#" |
1737 | fn foo() { | 1774 | fn foo() { |
1738 | fun_name() | 1775 | fun_name() |
@@ -1742,7 +1779,8 @@ fn $0fun_name() -> ! { | |||
1742 | loop { | 1779 | loop { |
1743 | let m = 1; | 1780 | let m = 1; |
1744 | } | 1781 | } |
1745 | }"#, | 1782 | } |
1783 | "#, | ||
1746 | ); | 1784 | ); |
1747 | } | 1785 | } |
1748 | 1786 | ||
@@ -1756,7 +1794,8 @@ fn foo() { | |||
1756 | let m = 1; | 1794 | let m = 1; |
1757 | break m; | 1795 | break m; |
1758 | }$0; | 1796 | }$0; |
1759 | }"#, | 1797 | } |
1798 | "#, | ||
1760 | r#" | 1799 | r#" |
1761 | fn foo() { | 1800 | fn foo() { |
1762 | let v = fun_name(); | 1801 | let v = fun_name(); |
@@ -1767,7 +1806,8 @@ fn $0fun_name() -> i32 { | |||
1767 | let m = 1; | 1806 | let m = 1; |
1768 | break m; | 1807 | break m; |
1769 | } | 1808 | } |
1770 | }"#, | 1809 | } |
1810 | "#, | ||
1771 | ); | 1811 | ); |
1772 | } | 1812 | } |
1773 | 1813 | ||
@@ -1781,7 +1821,8 @@ fn foo() { | |||
1781 | Some(x) => x, | 1821 | Some(x) => x, |
1782 | None => 0, | 1822 | None => 0, |
1783 | }$0; | 1823 | }$0; |
1784 | }"#, | 1824 | } |
1825 | "#, | ||
1785 | r#" | 1826 | r#" |
1786 | fn foo() { | 1827 | fn foo() { |
1787 | let v: i32 = fun_name(); | 1828 | let v: i32 = fun_name(); |
@@ -1792,7 +1833,8 @@ fn $0fun_name() -> i32 { | |||
1792 | Some(x) => x, | 1833 | Some(x) => x, |
1793 | None => 0, | 1834 | None => 0, |
1794 | } | 1835 | } |
1795 | }"#, | 1836 | } |
1837 | "#, | ||
1796 | ); | 1838 | ); |
1797 | } | 1839 | } |
1798 | 1840 | ||
@@ -1805,7 +1847,8 @@ fn foo() { | |||
1805 | let n = 1; | 1847 | let n = 1; |
1806 | let mut v = $0n * n;$0 | 1848 | let mut v = $0n * n;$0 |
1807 | v += 1; | 1849 | v += 1; |
1808 | }"#, | 1850 | } |
1851 | "#, | ||
1809 | r#" | 1852 | r#" |
1810 | fn foo() { | 1853 | fn foo() { |
1811 | let n = 1; | 1854 | let n = 1; |
@@ -1816,7 +1859,8 @@ fn foo() { | |||
1816 | fn $0fun_name(n: i32) -> i32 { | 1859 | fn $0fun_name(n: i32) -> i32 { |
1817 | let mut v = n * n; | 1860 | let mut v = n * n; |
1818 | v | 1861 | v |
1819 | }"#, | 1862 | } |
1863 | "#, | ||
1820 | ); | 1864 | ); |
1821 | } | 1865 | } |
1822 | 1866 | ||
@@ -1832,7 +1876,8 @@ fn foo() { | |||
1832 | let mut w = 3;$0 | 1876 | let mut w = 3;$0 |
1833 | v += 1; | 1877 | v += 1; |
1834 | w += 1; | 1878 | w += 1; |
1835 | }"#, | 1879 | } |
1880 | "#, | ||
1836 | r#" | 1881 | r#" |
1837 | fn foo() { | 1882 | fn foo() { |
1838 | let m = 2; | 1883 | let m = 2; |
@@ -1846,7 +1891,8 @@ fn $0fun_name(m: i32, n: i32) -> (i32, i32) { | |||
1846 | let mut v = m * n; | 1891 | let mut v = m * n; |
1847 | let mut w = 3; | 1892 | let mut w = 3; |
1848 | (v, w) | 1893 | (v, w) |
1849 | }"#, | 1894 | } |
1895 | "#, | ||
1850 | ); | 1896 | ); |
1851 | } | 1897 | } |
1852 | 1898 | ||
@@ -1854,12 +1900,13 @@ fn $0fun_name(m: i32, n: i32) -> (i32, i32) { | |||
1854 | fn argument_form_expr() { | 1900 | fn argument_form_expr() { |
1855 | check_assist( | 1901 | check_assist( |
1856 | extract_function, | 1902 | extract_function, |
1857 | r" | 1903 | r#" |
1858 | fn foo() -> u32 { | 1904 | fn foo() -> u32 { |
1859 | let n = 2; | 1905 | let n = 2; |
1860 | $0n+2$0 | 1906 | $0n+2$0 |
1861 | }", | 1907 | } |
1862 | r" | 1908 | "#, |
1909 | r#" | ||
1863 | fn foo() -> u32 { | 1910 | fn foo() -> u32 { |
1864 | let n = 2; | 1911 | let n = 2; |
1865 | fun_name(n) | 1912 | fun_name(n) |
@@ -1867,7 +1914,8 @@ fn foo() -> u32 { | |||
1867 | 1914 | ||
1868 | fn $0fun_name(n: u32) -> u32 { | 1915 | fn $0fun_name(n: u32) -> u32 { |
1869 | n+2 | 1916 | n+2 |
1870 | }", | 1917 | } |
1918 | "#, | ||
1871 | ) | 1919 | ) |
1872 | } | 1920 | } |
1873 | 1921 | ||
@@ -1875,12 +1923,13 @@ fn $0fun_name(n: u32) -> u32 { | |||
1875 | fn argument_used_twice_form_expr() { | 1923 | fn argument_used_twice_form_expr() { |
1876 | check_assist( | 1924 | check_assist( |
1877 | extract_function, | 1925 | extract_function, |
1878 | r" | 1926 | r#" |
1879 | fn foo() -> u32 { | 1927 | fn foo() -> u32 { |
1880 | let n = 2; | 1928 | let n = 2; |
1881 | $0n+n$0 | 1929 | $0n+n$0 |
1882 | }", | 1930 | } |
1883 | r" | 1931 | "#, |
1932 | r#" | ||
1884 | fn foo() -> u32 { | 1933 | fn foo() -> u32 { |
1885 | let n = 2; | 1934 | let n = 2; |
1886 | fun_name(n) | 1935 | fun_name(n) |
@@ -1888,7 +1937,8 @@ fn foo() -> u32 { | |||
1888 | 1937 | ||
1889 | fn $0fun_name(n: u32) -> u32 { | 1938 | fn $0fun_name(n: u32) -> u32 { |
1890 | n+n | 1939 | n+n |
1891 | }", | 1940 | } |
1941 | "#, | ||
1892 | ) | 1942 | ) |
1893 | } | 1943 | } |
1894 | 1944 | ||
@@ -1896,13 +1946,14 @@ fn $0fun_name(n: u32) -> u32 { | |||
1896 | fn two_arguments_form_expr() { | 1946 | fn two_arguments_form_expr() { |
1897 | check_assist( | 1947 | check_assist( |
1898 | extract_function, | 1948 | extract_function, |
1899 | r" | 1949 | r#" |
1900 | fn foo() -> u32 { | 1950 | fn foo() -> u32 { |
1901 | let n = 2; | 1951 | let n = 2; |
1902 | let m = 3; | 1952 | let m = 3; |
1903 | $0n+n*m$0 | 1953 | $0n+n*m$0 |
1904 | }", | 1954 | } |
1905 | r" | 1955 | "#, |
1956 | r#" | ||
1906 | fn foo() -> u32 { | 1957 | fn foo() -> u32 { |
1907 | let n = 2; | 1958 | let n = 2; |
1908 | let m = 3; | 1959 | let m = 3; |
@@ -1911,7 +1962,8 @@ fn foo() -> u32 { | |||
1911 | 1962 | ||
1912 | fn $0fun_name(n: u32, m: u32) -> u32 { | 1963 | fn $0fun_name(n: u32, m: u32) -> u32 { |
1913 | n+n*m | 1964 | n+n*m |
1914 | }", | 1965 | } |
1966 | "#, | ||
1915 | ) | 1967 | ) |
1916 | } | 1968 | } |
1917 | 1969 | ||
@@ -1919,13 +1971,14 @@ fn $0fun_name(n: u32, m: u32) -> u32 { | |||
1919 | fn argument_and_locals() { | 1971 | fn argument_and_locals() { |
1920 | check_assist( | 1972 | check_assist( |
1921 | extract_function, | 1973 | extract_function, |
1922 | r" | 1974 | r#" |
1923 | fn foo() -> u32 { | 1975 | fn foo() -> u32 { |
1924 | let n = 2; | 1976 | let n = 2; |
1925 | $0let m = 1; | 1977 | $0let m = 1; |
1926 | n + m$0 | 1978 | n + m$0 |
1927 | }", | 1979 | } |
1928 | r" | 1980 | "#, |
1981 | r#" | ||
1929 | fn foo() -> u32 { | 1982 | fn foo() -> u32 { |
1930 | let n = 2; | 1983 | let n = 2; |
1931 | fun_name(n) | 1984 | fun_name(n) |
@@ -1934,7 +1987,8 @@ fn foo() -> u32 { | |||
1934 | fn $0fun_name(n: u32) -> u32 { | 1987 | fn $0fun_name(n: u32) -> u32 { |
1935 | let m = 1; | 1988 | let m = 1; |
1936 | n + m | 1989 | n + m |
1937 | }", | 1990 | } |
1991 | "#, | ||
1938 | ) | 1992 | ) |
1939 | } | 1993 | } |
1940 | 1994 | ||
@@ -1948,18 +2002,20 @@ fn $0fun_name(n: u32) -> u32 { | |||
1948 | fn part_of_expr_stmt() { | 2002 | fn part_of_expr_stmt() { |
1949 | check_assist( | 2003 | check_assist( |
1950 | extract_function, | 2004 | extract_function, |
1951 | " | 2005 | r#" |
1952 | fn foo() { | 2006 | fn foo() { |
1953 | $01$0 + 1; | 2007 | $01$0 + 1; |
1954 | }", | 2008 | } |
1955 | " | 2009 | "#, |
2010 | r#" | ||
1956 | fn foo() { | 2011 | fn foo() { |
1957 | fun_name() + 1; | 2012 | fun_name() + 1; |
1958 | } | 2013 | } |
1959 | 2014 | ||
1960 | fn $0fun_name() -> i32 { | 2015 | fn $0fun_name() -> i32 { |
1961 | 1 | 2016 | 1 |
1962 | }", | 2017 | } |
2018 | "#, | ||
1963 | ); | 2019 | ); |
1964 | } | 2020 | } |
1965 | 2021 | ||
@@ -1970,7 +2026,8 @@ fn $0fun_name() -> i32 { | |||
1970 | r#" | 2026 | r#" |
1971 | fn foo() { | 2027 | fn foo() { |
1972 | $0bar(1 + 1)$0 | 2028 | $0bar(1 + 1)$0 |
1973 | }"#, | 2029 | } |
2030 | "#, | ||
1974 | r#" | 2031 | r#" |
1975 | fn foo() { | 2032 | fn foo() { |
1976 | fun_name(); | 2033 | fun_name(); |
@@ -1978,7 +2035,8 @@ fn foo() { | |||
1978 | 2035 | ||
1979 | fn $0fun_name() { | 2036 | fn $0fun_name() { |
1980 | bar(1 + 1) | 2037 | bar(1 + 1) |
1981 | }"#, | 2038 | } |
2039 | "#, | ||
1982 | ) | 2040 | ) |
1983 | } | 2041 | } |
1984 | 2042 | ||
@@ -1986,15 +2044,16 @@ fn $0fun_name() { | |||
1986 | fn extract_from_nested() { | 2044 | fn extract_from_nested() { |
1987 | check_assist( | 2045 | check_assist( |
1988 | extract_function, | 2046 | extract_function, |
1989 | r" | 2047 | r#" |
1990 | fn main() { | 2048 | fn main() { |
1991 | let x = true; | 2049 | let x = true; |
1992 | let tuple = match x { | 2050 | let tuple = match x { |
1993 | true => ($02 + 2$0, true) | 2051 | true => ($02 + 2$0, true) |
1994 | _ => (0, false) | 2052 | _ => (0, false) |
1995 | }; | 2053 | }; |
1996 | }", | 2054 | } |
1997 | r" | 2055 | "#, |
2056 | r#" | ||
1998 | fn main() { | 2057 | fn main() { |
1999 | let x = true; | 2058 | let x = true; |
2000 | let tuple = match x { | 2059 | let tuple = match x { |
@@ -2005,7 +2064,8 @@ fn main() { | |||
2005 | 2064 | ||
2006 | fn $0fun_name() -> i32 { | 2065 | fn $0fun_name() -> i32 { |
2007 | 2 + 2 | 2066 | 2 + 2 |
2008 | }", | 2067 | } |
2068 | "#, | ||
2009 | ); | 2069 | ); |
2010 | } | 2070 | } |
2011 | 2071 | ||
@@ -2013,18 +2073,20 @@ fn $0fun_name() -> i32 { | |||
2013 | fn param_from_closure() { | 2073 | fn param_from_closure() { |
2014 | check_assist( | 2074 | check_assist( |
2015 | extract_function, | 2075 | extract_function, |
2016 | r" | 2076 | r#" |
2017 | fn main() { | 2077 | fn main() { |
2018 | let lambda = |x: u32| $0x * 2$0; | 2078 | let lambda = |x: u32| $0x * 2$0; |
2019 | }", | 2079 | } |
2020 | r" | 2080 | "#, |
2081 | r#" | ||
2021 | fn main() { | 2082 | fn main() { |
2022 | let lambda = |x: u32| fun_name(x); | 2083 | let lambda = |x: u32| fun_name(x); |
2023 | } | 2084 | } |
2024 | 2085 | ||
2025 | fn $0fun_name(x: u32) -> u32 { | 2086 | fn $0fun_name(x: u32) -> u32 { |
2026 | x * 2 | 2087 | x * 2 |
2027 | }", | 2088 | } |
2089 | "#, | ||
2028 | ); | 2090 | ); |
2029 | } | 2091 | } |
2030 | 2092 | ||
@@ -2032,18 +2094,20 @@ fn $0fun_name(x: u32) -> u32 { | |||
2032 | fn extract_return_stmt() { | 2094 | fn extract_return_stmt() { |
2033 | check_assist( | 2095 | check_assist( |
2034 | extract_function, | 2096 | extract_function, |
2035 | r" | 2097 | r#" |
2036 | fn foo() -> u32 { | 2098 | fn foo() -> u32 { |
2037 | $0return 2 + 2$0; | 2099 | $0return 2 + 2$0; |
2038 | }", | 2100 | } |
2039 | r" | 2101 | "#, |
2102 | r#" | ||
2040 | fn foo() -> u32 { | 2103 | fn foo() -> u32 { |
2041 | return fun_name(); | 2104 | return fun_name(); |
2042 | } | 2105 | } |
2043 | 2106 | ||
2044 | fn $0fun_name() -> u32 { | 2107 | fn $0fun_name() -> u32 { |
2045 | 2 + 2 | 2108 | 2 + 2 |
2046 | }", | 2109 | } |
2110 | "#, | ||
2047 | ); | 2111 | ); |
2048 | } | 2112 | } |
2049 | 2113 | ||
@@ -2051,13 +2115,14 @@ fn $0fun_name() -> u32 { | |||
2051 | fn does_not_add_extra_whitespace() { | 2115 | fn does_not_add_extra_whitespace() { |
2052 | check_assist( | 2116 | check_assist( |
2053 | extract_function, | 2117 | extract_function, |
2054 | r" | 2118 | r#" |
2055 | fn foo() -> u32 { | 2119 | fn foo() -> u32 { |
2056 | 2120 | ||
2057 | 2121 | ||
2058 | $0return 2 + 2$0; | 2122 | $0return 2 + 2$0; |
2059 | }", | 2123 | } |
2060 | r" | 2124 | "#, |
2125 | r#" | ||
2061 | fn foo() -> u32 { | 2126 | fn foo() -> u32 { |
2062 | 2127 | ||
2063 | 2128 | ||
@@ -2066,7 +2131,8 @@ fn foo() -> u32 { | |||
2066 | 2131 | ||
2067 | fn $0fun_name() -> u32 { | 2132 | fn $0fun_name() -> u32 { |
2068 | 2 + 2 | 2133 | 2 + 2 |
2069 | }", | 2134 | } |
2135 | "#, | ||
2070 | ); | 2136 | ); |
2071 | } | 2137 | } |
2072 | 2138 | ||
@@ -2074,13 +2140,14 @@ fn $0fun_name() -> u32 { | |||
2074 | fn break_stmt() { | 2140 | fn break_stmt() { |
2075 | check_assist( | 2141 | check_assist( |
2076 | extract_function, | 2142 | extract_function, |
2077 | r" | 2143 | r#" |
2078 | fn main() { | 2144 | fn main() { |
2079 | let result = loop { | 2145 | let result = loop { |
2080 | $0break 2 + 2$0; | 2146 | $0break 2 + 2$0; |
2081 | }; | 2147 | }; |
2082 | }", | 2148 | } |
2083 | r" | 2149 | "#, |
2150 | r#" | ||
2084 | fn main() { | 2151 | fn main() { |
2085 | let result = loop { | 2152 | let result = loop { |
2086 | break fun_name(); | 2153 | break fun_name(); |
@@ -2089,7 +2156,8 @@ fn main() { | |||
2089 | 2156 | ||
2090 | fn $0fun_name() -> i32 { | 2157 | fn $0fun_name() -> i32 { |
2091 | 2 + 2 | 2158 | 2 + 2 |
2092 | }", | 2159 | } |
2160 | "#, | ||
2093 | ); | 2161 | ); |
2094 | } | 2162 | } |
2095 | 2163 | ||
@@ -2097,18 +2165,20 @@ fn $0fun_name() -> i32 { | |||
2097 | fn extract_cast() { | 2165 | fn extract_cast() { |
2098 | check_assist( | 2166 | check_assist( |
2099 | extract_function, | 2167 | extract_function, |
2100 | r" | 2168 | r#" |
2101 | fn main() { | 2169 | fn main() { |
2102 | let v = $00f32 as u32$0; | 2170 | let v = $00f32 as u32$0; |
2103 | }", | 2171 | } |
2104 | r" | 2172 | "#, |
2173 | r#" | ||
2105 | fn main() { | 2174 | fn main() { |
2106 | let v = fun_name(); | 2175 | let v = fun_name(); |
2107 | } | 2176 | } |
2108 | 2177 | ||
2109 | fn $0fun_name() -> u32 { | 2178 | fn $0fun_name() -> u32 { |
2110 | 0f32 as u32 | 2179 | 0f32 as u32 |
2111 | }", | 2180 | } |
2181 | "#, | ||
2112 | ); | 2182 | ); |
2113 | } | 2183 | } |
2114 | 2184 | ||
@@ -2121,15 +2191,16 @@ fn $0fun_name() -> u32 { | |||
2121 | fn method_to_freestanding() { | 2191 | fn method_to_freestanding() { |
2122 | check_assist( | 2192 | check_assist( |
2123 | extract_function, | 2193 | extract_function, |
2124 | r" | 2194 | r#" |
2125 | struct S; | 2195 | struct S; |
2126 | 2196 | ||
2127 | impl S { | 2197 | impl S { |
2128 | fn foo(&self) -> i32 { | 2198 | fn foo(&self) -> i32 { |
2129 | $01+1$0 | 2199 | $01+1$0 |
2130 | } | 2200 | } |
2131 | }", | 2201 | } |
2132 | r" | 2202 | "#, |
2203 | r#" | ||
2133 | struct S; | 2204 | struct S; |
2134 | 2205 | ||
2135 | impl S { | 2206 | impl S { |
@@ -2140,7 +2211,8 @@ impl S { | |||
2140 | 2211 | ||
2141 | fn $0fun_name() -> i32 { | 2212 | fn $0fun_name() -> i32 { |
2142 | 1+1 | 2213 | 1+1 |
2143 | }", | 2214 | } |
2215 | "#, | ||
2144 | ); | 2216 | ); |
2145 | } | 2217 | } |
2146 | 2218 | ||
@@ -2148,15 +2220,16 @@ fn $0fun_name() -> i32 { | |||
2148 | fn method_with_reference() { | 2220 | fn method_with_reference() { |
2149 | check_assist( | 2221 | check_assist( |
2150 | extract_function, | 2222 | extract_function, |
2151 | r" | 2223 | r#" |
2152 | struct S { f: i32 }; | 2224 | struct S { f: i32 }; |
2153 | 2225 | ||
2154 | impl S { | 2226 | impl S { |
2155 | fn foo(&self) -> i32 { | 2227 | fn foo(&self) -> i32 { |
2156 | $01+self.f$0 | 2228 | $01+self.f$0 |
2157 | } | 2229 | } |
2158 | }", | 2230 | } |
2159 | r" | 2231 | "#, |
2232 | r#" | ||
2160 | struct S { f: i32 }; | 2233 | struct S { f: i32 }; |
2161 | 2234 | ||
2162 | impl S { | 2235 | impl S { |
@@ -2167,7 +2240,8 @@ impl S { | |||
2167 | fn $0fun_name(&self) -> i32 { | 2240 | fn $0fun_name(&self) -> i32 { |
2168 | 1+self.f | 2241 | 1+self.f |
2169 | } | 2242 | } |
2170 | }", | 2243 | } |
2244 | "#, | ||
2171 | ); | 2245 | ); |
2172 | } | 2246 | } |
2173 | 2247 | ||
@@ -2175,15 +2249,16 @@ impl S { | |||
2175 | fn method_with_mut() { | 2249 | fn method_with_mut() { |
2176 | check_assist( | 2250 | check_assist( |
2177 | extract_function, | 2251 | extract_function, |
2178 | r" | 2252 | r#" |
2179 | struct S { f: i32 }; | 2253 | struct S { f: i32 }; |
2180 | 2254 | ||
2181 | impl S { | 2255 | impl S { |
2182 | fn foo(&mut self) { | 2256 | fn foo(&mut self) { |
2183 | $0self.f += 1;$0 | 2257 | $0self.f += 1;$0 |
2184 | } | 2258 | } |
2185 | }", | 2259 | } |
2186 | r" | 2260 | "#, |
2261 | r#" | ||
2187 | struct S { f: i32 }; | 2262 | struct S { f: i32 }; |
2188 | 2263 | ||
2189 | impl S { | 2264 | impl S { |
@@ -2194,7 +2269,8 @@ impl S { | |||
2194 | fn $0fun_name(&mut self) { | 2269 | fn $0fun_name(&mut self) { |
2195 | self.f += 1; | 2270 | self.f += 1; |
2196 | } | 2271 | } |
2197 | }", | 2272 | } |
2273 | "#, | ||
2198 | ); | 2274 | ); |
2199 | } | 2275 | } |
2200 | 2276 | ||
@@ -2202,13 +2278,14 @@ impl S { | |||
2202 | fn variable_defined_inside_and_used_after_no_ret() { | 2278 | fn variable_defined_inside_and_used_after_no_ret() { |
2203 | check_assist( | 2279 | check_assist( |
2204 | extract_function, | 2280 | extract_function, |
2205 | r" | 2281 | r#" |
2206 | fn foo() { | 2282 | fn foo() { |
2207 | let n = 1; | 2283 | let n = 1; |
2208 | $0let k = n * n;$0 | 2284 | $0let k = n * n;$0 |
2209 | let m = k + 1; | 2285 | let m = k + 1; |
2210 | }", | 2286 | } |
2211 | r" | 2287 | "#, |
2288 | r#" | ||
2212 | fn foo() { | 2289 | fn foo() { |
2213 | let n = 1; | 2290 | let n = 1; |
2214 | let k = fun_name(n); | 2291 | let k = fun_name(n); |
@@ -2218,7 +2295,8 @@ fn foo() { | |||
2218 | fn $0fun_name(n: i32) -> i32 { | 2295 | fn $0fun_name(n: i32) -> i32 { |
2219 | let k = n * n; | 2296 | let k = n * n; |
2220 | k | 2297 | k |
2221 | }", | 2298 | } |
2299 | "#, | ||
2222 | ); | 2300 | ); |
2223 | } | 2301 | } |
2224 | 2302 | ||
@@ -2226,13 +2304,14 @@ fn $0fun_name(n: i32) -> i32 { | |||
2226 | fn variable_defined_inside_and_used_after_mutably_no_ret() { | 2304 | fn variable_defined_inside_and_used_after_mutably_no_ret() { |
2227 | check_assist( | 2305 | check_assist( |
2228 | extract_function, | 2306 | extract_function, |
2229 | r" | 2307 | r#" |
2230 | fn foo() { | 2308 | fn foo() { |
2231 | let n = 1; | 2309 | let n = 1; |
2232 | $0let mut k = n * n;$0 | 2310 | $0let mut k = n * n;$0 |
2233 | k += 1; | 2311 | k += 1; |
2234 | }", | 2312 | } |
2235 | r" | 2313 | "#, |
2314 | r#" | ||
2236 | fn foo() { | 2315 | fn foo() { |
2237 | let n = 1; | 2316 | let n = 1; |
2238 | let mut k = fun_name(n); | 2317 | let mut k = fun_name(n); |
@@ -2242,7 +2321,8 @@ fn foo() { | |||
2242 | fn $0fun_name(n: i32) -> i32 { | 2321 | fn $0fun_name(n: i32) -> i32 { |
2243 | let mut k = n * n; | 2322 | let mut k = n * n; |
2244 | k | 2323 | k |
2245 | }", | 2324 | } |
2325 | "#, | ||
2246 | ); | 2326 | ); |
2247 | } | 2327 | } |
2248 | 2328 | ||
@@ -2250,14 +2330,15 @@ fn $0fun_name(n: i32) -> i32 { | |||
2250 | fn two_variables_defined_inside_and_used_after_no_ret() { | 2330 | fn two_variables_defined_inside_and_used_after_no_ret() { |
2251 | check_assist( | 2331 | check_assist( |
2252 | extract_function, | 2332 | extract_function, |
2253 | r" | 2333 | r#" |
2254 | fn foo() { | 2334 | fn foo() { |
2255 | let n = 1; | 2335 | let n = 1; |
2256 | $0let k = n * n; | 2336 | $0let k = n * n; |
2257 | let m = k + 2;$0 | 2337 | let m = k + 2;$0 |
2258 | let h = k + m; | 2338 | let h = k + m; |
2259 | }", | 2339 | } |
2260 | r" | 2340 | "#, |
2341 | r#" | ||
2261 | fn foo() { | 2342 | fn foo() { |
2262 | let n = 1; | 2343 | let n = 1; |
2263 | let (k, m) = fun_name(n); | 2344 | let (k, m) = fun_name(n); |
@@ -2268,7 +2349,8 @@ fn $0fun_name(n: i32) -> (i32, i32) { | |||
2268 | let k = n * n; | 2349 | let k = n * n; |
2269 | let m = k + 2; | 2350 | let m = k + 2; |
2270 | (k, m) | 2351 | (k, m) |
2271 | }", | 2352 | } |
2353 | "#, | ||
2272 | ); | 2354 | ); |
2273 | } | 2355 | } |
2274 | 2356 | ||
@@ -2276,7 +2358,7 @@ fn $0fun_name(n: i32) -> (i32, i32) { | |||
2276 | fn multi_variables_defined_inside_and_used_after_mutably_no_ret() { | 2358 | fn multi_variables_defined_inside_and_used_after_mutably_no_ret() { |
2277 | check_assist( | 2359 | check_assist( |
2278 | extract_function, | 2360 | extract_function, |
2279 | r" | 2361 | r#" |
2280 | fn foo() { | 2362 | fn foo() { |
2281 | let n = 1; | 2363 | let n = 1; |
2282 | $0let mut k = n * n; | 2364 | $0let mut k = n * n; |
@@ -2285,8 +2367,9 @@ fn foo() { | |||
2285 | o += 1;$0 | 2367 | o += 1;$0 |
2286 | k += o; | 2368 | k += o; |
2287 | m = 1; | 2369 | m = 1; |
2288 | }", | 2370 | } |
2289 | r" | 2371 | "#, |
2372 | r#" | ||
2290 | fn foo() { | 2373 | fn foo() { |
2291 | let n = 1; | 2374 | let n = 1; |
2292 | let (mut k, mut m, o) = fun_name(n); | 2375 | let (mut k, mut m, o) = fun_name(n); |
@@ -2300,7 +2383,8 @@ fn $0fun_name(n: i32) -> (i32, i32, i32) { | |||
2300 | let mut o = m + 3; | 2383 | let mut o = m + 3; |
2301 | o += 1; | 2384 | o += 1; |
2302 | (k, m, o) | 2385 | (k, m, o) |
2303 | }", | 2386 | } |
2387 | "#, | ||
2304 | ); | 2388 | ); |
2305 | } | 2389 | } |
2306 | 2390 | ||
@@ -2308,13 +2392,14 @@ fn $0fun_name(n: i32) -> (i32, i32, i32) { | |||
2308 | fn nontrivial_patterns_define_variables() { | 2392 | fn nontrivial_patterns_define_variables() { |
2309 | check_assist( | 2393 | check_assist( |
2310 | extract_function, | 2394 | extract_function, |
2311 | r" | 2395 | r#" |
2312 | struct Counter(i32); | 2396 | struct Counter(i32); |
2313 | fn foo() { | 2397 | fn foo() { |
2314 | $0let Counter(n) = Counter(0);$0 | 2398 | $0let Counter(n) = Counter(0);$0 |
2315 | let m = n; | 2399 | let m = n; |
2316 | }", | 2400 | } |
2317 | r" | 2401 | "#, |
2402 | r#" | ||
2318 | struct Counter(i32); | 2403 | struct Counter(i32); |
2319 | fn foo() { | 2404 | fn foo() { |
2320 | let n = fun_name(); | 2405 | let n = fun_name(); |
@@ -2324,7 +2409,8 @@ fn foo() { | |||
2324 | fn $0fun_name() -> i32 { | 2409 | fn $0fun_name() -> i32 { |
2325 | let Counter(n) = Counter(0); | 2410 | let Counter(n) = Counter(0); |
2326 | n | 2411 | n |
2327 | }", | 2412 | } |
2413 | "#, | ||
2328 | ); | 2414 | ); |
2329 | } | 2415 | } |
2330 | 2416 | ||
@@ -2332,13 +2418,14 @@ fn $0fun_name() -> i32 { | |||
2332 | fn struct_with_two_fields_pattern_define_variables() { | 2418 | fn struct_with_two_fields_pattern_define_variables() { |
2333 | check_assist( | 2419 | check_assist( |
2334 | extract_function, | 2420 | extract_function, |
2335 | r" | 2421 | r#" |
2336 | struct Counter { n: i32, m: i32 }; | 2422 | struct Counter { n: i32, m: i32 }; |
2337 | fn foo() { | 2423 | fn foo() { |
2338 | $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0 | 2424 | $0let Counter { n, m: k } = Counter { n: 1, m: 2 };$0 |
2339 | let h = n + k; | 2425 | let h = n + k; |
2340 | }", | 2426 | } |
2341 | r" | 2427 | "#, |
2428 | r#" | ||
2342 | struct Counter { n: i32, m: i32 }; | 2429 | struct Counter { n: i32, m: i32 }; |
2343 | fn foo() { | 2430 | fn foo() { |
2344 | let (n, k) = fun_name(); | 2431 | let (n, k) = fun_name(); |
@@ -2348,7 +2435,8 @@ fn foo() { | |||
2348 | fn $0fun_name() -> (i32, i32) { | 2435 | fn $0fun_name() -> (i32, i32) { |
2349 | let Counter { n, m: k } = Counter { n: 1, m: 2 }; | 2436 | let Counter { n, m: k } = Counter { n: 1, m: 2 }; |
2350 | (n, k) | 2437 | (n, k) |
2351 | }", | 2438 | } |
2439 | "#, | ||
2352 | ); | 2440 | ); |
2353 | } | 2441 | } |
2354 | 2442 | ||
@@ -2356,13 +2444,14 @@ fn $0fun_name() -> (i32, i32) { | |||
2356 | fn mut_var_from_outer_scope() { | 2444 | fn mut_var_from_outer_scope() { |
2357 | check_assist( | 2445 | check_assist( |
2358 | extract_function, | 2446 | extract_function, |
2359 | r" | 2447 | r#" |
2360 | fn foo() { | 2448 | fn foo() { |
2361 | let mut n = 1; | 2449 | let mut n = 1; |
2362 | $0n += 1;$0 | 2450 | $0n += 1;$0 |
2363 | let m = n + 1; | 2451 | let m = n + 1; |
2364 | }", | 2452 | } |
2365 | r" | 2453 | "#, |
2454 | r#" | ||
2366 | fn foo() { | 2455 | fn foo() { |
2367 | let mut n = 1; | 2456 | let mut n = 1; |
2368 | fun_name(&mut n); | 2457 | fun_name(&mut n); |
@@ -2371,7 +2460,8 @@ fn foo() { | |||
2371 | 2460 | ||
2372 | fn $0fun_name(n: &mut i32) { | 2461 | fn $0fun_name(n: &mut i32) { |
2373 | *n += 1; | 2462 | *n += 1; |
2374 | }", | 2463 | } |
2464 | "#, | ||
2375 | ); | 2465 | ); |
2376 | } | 2466 | } |
2377 | 2467 | ||
@@ -2379,14 +2469,15 @@ fn $0fun_name(n: &mut i32) { | |||
2379 | fn mut_field_from_outer_scope() { | 2469 | fn mut_field_from_outer_scope() { |
2380 | check_assist( | 2470 | check_assist( |
2381 | extract_function, | 2471 | extract_function, |
2382 | r" | 2472 | r#" |
2383 | struct C { n: i32 } | 2473 | struct C { n: i32 } |
2384 | fn foo() { | 2474 | fn foo() { |
2385 | let mut c = C { n: 0 }; | 2475 | let mut c = C { n: 0 }; |
2386 | $0c.n += 1;$0 | 2476 | $0c.n += 1;$0 |
2387 | let m = c.n + 1; | 2477 | let m = c.n + 1; |
2388 | }", | 2478 | } |
2389 | r" | 2479 | "#, |
2480 | r#" | ||
2390 | struct C { n: i32 } | 2481 | struct C { n: i32 } |
2391 | fn foo() { | 2482 | fn foo() { |
2392 | let mut c = C { n: 0 }; | 2483 | let mut c = C { n: 0 }; |
@@ -2396,7 +2487,8 @@ fn foo() { | |||
2396 | 2487 | ||
2397 | fn $0fun_name(c: &mut C) { | 2488 | fn $0fun_name(c: &mut C) { |
2398 | c.n += 1; | 2489 | c.n += 1; |
2399 | }", | 2490 | } |
2491 | "#, | ||
2400 | ); | 2492 | ); |
2401 | } | 2493 | } |
2402 | 2494 | ||
@@ -2404,7 +2496,7 @@ fn $0fun_name(c: &mut C) { | |||
2404 | fn mut_nested_field_from_outer_scope() { | 2496 | fn mut_nested_field_from_outer_scope() { |
2405 | check_assist( | 2497 | check_assist( |
2406 | extract_function, | 2498 | extract_function, |
2407 | r" | 2499 | r#" |
2408 | struct P { n: i32} | 2500 | struct P { n: i32} |
2409 | struct C { p: P } | 2501 | struct C { p: P } |
2410 | fn foo() { | 2502 | fn foo() { |
@@ -2414,8 +2506,9 @@ fn foo() { | |||
2414 | $0c.p.n += u.p.n; | 2506 | $0c.p.n += u.p.n; |
2415 | let r = &mut v.p.n;$0 | 2507 | let r = &mut v.p.n;$0 |
2416 | let m = c.p.n + v.p.n + u.p.n; | 2508 | let m = c.p.n + v.p.n + u.p.n; |
2417 | }", | 2509 | } |
2418 | r" | 2510 | "#, |
2511 | r#" | ||
2419 | struct P { n: i32} | 2512 | struct P { n: i32} |
2420 | struct C { p: P } | 2513 | struct C { p: P } |
2421 | fn foo() { | 2514 | fn foo() { |
@@ -2429,7 +2522,8 @@ fn foo() { | |||
2429 | fn $0fun_name(c: &mut C, u: &C, v: &mut C) { | 2522 | fn $0fun_name(c: &mut C, u: &C, v: &mut C) { |
2430 | c.p.n += u.p.n; | 2523 | c.p.n += u.p.n; |
2431 | let r = &mut v.p.n; | 2524 | let r = &mut v.p.n; |
2432 | }", | 2525 | } |
2526 | "#, | ||
2433 | ); | 2527 | ); |
2434 | } | 2528 | } |
2435 | 2529 | ||
@@ -2437,7 +2531,7 @@ fn $0fun_name(c: &mut C, u: &C, v: &mut C) { | |||
2437 | fn mut_param_many_usages_stmt() { | 2531 | fn mut_param_many_usages_stmt() { |
2438 | check_assist( | 2532 | check_assist( |
2439 | extract_function, | 2533 | extract_function, |
2440 | r" | 2534 | r#" |
2441 | fn bar(k: i32) {} | 2535 | fn bar(k: i32) {} |
2442 | trait I: Copy { | 2536 | trait I: Copy { |
2443 | fn succ(&self) -> Self; | 2537 | fn succ(&self) -> Self; |
@@ -2458,8 +2552,9 @@ fn foo() { | |||
2458 | *v = v.succ(); | 2552 | *v = v.succ(); |
2459 | n.succ();$0 | 2553 | n.succ();$0 |
2460 | let m = n + 1; | 2554 | let m = n + 1; |
2461 | }", | 2555 | } |
2462 | r" | 2556 | "#, |
2557 | r#" | ||
2463 | fn bar(k: i32) {} | 2558 | fn bar(k: i32) {} |
2464 | trait I: Copy { | 2559 | trait I: Copy { |
2465 | fn succ(&self) -> Self; | 2560 | fn succ(&self) -> Self; |
@@ -2484,7 +2579,8 @@ fn $0fun_name(n: &mut i32) { | |||
2484 | let v = n; | 2579 | let v = n; |
2485 | *v = v.succ(); | 2580 | *v = v.succ(); |
2486 | n.succ(); | 2581 | n.succ(); |
2487 | }", | 2582 | } |
2583 | "#, | ||
2488 | ); | 2584 | ); |
2489 | } | 2585 | } |
2490 | 2586 | ||
@@ -2492,7 +2588,7 @@ fn $0fun_name(n: &mut i32) { | |||
2492 | fn mut_param_many_usages_expr() { | 2588 | fn mut_param_many_usages_expr() { |
2493 | check_assist( | 2589 | check_assist( |
2494 | extract_function, | 2590 | extract_function, |
2495 | r" | 2591 | r#" |
2496 | fn bar(k: i32) {} | 2592 | fn bar(k: i32) {} |
2497 | trait I: Copy { | 2593 | trait I: Copy { |
2498 | fn succ(&self) -> Self; | 2594 | fn succ(&self) -> Self; |
@@ -2515,8 +2611,9 @@ fn foo() { | |||
2515 | n.succ(); | 2611 | n.succ(); |
2516 | }$0 | 2612 | }$0 |
2517 | let m = n + 1; | 2613 | let m = n + 1; |
2518 | }", | 2614 | } |
2519 | r" | 2615 | "#, |
2616 | r#" | ||
2520 | fn bar(k: i32) {} | 2617 | fn bar(k: i32) {} |
2521 | trait I: Copy { | 2618 | trait I: Copy { |
2522 | fn succ(&self) -> Self; | 2619 | fn succ(&self) -> Self; |
@@ -2541,7 +2638,8 @@ fn $0fun_name(n: &mut i32) { | |||
2541 | let v = n; | 2638 | let v = n; |
2542 | *v = v.succ(); | 2639 | *v = v.succ(); |
2543 | n.succ(); | 2640 | n.succ(); |
2544 | }", | 2641 | } |
2642 | "#, | ||
2545 | ); | 2643 | ); |
2546 | } | 2644 | } |
2547 | 2645 | ||
@@ -2549,11 +2647,12 @@ fn $0fun_name(n: &mut i32) { | |||
2549 | fn mut_param_by_value() { | 2647 | fn mut_param_by_value() { |
2550 | check_assist( | 2648 | check_assist( |
2551 | extract_function, | 2649 | extract_function, |
2552 | r" | 2650 | r#" |
2553 | fn foo() { | 2651 | fn foo() { |
2554 | let mut n = 1; | 2652 | let mut n = 1; |
2555 | $0n += 1;$0 | 2653 | $0n += 1;$0 |
2556 | }", | 2654 | } |
2655 | "#, | ||
2557 | r" | 2656 | r" |
2558 | fn foo() { | 2657 | fn foo() { |
2559 | let mut n = 1; | 2658 | let mut n = 1; |
@@ -2562,7 +2661,8 @@ fn foo() { | |||
2562 | 2661 | ||
2563 | fn $0fun_name(mut n: i32) { | 2662 | fn $0fun_name(mut n: i32) { |
2564 | n += 1; | 2663 | n += 1; |
2565 | }", | 2664 | } |
2665 | ", | ||
2566 | ); | 2666 | ); |
2567 | } | 2667 | } |
2568 | 2668 | ||
@@ -2570,14 +2670,15 @@ fn $0fun_name(mut n: i32) { | |||
2570 | fn mut_param_because_of_mut_ref() { | 2670 | fn mut_param_because_of_mut_ref() { |
2571 | check_assist( | 2671 | check_assist( |
2572 | extract_function, | 2672 | extract_function, |
2573 | r" | 2673 | r#" |
2574 | fn foo() { | 2674 | fn foo() { |
2575 | let mut n = 1; | 2675 | let mut n = 1; |
2576 | $0let v = &mut n; | 2676 | $0let v = &mut n; |
2577 | *v += 1;$0 | 2677 | *v += 1;$0 |
2578 | let k = n; | 2678 | let k = n; |
2579 | }", | 2679 | } |
2580 | r" | 2680 | "#, |
2681 | r#" | ||
2581 | fn foo() { | 2682 | fn foo() { |
2582 | let mut n = 1; | 2683 | let mut n = 1; |
2583 | fun_name(&mut n); | 2684 | fun_name(&mut n); |
@@ -2587,7 +2688,8 @@ fn foo() { | |||
2587 | fn $0fun_name(n: &mut i32) { | 2688 | fn $0fun_name(n: &mut i32) { |
2588 | let v = n; | 2689 | let v = n; |
2589 | *v += 1; | 2690 | *v += 1; |
2590 | }", | 2691 | } |
2692 | "#, | ||
2591 | ); | 2693 | ); |
2592 | } | 2694 | } |
2593 | 2695 | ||
@@ -2600,8 +2702,9 @@ fn foo() { | |||
2600 | let mut n = 1; | 2702 | let mut n = 1; |
2601 | $0let v = &mut n; | 2703 | $0let v = &mut n; |
2602 | *v += 1;$0 | 2704 | *v += 1;$0 |
2603 | }", | 2705 | } |
2604 | r" | 2706 | ", |
2707 | r#" | ||
2605 | fn foo() { | 2708 | fn foo() { |
2606 | let mut n = 1; | 2709 | let mut n = 1; |
2607 | fun_name(n); | 2710 | fun_name(n); |
@@ -2610,7 +2713,8 @@ fn foo() { | |||
2610 | fn $0fun_name(mut n: i32) { | 2713 | fn $0fun_name(mut n: i32) { |
2611 | let v = &mut n; | 2714 | let v = &mut n; |
2612 | *v += 1; | 2715 | *v += 1; |
2613 | }", | 2716 | } |
2717 | "#, | ||
2614 | ); | 2718 | ); |
2615 | } | 2719 | } |
2616 | 2720 | ||
@@ -2618,7 +2722,7 @@ fn $0fun_name(mut n: i32) { | |||
2618 | fn mut_method_call() { | 2722 | fn mut_method_call() { |
2619 | check_assist( | 2723 | check_assist( |
2620 | extract_function, | 2724 | extract_function, |
2621 | r" | 2725 | r#" |
2622 | trait I { | 2726 | trait I { |
2623 | fn inc(&mut self); | 2727 | fn inc(&mut self); |
2624 | } | 2728 | } |
@@ -2628,8 +2732,9 @@ impl I for i32 { | |||
2628 | fn foo() { | 2732 | fn foo() { |
2629 | let mut n = 1; | 2733 | let mut n = 1; |
2630 | $0n.inc();$0 | 2734 | $0n.inc();$0 |
2631 | }", | 2735 | } |
2632 | r" | 2736 | "#, |
2737 | r#" | ||
2633 | trait I { | 2738 | trait I { |
2634 | fn inc(&mut self); | 2739 | fn inc(&mut self); |
2635 | } | 2740 | } |
@@ -2643,7 +2748,8 @@ fn foo() { | |||
2643 | 2748 | ||
2644 | fn $0fun_name(mut n: i32) { | 2749 | fn $0fun_name(mut n: i32) { |
2645 | n.inc(); | 2750 | n.inc(); |
2646 | }", | 2751 | } |
2752 | "#, | ||
2647 | ); | 2753 | ); |
2648 | } | 2754 | } |
2649 | 2755 | ||
@@ -2651,7 +2757,7 @@ fn $0fun_name(mut n: i32) { | |||
2651 | fn shared_method_call() { | 2757 | fn shared_method_call() { |
2652 | check_assist( | 2758 | check_assist( |
2653 | extract_function, | 2759 | extract_function, |
2654 | r" | 2760 | r#" |
2655 | trait I { | 2761 | trait I { |
2656 | fn succ(&self); | 2762 | fn succ(&self); |
2657 | } | 2763 | } |
@@ -2661,7 +2767,8 @@ impl I for i32 { | |||
2661 | fn foo() { | 2767 | fn foo() { |
2662 | let mut n = 1; | 2768 | let mut n = 1; |
2663 | $0n.succ();$0 | 2769 | $0n.succ();$0 |
2664 | }", | 2770 | } |
2771 | "#, | ||
2665 | r" | 2772 | r" |
2666 | trait I { | 2773 | trait I { |
2667 | fn succ(&self); | 2774 | fn succ(&self); |
@@ -2676,7 +2783,8 @@ fn foo() { | |||
2676 | 2783 | ||
2677 | fn $0fun_name(n: i32) { | 2784 | fn $0fun_name(n: i32) { |
2678 | n.succ(); | 2785 | n.succ(); |
2679 | }", | 2786 | } |
2787 | ", | ||
2680 | ); | 2788 | ); |
2681 | } | 2789 | } |
2682 | 2790 | ||
@@ -2684,7 +2792,7 @@ fn $0fun_name(n: i32) { | |||
2684 | fn mut_method_call_with_other_receiver() { | 2792 | fn mut_method_call_with_other_receiver() { |
2685 | check_assist( | 2793 | check_assist( |
2686 | extract_function, | 2794 | extract_function, |
2687 | r" | 2795 | r#" |
2688 | trait I { | 2796 | trait I { |
2689 | fn inc(&mut self, n: i32); | 2797 | fn inc(&mut self, n: i32); |
2690 | } | 2798 | } |
@@ -2695,7 +2803,8 @@ fn foo() { | |||
2695 | let mut n = 1; | 2803 | let mut n = 1; |
2696 | $0let mut m = 2; | 2804 | $0let mut m = 2; |
2697 | m.inc(n);$0 | 2805 | m.inc(n);$0 |
2698 | }", | 2806 | } |
2807 | "#, | ||
2699 | r" | 2808 | r" |
2700 | trait I { | 2809 | trait I { |
2701 | fn inc(&mut self, n: i32); | 2810 | fn inc(&mut self, n: i32); |
@@ -2711,7 +2820,8 @@ fn foo() { | |||
2711 | fn $0fun_name(n: i32) { | 2820 | fn $0fun_name(n: i32) { |
2712 | let mut m = 2; | 2821 | let mut m = 2; |
2713 | m.inc(n); | 2822 | m.inc(n); |
2714 | }", | 2823 | } |
2824 | ", | ||
2715 | ); | 2825 | ); |
2716 | } | 2826 | } |
2717 | 2827 | ||
@@ -2719,12 +2829,13 @@ fn $0fun_name(n: i32) { | |||
2719 | fn non_copy_without_usages_after() { | 2829 | fn non_copy_without_usages_after() { |
2720 | check_assist( | 2830 | check_assist( |
2721 | extract_function, | 2831 | extract_function, |
2722 | r" | 2832 | r#" |
2723 | struct Counter(i32); | 2833 | struct Counter(i32); |
2724 | fn foo() { | 2834 | fn foo() { |
2725 | let c = Counter(0); | 2835 | let c = Counter(0); |
2726 | $0let n = c.0;$0 | 2836 | $0let n = c.0;$0 |
2727 | }", | 2837 | } |
2838 | "#, | ||
2728 | r" | 2839 | r" |
2729 | struct Counter(i32); | 2840 | struct Counter(i32); |
2730 | fn foo() { | 2841 | fn foo() { |
@@ -2734,7 +2845,8 @@ fn foo() { | |||
2734 | 2845 | ||
2735 | fn $0fun_name(c: Counter) { | 2846 | fn $0fun_name(c: Counter) { |
2736 | let n = c.0; | 2847 | let n = c.0; |
2737 | }", | 2848 | } |
2849 | ", | ||
2738 | ); | 2850 | ); |
2739 | } | 2851 | } |
2740 | 2852 | ||
@@ -2748,8 +2860,9 @@ fn foo() { | |||
2748 | let c = Counter(0); | 2860 | let c = Counter(0); |
2749 | $0let n = c.0;$0 | 2861 | $0let n = c.0;$0 |
2750 | let m = c.0; | 2862 | let m = c.0; |
2751 | }", | 2863 | } |
2752 | r" | 2864 | ", |
2865 | r#" | ||
2753 | struct Counter(i32); | 2866 | struct Counter(i32); |
2754 | fn foo() { | 2867 | fn foo() { |
2755 | let c = Counter(0); | 2868 | let c = Counter(0); |
@@ -2759,7 +2872,8 @@ fn foo() { | |||
2759 | 2872 | ||
2760 | fn $0fun_name(c: &Counter) { | 2873 | fn $0fun_name(c: &Counter) { |
2761 | let n = c.0; | 2874 | let n = c.0; |
2762 | }", | 2875 | } |
2876 | "#, | ||
2763 | ); | 2877 | ); |
2764 | } | 2878 | } |
2765 | 2879 | ||
@@ -2767,19 +2881,15 @@ fn $0fun_name(c: &Counter) { | |||
2767 | fn copy_used_after() { | 2881 | fn copy_used_after() { |
2768 | check_assist( | 2882 | check_assist( |
2769 | extract_function, | 2883 | extract_function, |
2770 | r##" | 2884 | r#" |
2771 | #[lang = "copy"] | 2885 | //- minicore: copy |
2772 | pub trait Copy {} | ||
2773 | impl Copy for i32 {} | ||
2774 | fn foo() { | 2886 | fn foo() { |
2775 | let n = 0; | 2887 | let n = 0; |
2776 | $0let m = n;$0 | 2888 | $0let m = n;$0 |
2777 | let k = n; | 2889 | let k = n; |
2778 | }"##, | 2890 | } |
2779 | r##" | 2891 | "#, |
2780 | #[lang = "copy"] | 2892 | r#" |
2781 | pub trait Copy {} | ||
2782 | impl Copy for i32 {} | ||
2783 | fn foo() { | 2893 | fn foo() { |
2784 | let n = 0; | 2894 | let n = 0; |
2785 | fun_name(n); | 2895 | fun_name(n); |
@@ -2788,7 +2898,8 @@ fn foo() { | |||
2788 | 2898 | ||
2789 | fn $0fun_name(n: i32) { | 2899 | fn $0fun_name(n: i32) { |
2790 | let m = n; | 2900 | let m = n; |
2791 | }"##, | 2901 | } |
2902 | "#, | ||
2792 | ) | 2903 | ) |
2793 | } | 2904 | } |
2794 | 2905 | ||
@@ -2796,21 +2907,19 @@ fn $0fun_name(n: i32) { | |||
2796 | fn copy_custom_used_after() { | 2907 | fn copy_custom_used_after() { |
2797 | check_assist( | 2908 | check_assist( |
2798 | extract_function, | 2909 | extract_function, |
2799 | r##" | 2910 | r#" |
2800 | #[lang = "copy"] | 2911 | //- minicore: copy, derive |
2801 | pub trait Copy {} | 2912 | #[derive(Clone, Copy)] |
2802 | struct Counter(i32); | 2913 | struct Counter(i32); |
2803 | impl Copy for Counter {} | ||
2804 | fn foo() { | 2914 | fn foo() { |
2805 | let c = Counter(0); | 2915 | let c = Counter(0); |
2806 | $0let n = c.0;$0 | 2916 | $0let n = c.0;$0 |
2807 | let m = c.0; | 2917 | let m = c.0; |
2808 | }"##, | 2918 | } |
2809 | r##" | 2919 | "#, |
2810 | #[lang = "copy"] | 2920 | r#" |
2811 | pub trait Copy {} | 2921 | #[derive(Clone, Copy)] |
2812 | struct Counter(i32); | 2922 | struct Counter(i32); |
2813 | impl Copy for Counter {} | ||
2814 | fn foo() { | 2923 | fn foo() { |
2815 | let c = Counter(0); | 2924 | let c = Counter(0); |
2816 | fun_name(c); | 2925 | fun_name(c); |
@@ -2819,7 +2928,8 @@ fn foo() { | |||
2819 | 2928 | ||
2820 | fn $0fun_name(c: Counter) { | 2929 | fn $0fun_name(c: Counter) { |
2821 | let n = c.0; | 2930 | let n = c.0; |
2822 | }"##, | 2931 | } |
2932 | "#, | ||
2823 | ); | 2933 | ); |
2824 | } | 2934 | } |
2825 | 2935 | ||
@@ -2827,7 +2937,7 @@ fn $0fun_name(c: Counter) { | |||
2827 | fn indented_stmts() { | 2937 | fn indented_stmts() { |
2828 | check_assist( | 2938 | check_assist( |
2829 | extract_function, | 2939 | extract_function, |
2830 | r" | 2940 | r#" |
2831 | fn foo() { | 2941 | fn foo() { |
2832 | if true { | 2942 | if true { |
2833 | loop { | 2943 | loop { |
@@ -2835,8 +2945,9 @@ fn foo() { | |||
2835 | let m = 2;$0 | 2945 | let m = 2;$0 |
2836 | } | 2946 | } |
2837 | } | 2947 | } |
2838 | }", | 2948 | } |
2839 | r" | 2949 | "#, |
2950 | r#" | ||
2840 | fn foo() { | 2951 | fn foo() { |
2841 | if true { | 2952 | if true { |
2842 | loop { | 2953 | loop { |
@@ -2848,7 +2959,8 @@ fn foo() { | |||
2848 | fn $0fun_name() { | 2959 | fn $0fun_name() { |
2849 | let n = 1; | 2960 | let n = 1; |
2850 | let m = 2; | 2961 | let m = 2; |
2851 | }", | 2962 | } |
2963 | "#, | ||
2852 | ); | 2964 | ); |
2853 | } | 2965 | } |
2854 | 2966 | ||
@@ -2856,7 +2968,7 @@ fn $0fun_name() { | |||
2856 | fn indented_stmts_inside_mod() { | 2968 | fn indented_stmts_inside_mod() { |
2857 | check_assist( | 2969 | check_assist( |
2858 | extract_function, | 2970 | extract_function, |
2859 | r" | 2971 | r#" |
2860 | mod bar { | 2972 | mod bar { |
2861 | fn foo() { | 2973 | fn foo() { |
2862 | if true { | 2974 | if true { |
@@ -2866,8 +2978,9 @@ mod bar { | |||
2866 | } | 2978 | } |
2867 | } | 2979 | } |
2868 | } | 2980 | } |
2869 | }", | 2981 | } |
2870 | r" | 2982 | "#, |
2983 | r#" | ||
2871 | mod bar { | 2984 | mod bar { |
2872 | fn foo() { | 2985 | fn foo() { |
2873 | if true { | 2986 | if true { |
@@ -2881,7 +2994,8 @@ mod bar { | |||
2881 | let n = 1; | 2994 | let n = 1; |
2882 | let m = 2; | 2995 | let m = 2; |
2883 | } | 2996 | } |
2884 | }", | 2997 | } |
2998 | "#, | ||
2885 | ); | 2999 | ); |
2886 | } | 3000 | } |
2887 | 3001 | ||
@@ -2889,12 +3003,8 @@ mod bar { | |||
2889 | fn break_loop() { | 3003 | fn break_loop() { |
2890 | check_assist( | 3004 | check_assist( |
2891 | extract_function, | 3005 | extract_function, |
2892 | r##" | 3006 | r#" |
2893 | enum Option<T> { | 3007 | //- minicore: option |
2894 | #[lang = "None"] None, | ||
2895 | #[lang = "Some"] Some(T), | ||
2896 | } | ||
2897 | use Option::*; | ||
2898 | fn foo() { | 3008 | fn foo() { |
2899 | loop { | 3009 | loop { |
2900 | let n = 1; | 3010 | let n = 1; |
@@ -2903,13 +3013,9 @@ fn foo() { | |||
2903 | let k = 2;$0 | 3013 | let k = 2;$0 |
2904 | let h = 1 + k; | 3014 | let h = 1 + k; |
2905 | } | 3015 | } |
2906 | }"##, | ||
2907 | r##" | ||
2908 | enum Option<T> { | ||
2909 | #[lang = "None"] None, | ||
2910 | #[lang = "Some"] Some(T), | ||
2911 | } | 3016 | } |
2912 | use Option::*; | 3017 | "#, |
3018 | r#" | ||
2913 | fn foo() { | 3019 | fn foo() { |
2914 | loop { | 3020 | loop { |
2915 | let n = 1; | 3021 | let n = 1; |
@@ -2926,7 +3032,8 @@ fn $0fun_name(n: i32) -> Option<i32> { | |||
2926 | return None; | 3032 | return None; |
2927 | let k = 2; | 3033 | let k = 2; |
2928 | Some(k) | 3034 | Some(k) |
2929 | }"##, | 3035 | } |
3036 | "#, | ||
2930 | ); | 3037 | ); |
2931 | } | 3038 | } |
2932 | 3039 | ||
@@ -2934,31 +3041,17 @@ fn $0fun_name(n: i32) -> Option<i32> { | |||
2934 | fn return_to_parent() { | 3041 | fn return_to_parent() { |
2935 | check_assist( | 3042 | check_assist( |
2936 | extract_function, | 3043 | extract_function, |
2937 | r##" | 3044 | r#" |
2938 | #[lang = "copy"] | 3045 | //- minicore: copy, result |
2939 | pub trait Copy {} | ||
2940 | impl Copy for i32 {} | ||
2941 | enum Result<T, E> { | ||
2942 | #[lang = "Ok"] Ok(T), | ||
2943 | #[lang = "Err"] Err(E), | ||
2944 | } | ||
2945 | use Result::*; | ||
2946 | fn foo() -> i64 { | 3046 | fn foo() -> i64 { |
2947 | let n = 1; | 3047 | let n = 1; |
2948 | $0let m = n + 1; | 3048 | $0let m = n + 1; |
2949 | return 1; | 3049 | return 1; |
2950 | let k = 2;$0 | 3050 | let k = 2;$0 |
2951 | (n + k) as i64 | 3051 | (n + k) as i64 |
2952 | }"##, | 3052 | } |
2953 | r##" | 3053 | "#, |
2954 | #[lang = "copy"] | 3054 | r#" |
2955 | pub trait Copy {} | ||
2956 | impl Copy for i32 {} | ||
2957 | enum Result<T, E> { | ||
2958 | #[lang = "Ok"] Ok(T), | ||
2959 | #[lang = "Err"] Err(E), | ||
2960 | } | ||
2961 | use Result::*; | ||
2962 | fn foo() -> i64 { | 3055 | fn foo() -> i64 { |
2963 | let n = 1; | 3056 | let n = 1; |
2964 | let k = match fun_name(n) { | 3057 | let k = match fun_name(n) { |
@@ -2973,7 +3066,8 @@ fn $0fun_name(n: i32) -> Result<i32, i64> { | |||
2973 | return Err(1); | 3066 | return Err(1); |
2974 | let k = 2; | 3067 | let k = 2; |
2975 | Ok(k) | 3068 | Ok(k) |
2976 | }"##, | 3069 | } |
3070 | "#, | ||
2977 | ); | 3071 | ); |
2978 | } | 3072 | } |
2979 | 3073 | ||
@@ -2982,7 +3076,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> { | |||
2982 | cov_mark::check!(external_control_flow_break_and_continue); | 3076 | cov_mark::check!(external_control_flow_break_and_continue); |
2983 | check_assist_not_applicable( | 3077 | check_assist_not_applicable( |
2984 | extract_function, | 3078 | extract_function, |
2985 | r##" | 3079 | r#" |
2986 | fn foo() { | 3080 | fn foo() { |
2987 | loop { | 3081 | loop { |
2988 | let n = 1; | 3082 | let n = 1; |
@@ -2993,7 +3087,8 @@ fn foo() { | |||
2993 | let k = k + 1;$0 | 3087 | let k = k + 1;$0 |
2994 | let r = n + k; | 3088 | let r = n + k; |
2995 | } | 3089 | } |
2996 | }"##, | 3090 | } |
3091 | "#, | ||
2997 | ); | 3092 | ); |
2998 | } | 3093 | } |
2999 | 3094 | ||
@@ -3002,7 +3097,7 @@ fn foo() { | |||
3002 | cov_mark::check!(external_control_flow_return_and_bc); | 3097 | cov_mark::check!(external_control_flow_return_and_bc); |
3003 | check_assist_not_applicable( | 3098 | check_assist_not_applicable( |
3004 | extract_function, | 3099 | extract_function, |
3005 | r##" | 3100 | r#" |
3006 | fn foo() { | 3101 | fn foo() { |
3007 | loop { | 3102 | loop { |
3008 | let n = 1; | 3103 | let n = 1; |
@@ -3013,7 +3108,8 @@ fn foo() { | |||
3013 | let k = k + 1;$0 | 3108 | let k = k + 1;$0 |
3014 | let r = n + k; | 3109 | let r = n + k; |
3015 | } | 3110 | } |
3016 | }"##, | 3111 | } |
3112 | "#, | ||
3017 | ); | 3113 | ); |
3018 | } | 3114 | } |
3019 | 3115 | ||
@@ -3021,7 +3117,7 @@ fn foo() { | |||
3021 | fn break_loop_with_if() { | 3117 | fn break_loop_with_if() { |
3022 | check_assist( | 3118 | check_assist( |
3023 | extract_function, | 3119 | extract_function, |
3024 | r##" | 3120 | r#" |
3025 | fn foo() { | 3121 | fn foo() { |
3026 | loop { | 3122 | loop { |
3027 | let mut n = 1; | 3123 | let mut n = 1; |
@@ -3030,8 +3126,9 @@ fn foo() { | |||
3030 | n += m;$0 | 3126 | n += m;$0 |
3031 | let h = 1 + n; | 3127 | let h = 1 + n; |
3032 | } | 3128 | } |
3033 | }"##, | 3129 | } |
3034 | r##" | 3130 | "#, |
3131 | r#" | ||
3035 | fn foo() { | 3132 | fn foo() { |
3036 | loop { | 3133 | loop { |
3037 | let mut n = 1; | 3134 | let mut n = 1; |
@@ -3047,7 +3144,8 @@ fn $0fun_name(n: &mut i32) -> bool { | |||
3047 | return true; | 3144 | return true; |
3048 | *n += m; | 3145 | *n += m; |
3049 | false | 3146 | false |
3050 | }"##, | 3147 | } |
3148 | "#, | ||
3051 | ); | 3149 | ); |
3052 | } | 3150 | } |
3053 | 3151 | ||
@@ -3055,7 +3153,7 @@ fn $0fun_name(n: &mut i32) -> bool { | |||
3055 | fn break_loop_nested() { | 3153 | fn break_loop_nested() { |
3056 | check_assist( | 3154 | check_assist( |
3057 | extract_function, | 3155 | extract_function, |
3058 | r##" | 3156 | r#" |
3059 | fn foo() { | 3157 | fn foo() { |
3060 | loop { | 3158 | loop { |
3061 | let mut n = 1; | 3159 | let mut n = 1; |
@@ -3065,8 +3163,9 @@ fn foo() { | |||
3065 | }$0 | 3163 | }$0 |
3066 | let h = 1; | 3164 | let h = 1; |
3067 | } | 3165 | } |
3068 | }"##, | 3166 | } |
3069 | r##" | 3167 | "#, |
3168 | r#" | ||
3070 | fn foo() { | 3169 | fn foo() { |
3071 | loop { | 3170 | loop { |
3072 | let mut n = 1; | 3171 | let mut n = 1; |
@@ -3083,7 +3182,8 @@ fn $0fun_name(n: i32) -> bool { | |||
3083 | return true; | 3182 | return true; |
3084 | } | 3183 | } |
3085 | false | 3184 | false |
3086 | }"##, | 3185 | } |
3186 | "#, | ||
3087 | ); | 3187 | ); |
3088 | } | 3188 | } |
3089 | 3189 | ||
@@ -3091,7 +3191,7 @@ fn $0fun_name(n: i32) -> bool { | |||
3091 | fn return_from_nested_loop() { | 3191 | fn return_from_nested_loop() { |
3092 | check_assist( | 3192 | check_assist( |
3093 | extract_function, | 3193 | extract_function, |
3094 | r##" | 3194 | r#" |
3095 | fn foo() { | 3195 | fn foo() { |
3096 | loop { | 3196 | loop { |
3097 | let n = 1; | 3197 | let n = 1; |
@@ -3103,8 +3203,9 @@ fn foo() { | |||
3103 | let m = k + 1;$0 | 3203 | let m = k + 1;$0 |
3104 | let h = 1 + m; | 3204 | let h = 1 + m; |
3105 | } | 3205 | } |
3106 | }"##, | 3206 | } |
3107 | r##" | 3207 | "#, |
3208 | r#" | ||
3108 | fn foo() { | 3209 | fn foo() { |
3109 | loop { | 3210 | loop { |
3110 | let n = 1; | 3211 | let n = 1; |
@@ -3123,7 +3224,8 @@ fn $0fun_name() -> Option<i32> { | |||
3123 | } | 3224 | } |
3124 | let m = k + 1; | 3225 | let m = k + 1; |
3125 | Some(m) | 3226 | Some(m) |
3126 | }"##, | 3227 | } |
3228 | "#, | ||
3127 | ); | 3229 | ); |
3128 | } | 3230 | } |
3129 | 3231 | ||
@@ -3131,7 +3233,7 @@ fn $0fun_name() -> Option<i32> { | |||
3131 | fn break_from_nested_loop() { | 3233 | fn break_from_nested_loop() { |
3132 | check_assist( | 3234 | check_assist( |
3133 | extract_function, | 3235 | extract_function, |
3134 | r##" | 3236 | r#" |
3135 | fn foo() { | 3237 | fn foo() { |
3136 | loop { | 3238 | loop { |
3137 | let n = 1; | 3239 | let n = 1; |
@@ -3142,8 +3244,9 @@ fn foo() { | |||
3142 | let m = k + 1;$0 | 3244 | let m = k + 1;$0 |
3143 | let h = 1 + m; | 3245 | let h = 1 + m; |
3144 | } | 3246 | } |
3145 | }"##, | 3247 | } |
3146 | r##" | 3248 | "#, |
3249 | r#" | ||
3147 | fn foo() { | 3250 | fn foo() { |
3148 | loop { | 3251 | loop { |
3149 | let n = 1; | 3252 | let n = 1; |
@@ -3159,7 +3262,8 @@ fn $0fun_name() -> i32 { | |||
3159 | } | 3262 | } |
3160 | let m = k + 1; | 3263 | let m = k + 1; |
3161 | m | 3264 | m |
3162 | }"##, | 3265 | } |
3266 | "#, | ||
3163 | ); | 3267 | ); |
3164 | } | 3268 | } |
3165 | 3269 | ||
@@ -3167,7 +3271,7 @@ fn $0fun_name() -> i32 { | |||
3167 | fn break_from_nested_and_outer_loops() { | 3271 | fn break_from_nested_and_outer_loops() { |
3168 | check_assist( | 3272 | check_assist( |
3169 | extract_function, | 3273 | extract_function, |
3170 | r##" | 3274 | r#" |
3171 | fn foo() { | 3275 | fn foo() { |
3172 | loop { | 3276 | loop { |
3173 | let n = 1; | 3277 | let n = 1; |
@@ -3181,8 +3285,9 @@ fn foo() { | |||
3181 | let m = k + 1;$0 | 3285 | let m = k + 1;$0 |
3182 | let h = 1 + m; | 3286 | let h = 1 + m; |
3183 | } | 3287 | } |
3184 | }"##, | 3288 | } |
3185 | r##" | 3289 | "#, |
3290 | r#" | ||
3186 | fn foo() { | 3291 | fn foo() { |
3187 | loop { | 3292 | loop { |
3188 | let n = 1; | 3293 | let n = 1; |
@@ -3204,7 +3309,8 @@ fn $0fun_name() -> Option<i32> { | |||
3204 | } | 3309 | } |
3205 | let m = k + 1; | 3310 | let m = k + 1; |
3206 | Some(m) | 3311 | Some(m) |
3207 | }"##, | 3312 | } |
3313 | "#, | ||
3208 | ); | 3314 | ); |
3209 | } | 3315 | } |
3210 | 3316 | ||
@@ -3212,7 +3318,7 @@ fn $0fun_name() -> Option<i32> { | |||
3212 | fn return_from_nested_fn() { | 3318 | fn return_from_nested_fn() { |
3213 | check_assist( | 3319 | check_assist( |
3214 | extract_function, | 3320 | extract_function, |
3215 | r##" | 3321 | r#" |
3216 | fn foo() { | 3322 | fn foo() { |
3217 | loop { | 3323 | loop { |
3218 | let n = 1; | 3324 | let n = 1; |
@@ -3223,8 +3329,9 @@ fn foo() { | |||
3223 | let m = k + 1;$0 | 3329 | let m = k + 1;$0 |
3224 | let h = 1 + m; | 3330 | let h = 1 + m; |
3225 | } | 3331 | } |
3226 | }"##, | 3332 | } |
3227 | r##" | 3333 | "#, |
3334 | r#" | ||
3228 | fn foo() { | 3335 | fn foo() { |
3229 | loop { | 3336 | loop { |
3230 | let n = 1; | 3337 | let n = 1; |
@@ -3240,7 +3347,8 @@ fn $0fun_name() -> i32 { | |||
3240 | } | 3347 | } |
3241 | let m = k + 1; | 3348 | let m = k + 1; |
3242 | m | 3349 | m |
3243 | }"##, | 3350 | } |
3351 | "#, | ||
3244 | ); | 3352 | ); |
3245 | } | 3353 | } |
3246 | 3354 | ||
@@ -3248,7 +3356,7 @@ fn $0fun_name() -> i32 { | |||
3248 | fn break_with_value() { | 3356 | fn break_with_value() { |
3249 | check_assist( | 3357 | check_assist( |
3250 | extract_function, | 3358 | extract_function, |
3251 | r##" | 3359 | r#" |
3252 | fn foo() -> i32 { | 3360 | fn foo() -> i32 { |
3253 | loop { | 3361 | loop { |
3254 | let n = 1; | 3362 | let n = 1; |
@@ -3259,8 +3367,9 @@ fn foo() -> i32 { | |||
3259 | let m = k + 1;$0 | 3367 | let m = k + 1;$0 |
3260 | let h = 1; | 3368 | let h = 1; |
3261 | } | 3369 | } |
3262 | }"##, | 3370 | } |
3263 | r##" | 3371 | "#, |
3372 | r#" | ||
3264 | fn foo() -> i32 { | 3373 | fn foo() -> i32 { |
3265 | loop { | 3374 | loop { |
3266 | let n = 1; | 3375 | let n = 1; |
@@ -3278,7 +3387,8 @@ fn $0fun_name() -> Option<i32> { | |||
3278 | } | 3387 | } |
3279 | let m = k + 1; | 3388 | let m = k + 1; |
3280 | None | 3389 | None |
3281 | }"##, | 3390 | } |
3391 | "#, | ||
3282 | ); | 3392 | ); |
3283 | } | 3393 | } |
3284 | 3394 | ||
@@ -3286,7 +3396,7 @@ fn $0fun_name() -> Option<i32> { | |||
3286 | fn break_with_value_and_return() { | 3396 | fn break_with_value_and_return() { |
3287 | check_assist( | 3397 | check_assist( |
3288 | extract_function, | 3398 | extract_function, |
3289 | r##" | 3399 | r#" |
3290 | fn foo() -> i64 { | 3400 | fn foo() -> i64 { |
3291 | loop { | 3401 | loop { |
3292 | let n = 1; | 3402 | let n = 1; |
@@ -3298,8 +3408,9 @@ fn foo() -> i64 { | |||
3298 | let m = k + 1;$0 | 3408 | let m = k + 1;$0 |
3299 | let h = 1 + m; | 3409 | let h = 1 + m; |
3300 | } | 3410 | } |
3301 | }"##, | 3411 | } |
3302 | r##" | 3412 | "#, |
3413 | r#" | ||
3303 | fn foo() -> i64 { | 3414 | fn foo() -> i64 { |
3304 | loop { | 3415 | loop { |
3305 | let n = 1; | 3416 | let n = 1; |
@@ -3318,7 +3429,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3318 | } | 3429 | } |
3319 | let m = k + 1; | 3430 | let m = k + 1; |
3320 | Ok(m) | 3431 | Ok(m) |
3321 | }"##, | 3432 | } |
3433 | "#, | ||
3322 | ); | 3434 | ); |
3323 | } | 3435 | } |
3324 | 3436 | ||
@@ -3326,9 +3438,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3326 | fn try_option() { | 3438 | fn try_option() { |
3327 | check_assist( | 3439 | check_assist( |
3328 | extract_function, | 3440 | extract_function, |
3329 | r##" | 3441 | r#" |
3330 | enum Option<T> { None, Some(T), } | 3442 | //- minicore: option |
3331 | use Option::*; | ||
3332 | fn bar() -> Option<i32> { None } | 3443 | fn bar() -> Option<i32> { None } |
3333 | fn foo() -> Option<()> { | 3444 | fn foo() -> Option<()> { |
3334 | let n = bar()?; | 3445 | let n = bar()?; |
@@ -3336,10 +3447,9 @@ fn foo() -> Option<()> { | |||
3336 | let m = k + 1;$0 | 3447 | let m = k + 1;$0 |
3337 | let h = 1 + m; | 3448 | let h = 1 + m; |
3338 | Some(()) | 3449 | Some(()) |
3339 | }"##, | 3450 | } |
3340 | r##" | 3451 | "#, |
3341 | enum Option<T> { None, Some(T), } | 3452 | r#" |
3342 | use Option::*; | ||
3343 | fn bar() -> Option<i32> { None } | 3453 | fn bar() -> Option<i32> { None } |
3344 | fn foo() -> Option<()> { | 3454 | fn foo() -> Option<()> { |
3345 | let n = bar()?; | 3455 | let n = bar()?; |
@@ -3352,7 +3462,8 @@ fn $0fun_name() -> Option<i32> { | |||
3352 | let k = foo()?; | 3462 | let k = foo()?; |
3353 | let m = k + 1; | 3463 | let m = k + 1; |
3354 | Some(m) | 3464 | Some(m) |
3355 | }"##, | 3465 | } |
3466 | "#, | ||
3356 | ); | 3467 | ); |
3357 | } | 3468 | } |
3358 | 3469 | ||
@@ -3360,19 +3471,17 @@ fn $0fun_name() -> Option<i32> { | |||
3360 | fn try_option_unit() { | 3471 | fn try_option_unit() { |
3361 | check_assist( | 3472 | check_assist( |
3362 | extract_function, | 3473 | extract_function, |
3363 | r##" | 3474 | r#" |
3364 | enum Option<T> { None, Some(T), } | 3475 | //- minicore: option |
3365 | use Option::*; | ||
3366 | fn foo() -> Option<()> { | 3476 | fn foo() -> Option<()> { |
3367 | let n = 1; | 3477 | let n = 1; |
3368 | $0let k = foo()?; | 3478 | $0let k = foo()?; |
3369 | let m = k + 1;$0 | 3479 | let m = k + 1;$0 |
3370 | let h = 1 + n; | 3480 | let h = 1 + n; |
3371 | Some(()) | 3481 | Some(()) |
3372 | }"##, | 3482 | } |
3373 | r##" | 3483 | "#, |
3374 | enum Option<T> { None, Some(T), } | 3484 | r#" |
3375 | use Option::*; | ||
3376 | fn foo() -> Option<()> { | 3485 | fn foo() -> Option<()> { |
3377 | let n = 1; | 3486 | let n = 1; |
3378 | fun_name()?; | 3487 | fun_name()?; |
@@ -3384,7 +3493,8 @@ fn $0fun_name() -> Option<()> { | |||
3384 | let k = foo()?; | 3493 | let k = foo()?; |
3385 | let m = k + 1; | 3494 | let m = k + 1; |
3386 | Some(()) | 3495 | Some(()) |
3387 | }"##, | 3496 | } |
3497 | "#, | ||
3388 | ); | 3498 | ); |
3389 | } | 3499 | } |
3390 | 3500 | ||
@@ -3392,19 +3502,17 @@ fn $0fun_name() -> Option<()> { | |||
3392 | fn try_result() { | 3502 | fn try_result() { |
3393 | check_assist( | 3503 | check_assist( |
3394 | extract_function, | 3504 | extract_function, |
3395 | r##" | 3505 | r#" |
3396 | enum Result<T, E> { Ok(T), Err(E), } | 3506 | //- minicore: result |
3397 | use Result::*; | ||
3398 | fn foo() -> Result<(), i64> { | 3507 | fn foo() -> Result<(), i64> { |
3399 | let n = 1; | 3508 | let n = 1; |
3400 | $0let k = foo()?; | 3509 | $0let k = foo()?; |
3401 | let m = k + 1;$0 | 3510 | let m = k + 1;$0 |
3402 | let h = 1 + m; | 3511 | let h = 1 + m; |
3403 | Ok(()) | 3512 | Ok(()) |
3404 | }"##, | 3513 | } |
3405 | r##" | 3514 | "#, |
3406 | enum Result<T, E> { Ok(T), Err(E), } | 3515 | r#" |
3407 | use Result::*; | ||
3408 | fn foo() -> Result<(), i64> { | 3516 | fn foo() -> Result<(), i64> { |
3409 | let n = 1; | 3517 | let n = 1; |
3410 | let m = fun_name()?; | 3518 | let m = fun_name()?; |
@@ -3416,7 +3524,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3416 | let k = foo()?; | 3524 | let k = foo()?; |
3417 | let m = k + 1; | 3525 | let m = k + 1; |
3418 | Ok(m) | 3526 | Ok(m) |
3419 | }"##, | 3527 | } |
3528 | "#, | ||
3420 | ); | 3529 | ); |
3421 | } | 3530 | } |
3422 | 3531 | ||
@@ -3424,9 +3533,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3424 | fn try_option_with_return() { | 3533 | fn try_option_with_return() { |
3425 | check_assist( | 3534 | check_assist( |
3426 | extract_function, | 3535 | extract_function, |
3427 | r##" | 3536 | r#" |
3428 | enum Option<T> { None, Some(T) } | 3537 | //- minicore: option |
3429 | use Option::*; | ||
3430 | fn foo() -> Option<()> { | 3538 | fn foo() -> Option<()> { |
3431 | let n = 1; | 3539 | let n = 1; |
3432 | $0let k = foo()?; | 3540 | $0let k = foo()?; |
@@ -3436,10 +3544,9 @@ fn foo() -> Option<()> { | |||
3436 | let m = k + 1;$0 | 3544 | let m = k + 1;$0 |
3437 | let h = 1 + m; | 3545 | let h = 1 + m; |
3438 | Some(()) | 3546 | Some(()) |
3439 | }"##, | 3547 | } |
3440 | r##" | 3548 | "#, |
3441 | enum Option<T> { None, Some(T) } | 3549 | r#" |
3442 | use Option::*; | ||
3443 | fn foo() -> Option<()> { | 3550 | fn foo() -> Option<()> { |
3444 | let n = 1; | 3551 | let n = 1; |
3445 | let m = fun_name()?; | 3552 | let m = fun_name()?; |
@@ -3454,7 +3561,8 @@ fn $0fun_name() -> Option<i32> { | |||
3454 | } | 3561 | } |
3455 | let m = k + 1; | 3562 | let m = k + 1; |
3456 | Some(m) | 3563 | Some(m) |
3457 | }"##, | 3564 | } |
3565 | "#, | ||
3458 | ); | 3566 | ); |
3459 | } | 3567 | } |
3460 | 3568 | ||
@@ -3462,9 +3570,8 @@ fn $0fun_name() -> Option<i32> { | |||
3462 | fn try_result_with_return() { | 3570 | fn try_result_with_return() { |
3463 | check_assist( | 3571 | check_assist( |
3464 | extract_function, | 3572 | extract_function, |
3465 | r##" | 3573 | r#" |
3466 | enum Result<T, E> { Ok(T), Err(E), } | 3574 | //- minicore: result |
3467 | use Result::*; | ||
3468 | fn foo() -> Result<(), i64> { | 3575 | fn foo() -> Result<(), i64> { |
3469 | let n = 1; | 3576 | let n = 1; |
3470 | $0let k = foo()?; | 3577 | $0let k = foo()?; |
@@ -3474,10 +3581,9 @@ fn foo() -> Result<(), i64> { | |||
3474 | let m = k + 1;$0 | 3581 | let m = k + 1;$0 |
3475 | let h = 1 + m; | 3582 | let h = 1 + m; |
3476 | Ok(()) | 3583 | Ok(()) |
3477 | }"##, | 3584 | } |
3478 | r##" | 3585 | "#, |
3479 | enum Result<T, E> { Ok(T), Err(E), } | 3586 | r#" |
3480 | use Result::*; | ||
3481 | fn foo() -> Result<(), i64> { | 3587 | fn foo() -> Result<(), i64> { |
3482 | let n = 1; | 3588 | let n = 1; |
3483 | let m = fun_name()?; | 3589 | let m = fun_name()?; |
@@ -3492,7 +3598,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3492 | } | 3598 | } |
3493 | let m = k + 1; | 3599 | let m = k + 1; |
3494 | Ok(m) | 3600 | Ok(m) |
3495 | }"##, | 3601 | } |
3602 | "#, | ||
3496 | ); | 3603 | ); |
3497 | } | 3604 | } |
3498 | 3605 | ||
@@ -3501,9 +3608,8 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3501 | cov_mark::check!(external_control_flow_try_and_bc); | 3608 | cov_mark::check!(external_control_flow_try_and_bc); |
3502 | check_assist_not_applicable( | 3609 | check_assist_not_applicable( |
3503 | extract_function, | 3610 | extract_function, |
3504 | r##" | 3611 | r#" |
3505 | enum Option<T> { None, Some(T) } | 3612 | //- minicore: option |
3506 | use Option::*; | ||
3507 | fn foo() -> Option<()> { | 3613 | fn foo() -> Option<()> { |
3508 | loop { | 3614 | loop { |
3509 | let n = Some(1); | 3615 | let n = Some(1); |
@@ -3514,7 +3620,8 @@ fn foo() -> Option<()> { | |||
3514 | let r = n + k; | 3620 | let r = n + k; |
3515 | } | 3621 | } |
3516 | Some(()) | 3622 | Some(()) |
3517 | }"##, | 3623 | } |
3624 | "#, | ||
3518 | ); | 3625 | ); |
3519 | } | 3626 | } |
3520 | 3627 | ||
@@ -3523,9 +3630,8 @@ fn foo() -> Option<()> { | |||
3523 | cov_mark::check!(external_control_flow_try_and_return_non_err); | 3630 | cov_mark::check!(external_control_flow_try_and_return_non_err); |
3524 | check_assist_not_applicable( | 3631 | check_assist_not_applicable( |
3525 | extract_function, | 3632 | extract_function, |
3526 | r##" | 3633 | r#" |
3527 | enum Result<T, E> { Ok(T), Err(E), } | 3634 | //- minicore: result |
3528 | use Result::*; | ||
3529 | fn foo() -> Result<(), i64> { | 3635 | fn foo() -> Result<(), i64> { |
3530 | let n = 1; | 3636 | let n = 1; |
3531 | $0let k = foo()?; | 3637 | $0let k = foo()?; |
@@ -3535,7 +3641,8 @@ fn foo() -> Result<(), i64> { | |||
3535 | let m = k + 1;$0 | 3641 | let m = k + 1;$0 |
3536 | let h = 1 + m; | 3642 | let h = 1 + m; |
3537 | Ok(()) | 3643 | Ok(()) |
3538 | }"##, | 3644 | } |
3645 | "#, | ||
3539 | ); | 3646 | ); |
3540 | } | 3647 | } |
3541 | 3648 | ||
@@ -3543,7 +3650,7 @@ fn foo() -> Result<(), i64> { | |||
3543 | fn param_usage_in_macro() { | 3650 | fn param_usage_in_macro() { |
3544 | check_assist( | 3651 | check_assist( |
3545 | extract_function, | 3652 | extract_function, |
3546 | r" | 3653 | r#" |
3547 | macro_rules! m { | 3654 | macro_rules! m { |
3548 | ($val:expr) => { $val }; | 3655 | ($val:expr) => { $val }; |
3549 | } | 3656 | } |
@@ -3552,8 +3659,9 @@ fn foo() { | |||
3552 | let n = 1; | 3659 | let n = 1; |
3553 | $0let k = n * m!(n);$0 | 3660 | $0let k = n * m!(n);$0 |
3554 | let m = k + 1; | 3661 | let m = k + 1; |
3555 | }", | 3662 | } |
3556 | r" | 3663 | "#, |
3664 | r#" | ||
3557 | macro_rules! m { | 3665 | macro_rules! m { |
3558 | ($val:expr) => { $val }; | 3666 | ($val:expr) => { $val }; |
3559 | } | 3667 | } |
@@ -3567,7 +3675,8 @@ fn foo() { | |||
3567 | fn $0fun_name(n: i32) -> i32 { | 3675 | fn $0fun_name(n: i32) -> i32 { |
3568 | let k = n * m!(n); | 3676 | let k = n * m!(n); |
3569 | k | 3677 | k |
3570 | }", | 3678 | } |
3679 | "#, | ||
3571 | ); | 3680 | ); |
3572 | } | 3681 | } |
3573 | 3682 | ||
@@ -3575,7 +3684,8 @@ fn $0fun_name(n: i32) -> i32 { | |||
3575 | fn extract_with_await() { | 3684 | fn extract_with_await() { |
3576 | check_assist( | 3685 | check_assist( |
3577 | extract_function, | 3686 | extract_function, |
3578 | r#"fn main() { | 3687 | r#" |
3688 | fn main() { | ||
3579 | $0some_function().await;$0 | 3689 | $0some_function().await;$0 |
3580 | } | 3690 | } |
3581 | 3691 | ||
@@ -3585,7 +3695,7 @@ async fn some_function() { | |||
3585 | "#, | 3695 | "#, |
3586 | r#" | 3696 | r#" |
3587 | fn main() { | 3697 | fn main() { |
3588 | fun_name(); | 3698 | fun_name().await; |
3589 | } | 3699 | } |
3590 | 3700 | ||
3591 | async fn $0fun_name() { | 3701 | async fn $0fun_name() { |
@@ -3603,7 +3713,8 @@ async fn some_function() { | |||
3603 | fn extract_with_await_in_args() { | 3713 | fn extract_with_await_in_args() { |
3604 | check_assist( | 3714 | check_assist( |
3605 | extract_function, | 3715 | extract_function, |
3606 | r#"fn main() { | 3716 | r#" |
3717 | fn main() { | ||
3607 | $0function_call("a", some_function().await);$0 | 3718 | $0function_call("a", some_function().await);$0 |
3608 | } | 3719 | } |
3609 | 3720 | ||
@@ -3613,7 +3724,7 @@ async fn some_function() { | |||
3613 | "#, | 3724 | "#, |
3614 | r#" | 3725 | r#" |
3615 | fn main() { | 3726 | fn main() { |
3616 | fun_name(); | 3727 | fun_name().await; |
3617 | } | 3728 | } |
3618 | 3729 | ||
3619 | async fn $0fun_name() { | 3730 | async fn $0fun_name() { |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index d3ff7b65c..430710448 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -48,6 +48,7 @@ pub(crate) fn extract_struct_from_enum_variant( | |||
48 | let variant_name = variant.name()?; | 48 | let variant_name = variant.name()?; |
49 | let variant_hir = ctx.sema.to_def(&variant)?; | 49 | let variant_hir = ctx.sema.to_def(&variant)?; |
50 | if existing_definition(ctx.db(), &variant_name, &variant_hir) { | 50 | if existing_definition(ctx.db(), &variant_name, &variant_hir) { |
51 | cov_mark::hit!(test_extract_enum_not_applicable_if_struct_exists); | ||
51 | return None; | 52 | return None; |
52 | } | 53 | } |
53 | 54 | ||
@@ -235,7 +236,7 @@ fn apply_references( | |||
235 | import: Option<(ImportScope, hir::ModPath)>, | 236 | import: Option<(ImportScope, hir::ModPath)>, |
236 | ) { | 237 | ) { |
237 | if let Some((scope, path)) = import { | 238 | if let Some((scope, path)) = import { |
238 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); | 239 | insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg); |
239 | } | 240 | } |
240 | // deep clone to prevent cycle | 241 | // deep clone to prevent cycle |
241 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); | 242 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); |
@@ -300,18 +301,10 @@ fn reference_to_node( | |||
300 | 301 | ||
301 | #[cfg(test)] | 302 | #[cfg(test)] |
302 | mod tests { | 303 | mod tests { |
303 | use ide_db::helpers::FamousDefs; | ||
304 | |||
305 | use crate::tests::{check_assist, check_assist_not_applicable}; | 304 | use crate::tests::{check_assist, check_assist_not_applicable}; |
306 | 305 | ||
307 | use super::*; | 306 | use super::*; |
308 | 307 | ||
309 | fn check_not_applicable(ra_fixture: &str) { | ||
310 | let fixture = | ||
311 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
312 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | ||
313 | } | ||
314 | |||
315 | #[test] | 308 | #[test] |
316 | fn test_extract_struct_several_fields_tuple() { | 309 | fn test_extract_struct_several_fields_tuple() { |
317 | check_assist( | 310 | check_assist( |
@@ -699,29 +692,33 @@ fn foo() { | |||
699 | 692 | ||
700 | #[test] | 693 | #[test] |
701 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { | 694 | fn test_extract_enum_not_applicable_for_element_with_no_fields() { |
702 | check_not_applicable("enum A { $0One }"); | 695 | check_assist_not_applicable(extract_struct_from_enum_variant, r#"enum A { $0One }"#); |
703 | } | 696 | } |
704 | 697 | ||
705 | #[test] | 698 | #[test] |
706 | fn test_extract_enum_not_applicable_if_struct_exists() { | 699 | fn test_extract_enum_not_applicable_if_struct_exists() { |
707 | check_not_applicable( | 700 | cov_mark::check!(test_extract_enum_not_applicable_if_struct_exists); |
708 | r#"struct One; | 701 | check_assist_not_applicable( |
709 | enum A { $0One(u8, u32) }"#, | 702 | extract_struct_from_enum_variant, |
703 | r#" | ||
704 | struct One; | ||
705 | enum A { $0One(u8, u32) } | ||
706 | "#, | ||
710 | ); | 707 | ); |
711 | } | 708 | } |
712 | 709 | ||
713 | #[test] | 710 | #[test] |
714 | fn test_extract_not_applicable_one_field() { | 711 | fn test_extract_not_applicable_one_field() { |
715 | check_not_applicable(r"enum A { $0One(u32) }"); | 712 | check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0One(u32) }"); |
716 | } | 713 | } |
717 | 714 | ||
718 | #[test] | 715 | #[test] |
719 | fn test_extract_not_applicable_no_field_tuple() { | 716 | fn test_extract_not_applicable_no_field_tuple() { |
720 | check_not_applicable(r"enum A { $0None() }"); | 717 | check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None() }"); |
721 | } | 718 | } |
722 | 719 | ||
723 | #[test] | 720 | #[test] |
724 | fn test_extract_not_applicable_no_field_named() { | 721 | fn test_extract_not_applicable_no_field_named() { |
725 | check_not_applicable(r"enum A { $0None {} }"); | 722 | check_assist_not_applicable(extract_struct_from_enum_variant, r"enum A { $0None {} }"); |
726 | } | 723 | } |
727 | } | 724 | } |
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 5a43bdd6f..318faa0fc 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -278,8 +278,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Op | |||
278 | 278 | ||
279 | #[cfg(test)] | 279 | #[cfg(test)] |
280 | mod tests { | 280 | mod tests { |
281 | use ide_db::helpers::FamousDefs; | ||
282 | |||
283 | use crate::tests::{ | 281 | use crate::tests::{ |
284 | check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved, | 282 | check_assist, check_assist_not_applicable, check_assist_target, check_assist_unresolved, |
285 | }; | 283 | }; |
@@ -483,26 +481,21 @@ fn main() { | |||
483 | check_assist( | 481 | check_assist( |
484 | fill_match_arms, | 482 | fill_match_arms, |
485 | r#" | 483 | r#" |
486 | enum Option<T> { Some(T), None } | 484 | //- minicore: option |
487 | use Option::*; | ||
488 | |||
489 | fn main() { | 485 | fn main() { |
490 | match None$0 { | 486 | match None$0 { |
491 | None => {} | 487 | None => {} |
492 | } | 488 | } |
493 | } | 489 | } |
494 | "#, | 490 | "#, |
495 | r#" | 491 | r#" |
496 | enum Option<T> { Some(T), None } | ||
497 | use Option::*; | ||
498 | |||
499 | fn main() { | 492 | fn main() { |
500 | match None { | 493 | match None { |
501 | None => {} | 494 | None => {} |
502 | Some(${0:_}) => todo!(), | 495 | Some(${0:_}) => todo!(), |
503 | } | 496 | } |
504 | } | 497 | } |
505 | "#, | 498 | "#, |
506 | ); | 499 | ); |
507 | } | 500 | } |
508 | 501 | ||
@@ -716,7 +709,10 @@ fn main() { | |||
716 | 709 | ||
717 | #[test] | 710 | #[test] |
718 | fn fill_match_arms_tuple_of_enum_partial_with_wildcards() { | 711 | fn fill_match_arms_tuple_of_enum_partial_with_wildcards() { |
719 | let ra_fixture = r#" | 712 | check_assist( |
713 | fill_match_arms, | ||
714 | r#" | ||
715 | //- minicore: option | ||
720 | fn main() { | 716 | fn main() { |
721 | let a = Some(1); | 717 | let a = Some(1); |
722 | let b = Some(()); | 718 | let b = Some(()); |
@@ -725,10 +721,7 @@ fn main() { | |||
725 | (None, Some(_)) => {} | 721 | (None, Some(_)) => {} |
726 | } | 722 | } |
727 | } | 723 | } |
728 | "#; | 724 | "#, |
729 | check_assist( | ||
730 | fill_match_arms, | ||
731 | &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE), | ||
732 | r#" | 725 | r#" |
733 | fn main() { | 726 | fn main() { |
734 | let a = Some(1); | 727 | let a = Some(1); |
@@ -746,17 +739,17 @@ fn main() { | |||
746 | #[test] | 739 | #[test] |
747 | fn fill_match_arms_partial_with_deep_pattern() { | 740 | fn fill_match_arms_partial_with_deep_pattern() { |
748 | // Fixme: cannot handle deep patterns | 741 | // Fixme: cannot handle deep patterns |
749 | let ra_fixture = r#" | 742 | check_assist_not_applicable( |
743 | fill_match_arms, | ||
744 | r#" | ||
745 | //- minicore: option | ||
750 | fn main() { | 746 | fn main() { |
751 | match $0Some(true) { | 747 | match $0Some(true) { |
752 | Some(true) => {} | 748 | Some(true) => {} |
753 | None => {} | 749 | None => {} |
754 | } | 750 | } |
755 | } | 751 | } |
756 | "#; | 752 | "#, |
757 | check_assist_not_applicable( | ||
758 | fill_match_arms, | ||
759 | &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE), | ||
760 | ); | 753 | ); |
761 | } | 754 | } |
762 | 755 | ||
@@ -1007,17 +1000,15 @@ fn foo(a: A) { | |||
1007 | #[test] | 1000 | #[test] |
1008 | fn option_order() { | 1001 | fn option_order() { |
1009 | cov_mark::check!(option_order); | 1002 | cov_mark::check!(option_order); |
1010 | let before = r#" | 1003 | check_assist( |
1004 | fill_match_arms, | ||
1005 | r#" | ||
1006 | //- minicore: option | ||
1011 | fn foo(opt: Option<i32>) { | 1007 | fn foo(opt: Option<i32>) { |
1012 | match opt$0 { | 1008 | match opt$0 { |
1013 | } | 1009 | } |
1014 | } | 1010 | } |
1015 | "#; | 1011 | "#, |
1016 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
1017 | |||
1018 | check_assist( | ||
1019 | fill_match_arms, | ||
1020 | before, | ||
1021 | r#" | 1012 | r#" |
1022 | fn foo(opt: Option<i32>) { | 1013 | fn foo(opt: Option<i32>) { |
1023 | match opt { | 1014 | match opt { |
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs index 9b432e92f..f834bf16a 100644 --- a/crates/ide_assists/src/handlers/fix_visibility.rs +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -361,8 +361,6 @@ pub struct Foo { pub bar: () } | |||
361 | } | 361 | } |
362 | 362 | ||
363 | #[test] | 363 | #[test] |
364 | #[ignore] | ||
365 | // FIXME reenable this test when `Semantics::resolve_record_field` works with union fields | ||
366 | fn fix_visibility_of_union_field() { | 364 | fn fix_visibility_of_union_field() { |
367 | check_assist( | 365 | check_assist( |
368 | fix_visibility, | 366 | fix_visibility, |
@@ -583,25 +581,25 @@ pub struct Foo { pub(crate) bar: () } | |||
583 | } | 581 | } |
584 | 582 | ||
585 | #[test] | 583 | #[test] |
586 | #[ignore] | ||
587 | // FIXME handle reexports properly | ||
588 | fn fix_visibility_of_reexport() { | 584 | fn fix_visibility_of_reexport() { |
585 | // FIXME: broken test, this should fix visibility of the re-export | ||
586 | // rather than the struct. | ||
589 | check_assist( | 587 | check_assist( |
590 | fix_visibility, | 588 | fix_visibility, |
591 | r" | 589 | r#" |
592 | mod foo { | 590 | mod foo { |
593 | use bar::Baz; | 591 | use bar::Baz; |
594 | mod bar { pub(super) struct Baz; } | 592 | mod bar { pub(super) struct Baz; } |
595 | } | 593 | } |
596 | foo::Baz$0 | 594 | foo::Baz$0 |
597 | ", | 595 | "#, |
598 | r" | 596 | r#" |
599 | mod foo { | 597 | mod foo { |
600 | $0pub(crate) use bar::Baz; | 598 | use bar::Baz; |
601 | mod bar { pub(super) struct Baz; } | 599 | mod bar { $0pub(crate) struct Baz; } |
602 | } | 600 | } |
603 | foo::Baz | 601 | foo::Baz |
604 | ", | 602 | "#, |
605 | ) | 603 | ) |
606 | } | 604 | } |
607 | } | 605 | } |
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs index 588ee1350..e55c38502 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use ide_db::helpers::FamousDefs; | 1 | use ide_db::{helpers::FamousDefs, RootDatabase}; |
2 | use ide_db::RootDatabase; | ||
3 | use syntax::ast::{self, AstNode, NameOwner}; | 2 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | 3 | ||
5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 4 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -92,23 +91,20 @@ mod tests { | |||
92 | 91 | ||
93 | use super::*; | 92 | use super::*; |
94 | 93 | ||
95 | fn check_not_applicable(ra_fixture: &str) { | ||
96 | let fixture = | ||
97 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
98 | check_assist_not_applicable(generate_default_from_enum_variant, &fixture) | ||
99 | } | ||
100 | |||
101 | #[test] | 94 | #[test] |
102 | fn test_generate_default_from_variant() { | 95 | fn test_generate_default_from_variant() { |
103 | check_assist( | 96 | check_assist( |
104 | generate_default_from_enum_variant, | 97 | generate_default_from_enum_variant, |
105 | r#" | 98 | r#" |
99 | //- minicore: default | ||
106 | enum Variant { | 100 | enum Variant { |
107 | Undefined, | 101 | Undefined, |
108 | Minor$0, | 102 | Minor$0, |
109 | Major, | 103 | Major, |
110 | }"#, | 104 | } |
111 | r#"enum Variant { | 105 | "#, |
106 | r#" | ||
107 | enum Variant { | ||
112 | Undefined, | 108 | Undefined, |
113 | Minor, | 109 | Minor, |
114 | Major, | 110 | Major, |
@@ -118,15 +114,18 @@ impl Default for Variant { | |||
118 | fn default() -> Self { | 114 | fn default() -> Self { |
119 | Self::Minor | 115 | Self::Minor |
120 | } | 116 | } |
121 | }"#, | 117 | } |
118 | "#, | ||
122 | ); | 119 | ); |
123 | } | 120 | } |
124 | 121 | ||
125 | #[test] | 122 | #[test] |
126 | fn test_generate_default_already_implemented() { | 123 | fn test_generate_default_already_implemented() { |
127 | cov_mark::check!(test_gen_default_impl_already_exists); | 124 | cov_mark::check!(test_gen_default_impl_already_exists); |
128 | check_not_applicable( | 125 | check_assist_not_applicable( |
126 | generate_default_from_enum_variant, | ||
129 | r#" | 127 | r#" |
128 | //- minicore: default | ||
130 | enum Variant { | 129 | enum Variant { |
131 | Undefined, | 130 | Undefined, |
132 | Minor$0, | 131 | Minor$0, |
@@ -137,20 +136,24 @@ impl Default for Variant { | |||
137 | fn default() -> Self { | 136 | fn default() -> Self { |
138 | Self::Minor | 137 | Self::Minor |
139 | } | 138 | } |
140 | }"#, | 139 | } |
140 | "#, | ||
141 | ); | 141 | ); |
142 | } | 142 | } |
143 | 143 | ||
144 | #[test] | 144 | #[test] |
145 | fn test_add_from_impl_no_element() { | 145 | fn test_add_from_impl_no_element() { |
146 | cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented); | 146 | cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented); |
147 | check_not_applicable( | 147 | check_assist_not_applicable( |
148 | generate_default_from_enum_variant, | ||
148 | r#" | 149 | r#" |
150 | //- minicore: default | ||
149 | enum Variant { | 151 | enum Variant { |
150 | Undefined, | 152 | Undefined, |
151 | Minor(u32)$0, | 153 | Minor(u32)$0, |
152 | Major, | 154 | Major, |
153 | }"#, | 155 | } |
156 | "#, | ||
154 | ); | 157 | ); |
155 | } | 158 | } |
156 | 159 | ||
@@ -158,7 +161,10 @@ enum Variant { | |||
158 | fn test_generate_default_from_variant_with_one_variant() { | 161 | fn test_generate_default_from_variant_with_one_variant() { |
159 | check_assist( | 162 | check_assist( |
160 | generate_default_from_enum_variant, | 163 | generate_default_from_enum_variant, |
161 | r#"enum Variant { Undefi$0ned }"#, | 164 | r#" |
165 | //- minicore: default | ||
166 | enum Variant { Undefi$0ned } | ||
167 | "#, | ||
162 | r#" | 168 | r#" |
163 | enum Variant { Undefined } | 169 | enum Variant { Undefined } |
164 | 170 | ||
@@ -166,7 +172,8 @@ impl Default for Variant { | |||
166 | fn default() -> Self { | 172 | fn default() -> Self { |
167 | Self::Undefined | 173 | Self::Undefined |
168 | } | 174 | } |
169 | }"#, | 175 | } |
176 | "#, | ||
170 | ); | 177 | ); |
171 | } | 178 | } |
172 | } | 179 | } |
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index bad826366..b54ec59da 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs | |||
@@ -1,7 +1,3 @@ | |||
1 | use crate::{ | ||
2 | assist_context::{AssistContext, Assists}, | ||
3 | AssistId, | ||
4 | }; | ||
5 | use ide_db::helpers::FamousDefs; | 1 | use ide_db::helpers::FamousDefs; |
6 | use itertools::Itertools; | 2 | use itertools::Itertools; |
7 | use stdx::format_to; | 3 | use stdx::format_to; |
@@ -10,6 +6,11 @@ use syntax::{ | |||
10 | AstNode, | 6 | AstNode, |
11 | }; | 7 | }; |
12 | 8 | ||
9 | use crate::{ | ||
10 | assist_context::{AssistContext, Assists}, | ||
11 | AssistId, | ||
12 | }; | ||
13 | |||
13 | // Assist: generate_default_from_new | 14 | // Assist: generate_default_from_new |
14 | // | 15 | // |
15 | // Generates default implementation from new method. | 16 | // Generates default implementation from new method. |
@@ -140,16 +141,16 @@ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { | |||
140 | 141 | ||
141 | #[cfg(test)] | 142 | #[cfg(test)] |
142 | mod tests { | 143 | mod tests { |
143 | use ide_db::helpers::FamousDefs; | ||
144 | |||
145 | use crate::tests::{check_assist, check_assist_not_applicable}; | 144 | use crate::tests::{check_assist, check_assist_not_applicable}; |
146 | 145 | ||
147 | use super::*; | 146 | use super::*; |
148 | 147 | ||
149 | #[test] | 148 | #[test] |
150 | fn generate_default() { | 149 | fn generate_default() { |
151 | check_pass( | 150 | check_assist( |
151 | generate_default_from_new, | ||
152 | r#" | 152 | r#" |
153 | //- minicore: default | ||
153 | struct Example { _inner: () } | 154 | struct Example { _inner: () } |
154 | 155 | ||
155 | impl Example { | 156 | impl Example { |
@@ -182,8 +183,10 @@ fn main() {} | |||
182 | 183 | ||
183 | #[test] | 184 | #[test] |
184 | fn generate_default2() { | 185 | fn generate_default2() { |
185 | check_pass( | 186 | check_assist( |
187 | generate_default_from_new, | ||
186 | r#" | 188 | r#" |
189 | //- minicore: default | ||
187 | struct Test { value: u32 } | 190 | struct Test { value: u32 } |
188 | 191 | ||
189 | impl Test { | 192 | impl Test { |
@@ -212,8 +215,10 @@ impl Default for Test { | |||
212 | 215 | ||
213 | #[test] | 216 | #[test] |
214 | fn new_function_with_generic() { | 217 | fn new_function_with_generic() { |
215 | check_pass( | 218 | check_assist( |
219 | generate_default_from_new, | ||
216 | r#" | 220 | r#" |
221 | //- minicore: default | ||
217 | pub struct Foo<T> { | 222 | pub struct Foo<T> { |
218 | _bar: *mut T, | 223 | _bar: *mut T, |
219 | } | 224 | } |
@@ -246,8 +251,10 @@ impl<T> Default for Foo<T> { | |||
246 | 251 | ||
247 | #[test] | 252 | #[test] |
248 | fn new_function_with_generics() { | 253 | fn new_function_with_generics() { |
249 | check_pass( | 254 | check_assist( |
255 | generate_default_from_new, | ||
250 | r#" | 256 | r#" |
257 | //- minicore: default | ||
251 | pub struct Foo<T, B> { | 258 | pub struct Foo<T, B> { |
252 | _tars: *mut T, | 259 | _tars: *mut T, |
253 | _bar: *mut B, | 260 | _bar: *mut B, |
@@ -282,8 +289,10 @@ impl<T, B> Default for Foo<T, B> { | |||
282 | 289 | ||
283 | #[test] | 290 | #[test] |
284 | fn new_function_with_generic_and_bound() { | 291 | fn new_function_with_generic_and_bound() { |
285 | check_pass( | 292 | check_assist( |
293 | generate_default_from_new, | ||
286 | r#" | 294 | r#" |
295 | //- minicore: default | ||
287 | pub struct Foo<T> { | 296 | pub struct Foo<T> { |
288 | t: T, | 297 | t: T, |
289 | } | 298 | } |
@@ -316,8 +325,10 @@ impl<T: From<i32>> Default for Foo<T> { | |||
316 | 325 | ||
317 | #[test] | 326 | #[test] |
318 | fn new_function_with_generics_and_bounds() { | 327 | fn new_function_with_generics_and_bounds() { |
319 | check_pass( | 328 | check_assist( |
329 | generate_default_from_new, | ||
320 | r#" | 330 | r#" |
331 | //- minicore: default | ||
321 | pub struct Foo<T, B> { | 332 | pub struct Foo<T, B> { |
322 | _tars: T, | 333 | _tars: T, |
323 | _bar: B, | 334 | _bar: B, |
@@ -352,8 +363,10 @@ impl<T: From<i32>, B: From<i64>> Default for Foo<T, B> { | |||
352 | 363 | ||
353 | #[test] | 364 | #[test] |
354 | fn new_function_with_generic_and_where() { | 365 | fn new_function_with_generic_and_where() { |
355 | check_pass( | 366 | check_assist( |
367 | generate_default_from_new, | ||
356 | r#" | 368 | r#" |
369 | //- minicore: default | ||
357 | pub struct Foo<T> { | 370 | pub struct Foo<T> { |
358 | t: T, | 371 | t: T, |
359 | } | 372 | } |
@@ -395,8 +408,10 @@ where | |||
395 | 408 | ||
396 | #[test] | 409 | #[test] |
397 | fn new_function_with_generics_and_wheres() { | 410 | fn new_function_with_generics_and_wheres() { |
398 | check_pass( | 411 | check_assist( |
412 | generate_default_from_new, | ||
399 | r#" | 413 | r#" |
414 | //- minicore: default | ||
400 | pub struct Foo<T, B> { | 415 | pub struct Foo<T, B> { |
401 | _tars: T, | 416 | _tars: T, |
402 | _bar: B, | 417 | _bar: B, |
@@ -441,8 +456,10 @@ where | |||
441 | #[test] | 456 | #[test] |
442 | fn new_function_with_parameters() { | 457 | fn new_function_with_parameters() { |
443 | cov_mark::check!(new_function_with_parameters); | 458 | cov_mark::check!(new_function_with_parameters); |
444 | check_not_applicable( | 459 | check_assist_not_applicable( |
460 | generate_default_from_new, | ||
445 | r#" | 461 | r#" |
462 | //- minicore: default | ||
446 | struct Example { _inner: () } | 463 | struct Example { _inner: () } |
447 | 464 | ||
448 | impl Example { | 465 | impl Example { |
@@ -457,7 +474,8 @@ impl Example { | |||
457 | #[test] | 474 | #[test] |
458 | fn other_function_than_new() { | 475 | fn other_function_than_new() { |
459 | cov_mark::check!(other_function_than_new); | 476 | cov_mark::check!(other_function_than_new); |
460 | check_not_applicable( | 477 | check_assist_not_applicable( |
478 | generate_default_from_new, | ||
461 | r#" | 479 | r#" |
462 | struct Example { _inner: () } | 480 | struct Example { _inner: () } |
463 | 481 | ||
@@ -474,8 +492,10 @@ impl Example { | |||
474 | #[test] | 492 | #[test] |
475 | fn default_block_is_already_present() { | 493 | fn default_block_is_already_present() { |
476 | cov_mark::check!(default_block_is_already_present); | 494 | cov_mark::check!(default_block_is_already_present); |
477 | check_not_applicable( | 495 | check_assist_not_applicable( |
496 | generate_default_from_new, | ||
478 | r#" | 497 | r#" |
498 | //- minicore: default | ||
479 | struct Example { _inner: () } | 499 | struct Example { _inner: () } |
480 | 500 | ||
481 | impl Example { | 501 | impl Example { |
@@ -495,7 +515,8 @@ impl Default for Example { | |||
495 | 515 | ||
496 | #[test] | 516 | #[test] |
497 | fn standalone_new_function() { | 517 | fn standalone_new_function() { |
498 | check_not_applicable( | 518 | check_assist_not_applicable( |
519 | generate_default_from_new, | ||
499 | r#" | 520 | r#" |
500 | fn n$0ew() -> u32 { | 521 | fn n$0ew() -> u32 { |
501 | 0 | 522 | 0 |
@@ -506,8 +527,10 @@ fn n$0ew() -> u32 { | |||
506 | 527 | ||
507 | #[test] | 528 | #[test] |
508 | fn multiple_struct_blocks() { | 529 | fn multiple_struct_blocks() { |
509 | check_pass( | 530 | check_assist( |
531 | generate_default_from_new, | ||
510 | r#" | 532 | r#" |
533 | //- minicore: default | ||
511 | struct Example { _inner: () } | 534 | struct Example { _inner: () } |
512 | struct Test { value: u32 } | 535 | struct Test { value: u32 } |
513 | 536 | ||
@@ -538,8 +561,10 @@ impl Default for Example { | |||
538 | 561 | ||
539 | #[test] | 562 | #[test] |
540 | fn when_struct_is_after_impl() { | 563 | fn when_struct_is_after_impl() { |
541 | check_pass( | 564 | check_assist( |
565 | generate_default_from_new, | ||
542 | r#" | 566 | r#" |
567 | //- minicore: default | ||
543 | impl Example { | 568 | impl Example { |
544 | pub fn $0new() -> Self { | 569 | pub fn $0new() -> Self { |
545 | Self { _inner: () } | 570 | Self { _inner: () } |
@@ -568,8 +593,10 @@ struct Example { _inner: () } | |||
568 | 593 | ||
569 | #[test] | 594 | #[test] |
570 | fn struct_in_module() { | 595 | fn struct_in_module() { |
571 | check_pass( | 596 | check_assist( |
597 | generate_default_from_new, | ||
572 | r#" | 598 | r#" |
599 | //- minicore: default | ||
573 | mod test { | 600 | mod test { |
574 | struct Example { _inner: () } | 601 | struct Example { _inner: () } |
575 | 602 | ||
@@ -603,8 +630,10 @@ impl Default for Example { | |||
603 | #[test] | 630 | #[test] |
604 | fn struct_in_module_with_default() { | 631 | fn struct_in_module_with_default() { |
605 | cov_mark::check!(struct_in_module_with_default); | 632 | cov_mark::check!(struct_in_module_with_default); |
606 | check_not_applicable( | 633 | check_assist_not_applicable( |
634 | generate_default_from_new, | ||
607 | r#" | 635 | r#" |
636 | //- minicore: default | ||
608 | mod test { | 637 | mod test { |
609 | struct Example { _inner: () } | 638 | struct Example { _inner: () } |
610 | 639 | ||
@@ -623,14 +652,4 @@ mod test { | |||
623 | "#, | 652 | "#, |
624 | ); | 653 | ); |
625 | } | 654 | } |
626 | |||
627 | fn check_pass(before: &str, after: &str) { | ||
628 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
629 | check_assist(generate_default_from_new, before, after); | ||
630 | } | ||
631 | |||
632 | fn check_not_applicable(before: &str) { | ||
633 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
634 | check_assist_not_applicable(generate_default_from_new, before); | ||
635 | } | ||
636 | } | 655 | } |
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs index 4998ff7a4..4e10fdb85 100644 --- a/crates/ide_assists/src/handlers/generate_deref.rs +++ b/crates/ide_assists/src/handlers/generate_deref.rs | |||
@@ -182,23 +182,17 @@ impl std::ops::Deref for B { | |||
182 | ); | 182 | ); |
183 | } | 183 | } |
184 | 184 | ||
185 | fn check_not_applicable(ra_fixture: &str) { | ||
186 | let fixture = format!( | ||
187 | "//- /main.rs crate:main deps:core,std\n{}\n{}", | ||
188 | ra_fixture, | ||
189 | FamousDefs::FIXTURE | ||
190 | ); | ||
191 | check_assist_not_applicable(generate_deref, &fixture) | ||
192 | } | ||
193 | |||
194 | #[test] | 185 | #[test] |
195 | fn test_generate_record_deref_not_applicable_if_already_impl() { | 186 | fn test_generate_record_deref_not_applicable_if_already_impl() { |
196 | cov_mark::check!(test_add_record_deref_impl_already_exists); | 187 | cov_mark::check!(test_add_record_deref_impl_already_exists); |
197 | check_not_applicable( | 188 | check_assist_not_applicable( |
198 | r#"struct A { } | 189 | generate_deref, |
190 | r#" | ||
191 | //- minicore: deref | ||
192 | struct A { } | ||
199 | struct B { $0a: A } | 193 | struct B { $0a: A } |
200 | 194 | ||
201 | impl std::ops::Deref for B { | 195 | impl core::ops::Deref for B { |
202 | type Target = A; | 196 | type Target = A; |
203 | 197 | ||
204 | fn deref(&self) -> &Self::Target { | 198 | fn deref(&self) -> &Self::Target { |
@@ -211,11 +205,14 @@ impl std::ops::Deref for B { | |||
211 | #[test] | 205 | #[test] |
212 | fn test_generate_field_deref_not_applicable_if_already_impl() { | 206 | fn test_generate_field_deref_not_applicable_if_already_impl() { |
213 | cov_mark::check!(test_add_field_deref_impl_already_exists); | 207 | cov_mark::check!(test_add_field_deref_impl_already_exists); |
214 | check_not_applicable( | 208 | check_assist_not_applicable( |
215 | r#"struct A { } | 209 | generate_deref, |
210 | r#" | ||
211 | //- minicore: deref | ||
212 | struct A { } | ||
216 | struct B($0A) | 213 | struct B($0A) |
217 | 214 | ||
218 | impl std::ops::Deref for B { | 215 | impl core::ops::Deref for B { |
219 | type Target = A; | 216 | type Target = A; |
220 | 217 | ||
221 | fn deref(&self) -> &Self::Target { | 218 | fn deref(&self) -> &Self::Target { |
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs index ce6998d82..8727be07d 100644 --- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs | |||
@@ -110,14 +110,19 @@ mod tests { | |||
110 | fn test_generate_from_impl_for_enum() { | 110 | fn test_generate_from_impl_for_enum() { |
111 | check_assist( | 111 | check_assist( |
112 | generate_from_impl_for_enum, | 112 | generate_from_impl_for_enum, |
113 | "enum A { $0One(u32) }", | 113 | r#" |
114 | r#"enum A { One(u32) } | 114 | //- minicore: from |
115 | enum A { $0One(u32) } | ||
116 | "#, | ||
117 | r#" | ||
118 | enum A { One(u32) } | ||
115 | 119 | ||
116 | impl From<u32> for A { | 120 | impl From<u32> for A { |
117 | fn from(v: u32) -> Self { | 121 | fn from(v: u32) -> Self { |
118 | Self::One(v) | 122 | Self::One(v) |
119 | } | 123 | } |
120 | }"#, | 124 | } |
125 | "#, | ||
121 | ); | 126 | ); |
122 | } | 127 | } |
123 | 128 | ||
@@ -125,53 +130,71 @@ impl From<u32> for A { | |||
125 | fn test_generate_from_impl_for_enum_complicated_path() { | 130 | fn test_generate_from_impl_for_enum_complicated_path() { |
126 | check_assist( | 131 | check_assist( |
127 | generate_from_impl_for_enum, | 132 | generate_from_impl_for_enum, |
128 | r#"enum A { $0One(foo::bar::baz::Boo) }"#, | 133 | r#" |
129 | r#"enum A { One(foo::bar::baz::Boo) } | 134 | //- minicore: from |
135 | enum A { $0One(foo::bar::baz::Boo) } | ||
136 | "#, | ||
137 | r#" | ||
138 | enum A { One(foo::bar::baz::Boo) } | ||
130 | 139 | ||
131 | impl From<foo::bar::baz::Boo> for A { | 140 | impl From<foo::bar::baz::Boo> for A { |
132 | fn from(v: foo::bar::baz::Boo) -> Self { | 141 | fn from(v: foo::bar::baz::Boo) -> Self { |
133 | Self::One(v) | 142 | Self::One(v) |
134 | } | 143 | } |
135 | }"#, | 144 | } |
145 | "#, | ||
136 | ); | 146 | ); |
137 | } | 147 | } |
138 | 148 | ||
139 | fn check_not_applicable(ra_fixture: &str) { | ||
140 | let fixture = | ||
141 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
142 | check_assist_not_applicable(generate_from_impl_for_enum, &fixture) | ||
143 | } | ||
144 | |||
145 | #[test] | 149 | #[test] |
146 | fn test_add_from_impl_no_element() { | 150 | fn test_add_from_impl_no_element() { |
147 | check_not_applicable("enum A { $0One }"); | 151 | check_assist_not_applicable( |
152 | generate_from_impl_for_enum, | ||
153 | r#" | ||
154 | //- minicore: from | ||
155 | enum A { $0One } | ||
156 | "#, | ||
157 | ); | ||
148 | } | 158 | } |
149 | 159 | ||
150 | #[test] | 160 | #[test] |
151 | fn test_add_from_impl_more_than_one_element_in_tuple() { | 161 | fn test_add_from_impl_more_than_one_element_in_tuple() { |
152 | check_not_applicable("enum A { $0One(u32, String) }"); | 162 | check_assist_not_applicable( |
163 | generate_from_impl_for_enum, | ||
164 | r#" | ||
165 | //- minicore: from | ||
166 | enum A { $0One(u32, String) } | ||
167 | "#, | ||
168 | ); | ||
153 | } | 169 | } |
154 | 170 | ||
155 | #[test] | 171 | #[test] |
156 | fn test_add_from_impl_struct_variant() { | 172 | fn test_add_from_impl_struct_variant() { |
157 | check_assist( | 173 | check_assist( |
158 | generate_from_impl_for_enum, | 174 | generate_from_impl_for_enum, |
159 | "enum A { $0One { x: u32 } }", | 175 | r#" |
160 | r#"enum A { One { x: u32 } } | 176 | //- minicore: from |
177 | enum A { $0One { x: u32 } } | ||
178 | "#, | ||
179 | r#" | ||
180 | enum A { One { x: u32 } } | ||
161 | 181 | ||
162 | impl From<u32> for A { | 182 | impl From<u32> for A { |
163 | fn from(x: u32) -> Self { | 183 | fn from(x: u32) -> Self { |
164 | Self::One { x } | 184 | Self::One { x } |
165 | } | 185 | } |
166 | }"#, | 186 | } |
187 | "#, | ||
167 | ); | 188 | ); |
168 | } | 189 | } |
169 | 190 | ||
170 | #[test] | 191 | #[test] |
171 | fn test_add_from_impl_already_exists() { | 192 | fn test_add_from_impl_already_exists() { |
172 | cov_mark::check!(test_add_from_impl_already_exists); | 193 | cov_mark::check!(test_add_from_impl_already_exists); |
173 | check_not_applicable( | 194 | check_assist_not_applicable( |
195 | generate_from_impl_for_enum, | ||
174 | r#" | 196 | r#" |
197 | //- minicore: from | ||
175 | enum A { $0One(u32), } | 198 | enum A { $0One(u32), } |
176 | 199 | ||
177 | impl From<u32> for A { | 200 | impl From<u32> for A { |
@@ -187,7 +210,9 @@ impl From<u32> for A { | |||
187 | fn test_add_from_impl_different_variant_impl_exists() { | 210 | fn test_add_from_impl_different_variant_impl_exists() { |
188 | check_assist( | 211 | check_assist( |
189 | generate_from_impl_for_enum, | 212 | generate_from_impl_for_enum, |
190 | r#"enum A { $0One(u32), Two(String), } | 213 | r#" |
214 | //- minicore: from | ||
215 | enum A { $0One(u32), Two(String), } | ||
191 | 216 | ||
192 | impl From<String> for A { | 217 | impl From<String> for A { |
193 | fn from(v: String) -> Self { | 218 | fn from(v: String) -> Self { |
@@ -197,8 +222,10 @@ impl From<String> for A { | |||
197 | 222 | ||
198 | pub trait From<T> { | 223 | pub trait From<T> { |
199 | fn from(T) -> Self; | 224 | fn from(T) -> Self; |
200 | }"#, | 225 | } |
201 | r#"enum A { One(u32), Two(String), } | 226 | "#, |
227 | r#" | ||
228 | enum A { One(u32), Two(String), } | ||
202 | 229 | ||
203 | impl From<u32> for A { | 230 | impl From<u32> for A { |
204 | fn from(v: u32) -> Self { | 231 | fn from(v: u32) -> Self { |
@@ -214,7 +241,8 @@ impl From<String> for A { | |||
214 | 241 | ||
215 | pub trait From<T> { | 242 | pub trait From<T> { |
216 | fn from(T) -> Self; | 243 | fn from(T) -> Self; |
217 | }"#, | 244 | } |
245 | "#, | ||
218 | ); | 246 | ); |
219 | } | 247 | } |
220 | 248 | ||
@@ -222,14 +250,19 @@ pub trait From<T> { | |||
222 | fn test_add_from_impl_static_str() { | 250 | fn test_add_from_impl_static_str() { |
223 | check_assist( | 251 | check_assist( |
224 | generate_from_impl_for_enum, | 252 | generate_from_impl_for_enum, |
225 | "enum A { $0One(&'static str) }", | 253 | r#" |
226 | r#"enum A { One(&'static str) } | 254 | //- minicore: from |
255 | enum A { $0One(&'static str) } | ||
256 | "#, | ||
257 | r#" | ||
258 | enum A { One(&'static str) } | ||
227 | 259 | ||
228 | impl From<&'static str> for A { | 260 | impl From<&'static str> for A { |
229 | fn from(v: &'static str) -> Self { | 261 | fn from(v: &'static str) -> Self { |
230 | Self::One(v) | 262 | Self::One(v) |
231 | } | 263 | } |
232 | }"#, | 264 | } |
265 | "#, | ||
233 | ); | 266 | ); |
234 | } | 267 | } |
235 | 268 | ||
@@ -237,14 +270,19 @@ impl From<&'static str> for A { | |||
237 | fn test_add_from_impl_generic_enum() { | 270 | fn test_add_from_impl_generic_enum() { |
238 | check_assist( | 271 | check_assist( |
239 | generate_from_impl_for_enum, | 272 | generate_from_impl_for_enum, |
240 | "enum Generic<T, U: Clone> { $0One(T), Two(U) }", | 273 | r#" |
241 | r#"enum Generic<T, U: Clone> { One(T), Two(U) } | 274 | //- minicore: from |
275 | enum Generic<T, U: Clone> { $0One(T), Two(U) } | ||
276 | "#, | ||
277 | r#" | ||
278 | enum Generic<T, U: Clone> { One(T), Two(U) } | ||
242 | 279 | ||
243 | impl<T, U: Clone> From<T> for Generic<T, U> { | 280 | impl<T, U: Clone> From<T> for Generic<T, U> { |
244 | fn from(v: T) -> Self { | 281 | fn from(v: T) -> Self { |
245 | Self::One(v) | 282 | Self::One(v) |
246 | } | 283 | } |
247 | }"#, | 284 | } |
285 | "#, | ||
248 | ); | 286 | ); |
249 | } | 287 | } |
250 | 288 | ||
@@ -252,14 +290,19 @@ impl<T, U: Clone> From<T> for Generic<T, U> { | |||
252 | fn test_add_from_impl_with_lifetime() { | 290 | fn test_add_from_impl_with_lifetime() { |
253 | check_assist( | 291 | check_assist( |
254 | generate_from_impl_for_enum, | 292 | generate_from_impl_for_enum, |
255 | "enum Generic<'a> { $0One(&'a i32) }", | 293 | r#" |
256 | r#"enum Generic<'a> { One(&'a i32) } | 294 | //- minicore: from |
295 | enum Generic<'a> { $0One(&'a i32) } | ||
296 | "#, | ||
297 | r#" | ||
298 | enum Generic<'a> { One(&'a i32) } | ||
257 | 299 | ||
258 | impl<'a> From<&'a i32> for Generic<'a> { | 300 | impl<'a> From<&'a i32> for Generic<'a> { |
259 | fn from(v: &'a i32) -> Self { | 301 | fn from(v: &'a i32) -> Self { |
260 | Self::One(v) | 302 | Self::One(v) |
261 | } | 303 | } |
262 | }"#, | 304 | } |
305 | "#, | ||
263 | ); | 306 | ); |
264 | } | 307 | } |
265 | } | 308 | } |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 706c995ac..6a658d4cf 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -811,9 +811,8 @@ fn bar(baz: Baz::Bof) ${0:-> ()} { | |||
811 | } | 811 | } |
812 | 812 | ||
813 | #[test] | 813 | #[test] |
814 | #[ignore] | ||
815 | // FIXME fix printing the generics of a `Ty` to make this test pass | ||
816 | fn add_function_with_generic_arg() { | 814 | fn add_function_with_generic_arg() { |
815 | // FIXME: This is wrong, generated `bar` should include generic parameter. | ||
817 | check_assist( | 816 | check_assist( |
818 | generate_function, | 817 | generate_function, |
819 | r" | 818 | r" |
@@ -826,7 +825,7 @@ fn foo<T>(t: T) { | |||
826 | bar(t) | 825 | bar(t) |
827 | } | 826 | } |
828 | 827 | ||
829 | fn bar<T>(t: T) ${0:-> ()} { | 828 | fn bar(t: T) ${0:-> ()} { |
830 | todo!() | 829 | todo!() |
831 | } | 830 | } |
832 | ", | 831 | ", |
@@ -834,9 +833,8 @@ fn bar<T>(t: T) ${0:-> ()} { | |||
834 | } | 833 | } |
835 | 834 | ||
836 | #[test] | 835 | #[test] |
837 | #[ignore] | ||
838 | // FIXME Fix function type printing to make this test pass | ||
839 | fn add_function_with_fn_arg() { | 836 | fn add_function_with_fn_arg() { |
837 | // FIXME: The argument in `bar` is wrong. | ||
840 | check_assist( | 838 | check_assist( |
841 | generate_function, | 839 | generate_function, |
842 | r" | 840 | r" |
@@ -857,7 +855,7 @@ fn foo() { | |||
857 | bar(Baz::new); | 855 | bar(Baz::new); |
858 | } | 856 | } |
859 | 857 | ||
860 | fn bar(arg: fn() -> Baz) ${0:-> ()} { | 858 | fn bar(new: fn) ${0:-> ()} { |
861 | todo!() | 859 | todo!() |
862 | } | 860 | } |
863 | ", | 861 | ", |
@@ -865,9 +863,8 @@ fn bar(arg: fn() -> Baz) ${0:-> ()} { | |||
865 | } | 863 | } |
866 | 864 | ||
867 | #[test] | 865 | #[test] |
868 | #[ignore] | ||
869 | // FIXME Fix closure type printing to make this test pass | ||
870 | fn add_function_with_closure_arg() { | 866 | fn add_function_with_closure_arg() { |
867 | // FIXME: The argument in `bar` is wrong. | ||
871 | check_assist( | 868 | check_assist( |
872 | generate_function, | 869 | generate_function, |
873 | r" | 870 | r" |
@@ -882,7 +879,7 @@ fn foo() { | |||
882 | bar(closure) | 879 | bar(closure) |
883 | } | 880 | } |
884 | 881 | ||
885 | fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} { | 882 | fn bar(closure: ()) ${0:-> ()} { |
886 | todo!() | 883 | todo!() |
887 | } | 884 | } |
888 | ", | 885 | ", |
@@ -986,13 +983,10 @@ fn foo() { | |||
986 | } | 983 | } |
987 | 984 | ||
988 | #[test] | 985 | #[test] |
989 | #[ignore] | ||
990 | // Ignored until local imports are supported. | ||
991 | // See https://github.com/rust-analyzer/rust-analyzer/issues/1165 | ||
992 | fn qualified_path_uses_correct_scope() { | 986 | fn qualified_path_uses_correct_scope() { |
993 | check_assist( | 987 | check_assist( |
994 | generate_function, | 988 | generate_function, |
995 | " | 989 | r#" |
996 | mod foo { | 990 | mod foo { |
997 | pub struct Foo; | 991 | pub struct Foo; |
998 | } | 992 | } |
@@ -1001,8 +995,8 @@ fn bar() { | |||
1001 | let foo = Foo; | 995 | let foo = Foo; |
1002 | baz$0(foo) | 996 | baz$0(foo) |
1003 | } | 997 | } |
1004 | ", | 998 | "#, |
1005 | " | 999 | r#" |
1006 | mod foo { | 1000 | mod foo { |
1007 | pub struct Foo; | 1001 | pub struct Foo; |
1008 | } | 1002 | } |
@@ -1015,7 +1009,7 @@ fn bar() { | |||
1015 | fn baz(foo: foo::Foo) ${0:-> ()} { | 1009 | fn baz(foo: foo::Foo) ${0:-> ()} { |
1016 | todo!() | 1010 | todo!() |
1017 | } | 1011 | } |
1018 | ", | 1012 | "#, |
1019 | ) | 1013 | ) |
1020 | } | 1014 | } |
1021 | 1015 | ||
@@ -1141,40 +1135,29 @@ fn bar() {} | |||
1141 | // The assist is only active if the cursor is on an unresolved path, | 1135 | // The assist is only active if the cursor is on an unresolved path, |
1142 | // but the assist should only be offered if the path is a function call. | 1136 | // but the assist should only be offered if the path is a function call. |
1143 | generate_function, | 1137 | generate_function, |
1144 | r" | 1138 | r#" |
1145 | fn foo() { | 1139 | fn foo() { |
1146 | bar(b$0az); | 1140 | bar(b$0az); |
1147 | } | 1141 | } |
1148 | 1142 | ||
1149 | fn bar(baz: ()) {} | 1143 | fn bar(baz: ()) {} |
1150 | ", | 1144 | "#, |
1151 | ) | 1145 | ) |
1152 | } | 1146 | } |
1153 | 1147 | ||
1154 | #[test] | 1148 | #[test] |
1155 | #[ignore] | ||
1156 | fn create_method_with_no_args() { | 1149 | fn create_method_with_no_args() { |
1157 | check_assist( | 1150 | // FIXME: This is wrong, this should just work. |
1151 | check_assist_not_applicable( | ||
1158 | generate_function, | 1152 | generate_function, |
1159 | r" | 1153 | r#" |
1160 | struct Foo; | 1154 | struct Foo; |
1161 | impl Foo { | 1155 | impl Foo { |
1162 | fn foo(&self) { | 1156 | fn foo(&self) { |
1163 | self.bar()$0; | 1157 | self.bar()$0; |
1164 | } | 1158 | } |
1165 | } | 1159 | } |
1166 | ", | 1160 | "#, |
1167 | r" | ||
1168 | struct Foo; | ||
1169 | impl Foo { | ||
1170 | fn foo(&self) { | ||
1171 | self.bar(); | ||
1172 | } | ||
1173 | fn bar(&self) { | ||
1174 | todo!(); | ||
1175 | } | ||
1176 | } | ||
1177 | ", | ||
1178 | ) | 1161 | ) |
1179 | } | 1162 | } |
1180 | } | 1163 | } |
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs index 2441dbb8b..945d28650 100644 --- a/crates/ide_assists/src/handlers/inline_local_variable.rs +++ b/crates/ide_assists/src/handlers/inline_local_variable.rs | |||
@@ -65,32 +65,35 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
65 | Some(u) => u, | 65 | Some(u) => u, |
66 | None => return Some(false), | 66 | None => return Some(false), |
67 | }; | 67 | }; |
68 | 68 | Some( | |
69 | Some(!matches!( | 69 | !(matches!( |
70 | (&initializer_expr, usage_parent), | 70 | initializer_expr, |
71 | (ast::Expr::CallExpr(_), _) | 71 | ast::Expr::CallExpr(_) |
72 | | (ast::Expr::IndexExpr(_), _) | 72 | | ast::Expr::IndexExpr(_) |
73 | | (ast::Expr::MethodCallExpr(_), _) | 73 | | ast::Expr::MethodCallExpr(_) |
74 | | (ast::Expr::FieldExpr(_), _) | 74 | | ast::Expr::FieldExpr(_) |
75 | | (ast::Expr::TryExpr(_), _) | 75 | | ast::Expr::TryExpr(_) |
76 | | (ast::Expr::RefExpr(_), _) | 76 | | ast::Expr::RefExpr(_) |
77 | | (ast::Expr::Literal(_), _) | 77 | | ast::Expr::Literal(_) |
78 | | (ast::Expr::TupleExpr(_), _) | 78 | | ast::Expr::TupleExpr(_) |
79 | | (ast::Expr::ArrayExpr(_), _) | 79 | | ast::Expr::ArrayExpr(_) |
80 | | (ast::Expr::ParenExpr(_), _) | 80 | | ast::Expr::ParenExpr(_) |
81 | | (ast::Expr::PathExpr(_), _) | 81 | | ast::Expr::PathExpr(_) |
82 | | (ast::Expr::BlockExpr(_), _) | 82 | | ast::Expr::BlockExpr(_) |
83 | | (ast::Expr::EffectExpr(_), _) | 83 | | ast::Expr::EffectExpr(_), |
84 | | (_, ast::Expr::CallExpr(_)) | 84 | ) || matches!( |
85 | | (_, ast::Expr::TupleExpr(_)) | 85 | usage_parent, |
86 | | (_, ast::Expr::ArrayExpr(_)) | 86 | ast::Expr::CallExpr(_) |
87 | | (_, ast::Expr::ParenExpr(_)) | 87 | | ast::Expr::TupleExpr(_) |
88 | | (_, ast::Expr::ForExpr(_)) | 88 | | ast::Expr::ArrayExpr(_) |
89 | | (_, ast::Expr::WhileExpr(_)) | 89 | | ast::Expr::ParenExpr(_) |
90 | | (_, ast::Expr::BreakExpr(_)) | 90 | | ast::Expr::ForExpr(_) |
91 | | (_, ast::Expr::ReturnExpr(_)) | 91 | | ast::Expr::WhileExpr(_) |
92 | | (_, ast::Expr::MatchExpr(_)) | 92 | | ast::Expr::BreakExpr(_) |
93 | )) | 93 | | ast::Expr::ReturnExpr(_) |
94 | | ast::Expr::MatchExpr(_) | ||
95 | )), | ||
96 | ) | ||
94 | }) | 97 | }) |
95 | .collect::<Option<_>>() | 98 | .collect::<Option<_>>() |
96 | .map(|b| (file_id, b)) | 99 | .map(|b| (file_id, b)) |
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs index 93f702c55..cfc54be8d 100644 --- a/crates/ide_assists/src/handlers/move_module_to_file.rs +++ b/crates/ide_assists/src/handlers/move_module_to_file.rs | |||
@@ -1,5 +1,8 @@ | |||
1 | use std::iter; | ||
2 | |||
1 | use ast::edit::IndentLevel; | 3 | use ast::edit::IndentLevel; |
2 | use ide_db::base_db::AnchoredPathBuf; | 4 | use ide_db::base_db::AnchoredPathBuf; |
5 | use itertools::Itertools; | ||
3 | use stdx::format_to; | 6 | use stdx::format_to; |
4 | use syntax::{ | 7 | use syntax::{ |
5 | ast::{self, edit::AstNodeEdit, NameOwner}, | 8 | ast::{self, edit::AstNodeEdit, NameOwner}, |
@@ -34,7 +37,10 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
34 | 37 | ||
35 | let module_name = module_ast.name()?; | 38 | let module_name = module_ast.name()?; |
36 | 39 | ||
37 | let module_def = ctx.sema.to_def(&module_ast)?; | 40 | // get to the outermost module syntax so we can grab the module of file we are in |
41 | let outermost_mod_decl = | ||
42 | iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?; | ||
43 | let module_def = ctx.sema.to_def(&outermost_mod_decl)?; | ||
38 | let parent_module = module_def.parent(ctx.db())?; | 44 | let parent_module = module_def.parent(ctx.db())?; |
39 | 45 | ||
40 | acc.add( | 46 | acc.add( |
@@ -43,11 +49,19 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
43 | target, | 49 | target, |
44 | |builder| { | 50 | |builder| { |
45 | let path = { | 51 | let path = { |
46 | let dir = match parent_module.name(ctx.db()) { | 52 | let mut buf = String::from("./"); |
47 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), | 53 | match parent_module.name(ctx.db()) { |
48 | _ => String::new(), | 54 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => { |
49 | }; | 55 | format_to!(buf, "{}/", name) |
50 | format!("./{}{}.rs", dir, module_name) | 56 | } |
57 | _ => (), | ||
58 | } | ||
59 | let segments = iter::successors(Some(module_ast.clone()), |module| module.parent()) | ||
60 | .filter_map(|it| it.name()) | ||
61 | .collect::<Vec<_>>(); | ||
62 | format_to!(buf, "{}", segments.into_iter().rev().format("/")); | ||
63 | format_to!(buf, ".rs"); | ||
64 | buf | ||
51 | }; | 65 | }; |
52 | let contents = { | 66 | let contents = { |
53 | let items = module_items.dedent(IndentLevel(1)).to_string(); | 67 | let items = module_items.dedent(IndentLevel(1)).to_string(); |
@@ -59,14 +73,13 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
59 | items | 73 | items |
60 | }; | 74 | }; |
61 | 75 | ||
62 | let mut buf = String::new(); | 76 | let buf = format!("mod {};", module_name); |
63 | format_to!(buf, "mod {};", module_name); | ||
64 | 77 | ||
65 | let replacement_start = if let Some(mod_token) = module_ast.mod_token() { | 78 | let replacement_start = match module_ast.mod_token() { |
66 | mod_token.text_range().start() | 79 | Some(mod_token) => mod_token.text_range(), |
67 | } else { | 80 | None => module_ast.syntax().text_range(), |
68 | module_ast.syntax().text_range().start() | 81 | } |
69 | }; | 82 | .start(); |
70 | 83 | ||
71 | builder.replace( | 84 | builder.replace( |
72 | TextRange::new(replacement_start, module_ast.syntax().text_range().end()), | 85 | TextRange::new(replacement_start, module_ast.syntax().text_range().end()), |
@@ -212,4 +225,30 @@ mod tests; | |||
212 | "#, | 225 | "#, |
213 | ); | 226 | ); |
214 | } | 227 | } |
228 | |||
229 | #[test] | ||
230 | fn extract_nested() { | ||
231 | check_assist( | ||
232 | move_module_to_file, | ||
233 | r#" | ||
234 | //- /lib.rs | ||
235 | mod foo; | ||
236 | //- /foo.rs | ||
237 | mod bar { | ||
238 | mod baz { | ||
239 | mod qux$0 {} | ||
240 | } | ||
241 | } | ||
242 | "#, | ||
243 | r#" | ||
244 | //- /foo.rs | ||
245 | mod bar { | ||
246 | mod baz { | ||
247 | mod qux; | ||
248 | } | ||
249 | } | ||
250 | //- /foo/bar/baz/qux.rs | ||
251 | "#, | ||
252 | ); | ||
253 | } | ||
215 | } | 254 | } |
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index f91770a76..1d7be183a 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs | |||
@@ -216,28 +216,28 @@ mod tests { | |||
216 | cov_mark::check!(qualify_path_unqualified_name); | 216 | cov_mark::check!(qualify_path_unqualified_name); |
217 | check_assist( | 217 | check_assist( |
218 | qualify_path, | 218 | qualify_path, |
219 | r" | 219 | r#" |
220 | mod std { | 220 | mod std { |
221 | pub mod fmt { | 221 | pub mod fmt { |
222 | pub struct Formatter; | 222 | pub struct Formatter; |
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | use std::fmt; | 226 | use std::fmt; |
227 | 227 | ||
228 | $0Formatter | 228 | $0Formatter |
229 | ", | 229 | "#, |
230 | r" | 230 | r#" |
231 | mod std { | 231 | mod std { |
232 | pub mod fmt { | 232 | pub mod fmt { |
233 | pub struct Formatter; | 233 | pub struct Formatter; |
234 | } | 234 | } |
235 | } | 235 | } |
236 | 236 | ||
237 | use std::fmt; | 237 | use std::fmt; |
238 | 238 | ||
239 | fmt::Formatter | 239 | fmt::Formatter |
240 | ", | 240 | "#, |
241 | ); | 241 | ); |
242 | } | 242 | } |
243 | 243 | ||
@@ -245,20 +245,20 @@ mod tests { | |||
245 | fn applicable_when_found_an_import() { | 245 | fn applicable_when_found_an_import() { |
246 | check_assist( | 246 | check_assist( |
247 | qualify_path, | 247 | qualify_path, |
248 | r" | 248 | r#" |
249 | $0PubStruct | 249 | $0PubStruct |
250 | 250 | ||
251 | pub mod PubMod { | 251 | pub mod PubMod { |
252 | pub struct PubStruct; | 252 | pub struct PubStruct; |
253 | } | 253 | } |
254 | ", | 254 | "#, |
255 | r" | 255 | r#" |
256 | PubMod::PubStruct | 256 | PubMod::PubStruct |
257 | 257 | ||
258 | pub mod PubMod { | 258 | pub mod PubMod { |
259 | pub struct PubStruct; | 259 | pub struct PubStruct; |
260 | } | 260 | } |
261 | ", | 261 | "#, |
262 | ); | 262 | ); |
263 | } | 263 | } |
264 | 264 | ||
@@ -266,26 +266,26 @@ mod tests { | |||
266 | fn applicable_in_macros() { | 266 | fn applicable_in_macros() { |
267 | check_assist( | 267 | check_assist( |
268 | qualify_path, | 268 | qualify_path, |
269 | r" | 269 | r#" |
270 | macro_rules! foo { | 270 | macro_rules! foo { |
271 | ($i:ident) => { fn foo(a: $i) {} } | 271 | ($i:ident) => { fn foo(a: $i) {} } |
272 | } | 272 | } |
273 | foo!(Pub$0Struct); | 273 | foo!(Pub$0Struct); |
274 | 274 | ||
275 | pub mod PubMod { | 275 | pub mod PubMod { |
276 | pub struct PubStruct; | 276 | pub struct PubStruct; |
277 | } | 277 | } |
278 | ", | 278 | "#, |
279 | r" | 279 | r#" |
280 | macro_rules! foo { | 280 | macro_rules! foo { |
281 | ($i:ident) => { fn foo(a: $i) {} } | 281 | ($i:ident) => { fn foo(a: $i) {} } |
282 | } | 282 | } |
283 | foo!(PubMod::PubStruct); | 283 | foo!(PubMod::PubStruct); |
284 | 284 | ||
285 | pub mod PubMod { | 285 | pub mod PubMod { |
286 | pub struct PubStruct; | 286 | pub struct PubStruct; |
287 | } | 287 | } |
288 | ", | 288 | "#, |
289 | ); | 289 | ); |
290 | } | 290 | } |
291 | 291 | ||
@@ -293,32 +293,32 @@ mod tests { | |||
293 | fn applicable_when_found_multiple_imports() { | 293 | fn applicable_when_found_multiple_imports() { |
294 | check_assist( | 294 | check_assist( |
295 | qualify_path, | 295 | qualify_path, |
296 | r" | 296 | r#" |
297 | PubSt$0ruct | 297 | PubSt$0ruct |
298 | 298 | ||
299 | pub mod PubMod1 { | 299 | pub mod PubMod1 { |
300 | pub struct PubStruct; | 300 | pub struct PubStruct; |
301 | } | 301 | } |
302 | pub mod PubMod2 { | 302 | pub mod PubMod2 { |
303 | pub struct PubStruct; | 303 | pub struct PubStruct; |
304 | } | 304 | } |
305 | pub mod PubMod3 { | 305 | pub mod PubMod3 { |
306 | pub struct PubStruct; | 306 | pub struct PubStruct; |
307 | } | 307 | } |
308 | ", | 308 | "#, |
309 | r" | 309 | r#" |
310 | PubMod3::PubStruct | 310 | PubMod3::PubStruct |
311 | 311 | ||
312 | pub mod PubMod1 { | 312 | pub mod PubMod1 { |
313 | pub struct PubStruct; | 313 | pub struct PubStruct; |
314 | } | 314 | } |
315 | pub mod PubMod2 { | 315 | pub mod PubMod2 { |
316 | pub struct PubStruct; | 316 | pub struct PubStruct; |
317 | } | 317 | } |
318 | pub mod PubMod3 { | 318 | pub mod PubMod3 { |
319 | pub struct PubStruct; | 319 | pub struct PubStruct; |
320 | } | 320 | } |
321 | ", | 321 | "#, |
322 | ); | 322 | ); |
323 | } | 323 | } |
324 | 324 | ||
@@ -326,15 +326,15 @@ mod tests { | |||
326 | fn not_applicable_for_already_imported_types() { | 326 | fn not_applicable_for_already_imported_types() { |
327 | check_assist_not_applicable( | 327 | check_assist_not_applicable( |
328 | qualify_path, | 328 | qualify_path, |
329 | r" | 329 | r#" |
330 | use PubMod::PubStruct; | 330 | use PubMod::PubStruct; |
331 | 331 | ||
332 | PubStruct$0 | 332 | PubStruct$0 |
333 | 333 | ||
334 | pub mod PubMod { | 334 | pub mod PubMod { |
335 | pub struct PubStruct; | 335 | pub struct PubStruct; |
336 | } | 336 | } |
337 | ", | 337 | "#, |
338 | ); | 338 | ); |
339 | } | 339 | } |
340 | 340 | ||
@@ -342,35 +342,32 @@ mod tests { | |||
342 | fn not_applicable_for_types_with_private_paths() { | 342 | fn not_applicable_for_types_with_private_paths() { |
343 | check_assist_not_applicable( | 343 | check_assist_not_applicable( |
344 | qualify_path, | 344 | qualify_path, |
345 | r" | 345 | r#" |
346 | PrivateStruct$0 | 346 | PrivateStruct$0 |
347 | 347 | ||
348 | pub mod PubMod { | 348 | pub mod PubMod { |
349 | struct PrivateStruct; | 349 | struct PrivateStruct; |
350 | } | 350 | } |
351 | ", | 351 | "#, |
352 | ); | 352 | ); |
353 | } | 353 | } |
354 | 354 | ||
355 | #[test] | 355 | #[test] |
356 | fn not_applicable_when_no_imports_found() { | 356 | fn not_applicable_when_no_imports_found() { |
357 | check_assist_not_applicable( | 357 | check_assist_not_applicable(qualify_path, r#"PubStruct$0"#); |
358 | qualify_path, | ||
359 | " | ||
360 | PubStruct$0", | ||
361 | ); | ||
362 | } | 358 | } |
363 | 359 | ||
364 | #[test] | 360 | #[test] |
365 | fn not_applicable_in_import_statements() { | 361 | fn not_applicable_in_import_statements() { |
366 | check_assist_not_applicable( | 362 | check_assist_not_applicable( |
367 | qualify_path, | 363 | qualify_path, |
368 | r" | 364 | r#" |
369 | use PubStruct$0; | 365 | use PubStruct$0; |
370 | 366 | ||
371 | pub mod PubMod { | 367 | pub mod PubMod { |
372 | pub struct PubStruct; | 368 | pub struct PubStruct; |
373 | }", | 369 | } |
370 | "#, | ||
374 | ); | 371 | ); |
375 | } | 372 | } |
376 | 373 | ||
@@ -378,20 +375,20 @@ mod tests { | |||
378 | fn qualify_function() { | 375 | fn qualify_function() { |
379 | check_assist( | 376 | check_assist( |
380 | qualify_path, | 377 | qualify_path, |
381 | r" | 378 | r#" |
382 | test_function$0 | 379 | test_function$0 |
383 | 380 | ||
384 | pub mod PubMod { | 381 | pub mod PubMod { |
385 | pub fn test_function() {}; | 382 | pub fn test_function() {}; |
386 | } | 383 | } |
387 | ", | 384 | "#, |
388 | r" | 385 | r#" |
389 | PubMod::test_function | 386 | PubMod::test_function |
390 | 387 | ||
391 | pub mod PubMod { | 388 | pub mod PubMod { |
392 | pub fn test_function() {}; | 389 | pub fn test_function() {}; |
393 | } | 390 | } |
394 | ", | 391 | "#, |
395 | ); | 392 | ); |
396 | } | 393 | } |
397 | 394 | ||
@@ -399,7 +396,7 @@ mod tests { | |||
399 | fn qualify_macro() { | 396 | fn qualify_macro() { |
400 | check_assist( | 397 | check_assist( |
401 | qualify_path, | 398 | qualify_path, |
402 | r" | 399 | r#" |
403 | //- /lib.rs crate:crate_with_macro | 400 | //- /lib.rs crate:crate_with_macro |
404 | #[macro_export] | 401 | #[macro_export] |
405 | macro_rules! foo { | 402 | macro_rules! foo { |
@@ -410,12 +407,12 @@ macro_rules! foo { | |||
410 | fn main() { | 407 | fn main() { |
411 | foo$0 | 408 | foo$0 |
412 | } | 409 | } |
413 | ", | 410 | "#, |
414 | r" | 411 | r#" |
415 | fn main() { | 412 | fn main() { |
416 | crate_with_macro::foo | 413 | crate_with_macro::foo |
417 | } | 414 | } |
418 | ", | 415 | "#, |
419 | ); | 416 | ); |
420 | } | 417 | } |
421 | 418 | ||
@@ -423,13 +420,13 @@ fn main() { | |||
423 | fn qualify_path_target() { | 420 | fn qualify_path_target() { |
424 | check_assist_target( | 421 | check_assist_target( |
425 | qualify_path, | 422 | qualify_path, |
426 | r" | 423 | r#" |
427 | struct AssistInfo { | 424 | struct AssistInfo { |
428 | group_label: Option<$0GroupLabel>, | 425 | group_label: Option<$0GroupLabel>, |
429 | } | 426 | } |
430 | 427 | ||
431 | mod m { pub struct GroupLabel; } | 428 | mod m { pub struct GroupLabel; } |
432 | ", | 429 | "#, |
433 | "GroupLabel", | 430 | "GroupLabel", |
434 | ) | 431 | ) |
435 | } | 432 | } |
@@ -438,20 +435,20 @@ fn main() { | |||
438 | fn not_applicable_when_path_start_is_imported() { | 435 | fn not_applicable_when_path_start_is_imported() { |
439 | check_assist_not_applicable( | 436 | check_assist_not_applicable( |
440 | qualify_path, | 437 | qualify_path, |
441 | r" | 438 | r#" |
442 | pub mod mod1 { | 439 | pub mod mod1 { |
443 | pub mod mod2 { | 440 | pub mod mod2 { |
444 | pub mod mod3 { | 441 | pub mod mod3 { |
445 | pub struct TestStruct; | 442 | pub struct TestStruct; |
446 | } | 443 | } |
447 | } | 444 | } |
448 | } | 445 | } |
449 | 446 | ||
450 | use mod1::mod2; | 447 | use mod1::mod2; |
451 | fn main() { | 448 | fn main() { |
452 | mod2::mod3::TestStruct$0 | 449 | mod2::mod3::TestStruct$0 |
453 | } | 450 | } |
454 | ", | 451 | "#, |
455 | ); | 452 | ); |
456 | } | 453 | } |
457 | 454 | ||
@@ -459,16 +456,16 @@ fn main() { | |||
459 | fn not_applicable_for_imported_function() { | 456 | fn not_applicable_for_imported_function() { |
460 | check_assist_not_applicable( | 457 | check_assist_not_applicable( |
461 | qualify_path, | 458 | qualify_path, |
462 | r" | 459 | r#" |
463 | pub mod test_mod { | 460 | pub mod test_mod { |
464 | pub fn test_function() {} | 461 | pub fn test_function() {} |
465 | } | 462 | } |
466 | 463 | ||
467 | use test_mod::test_function; | 464 | use test_mod::test_function; |
468 | fn main() { | 465 | fn main() { |
469 | test_function$0 | 466 | test_function$0 |
470 | } | 467 | } |
471 | ", | 468 | "#, |
472 | ); | 469 | ); |
473 | } | 470 | } |
474 | 471 | ||
@@ -476,30 +473,30 @@ fn main() { | |||
476 | fn associated_struct_function() { | 473 | fn associated_struct_function() { |
477 | check_assist( | 474 | check_assist( |
478 | qualify_path, | 475 | qualify_path, |
479 | r" | 476 | r#" |
480 | mod test_mod { | 477 | mod test_mod { |
481 | pub struct TestStruct {} | 478 | pub struct TestStruct {} |
482 | impl TestStruct { | 479 | impl TestStruct { |
483 | pub fn test_function() {} | 480 | pub fn test_function() {} |
484 | } | 481 | } |
485 | } | 482 | } |
486 | 483 | ||
487 | fn main() { | 484 | fn main() { |
488 | TestStruct::test_function$0 | 485 | TestStruct::test_function$0 |
489 | } | 486 | } |
490 | ", | 487 | "#, |
491 | r" | 488 | r#" |
492 | mod test_mod { | 489 | mod test_mod { |
493 | pub struct TestStruct {} | 490 | pub struct TestStruct {} |
494 | impl TestStruct { | 491 | impl TestStruct { |
495 | pub fn test_function() {} | 492 | pub fn test_function() {} |
496 | } | 493 | } |
497 | } | 494 | } |
498 | 495 | ||
499 | fn main() { | 496 | fn main() { |
500 | test_mod::TestStruct::test_function | 497 | test_mod::TestStruct::test_function |
501 | } | 498 | } |
502 | ", | 499 | "#, |
503 | ); | 500 | ); |
504 | } | 501 | } |
505 | 502 | ||
@@ -508,62 +505,50 @@ fn main() { | |||
508 | cov_mark::check!(qualify_path_qualifier_start); | 505 | cov_mark::check!(qualify_path_qualifier_start); |
509 | check_assist( | 506 | check_assist( |
510 | qualify_path, | 507 | qualify_path, |
511 | r" | 508 | r#" |
512 | mod test_mod { | 509 | mod test_mod { |
513 | pub struct TestStruct {} | 510 | pub struct TestStruct {} |
514 | impl TestStruct { | 511 | impl TestStruct { |
515 | const TEST_CONST: u8 = 42; | 512 | const TEST_CONST: u8 = 42; |
516 | } | 513 | } |
517 | } | 514 | } |
518 | 515 | ||
519 | fn main() { | 516 | fn main() { |
520 | TestStruct::TEST_CONST$0 | 517 | TestStruct::TEST_CONST$0 |
521 | } | 518 | } |
522 | ", | 519 | "#, |
523 | r" | 520 | r#" |
524 | mod test_mod { | 521 | mod test_mod { |
525 | pub struct TestStruct {} | 522 | pub struct TestStruct {} |
526 | impl TestStruct { | 523 | impl TestStruct { |
527 | const TEST_CONST: u8 = 42; | 524 | const TEST_CONST: u8 = 42; |
528 | } | 525 | } |
529 | } | 526 | } |
530 | 527 | ||
531 | fn main() { | 528 | fn main() { |
532 | test_mod::TestStruct::TEST_CONST | 529 | test_mod::TestStruct::TEST_CONST |
533 | } | 530 | } |
534 | ", | 531 | "#, |
535 | ); | 532 | ); |
536 | } | 533 | } |
537 | 534 | ||
538 | #[test] | 535 | #[test] |
539 | #[ignore = "FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details"] | ||
540 | fn associated_struct_const_unqualified() { | 536 | fn associated_struct_const_unqualified() { |
541 | check_assist( | 537 | // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details |
538 | check_assist_not_applicable( | ||
542 | qualify_path, | 539 | qualify_path, |
543 | r" | 540 | r#" |
544 | mod test_mod { | 541 | mod test_mod { |
545 | pub struct TestStruct {} | 542 | pub struct TestStruct {} |
546 | impl TestStruct { | 543 | impl TestStruct { |
547 | const TEST_CONST: u8 = 42; | 544 | const TEST_CONST: u8 = 42; |
548 | } | 545 | } |
549 | } | 546 | } |
550 | |||
551 | fn main() { | ||
552 | TEST_CONST$0 | ||
553 | } | ||
554 | ", | ||
555 | r" | ||
556 | mod test_mod { | ||
557 | pub struct TestStruct {} | ||
558 | impl TestStruct { | ||
559 | const TEST_CONST: u8 = 42; | ||
560 | } | ||
561 | } | ||
562 | 547 | ||
563 | fn main() { | 548 | fn main() { |
564 | test_mod::TestStruct::TEST_CONST | 549 | TEST_CONST$0 |
565 | } | 550 | } |
566 | ", | 551 | "#, |
567 | ); | 552 | ); |
568 | } | 553 | } |
569 | 554 | ||
@@ -571,36 +556,36 @@ fn main() { | |||
571 | fn associated_trait_function() { | 556 | fn associated_trait_function() { |
572 | check_assist( | 557 | check_assist( |
573 | qualify_path, | 558 | qualify_path, |
574 | r" | 559 | r#" |
575 | mod test_mod { | 560 | mod test_mod { |
576 | pub trait TestTrait { | 561 | pub trait TestTrait { |
577 | fn test_function(); | 562 | fn test_function(); |
578 | } | 563 | } |
579 | pub struct TestStruct {} | 564 | pub struct TestStruct {} |
580 | impl TestTrait for TestStruct { | 565 | impl TestTrait for TestStruct { |
581 | fn test_function() {} | 566 | fn test_function() {} |
582 | } | 567 | } |
583 | } | 568 | } |
584 | 569 | ||
585 | fn main() { | 570 | fn main() { |
586 | test_mod::TestStruct::test_function$0 | 571 | test_mod::TestStruct::test_function$0 |
587 | } | 572 | } |
588 | ", | 573 | "#, |
589 | r" | 574 | r#" |
590 | mod test_mod { | 575 | mod test_mod { |
591 | pub trait TestTrait { | 576 | pub trait TestTrait { |
592 | fn test_function(); | 577 | fn test_function(); |
593 | } | 578 | } |
594 | pub struct TestStruct {} | 579 | pub struct TestStruct {} |
595 | impl TestTrait for TestStruct { | 580 | impl TestTrait for TestStruct { |
596 | fn test_function() {} | 581 | fn test_function() {} |
597 | } | 582 | } |
598 | } | 583 | } |
599 | 584 | ||
600 | fn main() { | 585 | fn main() { |
601 | <test_mod::TestStruct as test_mod::TestTrait>::test_function | 586 | <test_mod::TestStruct as test_mod::TestTrait>::test_function |
602 | } | 587 | } |
603 | ", | 588 | "#, |
604 | ); | 589 | ); |
605 | } | 590 | } |
606 | 591 | ||
@@ -608,31 +593,31 @@ fn main() { | |||
608 | fn not_applicable_for_imported_trait_for_function() { | 593 | fn not_applicable_for_imported_trait_for_function() { |
609 | check_assist_not_applicable( | 594 | check_assist_not_applicable( |
610 | qualify_path, | 595 | qualify_path, |
611 | r" | 596 | r#" |
612 | mod test_mod { | 597 | mod test_mod { |
613 | pub trait TestTrait { | 598 | pub trait TestTrait { |
614 | fn test_function(); | 599 | fn test_function(); |
615 | } | 600 | } |
616 | pub trait TestTrait2 { | 601 | pub trait TestTrait2 { |
617 | fn test_function(); | 602 | fn test_function(); |
618 | } | 603 | } |
619 | pub enum TestEnum { | 604 | pub enum TestEnum { |
620 | One, | 605 | One, |
621 | Two, | 606 | Two, |
622 | } | 607 | } |
623 | impl TestTrait2 for TestEnum { | 608 | impl TestTrait2 for TestEnum { |
624 | fn test_function() {} | 609 | fn test_function() {} |
625 | } | 610 | } |
626 | impl TestTrait for TestEnum { | 611 | impl TestTrait for TestEnum { |
627 | fn test_function() {} | 612 | fn test_function() {} |
628 | } | 613 | } |
629 | } | 614 | } |
630 | 615 | ||
631 | use test_mod::TestTrait2; | 616 | use test_mod::TestTrait2; |
632 | fn main() { | 617 | fn main() { |
633 | test_mod::TestEnum::test_function$0; | 618 | test_mod::TestEnum::test_function$0; |
634 | } | 619 | } |
635 | ", | 620 | "#, |
636 | ) | 621 | ) |
637 | } | 622 | } |
638 | 623 | ||
@@ -641,36 +626,36 @@ fn main() { | |||
641 | cov_mark::check!(qualify_path_trait_assoc_item); | 626 | cov_mark::check!(qualify_path_trait_assoc_item); |
642 | check_assist( | 627 | check_assist( |
643 | qualify_path, | 628 | qualify_path, |
644 | r" | 629 | r#" |
645 | mod test_mod { | 630 | mod test_mod { |
646 | pub trait TestTrait { | 631 | pub trait TestTrait { |
647 | const TEST_CONST: u8; | 632 | const TEST_CONST: u8; |
648 | } | 633 | } |
649 | pub struct TestStruct {} | 634 | pub struct TestStruct {} |
650 | impl TestTrait for TestStruct { | 635 | impl TestTrait for TestStruct { |
651 | const TEST_CONST: u8 = 42; | 636 | const TEST_CONST: u8 = 42; |
652 | } | 637 | } |
653 | } | 638 | } |
654 | 639 | ||
655 | fn main() { | 640 | fn main() { |
656 | test_mod::TestStruct::TEST_CONST$0 | 641 | test_mod::TestStruct::TEST_CONST$0 |
657 | } | 642 | } |
658 | ", | 643 | "#, |
659 | r" | 644 | r#" |
660 | mod test_mod { | 645 | mod test_mod { |
661 | pub trait TestTrait { | 646 | pub trait TestTrait { |
662 | const TEST_CONST: u8; | 647 | const TEST_CONST: u8; |
663 | } | 648 | } |
664 | pub struct TestStruct {} | 649 | pub struct TestStruct {} |
665 | impl TestTrait for TestStruct { | 650 | impl TestTrait for TestStruct { |
666 | const TEST_CONST: u8 = 42; | 651 | const TEST_CONST: u8 = 42; |
667 | } | 652 | } |
668 | } | 653 | } |
669 | 654 | ||
670 | fn main() { | 655 | fn main() { |
671 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST | 656 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST |
672 | } | 657 | } |
673 | ", | 658 | "#, |
674 | ); | 659 | ); |
675 | } | 660 | } |
676 | 661 | ||
@@ -678,31 +663,31 @@ fn main() { | |||
678 | fn not_applicable_for_imported_trait_for_const() { | 663 | fn not_applicable_for_imported_trait_for_const() { |
679 | check_assist_not_applicable( | 664 | check_assist_not_applicable( |
680 | qualify_path, | 665 | qualify_path, |
681 | r" | 666 | r#" |
682 | mod test_mod { | 667 | mod test_mod { |
683 | pub trait TestTrait { | 668 | pub trait TestTrait { |
684 | const TEST_CONST: u8; | 669 | const TEST_CONST: u8; |
685 | } | 670 | } |
686 | pub trait TestTrait2 { | 671 | pub trait TestTrait2 { |
687 | const TEST_CONST: f64; | 672 | const TEST_CONST: f64; |
688 | } | 673 | } |
689 | pub enum TestEnum { | 674 | pub enum TestEnum { |
690 | One, | 675 | One, |
691 | Two, | 676 | Two, |
692 | } | 677 | } |
693 | impl TestTrait2 for TestEnum { | 678 | impl TestTrait2 for TestEnum { |
694 | const TEST_CONST: f64 = 42.0; | 679 | const TEST_CONST: f64 = 42.0; |
695 | } | 680 | } |
696 | impl TestTrait for TestEnum { | 681 | impl TestTrait for TestEnum { |
697 | const TEST_CONST: u8 = 42; | 682 | const TEST_CONST: u8 = 42; |
698 | } | 683 | } |
699 | } | 684 | } |
700 | 685 | ||
701 | use test_mod::TestTrait2; | 686 | use test_mod::TestTrait2; |
702 | fn main() { | 687 | fn main() { |
703 | test_mod::TestEnum::TEST_CONST$0; | 688 | test_mod::TestEnum::TEST_CONST$0; |
704 | } | 689 | } |
705 | ", | 690 | "#, |
706 | ) | 691 | ) |
707 | } | 692 | } |
708 | 693 | ||
@@ -711,38 +696,38 @@ fn main() { | |||
711 | cov_mark::check!(qualify_path_trait_method); | 696 | cov_mark::check!(qualify_path_trait_method); |
712 | check_assist( | 697 | check_assist( |
713 | qualify_path, | 698 | qualify_path, |
714 | r" | 699 | r#" |
715 | mod test_mod { | 700 | mod test_mod { |
716 | pub trait TestTrait { | 701 | pub trait TestTrait { |
717 | fn test_method(&self); | 702 | fn test_method(&self); |
718 | } | 703 | } |
719 | pub struct TestStruct {} | 704 | pub struct TestStruct {} |
720 | impl TestTrait for TestStruct { | 705 | impl TestTrait for TestStruct { |
721 | fn test_method(&self) {} | 706 | fn test_method(&self) {} |
722 | } | 707 | } |
723 | } | 708 | } |
724 | 709 | ||
725 | fn main() { | 710 | fn main() { |
726 | let test_struct = test_mod::TestStruct {}; | 711 | let test_struct = test_mod::TestStruct {}; |
727 | test_struct.test_meth$0od() | 712 | test_struct.test_meth$0od() |
728 | } | 713 | } |
729 | ", | 714 | "#, |
730 | r" | 715 | r#" |
731 | mod test_mod { | 716 | mod test_mod { |
732 | pub trait TestTrait { | 717 | pub trait TestTrait { |
733 | fn test_method(&self); | 718 | fn test_method(&self); |
734 | } | 719 | } |
735 | pub struct TestStruct {} | 720 | pub struct TestStruct {} |
736 | impl TestTrait for TestStruct { | 721 | impl TestTrait for TestStruct { |
737 | fn test_method(&self) {} | 722 | fn test_method(&self) {} |
738 | } | 723 | } |
739 | } | 724 | } |
740 | 725 | ||
741 | fn main() { | 726 | fn main() { |
742 | let test_struct = test_mod::TestStruct {}; | 727 | let test_struct = test_mod::TestStruct {}; |
743 | test_mod::TestTrait::test_method(&test_struct) | 728 | test_mod::TestTrait::test_method(&test_struct) |
744 | } | 729 | } |
745 | ", | 730 | "#, |
746 | ); | 731 | ); |
747 | } | 732 | } |
748 | 733 | ||
@@ -750,38 +735,38 @@ fn main() { | |||
750 | fn trait_method_multi_params() { | 735 | fn trait_method_multi_params() { |
751 | check_assist( | 736 | check_assist( |
752 | qualify_path, | 737 | qualify_path, |
753 | r" | 738 | r#" |
754 | mod test_mod { | 739 | mod test_mod { |
755 | pub trait TestTrait { | 740 | pub trait TestTrait { |
756 | fn test_method(&self, test: i32); | 741 | fn test_method(&self, test: i32); |
757 | } | 742 | } |
758 | pub struct TestStruct {} | 743 | pub struct TestStruct {} |
759 | impl TestTrait for TestStruct { | 744 | impl TestTrait for TestStruct { |
760 | fn test_method(&self, test: i32) {} | 745 | fn test_method(&self, test: i32) {} |
761 | } | 746 | } |
762 | } | 747 | } |
763 | 748 | ||
764 | fn main() { | 749 | fn main() { |
765 | let test_struct = test_mod::TestStruct {}; | 750 | let test_struct = test_mod::TestStruct {}; |
766 | test_struct.test_meth$0od(42) | 751 | test_struct.test_meth$0od(42) |
767 | } | 752 | } |
768 | ", | 753 | "#, |
769 | r" | 754 | r#" |
770 | mod test_mod { | 755 | mod test_mod { |
771 | pub trait TestTrait { | 756 | pub trait TestTrait { |
772 | fn test_method(&self, test: i32); | 757 | fn test_method(&self, test: i32); |
773 | } | 758 | } |
774 | pub struct TestStruct {} | 759 | pub struct TestStruct {} |
775 | impl TestTrait for TestStruct { | 760 | impl TestTrait for TestStruct { |
776 | fn test_method(&self, test: i32) {} | 761 | fn test_method(&self, test: i32) {} |
777 | } | 762 | } |
778 | } | 763 | } |
779 | 764 | ||
780 | fn main() { | 765 | fn main() { |
781 | let test_struct = test_mod::TestStruct {}; | 766 | let test_struct = test_mod::TestStruct {}; |
782 | test_mod::TestTrait::test_method(&test_struct, 42) | 767 | test_mod::TestTrait::test_method(&test_struct, 42) |
783 | } | 768 | } |
784 | ", | 769 | "#, |
785 | ); | 770 | ); |
786 | } | 771 | } |
787 | 772 | ||
@@ -789,38 +774,38 @@ fn main() { | |||
789 | fn trait_method_consume() { | 774 | fn trait_method_consume() { |
790 | check_assist( | 775 | check_assist( |
791 | qualify_path, | 776 | qualify_path, |
792 | r" | 777 | r#" |
793 | mod test_mod { | 778 | mod test_mod { |
794 | pub trait TestTrait { | 779 | pub trait TestTrait { |
795 | fn test_method(self); | 780 | fn test_method(self); |
796 | } | 781 | } |
797 | pub struct TestStruct {} | 782 | pub struct TestStruct {} |
798 | impl TestTrait for TestStruct { | 783 | impl TestTrait for TestStruct { |
799 | fn test_method(self) {} | 784 | fn test_method(self) {} |
800 | } | 785 | } |
801 | } | 786 | } |
802 | 787 | ||
803 | fn main() { | 788 | fn main() { |
804 | let test_struct = test_mod::TestStruct {}; | 789 | let test_struct = test_mod::TestStruct {}; |
805 | test_struct.test_meth$0od() | 790 | test_struct.test_meth$0od() |
806 | } | 791 | } |
807 | ", | 792 | "#, |
808 | r" | 793 | r#" |
809 | mod test_mod { | 794 | mod test_mod { |
810 | pub trait TestTrait { | 795 | pub trait TestTrait { |
811 | fn test_method(self); | 796 | fn test_method(self); |
812 | } | 797 | } |
813 | pub struct TestStruct {} | 798 | pub struct TestStruct {} |
814 | impl TestTrait for TestStruct { | 799 | impl TestTrait for TestStruct { |
815 | fn test_method(self) {} | 800 | fn test_method(self) {} |
816 | } | 801 | } |
817 | } | 802 | } |
818 | 803 | ||
819 | fn main() { | 804 | fn main() { |
820 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
821 | test_mod::TestTrait::test_method(test_struct) | 806 | test_mod::TestTrait::test_method(test_struct) |
822 | } | 807 | } |
823 | ", | 808 | "#, |
824 | ); | 809 | ); |
825 | } | 810 | } |
826 | 811 | ||
@@ -828,29 +813,29 @@ fn main() { | |||
828 | fn trait_method_cross_crate() { | 813 | fn trait_method_cross_crate() { |
829 | check_assist( | 814 | check_assist( |
830 | qualify_path, | 815 | qualify_path, |
831 | r" | 816 | r#" |
832 | //- /main.rs crate:main deps:dep | 817 | //- /main.rs crate:main deps:dep |
833 | fn main() { | 818 | fn main() { |
834 | let test_struct = dep::test_mod::TestStruct {}; | 819 | let test_struct = dep::test_mod::TestStruct {}; |
835 | test_struct.test_meth$0od() | 820 | test_struct.test_meth$0od() |
836 | } | 821 | } |
837 | //- /dep.rs crate:dep | 822 | //- /dep.rs crate:dep |
838 | pub mod test_mod { | 823 | pub mod test_mod { |
839 | pub trait TestTrait { | 824 | pub trait TestTrait { |
840 | fn test_method(&self); | 825 | fn test_method(&self); |
841 | } | 826 | } |
842 | pub struct TestStruct {} | 827 | pub struct TestStruct {} |
843 | impl TestTrait for TestStruct { | 828 | impl TestTrait for TestStruct { |
844 | fn test_method(&self) {} | 829 | fn test_method(&self) {} |
845 | } | 830 | } |
846 | } | 831 | } |
847 | ", | 832 | "#, |
848 | r" | 833 | r#" |
849 | fn main() { | 834 | fn main() { |
850 | let test_struct = dep::test_mod::TestStruct {}; | 835 | let test_struct = dep::test_mod::TestStruct {}; |
851 | dep::test_mod::TestTrait::test_method(&test_struct) | 836 | dep::test_mod::TestTrait::test_method(&test_struct) |
852 | } | 837 | } |
853 | ", | 838 | "#, |
854 | ); | 839 | ); |
855 | } | 840 | } |
856 | 841 | ||
@@ -858,27 +843,27 @@ fn main() { | |||
858 | fn assoc_fn_cross_crate() { | 843 | fn assoc_fn_cross_crate() { |
859 | check_assist( | 844 | check_assist( |
860 | qualify_path, | 845 | qualify_path, |
861 | r" | 846 | r#" |
862 | //- /main.rs crate:main deps:dep | 847 | //- /main.rs crate:main deps:dep |
863 | fn main() { | 848 | fn main() { |
864 | dep::test_mod::TestStruct::test_func$0tion | 849 | dep::test_mod::TestStruct::test_func$0tion |
865 | } | 850 | } |
866 | //- /dep.rs crate:dep | 851 | //- /dep.rs crate:dep |
867 | pub mod test_mod { | 852 | pub mod test_mod { |
868 | pub trait TestTrait { | 853 | pub trait TestTrait { |
869 | fn test_function(); | 854 | fn test_function(); |
870 | } | 855 | } |
871 | pub struct TestStruct {} | 856 | pub struct TestStruct {} |
872 | impl TestTrait for TestStruct { | 857 | impl TestTrait for TestStruct { |
873 | fn test_function() {} | 858 | fn test_function() {} |
874 | } | 859 | } |
875 | } | 860 | } |
876 | ", | 861 | "#, |
877 | r" | 862 | r#" |
878 | fn main() { | 863 | fn main() { |
879 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function | 864 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function |
880 | } | 865 | } |
881 | ", | 866 | "#, |
882 | ); | 867 | ); |
883 | } | 868 | } |
884 | 869 | ||
@@ -886,27 +871,27 @@ fn main() { | |||
886 | fn assoc_const_cross_crate() { | 871 | fn assoc_const_cross_crate() { |
887 | check_assist( | 872 | check_assist( |
888 | qualify_path, | 873 | qualify_path, |
889 | r" | 874 | r#" |
890 | //- /main.rs crate:main deps:dep | 875 | //- /main.rs crate:main deps:dep |
891 | fn main() { | 876 | fn main() { |
892 | dep::test_mod::TestStruct::CONST$0 | 877 | dep::test_mod::TestStruct::CONST$0 |
893 | } | 878 | } |
894 | //- /dep.rs crate:dep | 879 | //- /dep.rs crate:dep |
895 | pub mod test_mod { | 880 | pub mod test_mod { |
896 | pub trait TestTrait { | 881 | pub trait TestTrait { |
897 | const CONST: bool; | 882 | const CONST: bool; |
898 | } | 883 | } |
899 | pub struct TestStruct {} | 884 | pub struct TestStruct {} |
900 | impl TestTrait for TestStruct { | 885 | impl TestTrait for TestStruct { |
901 | const CONST: bool = true; | 886 | const CONST: bool = true; |
902 | } | 887 | } |
903 | } | 888 | } |
904 | ", | 889 | "#, |
905 | r" | 890 | r#" |
906 | fn main() { | 891 | fn main() { |
907 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST | 892 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST |
908 | } | 893 | } |
909 | ", | 894 | "#, |
910 | ); | 895 | ); |
911 | } | 896 | } |
912 | 897 | ||
@@ -914,23 +899,23 @@ fn main() { | |||
914 | fn assoc_fn_as_method_cross_crate() { | 899 | fn assoc_fn_as_method_cross_crate() { |
915 | check_assist_not_applicable( | 900 | check_assist_not_applicable( |
916 | qualify_path, | 901 | qualify_path, |
917 | r" | 902 | r#" |
918 | //- /main.rs crate:main deps:dep | 903 | //- /main.rs crate:main deps:dep |
919 | fn main() { | 904 | fn main() { |
920 | let test_struct = dep::test_mod::TestStruct {}; | 905 | let test_struct = dep::test_mod::TestStruct {}; |
921 | test_struct.test_func$0tion() | 906 | test_struct.test_func$0tion() |
922 | } | 907 | } |
923 | //- /dep.rs crate:dep | 908 | //- /dep.rs crate:dep |
924 | pub mod test_mod { | 909 | pub mod test_mod { |
925 | pub trait TestTrait { | 910 | pub trait TestTrait { |
926 | fn test_function(); | 911 | fn test_function(); |
927 | } | 912 | } |
928 | pub struct TestStruct {} | 913 | pub struct TestStruct {} |
929 | impl TestTrait for TestStruct { | 914 | impl TestTrait for TestStruct { |
930 | fn test_function() {} | 915 | fn test_function() {} |
931 | } | 916 | } |
932 | } | 917 | } |
933 | ", | 918 | "#, |
934 | ); | 919 | ); |
935 | } | 920 | } |
936 | 921 | ||
@@ -938,23 +923,23 @@ fn main() { | |||
938 | fn private_trait_cross_crate() { | 923 | fn private_trait_cross_crate() { |
939 | check_assist_not_applicable( | 924 | check_assist_not_applicable( |
940 | qualify_path, | 925 | qualify_path, |
941 | r" | 926 | r#" |
942 | //- /main.rs crate:main deps:dep | 927 | //- /main.rs crate:main deps:dep |
943 | fn main() { | 928 | fn main() { |
944 | let test_struct = dep::test_mod::TestStruct {}; | 929 | let test_struct = dep::test_mod::TestStruct {}; |
945 | test_struct.test_meth$0od() | 930 | test_struct.test_meth$0od() |
946 | } | 931 | } |
947 | //- /dep.rs crate:dep | 932 | //- /dep.rs crate:dep |
948 | pub mod test_mod { | 933 | pub mod test_mod { |
949 | trait TestTrait { | 934 | trait TestTrait { |
950 | fn test_method(&self); | 935 | fn test_method(&self); |
951 | } | 936 | } |
952 | pub struct TestStruct {} | 937 | pub struct TestStruct {} |
953 | impl TestTrait for TestStruct { | 938 | impl TestTrait for TestStruct { |
954 | fn test_method(&self) {} | 939 | fn test_method(&self) {} |
955 | } | 940 | } |
956 | } | 941 | } |
957 | ", | 942 | "#, |
958 | ); | 943 | ); |
959 | } | 944 | } |
960 | 945 | ||
@@ -962,32 +947,32 @@ fn main() { | |||
962 | fn not_applicable_for_imported_trait_for_method() { | 947 | fn not_applicable_for_imported_trait_for_method() { |
963 | check_assist_not_applicable( | 948 | check_assist_not_applicable( |
964 | qualify_path, | 949 | qualify_path, |
965 | r" | 950 | r#" |
966 | mod test_mod { | 951 | mod test_mod { |
967 | pub trait TestTrait { | 952 | pub trait TestTrait { |
968 | fn test_method(&self); | 953 | fn test_method(&self); |
969 | } | 954 | } |
970 | pub trait TestTrait2 { | 955 | pub trait TestTrait2 { |
971 | fn test_method(&self); | 956 | fn test_method(&self); |
972 | } | 957 | } |
973 | pub enum TestEnum { | 958 | pub enum TestEnum { |
974 | One, | 959 | One, |
975 | Two, | 960 | Two, |
976 | } | 961 | } |
977 | impl TestTrait2 for TestEnum { | 962 | impl TestTrait2 for TestEnum { |
978 | fn test_method(&self) {} | 963 | fn test_method(&self) {} |
979 | } | 964 | } |
980 | impl TestTrait for TestEnum { | 965 | impl TestTrait for TestEnum { |
981 | fn test_method(&self) {} | 966 | fn test_method(&self) {} |
982 | } | 967 | } |
983 | } | 968 | } |
984 | 969 | ||
985 | use test_mod::TestTrait2; | 970 | use test_mod::TestTrait2; |
986 | fn main() { | 971 | fn main() { |
987 | let one = test_mod::TestEnum::One; | 972 | let one = test_mod::TestEnum::One; |
988 | one.test$0_method(); | 973 | one.test$0_method(); |
989 | } | 974 | } |
990 | ", | 975 | "#, |
991 | ) | 976 | ) |
992 | } | 977 | } |
993 | 978 | ||
@@ -1114,7 +1099,7 @@ fn main() {} | |||
1114 | fn keep_generic_annotations_leading_colon() { | 1099 | fn keep_generic_annotations_leading_colon() { |
1115 | check_assist( | 1100 | check_assist( |
1116 | qualify_path, | 1101 | qualify_path, |
1117 | r" | 1102 | r#" |
1118 | //- /lib.rs crate:dep | 1103 | //- /lib.rs crate:dep |
1119 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | 1104 | pub mod generic { pub struct Thing<'a, T>(&'a T); } |
1120 | 1105 | ||
@@ -1122,7 +1107,7 @@ pub mod generic { pub struct Thing<'a, T>(&'a T); } | |||
1122 | fn foo() -> Thin$0g::<'static, ()> {} | 1107 | fn foo() -> Thin$0g::<'static, ()> {} |
1123 | 1108 | ||
1124 | fn main() {} | 1109 | fn main() {} |
1125 | ", | 1110 | "#, |
1126 | r" | 1111 | r" |
1127 | fn foo() -> dep::generic::Thing::<'static, ()> {} | 1112 | fn foo() -> dep::generic::Thing::<'static, ()> {} |
1128 | 1113 | ||
@@ -1135,30 +1120,30 @@ fn main() {} | |||
1135 | fn associated_struct_const_generic() { | 1120 | fn associated_struct_const_generic() { |
1136 | check_assist( | 1121 | check_assist( |
1137 | qualify_path, | 1122 | qualify_path, |
1138 | r" | 1123 | r#" |
1139 | mod test_mod { | 1124 | mod test_mod { |
1140 | pub struct TestStruct<T> {} | 1125 | pub struct TestStruct<T> {} |
1141 | impl<T> TestStruct<T> { | 1126 | impl<T> TestStruct<T> { |
1142 | const TEST_CONST: u8 = 42; | 1127 | const TEST_CONST: u8 = 42; |
1143 | } | 1128 | } |
1144 | } | 1129 | } |
1145 | 1130 | ||
1146 | fn main() { | 1131 | fn main() { |
1147 | TestStruct::<()>::TEST_CONST$0 | 1132 | TestStruct::<()>::TEST_CONST$0 |
1148 | } | 1133 | } |
1149 | ", | 1134 | "#, |
1150 | r" | 1135 | r#" |
1151 | mod test_mod { | 1136 | mod test_mod { |
1152 | pub struct TestStruct<T> {} | 1137 | pub struct TestStruct<T> {} |
1153 | impl<T> TestStruct<T> { | 1138 | impl<T> TestStruct<T> { |
1154 | const TEST_CONST: u8 = 42; | 1139 | const TEST_CONST: u8 = 42; |
1155 | } | 1140 | } |
1156 | } | 1141 | } |
1157 | 1142 | ||
1158 | fn main() { | 1143 | fn main() { |
1159 | test_mod::TestStruct::<()>::TEST_CONST | 1144 | test_mod::TestStruct::<()>::TEST_CONST |
1160 | } | 1145 | } |
1161 | ", | 1146 | "#, |
1162 | ); | 1147 | ); |
1163 | } | 1148 | } |
1164 | 1149 | ||
@@ -1166,36 +1151,36 @@ fn main() {} | |||
1166 | fn associated_trait_const_generic() { | 1151 | fn associated_trait_const_generic() { |
1167 | check_assist( | 1152 | check_assist( |
1168 | qualify_path, | 1153 | qualify_path, |
1169 | r" | 1154 | r#" |
1170 | mod test_mod { | 1155 | mod test_mod { |
1171 | pub trait TestTrait { | 1156 | pub trait TestTrait { |
1172 | const TEST_CONST: u8; | 1157 | const TEST_CONST: u8; |
1173 | } | 1158 | } |
1174 | pub struct TestStruct<T> {} | 1159 | pub struct TestStruct<T> {} |
1175 | impl<T> TestTrait for TestStruct<T> { | 1160 | impl<T> TestTrait for TestStruct<T> { |
1176 | const TEST_CONST: u8 = 42; | 1161 | const TEST_CONST: u8 = 42; |
1177 | } | 1162 | } |
1178 | } | 1163 | } |
1179 | 1164 | ||
1180 | fn main() { | 1165 | fn main() { |
1181 | test_mod::TestStruct::<()>::TEST_CONST$0 | 1166 | test_mod::TestStruct::<()>::TEST_CONST$0 |
1182 | } | 1167 | } |
1183 | ", | 1168 | "#, |
1184 | r" | 1169 | r#" |
1185 | mod test_mod { | 1170 | mod test_mod { |
1186 | pub trait TestTrait { | 1171 | pub trait TestTrait { |
1187 | const TEST_CONST: u8; | 1172 | const TEST_CONST: u8; |
1188 | } | 1173 | } |
1189 | pub struct TestStruct<T> {} | 1174 | pub struct TestStruct<T> {} |
1190 | impl<T> TestTrait for TestStruct<T> { | 1175 | impl<T> TestTrait for TestStruct<T> { |
1191 | const TEST_CONST: u8 = 42; | 1176 | const TEST_CONST: u8 = 42; |
1192 | } | 1177 | } |
1193 | } | 1178 | } |
1194 | 1179 | ||
1195 | fn main() { | 1180 | fn main() { |
1196 | <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST | 1181 | <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST |
1197 | } | 1182 | } |
1198 | ", | 1183 | "#, |
1199 | ); | 1184 | ); |
1200 | } | 1185 | } |
1201 | 1186 | ||
@@ -1203,38 +1188,38 @@ fn main() {} | |||
1203 | fn trait_method_generic() { | 1188 | fn trait_method_generic() { |
1204 | check_assist( | 1189 | check_assist( |
1205 | qualify_path, | 1190 | qualify_path, |
1206 | r" | 1191 | r#" |
1207 | mod test_mod { | 1192 | mod test_mod { |
1208 | pub trait TestTrait { | 1193 | pub trait TestTrait { |
1209 | fn test_method<T>(&self); | 1194 | fn test_method<T>(&self); |
1210 | } | 1195 | } |
1211 | pub struct TestStruct {} | 1196 | pub struct TestStruct {} |
1212 | impl TestTrait for TestStruct { | 1197 | impl TestTrait for TestStruct { |
1213 | fn test_method<T>(&self) {} | 1198 | fn test_method<T>(&self) {} |
1214 | } | 1199 | } |
1215 | } | 1200 | } |
1216 | 1201 | ||
1217 | fn main() { | 1202 | fn main() { |
1218 | let test_struct = test_mod::TestStruct {}; | 1203 | let test_struct = test_mod::TestStruct {}; |
1219 | test_struct.test_meth$0od::<()>() | 1204 | test_struct.test_meth$0od::<()>() |
1220 | } | 1205 | } |
1221 | ", | 1206 | "#, |
1222 | r" | 1207 | r#" |
1223 | mod test_mod { | 1208 | mod test_mod { |
1224 | pub trait TestTrait { | 1209 | pub trait TestTrait { |
1225 | fn test_method<T>(&self); | 1210 | fn test_method<T>(&self); |
1226 | } | 1211 | } |
1227 | pub struct TestStruct {} | 1212 | pub struct TestStruct {} |
1228 | impl TestTrait for TestStruct { | 1213 | impl TestTrait for TestStruct { |
1229 | fn test_method<T>(&self) {} | 1214 | fn test_method<T>(&self) {} |
1230 | } | 1215 | } |
1231 | } | 1216 | } |
1232 | 1217 | ||
1233 | fn main() { | 1218 | fn main() { |
1234 | let test_struct = test_mod::TestStruct {}; | 1219 | let test_struct = test_mod::TestStruct {}; |
1235 | test_mod::TestTrait::test_method::<()>(&test_struct) | 1220 | test_mod::TestTrait::test_method::<()>(&test_struct) |
1236 | } | 1221 | } |
1237 | ", | 1222 | "#, |
1238 | ); | 1223 | ); |
1239 | } | 1224 | } |
1240 | } | 1225 | } |
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index b20fe992d..5866d8974 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs | |||
@@ -35,14 +35,14 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
35 | .prev_sibling_or_token() | 35 | .prev_sibling_or_token() |
36 | .and_then(whitespace_start) | 36 | .and_then(whitespace_start) |
37 | .map(|start| TextRange::new(start, macro_call.syntax().text_range().end())) | 37 | .map(|start| TextRange::new(start, macro_call.syntax().text_range().end())) |
38 | .unwrap_or(macro_call.syntax().text_range()) | 38 | .unwrap_or_else(|| macro_call.syntax().text_range()) |
39 | }, | 39 | }, |
40 | ast::ExprStmt(it) => { | 40 | ast::ExprStmt(it) => { |
41 | let start = it | 41 | let start = it |
42 | .syntax() | 42 | .syntax() |
43 | .prev_sibling_or_token() | 43 | .prev_sibling_or_token() |
44 | .and_then(whitespace_start) | 44 | .and_then(whitespace_start) |
45 | .unwrap_or(it.syntax().text_range().start()); | 45 | .unwrap_or_else(|| it.syntax().text_range().start()); |
46 | let end = it.syntax().text_range().end(); | 46 | let end = it.syntax().text_range().end(); |
47 | 47 | ||
48 | TextRange::new(start, end) | 48 | TextRange::new(start, end) |
diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs index 50b05ab0b..5f2aa016f 100644 --- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs +++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs | |||
@@ -85,38 +85,48 @@ fn is_ref_and_impls_iter_method( | |||
85 | let krate = scope.module()?.krate(); | 85 | let krate = scope.module()?.krate(); |
86 | let traits_in_scope = scope.traits_in_scope(); | 86 | let traits_in_scope = scope.traits_in_scope(); |
87 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; | 87 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; |
88 | let has_wanted_method = typ.iterate_method_candidates( | 88 | |
89 | sema.db, | 89 | let has_wanted_method = typ |
90 | krate, | 90 | .iterate_method_candidates( |
91 | &traits_in_scope, | 91 | sema.db, |
92 | Some(&wanted_method), | 92 | krate, |
93 | |_, func| { | 93 | &traits_in_scope, |
94 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { | 94 | Some(&wanted_method), |
95 | return Some(()); | 95 | |_, func| { |
96 | } | 96 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { |
97 | None | 97 | return Some(()); |
98 | }, | 98 | } |
99 | ); | 99 | None |
100 | has_wanted_method.and(Some((expr_behind_ref, wanted_method))) | 100 | }, |
101 | ) | ||
102 | .is_some(); | ||
103 | if !has_wanted_method { | ||
104 | return None; | ||
105 | } | ||
106 | |||
107 | Some((expr_behind_ref, wanted_method)) | ||
101 | } | 108 | } |
102 | 109 | ||
103 | /// Whether iterable implements core::Iterator | 110 | /// Whether iterable implements core::Iterator |
104 | fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { | 111 | fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { |
105 | let it_typ = if let Some(i) = sema.type_of_expr(iterable) { | 112 | let it_typ = match sema.type_of_expr(iterable) { |
106 | i | 113 | Some(it) => it, |
107 | } else { | 114 | None => return false, |
108 | return false; | ||
109 | }; | 115 | }; |
110 | let module = if let Some(m) = sema.scope(iterable.syntax()).module() { | 116 | |
111 | m | 117 | let module = match sema.scope(iterable.syntax()).module() { |
112 | } else { | 118 | Some(it) => it, |
113 | return false; | 119 | None => return false, |
114 | }; | 120 | }; |
121 | |||
115 | let krate = module.krate(); | 122 | let krate = module.krate(); |
116 | if let Some(iter_trait) = FamousDefs(sema, Some(krate)).core_iter_Iterator() { | 123 | match FamousDefs(sema, Some(krate)).core_iter_Iterator() { |
117 | return it_typ.impls_trait(sema.db, iter_trait, &[]); | 124 | Some(iter_trait) => { |
125 | cov_mark::hit!(test_already_impls_iterator); | ||
126 | it_typ.impls_trait(sema.db, iter_trait, &[]) | ||
127 | } | ||
128 | None => false, | ||
118 | } | 129 | } |
119 | false | ||
120 | } | 130 | } |
121 | 131 | ||
122 | #[cfg(test)] | 132 | #[cfg(test)] |
@@ -125,33 +135,6 @@ mod tests { | |||
125 | 135 | ||
126 | use super::*; | 136 | use super::*; |
127 | 137 | ||
128 | const EMPTY_ITER_FIXTURE: &'static str = r" | ||
129 | //- /lib.rs deps:core crate:empty_iter | ||
130 | pub struct EmptyIter; | ||
131 | impl Iterator for EmptyIter { | ||
132 | type Item = usize; | ||
133 | fn next(&mut self) -> Option<Self::Item> { None } | ||
134 | } | ||
135 | |||
136 | pub struct Empty; | ||
137 | impl Empty { | ||
138 | pub fn iter(&self) -> EmptyIter { EmptyIter } | ||
139 | pub fn iter_mut(&self) -> EmptyIter { EmptyIter } | ||
140 | } | ||
141 | |||
142 | pub struct NoIterMethod; | ||
143 | "; | ||
144 | |||
145 | fn check_assist_with_fixtures(before: &str, after: &str) { | ||
146 | let before = &format!( | ||
147 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
148 | before, | ||
149 | FamousDefs::FIXTURE, | ||
150 | EMPTY_ITER_FIXTURE | ||
151 | ); | ||
152 | check_assist(replace_for_loop_with_for_each, before, after); | ||
153 | } | ||
154 | |||
155 | #[test] | 138 | #[test] |
156 | fn test_not_for() { | 139 | fn test_not_for() { |
157 | check_assist_not_applicable( | 140 | check_assist_not_applicable( |
@@ -201,33 +184,50 @@ fn main() { | |||
201 | 184 | ||
202 | #[test] | 185 | #[test] |
203 | fn test_for_borrowed() { | 186 | fn test_for_borrowed() { |
204 | check_assist_with_fixtures( | 187 | check_assist( |
205 | r" | 188 | replace_for_loop_with_for_each, |
206 | use empty_iter::*; | 189 | r#" |
190 | //- minicore: iterators | ||
191 | use core::iter::{Repeat, repeat}; | ||
192 | |||
193 | struct S; | ||
194 | impl S { | ||
195 | fn iter(&self) -> Repeat<i32> { repeat(92) } | ||
196 | fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) } | ||
197 | } | ||
198 | |||
207 | fn main() { | 199 | fn main() { |
208 | let x = Empty; | 200 | let x = S; |
209 | for $0v in &x { | 201 | for $0v in &x { |
210 | let a = v * 2; | 202 | let a = v * 2; |
211 | } | 203 | } |
212 | } | 204 | } |
213 | ", | 205 | "#, |
214 | r" | 206 | r#" |
215 | use empty_iter::*; | 207 | use core::iter::{Repeat, repeat}; |
208 | |||
209 | struct S; | ||
210 | impl S { | ||
211 | fn iter(&self) -> Repeat<i32> { repeat(92) } | ||
212 | fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) } | ||
213 | } | ||
214 | |||
216 | fn main() { | 215 | fn main() { |
217 | let x = Empty; | 216 | let x = S; |
218 | x.iter().for_each(|v| { | 217 | x.iter().for_each(|v| { |
219 | let a = v * 2; | 218 | let a = v * 2; |
220 | }); | 219 | }); |
221 | } | 220 | } |
222 | ", | 221 | "#, |
223 | ) | 222 | ) |
224 | } | 223 | } |
225 | 224 | ||
226 | #[test] | 225 | #[test] |
227 | fn test_for_borrowed_no_iter_method() { | 226 | fn test_for_borrowed_no_iter_method() { |
228 | check_assist_with_fixtures( | 227 | check_assist( |
228 | replace_for_loop_with_for_each, | ||
229 | r" | 229 | r" |
230 | use empty_iter::*; | 230 | struct NoIterMethod; |
231 | fn main() { | 231 | fn main() { |
232 | let x = NoIterMethod; | 232 | let x = NoIterMethod; |
233 | for $0v in &x { | 233 | for $0v in &x { |
@@ -236,7 +236,7 @@ fn main() { | |||
236 | } | 236 | } |
237 | ", | 237 | ", |
238 | r" | 238 | r" |
239 | use empty_iter::*; | 239 | struct NoIterMethod; |
240 | fn main() { | 240 | fn main() { |
241 | let x = NoIterMethod; | 241 | let x = NoIterMethod; |
242 | (&x).into_iter().for_each(|v| { | 242 | (&x).into_iter().for_each(|v| { |
@@ -249,25 +249,41 @@ fn main() { | |||
249 | 249 | ||
250 | #[test] | 250 | #[test] |
251 | fn test_for_borrowed_mut() { | 251 | fn test_for_borrowed_mut() { |
252 | check_assist_with_fixtures( | 252 | check_assist( |
253 | r" | 253 | replace_for_loop_with_for_each, |
254 | use empty_iter::*; | 254 | r#" |
255 | //- minicore: iterators | ||
256 | use core::iter::{Repeat, repeat}; | ||
257 | |||
258 | struct S; | ||
259 | impl S { | ||
260 | fn iter(&self) -> Repeat<i32> { repeat(92) } | ||
261 | fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) } | ||
262 | } | ||
263 | |||
255 | fn main() { | 264 | fn main() { |
256 | let x = Empty; | 265 | let x = S; |
257 | for $0v in &mut x { | 266 | for $0v in &mut x { |
258 | let a = v * 2; | 267 | let a = v * 2; |
259 | } | 268 | } |
260 | } | 269 | } |
261 | ", | 270 | "#, |
262 | r" | 271 | r#" |
263 | use empty_iter::*; | 272 | use core::iter::{Repeat, repeat}; |
273 | |||
274 | struct S; | ||
275 | impl S { | ||
276 | fn iter(&self) -> Repeat<i32> { repeat(92) } | ||
277 | fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) } | ||
278 | } | ||
279 | |||
264 | fn main() { | 280 | fn main() { |
265 | let x = Empty; | 281 | let x = S; |
266 | x.iter_mut().for_each(|v| { | 282 | x.iter_mut().for_each(|v| { |
267 | let a = v * 2; | 283 | let a = v * 2; |
268 | }); | 284 | }); |
269 | } | 285 | } |
270 | ", | 286 | "#, |
271 | ) | 287 | ) |
272 | } | 288 | } |
273 | 289 | ||
@@ -296,21 +312,20 @@ fn main() { | |||
296 | 312 | ||
297 | #[test] | 313 | #[test] |
298 | fn test_already_impls_iterator() { | 314 | fn test_already_impls_iterator() { |
299 | check_assist_with_fixtures( | 315 | cov_mark::check!(test_already_impls_iterator); |
316 | check_assist( | ||
317 | replace_for_loop_with_for_each, | ||
300 | r#" | 318 | r#" |
301 | use empty_iter::*; | 319 | //- minicore: iterators |
302 | fn main() { | 320 | fn main() { |
303 | let x = Empty; | 321 | for$0 a in core::iter::repeat(92).take(1) { |
304 | for$0 a in x.iter().take(1) { | ||
305 | println!("{}", a); | 322 | println!("{}", a); |
306 | } | 323 | } |
307 | } | 324 | } |
308 | "#, | 325 | "#, |
309 | r#" | 326 | r#" |
310 | use empty_iter::*; | ||
311 | fn main() { | 327 | fn main() { |
312 | let x = Empty; | 328 | core::iter::repeat(92).take(1).for_each(|a| { |
313 | x.iter().take(1).for_each(|a| { | ||
314 | println!("{}", a); | 329 | println!("{}", a); |
315 | }); | 330 | }); |
316 | } | 331 | } |
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs index 9404aa26d..f37aa0d53 100644 --- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -262,9 +262,7 @@ impl VariantData { | |||
262 | check_assist( | 262 | check_assist( |
263 | replace_if_let_with_match, | 263 | replace_if_let_with_match, |
264 | r#" | 264 | r#" |
265 | enum Option<T> { Some(T), None } | 265 | //- minicore: option |
266 | use Option::*; | ||
267 | |||
268 | fn foo(x: Option<i32>) { | 266 | fn foo(x: Option<i32>) { |
269 | $0if let Some(x) = x { | 267 | $0if let Some(x) = x { |
270 | println!("{}", x) | 268 | println!("{}", x) |
@@ -272,18 +270,15 @@ fn foo(x: Option<i32>) { | |||
272 | println!("none") | 270 | println!("none") |
273 | } | 271 | } |
274 | } | 272 | } |
275 | "#, | 273 | "#, |
276 | r#" | 274 | r#" |
277 | enum Option<T> { Some(T), None } | ||
278 | use Option::*; | ||
279 | |||
280 | fn foo(x: Option<i32>) { | 275 | fn foo(x: Option<i32>) { |
281 | match x { | 276 | match x { |
282 | Some(x) => println!("{}", x), | 277 | Some(x) => println!("{}", x), |
283 | None => println!("none"), | 278 | None => println!("none"), |
284 | } | 279 | } |
285 | } | 280 | } |
286 | "#, | 281 | "#, |
287 | ); | 282 | ); |
288 | } | 283 | } |
289 | 284 | ||
@@ -292,9 +287,7 @@ fn foo(x: Option<i32>) { | |||
292 | check_assist( | 287 | check_assist( |
293 | replace_if_let_with_match, | 288 | replace_if_let_with_match, |
294 | r#" | 289 | r#" |
295 | enum Option<T> { Some(T), None } | 290 | //- minicore: option |
296 | use Option::*; | ||
297 | |||
298 | fn foo(x: Option<i32>) { | 291 | fn foo(x: Option<i32>) { |
299 | $0if let None = x { | 292 | $0if let None = x { |
300 | println!("none") | 293 | println!("none") |
@@ -302,18 +295,15 @@ fn foo(x: Option<i32>) { | |||
302 | println!("some") | 295 | println!("some") |
303 | } | 296 | } |
304 | } | 297 | } |
305 | "#, | 298 | "#, |
306 | r#" | 299 | r#" |
307 | enum Option<T> { Some(T), None } | ||
308 | use Option::*; | ||
309 | |||
310 | fn foo(x: Option<i32>) { | 300 | fn foo(x: Option<i32>) { |
311 | match x { | 301 | match x { |
312 | None => println!("none"), | 302 | None => println!("none"), |
313 | Some(_) => println!("some"), | 303 | Some(_) => println!("some"), |
314 | } | 304 | } |
315 | } | 305 | } |
316 | "#, | 306 | "#, |
317 | ); | 307 | ); |
318 | } | 308 | } |
319 | 309 | ||
@@ -322,9 +312,7 @@ fn foo(x: Option<i32>) { | |||
322 | check_assist( | 312 | check_assist( |
323 | replace_if_let_with_match, | 313 | replace_if_let_with_match, |
324 | r#" | 314 | r#" |
325 | enum Result<T, E> { Ok(T), Err(E) } | 315 | //- minicore: result |
326 | use Result::*; | ||
327 | |||
328 | fn foo(x: Result<i32, ()>) { | 316 | fn foo(x: Result<i32, ()>) { |
329 | $0if let Ok(x) = x { | 317 | $0if let Ok(x) = x { |
330 | println!("{}", x) | 318 | println!("{}", x) |
@@ -332,18 +320,15 @@ fn foo(x: Result<i32, ()>) { | |||
332 | println!("none") | 320 | println!("none") |
333 | } | 321 | } |
334 | } | 322 | } |
335 | "#, | 323 | "#, |
336 | r#" | 324 | r#" |
337 | enum Result<T, E> { Ok(T), Err(E) } | ||
338 | use Result::*; | ||
339 | |||
340 | fn foo(x: Result<i32, ()>) { | 325 | fn foo(x: Result<i32, ()>) { |
341 | match x { | 326 | match x { |
342 | Ok(x) => println!("{}", x), | 327 | Ok(x) => println!("{}", x), |
343 | Err(_) => println!("none"), | 328 | Err(_) => println!("none"), |
344 | } | 329 | } |
345 | } | 330 | } |
346 | "#, | 331 | "#, |
347 | ); | 332 | ); |
348 | } | 333 | } |
349 | 334 | ||
@@ -352,9 +337,7 @@ fn foo(x: Result<i32, ()>) { | |||
352 | check_assist( | 337 | check_assist( |
353 | replace_if_let_with_match, | 338 | replace_if_let_with_match, |
354 | r#" | 339 | r#" |
355 | enum Result<T, E> { Ok(T), Err(E) } | 340 | //- minicore: result |
356 | use Result::*; | ||
357 | |||
358 | fn foo(x: Result<i32, ()>) { | 341 | fn foo(x: Result<i32, ()>) { |
359 | $0if let Err(x) = x { | 342 | $0if let Err(x) = x { |
360 | println!("{}", x) | 343 | println!("{}", x) |
@@ -362,18 +345,15 @@ fn foo(x: Result<i32, ()>) { | |||
362 | println!("ok") | 345 | println!("ok") |
363 | } | 346 | } |
364 | } | 347 | } |
365 | "#, | 348 | "#, |
366 | r#" | 349 | r#" |
367 | enum Result<T, E> { Ok(T), Err(E) } | ||
368 | use Result::*; | ||
369 | |||
370 | fn foo(x: Result<i32, ()>) { | 350 | fn foo(x: Result<i32, ()>) { |
371 | match x { | 351 | match x { |
372 | Err(x) => println!("{}", x), | 352 | Err(x) => println!("{}", x), |
373 | Ok(_) => println!("ok"), | 353 | Ok(_) => println!("ok"), |
374 | } | 354 | } |
375 | } | 355 | } |
376 | "#, | 356 | "#, |
377 | ); | 357 | ); |
378 | } | 358 | } |
379 | 359 | ||
@@ -488,20 +468,15 @@ impl VariantData { | |||
488 | check_assist( | 468 | check_assist( |
489 | replace_match_with_if_let, | 469 | replace_match_with_if_let, |
490 | r#" | 470 | r#" |
491 | enum Option<T> { Some(T), None } | 471 | //- minicore: option |
492 | use Option::*; | ||
493 | |||
494 | fn foo(x: Option<i32>) { | 472 | fn foo(x: Option<i32>) { |
495 | $0match x { | 473 | $0match x { |
496 | Some(x) => println!("{}", x), | 474 | Some(x) => println!("{}", x), |
497 | None => println!("none"), | 475 | None => println!("none"), |
498 | } | 476 | } |
499 | } | 477 | } |
500 | "#, | 478 | "#, |
501 | r#" | 479 | r#" |
502 | enum Option<T> { Some(T), None } | ||
503 | use Option::*; | ||
504 | |||
505 | fn foo(x: Option<i32>) { | 480 | fn foo(x: Option<i32>) { |
506 | if let Some(x) = x { | 481 | if let Some(x) = x { |
507 | println!("{}", x) | 482 | println!("{}", x) |
@@ -509,7 +484,7 @@ fn foo(x: Option<i32>) { | |||
509 | println!("none") | 484 | println!("none") |
510 | } | 485 | } |
511 | } | 486 | } |
512 | "#, | 487 | "#, |
513 | ); | 488 | ); |
514 | } | 489 | } |
515 | 490 | ||
@@ -518,20 +493,15 @@ fn foo(x: Option<i32>) { | |||
518 | check_assist( | 493 | check_assist( |
519 | replace_match_with_if_let, | 494 | replace_match_with_if_let, |
520 | r#" | 495 | r#" |
521 | enum Result<T, E> { Ok(T), Err(E) } | 496 | //- minicore: result |
522 | use Result::*; | ||
523 | |||
524 | fn foo(x: Result<i32, ()>) { | 497 | fn foo(x: Result<i32, ()>) { |
525 | $0match x { | 498 | $0match x { |
526 | Ok(x) => println!("{}", x), | 499 | Ok(x) => println!("{}", x), |
527 | Err(_) => println!("none"), | 500 | Err(_) => println!("none"), |
528 | } | 501 | } |
529 | } | 502 | } |
530 | "#, | 503 | "#, |
531 | r#" | 504 | r#" |
532 | enum Result<T, E> { Ok(T), Err(E) } | ||
533 | use Result::*; | ||
534 | |||
535 | fn foo(x: Result<i32, ()>) { | 505 | fn foo(x: Result<i32, ()>) { |
536 | if let Ok(x) = x { | 506 | if let Ok(x) = x { |
537 | println!("{}", x) | 507 | println!("{}", x) |
@@ -539,7 +509,7 @@ fn foo(x: Result<i32, ()>) { | |||
539 | println!("none") | 509 | println!("none") |
540 | } | 510 | } |
541 | } | 511 | } |
542 | "#, | 512 | "#, |
543 | ); | 513 | ); |
544 | } | 514 | } |
545 | 515 | ||
diff --git a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs index 540a905cc..a2af2035f 100644 --- a/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs +++ b/crates/ide_assists/src/handlers/replace_impl_trait_with_generic.rs | |||
@@ -105,12 +105,13 @@ fn foo<B: Bar | |||
105 | } | 105 | } |
106 | 106 | ||
107 | #[test] | 107 | #[test] |
108 | #[ignore = "This case is very rare but there is no simple solutions to fix it."] | ||
109 | fn replace_impl_trait_with_exist_generic_letter() { | 108 | fn replace_impl_trait_with_exist_generic_letter() { |
109 | // FIXME: This is wrong, we should pick a different name if the one we | ||
110 | // want is already bound. | ||
110 | check_assist( | 111 | check_assist( |
111 | replace_impl_trait_with_generic, | 112 | replace_impl_trait_with_generic, |
112 | r#"fn foo<B>(bar: $0impl Bar) {}"#, | 113 | r#"fn foo<B>(bar: $0impl Bar) {}"#, |
113 | r#"fn foo<B, C: Bar>(bar: C) {}"#, | 114 | r#"fn foo<B, B: Bar>(bar: B) {}"#, |
114 | ); | 115 | ); |
115 | } | 116 | } |
116 | 117 | ||
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs index 39f5eb4ff..26778ee74 100644 --- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -32,7 +32,6 @@ pub(crate) fn replace_qualified_name_with_use( | |||
32 | 32 | ||
33 | let target = path.syntax().text_range(); | 33 | let target = path.syntax().text_range(); |
34 | let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?; | 34 | let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?; |
35 | let syntax = scope.as_syntax_node(); | ||
36 | acc.add( | 35 | acc.add( |
37 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), | 36 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), |
38 | "Replace qualified path with use", | 37 | "Replace qualified path with use", |
@@ -40,11 +39,13 @@ pub(crate) fn replace_qualified_name_with_use( | |||
40 | |builder| { | 39 | |builder| { |
41 | // Now that we've brought the name into scope, re-qualify all paths that could be | 40 | // Now that we've brought the name into scope, re-qualify all paths that could be |
42 | // affected (that is, all paths inside the node we added the `use` to). | 41 | // affected (that is, all paths inside the node we added the `use` to). |
43 | let syntax = builder.make_syntax_mut(syntax.clone()); | 42 | let scope = match scope { |
44 | if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { | 43 | ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), |
45 | shorten_paths(&syntax, &path.clone_for_update()); | 44 | ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), |
46 | insert_use(import_scope, path, ctx.config.insert_use); | 45 | ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), |
47 | } | 46 | }; |
47 | shorten_paths(scope.as_syntax_node(), &path.clone_for_update()); | ||
48 | insert_use(&scope, path, &ctx.config.insert_use); | ||
48 | }, | 49 | }, |
49 | ) | 50 | ) |
50 | } | 51 | } |
diff --git a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs index a3bfa221c..f39c48d8f 100644 --- a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -20,17 +20,16 @@ use ide_db::ty_filter::TryEnum; | |||
20 | // Replaces `unwrap` with a `match` expression. Works for Result and Option. | 20 | // Replaces `unwrap` with a `match` expression. Works for Result and Option. |
21 | // | 21 | // |
22 | // ``` | 22 | // ``` |
23 | // enum Result<T, E> { Ok(T), Err(E) } | 23 | // # //- minicore: result |
24 | // fn main() { | 24 | // fn main() { |
25 | // let x: Result<i32, i32> = Result::Ok(92); | 25 | // let x: Result<i32, i32> = Ok(92); |
26 | // let y = x.$0unwrap(); | 26 | // let y = x.$0unwrap(); |
27 | // } | 27 | // } |
28 | // ``` | 28 | // ``` |
29 | // -> | 29 | // -> |
30 | // ``` | 30 | // ``` |
31 | // enum Result<T, E> { Ok(T), Err(E) } | ||
32 | // fn main() { | 31 | // fn main() { |
33 | // let x: Result<i32, i32> = Result::Ok(92); | 32 | // let x: Result<i32, i32> = Ok(92); |
34 | // let y = match x { | 33 | // let y = match x { |
35 | // Ok(it) => it, | 34 | // Ok(it) => it, |
36 | // $0_ => unreachable!(), | 35 | // $0_ => unreachable!(), |
@@ -97,25 +96,24 @@ mod tests { | |||
97 | fn test_replace_result_unwrap_with_match() { | 96 | fn test_replace_result_unwrap_with_match() { |
98 | check_assist( | 97 | check_assist( |
99 | replace_unwrap_with_match, | 98 | replace_unwrap_with_match, |
100 | r" | 99 | r#" |
101 | enum Result<T, E> { Ok(T), Err(E) } | 100 | //- minicore: result |
102 | fn i<T>(a: T) -> T { a } | 101 | fn i<T>(a: T) -> T { a } |
103 | fn main() { | 102 | fn main() { |
104 | let x: Result<i32, i32> = Result::Ok(92); | 103 | let x: Result<i32, i32> = Ok(92); |
105 | let y = i(x).$0unwrap(); | 104 | let y = i(x).$0unwrap(); |
106 | } | 105 | } |
107 | ", | 106 | "#, |
108 | r" | 107 | r#" |
109 | enum Result<T, E> { Ok(T), Err(E) } | ||
110 | fn i<T>(a: T) -> T { a } | 108 | fn i<T>(a: T) -> T { a } |
111 | fn main() { | 109 | fn main() { |
112 | let x: Result<i32, i32> = Result::Ok(92); | 110 | let x: Result<i32, i32> = Ok(92); |
113 | let y = match i(x) { | 111 | let y = match i(x) { |
114 | Ok(it) => it, | 112 | Ok(it) => it, |
115 | $0_ => unreachable!(), | 113 | $0_ => unreachable!(), |
116 | }; | 114 | }; |
117 | } | 115 | } |
118 | ", | 116 | "#, |
119 | ) | 117 | ) |
120 | } | 118 | } |
121 | 119 | ||
@@ -123,25 +121,24 @@ fn main() { | |||
123 | fn test_replace_option_unwrap_with_match() { | 121 | fn test_replace_option_unwrap_with_match() { |
124 | check_assist( | 122 | check_assist( |
125 | replace_unwrap_with_match, | 123 | replace_unwrap_with_match, |
126 | r" | 124 | r#" |
127 | enum Option<T> { Some(T), None } | 125 | //- minicore: option |
128 | fn i<T>(a: T) -> T { a } | 126 | fn i<T>(a: T) -> T { a } |
129 | fn main() { | 127 | fn main() { |
130 | let x = Option::Some(92); | 128 | let x = Some(92); |
131 | let y = i(x).$0unwrap(); | 129 | let y = i(x).$0unwrap(); |
132 | } | 130 | } |
133 | ", | 131 | "#, |
134 | r" | 132 | r#" |
135 | enum Option<T> { Some(T), None } | ||
136 | fn i<T>(a: T) -> T { a } | 133 | fn i<T>(a: T) -> T { a } |
137 | fn main() { | 134 | fn main() { |
138 | let x = Option::Some(92); | 135 | let x = Some(92); |
139 | let y = match i(x) { | 136 | let y = match i(x) { |
140 | Some(it) => it, | 137 | Some(it) => it, |
141 | $0_ => unreachable!(), | 138 | $0_ => unreachable!(), |
142 | }; | 139 | }; |
143 | } | 140 | } |
144 | ", | 141 | "#, |
145 | ); | 142 | ); |
146 | } | 143 | } |
147 | 144 | ||
@@ -149,25 +146,24 @@ fn main() { | |||
149 | fn test_replace_result_unwrap_with_match_chaining() { | 146 | fn test_replace_result_unwrap_with_match_chaining() { |
150 | check_assist( | 147 | check_assist( |
151 | replace_unwrap_with_match, | 148 | replace_unwrap_with_match, |
152 | r" | 149 | r#" |
153 | enum Result<T, E> { Ok(T), Err(E) } | 150 | //- minicore: result |
154 | fn i<T>(a: T) -> T { a } | 151 | fn i<T>(a: T) -> T { a } |
155 | fn main() { | 152 | fn main() { |
156 | let x: Result<i32, i32> = Result::Ok(92); | 153 | let x: Result<i32, i32> = Ok(92); |
157 | let y = i(x).$0unwrap().count_zeroes(); | 154 | let y = i(x).$0unwrap().count_zeroes(); |
158 | } | 155 | } |
159 | ", | 156 | "#, |
160 | r" | 157 | r#" |
161 | enum Result<T, E> { Ok(T), Err(E) } | ||
162 | fn i<T>(a: T) -> T { a } | 158 | fn i<T>(a: T) -> T { a } |
163 | fn main() { | 159 | fn main() { |
164 | let x: Result<i32, i32> = Result::Ok(92); | 160 | let x: Result<i32, i32> = Ok(92); |
165 | let y = match i(x) { | 161 | let y = match i(x) { |
166 | Ok(it) => it, | 162 | Ok(it) => it, |
167 | $0_ => unreachable!(), | 163 | $0_ => unreachable!(), |
168 | }.count_zeroes(); | 164 | }.count_zeroes(); |
169 | } | 165 | } |
170 | ", | 166 | "#, |
171 | ) | 167 | ) |
172 | } | 168 | } |
173 | 169 | ||
@@ -175,14 +171,14 @@ fn main() { | |||
175 | fn replace_unwrap_with_match_target() { | 171 | fn replace_unwrap_with_match_target() { |
176 | check_assist_target( | 172 | check_assist_target( |
177 | replace_unwrap_with_match, | 173 | replace_unwrap_with_match, |
178 | r" | 174 | r#" |
179 | enum Option<T> { Some(T), None } | 175 | //- minicore: option |
180 | fn i<T>(a: T) -> T { a } | 176 | fn i<T>(a: T) -> T { a } |
181 | fn main() { | 177 | fn main() { |
182 | let x = Option::Some(92); | 178 | let x = Some(92); |
183 | let y = i(x).$0unwrap(); | 179 | let y = i(x).$0unwrap(); |
184 | } | 180 | } |
185 | ", | 181 | "#, |
186 | r"i(x).unwrap()", | 182 | r"i(x).unwrap()", |
187 | ); | 183 | ); |
188 | } | 184 | } |
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs index 8d271e056..14e862cd0 100644 --- a/crates/ide_assists/src/handlers/unmerge_use.rs +++ b/crates/ide_assists/src/handlers/unmerge_use.rs | |||
@@ -73,7 +73,11 @@ fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> { | |||
73 | for path in paths { | 73 | for path in paths { |
74 | final_path = ast::make::path_concat(path, final_path) | 74 | final_path = ast::make::path_concat(path, final_path) |
75 | } | 75 | } |
76 | Some(final_path) | 76 | if final_path.segment().map_or(false, |it| it.self_token().is_some()) { |
77 | final_path.qualifier() | ||
78 | } else { | ||
79 | Some(final_path) | ||
80 | } | ||
77 | } | 81 | } |
78 | 82 | ||
79 | #[cfg(test)] | 83 | #[cfg(test)] |
@@ -223,4 +227,14 @@ pub use std::fmt::Display; | |||
223 | ", | 227 | ", |
224 | ); | 228 | ); |
225 | } | 229 | } |
230 | |||
231 | #[test] | ||
232 | fn unmerge_use_item_on_self() { | ||
233 | check_assist( | ||
234 | unmerge_use, | ||
235 | r"use std::process::{Command, self$0};", | ||
236 | r"use std::process::{Command}; | ||
237 | use std::process;", | ||
238 | ); | ||
239 | } | ||
226 | } | 240 | } |
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 331a6df2b..86a57ce5d 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -15,158 +15,32 @@ mod assist_context; | |||
15 | #[cfg(test)] | 15 | #[cfg(test)] |
16 | mod tests; | 16 | mod tests; |
17 | pub mod utils; | 17 | pub mod utils; |
18 | pub mod path_transform; | ||
19 | |||
20 | use std::str::FromStr; | ||
21 | 18 | ||
22 | use hir::Semantics; | 19 | use hir::Semantics; |
23 | use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; | 20 | use ide_db::{base_db::FileRange, RootDatabase}; |
24 | use syntax::TextRange; | 21 | use syntax::TextRange; |
25 | 22 | ||
26 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 23 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
27 | 24 | ||
28 | pub use assist_config::AssistConfig; | 25 | pub use assist_config::AssistConfig; |
29 | 26 | pub use ide_db::assists::{ | |
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 27 | Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve, |
31 | pub enum AssistKind { | 28 | }; |
32 | // FIXME: does the None variant make sense? Probably not. | 29 | |
33 | None, | 30 | /// Return all the assists applicable at the given position. |
34 | 31 | pub fn assists( | |
35 | QuickFix, | 32 | db: &RootDatabase, |
36 | Generate, | 33 | config: &AssistConfig, |
37 | Refactor, | 34 | resolve: AssistResolveStrategy, |
38 | RefactorExtract, | 35 | range: FileRange, |
39 | RefactorInline, | 36 | ) -> Vec<Assist> { |
40 | RefactorRewrite, | 37 | let sema = Semantics::new(db); |
41 | } | 38 | let ctx = AssistContext::new(sema, config, range); |
42 | 39 | let mut acc = Assists::new(&ctx, resolve); | |
43 | impl AssistKind { | 40 | handlers::all().iter().for_each(|handler| { |
44 | pub fn contains(self, other: AssistKind) -> bool { | 41 | handler(&mut acc, &ctx); |
45 | if self == other { | 42 | }); |
46 | return true; | 43 | acc.finish() |
47 | } | ||
48 | |||
49 | match self { | ||
50 | AssistKind::None | AssistKind::Generate => true, | ||
51 | AssistKind::Refactor => match other { | ||
52 | AssistKind::RefactorExtract | ||
53 | | AssistKind::RefactorInline | ||
54 | | AssistKind::RefactorRewrite => true, | ||
55 | _ => false, | ||
56 | }, | ||
57 | _ => false, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub fn name(&self) -> &str { | ||
62 | match self { | ||
63 | AssistKind::None => "None", | ||
64 | AssistKind::QuickFix => "QuickFix", | ||
65 | AssistKind::Generate => "Generate", | ||
66 | AssistKind::Refactor => "Refactor", | ||
67 | AssistKind::RefactorExtract => "RefactorExtract", | ||
68 | AssistKind::RefactorInline => "RefactorInline", | ||
69 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl FromStr for AssistKind { | ||
75 | type Err = String; | ||
76 | |||
77 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
78 | match s { | ||
79 | "None" => Ok(AssistKind::None), | ||
80 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
81 | "Generate" => Ok(AssistKind::Generate), | ||
82 | "Refactor" => Ok(AssistKind::Refactor), | ||
83 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
84 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
85 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
86 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /// Unique identifier of the assist, should not be shown to the user | ||
92 | /// directly. | ||
93 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
94 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
95 | |||
96 | /// A way to control how many asssist to resolve during the assist resolution. | ||
97 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
98 | #[derive(Debug)] | ||
99 | pub enum AssistResolveStrategy { | ||
100 | /// No assists should be resolved. | ||
101 | None, | ||
102 | /// All assists should be resolved. | ||
103 | All, | ||
104 | /// Only a certain assist should be resolved. | ||
105 | Single(SingleResolve), | ||
106 | } | ||
107 | |||
108 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
109 | /// The original id object cannot be used due to a `'static` lifetime | ||
110 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
111 | #[derive(Debug)] | ||
112 | pub struct SingleResolve { | ||
113 | /// The id of the assist. | ||
114 | pub assist_id: String, | ||
115 | // The kind of the assist. | ||
116 | pub assist_kind: AssistKind, | ||
117 | } | ||
118 | |||
119 | impl AssistResolveStrategy { | ||
120 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
121 | match self { | ||
122 | AssistResolveStrategy::None => false, | ||
123 | AssistResolveStrategy::All => true, | ||
124 | AssistResolveStrategy::Single(single_resolve) => { | ||
125 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Clone, Debug)] | ||
132 | pub struct GroupLabel(pub String); | ||
133 | |||
134 | #[derive(Debug, Clone)] | ||
135 | pub struct Assist { | ||
136 | pub id: AssistId, | ||
137 | /// Short description of the assist, as shown in the UI. | ||
138 | pub label: Label, | ||
139 | pub group: Option<GroupLabel>, | ||
140 | /// Target ranges are used to sort assists: the smaller the target range, | ||
141 | /// the more specific assist is, and so it should be sorted first. | ||
142 | pub target: TextRange, | ||
143 | /// Computing source change sometimes is much more costly then computing the | ||
144 | /// other fields. Additionally, the actual change is not required to show | ||
145 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
146 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
147 | /// or without source change. We could (and in fact, used to) distinguish | ||
148 | /// between resolved and unresolved assists at the type level, but this is | ||
149 | /// cumbersome, especially if you want to embed an assist into another data | ||
150 | /// structure, such as a diagnostic. | ||
151 | pub source_change: Option<SourceChange>, | ||
152 | } | ||
153 | |||
154 | impl Assist { | ||
155 | /// Return all the assists applicable at the given position. | ||
156 | pub fn get( | ||
157 | db: &RootDatabase, | ||
158 | config: &AssistConfig, | ||
159 | resolve: AssistResolveStrategy, | ||
160 | range: FileRange, | ||
161 | ) -> Vec<Assist> { | ||
162 | let sema = Semantics::new(db); | ||
163 | let ctx = AssistContext::new(sema, config, range); | ||
164 | let mut acc = Assists::new(&ctx, resolve); | ||
165 | handlers::all().iter().for_each(|handler| { | ||
166 | handler(&mut acc, &ctx); | ||
167 | }); | ||
168 | acc.finish() | ||
169 | } | ||
170 | } | 44 | } |
171 | 45 | ||
172 | mod handlers { | 46 | mod handlers { |
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index bdf9cb71c..841537c77 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -16,8 +16,8 @@ use syntax::TextRange; | |||
16 | use test_utils::{assert_eq_text, extract_offset}; | 16 | use test_utils::{assert_eq_text, extract_offset}; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, AssistResolveStrategy, | 19 | assists, handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, |
20 | Assists, SingleResolve, | 20 | AssistResolveStrategy, Assists, SingleResolve, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | 23 | pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { |
@@ -28,6 +28,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | |||
28 | prefix_kind: hir::PrefixKind::Plain, | 28 | prefix_kind: hir::PrefixKind::Plain, |
29 | enforce_granularity: true, | 29 | enforce_granularity: true, |
30 | group: true, | 30 | group: true, |
31 | skip_glob_imports: true, | ||
31 | }, | 32 | }, |
32 | }; | 33 | }; |
33 | 34 | ||
@@ -35,6 +36,7 @@ pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | |||
35 | RootDatabase::with_single_file(text) | 36 | RootDatabase::with_single_file(text) |
36 | } | 37 | } |
37 | 38 | ||
39 | #[track_caller] | ||
38 | pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { | 40 | pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { |
39 | let ra_fixture_after = trim_indent(ra_fixture_after); | 41 | let ra_fixture_after = trim_indent(ra_fixture_after); |
40 | check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None); | 42 | check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None); |
@@ -78,14 +80,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
78 | let before = db.file_text(file_id).to_string(); | 80 | let before = db.file_text(file_id).to_string(); |
79 | let frange = FileRange { file_id, range: selection.into() }; | 81 | let frange = FileRange { file_id, range: selection.into() }; |
80 | 82 | ||
81 | let assist = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange) | 83 | let assist = assists(&db, &TEST_CONFIG, AssistResolveStrategy::All, frange) |
82 | .into_iter() | 84 | .into_iter() |
83 | .find(|assist| assist.id.0 == assist_id) | 85 | .find(|assist| assist.id.0 == assist_id) |
84 | .unwrap_or_else(|| { | 86 | .unwrap_or_else(|| { |
85 | panic!( | 87 | panic!( |
86 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 88 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
87 | assist_id, | 89 | assist_id, |
88 | Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange) | 90 | assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange) |
89 | .into_iter() | 91 | .into_iter() |
90 | .map(|assist| assist.id.0) | 92 | .map(|assist| assist.id.0) |
91 | .collect::<Vec<_>>() | 93 | .collect::<Vec<_>>() |
@@ -179,9 +181,10 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
179 | "unresolved assist should not contain source changes" | 181 | "unresolved assist should not contain source changes" |
180 | ), | 182 | ), |
181 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 183 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
182 | (None, ExpectedResult::After(_)) | 184 | ( |
183 | | (None, ExpectedResult::Target(_)) | 185 | None, |
184 | | (None, ExpectedResult::Unresolved) => { | 186 | ExpectedResult::After(_) | ExpectedResult::Target(_) | ExpectedResult::Unresolved, |
187 | ) => { | ||
185 | panic!("code action is not applicable") | 188 | panic!("code action is not applicable") |
186 | } | 189 | } |
187 | (None, ExpectedResult::NotApplicable) => (), | 190 | (None, ExpectedResult::NotApplicable) => (), |
@@ -210,7 +213,7 @@ fn assist_order_field_struct() { | |||
210 | let (before_cursor_pos, before) = extract_offset(before); | 213 | let (before_cursor_pos, before) = extract_offset(before); |
211 | let (db, file_id) = with_single_file(&before); | 214 | let (db, file_id) = with_single_file(&before); |
212 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; | 215 | let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; |
213 | let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); | 216 | let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); |
214 | let mut assists = assists.iter(); | 217 | let mut assists = assists.iter(); |
215 | 218 | ||
216 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); | 219 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); |
@@ -235,7 +238,7 @@ pub fn test_some_range(a: int) -> bool { | |||
235 | "#, | 238 | "#, |
236 | ); | 239 | ); |
237 | 240 | ||
238 | let assists = Assist::get(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); | 241 | let assists = assists(&db, &TEST_CONFIG, AssistResolveStrategy::None, frange); |
239 | let expected = labels(&assists); | 242 | let expected = labels(&assists); |
240 | 243 | ||
241 | expect![[r#" | 244 | expect![[r#" |
@@ -264,7 +267,7 @@ pub fn test_some_range(a: int) -> bool { | |||
264 | let mut cfg = TEST_CONFIG; | 267 | let mut cfg = TEST_CONFIG; |
265 | cfg.allowed = Some(vec![AssistKind::Refactor]); | 268 | cfg.allowed = Some(vec![AssistKind::Refactor]); |
266 | 269 | ||
267 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 270 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
268 | let expected = labels(&assists); | 271 | let expected = labels(&assists); |
269 | 272 | ||
270 | expect![[r#" | 273 | expect![[r#" |
@@ -279,7 +282,7 @@ pub fn test_some_range(a: int) -> bool { | |||
279 | { | 282 | { |
280 | let mut cfg = TEST_CONFIG; | 283 | let mut cfg = TEST_CONFIG; |
281 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 284 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
282 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 285 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
283 | let expected = labels(&assists); | 286 | let expected = labels(&assists); |
284 | 287 | ||
285 | expect![[r#" | 288 | expect![[r#" |
@@ -292,7 +295,7 @@ pub fn test_some_range(a: int) -> bool { | |||
292 | { | 295 | { |
293 | let mut cfg = TEST_CONFIG; | 296 | let mut cfg = TEST_CONFIG; |
294 | cfg.allowed = Some(vec![AssistKind::QuickFix]); | 297 | cfg.allowed = Some(vec![AssistKind::QuickFix]); |
295 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 298 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
296 | let expected = labels(&assists); | 299 | let expected = labels(&assists); |
297 | 300 | ||
298 | expect![[r#""#]].assert_eq(&expected); | 301 | expect![[r#""#]].assert_eq(&expected); |
@@ -317,7 +320,7 @@ pub fn test_some_range(a: int) -> bool { | |||
317 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | 320 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); |
318 | 321 | ||
319 | { | 322 | { |
320 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::None, frange); | 323 | let assists = assists(&db, &cfg, AssistResolveStrategy::None, frange); |
321 | assert_eq!(2, assists.len()); | 324 | assert_eq!(2, assists.len()); |
322 | let mut assists = assists.into_iter(); | 325 | let mut assists = assists.into_iter(); |
323 | 326 | ||
@@ -353,7 +356,7 @@ pub fn test_some_range(a: int) -> bool { | |||
353 | } | 356 | } |
354 | 357 | ||
355 | { | 358 | { |
356 | let assists = Assist::get( | 359 | let assists = assists( |
357 | &db, | 360 | &db, |
358 | &cfg, | 361 | &cfg, |
359 | AssistResolveStrategy::Single(SingleResolve { | 362 | AssistResolveStrategy::Single(SingleResolve { |
@@ -397,7 +400,7 @@ pub fn test_some_range(a: int) -> bool { | |||
397 | } | 400 | } |
398 | 401 | ||
399 | { | 402 | { |
400 | let assists = Assist::get( | 403 | let assists = assists( |
401 | &db, | 404 | &db, |
402 | &cfg, | 405 | &cfg, |
403 | AssistResolveStrategy::Single(SingleResolve { | 406 | AssistResolveStrategy::Single(SingleResolve { |
@@ -462,7 +465,7 @@ pub fn test_some_range(a: int) -> bool { | |||
462 | } | 465 | } |
463 | 466 | ||
464 | { | 467 | { |
465 | let assists = Assist::get(&db, &cfg, AssistResolveStrategy::All, frange); | 468 | let assists = assists(&db, &cfg, AssistResolveStrategy::All, frange); |
466 | assert_eq!(2, assists.len()); | 469 | assert_eq!(2, assists.len()); |
467 | let mut assists = assists.into_iter(); | 470 | let mut assists = assists.into_iter(); |
468 | 471 | ||
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index de5d9e55a..1509c3c63 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -209,10 +209,7 @@ fn doctest_convert_into_to_from() { | |||
209 | check_doc_test( | 209 | check_doc_test( |
210 | "convert_into_to_from", | 210 | "convert_into_to_from", |
211 | r#####" | 211 | r#####" |
212 | //- /lib.rs crate:core | 212 | //- minicore: from |
213 | pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } } | ||
214 | //- /lib.rs crate:main deps:core | ||
215 | use core::convert::Into; | ||
216 | impl $0Into<Thing> for usize { | 213 | impl $0Into<Thing> for usize { |
217 | fn into(self) -> Thing { | 214 | fn into(self) -> Thing { |
218 | Thing { | 215 | Thing { |
@@ -223,7 +220,6 @@ impl $0Into<Thing> for usize { | |||
223 | } | 220 | } |
224 | "#####, | 221 | "#####, |
225 | r#####" | 222 | r#####" |
226 | use core::convert::Into; | ||
227 | impl From<usize> for Thing { | 223 | impl From<usize> for Thing { |
228 | fn from(val: usize) -> Self { | 224 | fn from(val: usize) -> Self { |
229 | Thing { | 225 | Thing { |
@@ -241,23 +237,19 @@ fn doctest_convert_iter_for_each_to_for() { | |||
241 | check_doc_test( | 237 | check_doc_test( |
242 | "convert_iter_for_each_to_for", | 238 | "convert_iter_for_each_to_for", |
243 | r#####" | 239 | r#####" |
244 | //- /lib.rs crate:core | 240 | //- minicore: iterators |
245 | pub mod iter { pub mod traits { pub mod iterator { pub trait Iterator {} } } } | 241 | use core::iter; |
246 | pub struct SomeIter; | ||
247 | impl self::iter::traits::iterator::Iterator for SomeIter {} | ||
248 | //- /lib.rs crate:main deps:core | ||
249 | use core::SomeIter; | ||
250 | fn main() { | 242 | fn main() { |
251 | let iter = SomeIter; | 243 | let iter = iter::repeat((9, 2)); |
252 | iter.for_each$0(|(x, y)| { | 244 | iter.for_each$0(|(x, y)| { |
253 | println!("x: {}, y: {}", x, y); | 245 | println!("x: {}, y: {}", x, y); |
254 | }); | 246 | }); |
255 | } | 247 | } |
256 | "#####, | 248 | "#####, |
257 | r#####" | 249 | r#####" |
258 | use core::SomeIter; | 250 | use core::iter; |
259 | fn main() { | 251 | fn main() { |
260 | let iter = SomeIter; | 252 | let iter = iter::repeat((9, 2)); |
261 | for (x, y) in iter { | 253 | for (x, y) in iter { |
262 | println!("x: {}, y: {}", x, y); | 254 | println!("x: {}, y: {}", x, y); |
263 | } | 255 | } |
@@ -1519,16 +1511,15 @@ fn doctest_replace_unwrap_with_match() { | |||
1519 | check_doc_test( | 1511 | check_doc_test( |
1520 | "replace_unwrap_with_match", | 1512 | "replace_unwrap_with_match", |
1521 | r#####" | 1513 | r#####" |
1522 | enum Result<T, E> { Ok(T), Err(E) } | 1514 | //- minicore: result |
1523 | fn main() { | 1515 | fn main() { |
1524 | let x: Result<i32, i32> = Result::Ok(92); | 1516 | let x: Result<i32, i32> = Ok(92); |
1525 | let y = x.$0unwrap(); | 1517 | let y = x.$0unwrap(); |
1526 | } | 1518 | } |
1527 | "#####, | 1519 | "#####, |
1528 | r#####" | 1520 | r#####" |
1529 | enum Result<T, E> { Ok(T), Err(E) } | ||
1530 | fn main() { | 1521 | fn main() { |
1531 | let x: Result<i32, i32> = Result::Ok(92); | 1522 | let x: Result<i32, i32> = Ok(92); |
1532 | let y = match x { | 1523 | let y = match x { |
1533 | Ok(it) => it, | 1524 | Ok(it) => it, |
1534 | $0_ => unreachable!(), | 1525 | $0_ => unreachable!(), |
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs index 068df005b..0ec236aa0 100644 --- a/crates/ide_assists/src/utils.rs +++ b/crates/ide_assists/src/utils.rs | |||
@@ -8,6 +8,7 @@ use ast::TypeBoundsOwner; | |||
8 | use hir::{Adt, HasSource, Semantics}; | 8 | use hir::{Adt, HasSource, Semantics}; |
9 | use ide_db::{ | 9 | use ide_db::{ |
10 | helpers::{FamousDefs, SnippetCap}, | 10 | helpers::{FamousDefs, SnippetCap}, |
11 | path_transform::PathTransform, | ||
11 | RootDatabase, | 12 | RootDatabase, |
12 | }; | 13 | }; |
13 | use itertools::Itertools; | 14 | use itertools::Itertools; |
@@ -22,10 +23,7 @@ use syntax::{ | |||
22 | SyntaxNode, TextSize, T, | 23 | SyntaxNode, TextSize, T, |
23 | }; | 24 | }; |
24 | 25 | ||
25 | use crate::{ | 26 | use crate::assist_context::{AssistBuilder, AssistContext}; |
26 | assist_context::{AssistBuilder, AssistContext}, | ||
27 | path_transform::PathTransform, | ||
28 | }; | ||
29 | 27 | ||
30 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | 28 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { |
31 | extract_trivial_expression(&block) | 29 | extract_trivial_expression(&block) |
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index bd90cefb2..cba5eb0c6 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -41,9 +41,9 @@ pub struct Completions { | |||
41 | buf: Vec<CompletionItem>, | 41 | buf: Vec<CompletionItem>, |
42 | } | 42 | } |
43 | 43 | ||
44 | impl Into<Vec<CompletionItem>> for Completions { | 44 | impl From<Completions> for Vec<CompletionItem> { |
45 | fn into(self) -> Vec<CompletionItem> { | 45 | fn from(val: Completions) -> Self { |
46 | self.buf | 46 | val.buf |
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
@@ -74,44 +74,12 @@ impl Completions { | |||
74 | items.into_iter().for_each(|item| self.add(item.into())) | 74 | items.into_iter().for_each(|item| self.add(item.into())) |
75 | } | 75 | } |
76 | 76 | ||
77 | pub(crate) fn add_field( | ||
78 | &mut self, | ||
79 | ctx: &CompletionContext, | ||
80 | receiver: Option<hir::Name>, | ||
81 | field: hir::Field, | ||
82 | ty: &hir::Type, | ||
83 | ) { | ||
84 | let item = render_field(RenderContext::new(ctx), receiver, field, ty); | ||
85 | self.add(item); | ||
86 | } | ||
87 | |||
88 | pub(crate) fn add_tuple_field( | ||
89 | &mut self, | ||
90 | ctx: &CompletionContext, | ||
91 | receiver: Option<hir::Name>, | ||
92 | field: usize, | ||
93 | ty: &hir::Type, | ||
94 | ) { | ||
95 | let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); | ||
96 | self.add(item); | ||
97 | } | ||
98 | |||
99 | pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { | ||
100 | let mut item = | ||
101 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); | ||
102 | item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); | ||
103 | self.add(item.build()); | ||
104 | } | ||
105 | |||
106 | pub(crate) fn add_resolution( | 77 | pub(crate) fn add_resolution( |
107 | &mut self, | 78 | &mut self, |
108 | ctx: &CompletionContext, | 79 | ctx: &CompletionContext, |
109 | local_name: hir::Name, | 80 | local_name: hir::Name, |
110 | resolution: &hir::ScopeDef, | 81 | resolution: &hir::ScopeDef, |
111 | ) { | 82 | ) { |
112 | if ctx.expects_type() && resolution.is_value_def() { | ||
113 | return; | ||
114 | } | ||
115 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); | 83 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); |
116 | } | 84 | } |
117 | 85 | ||
@@ -134,9 +102,6 @@ impl Completions { | |||
134 | func: hir::Function, | 102 | func: hir::Function, |
135 | local_name: Option<hir::Name>, | 103 | local_name: Option<hir::Name>, |
136 | ) { | 104 | ) { |
137 | if ctx.expects_type() { | ||
138 | return; | ||
139 | } | ||
140 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); | 105 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); |
141 | } | 106 | } |
142 | 107 | ||
@@ -150,94 +115,119 @@ impl Completions { | |||
150 | self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); | 115 | self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func)); |
151 | } | 116 | } |
152 | 117 | ||
153 | pub(crate) fn add_variant_pat( | 118 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
119 | self.add_opt(render_const(RenderContext::new(ctx), constant)); | ||
120 | } | ||
121 | |||
122 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | ||
123 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | ||
124 | } | ||
125 | |||
126 | pub(crate) fn add_type_alias_with_eq( | ||
154 | &mut self, | 127 | &mut self, |
155 | ctx: &CompletionContext, | 128 | ctx: &CompletionContext, |
156 | variant: hir::Variant, | 129 | type_alias: hir::TypeAlias, |
157 | local_name: Option<hir::Name>, | ||
158 | ) { | 130 | ) { |
159 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); | 131 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); |
160 | } | 132 | } |
161 | 133 | ||
162 | pub(crate) fn add_qualified_variant_pat( | 134 | pub(crate) fn add_qualified_enum_variant( |
163 | &mut self, | 135 | &mut self, |
164 | ctx: &CompletionContext, | 136 | ctx: &CompletionContext, |
165 | variant: hir::Variant, | 137 | variant: hir::Variant, |
166 | path: hir::ModPath, | 138 | path: hir::ModPath, |
167 | ) { | 139 | ) { |
168 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); | 140 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); |
141 | self.add(item); | ||
169 | } | 142 | } |
170 | 143 | ||
171 | pub(crate) fn add_struct_pat( | 144 | pub(crate) fn add_enum_variant( |
172 | &mut self, | 145 | &mut self, |
173 | ctx: &CompletionContext, | 146 | ctx: &CompletionContext, |
174 | strukt: hir::Struct, | 147 | variant: hir::Variant, |
175 | local_name: Option<hir::Name>, | 148 | local_name: Option<hir::Name>, |
176 | ) { | 149 | ) { |
177 | self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); | 150 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); |
151 | self.add(item); | ||
178 | } | 152 | } |
179 | 153 | ||
180 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 154 | pub(crate) fn add_field( |
181 | if ctx.expects_type() { | 155 | &mut self, |
182 | return; | 156 | ctx: &CompletionContext, |
183 | } | 157 | receiver: Option<hir::Name>, |
184 | self.add_opt(render_const(RenderContext::new(ctx), constant)); | 158 | field: hir::Field, |
159 | ty: &hir::Type, | ||
160 | ) { | ||
161 | let item = render_field(RenderContext::new(ctx), receiver, field, ty); | ||
162 | self.add(item); | ||
185 | } | 163 | } |
186 | 164 | ||
187 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | 165 | pub(crate) fn add_tuple_field( |
188 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | 166 | &mut self, |
167 | ctx: &CompletionContext, | ||
168 | receiver: Option<hir::Name>, | ||
169 | field: usize, | ||
170 | ty: &hir::Type, | ||
171 | ) { | ||
172 | let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty); | ||
173 | self.add(item); | ||
189 | } | 174 | } |
190 | 175 | ||
191 | pub(crate) fn add_type_alias_with_eq( | 176 | pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { |
177 | let mut item = | ||
178 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), "'static"); | ||
179 | item.kind(CompletionItemKind::SymbolKind(SymbolKind::LifetimeParam)); | ||
180 | self.add(item.build()); | ||
181 | } | ||
182 | |||
183 | pub(crate) fn add_variant_pat( | ||
192 | &mut self, | 184 | &mut self, |
193 | ctx: &CompletionContext, | 185 | ctx: &CompletionContext, |
194 | type_alias: hir::TypeAlias, | 186 | variant: hir::Variant, |
187 | local_name: Option<hir::Name>, | ||
195 | ) { | 188 | ) { |
196 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); | 189 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None)); |
197 | } | 190 | } |
198 | 191 | ||
199 | pub(crate) fn add_qualified_enum_variant( | 192 | pub(crate) fn add_qualified_variant_pat( |
200 | &mut self, | 193 | &mut self, |
201 | ctx: &CompletionContext, | 194 | ctx: &CompletionContext, |
202 | variant: hir::Variant, | 195 | variant: hir::Variant, |
203 | path: hir::ModPath, | 196 | path: hir::ModPath, |
204 | ) { | 197 | ) { |
205 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); | 198 | self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path))); |
206 | self.add(item); | ||
207 | } | 199 | } |
208 | 200 | ||
209 | pub(crate) fn add_enum_variant( | 201 | pub(crate) fn add_struct_pat( |
210 | &mut self, | 202 | &mut self, |
211 | ctx: &CompletionContext, | 203 | ctx: &CompletionContext, |
212 | variant: hir::Variant, | 204 | strukt: hir::Struct, |
213 | local_name: Option<hir::Name>, | 205 | local_name: Option<hir::Name>, |
214 | ) { | 206 | ) { |
215 | if ctx.expects_type() { | 207 | self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name)); |
216 | return; | ||
217 | } | ||
218 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); | ||
219 | self.add(item); | ||
220 | } | 208 | } |
221 | } | 209 | } |
222 | 210 | ||
223 | fn complete_enum_variants( | 211 | /// Calls the callback for each variant of the provided enum with the path to the variant. |
212 | /// Skips variants that are visible with single segment paths. | ||
213 | fn enum_variants_with_paths( | ||
224 | acc: &mut Completions, | 214 | acc: &mut Completions, |
225 | ctx: &CompletionContext, | 215 | ctx: &CompletionContext, |
226 | enum_data: hir::Enum, | 216 | enum_: hir::Enum, |
227 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), | 217 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), |
228 | ) { | 218 | ) { |
229 | let variants = enum_data.variants(ctx.db); | 219 | let variants = enum_.variants(ctx.db); |
230 | 220 | ||
231 | let module = if let Some(module) = ctx.scope.module() { | 221 | let module = if let Some(module) = ctx.scope.module() { |
232 | // Compute path from the completion site if available. | 222 | // Compute path from the completion site if available. |
233 | module | 223 | module |
234 | } else { | 224 | } else { |
235 | // Otherwise fall back to the enum's definition site. | 225 | // Otherwise fall back to the enum's definition site. |
236 | enum_data.module(ctx.db) | 226 | enum_.module(ctx.db) |
237 | }; | 227 | }; |
238 | 228 | ||
239 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 229 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
240 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_data)) { | 230 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { |
241 | for &variant in &variants { | 231 | for &variant in &variants { |
242 | let self_path = hir::ModPath::from_segments( | 232 | let self_path = hir::ModPath::from_segments( |
243 | hir::PathKind::Plain, | 233 | hir::PathKind::Plain, |
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 6df569c2a..78fc30e16 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -17,12 +17,14 @@ use crate::{ | |||
17 | 17 | ||
18 | mod derive; | 18 | mod derive; |
19 | mod lint; | 19 | mod lint; |
20 | mod repr; | ||
20 | 21 | ||
21 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 22 | pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
22 | let attribute = ctx.attribute_under_caret.as_ref()?; | 23 | let attribute = ctx.attribute_under_caret.as_ref()?; |
23 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { | 24 | match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { |
24 | (Some(path), Some(token_tree)) => match path.text().as_str() { | 25 | (Some(path), Some(token_tree)) => match path.text().as_str() { |
25 | "derive" => derive::complete_derive(acc, ctx, token_tree), | 26 | "derive" => derive::complete_derive(acc, ctx, token_tree), |
27 | "repr" => repr::complete_repr(acc, ctx, token_tree), | ||
26 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), | 28 | "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), |
27 | "allow" | "warn" | "deny" | "forbid" => { | 29 | "allow" | "warn" | "deny" | "forbid" => { |
28 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); | 30 | lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); |
@@ -322,7 +324,7 @@ mod tests { | |||
322 | 324 | ||
323 | use expect_test::{expect, Expect}; | 325 | use expect_test::{expect, Expect}; |
324 | 326 | ||
325 | use crate::{test_utils::completion_list, CompletionKind}; | 327 | use crate::tests::completion_list; |
326 | 328 | ||
327 | #[test] | 329 | #[test] |
328 | fn attributes_are_sorted() { | 330 | fn attributes_are_sorted() { |
@@ -341,7 +343,7 @@ mod tests { | |||
341 | } | 343 | } |
342 | 344 | ||
343 | fn check(ra_fixture: &str, expect: Expect) { | 345 | fn check(ra_fixture: &str, expect: Expect) { |
344 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | 346 | let actual = completion_list(ra_fixture); |
345 | expect.assert_eq(&actual); | 347 | expect.assert_eq(&actual); |
346 | } | 348 | } |
347 | 349 | ||
@@ -792,6 +794,7 @@ mod tests { | |||
792 | 794 | ||
793 | #[test] | 795 | #[test] |
794 | fn complete_attribute_on_expr() { | 796 | fn complete_attribute_on_expr() { |
797 | cov_mark::check!(no_keyword_completion_in_attr_of_expr); | ||
795 | check( | 798 | check( |
796 | r#"fn main() { #[$0] foo() }"#, | 799 | r#"fn main() { #[$0] foo() }"#, |
797 | expect![[r#" | 800 | expect![[r#" |
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index d526824fb..6fe41e0d6 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -31,6 +31,8 @@ pub(super) fn complete_derive( | |||
31 | let lookup = components.join(", "); | 31 | let lookup = components.join(", "); |
32 | let label = components.iter().rev().join(", "); | 32 | let label = components.iter().rev().join(", "); |
33 | (label, Some(lookup)) | 33 | (label, Some(lookup)) |
34 | } else if existing_derives.contains(&derive) { | ||
35 | continue; | ||
34 | } else { | 36 | } else { |
35 | (derive, None) | 37 | (derive, None) |
36 | }; | 38 | }; |
@@ -80,10 +82,31 @@ const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ | |||
80 | mod tests { | 82 | mod tests { |
81 | use expect_test::{expect, Expect}; | 83 | use expect_test::{expect, Expect}; |
82 | 84 | ||
83 | use crate::{test_utils::completion_list, CompletionKind}; | 85 | use crate::tests::completion_list; |
84 | 86 | ||
85 | fn check(ra_fixture: &str, expect: Expect) { | 87 | fn check(ra_fixture: &str, expect: Expect) { |
86 | let actual = completion_list(ra_fixture, CompletionKind::Attribute); | 88 | let builtin_derives = r#" |
89 | #[rustc_builtin_macro] | ||
90 | pub macro Clone {} | ||
91 | #[rustc_builtin_macro] | ||
92 | pub macro Copy {} | ||
93 | #[rustc_builtin_macro] | ||
94 | pub macro Default {} | ||
95 | #[rustc_builtin_macro] | ||
96 | pub macro Debug {} | ||
97 | #[rustc_builtin_macro] | ||
98 | pub macro Hash {} | ||
99 | #[rustc_builtin_macro] | ||
100 | pub macro PartialEq {} | ||
101 | #[rustc_builtin_macro] | ||
102 | pub macro Eq {} | ||
103 | #[rustc_builtin_macro] | ||
104 | pub macro PartialOrd {} | ||
105 | #[rustc_builtin_macro] | ||
106 | pub macro Ord {} | ||
107 | |||
108 | "#; | ||
109 | let actual = completion_list(&format!("{} {}", builtin_derives, ra_fixture)); | ||
87 | expect.assert_eq(&actual); | 110 | expect.assert_eq(&actual); |
88 | } | 111 | } |
89 | 112 | ||
@@ -93,56 +116,53 @@ mod tests { | |||
93 | } | 116 | } |
94 | 117 | ||
95 | #[test] | 118 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 119 | fn empty_derive() { |
98 | check( | 120 | check( |
99 | r#"#[derive($0)] struct Test;"#, | 121 | r#"#[derive($0)] struct Test;"#, |
100 | expect![[r#" | 122 | expect![[r#" |
101 | at Clone | 123 | at PartialEq |
102 | at Clone, Copy | 124 | at Default |
103 | at Debug | 125 | at PartialEq, Eq |
104 | at Default | 126 | at PartialEq, Eq, PartialOrd, Ord |
105 | at Hash | 127 | at Clone, Copy |
106 | at PartialEq | 128 | at Debug |
107 | at PartialEq, Eq | 129 | at Clone |
108 | at PartialEq, PartialOrd | 130 | at Hash |
109 | at PartialEq, Eq, PartialOrd, Ord | 131 | at PartialEq, PartialOrd |
110 | "#]], | 132 | "#]], |
111 | ); | 133 | ); |
112 | } | 134 | } |
113 | 135 | ||
114 | #[test] | 136 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
116 | fn derive_with_input() { | 137 | fn derive_with_input() { |
117 | check( | 138 | check( |
118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 139 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, |
119 | expect![[r#" | 140 | expect![[r#" |
120 | at Clone | 141 | at Default |
142 | at Eq | ||
143 | at Eq, PartialOrd, Ord | ||
121 | at Clone, Copy | 144 | at Clone, Copy |
122 | at Debug | 145 | at Debug |
123 | at Default | 146 | at Clone |
124 | at Hash | 147 | at Hash |
125 | at Eq | ||
126 | at PartialOrd | 148 | at PartialOrd |
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | 149 | "#]], |
129 | ) | 150 | ) |
130 | } | 151 | } |
131 | 152 | ||
132 | #[test] | 153 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
134 | fn derive_with_input2() { | 154 | fn derive_with_input2() { |
135 | check( | 155 | check( |
136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 156 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, |
137 | expect![[r#" | 157 | expect![[r#" |
138 | at Clone | 158 | at Default |
159 | at Eq | ||
160 | at Eq, PartialOrd, Ord | ||
139 | at Clone, Copy | 161 | at Clone, Copy |
140 | at Debug | 162 | at Debug |
141 | at Default | 163 | at Clone |
142 | at Hash | 164 | at Hash |
143 | at Eq | ||
144 | at PartialOrd | 165 | at PartialOrd |
145 | at Eq, PartialOrd, Ord | ||
146 | "#]], | 166 | "#]], |
147 | ) | 167 | ) |
148 | } | 168 | } |
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index ca99e9759..1ddc38986 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs | |||
@@ -33,8 +33,7 @@ pub(super) fn complete_lint( | |||
33 | 33 | ||
34 | #[cfg(test)] | 34 | #[cfg(test)] |
35 | mod tests { | 35 | mod tests { |
36 | 36 | use crate::tests::check_edit; | |
37 | use crate::test_utils::check_edit; | ||
38 | 37 | ||
39 | #[test] | 38 | #[test] |
40 | fn check_empty() { | 39 | fn check_empty() { |
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs new file mode 100644 index 000000000..92a262a43 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/repr.rs | |||
@@ -0,0 +1,199 @@ | |||
1 | //! Completion for representations. | ||
2 | |||
3 | use syntax::ast; | ||
4 | |||
5 | use crate::{ | ||
6 | context::CompletionContext, | ||
7 | item::{CompletionItem, CompletionItemKind, CompletionKind}, | ||
8 | Completions, | ||
9 | }; | ||
10 | |||
11 | pub(super) fn complete_repr( | ||
12 | acc: &mut Completions, | ||
13 | ctx: &CompletionContext, | ||
14 | derive_input: ast::TokenTree, | ||
15 | ) { | ||
16 | if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) { | ||
17 | for repr_completion in REPR_COMPLETIONS { | ||
18 | if existing_reprs | ||
19 | .iter() | ||
20 | .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it)) | ||
21 | { | ||
22 | continue; | ||
23 | } | ||
24 | let mut item = CompletionItem::new( | ||
25 | CompletionKind::Attribute, | ||
26 | ctx.source_range(), | ||
27 | repr_completion.label, | ||
28 | ); | ||
29 | item.kind(CompletionItemKind::Attribute); | ||
30 | if let Some(lookup) = repr_completion.lookup { | ||
31 | item.lookup_by(lookup); | ||
32 | } | ||
33 | if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) { | ||
34 | item.insert_snippet(cap, snippet); | ||
35 | } | ||
36 | item.add_to(acc); | ||
37 | } | ||
38 | } | ||
39 | } | ||
40 | |||
41 | struct ReprCompletion { | ||
42 | label: &'static str, | ||
43 | snippet: Option<&'static str>, | ||
44 | lookup: Option<&'static str>, | ||
45 | collides: &'static [&'static str], | ||
46 | } | ||
47 | |||
48 | const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion { | ||
49 | ReprCompletion { label, snippet: None, lookup: None, collides } | ||
50 | } | ||
51 | |||
52 | #[rustfmt::skip] | ||
53 | const REPR_COMPLETIONS: &[ReprCompletion] = &[ | ||
54 | ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] }, | ||
55 | attr("packed", &["transparent", "align"]), | ||
56 | attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
57 | attr("C", &["transparent"]), | ||
58 | attr("u8", &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
59 | attr("u16", &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
60 | attr("u32", &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
61 | attr("u64", &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
62 | attr("u128", &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
63 | attr("usize", &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]), | ||
64 | attr("i8", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]), | ||
65 | attr("i16", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]), | ||
66 | attr("i32", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]), | ||
67 | attr("i64", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]), | ||
68 | attr("i28", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]), | ||
69 | attr("isize", &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]), | ||
70 | ]; | ||
71 | |||
72 | #[cfg(test)] | ||
73 | mod tests { | ||
74 | use expect_test::{expect, Expect}; | ||
75 | |||
76 | use crate::tests::completion_list; | ||
77 | |||
78 | fn check(ra_fixture: &str, expect: Expect) { | ||
79 | let actual = completion_list(ra_fixture); | ||
80 | expect.assert_eq(&actual); | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn no_completion_for_incorrect_repr() { | ||
85 | check(r#"#[repr{$0)] struct Test;"#, expect![[]]) | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn empty() { | ||
90 | check( | ||
91 | r#"#[repr($0)] struct Test;"#, | ||
92 | expect![[r#" | ||
93 | at align($0) | ||
94 | at packed | ||
95 | at transparent | ||
96 | at C | ||
97 | at u8 | ||
98 | at u16 | ||
99 | at u32 | ||
100 | at u64 | ||
101 | at u128 | ||
102 | at usize | ||
103 | at i8 | ||
104 | at i16 | ||
105 | at i32 | ||
106 | at i64 | ||
107 | at i28 | ||
108 | at isize | ||
109 | "#]], | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn transparent() { | ||
115 | check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); | ||
116 | } | ||
117 | |||
118 | #[test] | ||
119 | fn align() { | ||
120 | check( | ||
121 | r#"#[repr(align(1), $0)] struct Test;"#, | ||
122 | expect![[r#" | ||
123 | at align($0) | ||
124 | at transparent | ||
125 | at C | ||
126 | at u8 | ||
127 | at u16 | ||
128 | at u32 | ||
129 | at u64 | ||
130 | at u128 | ||
131 | at usize | ||
132 | at i8 | ||
133 | at i16 | ||
134 | at i32 | ||
135 | at i64 | ||
136 | at i28 | ||
137 | at isize | ||
138 | "#]], | ||
139 | ); | ||
140 | } | ||
141 | |||
142 | #[test] | ||
143 | fn packed() { | ||
144 | check( | ||
145 | r#"#[repr(packed, $0)] struct Test;"#, | ||
146 | expect![[r#" | ||
147 | at transparent | ||
148 | at C | ||
149 | at u8 | ||
150 | at u16 | ||
151 | at u32 | ||
152 | at u64 | ||
153 | at u128 | ||
154 | at usize | ||
155 | at i8 | ||
156 | at i16 | ||
157 | at i32 | ||
158 | at i64 | ||
159 | at i28 | ||
160 | at isize | ||
161 | "#]], | ||
162 | ); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn c() { | ||
167 | check( | ||
168 | r#"#[repr(C, $0)] struct Test;"#, | ||
169 | expect![[r#" | ||
170 | at align($0) | ||
171 | at packed | ||
172 | at u8 | ||
173 | at u16 | ||
174 | at u32 | ||
175 | at u64 | ||
176 | at u128 | ||
177 | at usize | ||
178 | at i8 | ||
179 | at i16 | ||
180 | at i32 | ||
181 | at i64 | ||
182 | at i28 | ||
183 | at isize | ||
184 | "#]], | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
189 | fn prim() { | ||
190 | check( | ||
191 | r#"#[repr(usize, $0)] struct Test;"#, | ||
192 | expect![[r#" | ||
193 | at align($0) | ||
194 | at packed | ||
195 | at C | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | } | ||
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 9552875c1..286d7cb67 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -101,10 +101,10 @@ fn complete_methods( | |||
101 | mod tests { | 101 | mod tests { |
102 | use expect_test::{expect, Expect}; | 102 | use expect_test::{expect, Expect}; |
103 | 103 | ||
104 | use crate::{test_utils::completion_list, CompletionKind}; | 104 | use crate::{tests::filtered_completion_list, CompletionKind}; |
105 | 105 | ||
106 | fn check(ra_fixture: &str, expect: Expect) { | 106 | fn check(ra_fixture: &str, expect: Expect) { |
107 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 107 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
108 | expect.assert_eq(&actual); | 108 | expect.assert_eq(&actual); |
109 | } | 109 | } |
110 | 110 | ||
@@ -498,10 +498,7 @@ mod foo { | |||
498 | fn issue_8931() { | 498 | fn issue_8931() { |
499 | check( | 499 | check( |
500 | r#" | 500 | r#" |
501 | #[lang = "fn_once"] | 501 | //- minicore: fn |
502 | trait FnOnce<Args> { | ||
503 | type Output; | ||
504 | } | ||
505 | struct S; | 502 | struct S; |
506 | 503 | ||
507 | struct Foo; | 504 | struct Foo; |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 30b8d44bd..814c15653 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
109 | if !ctx.config.enable_imports_on_the_fly { | 109 | if !ctx.config.enable_imports_on_the_fly { |
110 | return None; | 110 | return None; |
111 | } | 111 | } |
112 | if ctx.use_item_syntax.is_some() | 112 | if ctx.in_use_tree() |
113 | || ctx.is_path_disallowed() | 113 | || ctx.is_path_disallowed() |
114 | || ctx.expects_item() | 114 | || ctx.expects_item() |
115 | || ctx.expects_assoc_item() | 115 | || ctx.expects_assoc_item() |
@@ -227,11 +227,11 @@ mod tests { | |||
227 | 227 | ||
228 | use crate::{ | 228 | use crate::{ |
229 | item::CompletionKind, | 229 | item::CompletionKind, |
230 | test_utils::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, | 230 | tests::{check_edit, check_edit_with_config, filtered_completion_list, TEST_CONFIG}, |
231 | }; | 231 | }; |
232 | 232 | ||
233 | fn check(ra_fixture: &str, expect: Expect) { | 233 | fn check(ra_fixture: &str, expect: Expect) { |
234 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 234 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
235 | expect.assert_eq(&actual); | 235 | expect.assert_eq(&actual); |
236 | } | 236 | } |
237 | 237 | ||
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index cb90e8a3e..c9f0e2473 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs | |||
@@ -64,10 +64,10 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
64 | mod tests { | 64 | mod tests { |
65 | use expect_test::{expect, Expect}; | 65 | use expect_test::{expect, Expect}; |
66 | 66 | ||
67 | use crate::{test_utils::completion_list, CompletionKind}; | 67 | use crate::{tests::filtered_completion_list, CompletionKind}; |
68 | 68 | ||
69 | fn check(ra_fixture: &str, expect: Expect) { | 69 | fn check(ra_fixture: &str, expect: Expect) { |
70 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 70 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
71 | expect.assert_eq(&actual); | 71 | expect.assert_eq(&actual); |
72 | } | 72 | } |
73 | 73 | ||
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index ba13d3707..407f796ef 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -18,26 +18,22 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
18 | item | 18 | item |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.use_item_syntax.is_some() { | 21 | if ctx.in_use_tree() { |
22 | let qual = ctx.path_qual(); | 22 | match &ctx.path_context { |
23 | if qual.is_none() { | 23 | Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => { |
24 | kw_completion("crate::").add_to(acc); | 24 | if iter::successors(Some(qual.clone()), |p| p.qualifier()) |
25 | } | 25 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) |
26 | kw_completion("self").add_to(acc); | 26 | { |
27 | if iter::successors(qual.cloned(), |p| p.qualifier()) | 27 | kw_completion("super::").add_to(acc); |
28 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) | 28 | } |
29 | { | 29 | if *use_tree_parent { |
30 | kw_completion("super::").add_to(acc); | 30 | kw_completion("self").add_to(acc); |
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | _ => { | |
34 | // Suggest .await syntax for types that implement Future trait | 34 | kw_completion("crate::").add_to(acc); |
35 | if let Some(receiver) = ctx.dot_receiver() { | 35 | kw_completion("self::").add_to(acc); |
36 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | 36 | kw_completion("super::").add_to(acc); |
37 | if ty.impls_future(ctx.db) { | ||
38 | let mut item = kw_completion("await"); | ||
39 | item.detail("expr.await"); | ||
40 | item.add_to(acc); | ||
41 | } | 37 | } |
42 | }; | 38 | }; |
43 | } | 39 | } |
@@ -52,6 +48,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
52 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 48 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
53 | return; | 49 | return; |
54 | } | 50 | } |
51 | if ctx.attribute_under_caret.is_some() { | ||
52 | cov_mark::hit!(no_keyword_completion_in_attr_of_expr); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | // Suggest .await syntax for types that implement Future trait | ||
57 | if let Some(receiver) = ctx.dot_receiver() { | ||
58 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | ||
59 | if ty.impls_future(ctx.db) { | ||
60 | let mut item = | ||
61 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await"); | ||
62 | item.kind(CompletionItemKind::Keyword).detail("expr.await"); | ||
63 | item.add_to(acc); | ||
64 | } | ||
65 | }; | ||
66 | } | ||
67 | |||
55 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); | 68 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); |
56 | 69 | ||
57 | let expects_assoc_item = ctx.expects_assoc_item(); | 70 | let expects_assoc_item = ctx.expects_assoc_item(); |
@@ -60,6 +73,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
60 | 73 | ||
61 | if ctx.has_impl_or_trait_prev_sibling() { | 74 | if ctx.has_impl_or_trait_prev_sibling() { |
62 | add_keyword("where", "where "); | 75 | add_keyword("where", "where "); |
76 | if ctx.has_impl_prev_sibling() { | ||
77 | add_keyword("for", "for "); | ||
78 | } | ||
63 | return; | 79 | return; |
64 | } | 80 | } |
65 | if ctx.previous_token_is(T![unsafe]) { | 81 | if ctx.previous_token_is(T![unsafe]) { |
@@ -75,7 +91,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
75 | return; | 91 | return; |
76 | } | 92 | } |
77 | 93 | ||
78 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { | 94 | if !ctx.has_visibility_prev_sibling() |
95 | && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field()) | ||
96 | { | ||
79 | add_keyword("pub(crate)", "pub(crate) "); | 97 | add_keyword("pub(crate)", "pub(crate) "); |
80 | add_keyword("pub", "pub "); | 98 | add_keyword("pub", "pub "); |
81 | } | 99 | } |
@@ -88,11 +106,13 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
88 | } | 106 | } |
89 | 107 | ||
90 | if expects_item || has_block_expr_parent { | 108 | if expects_item || has_block_expr_parent { |
109 | if !ctx.has_visibility_prev_sibling() { | ||
110 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
111 | add_keyword("extern", "extern $0"); | ||
112 | } | ||
91 | add_keyword("use", "use $0"); | 113 | add_keyword("use", "use $0"); |
92 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
93 | add_keyword("trait", "trait $1 {\n $0\n}"); | 114 | add_keyword("trait", "trait $1 {\n $0\n}"); |
94 | add_keyword("static", "static $0"); | 115 | add_keyword("static", "static $0"); |
95 | add_keyword("extern", "extern $0"); | ||
96 | add_keyword("mod", "mod $0"); | 116 | add_keyword("mod", "mod $0"); |
97 | } | 117 | } |
98 | 118 | ||
@@ -102,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
102 | add_keyword("union", "union $1 {\n $0\n}"); | 122 | add_keyword("union", "union $1 {\n $0\n}"); |
103 | } | 123 | } |
104 | 124 | ||
125 | if ctx.expects_type() { | ||
126 | return; | ||
127 | } | ||
128 | |||
105 | if ctx.expects_expression() { | 129 | if ctx.expects_expression() { |
106 | if !has_block_expr_parent { | 130 | if !has_block_expr_parent { |
107 | add_keyword("unsafe", "unsafe {\n $0\n}"); | 131 | add_keyword("unsafe", "unsafe {\n $0\n}"); |
@@ -186,75 +210,16 @@ mod tests { | |||
186 | use expect_test::{expect, Expect}; | 210 | use expect_test::{expect, Expect}; |
187 | 211 | ||
188 | use crate::{ | 212 | use crate::{ |
189 | test_utils::{check_edit, completion_list}, | 213 | tests::{check_edit, filtered_completion_list}, |
190 | CompletionKind, | 214 | CompletionKind, |
191 | }; | 215 | }; |
192 | 216 | ||
193 | fn check(ra_fixture: &str, expect: Expect) { | 217 | fn check(ra_fixture: &str, expect: Expect) { |
194 | let actual = completion_list(ra_fixture, CompletionKind::Keyword); | 218 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword); |
195 | expect.assert_eq(&actual) | 219 | expect.assert_eq(&actual) |
196 | } | 220 | } |
197 | 221 | ||
198 | #[test] | 222 | #[test] |
199 | fn test_keywords_in_use_stmt() { | ||
200 | check( | ||
201 | r"use $0", | ||
202 | expect![[r#" | ||
203 | kw crate:: | ||
204 | kw self | ||
205 | kw super:: | ||
206 | "#]], | ||
207 | ); | ||
208 | |||
209 | // FIXME: `self` shouldn't be shown here and the check below | ||
210 | check( | ||
211 | r"use a::$0", | ||
212 | expect![[r#" | ||
213 | kw self | ||
214 | "#]], | ||
215 | ); | ||
216 | |||
217 | check( | ||
218 | r"use super::$0", | ||
219 | expect![[r#" | ||
220 | kw self | ||
221 | kw super:: | ||
222 | "#]], | ||
223 | ); | ||
224 | |||
225 | check( | ||
226 | r"use a::{b, $0}", | ||
227 | expect![[r#" | ||
228 | kw self | ||
229 | "#]], | ||
230 | ); | ||
231 | } | ||
232 | |||
233 | #[test] | ||
234 | fn test_keywords_at_source_file_level() { | ||
235 | check( | ||
236 | r"m$0", | ||
237 | expect![[r#" | ||
238 | kw pub(crate) | ||
239 | kw pub | ||
240 | kw unsafe | ||
241 | kw fn | ||
242 | kw const | ||
243 | kw type | ||
244 | kw use | ||
245 | kw impl | ||
246 | kw trait | ||
247 | kw static | ||
248 | kw extern | ||
249 | kw mod | ||
250 | kw enum | ||
251 | kw struct | ||
252 | kw union | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn test_keywords_in_function() { | 223 | fn test_keywords_in_function() { |
259 | check( | 224 | check( |
260 | r"fn quux() { $0 }", | 225 | r"fn quux() { $0 }", |
@@ -263,11 +228,11 @@ mod tests { | |||
263 | kw fn | 228 | kw fn |
264 | kw const | 229 | kw const |
265 | kw type | 230 | kw type |
266 | kw use | ||
267 | kw impl | 231 | kw impl |
232 | kw extern | ||
233 | kw use | ||
268 | kw trait | 234 | kw trait |
269 | kw static | 235 | kw static |
270 | kw extern | ||
271 | kw mod | 236 | kw mod |
272 | kw match | 237 | kw match |
273 | kw while | 238 | kw while |
@@ -291,11 +256,11 @@ mod tests { | |||
291 | kw fn | 256 | kw fn |
292 | kw const | 257 | kw const |
293 | kw type | 258 | kw type |
294 | kw use | ||
295 | kw impl | 259 | kw impl |
260 | kw extern | ||
261 | kw use | ||
296 | kw trait | 262 | kw trait |
297 | kw static | 263 | kw static |
298 | kw extern | ||
299 | kw mod | 264 | kw mod |
300 | kw match | 265 | kw match |
301 | kw while | 266 | kw while |
@@ -319,11 +284,11 @@ mod tests { | |||
319 | kw fn | 284 | kw fn |
320 | kw const | 285 | kw const |
321 | kw type | 286 | kw type |
322 | kw use | ||
323 | kw impl | 287 | kw impl |
288 | kw extern | ||
289 | kw use | ||
324 | kw trait | 290 | kw trait |
325 | kw static | 291 | kw static |
326 | kw extern | ||
327 | kw mod | 292 | kw mod |
328 | kw match | 293 | kw match |
329 | kw while | 294 | kw while |
@@ -370,49 +335,6 @@ fn quux() -> i32 { | |||
370 | } | 335 | } |
371 | 336 | ||
372 | #[test] | 337 | #[test] |
373 | fn test_keywords_in_trait_def() { | ||
374 | check( | ||
375 | r"trait My { $0 }", | ||
376 | expect![[r#" | ||
377 | kw unsafe | ||
378 | kw fn | ||
379 | kw const | ||
380 | kw type | ||
381 | "#]], | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_keywords_in_impl_def() { | ||
387 | check( | ||
388 | r"impl My { $0 }", | ||
389 | expect![[r#" | ||
390 | kw pub(crate) | ||
391 | kw pub | ||
392 | kw unsafe | ||
393 | kw fn | ||
394 | kw const | ||
395 | kw type | ||
396 | "#]], | ||
397 | ); | ||
398 | } | ||
399 | |||
400 | #[test] | ||
401 | fn test_keywords_in_impl_def_with_attr() { | ||
402 | check( | ||
403 | r"impl My { #[foo] $0 }", | ||
404 | expect![[r#" | ||
405 | kw pub(crate) | ||
406 | kw pub | ||
407 | kw unsafe | ||
408 | kw fn | ||
409 | kw const | ||
410 | kw type | ||
411 | "#]], | ||
412 | ); | ||
413 | } | ||
414 | |||
415 | #[test] | ||
416 | fn test_keywords_in_loop() { | 338 | fn test_keywords_in_loop() { |
417 | check( | 339 | check( |
418 | r"fn my() { loop { $0 } }", | 340 | r"fn my() { loop { $0 } }", |
@@ -421,11 +343,11 @@ fn quux() -> i32 { | |||
421 | kw fn | 343 | kw fn |
422 | kw const | 344 | kw const |
423 | kw type | 345 | kw type |
424 | kw use | ||
425 | kw impl | 346 | kw impl |
347 | kw extern | ||
348 | kw use | ||
426 | kw trait | 349 | kw trait |
427 | kw static | 350 | kw static |
428 | kw extern | ||
429 | kw mod | 351 | kw mod |
430 | kw match | 352 | kw match |
431 | kw while | 353 | kw while |
@@ -443,18 +365,6 @@ fn quux() -> i32 { | |||
443 | } | 365 | } |
444 | 366 | ||
445 | #[test] | 367 | #[test] |
446 | fn test_keywords_after_unsafe_in_item_list() { | ||
447 | check( | ||
448 | r"unsafe $0", | ||
449 | expect![[r#" | ||
450 | kw fn | ||
451 | kw trait | ||
452 | kw impl | ||
453 | "#]], | ||
454 | ); | ||
455 | } | ||
456 | |||
457 | #[test] | ||
458 | fn test_keywords_after_unsafe_in_block_expr() { | 368 | fn test_keywords_after_unsafe_in_block_expr() { |
459 | check( | 369 | check( |
460 | r"fn my_fn() { unsafe $0 }", | 370 | r"fn my_fn() { unsafe $0 }", |
@@ -467,44 +377,6 @@ fn quux() -> i32 { | |||
467 | } | 377 | } |
468 | 378 | ||
469 | #[test] | 379 | #[test] |
470 | fn test_mut_in_ref_and_in_fn_parameters_list() { | ||
471 | check( | ||
472 | r"fn my_fn(&$0) {}", | ||
473 | expect![[r#" | ||
474 | kw mut | ||
475 | "#]], | ||
476 | ); | ||
477 | check( | ||
478 | r"fn my_fn($0) {}", | ||
479 | expect![[r#" | ||
480 | kw mut | ||
481 | "#]], | ||
482 | ); | ||
483 | check( | ||
484 | r"fn my_fn() { let &$0 }", | ||
485 | expect![[r#" | ||
486 | kw mut | ||
487 | "#]], | ||
488 | ); | ||
489 | } | ||
490 | |||
491 | #[test] | ||
492 | fn test_where_keyword() { | ||
493 | check( | ||
494 | r"trait A $0", | ||
495 | expect![[r#" | ||
496 | kw where | ||
497 | "#]], | ||
498 | ); | ||
499 | check( | ||
500 | r"impl A $0", | ||
501 | expect![[r#" | ||
502 | kw where | ||
503 | "#]], | ||
504 | ); | ||
505 | } | ||
506 | |||
507 | #[test] | ||
508 | fn no_keyword_completion_in_comments() { | 380 | fn no_keyword_completion_in_comments() { |
509 | cov_mark::check!(no_keyword_completion_in_comments); | 381 | cov_mark::check!(no_keyword_completion_in_comments); |
510 | check( | 382 | check( |
@@ -536,17 +408,11 @@ Some multi-line comment$0 | |||
536 | fn test_completion_await_impls_future() { | 408 | fn test_completion_await_impls_future() { |
537 | check( | 409 | check( |
538 | r#" | 410 | r#" |
539 | //- /main.rs crate:main deps:std | 411 | //- minicore: future |
540 | use std::future::*; | 412 | use core::future::*; |
541 | struct A {} | 413 | struct A {} |
542 | impl Future for A {} | 414 | impl Future for A {} |
543 | fn foo(a: A) { a.$0 } | 415 | fn foo(a: A) { a.$0 } |
544 | |||
545 | //- /std/lib.rs crate:std | ||
546 | pub mod future { | ||
547 | #[lang = "future_trait"] | ||
548 | pub trait Future {} | ||
549 | } | ||
550 | "#, | 416 | "#, |
551 | expect![[r#" | 417 | expect![[r#" |
552 | kw await expr.await | 418 | kw await expr.await |
@@ -555,20 +421,12 @@ pub mod future { | |||
555 | 421 | ||
556 | check( | 422 | check( |
557 | r#" | 423 | r#" |
558 | //- /main.rs crate:main deps:std | 424 | //- minicore: future |
559 | use std::future::*; | 425 | use std::future::*; |
560 | fn foo() { | 426 | fn foo() { |
561 | let a = async {}; | 427 | let a = async {}; |
562 | a.$0 | 428 | a.$0 |
563 | } | 429 | } |
564 | |||
565 | //- /std/lib.rs crate:std | ||
566 | pub mod future { | ||
567 | #[lang = "future_trait"] | ||
568 | pub trait Future { | ||
569 | type Output; | ||
570 | } | ||
571 | } | ||
572 | "#, | 430 | "#, |
573 | expect![[r#" | 431 | expect![[r#" |
574 | kw await expr.await | 432 | kw await expr.await |
@@ -595,22 +453,6 @@ pub mod future { | |||
595 | } | 453 | } |
596 | 454 | ||
597 | #[test] | 455 | #[test] |
598 | fn before_field() { | ||
599 | check( | ||
600 | r#" | ||
601 | struct Foo { | ||
602 | $0 | ||
603 | pub f: i32, | ||
604 | } | ||
605 | "#, | ||
606 | expect![[r#" | ||
607 | kw pub(crate) | ||
608 | kw pub | ||
609 | "#]], | ||
610 | ) | ||
611 | } | ||
612 | |||
613 | #[test] | ||
614 | fn skip_struct_initializer() { | 456 | fn skip_struct_initializer() { |
615 | cov_mark::check!(no_keyword_completion_in_record_lit); | 457 | cov_mark::check!(no_keyword_completion_in_record_lit); |
616 | check( | 458 | check( |
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 8ccccb646..abf6935c9 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -49,18 +49,11 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) { | |||
49 | mod tests { | 49 | mod tests { |
50 | use expect_test::{expect, Expect}; | 50 | use expect_test::{expect, Expect}; |
51 | 51 | ||
52 | use crate::{ | 52 | use crate::tests::{check_edit, completion_list}; |
53 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, | ||
54 | CompletionConfig, CompletionKind, | ||
55 | }; | ||
56 | 53 | ||
57 | fn check(ra_fixture: &str, expect: Expect) { | 54 | fn check(ra_fixture: &str, expect: Expect) { |
58 | check_with_config(TEST_CONFIG, ra_fixture, expect); | 55 | let actual = completion_list(ra_fixture); |
59 | } | 56 | expect.assert_eq(&actual); |
60 | |||
61 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { | ||
62 | let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | ||
63 | expect.assert_eq(&actual) | ||
64 | } | 57 | } |
65 | 58 | ||
66 | #[test] | 59 | #[test] |
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs index 6a5746fb9..1c864c0e7 100644 --- a/crates/ide_completion/src/completions/mod_.rs +++ b/crates/ide_completion/src/completions/mod_.rs | |||
@@ -141,11 +141,11 @@ fn module_chain_to_containing_module_file( | |||
141 | 141 | ||
142 | #[cfg(test)] | 142 | #[cfg(test)] |
143 | mod tests { | 143 | mod tests { |
144 | use crate::{test_utils::completion_list, CompletionKind}; | 144 | use crate::tests::completion_list; |
145 | use expect_test::{expect, Expect}; | 145 | use expect_test::{expect, Expect}; |
146 | 146 | ||
147 | fn check(ra_fixture: &str, expect: Expect) { | 147 | fn check(ra_fixture: &str, expect: Expect) { |
148 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 148 | let actual = completion_list(ra_fixture); |
149 | expect.assert_eq(&actual); | 149 | expect.assert_eq(&actual); |
150 | } | 150 | } |
151 | 151 | ||
@@ -153,17 +153,17 @@ mod tests { | |||
153 | fn lib_module_completion() { | 153 | fn lib_module_completion() { |
154 | check( | 154 | check( |
155 | r#" | 155 | r#" |
156 | //- /lib.rs | 156 | //- /lib.rs |
157 | mod $0 | 157 | mod $0 |
158 | //- /foo.rs | 158 | //- /foo.rs |
159 | fn foo() {} | 159 | fn foo() {} |
160 | //- /foo/ignored_foo.rs | 160 | //- /foo/ignored_foo.rs |
161 | fn ignored_foo() {} | 161 | fn ignored_foo() {} |
162 | //- /bar/mod.rs | 162 | //- /bar/mod.rs |
163 | fn bar() {} | 163 | fn bar() {} |
164 | //- /bar/ignored_bar.rs | 164 | //- /bar/ignored_bar.rs |
165 | fn ignored_bar() {} | 165 | fn ignored_bar() {} |
166 | "#, | 166 | "#, |
167 | expect![[r#" | 167 | expect![[r#" |
168 | md foo; | 168 | md foo; |
169 | md bar; | 169 | md bar; |
@@ -175,13 +175,13 @@ mod tests { | |||
175 | fn no_module_completion_with_module_body() { | 175 | fn no_module_completion_with_module_body() { |
176 | check( | 176 | check( |
177 | r#" | 177 | r#" |
178 | //- /lib.rs | 178 | //- /lib.rs |
179 | mod $0 { | 179 | mod $0 { |
180 | 180 | ||
181 | } | 181 | } |
182 | //- /foo.rs | 182 | //- /foo.rs |
183 | fn foo() {} | 183 | fn foo() {} |
184 | "#, | 184 | "#, |
185 | expect![[r#""#]], | 185 | expect![[r#""#]], |
186 | ); | 186 | ); |
187 | } | 187 | } |
@@ -190,17 +190,17 @@ mod tests { | |||
190 | fn main_module_completion() { | 190 | fn main_module_completion() { |
191 | check( | 191 | check( |
192 | r#" | 192 | r#" |
193 | //- /main.rs | 193 | //- /main.rs |
194 | mod $0 | 194 | mod $0 |
195 | //- /foo.rs | 195 | //- /foo.rs |
196 | fn foo() {} | 196 | fn foo() {} |
197 | //- /foo/ignored_foo.rs | 197 | //- /foo/ignored_foo.rs |
198 | fn ignored_foo() {} | 198 | fn ignored_foo() {} |
199 | //- /bar/mod.rs | 199 | //- /bar/mod.rs |
200 | fn bar() {} | 200 | fn bar() {} |
201 | //- /bar/ignored_bar.rs | 201 | //- /bar/ignored_bar.rs |
202 | fn ignored_bar() {} | 202 | fn ignored_bar() {} |
203 | "#, | 203 | "#, |
204 | expect![[r#" | 204 | expect![[r#" |
205 | md foo; | 205 | md foo; |
206 | md bar; | 206 | md bar; |
@@ -212,13 +212,13 @@ mod tests { | |||
212 | fn main_test_module_completion() { | 212 | fn main_test_module_completion() { |
213 | check( | 213 | check( |
214 | r#" | 214 | r#" |
215 | //- /main.rs | 215 | //- /main.rs |
216 | mod tests { | 216 | mod tests { |
217 | mod $0; | 217 | mod $0; |
218 | } | 218 | } |
219 | //- /tests/foo.rs | 219 | //- /tests/foo.rs |
220 | fn foo() {} | 220 | fn foo() {} |
221 | "#, | 221 | "#, |
222 | expect![[r#" | 222 | expect![[r#" |
223 | md foo | 223 | md foo |
224 | "#]], | 224 | "#]], |
@@ -229,19 +229,19 @@ mod tests { | |||
229 | fn directly_nested_module_completion() { | 229 | fn directly_nested_module_completion() { |
230 | check( | 230 | check( |
231 | r#" | 231 | r#" |
232 | //- /lib.rs | 232 | //- /lib.rs |
233 | mod foo; | 233 | mod foo; |
234 | //- /foo.rs | 234 | //- /foo.rs |
235 | mod $0; | 235 | mod $0; |
236 | //- /foo/bar.rs | 236 | //- /foo/bar.rs |
237 | fn bar() {} | 237 | fn bar() {} |
238 | //- /foo/bar/ignored_bar.rs | 238 | //- /foo/bar/ignored_bar.rs |
239 | fn ignored_bar() {} | 239 | fn ignored_bar() {} |
240 | //- /foo/baz/mod.rs | 240 | //- /foo/baz/mod.rs |
241 | fn baz() {} | 241 | fn baz() {} |
242 | //- /foo/moar/ignored_moar.rs | 242 | //- /foo/moar/ignored_moar.rs |
243 | fn ignored_moar() {} | 243 | fn ignored_moar() {} |
244 | "#, | 244 | "#, |
245 | expect![[r#" | 245 | expect![[r#" |
246 | md bar | 246 | md bar |
247 | md baz | 247 | md baz |
@@ -253,15 +253,15 @@ mod tests { | |||
253 | fn nested_in_source_module_completion() { | 253 | fn nested_in_source_module_completion() { |
254 | check( | 254 | check( |
255 | r#" | 255 | r#" |
256 | //- /lib.rs | 256 | //- /lib.rs |
257 | mod foo; | 257 | mod foo; |
258 | //- /foo.rs | 258 | //- /foo.rs |
259 | mod bar { | 259 | mod bar { |
260 | mod $0 | 260 | mod $0 |
261 | } | 261 | } |
262 | //- /foo/bar/baz.rs | 262 | //- /foo/bar/baz.rs |
263 | fn baz() {} | 263 | fn baz() {} |
264 | "#, | 264 | "#, |
265 | expect![[r#" | 265 | expect![[r#" |
266 | md baz; | 266 | md baz; |
267 | "#]], | 267 | "#]], |
@@ -299,16 +299,16 @@ mod tests { | |||
299 | fn already_declared_bin_module_completion_omitted() { | 299 | fn already_declared_bin_module_completion_omitted() { |
300 | check( | 300 | check( |
301 | r#" | 301 | r#" |
302 | //- /src/bin.rs crate:main | 302 | //- /src/bin.rs crate:main |
303 | fn main() {} | 303 | fn main() {} |
304 | //- /src/bin/foo.rs | 304 | //- /src/bin/foo.rs |
305 | mod $0 | 305 | mod $0 |
306 | //- /src/bin/bar.rs | 306 | //- /src/bin/bar.rs |
307 | mod foo; | 307 | mod foo; |
308 | fn bar() {} | 308 | fn bar() {} |
309 | //- /src/bin/bar/bar_ignored.rs | 309 | //- /src/bin/bar/bar_ignored.rs |
310 | fn bar_ignored() {} | 310 | fn bar_ignored() {} |
311 | "#, | 311 | "#, |
312 | expect![[r#""#]], | 312 | expect![[r#""#]], |
313 | ); | 313 | ); |
314 | } | 314 | } |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 1daa8595a..bd13a62d7 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -13,7 +13,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
13 | if let Some(hir::Adt::Enum(e)) = | 13 | if let Some(hir::Adt::Enum(e)) = |
14 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 14 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
15 | { | 15 | { |
16 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | 16 | super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { |
17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); | 17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); |
18 | acc.add_qualified_enum_variant(ctx, variant, path); | 18 | acc.add_qualified_enum_variant(ctx, variant, path); |
19 | }); | 19 | }); |
@@ -55,398 +55,3 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
55 | } | 55 | } |
56 | }); | 56 | }); |
57 | } | 57 | } |
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | use expect_test::{expect, Expect}; | ||
62 | |||
63 | use crate::{ | ||
64 | test_utils::{check_edit, completion_list}, | ||
65 | CompletionKind, | ||
66 | }; | ||
67 | |||
68 | fn check(ra_fixture: &str, expect: Expect) { | ||
69 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
70 | expect.assert_eq(&actual) | ||
71 | } | ||
72 | |||
73 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
74 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
75 | expect.assert_eq(&actual) | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn completes_enum_variants_and_modules() { | ||
80 | check( | ||
81 | r#" | ||
82 | enum E { X } | ||
83 | use self::E::X; | ||
84 | const Z: E = E::X; | ||
85 | mod m {} | ||
86 | |||
87 | static FOO: E = E::X; | ||
88 | struct Bar { f: u32 } | ||
89 | |||
90 | fn foo() { | ||
91 | match E::X { a$0 } | ||
92 | } | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | en E | ||
96 | ct Z | ||
97 | st Bar | ||
98 | ev X | ||
99 | md m | ||
100 | "#]], | ||
101 | ); | ||
102 | } | ||
103 | |||
104 | #[test] | ||
105 | fn does_not_complete_non_fn_macros() { | ||
106 | check( | ||
107 | r#" | ||
108 | macro_rules! m { ($e:expr) => { $e } } | ||
109 | enum E { X } | ||
110 | |||
111 | #[rustc_builtin_macro] | ||
112 | macro Clone {} | ||
113 | |||
114 | fn foo() { | ||
115 | match E::X { $0 } | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | ev E::X () | ||
120 | en E | ||
121 | ma m!(…) macro_rules! m | ||
122 | "#]], | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn completes_in_simple_macro_call() { | ||
128 | check( | ||
129 | r#" | ||
130 | macro_rules! m { ($e:expr) => { $e } } | ||
131 | enum E { X } | ||
132 | |||
133 | fn foo() { | ||
134 | m!(match E::X { a$0 }) | ||
135 | } | ||
136 | "#, | ||
137 | expect![[r#" | ||
138 | ev E::X () | ||
139 | en E | ||
140 | ma m!(…) macro_rules! m | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_in_irrefutable_let() { | ||
147 | check( | ||
148 | r#" | ||
149 | enum E { X } | ||
150 | use self::E::X; | ||
151 | const Z: E = E::X; | ||
152 | mod m {} | ||
153 | |||
154 | static FOO: E = E::X; | ||
155 | struct Bar { f: u32 } | ||
156 | |||
157 | fn foo() { | ||
158 | let a$0 | ||
159 | } | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | st Bar | ||
163 | "#]], | ||
164 | ); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn completes_in_param() { | ||
169 | check( | ||
170 | r#" | ||
171 | enum E { X } | ||
172 | |||
173 | static FOO: E = E::X; | ||
174 | struct Bar { f: u32 } | ||
175 | |||
176 | fn foo(a$0) { | ||
177 | } | ||
178 | "#, | ||
179 | expect![[r#" | ||
180 | st Bar | ||
181 | "#]], | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn completes_pat_in_let() { | ||
187 | check_snippet( | ||
188 | r#" | ||
189 | struct Bar { f: u32 } | ||
190 | |||
191 | fn foo() { | ||
192 | let a$0 | ||
193 | } | ||
194 | "#, | ||
195 | expect![[r#" | ||
196 | bn Bar Bar { f$1 }$0 | ||
197 | "#]], | ||
198 | ); | ||
199 | } | ||
200 | |||
201 | #[test] | ||
202 | fn completes_param_pattern() { | ||
203 | check_snippet( | ||
204 | r#" | ||
205 | struct Foo { bar: String, baz: String } | ||
206 | struct Bar(String, String); | ||
207 | struct Baz; | ||
208 | fn outer(a$0) {} | ||
209 | "#, | ||
210 | expect![[r#" | ||
211 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
212 | bn Bar Bar($1, $2): Bar$0 | ||
213 | "#]], | ||
214 | ) | ||
215 | } | ||
216 | |||
217 | #[test] | ||
218 | fn completes_let_pattern() { | ||
219 | check_snippet( | ||
220 | r#" | ||
221 | struct Foo { bar: String, baz: String } | ||
222 | struct Bar(String, String); | ||
223 | struct Baz; | ||
224 | fn outer() { | ||
225 | let a$0 | ||
226 | } | ||
227 | "#, | ||
228 | expect![[r#" | ||
229 | bn Foo Foo { bar$1, baz$2 }$0 | ||
230 | bn Bar Bar($1, $2)$0 | ||
231 | "#]], | ||
232 | ) | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn completes_refutable_pattern() { | ||
237 | check_snippet( | ||
238 | r#" | ||
239 | struct Foo { bar: i32, baz: i32 } | ||
240 | struct Bar(String, String); | ||
241 | struct Baz; | ||
242 | fn outer() { | ||
243 | match () { | ||
244 | a$0 | ||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | bn Foo Foo { bar$1, baz$2 }$0 | ||
250 | bn Bar Bar($1, $2)$0 | ||
251 | "#]], | ||
252 | ) | ||
253 | } | ||
254 | |||
255 | #[test] | ||
256 | fn omits_private_fields_pat() { | ||
257 | check_snippet( | ||
258 | r#" | ||
259 | mod foo { | ||
260 | pub struct Foo { pub bar: i32, baz: i32 } | ||
261 | pub struct Bar(pub String, String); | ||
262 | pub struct Invisible(String, String); | ||
263 | } | ||
264 | use foo::*; | ||
265 | |||
266 | fn outer() { | ||
267 | match () { | ||
268 | a$0 | ||
269 | } | ||
270 | } | ||
271 | "#, | ||
272 | expect![[r#" | ||
273 | bn Foo Foo { bar$1, .. }$0 | ||
274 | bn Bar Bar($1, ..)$0 | ||
275 | "#]], | ||
276 | ) | ||
277 | } | ||
278 | |||
279 | #[test] | ||
280 | fn only_shows_ident_completion() { | ||
281 | check_edit( | ||
282 | "Foo", | ||
283 | r#" | ||
284 | struct Foo(i32); | ||
285 | fn main() { | ||
286 | match Foo(92) { | ||
287 | a$0(92) => (), | ||
288 | } | ||
289 | } | ||
290 | "#, | ||
291 | r#" | ||
292 | struct Foo(i32); | ||
293 | fn main() { | ||
294 | match Foo(92) { | ||
295 | Foo(92) => (), | ||
296 | } | ||
297 | } | ||
298 | "#, | ||
299 | ); | ||
300 | } | ||
301 | |||
302 | #[test] | ||
303 | fn completes_self_pats() { | ||
304 | check_snippet( | ||
305 | r#" | ||
306 | struct Foo(i32); | ||
307 | impl Foo { | ||
308 | fn foo() { | ||
309 | match () { | ||
310 | a$0 | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | "#, | ||
315 | expect![[r#" | ||
316 | bn Self Self($1)$0 | ||
317 | bn Foo Foo($1)$0 | ||
318 | "#]], | ||
319 | ) | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn completes_qualified_variant() { | ||
324 | check_snippet( | ||
325 | r#" | ||
326 | enum Foo { | ||
327 | Bar { baz: i32 } | ||
328 | } | ||
329 | impl Foo { | ||
330 | fn foo() { | ||
331 | match {Foo::Bar { baz: 0 }} { | ||
332 | B$0 | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
339 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
340 | "#]], | ||
341 | ) | ||
342 | } | ||
343 | |||
344 | #[test] | ||
345 | fn completes_enum_variant_matcharm() { | ||
346 | check( | ||
347 | r#" | ||
348 | enum Foo { Bar, Baz, Quux } | ||
349 | |||
350 | fn main() { | ||
351 | let foo = Foo::Quux; | ||
352 | match foo { Qu$0 } | ||
353 | } | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | ev Foo::Bar () | ||
357 | ev Foo::Baz () | ||
358 | ev Foo::Quux () | ||
359 | en Foo | ||
360 | "#]], | ||
361 | ) | ||
362 | } | ||
363 | |||
364 | #[test] | ||
365 | fn completes_enum_variant_matcharm_ref() { | ||
366 | check( | ||
367 | r#" | ||
368 | enum Foo { Bar, Baz, Quux } | ||
369 | |||
370 | fn main() { | ||
371 | let foo = Foo::Quux; | ||
372 | match &foo { Qu$0 } | ||
373 | } | ||
374 | "#, | ||
375 | expect![[r#" | ||
376 | ev Foo::Bar () | ||
377 | ev Foo::Baz () | ||
378 | ev Foo::Quux () | ||
379 | en Foo | ||
380 | "#]], | ||
381 | ) | ||
382 | } | ||
383 | |||
384 | #[test] | ||
385 | fn completes_enum_variant_iflet() { | ||
386 | check( | ||
387 | r#" | ||
388 | enum Foo { Bar, Baz, Quux } | ||
389 | |||
390 | fn main() { | ||
391 | let foo = Foo::Quux; | ||
392 | if let Qu$0 = foo { } | ||
393 | } | ||
394 | "#, | ||
395 | expect![[r#" | ||
396 | ev Foo::Bar () | ||
397 | ev Foo::Baz () | ||
398 | ev Foo::Quux () | ||
399 | en Foo | ||
400 | "#]], | ||
401 | ) | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn completes_enum_variant_impl() { | ||
406 | check( | ||
407 | r#" | ||
408 | enum Foo { Bar, Baz, Quux } | ||
409 | impl Foo { | ||
410 | fn foo() { match Foo::Bar { Q$0 } } | ||
411 | } | ||
412 | "#, | ||
413 | expect![[r#" | ||
414 | ev Self::Bar () | ||
415 | ev Self::Baz () | ||
416 | ev Self::Quux () | ||
417 | ev Foo::Bar () | ||
418 | ev Foo::Baz () | ||
419 | ev Foo::Quux () | ||
420 | sp Self | ||
421 | en Foo | ||
422 | "#]], | ||
423 | ) | ||
424 | } | ||
425 | |||
426 | #[test] | ||
427 | fn completes_in_record_field_pat() { | ||
428 | check_snippet( | ||
429 | r#" | ||
430 | struct Foo { bar: Bar } | ||
431 | struct Bar(u32); | ||
432 | fn outer(Foo { bar: $0 }: Foo) {} | ||
433 | "#, | ||
434 | expect![[r#" | ||
435 | bn Foo Foo { bar$1 }$0 | ||
436 | bn Bar Bar($1)$0 | ||
437 | "#]], | ||
438 | ) | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn skips_in_record_field_pat_name() { | ||
443 | check_snippet( | ||
444 | r#" | ||
445 | struct Foo { bar: Bar } | ||
446 | struct Bar(u32); | ||
447 | fn outer(Foo { bar$0 }: Foo) {} | ||
448 | "#, | ||
449 | expect![[r#""#]], | ||
450 | ) | ||
451 | } | ||
452 | } | ||
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 9f98b21be..4e20ec003 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -307,12 +307,12 @@ mod tests { | |||
307 | use expect_test::{expect, Expect}; | 307 | use expect_test::{expect, Expect}; |
308 | 308 | ||
309 | use crate::{ | 309 | use crate::{ |
310 | test_utils::{check_edit, completion_list}, | 310 | tests::{check_edit, filtered_completion_list}, |
311 | CompletionKind, | 311 | CompletionKind, |
312 | }; | 312 | }; |
313 | 313 | ||
314 | fn check(ra_fixture: &str, expect: Expect) { | 314 | fn check(ra_fixture: &str, expect: Expect) { |
315 | let actual = completion_list(ra_fixture, CompletionKind::Postfix); | 315 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Postfix); |
316 | expect.assert_eq(&actual) | 316 | expect.assert_eq(&actual) |
317 | } | 317 | } |
318 | 318 | ||
@@ -436,18 +436,15 @@ fn main() { | |||
436 | check_edit( | 436 | check_edit( |
437 | "ifl", | 437 | "ifl", |
438 | r#" | 438 | r#" |
439 | enum Option<T> { Some(T), None } | 439 | //- minicore: option |
440 | |||
441 | fn main() { | 440 | fn main() { |
442 | let bar = Option::Some(true); | 441 | let bar = Some(true); |
443 | bar.$0 | 442 | bar.$0 |
444 | } | 443 | } |
445 | "#, | 444 | "#, |
446 | r#" | 445 | r#" |
447 | enum Option<T> { Some(T), None } | ||
448 | |||
449 | fn main() { | 446 | fn main() { |
450 | let bar = Option::Some(true); | 447 | let bar = Some(true); |
451 | if let Some($1) = bar { | 448 | if let Some($1) = bar { |
452 | $0 | 449 | $0 |
453 | } | 450 | } |
@@ -461,18 +458,15 @@ fn main() { | |||
461 | check_edit( | 458 | check_edit( |
462 | "match", | 459 | "match", |
463 | r#" | 460 | r#" |
464 | enum Result<T, E> { Ok(T), Err(E) } | 461 | //- minicore: result |
465 | |||
466 | fn main() { | 462 | fn main() { |
467 | let bar = Result::Ok(true); | 463 | let bar = Ok(true); |
468 | bar.$0 | 464 | bar.$0 |
469 | } | 465 | } |
470 | "#, | 466 | "#, |
471 | r#" | 467 | r#" |
472 | enum Result<T, E> { Ok(T), Err(E) } | ||
473 | |||
474 | fn main() { | 468 | fn main() { |
475 | let bar = Result::Ok(true); | 469 | let bar = Ok(true); |
476 | match bar { | 470 | match bar { |
477 | Ok(${1:_}) => {$2}, | 471 | Ok(${1:_}) => {$2}, |
478 | Err(${3:_}) => {$0}, | 472 | Err(${3:_}) => {$0}, |
@@ -515,18 +509,15 @@ fn main() { | |||
515 | check_edit( | 509 | check_edit( |
516 | "ifl", | 510 | "ifl", |
517 | r#" | 511 | r#" |
518 | enum Option<T> { Some(T), None } | 512 | //- minicore: option |
519 | |||
520 | fn main() { | 513 | fn main() { |
521 | let bar = &Option::Some(true); | 514 | let bar = &Some(true); |
522 | bar.$0 | 515 | bar.$0 |
523 | } | 516 | } |
524 | "#, | 517 | "#, |
525 | r#" | 518 | r#" |
526 | enum Option<T> { Some(T), None } | ||
527 | |||
528 | fn main() { | 519 | fn main() { |
529 | let bar = &Option::Some(true); | 520 | let bar = &Some(true); |
530 | if let Some($1) = bar { | 521 | if let Some($1) = bar { |
531 | $0 | 522 | $0 |
532 | } | 523 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 6083537b7..1b8997ecf 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -19,6 +19,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
19 | Some(res) => res, | 19 | Some(res) => res, |
20 | None => return, | 20 | None => return, |
21 | }; | 21 | }; |
22 | |||
22 | let context_module = ctx.scope.module(); | 23 | let context_module = ctx.scope.module(); |
23 | 24 | ||
24 | if ctx.expects_item() || ctx.expects_assoc_item() { | 25 | if ctx.expects_item() || ctx.expects_assoc_item() { |
@@ -48,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
48 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { | 49 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { |
49 | let module_scope = module.scope(ctx.db, context_module); | 50 | let module_scope = module.scope(ctx.db, context_module); |
50 | for (name, def) in module_scope { | 51 | for (name, def) in module_scope { |
51 | if ctx.use_item_syntax.is_some() { | 52 | if ctx.in_use_tree() { |
52 | if let hir::ScopeDef::Unknown = def { | 53 | if let hir::ScopeDef::Unknown = def { |
53 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 54 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
54 | if name_ref.syntax().text() == name.to_string().as_str() { | 55 | if name_ref.syntax().text() == name.to_string().as_str() { |
@@ -60,21 +61,37 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
60 | } | 61 | } |
61 | } | 62 | } |
62 | 63 | ||
63 | if let hir::ScopeDef::MacroDef(macro_def) = def { | 64 | let add_resolution = match def { |
64 | if !macro_def.is_fn_like() { | 65 | // Don't suggest attribute macros and derives. |
65 | // Don't suggest attribute macros and derives. | 66 | hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
66 | continue; | 67 | // no values in type places |
68 | hir::ScopeDef::ModuleDef( | ||
69 | hir::ModuleDef::Function(_) | ||
70 | | hir::ModuleDef::Variant(_) | ||
71 | | hir::ModuleDef::Static(_), | ||
72 | ) | ||
73 | | hir::ScopeDef::Local(_) => !ctx.expects_type(), | ||
74 | // unless its a constant in a generic arg list position | ||
75 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => { | ||
76 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
67 | } | 77 | } |
68 | } | 78 | _ => true, |
79 | }; | ||
69 | 80 | ||
70 | acc.add_resolution(ctx, name, &def); | 81 | if add_resolution { |
82 | acc.add_resolution(ctx, name, &def); | ||
83 | } | ||
71 | } | 84 | } |
72 | } | 85 | } |
73 | hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) | 86 | hir::PathResolution::Def( |
74 | | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) | 87 | def |
75 | | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { | 88 | @ |
89 | (hir::ModuleDef::Adt(_) | ||
90 | | hir::ModuleDef::TypeAlias(_) | ||
91 | | hir::ModuleDef::BuiltinType(_)), | ||
92 | ) => { | ||
76 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { | 93 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { |
77 | add_enum_variants(ctx, acc, e); | 94 | add_enum_variants(acc, ctx, e); |
78 | } | 95 | } |
79 | let ty = match def { | 96 | let ty = match def { |
80 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), | 97 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), |
@@ -82,7 +99,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
82 | let ty = a.ty(ctx.db); | 99 | let ty = a.ty(ctx.db); |
83 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 100 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
84 | cov_mark::hit!(completes_variant_through_alias); | 101 | cov_mark::hit!(completes_variant_through_alias); |
85 | add_enum_variants(ctx, acc, e); | 102 | add_enum_variants(acc, ctx, e); |
86 | } | 103 | } |
87 | ty | 104 | ty |
88 | } | 105 | } |
@@ -107,11 +124,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
107 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 124 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
108 | return None; | 125 | return None; |
109 | } | 126 | } |
110 | match item { | 127 | add_assoc_item(acc, ctx, item); |
111 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
112 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
113 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
114 | } | ||
115 | None::<()> | 128 | None::<()> |
116 | }); | 129 | }); |
117 | 130 | ||
@@ -133,11 +146,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
133 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 146 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
134 | continue; | 147 | continue; |
135 | } | 148 | } |
136 | match item { | 149 | add_assoc_item(acc, ctx, item); |
137 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
138 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
139 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
140 | } | ||
141 | } | 150 | } |
142 | } | 151 | } |
143 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { | 152 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { |
@@ -149,7 +158,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
149 | }; | 158 | }; |
150 | 159 | ||
151 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 160 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
152 | add_enum_variants(ctx, acc, e); | 161 | add_enum_variants(acc, ctx, e); |
153 | } | 162 | } |
154 | 163 | ||
155 | let traits_in_scope = ctx.scope.traits_in_scope(); | 164 | let traits_in_scope = ctx.scope.traits_in_scope(); |
@@ -162,11 +171,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
162 | // We might iterate candidates of a trait multiple times here, so deduplicate | 171 | // We might iterate candidates of a trait multiple times here, so deduplicate |
163 | // them. | 172 | // them. |
164 | if seen.insert(item) { | 173 | if seen.insert(item) { |
165 | match item { | 174 | add_assoc_item(acc, ctx, item); |
166 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
167 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
168 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
169 | } | ||
170 | } | 175 | } |
171 | None::<()> | 176 | None::<()> |
172 | }); | 177 | }); |
@@ -176,82 +181,44 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
176 | } | 181 | } |
177 | } | 182 | } |
178 | 183 | ||
179 | fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { | 184 | fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) { |
180 | for variant in e.variants(ctx.db) { | 185 | match item { |
181 | acc.add_enum_variant(ctx, variant, None); | 186 | hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None), |
187 | hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => { | ||
188 | acc.add_const(ctx, ct) | ||
189 | } | ||
190 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
191 | _ => (), | ||
182 | } | 192 | } |
183 | } | 193 | } |
184 | 194 | ||
195 | fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) { | ||
196 | if ctx.expects_type() { | ||
197 | return; | ||
198 | } | ||
199 | e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None)); | ||
200 | } | ||
201 | |||
185 | #[cfg(test)] | 202 | #[cfg(test)] |
186 | mod tests { | 203 | mod tests { |
187 | use expect_test::{expect, Expect}; | 204 | use expect_test::{expect, Expect}; |
188 | 205 | ||
189 | use crate::{ | 206 | use crate::{ |
190 | test_utils::{check_edit, completion_list}, | 207 | tests::{check_edit, filtered_completion_list}, |
191 | CompletionKind, | 208 | CompletionKind, |
192 | }; | 209 | }; |
193 | 210 | ||
194 | fn check(ra_fixture: &str, expect: Expect) { | 211 | fn check(ra_fixture: &str, expect: Expect) { |
195 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 212 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
196 | expect.assert_eq(&actual); | 213 | expect.assert_eq(&actual); |
197 | } | 214 | } |
198 | 215 | ||
199 | fn check_builtin(ra_fixture: &str, expect: Expect) { | 216 | fn check_builtin(ra_fixture: &str, expect: Expect) { |
200 | let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); | 217 | let actual = filtered_completion_list(ra_fixture, CompletionKind::BuiltinType); |
201 | expect.assert_eq(&actual); | 218 | expect.assert_eq(&actual); |
202 | } | 219 | } |
203 | 220 | ||
204 | #[test] | 221 | #[test] |
205 | fn dont_complete_current_use() { | ||
206 | cov_mark::check!(dont_complete_current_use); | ||
207 | check(r#"use self::foo$0;"#, expect![[""]]); | ||
208 | } | ||
209 | |||
210 | #[test] | ||
211 | fn dont_complete_values_in_type_pos() { | ||
212 | check( | ||
213 | r#" | ||
214 | const FOO: () = (); | ||
215 | static BAR: () = (); | ||
216 | struct Baz; | ||
217 | fn foo() { | ||
218 | let _: self::$0; | ||
219 | } | ||
220 | "#, | ||
221 | expect![[r#" | ||
222 | st Baz | ||
223 | "#]], | ||
224 | ); | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn dont_complete_enum_variants_in_type_pos() { | ||
229 | check( | ||
230 | r#" | ||
231 | enum Foo { Bar } | ||
232 | fn foo() { | ||
233 | let _: Foo::$0; | ||
234 | } | ||
235 | "#, | ||
236 | expect![[r#""#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn dont_complete_current_use_in_braces_with_glob() { | ||
242 | check( | ||
243 | r#" | ||
244 | mod foo { pub struct S; } | ||
245 | use self::{foo::*, bar$0}; | ||
246 | "#, | ||
247 | expect![[r#" | ||
248 | st S | ||
249 | md foo | ||
250 | "#]], | ||
251 | ); | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn dont_complete_primitive_in_use() { | 222 | fn dont_complete_primitive_in_use() { |
256 | check_builtin(r#"use self::$0;"#, expect![[""]]); | 223 | check_builtin(r#"use self::$0;"#, expect![[""]]); |
257 | } | 224 | } |
@@ -262,134 +229,6 @@ use self::{foo::*, bar$0}; | |||
262 | } | 229 | } |
263 | 230 | ||
264 | #[test] | 231 | #[test] |
265 | fn completes_primitives() { | ||
266 | check_builtin( | ||
267 | r#"fn main() { let _: $0 = 92; }"#, | ||
268 | expect![[r#" | ||
269 | bt u32 | ||
270 | bt bool | ||
271 | bt u8 | ||
272 | bt isize | ||
273 | bt u16 | ||
274 | bt u64 | ||
275 | bt u128 | ||
276 | bt f32 | ||
277 | bt i128 | ||
278 | bt i16 | ||
279 | bt str | ||
280 | bt i64 | ||
281 | bt char | ||
282 | bt f64 | ||
283 | bt i32 | ||
284 | bt i8 | ||
285 | bt usize | ||
286 | "#]], | ||
287 | ); | ||
288 | } | ||
289 | |||
290 | #[test] | ||
291 | fn completes_mod_with_same_name_as_function() { | ||
292 | check( | ||
293 | r#" | ||
294 | use self::my::$0; | ||
295 | |||
296 | mod my { pub struct Bar; } | ||
297 | fn my() {} | ||
298 | "#, | ||
299 | expect![[r#" | ||
300 | st Bar | ||
301 | "#]], | ||
302 | ); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn filters_visibility() { | ||
307 | check( | ||
308 | r#" | ||
309 | use self::my::$0; | ||
310 | |||
311 | mod my { | ||
312 | struct Bar; | ||
313 | pub struct Foo; | ||
314 | pub use Bar as PublicBar; | ||
315 | } | ||
316 | "#, | ||
317 | expect![[r#" | ||
318 | st Foo | ||
319 | st PublicBar | ||
320 | "#]], | ||
321 | ); | ||
322 | } | ||
323 | |||
324 | #[test] | ||
325 | fn completes_use_item_starting_with_self() { | ||
326 | check( | ||
327 | r#" | ||
328 | use self::m::$0; | ||
329 | |||
330 | mod m { pub struct Bar; } | ||
331 | "#, | ||
332 | expect![[r#" | ||
333 | st Bar | ||
334 | "#]], | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn completes_use_item_starting_with_crate() { | ||
340 | check( | ||
341 | r#" | ||
342 | //- /lib.rs | ||
343 | mod foo; | ||
344 | struct Spam; | ||
345 | //- /foo.rs | ||
346 | use crate::Sp$0 | ||
347 | "#, | ||
348 | expect![[r#" | ||
349 | md foo | ||
350 | st Spam | ||
351 | "#]], | ||
352 | ); | ||
353 | } | ||
354 | |||
355 | #[test] | ||
356 | fn completes_nested_use_tree() { | ||
357 | check( | ||
358 | r#" | ||
359 | //- /lib.rs | ||
360 | mod foo; | ||
361 | struct Spam; | ||
362 | //- /foo.rs | ||
363 | use crate::{Sp$0}; | ||
364 | "#, | ||
365 | expect![[r#" | ||
366 | md foo | ||
367 | st Spam | ||
368 | "#]], | ||
369 | ); | ||
370 | } | ||
371 | |||
372 | #[test] | ||
373 | fn completes_deeply_nested_use_tree() { | ||
374 | check( | ||
375 | r#" | ||
376 | //- /lib.rs | ||
377 | mod foo; | ||
378 | pub mod bar { | ||
379 | pub mod baz { | ||
380 | pub struct Spam; | ||
381 | } | ||
382 | } | ||
383 | //- /foo.rs | ||
384 | use crate::{bar::{baz::Sp$0}}; | ||
385 | "#, | ||
386 | expect![[r#" | ||
387 | st Spam | ||
388 | "#]], | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn completes_enum_variant() { | 232 | fn completes_enum_variant() { |
394 | check( | 233 | check( |
395 | r#" | 234 | r#" |
@@ -486,22 +325,6 @@ fn foo() { let _ = U::$0 } | |||
486 | } | 325 | } |
487 | 326 | ||
488 | #[test] | 327 | #[test] |
489 | fn completes_use_paths_across_crates() { | ||
490 | check( | ||
491 | r#" | ||
492 | //- /main.rs crate:main deps:foo | ||
493 | use foo::$0; | ||
494 | |||
495 | //- /foo/lib.rs crate:foo | ||
496 | pub mod bar { pub struct S; } | ||
497 | "#, | ||
498 | expect![[r#" | ||
499 | md bar | ||
500 | "#]], | ||
501 | ); | ||
502 | } | ||
503 | |||
504 | #[test] | ||
505 | fn completes_trait_associated_method_1() { | 328 | fn completes_trait_associated_method_1() { |
506 | check( | 329 | check( |
507 | r#" | 330 | r#" |
@@ -683,63 +506,6 @@ fn f() {m::$0} | |||
683 | } | 506 | } |
684 | 507 | ||
685 | #[test] | 508 | #[test] |
686 | fn completes_in_assoc_item_list() { | ||
687 | check( | ||
688 | r#" | ||
689 | #[macro_export] | ||
690 | macro_rules! foo { () => {} } | ||
691 | mod bar {} | ||
692 | |||
693 | struct MyStruct {} | ||
694 | impl MyStruct { | ||
695 | crate::$0 | ||
696 | } | ||
697 | "#, | ||
698 | expect![[r##" | ||
699 | md bar | ||
700 | ma foo!(…) #[macro_export] macro_rules! foo | ||
701 | "##]], | ||
702 | ); | ||
703 | } | ||
704 | |||
705 | #[test] | ||
706 | fn completes_in_item_list() { | ||
707 | check( | ||
708 | r#" | ||
709 | struct MyStruct {} | ||
710 | #[macro_export] | ||
711 | macro_rules! foo {} | ||
712 | mod bar {} | ||
713 | |||
714 | crate::$0 | ||
715 | "#, | ||
716 | expect![[r#" | ||
717 | md bar | ||
718 | ma foo!(…) #[macro_export] macro_rules! foo | ||
719 | "#]], | ||
720 | ) | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn test_super_super_completion() { | ||
725 | check( | ||
726 | r#" | ||
727 | mod a { | ||
728 | const A: usize = 0; | ||
729 | mod b { | ||
730 | const B: usize = 0; | ||
731 | mod c { use super::super::$0 } | ||
732 | } | ||
733 | } | ||
734 | "#, | ||
735 | expect![[r#" | ||
736 | md b | ||
737 | ct A | ||
738 | "#]], | ||
739 | ); | ||
740 | } | ||
741 | |||
742 | #[test] | ||
743 | fn completes_reexported_items_under_correct_name() { | 509 | fn completes_reexported_items_under_correct_name() { |
744 | check( | 510 | check( |
745 | r#" | 511 | r#" |
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 0ac47cdbe..e876337f1 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs | |||
@@ -48,44 +48,29 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
48 | #[cfg(test)] | 48 | #[cfg(test)] |
49 | mod tests { | 49 | mod tests { |
50 | use expect_test::{expect, Expect}; | 50 | use expect_test::{expect, Expect}; |
51 | use ide_db::helpers::FamousDefs; | ||
52 | 51 | ||
53 | use crate::{ | 52 | use crate::{ |
54 | test_utils::{self, completion_list}, | 53 | tests::{check_edit, filtered_completion_list}, |
55 | CompletionKind, | 54 | CompletionKind, |
56 | }; | 55 | }; |
57 | 56 | ||
58 | fn check(ra_fixture: &str, expect: Expect) { | 57 | fn check(ra_fixture: &str, expect: Expect) { |
59 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 58 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); |
60 | expect.assert_eq(&actual); | 59 | expect.assert_eq(&actual); |
61 | } | 60 | } |
62 | 61 | ||
63 | fn check_snippet(ra_fixture: &str, expect: Expect) { | 62 | fn check_snippet(ra_fixture: &str, expect: Expect) { |
64 | let actual = completion_list( | 63 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); |
65 | &format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE), | ||
66 | CompletionKind::Snippet, | ||
67 | ); | ||
68 | expect.assert_eq(&actual); | 64 | expect.assert_eq(&actual); |
69 | } | 65 | } |
70 | 66 | ||
71 | fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
72 | test_utils::check_edit( | ||
73 | what, | ||
74 | &format!( | ||
75 | "//- /main.rs crate:main deps:core{}\n{}", | ||
76 | ra_fixture_before, | ||
77 | FamousDefs::FIXTURE, | ||
78 | ), | ||
79 | &(ra_fixture_after.to_owned() + "\n"), | ||
80 | ); | ||
81 | } | ||
82 | |||
83 | #[test] | 67 | #[test] |
84 | fn test_record_literal_field_default() { | 68 | fn test_record_literal_field_default() { |
85 | let test_code = r#" | 69 | let test_code = r#" |
70 | //- minicore: default | ||
86 | struct S { foo: u32, bar: usize } | 71 | struct S { foo: u32, bar: usize } |
87 | 72 | ||
88 | impl core::default::Default for S { | 73 | impl Default for S { |
89 | fn default() -> Self { | 74 | fn default() -> Self { |
90 | S { | 75 | S { |
91 | foo: 0, | 76 | foo: 0, |
@@ -121,9 +106,10 @@ fn process(f: S) { | |||
121 | check_edit( | 106 | check_edit( |
122 | "..Default::default()", | 107 | "..Default::default()", |
123 | r#" | 108 | r#" |
109 | //- minicore: default | ||
124 | struct S { foo: u32, bar: usize } | 110 | struct S { foo: u32, bar: usize } |
125 | 111 | ||
126 | impl core::default::Default for S { | 112 | impl Default for S { |
127 | fn default() -> Self { | 113 | fn default() -> Self { |
128 | S { | 114 | S { |
129 | foo: 0, | 115 | foo: 0, |
@@ -142,7 +128,7 @@ fn process(f: S) { | |||
142 | r#" | 128 | r#" |
143 | struct S { foo: u32, bar: usize } | 129 | struct S { foo: u32, bar: usize } |
144 | 130 | ||
145 | impl core::default::Default for S { | 131 | impl Default for S { |
146 | fn default() -> Self { | 132 | fn default() -> Self { |
147 | S { | 133 | S { |
148 | foo: 0, | 134 | foo: 0, |
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index b9862de67..cbc20cc2c 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. | 1 | //! This file provides snippet completions, like `pd` => `eprintln!(...)`. |
2 | 2 | ||
3 | use ide_db::helpers::SnippetCap; | 3 | use ide_db::helpers::SnippetCap; |
4 | use syntax::T; | ||
4 | 5 | ||
5 | use crate::{ | 6 | use crate::{ |
6 | context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, | 7 | context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem, |
@@ -35,9 +36,17 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
35 | } | 36 | } |
36 | 37 | ||
37 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 38 | pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { |
38 | if !ctx.expects_item() { | 39 | if !ctx.expects_item() |
40 | || ctx.previous_token_is(T![unsafe]) | ||
41 | || ctx.path_qual().is_some() | ||
42 | || ctx.has_impl_or_trait_prev_sibling() | ||
43 | { | ||
39 | return; | 44 | return; |
40 | } | 45 | } |
46 | if ctx.has_visibility_prev_sibling() { | ||
47 | return; // technically we could do some of these snippet completions if we were to put the | ||
48 | // attributes before the vis node. | ||
49 | } | ||
41 | let cap = match ctx.config.snippet_cap { | 50 | let cap = match ctx.config.snippet_cap { |
42 | Some(it) => it, | 51 | Some(it) => it, |
43 | None => return, | 52 | None => return, |
@@ -82,10 +91,10 @@ fn ${1:feature}() { | |||
82 | mod tests { | 91 | mod tests { |
83 | use expect_test::{expect, Expect}; | 92 | use expect_test::{expect, Expect}; |
84 | 93 | ||
85 | use crate::{test_utils::completion_list, CompletionKind}; | 94 | use crate::{tests::filtered_completion_list, CompletionKind}; |
86 | 95 | ||
87 | fn check(ra_fixture: &str, expect: Expect) { | 96 | fn check(ra_fixture: &str, expect: Expect) { |
88 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | 97 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); |
89 | expect.assert_eq(&actual) | 98 | expect.assert_eq(&actual) |
90 | } | 99 | } |
91 | 100 | ||
@@ -105,21 +114,4 @@ mod tests { | |||
105 | check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); | 114 | check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]); |
106 | check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); | 115 | check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]); |
107 | } | 116 | } |
108 | |||
109 | #[test] | ||
110 | fn completes_snippets_in_items() { | ||
111 | check( | ||
112 | r#" | ||
113 | #[cfg(test)] | ||
114 | mod tests { | ||
115 | $0 | ||
116 | } | ||
117 | "#, | ||
118 | expect![[r#" | ||
119 | sn tmod (Test module) | ||
120 | sn tfn (Test function) | ||
121 | sn macro_rules | ||
122 | "#]], | ||
123 | ) | ||
124 | } | ||
125 | } | 117 | } |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a60e5f43c..65f0f3843 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -32,7 +32,7 @@ | |||
32 | //! ``` | 32 | //! ``` |
33 | 33 | ||
34 | use hir::{self, HasAttrs, HasSource}; | 34 | use hir::{self, HasAttrs, HasSource}; |
35 | use ide_db::{traits::get_missing_assoc_items, SymbolKind}; | 35 | use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind}; |
36 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit}, | 37 | ast::{self, edit}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
@@ -52,24 +52,26 @@ enum ImplCompletionKind { | |||
52 | 52 | ||
53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { | 54 | if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { |
55 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { | 55 | if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { |
56 | hir::AssocItem::Function(fn_item) | 56 | get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { |
57 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => | 57 | hir::AssocItem::Function(fn_item) |
58 | { | 58 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => |
59 | add_function_impl(&trigger, acc, ctx, fn_item) | 59 | { |
60 | } | 60 | add_function_impl(&trigger, acc, ctx, fn_item, hir_impl) |
61 | hir::AssocItem::TypeAlias(type_item) | 61 | } |
62 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => | 62 | hir::AssocItem::TypeAlias(type_item) |
63 | { | 63 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => |
64 | add_type_alias_impl(&trigger, acc, ctx, type_item) | 64 | { |
65 | } | 65 | add_type_alias_impl(&trigger, acc, ctx, type_item) |
66 | hir::AssocItem::Const(const_item) | 66 | } |
67 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => | 67 | hir::AssocItem::Const(const_item) |
68 | { | 68 | if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => |
69 | add_const_impl(&trigger, acc, ctx, const_item) | 69 | { |
70 | } | 70 | add_const_impl(&trigger, acc, ctx, const_item, hir_impl) |
71 | _ => {} | 71 | } |
72 | }); | 72 | _ => {} |
73 | }); | ||
74 | } | ||
73 | } | 75 | } |
74 | } | 76 | } |
75 | 77 | ||
@@ -129,6 +131,7 @@ fn add_function_impl( | |||
129 | acc: &mut Completions, | 131 | acc: &mut Completions, |
130 | ctx: &CompletionContext, | 132 | ctx: &CompletionContext, |
131 | func: hir::Function, | 133 | func: hir::Function, |
134 | impl_def: hir::Impl, | ||
132 | ) { | 135 | ) { |
133 | let fn_name = func.name(ctx.db).to_string(); | 136 | let fn_name = func.name(ctx.db).to_string(); |
134 | 137 | ||
@@ -147,23 +150,55 @@ fn add_function_impl( | |||
147 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 150 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
148 | }; | 151 | }; |
149 | let range = replacement_range(ctx, fn_def_node); | 152 | let range = replacement_range(ctx, fn_def_node); |
150 | if let Some(src) = func.source(ctx.db) { | 153 | |
151 | let function_decl = function_declaration(&src.value); | 154 | if let Some(source) = func.source(ctx.db) { |
152 | match ctx.config.snippet_cap { | 155 | let assoc_item = ast::AssocItem::Fn(source.value); |
153 | Some(cap) => { | 156 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { |
154 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 157 | let transformed_fn = match transformed_item { |
155 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); | 158 | ast::AssocItem::Fn(func) => func, |
156 | } | 159 | _ => unreachable!(), |
157 | None => { | 160 | }; |
158 | let header = format!("{} {{", function_decl); | 161 | |
159 | item.text_edit(TextEdit::replace(range, header)); | 162 | let function_decl = function_declaration(&transformed_fn); |
160 | } | 163 | match ctx.config.snippet_cap { |
161 | }; | 164 | Some(cap) => { |
162 | item.kind(completion_kind); | 165 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
163 | item.add_to(acc); | 166 | item.snippet_edit(cap, TextEdit::replace(range, snippet)); |
167 | } | ||
168 | None => { | ||
169 | let header = format!("{} {{", function_decl); | ||
170 | item.text_edit(TextEdit::replace(range, header)); | ||
171 | } | ||
172 | }; | ||
173 | item.kind(completion_kind); | ||
174 | item.add_to(acc); | ||
175 | } | ||
164 | } | 176 | } |
165 | } | 177 | } |
166 | 178 | ||
179 | /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc. | ||
180 | fn get_transformed_assoc_item( | ||
181 | ctx: &CompletionContext, | ||
182 | assoc_item: ast::AssocItem, | ||
183 | impl_def: hir::Impl, | ||
184 | ) -> Option<ast::AssocItem> { | ||
185 | let assoc_item = assoc_item.clone_for_update(); | ||
186 | let trait_ = impl_def.trait_(ctx.db)?; | ||
187 | let source_scope = &ctx.sema.scope_for_def(trait_); | ||
188 | let target_scope = &ctx.sema.scope(impl_def.source(ctx.db)?.syntax().value); | ||
189 | let transform = PathTransform { | ||
190 | subst: (trait_, impl_def.source(ctx.db)?.value), | ||
191 | source_scope, | ||
192 | target_scope, | ||
193 | }; | ||
194 | |||
195 | transform.apply(assoc_item.clone()); | ||
196 | Some(match assoc_item { | ||
197 | ast::AssocItem::Fn(func) => ast::AssocItem::Fn(edit::remove_attrs_and_docs(&func)), | ||
198 | _ => assoc_item, | ||
199 | }) | ||
200 | } | ||
201 | |||
167 | fn add_type_alias_impl( | 202 | fn add_type_alias_impl( |
168 | type_def_node: &SyntaxNode, | 203 | type_def_node: &SyntaxNode, |
169 | acc: &mut Completions, | 204 | acc: &mut Completions, |
@@ -188,21 +223,30 @@ fn add_const_impl( | |||
188 | acc: &mut Completions, | 223 | acc: &mut Completions, |
189 | ctx: &CompletionContext, | 224 | ctx: &CompletionContext, |
190 | const_: hir::Const, | 225 | const_: hir::Const, |
226 | impl_def: hir::Impl, | ||
191 | ) { | 227 | ) { |
192 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 228 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
193 | 229 | ||
194 | if let Some(const_name) = const_name { | 230 | if let Some(const_name) = const_name { |
195 | if let Some(source) = const_.source(ctx.db) { | 231 | if let Some(source) = const_.source(ctx.db) { |
196 | let snippet = make_const_compl_syntax(&source.value); | 232 | let assoc_item = ast::AssocItem::Const(source.value); |
197 | 233 | if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { | |
198 | let range = replacement_range(ctx, const_def_node); | 234 | let transformed_const = match transformed_item { |
199 | let mut item = | 235 | ast::AssocItem::Const(const_) => const_, |
200 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 236 | _ => unreachable!(), |
201 | item.text_edit(TextEdit::replace(range, snippet)) | 237 | }; |
202 | .lookup_by(const_name) | 238 | |
203 | .kind(SymbolKind::Const) | 239 | let snippet = make_const_compl_syntax(&transformed_const); |
204 | .set_documentation(const_.docs(ctx.db)); | 240 | |
205 | item.add_to(acc); | 241 | let range = replacement_range(ctx, const_def_node); |
242 | let mut item = | ||
243 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | ||
244 | item.text_edit(TextEdit::replace(range, snippet)) | ||
245 | .lookup_by(const_name) | ||
246 | .kind(SymbolKind::Const) | ||
247 | .set_documentation(const_.docs(ctx.db)); | ||
248 | item.add_to(acc); | ||
249 | } | ||
206 | } | 250 | } |
207 | } | 251 | } |
208 | } | 252 | } |
@@ -246,12 +290,12 @@ mod tests { | |||
246 | use expect_test::{expect, Expect}; | 290 | use expect_test::{expect, Expect}; |
247 | 291 | ||
248 | use crate::{ | 292 | use crate::{ |
249 | test_utils::{check_edit, completion_list}, | 293 | tests::{check_edit, filtered_completion_list}, |
250 | CompletionKind, | 294 | CompletionKind, |
251 | }; | 295 | }; |
252 | 296 | ||
253 | fn check(ra_fixture: &str, expect: Expect) { | 297 | fn check(ra_fixture: &str, expect: Expect) { |
254 | let actual = completion_list(ra_fixture, CompletionKind::Magic); | 298 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Magic); |
255 | expect.assert_eq(&actual) | 299 | expect.assert_eq(&actual) |
256 | } | 300 | } |
257 | 301 | ||
@@ -779,4 +823,183 @@ impl Foo for T {{ | |||
779 | test("Type", "type T$0", "type Type = "); | 823 | test("Type", "type T$0", "type Type = "); |
780 | test("CONST", "const C$0", "const CONST: i32 = "); | 824 | test("CONST", "const C$0", "const CONST: i32 = "); |
781 | } | 825 | } |
826 | |||
827 | #[test] | ||
828 | fn generics_are_inlined_in_return_type() { | ||
829 | check_edit( | ||
830 | "function", | ||
831 | r#" | ||
832 | trait Foo<T> { | ||
833 | fn function() -> T; | ||
834 | } | ||
835 | struct Bar; | ||
836 | |||
837 | impl Foo<u32> for Bar { | ||
838 | fn f$0 | ||
839 | } | ||
840 | "#, | ||
841 | r#" | ||
842 | trait Foo<T> { | ||
843 | fn function() -> T; | ||
844 | } | ||
845 | struct Bar; | ||
846 | |||
847 | impl Foo<u32> for Bar { | ||
848 | fn function() -> u32 { | ||
849 | $0 | ||
850 | } | ||
851 | } | ||
852 | "#, | ||
853 | ) | ||
854 | } | ||
855 | |||
856 | #[test] | ||
857 | fn generics_are_inlined_in_parameter() { | ||
858 | check_edit( | ||
859 | "function", | ||
860 | r#" | ||
861 | trait Foo<T> { | ||
862 | fn function(bar: T); | ||
863 | } | ||
864 | struct Bar; | ||
865 | |||
866 | impl Foo<u32> for Bar { | ||
867 | fn f$0 | ||
868 | } | ||
869 | "#, | ||
870 | r#" | ||
871 | trait Foo<T> { | ||
872 | fn function(bar: T); | ||
873 | } | ||
874 | struct Bar; | ||
875 | |||
876 | impl Foo<u32> for Bar { | ||
877 | fn function(bar: u32) { | ||
878 | $0 | ||
879 | } | ||
880 | } | ||
881 | "#, | ||
882 | ) | ||
883 | } | ||
884 | |||
885 | #[test] | ||
886 | fn generics_are_inlined_when_part_of_other_types() { | ||
887 | check_edit( | ||
888 | "function", | ||
889 | r#" | ||
890 | trait Foo<T> { | ||
891 | fn function(bar: Vec<T>); | ||
892 | } | ||
893 | struct Bar; | ||
894 | |||
895 | impl Foo<u32> for Bar { | ||
896 | fn f$0 | ||
897 | } | ||
898 | "#, | ||
899 | r#" | ||
900 | trait Foo<T> { | ||
901 | fn function(bar: Vec<T>); | ||
902 | } | ||
903 | struct Bar; | ||
904 | |||
905 | impl Foo<u32> for Bar { | ||
906 | fn function(bar: Vec<u32>) { | ||
907 | $0 | ||
908 | } | ||
909 | } | ||
910 | "#, | ||
911 | ) | ||
912 | } | ||
913 | |||
914 | #[test] | ||
915 | fn generics_are_inlined_complex() { | ||
916 | check_edit( | ||
917 | "function", | ||
918 | r#" | ||
919 | trait Foo<T, U, V> { | ||
920 | fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>; | ||
921 | } | ||
922 | struct Bar; | ||
923 | |||
924 | impl Foo<u32, Vec<usize>, u8> for Bar { | ||
925 | fn f$0 | ||
926 | } | ||
927 | "#, | ||
928 | r#" | ||
929 | trait Foo<T, U, V> { | ||
930 | fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>; | ||
931 | } | ||
932 | struct Bar; | ||
933 | |||
934 | impl Foo<u32, Vec<usize>, u8> for Bar { | ||
935 | fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> { | ||
936 | $0 | ||
937 | } | ||
938 | } | ||
939 | "#, | ||
940 | ) | ||
941 | } | ||
942 | |||
943 | #[test] | ||
944 | fn generics_are_inlined_in_associated_const() { | ||
945 | check_edit( | ||
946 | "BAR", | ||
947 | r#" | ||
948 | trait Foo<T> { | ||
949 | const BAR: T; | ||
950 | } | ||
951 | struct Bar; | ||
952 | |||
953 | impl Foo<u32> for Bar { | ||
954 | const B$0; | ||
955 | } | ||
956 | "#, | ||
957 | r#" | ||
958 | trait Foo<T> { | ||
959 | const BAR: T; | ||
960 | } | ||
961 | struct Bar; | ||
962 | |||
963 | impl Foo<u32> for Bar { | ||
964 | const BAR: u32 = ; | ||
965 | } | ||
966 | "#, | ||
967 | ) | ||
968 | } | ||
969 | |||
970 | #[test] | ||
971 | fn generics_are_inlined_in_where_clause() { | ||
972 | check_edit( | ||
973 | "function", | ||
974 | r#" | ||
975 | trait SomeTrait<T> {} | ||
976 | |||
977 | trait Foo<T> { | ||
978 | fn function() | ||
979 | where Self: SomeTrait<T>; | ||
980 | } | ||
981 | struct Bar; | ||
982 | |||
983 | impl Foo<u32> for Bar { | ||
984 | fn f$0 | ||
985 | } | ||
986 | "#, | ||
987 | r#" | ||
988 | trait SomeTrait<T> {} | ||
989 | |||
990 | trait Foo<T> { | ||
991 | fn function() | ||
992 | where Self: SomeTrait<T>; | ||
993 | } | ||
994 | struct Bar; | ||
995 | |||
996 | impl Foo<u32> for Bar { | ||
997 | fn function() | ||
998 | where Self: SomeTrait<u32> { | ||
999 | $0 | ||
1000 | } | ||
1001 | } | ||
1002 | "#, | ||
1003 | ) | ||
1004 | } | ||
782 | } | 1005 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 952f052a1..380c1e079 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -6,7 +6,7 @@ use syntax::{ast, AstNode}; | |||
6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
7 | 7 | ||
8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { | 9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() { |
10 | return; | 10 | return; |
11 | } | 11 | } |
12 | 12 | ||
@@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
25 | return; | 25 | return; |
26 | } | 26 | } |
27 | 27 | ||
28 | if ctx.expects_use_tree() { | 28 | if ctx.in_use_tree() { |
29 | // only show modules in a fresh UseTree | 29 | // only show modules in a fresh UseTree |
30 | cov_mark::hit!(only_completes_modules_in_import); | 30 | cov_mark::hit!(only_completes_modules_in_import); |
31 | ctx.scope.process_all_names(&mut |name, res| { | 31 | ctx.scope.process_all_names(&mut |name, res| { |
@@ -36,12 +36,14 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
36 | return; | 36 | return; |
37 | } | 37 | } |
38 | 38 | ||
39 | if let Some(hir::Adt::Enum(e)) = | 39 | if !ctx.expects_type() { |
40 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 40 | if let Some(hir::Adt::Enum(e)) = |
41 | { | 41 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
42 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | 42 | { |
43 | acc.add_qualified_enum_variant(ctx, variant, path) | 43 | super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { |
44 | }); | 44 | acc.add_qualified_enum_variant(ctx, variant, path) |
45 | }); | ||
46 | } | ||
45 | } | 47 | } |
46 | 48 | ||
47 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | 49 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { |
@@ -59,12 +61,30 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
59 | } | 61 | } |
60 | 62 | ||
61 | ctx.scope.process_all_names(&mut |name, res| { | 63 | ctx.scope.process_all_names(&mut |name, res| { |
62 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 64 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) = |
65 | res | ||
66 | { | ||
63 | cov_mark::hit!(skip_lifetime_completion); | 67 | cov_mark::hit!(skip_lifetime_completion); |
64 | return; | 68 | return; |
65 | } | 69 | } |
66 | let add_resolution = match res { | 70 | let add_resolution = match res { |
71 | ScopeDef::ImplSelfType(_) => { | ||
72 | !ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for]) | ||
73 | } | ||
74 | // Don't suggest attribute macros and derives. | ||
67 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | 75 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
76 | // no values in type places | ||
77 | ScopeDef::ModuleDef( | ||
78 | hir::ModuleDef::Function(_) | ||
79 | | hir::ModuleDef::Variant(_) | ||
80 | | hir::ModuleDef::Static(_), | ||
81 | ) | ||
82 | | ScopeDef::Local(_) => !ctx.expects_type(), | ||
83 | // unless its a constant in a generic arg list position | ||
84 | ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) | ||
85 | | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => { | ||
86 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
87 | } | ||
68 | _ => true, | 88 | _ => true, |
69 | }; | 89 | }; |
70 | if add_resolution { | 90 | if add_resolution { |
@@ -78,7 +98,7 @@ mod tests { | |||
78 | use expect_test::{expect, Expect}; | 98 | use expect_test::{expect, Expect}; |
79 | 99 | ||
80 | use crate::{ | 100 | use crate::{ |
81 | test_utils::{check_edit, completion_list_with_config, TEST_CONFIG}, | 101 | tests::{check_edit, filtered_completion_list_with_config, TEST_CONFIG}, |
82 | CompletionConfig, CompletionKind, | 102 | CompletionConfig, CompletionKind, |
83 | }; | 103 | }; |
84 | 104 | ||
@@ -87,99 +107,12 @@ mod tests { | |||
87 | } | 107 | } |
88 | 108 | ||
89 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { | 109 | fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) { |
90 | let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | 110 | let actual = |
111 | filtered_completion_list_with_config(config, ra_fixture, CompletionKind::Reference); | ||
91 | expect.assert_eq(&actual) | 112 | expect.assert_eq(&actual) |
92 | } | 113 | } |
93 | 114 | ||
94 | #[test] | 115 | #[test] |
95 | fn dont_complete_values_in_type_pos() { | ||
96 | check( | ||
97 | r#" | ||
98 | const FOO: () = (); | ||
99 | static BAR: () = (); | ||
100 | enum Foo { | ||
101 | Bar | ||
102 | } | ||
103 | struct Baz; | ||
104 | fn foo() { | ||
105 | let local = (); | ||
106 | let _: $0; | ||
107 | } | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | en Foo | ||
111 | st Baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn only_completes_modules_in_import() { | ||
118 | cov_mark::check!(only_completes_modules_in_import); | ||
119 | check( | ||
120 | r#" | ||
121 | use f$0 | ||
122 | |||
123 | struct Foo; | ||
124 | mod foo {} | ||
125 | "#, | ||
126 | expect![[r#" | ||
127 | md foo | ||
128 | "#]], | ||
129 | ); | ||
130 | } | ||
131 | |||
132 | #[test] | ||
133 | fn bind_pat_and_path_ignore_at() { | ||
134 | check( | ||
135 | r#" | ||
136 | enum Enum { A, B } | ||
137 | fn quux(x: Option<Enum>) { | ||
138 | match x { | ||
139 | None => (), | ||
140 | Some(en$0 @ Enum::A) => (), | ||
141 | } | ||
142 | } | ||
143 | "#, | ||
144 | expect![[r#""#]], | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn bind_pat_and_path_ignore_ref() { | ||
150 | check( | ||
151 | r#" | ||
152 | enum Enum { A, B } | ||
153 | fn quux(x: Option<Enum>) { | ||
154 | match x { | ||
155 | None => (), | ||
156 | Some(ref en$0) => (), | ||
157 | } | ||
158 | } | ||
159 | "#, | ||
160 | expect![[r#""#]], | ||
161 | ); | ||
162 | } | ||
163 | |||
164 | #[test] | ||
165 | fn bind_pat_and_path() { | ||
166 | check( | ||
167 | r#" | ||
168 | enum Enum { A, B } | ||
169 | fn quux(x: Option<Enum>) { | ||
170 | match x { | ||
171 | None => (), | ||
172 | Some(En$0) => (), | ||
173 | } | ||
174 | } | ||
175 | "#, | ||
176 | expect![[r#" | ||
177 | en Enum | ||
178 | "#]], | ||
179 | ); | ||
180 | } | ||
181 | |||
182 | #[test] | ||
183 | fn completes_bindings_from_let() { | 116 | fn completes_bindings_from_let() { |
184 | check( | 117 | check( |
185 | r#" | 118 | r#" |
@@ -284,29 +217,6 @@ fn main() { | |||
284 | } | 217 | } |
285 | 218 | ||
286 | #[test] | 219 | #[test] |
287 | fn completes_generic_params_in_struct() { | ||
288 | check( | ||
289 | r#"struct S<T> { x: $0}"#, | ||
290 | expect![[r#" | ||
291 | sp Self | ||
292 | tp T | ||
293 | st S<…> | ||
294 | "#]], | ||
295 | ); | ||
296 | } | ||
297 | |||
298 | #[test] | ||
299 | fn completes_self_in_enum() { | ||
300 | check( | ||
301 | r#"enum X { Y($0) }"#, | ||
302 | expect![[r#" | ||
303 | sp Self | ||
304 | en X | ||
305 | "#]], | ||
306 | ); | ||
307 | } | ||
308 | |||
309 | #[test] | ||
310 | fn completes_module_items() { | 220 | fn completes_module_items() { |
311 | check( | 221 | check( |
312 | r#" | 222 | r#" |
@@ -343,22 +253,6 @@ fn _alpha() {} | |||
343 | } | 253 | } |
344 | 254 | ||
345 | #[test] | 255 | #[test] |
346 | fn completes_extern_prelude() { | ||
347 | check( | ||
348 | r#" | ||
349 | //- /lib.rs crate:main deps:other_crate | ||
350 | use $0; | ||
351 | |||
352 | //- /other_crate/lib.rs crate:other_crate | ||
353 | // nothing here | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | md other_crate | ||
357 | "#]], | ||
358 | ); | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn completes_module_items_in_nested_modules() { | 256 | fn completes_module_items_in_nested_modules() { |
363 | check( | 257 | check( |
364 | r#" | 258 | r#" |
@@ -376,19 +270,6 @@ mod m { | |||
376 | } | 270 | } |
377 | 271 | ||
378 | #[test] | 272 | #[test] |
379 | fn completes_return_type() { | ||
380 | check( | ||
381 | r#" | ||
382 | struct Foo; | ||
383 | fn x() -> $0 | ||
384 | "#, | ||
385 | expect![[r#" | ||
386 | st Foo | ||
387 | "#]], | ||
388 | ); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn dont_show_both_completions_for_shadowing() { | 273 | fn dont_show_both_completions_for_shadowing() { |
393 | check( | 274 | check( |
394 | r#" | 275 | r#" |
@@ -485,18 +366,6 @@ fn f() {$0} | |||
485 | check( | 366 | check( |
486 | r#" | 367 | r#" |
487 | #[rustc_builtin_macro] | 368 | #[rustc_builtin_macro] |
488 | pub macro Clone {} | ||
489 | |||
490 | struct S; | ||
491 | impl S { | ||
492 | $0 | ||
493 | } | ||
494 | "#, | ||
495 | expect![[r#""#]], | ||
496 | ); | ||
497 | check( | ||
498 | r#" | ||
499 | #[rustc_builtin_macro] | ||
500 | pub macro bench {} | 369 | pub macro bench {} |
501 | 370 | ||
502 | fn f() {$0} | 371 | fn f() {$0} |
@@ -582,19 +451,6 @@ fn foo() { $0 } | |||
582 | } | 451 | } |
583 | 452 | ||
584 | #[test] | 453 | #[test] |
585 | fn completes_macros_as_type() { | ||
586 | check( | ||
587 | r#" | ||
588 | macro_rules! foo { () => {} } | ||
589 | fn main() { let x: $0 } | ||
590 | "#, | ||
591 | expect![[r#" | ||
592 | ma foo!(…) macro_rules! foo | ||
593 | "#]], | ||
594 | ); | ||
595 | } | ||
596 | |||
597 | #[test] | ||
598 | fn completes_macros_as_stmt() { | 454 | fn completes_macros_as_stmt() { |
599 | check( | 455 | check( |
600 | r#" | 456 | r#" |
@@ -739,74 +595,4 @@ fn f() {} | |||
739 | expect![[""]], | 595 | expect![[""]], |
740 | ) | 596 | ) |
741 | } | 597 | } |
742 | |||
743 | #[test] | ||
744 | fn completes_target_type_or_trait_in_impl_block() { | ||
745 | check( | ||
746 | r#" | ||
747 | trait MyTrait {} | ||
748 | struct MyStruct {} | ||
749 | |||
750 | impl My$0 | ||
751 | "#, | ||
752 | expect![[r#" | ||
753 | sp Self | ||
754 | tt MyTrait | ||
755 | st MyStruct | ||
756 | "#]], | ||
757 | ) | ||
758 | } | ||
759 | |||
760 | #[test] | ||
761 | fn completes_in_assoc_item_list() { | ||
762 | check( | ||
763 | r#" | ||
764 | macro_rules! foo {} | ||
765 | mod bar {} | ||
766 | |||
767 | struct MyStruct {} | ||
768 | impl MyStruct { | ||
769 | $0 | ||
770 | } | ||
771 | "#, | ||
772 | expect![[r#" | ||
773 | md bar | ||
774 | ma foo!(…) macro_rules! foo | ||
775 | "#]], | ||
776 | ) | ||
777 | } | ||
778 | |||
779 | #[test] | ||
780 | fn completes_in_item_list() { | ||
781 | check( | ||
782 | r#" | ||
783 | struct MyStruct {} | ||
784 | macro_rules! foo {} | ||
785 | mod bar {} | ||
786 | |||
787 | $0 | ||
788 | "#, | ||
789 | expect![[r#" | ||
790 | md bar | ||
791 | ma foo!(…) macro_rules! foo | ||
792 | "#]], | ||
793 | ) | ||
794 | } | ||
795 | |||
796 | #[test] | ||
797 | fn completes_assoc_types_in_dynimpl_trait() { | ||
798 | check( | ||
799 | r#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn foo(_: impl Foo<B$0>) {} | ||
805 | "#, | ||
806 | expect![[r#" | ||
807 | ta Bar = type Bar; | ||
808 | tt Foo | ||
809 | "#]], | ||
810 | ); | ||
811 | } | ||
812 | } | 598 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 4c3929a26..f0da98739 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext { | |||
43 | pub(super) is_trivial_path: bool, | 43 | pub(super) is_trivial_path: bool, |
44 | /// If not a trivial path, the prefix (qualifier). | 44 | /// If not a trivial path, the prefix (qualifier). |
45 | pub(super) qualifier: Option<ast::Path>, | 45 | pub(super) qualifier: Option<ast::Path>, |
46 | /// Whether the qualifier comes from a use tree parent or not | ||
47 | pub(super) use_tree_parent: bool, | ||
46 | pub(super) kind: Option<PathKind>, | 48 | pub(super) kind: Option<PathKind>, |
47 | /// Whether the path segment has type args or not. | 49 | /// Whether the path segment has type args or not. |
48 | pub(super) has_type_args: bool, | 50 | pub(super) has_type_args: bool, |
@@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> { | |||
79 | /// The parent impl of the cursor position if it exists. | 81 | /// The parent impl of the cursor position if it exists. |
80 | pub(super) impl_def: Option<ast::Impl>, | 82 | pub(super) impl_def: Option<ast::Impl>, |
81 | pub(super) name_ref_syntax: Option<ast::NameRef>, | 83 | pub(super) name_ref_syntax: Option<ast::NameRef>, |
82 | pub(super) use_item_syntax: Option<ast::Use>, | ||
83 | 84 | ||
84 | // potentially set if we are completing a lifetime | 85 | // potentially set if we are completing a lifetime |
85 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | 86 | pub(super) lifetime_syntax: Option<ast::Lifetime>, |
@@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> { | |||
151 | function_def: None, | 152 | function_def: None, |
152 | impl_def: None, | 153 | impl_def: None, |
153 | name_ref_syntax: None, | 154 | name_ref_syntax: None, |
154 | use_item_syntax: None, | ||
155 | lifetime_syntax: None, | 155 | lifetime_syntax: None, |
156 | lifetime_param_syntax: None, | 156 | lifetime_param_syntax: None, |
157 | lifetime_allowed: false, | 157 | lifetime_allowed: false, |
@@ -242,32 +242,27 @@ impl<'a> CompletionContext<'a> { | |||
242 | } | 242 | } |
243 | 243 | ||
244 | pub(crate) fn expects_assoc_item(&self) -> bool { | 244 | pub(crate) fn expects_assoc_item(&self) -> bool { |
245 | matches!( | 245 | matches!(self.completion_location, Some(ImmediateLocation::Trait | ImmediateLocation::Impl)) |
246 | self.completion_location, | ||
247 | Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl) | ||
248 | ) | ||
249 | } | 246 | } |
250 | 247 | ||
251 | pub(crate) fn has_dot_receiver(&self) -> bool { | 248 | pub(crate) fn has_dot_receiver(&self) -> bool { |
252 | matches!( | 249 | matches!( |
253 | &self.completion_location, | 250 | &self.completion_location, |
254 | Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver,.. }) | 251 | Some(ImmediateLocation::FieldAccess { receiver, .. } | ImmediateLocation::MethodCall { receiver,.. }) |
255 | if receiver.is_some() | 252 | if receiver.is_some() |
256 | ) | 253 | ) |
257 | } | 254 | } |
258 | 255 | ||
259 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { | 256 | pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { |
260 | match &self.completion_location { | 257 | match &self.completion_location { |
261 | Some(ImmediateLocation::MethodCall { receiver, .. }) | 258 | Some( |
262 | | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), | 259 | ImmediateLocation::MethodCall { receiver, .. } |
260 | | ImmediateLocation::FieldAccess { receiver, .. }, | ||
261 | ) => receiver.as_ref(), | ||
263 | _ => None, | 262 | _ => None, |
264 | } | 263 | } |
265 | } | 264 | } |
266 | 265 | ||
267 | pub(crate) fn expects_use_tree(&self) -> bool { | ||
268 | matches!(self.completion_location, Some(ImmediateLocation::Use)) | ||
269 | } | ||
270 | |||
271 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { | 266 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { |
272 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) | 267 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) |
273 | } | 268 | } |
@@ -276,6 +271,10 @@ impl<'a> CompletionContext<'a> { | |||
276 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 271 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
277 | } | 272 | } |
278 | 273 | ||
274 | pub(crate) fn expects_generic_arg(&self) -> bool { | ||
275 | matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_))) | ||
276 | } | ||
277 | |||
279 | pub(crate) fn has_block_expr_parent(&self) -> bool { | 278 | pub(crate) fn has_block_expr_parent(&self) -> bool { |
280 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | 279 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) |
281 | } | 280 | } |
@@ -283,33 +282,59 @@ impl<'a> CompletionContext<'a> { | |||
283 | pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { | 282 | pub(crate) fn expects_ident_pat_or_ref_expr(&self) -> bool { |
284 | matches!( | 283 | matches!( |
285 | self.completion_location, | 284 | self.completion_location, |
286 | Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefExpr) | 285 | Some(ImmediateLocation::IdentPat | ImmediateLocation::RefExpr) |
287 | ) | 286 | ) |
288 | } | 287 | } |
289 | 288 | ||
290 | pub(crate) fn expect_record_field(&self) -> bool { | 289 | pub(crate) fn expect_field(&self) -> bool { |
291 | matches!(self.completion_location, Some(ImmediateLocation::RecordField)) | 290 | matches!( |
291 | self.completion_location, | ||
292 | Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField) | ||
293 | ) | ||
294 | } | ||
295 | |||
296 | pub(crate) fn in_use_tree(&self) -> bool { | ||
297 | matches!( | ||
298 | self.completion_location, | ||
299 | Some(ImmediateLocation::Use | ImmediateLocation::UseTree) | ||
300 | ) | ||
292 | } | 301 | } |
293 | 302 | ||
294 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { | 303 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { |
295 | matches!( | 304 | matches!( |
296 | self.prev_sibling, | 305 | self.prev_sibling, |
297 | Some(ImmediatePrevSibling::ImplDefType) | Some(ImmediatePrevSibling::TraitDefName) | 306 | Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName) |
298 | ) | 307 | ) |
299 | } | 308 | } |
300 | 309 | ||
310 | pub(crate) fn has_impl_prev_sibling(&self) -> bool { | ||
311 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType)) | ||
312 | } | ||
313 | |||
314 | pub(crate) fn has_visibility_prev_sibling(&self) -> bool { | ||
315 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::Visibility)) | ||
316 | } | ||
317 | |||
301 | pub(crate) fn after_if(&self) -> bool { | 318 | pub(crate) fn after_if(&self) -> bool { |
302 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) | 319 | matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr)) |
303 | } | 320 | } |
304 | 321 | ||
305 | pub(crate) fn is_path_disallowed(&self) -> bool { | 322 | pub(crate) fn is_path_disallowed(&self) -> bool { |
306 | matches!( | 323 | self.attribute_under_caret.is_some() |
307 | self.completion_location, | 324 | || self.previous_token_is(T![unsafe]) |
308 | Some(ImmediateLocation::Attribute(_)) | 325 | || matches!( |
309 | | Some(ImmediateLocation::ModDeclaration(_)) | 326 | self.prev_sibling, |
310 | | Some(ImmediateLocation::RecordPat(_)) | 327 | Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility) |
311 | | Some(ImmediateLocation::RecordExpr(_)) | 328 | ) |
312 | ) || self.attribute_under_caret.is_some() | 329 | || matches!( |
330 | self.completion_location, | ||
331 | Some( | ||
332 | ImmediateLocation::Attribute(_) | ||
333 | | ImmediateLocation::ModDeclaration(_) | ||
334 | | ImmediateLocation::RecordPat(_) | ||
335 | | ImmediateLocation::RecordExpr(_) | ||
336 | ) | ||
337 | ) | ||
313 | } | 338 | } |
314 | 339 | ||
315 | pub(crate) fn expects_expression(&self) -> bool { | 340 | pub(crate) fn expects_expression(&self) -> bool { |
@@ -363,14 +388,19 @@ impl<'a> CompletionContext<'a> { | |||
363 | (ty, name) | 388 | (ty, name) |
364 | }, | 389 | }, |
365 | ast::ArgList(_it) => { | 390 | ast::ArgList(_it) => { |
366 | cov_mark::hit!(expected_type_fn_param_with_leading_char); | 391 | cov_mark::hit!(expected_type_fn_param); |
367 | cov_mark::hit!(expected_type_fn_param_without_leading_char); | ||
368 | ActiveParameter::at_token( | 392 | ActiveParameter::at_token( |
369 | &self.sema, | 393 | &self.sema, |
370 | self.token.clone(), | 394 | self.token.clone(), |
371 | ).map(|ap| { | 395 | ).map(|ap| { |
372 | let name = ap.ident().map(NameOrNameRef::Name); | 396 | let name = ap.ident().map(NameOrNameRef::Name); |
373 | (Some(ap.ty), name) | 397 | let ty = if has_ref(&self.token) { |
398 | cov_mark::hit!(expected_type_fn_param_ref); | ||
399 | ap.ty.remove_ref() | ||
400 | } else { | ||
401 | Some(ap.ty) | ||
402 | }; | ||
403 | (ty, name) | ||
374 | }) | 404 | }) |
375 | .unwrap_or((None, None)) | 405 | .unwrap_or((None, None)) |
376 | }, | 406 | }, |
@@ -564,9 +594,6 @@ impl<'a> CompletionContext<'a> { | |||
564 | self.name_ref_syntax = | 594 | self.name_ref_syntax = |
565 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 595 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
566 | 596 | ||
567 | self.use_item_syntax = | ||
568 | self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); | ||
569 | |||
570 | self.function_def = self | 597 | self.function_def = self |
571 | .sema | 598 | .sema |
572 | .token_ancestors_with_macros(self.token.clone()) | 599 | .token_ancestors_with_macros(self.token.clone()) |
@@ -586,6 +613,7 @@ impl<'a> CompletionContext<'a> { | |||
586 | has_type_args: false, | 613 | has_type_args: false, |
587 | can_be_stmt: false, | 614 | can_be_stmt: false, |
588 | in_loop_body: false, | 615 | in_loop_body: false, |
616 | use_tree_parent: false, | ||
589 | kind: None, | 617 | kind: None, |
590 | }); | 618 | }); |
591 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); | 619 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); |
@@ -613,7 +641,8 @@ impl<'a> CompletionContext<'a> { | |||
613 | } | 641 | } |
614 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); | 642 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); |
615 | 643 | ||
616 | if let Some(path) = path_or_use_tree_qualifier(&path) { | 644 | if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) { |
645 | path_ctx.use_tree_parent = use_tree_parent; | ||
617 | path_ctx.qualifier = path | 646 | path_ctx.qualifier = path |
618 | .segment() | 647 | .segment() |
619 | .and_then(|it| { | 648 | .and_then(|it| { |
@@ -667,13 +696,26 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | |||
667 | } | 696 | } |
668 | } | 697 | } |
669 | 698 | ||
670 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { | 699 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { |
671 | if let Some(qual) = path.qualifier() { | 700 | if let Some(qual) = path.qualifier() { |
672 | return Some(qual); | 701 | return Some((qual, false)); |
673 | } | 702 | } |
674 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | 703 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; |
675 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; | 704 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; |
676 | use_tree.path() | 705 | use_tree.path().zip(Some(true)) |
706 | } | ||
707 | |||
708 | fn has_ref(token: &SyntaxToken) -> bool { | ||
709 | let mut token = token.clone(); | ||
710 | for skip in [WHITESPACE, IDENT, T![mut]] { | ||
711 | if token.kind() == skip { | ||
712 | token = match token.prev_token() { | ||
713 | Some(it) => it, | ||
714 | None => return false, | ||
715 | } | ||
716 | } | ||
717 | } | ||
718 | token.kind() == T![&] | ||
677 | } | 719 | } |
678 | 720 | ||
679 | #[cfg(test)] | 721 | #[cfg(test)] |
@@ -681,7 +723,7 @@ mod tests { | |||
681 | use expect_test::{expect, Expect}; | 723 | use expect_test::{expect, Expect}; |
682 | use hir::HirDisplay; | 724 | use hir::HirDisplay; |
683 | 725 | ||
684 | use crate::test_utils::{position, TEST_CONFIG}; | 726 | use crate::tests::{position, TEST_CONFIG}; |
685 | 727 | ||
686 | use super::CompletionContext; | 728 | use super::CompletionContext; |
687 | 729 | ||
@@ -748,14 +790,18 @@ fn foo() { | |||
748 | } | 790 | } |
749 | 791 | ||
750 | #[test] | 792 | #[test] |
751 | fn expected_type_fn_param_without_leading_char() { | 793 | fn expected_type_fn_param() { |
752 | cov_mark::check!(expected_type_fn_param_without_leading_char); | 794 | cov_mark::check!(expected_type_fn_param); |
753 | check_expected_type_and_name( | 795 | check_expected_type_and_name( |
754 | r#" | 796 | r#" |
755 | fn foo() { | 797 | fn foo() { bar($0); } |
756 | bar($0); | 798 | fn bar(x: u32) {} |
757 | } | 799 | "#, |
758 | 800 | expect![[r#"ty: u32, name: x"#]], | |
801 | ); | ||
802 | check_expected_type_and_name( | ||
803 | r#" | ||
804 | fn foo() { bar(c$0); } | ||
759 | fn bar(x: u32) {} | 805 | fn bar(x: u32) {} |
760 | "#, | 806 | "#, |
761 | expect![[r#"ty: u32, name: x"#]], | 807 | expect![[r#"ty: u32, name: x"#]], |
@@ -763,18 +809,29 @@ fn bar(x: u32) {} | |||
763 | } | 809 | } |
764 | 810 | ||
765 | #[test] | 811 | #[test] |
766 | fn expected_type_fn_param_with_leading_char() { | 812 | fn expected_type_fn_param_ref() { |
767 | cov_mark::check!(expected_type_fn_param_with_leading_char); | 813 | cov_mark::check!(expected_type_fn_param_ref); |
768 | check_expected_type_and_name( | 814 | check_expected_type_and_name( |
769 | r#" | 815 | r#" |
770 | fn foo() { | 816 | fn foo() { bar(&$0); } |
771 | bar(c$0); | 817 | fn bar(x: &u32) {} |
772 | } | 818 | "#, |
773 | 819 | expect![[r#"ty: u32, name: x"#]], | |
774 | fn bar(x: u32) {} | 820 | ); |
821 | check_expected_type_and_name( | ||
822 | r#" | ||
823 | fn foo() { bar(&mut $0); } | ||
824 | fn bar(x: &mut u32) {} | ||
775 | "#, | 825 | "#, |
776 | expect![[r#"ty: u32, name: x"#]], | 826 | expect![[r#"ty: u32, name: x"#]], |
777 | ); | 827 | ); |
828 | check_expected_type_and_name( | ||
829 | r#" | ||
830 | fn foo() { bar(&c$0); } | ||
831 | fn bar(x: &u32) {} | ||
832 | "#, | ||
833 | expect![[r#"ty: u32, name: x"#]], | ||
834 | ); | ||
778 | } | 835 | } |
779 | 836 | ||
780 | #[test] | 837 | #[test] |
@@ -921,13 +978,12 @@ fn foo() -> u32 { | |||
921 | // FIXME: make this work with `|| $0` | 978 | // FIXME: make this work with `|| $0` |
922 | check_expected_type_and_name( | 979 | check_expected_type_and_name( |
923 | r#" | 980 | r#" |
981 | //- minicore: fn | ||
924 | fn foo() { | 982 | fn foo() { |
925 | bar(|| a$0); | 983 | bar(|| a$0); |
926 | } | 984 | } |
927 | 985 | ||
928 | fn bar(f: impl FnOnce() -> u32) {} | 986 | fn bar(f: impl FnOnce() -> u32) {} |
929 | #[lang = "fn_once"] | ||
930 | trait FnOnce { type Output; } | ||
931 | "#, | 987 | "#, |
932 | expect![[r#"ty: u32, name: ?"#]], | 988 | expect![[r#"ty: u32, name: ?"#]], |
933 | ); | 989 | ); |
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 99edb9499..ae63d132e 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -378,7 +378,7 @@ impl ImportEdit { | |||
378 | let _p = profile::span("ImportEdit::to_text_edit"); | 378 | let _p = profile::span("ImportEdit::to_text_edit"); |
379 | 379 | ||
380 | let new_ast = self.scope.clone_for_update(); | 380 | let new_ast = self.scope.clone_for_update(); |
381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg); | 381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg); |
382 | let mut import_insert = TextEdit::builder(); | 382 | let mut import_insert = TextEdit::builder(); |
383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) | 383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) |
384 | .into_text_edit(&mut import_insert); | 384 | .into_text_edit(&mut import_insert); |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 18983aa01..bf73818dc 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -1,14 +1,14 @@ | |||
1 | //! `completions` crate provides utilities for generating completions of user input. | 1 | //! `completions` crate provides utilities for generating completions of user input. |
2 | 2 | ||
3 | mod completions; | ||
3 | mod config; | 4 | mod config; |
4 | mod item; | ||
5 | mod context; | 5 | mod context; |
6 | mod item; | ||
6 | mod patterns; | 7 | mod patterns; |
7 | #[cfg(test)] | ||
8 | mod test_utils; | ||
9 | mod render; | 8 | mod render; |
10 | 9 | ||
11 | mod completions; | 10 | #[cfg(test)] |
11 | mod tests; | ||
12 | 12 | ||
13 | use completions::flyimport::position_for_import; | 13 | use completions::flyimport::position_for_import; |
14 | use ide_db::{ | 14 | use ide_db::{ |
@@ -141,6 +141,7 @@ pub fn completions( | |||
141 | let ctx = CompletionContext::new(db, position, config)?; | 141 | let ctx = CompletionContext::new(db, position, config)?; |
142 | 142 | ||
143 | if ctx.no_completion_required() { | 143 | if ctx.no_completion_required() { |
144 | cov_mark::hit!(no_completion_required); | ||
144 | // No work required here. | 145 | // No work required here. |
145 | return None; | 146 | return None; |
146 | } | 147 | } |
@@ -200,117 +201,3 @@ pub fn resolve_completion_edits( | |||
200 | 201 | ||
201 | ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) | 202 | ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) |
202 | } | 203 | } |
203 | |||
204 | #[cfg(test)] | ||
205 | mod tests { | ||
206 | use crate::test_utils::{self, TEST_CONFIG}; | ||
207 | |||
208 | struct DetailAndDocumentation<'a> { | ||
209 | detail: &'a str, | ||
210 | documentation: &'a str, | ||
211 | } | ||
212 | |||
213 | fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) { | ||
214 | let (db, position) = test_utils::position(ra_fixture); | ||
215 | let config = TEST_CONFIG; | ||
216 | let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into(); | ||
217 | for item in completions { | ||
218 | if item.detail() == Some(expected.detail) { | ||
219 | let opt = item.documentation(); | ||
220 | let doc = opt.as_ref().map(|it| it.as_str()); | ||
221 | assert_eq!(doc, Some(expected.documentation)); | ||
222 | return; | ||
223 | } | ||
224 | } | ||
225 | panic!("completion detail not found: {}", expected.detail) | ||
226 | } | ||
227 | |||
228 | fn check_no_completion(ra_fixture: &str) { | ||
229 | let (db, position) = test_utils::position(ra_fixture); | ||
230 | let config = TEST_CONFIG; | ||
231 | |||
232 | let completions: Option<Vec<String>> = crate::completions(&db, &config, position) | ||
233 | .and_then(|completions| { | ||
234 | let completions: Vec<_> = completions.into(); | ||
235 | if completions.is_empty() { | ||
236 | None | ||
237 | } else { | ||
238 | Some(completions) | ||
239 | } | ||
240 | }) | ||
241 | .map(|completions| { | ||
242 | completions.into_iter().map(|completion| format!("{:?}", completion)).collect() | ||
243 | }); | ||
244 | |||
245 | // `assert_eq` instead of `assert!(completions.is_none())` to get the list of completions if test will panic. | ||
246 | assert_eq!(completions, None, "Completions were generated, but weren't expected"); | ||
247 | } | ||
248 | |||
249 | #[test] | ||
250 | fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { | ||
251 | check_detail_and_documentation( | ||
252 | r#" | ||
253 | macro_rules! bar { | ||
254 | () => { | ||
255 | struct Bar; | ||
256 | impl Bar { | ||
257 | #[doc = "Do the foo"] | ||
258 | fn foo(&self) {} | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | bar!(); | ||
264 | |||
265 | fn foo() { | ||
266 | let bar = Bar; | ||
267 | bar.fo$0; | ||
268 | } | ||
269 | "#, | ||
270 | DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, | ||
271 | ); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { | ||
276 | check_detail_and_documentation( | ||
277 | r#" | ||
278 | macro_rules! bar { | ||
279 | () => { | ||
280 | struct Bar; | ||
281 | impl Bar { | ||
282 | /// Do the foo | ||
283 | fn foo(&self) {} | ||
284 | } | ||
285 | } | ||
286 | } | ||
287 | |||
288 | bar!(); | ||
289 | |||
290 | fn foo() { | ||
291 | let bar = Bar; | ||
292 | bar.fo$0; | ||
293 | } | ||
294 | "#, | ||
295 | DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" }, | ||
296 | ); | ||
297 | } | ||
298 | |||
299 | #[test] | ||
300 | fn test_no_completions_required() { | ||
301 | // There must be no hint for 'in' keyword. | ||
302 | check_no_completion(r#"fn foo() { for i i$0 }"#); | ||
303 | // After 'in' keyword hints may be spawned. | ||
304 | check_detail_and_documentation( | ||
305 | r#" | ||
306 | /// Do the foo | ||
307 | fn foo() -> &'static str { "foo" } | ||
308 | |||
309 | fn bar() { | ||
310 | for c in fo$0 | ||
311 | } | ||
312 | "#, | ||
313 | DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" }, | ||
314 | ); | ||
315 | } | ||
316 | } | ||
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 72e67e3c4..757c9a3da 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -11,7 +11,7 @@ use syntax::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | #[cfg(test)] | 13 | #[cfg(test)] |
14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; | 14 | use crate::tests::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
15 | 15 | ||
16 | /// Immediate previous node to what we are completing. | 16 | /// Immediate previous node to what we are completing. |
17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
@@ -19,15 +19,19 @@ pub(crate) enum ImmediatePrevSibling { | |||
19 | IfExpr, | 19 | IfExpr, |
20 | TraitDefName, | 20 | TraitDefName, |
21 | ImplDefType, | 21 | ImplDefType, |
22 | Visibility, | ||
23 | Attribute, | ||
22 | } | 24 | } |
23 | 25 | ||
24 | /// Direct parent "thing" of what we are currently completing. | 26 | /// Direct parent "thing" of what we are currently completing. |
25 | #[derive(Clone, Debug, PartialEq, Eq)] | 27 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub(crate) enum ImmediateLocation { | 28 | pub(crate) enum ImmediateLocation { |
27 | Use, | 29 | Use, |
30 | UseTree, | ||
28 | Impl, | 31 | Impl, |
29 | Trait, | 32 | Trait, |
30 | RecordField, | 33 | RecordField, |
34 | TupleField, | ||
31 | RefExpr, | 35 | RefExpr, |
32 | IdentPat, | 36 | IdentPat, |
33 | BlockExpr, | 37 | BlockExpr, |
@@ -79,6 +83,17 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi | |||
79 | _ => node, | 83 | _ => node, |
80 | }; | 84 | }; |
81 | let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; | 85 | let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?; |
86 | if prev_sibling.kind() == ERROR { | ||
87 | let prev_sibling = prev_sibling.first_child()?; | ||
88 | let res = match_ast! { | ||
89 | match prev_sibling { | ||
90 | // vis followed by random ident will always error the parser | ||
91 | ast::Visibility(_it) => ImmediatePrevSibling::Visibility, | ||
92 | _ => return None, | ||
93 | } | ||
94 | }; | ||
95 | return Some(res); | ||
96 | } | ||
82 | let res = match_ast! { | 97 | let res = match_ast! { |
83 | match prev_sibling { | 98 | match prev_sibling { |
84 | ast::ExprStmt(it) => { | 99 | ast::ExprStmt(it) => { |
@@ -101,6 +116,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi | |||
101 | } else { | 116 | } else { |
102 | return None | 117 | return None |
103 | }, | 118 | }, |
119 | ast::Attr(_it) => ImmediatePrevSibling::Attribute, | ||
104 | _ => return None, | 120 | _ => return None, |
105 | } | 121 | } |
106 | }; | 122 | }; |
@@ -166,11 +182,19 @@ pub(crate) fn determine_location( | |||
166 | match parent { | 182 | match parent { |
167 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, | 183 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, |
168 | ast::Use(_it) => ImmediateLocation::Use, | 184 | ast::Use(_it) => ImmediateLocation::Use, |
185 | ast::UseTree(_it) => ImmediateLocation::UseTree, | ||
186 | ast::UseTreeList(_it) => ImmediateLocation::UseTree, | ||
169 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, | 187 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, |
170 | ast::SourceFile(_it) => ImmediateLocation::ItemList, | 188 | ast::SourceFile(_it) => ImmediateLocation::ItemList, |
171 | ast::ItemList(_it) => ImmediateLocation::ItemList, | 189 | ast::ItemList(_it) => ImmediateLocation::ItemList, |
172 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, | 190 | ast::RefExpr(_it) => ImmediateLocation::RefExpr, |
173 | ast::RecordField(_it) => ImmediateLocation::RecordField, | 191 | ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) { |
192 | return None; | ||
193 | } else { | ||
194 | ImmediateLocation::RecordField | ||
195 | }, | ||
196 | ast::TupleField(_it) => ImmediateLocation::TupleField, | ||
197 | ast::TupleFieldList(_it) => ImmediateLocation::TupleField, | ||
174 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { | 198 | ast::AssocItemList(it) => match it.syntax().parent().map(|it| it.kind()) { |
175 | Some(IMPL) => ImmediateLocation::Impl, | 199 | Some(IMPL) => ImmediateLocation::Impl, |
176 | Some(TRAIT) => ImmediateLocation::Trait, | 200 | Some(TRAIT) => ImmediateLocation::Trait, |
@@ -310,7 +334,7 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { | |||
310 | mod tests { | 334 | mod tests { |
311 | use syntax::algo::find_node_at_offset; | 335 | use syntax::algo::find_node_at_offset; |
312 | 336 | ||
313 | use crate::test_utils::position; | 337 | use crate::tests::position; |
314 | 338 | ||
315 | use super::*; | 339 | use super::*; |
316 | 340 | ||
@@ -359,8 +383,8 @@ mod tests { | |||
359 | fn test_use_loc() { | 383 | fn test_use_loc() { |
360 | check_location(r"use f$0", ImmediateLocation::Use); | 384 | check_location(r"use f$0", ImmediateLocation::Use); |
361 | check_location(r"use f$0;", ImmediateLocation::Use); | 385 | check_location(r"use f$0;", ImmediateLocation::Use); |
362 | check_location(r"use f::{f$0}", None); | 386 | check_location(r"use f::{f$0}", ImmediateLocation::UseTree); |
363 | check_location(r"use {f$0}", None); | 387 | check_location(r"use {f$0}", ImmediateLocation::UseTree); |
364 | } | 388 | } |
365 | 389 | ||
366 | #[test] | 390 | #[test] |
@@ -421,4 +445,14 @@ mod tests { | |||
421 | check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); | 445 | check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); |
422 | check_prev_sibling(r"fn foo() { if true {}; w$0", None); | 446 | check_prev_sibling(r"fn foo() { if true {}; w$0", None); |
423 | } | 447 | } |
448 | |||
449 | #[test] | ||
450 | fn test_vis_prev_sibling() { | ||
451 | check_prev_sibling(r"pub w$0", ImmediatePrevSibling::Visibility); | ||
452 | } | ||
453 | |||
454 | #[test] | ||
455 | fn test_attr_prev_sibling() { | ||
456 | check_prev_sibling(r"#[attr] w$0", ImmediatePrevSibling::Attribute); | ||
457 | } | ||
424 | } | 458 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d8ca18c73..1a9b6212a 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -23,53 +23,6 @@ use crate::{ | |||
23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, | 23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, |
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 25 | }; |
26 | |||
27 | pub(crate) fn render_field( | ||
28 | ctx: RenderContext<'_>, | ||
29 | receiver: Option<hir::Name>, | ||
30 | field: hir::Field, | ||
31 | ty: &hir::Type, | ||
32 | ) -> CompletionItem { | ||
33 | render_field_(ctx, receiver, field, ty) | ||
34 | } | ||
35 | |||
36 | pub(crate) fn render_tuple_field( | ||
37 | ctx: RenderContext<'_>, | ||
38 | receiver: Option<hir::Name>, | ||
39 | field: usize, | ||
40 | ty: &hir::Type, | ||
41 | ) -> CompletionItem { | ||
42 | render_tuple_field_(ctx, receiver, field, ty) | ||
43 | } | ||
44 | |||
45 | pub(crate) fn render_resolution( | ||
46 | ctx: RenderContext<'_>, | ||
47 | local_name: hir::Name, | ||
48 | resolution: &hir::ScopeDef, | ||
49 | ) -> Option<CompletionItem> { | ||
50 | render_resolution_(ctx, local_name, None, resolution) | ||
51 | } | ||
52 | |||
53 | pub(crate) fn render_resolution_with_import( | ||
54 | ctx: RenderContext<'_>, | ||
55 | import_edit: ImportEdit, | ||
56 | ) -> Option<CompletionItem> { | ||
57 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
58 | if ctx.completion.expects_type() && resolution.is_value_def() { | ||
59 | return None; | ||
60 | } | ||
61 | let local_name = match resolution { | ||
62 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
63 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
64 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
65 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
66 | }; | ||
67 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
68 | item.completion_kind = CompletionKind::Magic; | ||
69 | item | ||
70 | }) | ||
71 | } | ||
72 | |||
73 | /// Interface for data and methods required for items rendering. | 26 | /// Interface for data and methods required for items rendering. |
74 | #[derive(Debug)] | 27 | #[derive(Debug)] |
75 | pub(crate) struct RenderContext<'a> { | 28 | pub(crate) struct RenderContext<'a> { |
@@ -122,7 +75,7 @@ impl<'a> RenderContext<'a> { | |||
122 | } | 75 | } |
123 | } | 76 | } |
124 | 77 | ||
125 | fn render_field_( | 78 | pub(crate) fn render_field( |
126 | ctx: RenderContext<'_>, | 79 | ctx: RenderContext<'_>, |
127 | receiver: Option<hir::Name>, | 80 | receiver: Option<hir::Name>, |
128 | field: hir::Field, | 81 | field: hir::Field, |
@@ -135,7 +88,6 @@ fn render_field_( | |||
135 | ctx.source_range(), | 88 | ctx.source_range(), |
136 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | 89 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), |
137 | ); | 90 | ); |
138 | |||
139 | item.set_relevance(CompletionRelevance { | 91 | item.set_relevance(CompletionRelevance { |
140 | type_match: compute_type_match(ctx.completion, ty), | 92 | type_match: compute_type_match(ctx.completion, ty), |
141 | exact_name_match: compute_exact_name_match(ctx.completion, &name), | 93 | exact_name_match: compute_exact_name_match(ctx.completion, &name), |
@@ -146,17 +98,15 @@ fn render_field_( | |||
146 | .set_documentation(field.docs(ctx.db())) | 98 | .set_documentation(field.docs(ctx.db())) |
147 | .set_deprecated(is_deprecated) | 99 | .set_deprecated(is_deprecated) |
148 | .lookup_by(name); | 100 | .lookup_by(name); |
149 | |||
150 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { | 101 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { |
151 | // FIXME | 102 | // FIXME |
152 | // For now we don't properly calculate the edits for ref match | 103 | // For now we don't properly calculate the edits for ref match |
153 | // completions on struct fields, so we've disabled them. See #8058. | 104 | // completions on struct fields, so we've disabled them. See #8058. |
154 | } | 105 | } |
155 | |||
156 | item.build() | 106 | item.build() |
157 | } | 107 | } |
158 | 108 | ||
159 | fn render_tuple_field_( | 109 | pub(crate) fn render_tuple_field( |
160 | ctx: RenderContext<'_>, | 110 | ctx: RenderContext<'_>, |
161 | receiver: Option<hir::Name>, | 111 | receiver: Option<hir::Name>, |
162 | field: usize, | 112 | field: usize, |
@@ -167,14 +117,37 @@ fn render_tuple_field_( | |||
167 | ctx.source_range(), | 117 | ctx.source_range(), |
168 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | 118 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), |
169 | ); | 119 | ); |
170 | |||
171 | item.kind(SymbolKind::Field) | 120 | item.kind(SymbolKind::Field) |
172 | .detail(ty.display(ctx.db()).to_string()) | 121 | .detail(ty.display(ctx.db()).to_string()) |
173 | .lookup_by(field.to_string()); | 122 | .lookup_by(field.to_string()); |
174 | |||
175 | item.build() | 123 | item.build() |
176 | } | 124 | } |
177 | 125 | ||
126 | pub(crate) fn render_resolution( | ||
127 | ctx: RenderContext<'_>, | ||
128 | local_name: hir::Name, | ||
129 | resolution: &hir::ScopeDef, | ||
130 | ) -> Option<CompletionItem> { | ||
131 | render_resolution_(ctx, local_name, None, resolution) | ||
132 | } | ||
133 | |||
134 | pub(crate) fn render_resolution_with_import( | ||
135 | ctx: RenderContext<'_>, | ||
136 | import_edit: ImportEdit, | ||
137 | ) -> Option<CompletionItem> { | ||
138 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
139 | let local_name = match resolution { | ||
140 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
141 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
142 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
143 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
144 | }; | ||
145 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
146 | item.completion_kind = CompletionKind::Magic; | ||
147 | item | ||
148 | }) | ||
149 | } | ||
150 | |||
178 | fn render_resolution_( | 151 | fn render_resolution_( |
179 | ctx: RenderContext<'_>, | 152 | ctx: RenderContext<'_>, |
180 | local_name: hir::Name, | 153 | local_name: hir::Name, |
@@ -362,7 +335,7 @@ mod tests { | |||
362 | 335 | ||
363 | use crate::{ | 336 | use crate::{ |
364 | item::CompletionRelevanceTypeMatch, | 337 | item::CompletionRelevanceTypeMatch, |
365 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 338 | tests::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
366 | CompletionKind, CompletionRelevance, | 339 | CompletionKind, CompletionRelevance, |
367 | }; | 340 | }; |
368 | 341 | ||
@@ -1084,7 +1057,7 @@ fn f() { | |||
1084 | #[test] | 1057 | #[test] |
1085 | fn suggest_ref_mut() { | 1058 | fn suggest_ref_mut() { |
1086 | cov_mark::check!(suggest_ref); | 1059 | cov_mark::check!(suggest_ref); |
1087 | check( | 1060 | check_relevance( |
1088 | r#" | 1061 | r#" |
1089 | struct S; | 1062 | struct S; |
1090 | fn foo(s: &mut S) {} | 1063 | fn foo(s: &mut S) {} |
@@ -1094,74 +1067,40 @@ fn main() { | |||
1094 | } | 1067 | } |
1095 | "#, | 1068 | "#, |
1096 | expect![[r#" | 1069 | expect![[r#" |
1097 | [ | 1070 | lc s [name+local] |
1098 | CompletionItem { | 1071 | lc &mut s [type+name+local] |
1099 | label: "S", | 1072 | st S [] |
1100 | source_range: 70..70, | 1073 | fn main() [] |
1101 | delete: 70..70, | 1074 | fn foo(…) [] |
1102 | insert: "S", | ||
1103 | kind: SymbolKind( | ||
1104 | Struct, | ||
1105 | ), | ||
1106 | }, | ||
1107 | CompletionItem { | ||
1108 | label: "foo(…)", | ||
1109 | source_range: 70..70, | ||
1110 | delete: 70..70, | ||
1111 | insert: "foo(${1:&mut s})$0", | ||
1112 | kind: SymbolKind( | ||
1113 | Function, | ||
1114 | ), | ||
1115 | lookup: "foo", | ||
1116 | detail: "fn(&mut S)", | ||
1117 | trigger_call_info: true, | ||
1118 | }, | ||
1119 | CompletionItem { | ||
1120 | label: "main()", | ||
1121 | source_range: 70..70, | ||
1122 | delete: 70..70, | ||
1123 | insert: "main()$0", | ||
1124 | kind: SymbolKind( | ||
1125 | Function, | ||
1126 | ), | ||
1127 | lookup: "main", | ||
1128 | detail: "fn()", | ||
1129 | }, | ||
1130 | CompletionItem { | ||
1131 | label: "s", | ||
1132 | source_range: 70..70, | ||
1133 | delete: 70..70, | ||
1134 | insert: "s", | ||
1135 | kind: SymbolKind( | ||
1136 | Local, | ||
1137 | ), | ||
1138 | detail: "S", | ||
1139 | relevance: CompletionRelevance { | ||
1140 | exact_name_match: true, | ||
1141 | type_match: None, | ||
1142 | is_local: true, | ||
1143 | }, | ||
1144 | ref_match: "&mut ", | ||
1145 | }, | ||
1146 | ] | ||
1147 | "#]], | 1075 | "#]], |
1148 | ) | 1076 | ); |
1077 | check_relevance( | ||
1078 | r#" | ||
1079 | struct S; | ||
1080 | fn foo(s: &mut S) {} | ||
1081 | fn main() { | ||
1082 | let mut s = S; | ||
1083 | foo(&mut $0); | ||
1084 | } | ||
1085 | "#, | ||
1086 | expect![[r#" | ||
1087 | lc s [type+name+local] | ||
1088 | st S [] | ||
1089 | fn main() [] | ||
1090 | fn foo(…) [] | ||
1091 | "#]], | ||
1092 | ); | ||
1149 | } | 1093 | } |
1150 | 1094 | ||
1151 | #[test] | 1095 | #[test] |
1152 | fn suggest_deref() { | 1096 | fn suggest_deref() { |
1153 | check_relevance( | 1097 | check_relevance( |
1154 | r#" | 1098 | r#" |
1155 | #[lang = "deref"] | 1099 | //- minicore: deref |
1156 | trait Deref { | ||
1157 | type Target; | ||
1158 | fn deref(&self) -> &Self::Target; | ||
1159 | } | ||
1160 | |||
1161 | struct S; | 1100 | struct S; |
1162 | struct T(S); | 1101 | struct T(S); |
1163 | 1102 | ||
1164 | impl Deref for T { | 1103 | impl core::ops::Deref for T { |
1165 | type Target = S; | 1104 | type Target = S; |
1166 | 1105 | ||
1167 | fn deref(&self) -> &Self::Target { | 1106 | fn deref(&self) -> &Self::Target { |
@@ -1185,8 +1124,9 @@ fn main() { | |||
1185 | st T [] | 1124 | st T [] |
1186 | st S [] | 1125 | st S [] |
1187 | fn main() [] | 1126 | fn main() [] |
1188 | tt Deref [] | ||
1189 | fn foo(…) [] | 1127 | fn foo(…) [] |
1128 | md core [] | ||
1129 | tt Sized [] | ||
1190 | "#]], | 1130 | "#]], |
1191 | ) | 1131 | ) |
1192 | } | 1132 | } |
@@ -1195,21 +1135,11 @@ fn main() { | |||
1195 | fn suggest_deref_mut() { | 1135 | fn suggest_deref_mut() { |
1196 | check_relevance( | 1136 | check_relevance( |
1197 | r#" | 1137 | r#" |
1198 | #[lang = "deref"] | 1138 | //- minicore: deref_mut |
1199 | trait Deref { | ||
1200 | type Target; | ||
1201 | fn deref(&self) -> &Self::Target; | ||
1202 | } | ||
1203 | |||
1204 | #[lang = "deref_mut"] | ||
1205 | pub trait DerefMut: Deref { | ||
1206 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
1207 | } | ||
1208 | |||
1209 | struct S; | 1139 | struct S; |
1210 | struct T(S); | 1140 | struct T(S); |
1211 | 1141 | ||
1212 | impl Deref for T { | 1142 | impl core::ops::Deref for T { |
1213 | type Target = S; | 1143 | type Target = S; |
1214 | 1144 | ||
1215 | fn deref(&self) -> &Self::Target { | 1145 | fn deref(&self) -> &Self::Target { |
@@ -1217,7 +1147,7 @@ impl Deref for T { | |||
1217 | } | 1147 | } |
1218 | } | 1148 | } |
1219 | 1149 | ||
1220 | impl DerefMut for T { | 1150 | impl core::ops::DerefMut for T { |
1221 | fn deref_mut(&mut self) -> &mut Self::Target { | 1151 | fn deref_mut(&mut self) -> &mut Self::Target { |
1222 | &mut self.0 | 1152 | &mut self.0 |
1223 | } | 1153 | } |
@@ -1236,12 +1166,12 @@ fn main() { | |||
1236 | lc m [local] | 1166 | lc m [local] |
1237 | lc t [local] | 1167 | lc t [local] |
1238 | lc &mut t [type+local] | 1168 | lc &mut t [type+local] |
1239 | tt DerefMut [] | ||
1240 | tt Deref [] | ||
1241 | fn foo(…) [] | ||
1242 | st T [] | 1169 | st T [] |
1243 | st S [] | 1170 | st S [] |
1244 | fn main() [] | 1171 | fn main() [] |
1172 | fn foo(…) [] | ||
1173 | md core [] | ||
1174 | tt Sized [] | ||
1245 | "#]], | 1175 | "#]], |
1246 | ) | 1176 | ) |
1247 | } | 1177 | } |
@@ -1310,16 +1240,11 @@ fn bar(t: &Foo) {} | |||
1310 | fn suggest_deref_fn_ret() { | 1240 | fn suggest_deref_fn_ret() { |
1311 | check_relevance( | 1241 | check_relevance( |
1312 | r#" | 1242 | r#" |
1313 | #[lang = "deref"] | 1243 | //- minicore: deref |
1314 | trait Deref { | ||
1315 | type Target; | ||
1316 | fn deref(&self) -> &Self::Target; | ||
1317 | } | ||
1318 | |||
1319 | struct S; | 1244 | struct S; |
1320 | struct T(S); | 1245 | struct T(S); |
1321 | 1246 | ||
1322 | impl Deref for T { | 1247 | impl core::ops::Deref for T { |
1323 | type Target = S; | 1248 | type Target = S; |
1324 | 1249 | ||
1325 | fn deref(&self) -> &Self::Target { | 1250 | fn deref(&self) -> &Self::Target { |
@@ -1333,15 +1258,16 @@ fn bar() -> T {} | |||
1333 | fn main() { | 1258 | fn main() { |
1334 | foo($0); | 1259 | foo($0); |
1335 | } | 1260 | } |
1336 | "#, | 1261 | "#, |
1337 | expect![[r#" | 1262 | expect![[r#" |
1338 | tt Deref [] | ||
1339 | fn bar() [] | ||
1340 | fn &bar() [type] | ||
1341 | fn foo(…) [] | ||
1342 | st T [] | 1263 | st T [] |
1343 | st S [] | 1264 | st S [] |
1344 | fn main() [] | 1265 | fn main() [] |
1266 | fn bar() [] | ||
1267 | fn &bar() [type] | ||
1268 | fn foo(…) [] | ||
1269 | md core [] | ||
1270 | tt Sized [] | ||
1345 | "#]], | 1271 | "#]], |
1346 | ) | 1272 | ) |
1347 | } | 1273 | } |
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs index c54752d30..33d3a5ee1 100644 --- a/crates/ide_completion/src/render/builder_ext.rs +++ b/crates/ide_completion/src/render/builder_ext.rs | |||
@@ -28,11 +28,11 @@ impl Builder { | |||
28 | if !ctx.config.add_call_parenthesis { | 28 | if !ctx.config.add_call_parenthesis { |
29 | return false; | 29 | return false; |
30 | } | 30 | } |
31 | if ctx.use_item_syntax.is_some() { | 31 | if ctx.in_use_tree() { |
32 | cov_mark::hit!(no_parens_in_use_item); | 32 | cov_mark::hit!(no_parens_in_use_item); |
33 | return false; | 33 | return false; |
34 | } | 34 | } |
35 | if matches!(ctx.path_call_kind(), Some(CallKind::Expr) | Some(CallKind::Pat)) | 35 | if matches!(ctx.path_call_kind(), Some(CallKind::Expr | CallKind::Pat)) |
36 | | matches!( | 36 | | matches!( |
37 | ctx.completion_location, | 37 | ctx.completion_location, |
38 | Some(ImmediateLocation::MethodCall { has_parens: true, .. }) | 38 | Some(ImmediateLocation::MethodCall { has_parens: true, .. }) |
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 28f056e77..91dc178f3 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs | |||
@@ -121,7 +121,7 @@ impl<'a> EnumRender<'a> { | |||
121 | 121 | ||
122 | #[cfg(test)] | 122 | #[cfg(test)] |
123 | mod tests { | 123 | mod tests { |
124 | use crate::test_utils::check_edit; | 124 | use crate::tests::check_edit; |
125 | 125 | ||
126 | #[test] | 126 | #[test] |
127 | fn inserts_parens_for_tuple_enums() { | 127 | fn inserts_parens_for_tuple_enums() { |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 1357b9f4a..19f2c86e9 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -191,7 +191,7 @@ impl<'a> FunctionRender<'a> { | |||
191 | #[cfg(test)] | 191 | #[cfg(test)] |
192 | mod tests { | 192 | mod tests { |
193 | use crate::{ | 193 | use crate::{ |
194 | test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, | 194 | tests::{check_edit, check_edit_with_config, TEST_CONFIG}, |
195 | CompletionConfig, | 195 | CompletionConfig, |
196 | }; | 196 | }; |
197 | 197 | ||
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 429d937c8..4d5179c4f 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> { | |||
69 | } | 69 | } |
70 | 70 | ||
71 | fn needs_bang(&self) -> bool { | 71 | fn needs_bang(&self) -> bool { |
72 | self.ctx.completion.use_item_syntax.is_none() | 72 | !self.ctx.completion.in_use_tree() |
73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) | 73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) |
74 | } | 74 | } |
75 | 75 | ||
@@ -133,7 +133,7 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s | |||
133 | 133 | ||
134 | #[cfg(test)] | 134 | #[cfg(test)] |
135 | mod tests { | 135 | mod tests { |
136 | use crate::test_utils::check_edit; | 136 | use crate::tests::check_edit; |
137 | 137 | ||
138 | #[test] | 138 | #[test] |
139 | fn dont_insert_macro_call_parens_unncessary() { | 139 | fn dont_insert_macro_call_parens_unncessary() { |
@@ -180,7 +180,7 @@ fn main() { frobnicate!(); } | |||
180 | /// ``` | 180 | /// ``` |
181 | macro_rules! vec { () => {} } | 181 | macro_rules! vec { () => {} } |
182 | 182 | ||
183 | fn fn main() { v$0 } | 183 | fn main() { v$0 } |
184 | "#, | 184 | "#, |
185 | r#" | 185 | r#" |
186 | /// Creates a [`Vec`] containing the arguments. | 186 | /// Creates a [`Vec`] containing the arguments. |
@@ -193,7 +193,7 @@ fn fn main() { v$0 } | |||
193 | /// ``` | 193 | /// ``` |
194 | macro_rules! vec { () => {} } | 194 | macro_rules! vec { () => {} } |
195 | 195 | ||
196 | fn fn main() { vec![$0] } | 196 | fn main() { vec![$0] } |
197 | "#, | 197 | "#, |
198 | ); | 198 | ); |
199 | 199 | ||
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/tests.rs index b0a4b2026..97298ff27 100644 --- a/crates/ide_completion/src/test_utils.rs +++ b/crates/ide_completion/src/tests.rs | |||
@@ -1,4 +1,16 @@ | |||
1 | //! Runs completion for testing purposes. | 1 | //! Tests and test utilities for completions. |
2 | //! | ||
3 | //! Most tests live in this module or its submodules unless for very specific completions like | ||
4 | //! `attributes` or `lifetimes` where the completed concept is a distinct thing. | ||
5 | //! Notable examples for completions that are being tested in this module's submodule are paths. | ||
6 | |||
7 | mod item_list; | ||
8 | mod use_tree; | ||
9 | mod items; | ||
10 | mod pattern; | ||
11 | mod type_pos; | ||
12 | |||
13 | use std::mem; | ||
2 | 14 | ||
3 | use hir::{PrefixKind, Semantics}; | 15 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 16 | use ide_db::{ |
@@ -28,9 +40,27 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
28 | prefix_kind: PrefixKind::Plain, | 40 | prefix_kind: PrefixKind::Plain, |
29 | enforce_granularity: true, | 41 | enforce_granularity: true, |
30 | group: true, | 42 | group: true, |
43 | skip_glob_imports: true, | ||
31 | }, | 44 | }, |
32 | }; | 45 | }; |
33 | 46 | ||
47 | pub(crate) fn completion_list(code: &str) -> String { | ||
48 | completion_list_with_config(TEST_CONFIG, code) | ||
49 | } | ||
50 | |||
51 | fn completion_list_with_config(config: CompletionConfig, code: &str) -> String { | ||
52 | // filter out all but one builtintype completion for smaller test outputs | ||
53 | let items = get_all_items(config, code); | ||
54 | let mut bt_seen = false; | ||
55 | let items = items | ||
56 | .into_iter() | ||
57 | .filter(|it| { | ||
58 | it.completion_kind != CompletionKind::BuiltinType || !mem::replace(&mut bt_seen, true) | ||
59 | }) | ||
60 | .collect(); | ||
61 | render_completion_list(items) | ||
62 | } | ||
63 | |||
34 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. | 64 | /// Creates analysis from a multi-file fixture, returns positions marked with $0. |
35 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 65 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { |
36 | let change_fixture = ChangeFixture::parse(ra_fixture); | 66 | let change_fixture = ChangeFixture::parse(ra_fixture); |
@@ -57,24 +87,27 @@ pub(crate) fn do_completion_with_config( | |||
57 | .collect() | 87 | .collect() |
58 | } | 88 | } |
59 | 89 | ||
60 | pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { | 90 | pub(crate) fn filtered_completion_list(code: &str, kind: CompletionKind) -> String { |
61 | completion_list_with_config(TEST_CONFIG, code, kind) | 91 | filtered_completion_list_with_config(TEST_CONFIG, code, kind) |
62 | } | 92 | } |
63 | 93 | ||
64 | pub(crate) fn completion_list_with_config( | 94 | pub(crate) fn filtered_completion_list_with_config( |
65 | config: CompletionConfig, | 95 | config: CompletionConfig, |
66 | code: &str, | 96 | code: &str, |
67 | kind: CompletionKind, | 97 | kind: CompletionKind, |
68 | ) -> String { | 98 | ) -> String { |
69 | let kind_completions: Vec<CompletionItem> = | 99 | let kind_completions: Vec<CompletionItem> = |
70 | get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); | 100 | get_all_items(config, code).into_iter().filter(|c| c.completion_kind == kind).collect(); |
71 | let label_width = kind_completions | 101 | render_completion_list(kind_completions) |
72 | .iter() | 102 | } |
73 | .map(|it| monospace_width(it.label())) | 103 | |
74 | .max() | 104 | fn render_completion_list(completions: Vec<CompletionItem>) -> String { |
75 | .unwrap_or_default() | 105 | fn monospace_width(s: &str) -> usize { |
76 | .min(16); | 106 | s.chars().count() |
77 | kind_completions | 107 | } |
108 | let label_width = | ||
109 | completions.iter().map(|it| monospace_width(it.label())).max().unwrap_or_default().min(16); | ||
110 | completions | ||
78 | .into_iter() | 111 | .into_iter() |
79 | .map(|it| { | 112 | .map(|it| { |
80 | let tag = it.kind().unwrap().tag(); | 113 | let tag = it.kind().unwrap().tag(); |
@@ -93,10 +126,6 @@ pub(crate) fn completion_list_with_config( | |||
93 | .collect() | 126 | .collect() |
94 | } | 127 | } |
95 | 128 | ||
96 | fn monospace_width(s: &str) -> usize { | ||
97 | s.chars().count() | ||
98 | } | ||
99 | |||
100 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 129 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
101 | check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) | 130 | check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) |
102 | } | 131 | } |
@@ -152,3 +181,18 @@ pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<Complet | |||
152 | let (db, position) = position(code); | 181 | let (db, position) = position(code); |
153 | crate::completions(&db, &config, position).unwrap().into() | 182 | crate::completions(&db, &config, position).unwrap().into() |
154 | } | 183 | } |
184 | |||
185 | fn check_no_completion(ra_fixture: &str) { | ||
186 | let (db, position) = position(ra_fixture); | ||
187 | |||
188 | assert!( | ||
189 | crate::completions(&db, &TEST_CONFIG, position).is_none(), | ||
190 | "Completions were generated, but weren't expected" | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn test_no_completions_required() { | ||
196 | cov_mark::check!(no_completion_required); | ||
197 | check_no_completion(r#"fn foo() { for i i$0 }"#); | ||
198 | } | ||
diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs new file mode 100644 index 000000000..7c124ac37 --- /dev/null +++ b/crates/ide_completion/src/tests/item_list.rs | |||
@@ -0,0 +1,223 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | |||
3 | use crate::tests::completion_list; | ||
4 | |||
5 | fn check(ra_fixture: &str, expect: Expect) { | ||
6 | let base = r#"#[rustc_builtin_macro] | ||
7 | pub macro Clone {} | ||
8 | enum Enum { Variant } | ||
9 | struct Struct {} | ||
10 | #[macro_export] | ||
11 | macro_rules! foo {} | ||
12 | mod bar {} | ||
13 | const CONST: () = (); | ||
14 | trait Trait {} | ||
15 | "#; | ||
16 | let actual = completion_list(&format!("{}{}", base, ra_fixture)); | ||
17 | expect.assert_eq(&actual) | ||
18 | } | ||
19 | |||
20 | #[test] | ||
21 | fn in_mod_item_list() { | ||
22 | check( | ||
23 | r#"mod tests { $0 }"#, | ||
24 | expect![[r##" | ||
25 | kw pub(crate) | ||
26 | kw pub | ||
27 | kw unsafe | ||
28 | kw fn | ||
29 | kw const | ||
30 | kw type | ||
31 | kw impl | ||
32 | kw extern | ||
33 | kw use | ||
34 | kw trait | ||
35 | kw static | ||
36 | kw mod | ||
37 | kw enum | ||
38 | kw struct | ||
39 | kw union | ||
40 | sn tmod (Test module) | ||
41 | sn tfn (Test function) | ||
42 | sn macro_rules | ||
43 | ma foo!(…) #[macro_export] macro_rules! foo | ||
44 | "##]], | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn in_source_file_item_list() { | ||
50 | check( | ||
51 | r#"$0"#, | ||
52 | expect![[r##" | ||
53 | kw pub(crate) | ||
54 | kw pub | ||
55 | kw unsafe | ||
56 | kw fn | ||
57 | kw const | ||
58 | kw type | ||
59 | kw impl | ||
60 | kw extern | ||
61 | kw use | ||
62 | kw trait | ||
63 | kw static | ||
64 | kw mod | ||
65 | kw enum | ||
66 | kw struct | ||
67 | kw union | ||
68 | sn tmod (Test module) | ||
69 | sn tfn (Test function) | ||
70 | sn macro_rules | ||
71 | md bar | ||
72 | ma foo!(…) #[macro_export] macro_rules! foo | ||
73 | ma foo!(…) #[macro_export] macro_rules! foo | ||
74 | "##]], | ||
75 | ) | ||
76 | } | ||
77 | |||
78 | #[test] | ||
79 | fn in_item_list_after_attr() { | ||
80 | check( | ||
81 | r#"#[attr] $0"#, | ||
82 | expect![[r#" | ||
83 | kw pub(crate) | ||
84 | kw pub | ||
85 | kw unsafe | ||
86 | kw fn | ||
87 | kw const | ||
88 | kw type | ||
89 | kw impl | ||
90 | kw extern | ||
91 | kw use | ||
92 | kw trait | ||
93 | kw static | ||
94 | kw mod | ||
95 | kw enum | ||
96 | kw struct | ||
97 | kw union | ||
98 | sn tmod (Test module) | ||
99 | sn tfn (Test function) | ||
100 | sn macro_rules | ||
101 | "#]], | ||
102 | ) | ||
103 | } | ||
104 | |||
105 | #[test] | ||
106 | fn in_qualified_path() { | ||
107 | check( | ||
108 | r#"crate::$0"#, | ||
109 | expect![[r##" | ||
110 | kw pub(crate) | ||
111 | kw pub | ||
112 | kw unsafe | ||
113 | kw fn | ||
114 | kw const | ||
115 | kw type | ||
116 | kw impl | ||
117 | kw extern | ||
118 | kw use | ||
119 | kw trait | ||
120 | kw static | ||
121 | kw mod | ||
122 | kw enum | ||
123 | kw struct | ||
124 | kw union | ||
125 | md bar | ||
126 | ma foo!(…) #[macro_export] macro_rules! foo | ||
127 | "##]], | ||
128 | ) | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn after_unsafe_token() { | ||
133 | check( | ||
134 | r#"unsafe $0"#, | ||
135 | expect![[r#" | ||
136 | kw fn | ||
137 | kw trait | ||
138 | kw impl | ||
139 | "#]], | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn after_visibility() { | ||
145 | check( | ||
146 | r#"pub $0"#, | ||
147 | expect![[r#" | ||
148 | kw unsafe | ||
149 | kw fn | ||
150 | kw const | ||
151 | kw type | ||
152 | kw use | ||
153 | kw trait | ||
154 | kw static | ||
155 | kw mod | ||
156 | kw enum | ||
157 | kw struct | ||
158 | kw union | ||
159 | "#]], | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn after_visibility_unsafe() { | ||
165 | // FIXME this shouldn't show `impl` | ||
166 | check( | ||
167 | r#"pub unsafe $0"#, | ||
168 | expect![[r#" | ||
169 | kw fn | ||
170 | kw trait | ||
171 | kw impl | ||
172 | "#]], | ||
173 | ); | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn in_impl_assoc_item_list() { | ||
178 | check( | ||
179 | r#"impl Struct { $0 }"#, | ||
180 | expect![[r##" | ||
181 | kw pub(crate) | ||
182 | kw pub | ||
183 | kw unsafe | ||
184 | kw fn | ||
185 | kw const | ||
186 | kw type | ||
187 | md bar | ||
188 | ma foo!(…) #[macro_export] macro_rules! foo | ||
189 | ma foo!(…) #[macro_export] macro_rules! foo | ||
190 | "##]], | ||
191 | ) | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn in_impl_assoc_item_list_after_attr() { | ||
196 | check( | ||
197 | r#"impl Struct { #[attr] $0 }"#, | ||
198 | expect![[r#" | ||
199 | kw pub(crate) | ||
200 | kw pub | ||
201 | kw unsafe | ||
202 | kw fn | ||
203 | kw const | ||
204 | kw type | ||
205 | "#]], | ||
206 | ) | ||
207 | } | ||
208 | |||
209 | #[test] | ||
210 | fn in_trait_assoc_item_list() { | ||
211 | check( | ||
212 | r"trait Foo { $0 }", | ||
213 | expect![[r##" | ||
214 | kw unsafe | ||
215 | kw fn | ||
216 | kw const | ||
217 | kw type | ||
218 | md bar | ||
219 | ma foo!(…) #[macro_export] macro_rules! foo | ||
220 | ma foo!(…) #[macro_export] macro_rules! foo | ||
221 | "##]], | ||
222 | ); | ||
223 | } | ||
diff --git a/crates/ide_completion/src/tests/items.rs b/crates/ide_completion/src/tests/items.rs new file mode 100644 index 000000000..b98baffd6 --- /dev/null +++ b/crates/ide_completion/src/tests/items.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | //! Completions tests for item specifics overall. | ||
2 | //! | ||
3 | //! Except for use items which are tested in [super::use_tree] and mod declarations with are tested | ||
4 | //! in [crate::completions::mod_]. | ||
5 | use expect_test::{expect, Expect}; | ||
6 | |||
7 | use crate::tests::completion_list; | ||
8 | |||
9 | fn check(ra_fixture: &str, expect: Expect) { | ||
10 | let base = r#"#[rustc_builtin_macro] | ||
11 | pub macro Clone {} | ||
12 | enum Enum { Variant } | ||
13 | struct Struct {} | ||
14 | #[macro_export] | ||
15 | macro_rules! foo {} | ||
16 | mod bar {} | ||
17 | const CONST: () = (); | ||
18 | trait Trait {} | ||
19 | "#; | ||
20 | let actual = completion_list(&format!("{}{}", base, ra_fixture)); | ||
21 | expect.assert_eq(&actual) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn target_type_or_trait_in_impl_block() { | ||
26 | check( | ||
27 | r#" | ||
28 | impl Tra$0 | ||
29 | "#, | ||
30 | expect![[r##" | ||
31 | tt Trait | ||
32 | en Enum | ||
33 | st Struct | ||
34 | md bar | ||
35 | ma foo!(…) #[macro_export] macro_rules! foo | ||
36 | ma foo!(…) #[macro_export] macro_rules! foo | ||
37 | bt u32 | ||
38 | "##]], | ||
39 | ) | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn target_type_in_trait_impl_block() { | ||
44 | check( | ||
45 | r#" | ||
46 | impl Trait for Str$0 | ||
47 | "#, | ||
48 | expect![[r##" | ||
49 | tt Trait | ||
50 | en Enum | ||
51 | st Struct | ||
52 | md bar | ||
53 | ma foo!(…) #[macro_export] macro_rules! foo | ||
54 | ma foo!(…) #[macro_export] macro_rules! foo | ||
55 | bt u32 | ||
56 | "##]], | ||
57 | ) | ||
58 | } | ||
59 | |||
60 | #[test] | ||
61 | fn after_trait_name_in_trait_def() { | ||
62 | check( | ||
63 | r"trait A $0", | ||
64 | expect![[r#" | ||
65 | kw where | ||
66 | "#]], | ||
67 | ); | ||
68 | } | ||
69 | |||
70 | #[test] | ||
71 | fn after_trait_or_target_name_in_impl() { | ||
72 | check( | ||
73 | r"impl Trait $0", | ||
74 | expect![[r#" | ||
75 | kw where | ||
76 | kw for | ||
77 | "#]], | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn before_record_field() { | ||
83 | check( | ||
84 | r#" | ||
85 | struct Foo { | ||
86 | $0 | ||
87 | pub f: i32, | ||
88 | } | ||
89 | "#, | ||
90 | expect![[r#" | ||
91 | kw pub(crate) | ||
92 | kw pub | ||
93 | "#]], | ||
94 | ) | ||
95 | } | ||
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs new file mode 100644 index 000000000..1ad5ccd97 --- /dev/null +++ b/crates/ide_completion/src/tests/pattern.rs | |||
@@ -0,0 +1,348 @@ | |||
1 | //! Completions tests for pattern position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check(ra_fixture: &str, expect: Expect) { | ||
7 | let actual = completion_list(ra_fixture); | ||
8 | expect.assert_eq(&actual) | ||
9 | } | ||
10 | |||
11 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
12 | let base = r#" | ||
13 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
14 | use self::Enum::TupleV; | ||
15 | mod module {} | ||
16 | |||
17 | static STATIC: Unit = Unit; | ||
18 | const CONST: Unit = Unit; | ||
19 | struct Record { field: u32 } | ||
20 | struct Tuple(u32); | ||
21 | struct Unit | ||
22 | macro_rules! makro {} | ||
23 | "#; | ||
24 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
25 | expect.assert_eq(&actual) | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn ident_rebind_pat() { | ||
30 | check( | ||
31 | r#" | ||
32 | fn quux() { | ||
33 | let en$0 @ x | ||
34 | } | ||
35 | "#, | ||
36 | expect![[r#" | ||
37 | kw mut | ||
38 | "#]], | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn ident_ref_pat() { | ||
44 | check( | ||
45 | r#" | ||
46 | fn quux() { | ||
47 | let ref en$0 | ||
48 | } | ||
49 | "#, | ||
50 | expect![[r#" | ||
51 | kw mut | ||
52 | "#]], | ||
53 | ); | ||
54 | check( | ||
55 | r#" | ||
56 | fn quux() { | ||
57 | let ref en$0 @ x | ||
58 | } | ||
59 | "#, | ||
60 | expect![[r#" | ||
61 | kw mut | ||
62 | "#]], | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn ident_ref_mut_pat() { | ||
68 | // FIXME mut is already here, don't complete it again | ||
69 | check( | ||
70 | r#" | ||
71 | fn quux() { | ||
72 | let ref mut en$0 | ||
73 | } | ||
74 | "#, | ||
75 | expect![[r#" | ||
76 | kw mut | ||
77 | "#]], | ||
78 | ); | ||
79 | check( | ||
80 | r#" | ||
81 | fn quux() { | ||
82 | let ref mut en$0 @ x | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | kw mut | ||
87 | "#]], | ||
88 | ); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn ref_pat() { | ||
93 | check( | ||
94 | r#" | ||
95 | fn quux() { | ||
96 | let &en$0 | ||
97 | } | ||
98 | "#, | ||
99 | expect![[r#" | ||
100 | kw mut | ||
101 | "#]], | ||
102 | ); | ||
103 | // FIXME mut is already here, don't complete it again | ||
104 | check( | ||
105 | r#" | ||
106 | fn quux() { | ||
107 | let &mut en$0 | ||
108 | } | ||
109 | "#, | ||
110 | expect![[r#" | ||
111 | kw mut | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn refutable() { | ||
118 | check_with( | ||
119 | r#" | ||
120 | fn foo() { | ||
121 | if let a$0 | ||
122 | } | ||
123 | "#, | ||
124 | expect![[r#" | ||
125 | kw mut | ||
126 | bn Record Record { field$1 }$0 | ||
127 | st Record | ||
128 | en Enum | ||
129 | bn Tuple Tuple($1)$0 | ||
130 | st Tuple | ||
131 | md module | ||
132 | bn TupleV TupleV($1)$0 | ||
133 | ev TupleV | ||
134 | st Unit | ||
135 | ct CONST | ||
136 | ma makro!(…) macro_rules! makro | ||
137 | "#]], | ||
138 | ); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn irrefutable() { | ||
143 | check_with( | ||
144 | r#" | ||
145 | fn foo() { | ||
146 | let a$0 | ||
147 | } | ||
148 | "#, | ||
149 | expect![[r#" | ||
150 | kw mut | ||
151 | bn Record Record { field$1 }$0 | ||
152 | st Record | ||
153 | bn Tuple Tuple($1)$0 | ||
154 | st Tuple | ||
155 | st Unit | ||
156 | ma makro!(…) macro_rules! makro | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn in_param() { | ||
163 | check_with( | ||
164 | r#" | ||
165 | fn foo(a$0) { | ||
166 | } | ||
167 | "#, | ||
168 | expect![[r#" | ||
169 | kw mut | ||
170 | bn Record Record { field$1 }: Record$0 | ||
171 | st Record | ||
172 | bn Tuple Tuple($1): Tuple$0 | ||
173 | st Tuple | ||
174 | st Unit | ||
175 | ma makro!(…) macro_rules! makro | ||
176 | "#]], | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn only_fn_like_macros() { | ||
182 | check( | ||
183 | r#" | ||
184 | macro_rules! m { ($e:expr) => { $e } } | ||
185 | |||
186 | #[rustc_builtin_macro] | ||
187 | macro Clone {} | ||
188 | |||
189 | fn foo() { | ||
190 | let x$0 | ||
191 | } | ||
192 | "#, | ||
193 | expect![[r#" | ||
194 | kw mut | ||
195 | ma m!(…) macro_rules! m | ||
196 | "#]], | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn in_simple_macro_call() { | ||
202 | check( | ||
203 | r#" | ||
204 | macro_rules! m { ($e:expr) => { $e } } | ||
205 | enum E { X } | ||
206 | |||
207 | fn foo() { | ||
208 | m!(match E::X { a$0 }) | ||
209 | } | ||
210 | "#, | ||
211 | expect![[r#" | ||
212 | kw mut | ||
213 | ev E::X () | ||
214 | en E | ||
215 | ma m!(…) macro_rules! m | ||
216 | "#]], | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn omits_private_fields_pat() { | ||
222 | check( | ||
223 | r#" | ||
224 | mod foo { | ||
225 | pub struct Record { pub field: i32, _field: i32 } | ||
226 | pub struct Tuple(pub u32, u32); | ||
227 | pub struct Invisible(u32, u32); | ||
228 | } | ||
229 | use foo::*; | ||
230 | |||
231 | fn outer() { | ||
232 | if let a$0 | ||
233 | } | ||
234 | "#, | ||
235 | expect![[r#" | ||
236 | kw mut | ||
237 | bn Record Record { field$1, .. }$0 | ||
238 | st Record | ||
239 | bn Tuple Tuple($1, ..)$0 | ||
240 | st Tuple | ||
241 | st Invisible | ||
242 | md foo | ||
243 | "#]], | ||
244 | ) | ||
245 | } | ||
246 | |||
247 | // #[test] | ||
248 | // fn only_shows_ident_completion() { | ||
249 | // check_edit( | ||
250 | // "Foo", | ||
251 | // r#" | ||
252 | // struct Foo(i32); | ||
253 | // fn main() { | ||
254 | // match Foo(92) { | ||
255 | // a$0(92) => (), | ||
256 | // } | ||
257 | // } | ||
258 | // "#, | ||
259 | // r#" | ||
260 | // struct Foo(i32); | ||
261 | // fn main() { | ||
262 | // match Foo(92) { | ||
263 | // Foo(92) => (), | ||
264 | // } | ||
265 | // } | ||
266 | // "#, | ||
267 | // ); | ||
268 | // } | ||
269 | |||
270 | #[test] | ||
271 | fn completes_self_pats() { | ||
272 | check( | ||
273 | r#" | ||
274 | struct Foo(i32); | ||
275 | impl Foo { | ||
276 | fn foo() { | ||
277 | match Foo(0) { | ||
278 | a$0 | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | "#, | ||
283 | expect![[r#" | ||
284 | kw mut | ||
285 | bn Self Self($1)$0 | ||
286 | sp Self | ||
287 | bn Foo Foo($1)$0 | ||
288 | st Foo | ||
289 | "#]], | ||
290 | ) | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn completes_qualified_variant() { | ||
295 | check( | ||
296 | r#" | ||
297 | enum Foo { | ||
298 | Bar { baz: i32 } | ||
299 | } | ||
300 | impl Foo { | ||
301 | fn foo() { | ||
302 | match {Foo::Bar { baz: 0 }} { | ||
303 | B$0 | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | "#, | ||
308 | expect![[r#" | ||
309 | kw mut | ||
310 | bn Self::Bar Self::Bar { baz$1 }$0 | ||
311 | ev Self::Bar { baz: i32 } | ||
312 | bn Foo::Bar Foo::Bar { baz$1 }$0 | ||
313 | ev Foo::Bar { baz: i32 } | ||
314 | sp Self | ||
315 | en Foo | ||
316 | "#]], | ||
317 | ) | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn completes_in_record_field_pat() { | ||
322 | check( | ||
323 | r#" | ||
324 | struct Foo { bar: Bar } | ||
325 | struct Bar(u32); | ||
326 | fn outer(Foo { bar: $0 }: Foo) {} | ||
327 | "#, | ||
328 | expect![[r#" | ||
329 | kw mut | ||
330 | bn Foo Foo { bar$1 }$0 | ||
331 | st Foo | ||
332 | bn Bar Bar($1)$0 | ||
333 | st Bar | ||
334 | "#]], | ||
335 | ) | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn skips_in_record_field_pat_name() { | ||
340 | check( | ||
341 | r#" | ||
342 | struct Foo { bar: Bar } | ||
343 | struct Bar(u32); | ||
344 | fn outer(Foo { bar$0 }: Foo) {} | ||
345 | "#, | ||
346 | expect![[r#""#]], | ||
347 | ) | ||
348 | } | ||
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs new file mode 100644 index 000000000..1ab47b27e --- /dev/null +++ b/crates/ide_completion/src/tests/type_pos.rs | |||
@@ -0,0 +1,177 @@ | |||
1 | //! Completions tests for type position. | ||
2 | use expect_test::{expect, Expect}; | ||
3 | |||
4 | use crate::tests::completion_list; | ||
5 | |||
6 | fn check_with(ra_fixture: &str, expect: Expect) { | ||
7 | let base = r#" | ||
8 | enum Enum { TupleV(u32), RecordV { field: u32 }, UnitV } | ||
9 | use self::Enum::TupleV; | ||
10 | mod module {} | ||
11 | |||
12 | trait Trait {} | ||
13 | static STATIC: Unit = Unit; | ||
14 | const CONST: Unit = Unit; | ||
15 | struct Record { field: u32 } | ||
16 | struct Tuple(u32); | ||
17 | struct Unit | ||
18 | macro_rules! makro {} | ||
19 | "#; | ||
20 | let actual = completion_list(&format!("{}\n{}", base, ra_fixture)); | ||
21 | expect.assert_eq(&actual) | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn record_field_ty() { | ||
26 | check_with( | ||
27 | r#" | ||
28 | struct Foo<'lt, T, const C: usize> { | ||
29 | f: $0 | ||
30 | } | ||
31 | "#, | ||
32 | expect![[r#" | ||
33 | sp Self | ||
34 | tp T | ||
35 | tt Trait | ||
36 | en Enum | ||
37 | st Record | ||
38 | st Tuple | ||
39 | md module | ||
40 | st Foo<…> | ||
41 | st Unit | ||
42 | ma makro!(…) macro_rules! makro | ||
43 | bt u32 | ||
44 | "#]], | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | #[test] | ||
49 | fn tuple_struct_field() { | ||
50 | check_with( | ||
51 | r#" | ||
52 | struct Foo<'lt, T, const C: usize>(f$0); | ||
53 | "#, | ||
54 | expect![[r#" | ||
55 | kw pub(crate) | ||
56 | kw pub | ||
57 | sp Self | ||
58 | tp T | ||
59 | tt Trait | ||
60 | en Enum | ||
61 | st Record | ||
62 | st Tuple | ||
63 | md module | ||
64 | st Foo<…> | ||
65 | st Unit | ||
66 | ma makro!(…) macro_rules! makro | ||
67 | bt u32 | ||
68 | "#]], | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn fn_return_type() { | ||
74 | check_with( | ||
75 | r#" | ||
76 | fn x<'lt, T, const C: usize>() -> $0 | ||
77 | "#, | ||
78 | expect![[r#" | ||
79 | tp T | ||
80 | tt Trait | ||
81 | en Enum | ||
82 | st Record | ||
83 | st Tuple | ||
84 | md module | ||
85 | st Unit | ||
86 | ma makro!(…) macro_rules! makro | ||
87 | bt u32 | ||
88 | "#]], | ||
89 | ); | ||
90 | } | ||
91 | |||
92 | #[test] | ||
93 | fn body_type_pos() { | ||
94 | check_with( | ||
95 | r#" | ||
96 | fn foo<'lt, T, const C: usize>() { | ||
97 | let local = (); | ||
98 | let _: $0; | ||
99 | } | ||
100 | "#, | ||
101 | expect![[r#" | ||
102 | tp T | ||
103 | tt Trait | ||
104 | en Enum | ||
105 | st Record | ||
106 | st Tuple | ||
107 | md module | ||
108 | st Unit | ||
109 | ma makro!(…) macro_rules! makro | ||
110 | bt u32 | ||
111 | "#]], | ||
112 | ); | ||
113 | check_with( | ||
114 | r#" | ||
115 | fn foo<'lt, T, const C: usize>() { | ||
116 | let local = (); | ||
117 | let _: self::$0; | ||
118 | } | ||
119 | "#, | ||
120 | expect![[r#" | ||
121 | tt Trait | ||
122 | en Enum | ||
123 | st Record | ||
124 | st Tuple | ||
125 | md module | ||
126 | st Unit | ||
127 | "#]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn completes_types_and_const_in_arg_list() { | ||
133 | // FIXME: we should complete the lifetime here for now | ||
134 | check_with( | ||
135 | r#" | ||
136 | trait Trait2 { | ||
137 | type Foo; | ||
138 | } | ||
139 | |||
140 | fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} | ||
141 | "#, | ||
142 | expect![[r#" | ||
143 | ta Foo = type Foo; | ||
144 | tp T | ||
145 | cp CONST_PARAM | ||
146 | tt Trait | ||
147 | en Enum | ||
148 | st Record | ||
149 | st Tuple | ||
150 | tt Trait2 | ||
151 | md module | ||
152 | st Unit | ||
153 | ct CONST | ||
154 | ma makro!(…) macro_rules! makro | ||
155 | bt u32 | ||
156 | "#]], | ||
157 | ); | ||
158 | check_with( | ||
159 | r#" | ||
160 | trait Trait2 { | ||
161 | type Foo; | ||
162 | } | ||
163 | |||
164 | fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {} | ||
165 | "#, | ||
166 | expect![[r#" | ||
167 | tt Trait | ||
168 | en Enum | ||
169 | st Record | ||
170 | st Tuple | ||
171 | tt Trait2 | ||
172 | md module | ||
173 | st Unit | ||
174 | ct CONST | ||
175 | "#]], | ||
176 | ); | ||
177 | } | ||
diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs new file mode 100644 index 000000000..7e6748ccc --- /dev/null +++ b/crates/ide_completion/src/tests/use_tree.rs | |||
@@ -0,0 +1,255 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | |||
3 | use crate::tests::completion_list; | ||
4 | |||
5 | fn check(ra_fixture: &str, expect: Expect) { | ||
6 | let actual = completion_list(ra_fixture); | ||
7 | expect.assert_eq(&actual) | ||
8 | } | ||
9 | |||
10 | #[test] | ||
11 | fn use_tree_start() { | ||
12 | cov_mark::check!(only_completes_modules_in_import); | ||
13 | check( | ||
14 | r#" | ||
15 | //- /lib.rs crate:main deps:other_crate | ||
16 | use f$0 | ||
17 | |||
18 | struct Foo; | ||
19 | mod foo {} | ||
20 | //- /other_crate/lib.rs crate:other_crate | ||
21 | // nothing here | ||
22 | "#, | ||
23 | expect![[r#" | ||
24 | kw crate:: | ||
25 | kw self:: | ||
26 | kw super:: | ||
27 | md foo | ||
28 | md other_crate | ||
29 | "#]], | ||
30 | ); | ||
31 | } | ||
32 | |||
33 | #[test] | ||
34 | fn dont_complete_current_use() { | ||
35 | cov_mark::check!(dont_complete_current_use); | ||
36 | check(r#"use self::foo$0;"#, expect![[r#""#]]); | ||
37 | check( | ||
38 | r#" | ||
39 | mod foo { pub struct S; } | ||
40 | use self::{foo::*, bar$0}; | ||
41 | "#, | ||
42 | expect![[r#" | ||
43 | kw self | ||
44 | st S | ||
45 | md foo | ||
46 | "#]], | ||
47 | ); | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn nested_use_tree() { | ||
52 | check( | ||
53 | r#" | ||
54 | mod foo { | ||
55 | pub mod bar { | ||
56 | pub struct FooBar; | ||
57 | } | ||
58 | } | ||
59 | use foo::{bar::$0} | ||
60 | "#, | ||
61 | expect![[r#" | ||
62 | st FooBar | ||
63 | "#]], | ||
64 | ); | ||
65 | check( | ||
66 | r#" | ||
67 | mod foo { | ||
68 | pub mod bar { | ||
69 | pub struct FooBar; | ||
70 | } | ||
71 | } | ||
72 | use foo::{$0} | ||
73 | "#, | ||
74 | expect![[r#" | ||
75 | kw self | ||
76 | md bar | ||
77 | "#]], | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn deeply_nested_use_tree() { | ||
83 | check( | ||
84 | r#" | ||
85 | mod foo { | ||
86 | pub mod bar { | ||
87 | pub mod baz { | ||
88 | pub struct FooBarBaz; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | use foo::{bar::{baz::$0}} | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | st FooBarBaz | ||
96 | "#]], | ||
97 | ); | ||
98 | check( | ||
99 | r#" | ||
100 | mod foo { | ||
101 | pub mod bar { | ||
102 | pub mod baz { | ||
103 | pub struct FooBarBaz; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | use foo::{bar::{$0}} | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | kw self | ||
111 | md baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn plain_qualified_use_tree() { | ||
118 | check( | ||
119 | r#" | ||
120 | use foo::$0 | ||
121 | |||
122 | mod foo { | ||
123 | struct Private; | ||
124 | pub struct Foo; | ||
125 | } | ||
126 | struct Bar; | ||
127 | "#, | ||
128 | expect![[r#" | ||
129 | st Foo | ||
130 | "#]], | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn self_qualified_use_tree() { | ||
136 | check( | ||
137 | r#" | ||
138 | use self::$0 | ||
139 | |||
140 | mod foo {} | ||
141 | struct Bar; | ||
142 | "#, | ||
143 | expect![[r#" | ||
144 | md foo | ||
145 | st Bar | ||
146 | "#]], | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn super_qualified_use_tree() { | ||
152 | check( | ||
153 | r#" | ||
154 | mod bar { | ||
155 | use super::$0 | ||
156 | } | ||
157 | |||
158 | mod foo {} | ||
159 | struct Bar; | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | kw super:: | ||
163 | st Bar | ||
164 | md bar | ||
165 | md foo | ||
166 | "#]], | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn super_super_qualified_use_tree() { | ||
172 | check( | ||
173 | r#" | ||
174 | mod a { | ||
175 | const A: usize = 0; | ||
176 | mod b { | ||
177 | const B: usize = 0; | ||
178 | mod c { use super::super::$0 } | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | expect![[r#" | ||
183 | kw super:: | ||
184 | md b | ||
185 | ct A | ||
186 | "#]], | ||
187 | ); | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn crate_qualified_use_tree() { | ||
192 | check( | ||
193 | r#" | ||
194 | use crate::$0 | ||
195 | |||
196 | mod foo {} | ||
197 | struct Bar; | ||
198 | "#, | ||
199 | expect![[r#" | ||
200 | md foo | ||
201 | st Bar | ||
202 | "#]], | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn extern_crate_qualified_use_tree() { | ||
208 | check( | ||
209 | r#" | ||
210 | //- /lib.rs crate:main deps:other_crate | ||
211 | use other_crate::$0 | ||
212 | //- /other_crate/lib.rs crate:other_crate | ||
213 | pub struct Foo; | ||
214 | pub mod foo {} | ||
215 | "#, | ||
216 | expect![[r#" | ||
217 | st Foo | ||
218 | md foo | ||
219 | "#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn pub_use_tree() { | ||
225 | check( | ||
226 | r#" | ||
227 | pub struct X; | ||
228 | pub mod bar {} | ||
229 | pub use $0; | ||
230 | "#, | ||
231 | expect![[r#" | ||
232 | kw crate:: | ||
233 | kw self:: | ||
234 | kw super:: | ||
235 | md bar | ||
236 | "#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn use_tree_braces_at_start() { | ||
242 | check( | ||
243 | r#" | ||
244 | struct X; | ||
245 | mod bar {} | ||
246 | use {$0}; | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | kw crate:: | ||
250 | kw self:: | ||
251 | kw super:: | ||
252 | md bar | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
diff --git a/crates/ide_db/src/assists.rs b/crates/ide_db/src/assists.rs new file mode 100644 index 000000000..7881d8369 --- /dev/null +++ b/crates/ide_db/src/assists.rs | |||
@@ -0,0 +1,136 @@ | |||
1 | //! This module defines the `Assist` data structure. The actual assist live in | ||
2 | //! the `ide_assists` downstream crate. We want to define the data structures in | ||
3 | //! this low-level crate though, because `ide_diagnostics` also need them | ||
4 | //! (fixits for diagnostics and assists are the same thing under the hood). We | ||
5 | //! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so | ||
6 | //! we pull the common definitions upstream, to this crate. | ||
7 | |||
8 | use std::str::FromStr; | ||
9 | |||
10 | use syntax::TextRange; | ||
11 | |||
12 | use crate::{label::Label, source_change::SourceChange}; | ||
13 | |||
14 | #[derive(Debug, Clone)] | ||
15 | pub struct Assist { | ||
16 | pub id: AssistId, | ||
17 | /// Short description of the assist, as shown in the UI. | ||
18 | pub label: Label, | ||
19 | pub group: Option<GroupLabel>, | ||
20 | /// Target ranges are used to sort assists: the smaller the target range, | ||
21 | /// the more specific assist is, and so it should be sorted first. | ||
22 | pub target: TextRange, | ||
23 | /// Computing source change sometimes is much more costly then computing the | ||
24 | /// other fields. Additionally, the actual change is not required to show | ||
25 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
26 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
27 | /// or without source change. We could (and in fact, used to) distinguish | ||
28 | /// between resolved and unresolved assists at the type level, but this is | ||
29 | /// cumbersome, especially if you want to embed an assist into another data | ||
30 | /// structure, such as a diagnostic. | ||
31 | pub source_change: Option<SourceChange>, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
35 | pub enum AssistKind { | ||
36 | // FIXME: does the None variant make sense? Probably not. | ||
37 | None, | ||
38 | |||
39 | QuickFix, | ||
40 | Generate, | ||
41 | Refactor, | ||
42 | RefactorExtract, | ||
43 | RefactorInline, | ||
44 | RefactorRewrite, | ||
45 | } | ||
46 | |||
47 | impl AssistKind { | ||
48 | pub fn contains(self, other: AssistKind) -> bool { | ||
49 | if self == other { | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | match self { | ||
54 | AssistKind::None | AssistKind::Generate => true, | ||
55 | AssistKind::Refactor => match other { | ||
56 | AssistKind::RefactorExtract | ||
57 | | AssistKind::RefactorInline | ||
58 | | AssistKind::RefactorRewrite => true, | ||
59 | _ => false, | ||
60 | }, | ||
61 | _ => false, | ||
62 | } | ||
63 | } | ||
64 | |||
65 | pub fn name(&self) -> &str { | ||
66 | match self { | ||
67 | AssistKind::None => "None", | ||
68 | AssistKind::QuickFix => "QuickFix", | ||
69 | AssistKind::Generate => "Generate", | ||
70 | AssistKind::Refactor => "Refactor", | ||
71 | AssistKind::RefactorExtract => "RefactorExtract", | ||
72 | AssistKind::RefactorInline => "RefactorInline", | ||
73 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl FromStr for AssistKind { | ||
79 | type Err = String; | ||
80 | |||
81 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
82 | match s { | ||
83 | "None" => Ok(AssistKind::None), | ||
84 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
85 | "Generate" => Ok(AssistKind::Generate), | ||
86 | "Refactor" => Ok(AssistKind::Refactor), | ||
87 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
88 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
89 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
90 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /// Unique identifier of the assist, should not be shown to the user | ||
96 | /// directly. | ||
97 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
98 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
99 | |||
100 | /// A way to control how many asssist to resolve during the assist resolution. | ||
101 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
102 | #[derive(Debug)] | ||
103 | pub enum AssistResolveStrategy { | ||
104 | /// No assists should be resolved. | ||
105 | None, | ||
106 | /// All assists should be resolved. | ||
107 | All, | ||
108 | /// Only a certain assist should be resolved. | ||
109 | Single(SingleResolve), | ||
110 | } | ||
111 | |||
112 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
113 | /// The original id object cannot be used due to a `'static` lifetime | ||
114 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
115 | #[derive(Debug)] | ||
116 | pub struct SingleResolve { | ||
117 | /// The id of the assist. | ||
118 | pub assist_id: String, | ||
119 | // The kind of the assist. | ||
120 | pub assist_kind: AssistKind, | ||
121 | } | ||
122 | |||
123 | impl AssistResolveStrategy { | ||
124 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
125 | match self { | ||
126 | AssistResolveStrategy::None => false, | ||
127 | AssistResolveStrategy::All => true, | ||
128 | AssistResolveStrategy::Single(single_resolve) => { | ||
129 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | #[derive(Clone, Debug)] | ||
136 | pub struct GroupLabel(pub String); | ||
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index 00900cdc2..d96028cbc 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -74,12 +74,19 @@ pub fn visit_file_defs( | |||
74 | /// somewhat similar to the known paths infra inside hir, but it different; We | 74 | /// somewhat similar to the known paths infra inside hir, but it different; We |
75 | /// want to make sure that IDE specific paths don't become interesting inside | 75 | /// want to make sure that IDE specific paths don't become interesting inside |
76 | /// the compiler itself as well. | 76 | /// the compiler itself as well. |
77 | /// | ||
78 | /// Note that, by default, rust-analyzer tests **do not** include core or std | ||
79 | /// libraries. If you are writing tests for functionality using [`FamousDefs`], | ||
80 | /// you'd want to include [minicore](test_utils::MiniCore) declaration at the | ||
81 | /// start of your tests: | ||
82 | /// | ||
83 | /// ``` | ||
84 | /// //- minicore: iterator, ord, derive | ||
85 | /// ``` | ||
77 | pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>); | 86 | pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>); |
78 | 87 | ||
79 | #[allow(non_snake_case)] | 88 | #[allow(non_snake_case)] |
80 | impl FamousDefs<'_, '_> { | 89 | impl FamousDefs<'_, '_> { |
81 | pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs"); | ||
82 | |||
83 | pub fn std(&self) -> Option<Crate> { | 90 | pub fn std(&self) -> Option<Crate> { |
84 | self.find_crate("std") | 91 | self.find_crate("std") |
85 | } | 92 | } |
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs deleted file mode 100644 index 312851966..000000000 --- a/crates/ide_db/src/helpers/famous_defs_fixture.rs +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | //- /libcore.rs crate:core | ||
2 | //! Signatures of traits, types and functions from the core lib for use in tests. | ||
3 | pub mod cmp { | ||
4 | |||
5 | pub trait Ord { | ||
6 | fn cmp(&self, other: &Self) -> Ordering; | ||
7 | fn max(self, other: Self) -> Self; | ||
8 | fn min(self, other: Self) -> Self; | ||
9 | fn clamp(self, min: Self, max: Self) -> Self; | ||
10 | } | ||
11 | } | ||
12 | |||
13 | pub mod convert { | ||
14 | pub trait From<T> { | ||
15 | fn from(t: T) -> Self; | ||
16 | } | ||
17 | |||
18 | pub trait Into<T> { | ||
19 | pub fn into(self) -> T; | ||
20 | } | ||
21 | } | ||
22 | |||
23 | pub mod default { | ||
24 | pub trait Default { | ||
25 | fn default() -> Self; | ||
26 | } | ||
27 | } | ||
28 | |||
29 | pub mod iter { | ||
30 | pub use self::traits::{collect::IntoIterator, iterator::Iterator}; | ||
31 | mod traits { | ||
32 | pub(crate) mod iterator { | ||
33 | use crate::option::Option; | ||
34 | pub trait Iterator { | ||
35 | type Item; | ||
36 | fn next(&mut self) -> Option<Self::Item>; | ||
37 | fn by_ref(&mut self) -> &mut Self { | ||
38 | self | ||
39 | } | ||
40 | fn take(self, n: usize) -> crate::iter::Take<Self> { | ||
41 | crate::iter::Take { inner: self } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl<I: Iterator> Iterator for &mut I { | ||
46 | type Item = I::Item; | ||
47 | fn next(&mut self) -> Option<I::Item> { | ||
48 | (**self).next() | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | pub(crate) mod collect { | ||
53 | pub trait IntoIterator { | ||
54 | type Item; | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub use self::sources::*; | ||
60 | pub(crate) mod sources { | ||
61 | use super::Iterator; | ||
62 | use crate::option::Option::{self, *}; | ||
63 | pub struct Repeat<A> { | ||
64 | element: A, | ||
65 | } | ||
66 | |||
67 | pub fn repeat<T>(elt: T) -> Repeat<T> { | ||
68 | Repeat { element: elt } | ||
69 | } | ||
70 | |||
71 | impl<A> Iterator for Repeat<A> { | ||
72 | type Item = A; | ||
73 | |||
74 | fn next(&mut self) -> Option<A> { | ||
75 | None | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | pub use self::adapters::*; | ||
81 | pub(crate) mod adapters { | ||
82 | use super::Iterator; | ||
83 | use crate::option::Option::{self, *}; | ||
84 | pub struct Take<I> { | ||
85 | pub(crate) inner: I, | ||
86 | } | ||
87 | impl<I> Iterator for Take<I> | ||
88 | where | ||
89 | I: Iterator, | ||
90 | { | ||
91 | type Item = <I as Iterator>::Item; | ||
92 | fn next(&mut self) -> Option<<I as Iterator>::Item> { | ||
93 | None | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | pub mod ops { | ||
100 | #[lang = "fn"] | ||
101 | pub trait Fn<Args>: FnMut<Args> { | ||
102 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
103 | } | ||
104 | |||
105 | #[lang = "fn_mut"] | ||
106 | pub trait FnMut<Args>: FnOnce<Args> { | ||
107 | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; | ||
108 | } | ||
109 | #[lang = "fn_once"] | ||
110 | pub trait FnOnce<Args> { | ||
111 | #[lang = "fn_once_output"] | ||
112 | type Output; | ||
113 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
114 | } | ||
115 | |||
116 | #[lang = "deref"] | ||
117 | pub trait Deref { | ||
118 | type Target: ?Sized; | ||
119 | fn deref(&self) -> &Self::Target; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | pub mod option { | ||
124 | pub enum Option<T> { | ||
125 | None, | ||
126 | Some(T), | ||
127 | } | ||
128 | } | ||
129 | |||
130 | pub mod prelude { | ||
131 | pub mod rust_2018 { | ||
132 | pub use crate::{ | ||
133 | cmp::Ord, | ||
134 | convert::{From, Into}, | ||
135 | default::Default, | ||
136 | iter::{IntoIterator, Iterator}, | ||
137 | ops::{Fn, FnMut, FnOnce}, | ||
138 | option::Option::{self, *}, | ||
139 | }; | ||
140 | } | ||
141 | } | ||
142 | #[prelude_import] | ||
143 | pub use prelude::rust_2018::*; | ||
144 | //- /libstd.rs crate:std deps:core | ||
145 | //! Signatures of traits, types and functions from the std lib for use in tests. | ||
146 | |||
147 | /// Docs for return_keyword | ||
148 | mod return_keyword {} | ||
149 | |||
150 | /// Docs for prim_str | ||
151 | mod prim_str {} | ||
152 | |||
153 | pub use core::ops; | ||
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 10bbafe77..e6b4832e7 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -5,7 +5,7 @@ use hir::Semantics; | |||
5 | use syntax::{ | 5 | use syntax::{ |
6 | algo, | 6 | algo, |
7 | ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner}, | 7 | ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner}, |
8 | ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, | 8 | match_ast, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
@@ -36,22 +36,39 @@ pub struct InsertUseConfig { | |||
36 | pub enforce_granularity: bool, | 36 | pub enforce_granularity: bool, |
37 | pub prefix_kind: PrefixKind, | 37 | pub prefix_kind: PrefixKind, |
38 | pub group: bool, | 38 | pub group: bool, |
39 | pub skip_glob_imports: bool, | ||
39 | } | 40 | } |
40 | 41 | ||
41 | #[derive(Debug, Clone)] | 42 | #[derive(Debug, Clone)] |
42 | pub enum ImportScope { | 43 | pub enum ImportScope { |
43 | File(ast::SourceFile), | 44 | File(ast::SourceFile), |
44 | Module(ast::ItemList), | 45 | Module(ast::ItemList), |
46 | Block(ast::BlockExpr), | ||
45 | } | 47 | } |
46 | 48 | ||
47 | impl ImportScope { | 49 | impl ImportScope { |
48 | pub fn from(syntax: SyntaxNode) -> Option<Self> { | 50 | fn from(syntax: SyntaxNode) -> Option<Self> { |
49 | if let Some(module) = ast::Module::cast(syntax.clone()) { | 51 | fn contains_cfg_attr(attrs: &dyn AttrsOwner) -> bool { |
50 | module.item_list().map(ImportScope::Module) | 52 | attrs |
51 | } else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) { | 53 | .attrs() |
52 | this.map(ImportScope::File) | 54 | .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg")) |
53 | } else { | 55 | } |
54 | ast::ItemList::cast(syntax).map(ImportScope::Module) | 56 | match_ast! { |
57 | match syntax { | ||
58 | ast::Module(module) => module.item_list().map(ImportScope::Module), | ||
59 | ast::SourceFile(file) => Some(ImportScope::File(file)), | ||
60 | ast::Fn(func) => contains_cfg_attr(&func).then(|| func.body().map(ImportScope::Block)).flatten(), | ||
61 | ast::Const(konst) => contains_cfg_attr(&konst).then(|| match konst.body()? { | ||
62 | ast::Expr::BlockExpr(block) => Some(block), | ||
63 | _ => None, | ||
64 | }).flatten().map(ImportScope::Block), | ||
65 | ast::Static(statik) => contains_cfg_attr(&statik).then(|| match statik.body()? { | ||
66 | ast::Expr::BlockExpr(block) => Some(block), | ||
67 | _ => None, | ||
68 | }).flatten().map(ImportScope::Block), | ||
69 | _ => None, | ||
70 | |||
71 | } | ||
55 | } | 72 | } |
56 | } | 73 | } |
57 | 74 | ||
@@ -72,6 +89,7 @@ impl ImportScope { | |||
72 | match self { | 89 | match self { |
73 | ImportScope::File(file) => file.syntax(), | 90 | ImportScope::File(file) => file.syntax(), |
74 | ImportScope::Module(item_list) => item_list.syntax(), | 91 | ImportScope::Module(item_list) => item_list.syntax(), |
92 | ImportScope::Block(block) => block.syntax(), | ||
75 | } | 93 | } |
76 | } | 94 | } |
77 | 95 | ||
@@ -79,6 +97,7 @@ impl ImportScope { | |||
79 | match self { | 97 | match self { |
80 | ImportScope::File(file) => ImportScope::File(file.clone_for_update()), | 98 | ImportScope::File(file) => ImportScope::File(file.clone_for_update()), |
81 | ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), | 99 | ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), |
100 | ImportScope::Block(block) => ImportScope::Block(block.clone_for_update()), | ||
82 | } | 101 | } |
83 | } | 102 | } |
84 | 103 | ||
@@ -95,6 +114,7 @@ impl ImportScope { | |||
95 | let mut use_stmts = match self { | 114 | let mut use_stmts = match self { |
96 | ImportScope::File(f) => f.items(), | 115 | ImportScope::File(f) => f.items(), |
97 | ImportScope::Module(m) => m.items(), | 116 | ImportScope::Module(m) => m.items(), |
117 | ImportScope::Block(b) => b.items(), | ||
98 | } | 118 | } |
99 | .filter_map(use_stmt); | 119 | .filter_map(use_stmt); |
100 | let mut res = ImportGranularityGuess::Unknown; | 120 | let mut res = ImportGranularityGuess::Unknown; |
@@ -153,7 +173,7 @@ enum ImportGranularityGuess { | |||
153 | } | 173 | } |
154 | 174 | ||
155 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 175 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
156 | pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { | 176 | pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { |
157 | let _p = profile::span("insert_use"); | 177 | let _p = profile::span("insert_use"); |
158 | let mut mb = match cfg.granularity { | 178 | let mut mb = match cfg.granularity { |
159 | ImportGranularity::Crate => Some(MergeBehavior::Crate), | 179 | ImportGranularity::Crate => Some(MergeBehavior::Crate), |
@@ -175,7 +195,10 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig | |||
175 | make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); | 195 | make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); |
176 | // merge into existing imports if possible | 196 | // merge into existing imports if possible |
177 | if let Some(mb) = mb { | 197 | if let Some(mb) = mb { |
178 | for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { | 198 | let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it)); |
199 | for existing_use in | ||
200 | scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter) | ||
201 | { | ||
179 | if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { | 202 | if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { |
180 | ted::replace(existing_use.syntax(), merged.syntax()); | 203 | ted::replace(existing_use.syntax(), merged.syntax()); |
181 | return; | 204 | return; |
@@ -315,28 +338,29 @@ fn insert_use_( | |||
315 | ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline()); | 338 | ted::insert(ted::Position::after(last_inner_element), make::tokens::single_newline()); |
316 | return; | 339 | return; |
317 | } | 340 | } |
318 | match scope { | 341 | let l_curly = match scope { |
319 | ImportScope::File(_) => { | 342 | ImportScope::File(_) => { |
320 | cov_mark::hit!(insert_group_empty_file); | 343 | cov_mark::hit!(insert_group_empty_file); |
321 | ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line()); | 344 | ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line()); |
322 | ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()) | 345 | ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()); |
346 | return; | ||
323 | } | 347 | } |
348 | // don't insert the imports before the item list/block expr's opening curly brace | ||
349 | ImportScope::Module(item_list) => item_list.l_curly_token(), | ||
324 | // don't insert the imports before the item list's opening curly brace | 350 | // don't insert the imports before the item list's opening curly brace |
325 | ImportScope::Module(item_list) => match item_list.l_curly_token() { | 351 | ImportScope::Block(block) => block.l_curly_token(), |
326 | Some(b) => { | 352 | }; |
327 | cov_mark::hit!(insert_group_empty_module); | 353 | match l_curly { |
328 | ted::insert(ted::Position::after(&b), make::tokens::single_newline()); | 354 | Some(b) => { |
329 | ted::insert(ted::Position::after(&b), use_item.syntax()); | 355 | cov_mark::hit!(insert_group_empty_module); |
330 | } | 356 | ted::insert(ted::Position::after(&b), make::tokens::single_newline()); |
331 | None => { | 357 | ted::insert(ted::Position::after(&b), use_item.syntax()); |
332 | // This should never happens, broken module syntax node | 358 | } |
333 | ted::insert( | 359 | None => { |
334 | ted::Position::first_child_of(scope_syntax), | 360 | // This should never happens, broken module syntax node |
335 | make::tokens::blank_line(), | 361 | ted::insert(ted::Position::first_child_of(scope_syntax), make::tokens::blank_line()); |
336 | ); | 362 | ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()); |
337 | ted::insert(ted::Position::first_child_of(scope_syntax), use_item.syntax()); | 363 | } |
338 | } | ||
339 | }, | ||
340 | } | 364 | } |
341 | } | 365 | } |
342 | 366 | ||
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 70b11bf81..01894630a 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -1,12 +1,63 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | 2 | ||
3 | use hir::PrefixKind; | 3 | use hir::PrefixKind; |
4 | use test_utils::assert_eq_text; | 4 | use test_utils::{assert_eq_text, extract_range_or_offset, CURSOR_MARKER}; |
5 | |||
6 | #[test] | ||
7 | fn respects_cfg_attr_fn() { | ||
8 | check( | ||
9 | r"bar::Bar", | ||
10 | r#" | ||
11 | #[cfg(test)] | ||
12 | fn foo() {$0} | ||
13 | "#, | ||
14 | r#" | ||
15 | #[cfg(test)] | ||
16 | fn foo() { | ||
17 | use bar::Bar; | ||
18 | } | ||
19 | "#, | ||
20 | ImportGranularity::Crate, | ||
21 | ); | ||
22 | } | ||
23 | |||
24 | #[test] | ||
25 | fn respects_cfg_attr_const() { | ||
26 | check( | ||
27 | r"bar::Bar", | ||
28 | r#" | ||
29 | #[cfg(test)] | ||
30 | const FOO: Bar = {$0}; | ||
31 | "#, | ||
32 | r#" | ||
33 | #[cfg(test)] | ||
34 | const FOO: Bar = { | ||
35 | use bar::Bar; | ||
36 | }; | ||
37 | "#, | ||
38 | ImportGranularity::Crate, | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn insert_skips_lone_glob_imports() { | ||
44 | check( | ||
45 | "use foo::baz::A", | ||
46 | r" | ||
47 | use foo::bar::*; | ||
48 | ", | ||
49 | r" | ||
50 | use foo::bar::*; | ||
51 | use foo::baz::A; | ||
52 | ", | ||
53 | ImportGranularity::Crate, | ||
54 | ); | ||
55 | } | ||
5 | 56 | ||
6 | #[test] | 57 | #[test] |
7 | fn insert_not_group() { | 58 | fn insert_not_group() { |
8 | cov_mark::check!(insert_no_grouping_last); | 59 | cov_mark::check!(insert_no_grouping_last); |
9 | check( | 60 | check_with_config( |
10 | "use external_crate2::bar::A", | 61 | "use external_crate2::bar::A", |
11 | r" | 62 | r" |
12 | use std::bar::B; | 63 | use std::bar::B; |
@@ -21,24 +72,32 @@ use crate::bar::A; | |||
21 | use self::bar::A; | 72 | use self::bar::A; |
22 | use super::bar::A; | 73 | use super::bar::A; |
23 | use external_crate2::bar::A;", | 74 | use external_crate2::bar::A;", |
24 | ImportGranularity::Item, | 75 | &InsertUseConfig { |
25 | false, | 76 | granularity: ImportGranularity::Item, |
26 | false, | 77 | enforce_granularity: true, |
78 | prefix_kind: PrefixKind::Plain, | ||
79 | group: false, | ||
80 | skip_glob_imports: true, | ||
81 | }, | ||
27 | ); | 82 | ); |
28 | } | 83 | } |
29 | 84 | ||
30 | #[test] | 85 | #[test] |
31 | fn insert_not_group_empty() { | 86 | fn insert_not_group_empty() { |
32 | cov_mark::check!(insert_no_grouping_last2); | 87 | cov_mark::check!(insert_no_grouping_last2); |
33 | check( | 88 | check_with_config( |
34 | "use external_crate2::bar::A", | 89 | "use external_crate2::bar::A", |
35 | r"", | 90 | r"", |
36 | r"use external_crate2::bar::A; | 91 | r"use external_crate2::bar::A; |
37 | 92 | ||
38 | ", | 93 | ", |
39 | ImportGranularity::Item, | 94 | &InsertUseConfig { |
40 | false, | 95 | granularity: ImportGranularity::Item, |
41 | false, | 96 | enforce_granularity: true, |
97 | prefix_kind: PrefixKind::Plain, | ||
98 | group: false, | ||
99 | skip_glob_imports: true, | ||
100 | }, | ||
42 | ); | 101 | ); |
43 | } | 102 | } |
44 | 103 | ||
@@ -277,13 +336,15 @@ fn insert_empty_module() { | |||
277 | cov_mark::check!(insert_group_empty_module); | 336 | cov_mark::check!(insert_group_empty_module); |
278 | check( | 337 | check( |
279 | "foo::bar", | 338 | "foo::bar", |
280 | "mod x {}", | 339 | r" |
281 | r"{ | 340 | mod x {$0} |
341 | ", | ||
342 | r" | ||
343 | mod x { | ||
282 | use foo::bar; | 344 | use foo::bar; |
283 | }", | 345 | } |
346 | ", | ||
284 | ImportGranularity::Item, | 347 | ImportGranularity::Item, |
285 | true, | ||
286 | true, | ||
287 | ) | 348 | ) |
288 | } | 349 | } |
289 | 350 | ||
@@ -511,13 +572,14 @@ use std::io; | |||
511 | } | 572 | } |
512 | 573 | ||
513 | #[test] | 574 | #[test] |
514 | #[ignore] // FIXME: Support this | ||
515 | fn split_out_merge() { | 575 | fn split_out_merge() { |
576 | // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}` | ||
577 | // instead. | ||
516 | check_module( | 578 | check_module( |
517 | "std::fmt::Result", | 579 | "std::fmt::Result", |
518 | r"use std::{fmt, io};", | 580 | r"use std::{fmt, io};", |
519 | r"use std::fmt::{self, Result}; | 581 | r"use std::fmt::Result; |
520 | use std::io;", | 582 | use std::{fmt, io};", |
521 | ) | 583 | ) |
522 | } | 584 | } |
523 | 585 | ||
@@ -533,17 +595,35 @@ fn merge_groups_self() { | |||
533 | 595 | ||
534 | #[test] | 596 | #[test] |
535 | fn merge_mod_into_glob() { | 597 | fn merge_mod_into_glob() { |
536 | check_crate( | 598 | check_with_config( |
537 | "token::TokenKind", | 599 | "token::TokenKind", |
538 | r"use token::TokenKind::*;", | 600 | r"use token::TokenKind::*;", |
539 | r"use token::TokenKind::{*, self};", | 601 | r"use token::TokenKind::{*, self};", |
602 | &InsertUseConfig { | ||
603 | granularity: ImportGranularity::Crate, | ||
604 | enforce_granularity: true, | ||
605 | prefix_kind: PrefixKind::Plain, | ||
606 | group: false, | ||
607 | skip_glob_imports: false, | ||
608 | }, | ||
540 | ) | 609 | ) |
541 | // FIXME: have it emit `use token::TokenKind::{self, *}`? | 610 | // FIXME: have it emit `use token::TokenKind::{self, *}`? |
542 | } | 611 | } |
543 | 612 | ||
544 | #[test] | 613 | #[test] |
545 | fn merge_self_glob() { | 614 | fn merge_self_glob() { |
546 | check_crate("self", r"use self::*;", r"use self::{*, self};") | 615 | check_with_config( |
616 | "self", | ||
617 | r"use self::*;", | ||
618 | r"use self::{*, self};", | ||
619 | &InsertUseConfig { | ||
620 | granularity: ImportGranularity::Crate, | ||
621 | enforce_granularity: true, | ||
622 | prefix_kind: PrefixKind::Plain, | ||
623 | group: false, | ||
624 | skip_glob_imports: false, | ||
625 | }, | ||
626 | ) | ||
547 | // FIXME: have it emit `use {self, *}`? | 627 | // FIXME: have it emit `use {self, *}`? |
548 | } | 628 | } |
549 | 629 | ||
@@ -756,19 +836,24 @@ use foo::bar::qux; | |||
756 | ); | 836 | ); |
757 | } | 837 | } |
758 | 838 | ||
759 | fn check( | 839 | fn check_with_config( |
760 | path: &str, | 840 | path: &str, |
761 | ra_fixture_before: &str, | 841 | ra_fixture_before: &str, |
762 | ra_fixture_after: &str, | 842 | ra_fixture_after: &str, |
763 | granularity: ImportGranularity, | 843 | config: &InsertUseConfig, |
764 | module: bool, | ||
765 | group: bool, | ||
766 | ) { | 844 | ) { |
767 | let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); | 845 | let (text, pos) = if ra_fixture_before.contains(CURSOR_MARKER) { |
768 | if module { | 846 | let (range_or_offset, text) = extract_range_or_offset(ra_fixture_before); |
769 | syntax = syntax.descendants().find_map(ast::Module::cast).unwrap().syntax().clone(); | 847 | (text, Some(range_or_offset)) |
770 | } | 848 | } else { |
771 | let file = super::ImportScope::from(syntax.clone_for_update()).unwrap(); | 849 | (ra_fixture_before.to_owned(), None) |
850 | }; | ||
851 | let syntax = ast::SourceFile::parse(&text).tree().syntax().clone_for_update(); | ||
852 | let file = pos | ||
853 | .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent()) | ||
854 | .and_then(|it| super::ImportScope::find_insert_use_container(&it)) | ||
855 | .or_else(|| super::ImportScope::from(syntax)) | ||
856 | .unwrap(); | ||
772 | let path = ast::SourceFile::parse(&format!("use {};", path)) | 857 | let path = ast::SourceFile::parse(&format!("use {};", path)) |
773 | .tree() | 858 | .tree() |
774 | .syntax() | 859 | .syntax() |
@@ -776,30 +861,41 @@ fn check( | |||
776 | .find_map(ast::Path::cast) | 861 | .find_map(ast::Path::cast) |
777 | .unwrap(); | 862 | .unwrap(); |
778 | 863 | ||
779 | insert_use( | 864 | insert_use(&file, path, config); |
780 | &file, | 865 | let result = file.as_syntax_node().ancestors().last().unwrap().to_string(); |
866 | assert_eq_text!(ra_fixture_after, &result); | ||
867 | } | ||
868 | |||
869 | fn check( | ||
870 | path: &str, | ||
871 | ra_fixture_before: &str, | ||
872 | ra_fixture_after: &str, | ||
873 | granularity: ImportGranularity, | ||
874 | ) { | ||
875 | check_with_config( | ||
781 | path, | 876 | path, |
782 | InsertUseConfig { | 877 | ra_fixture_before, |
878 | ra_fixture_after, | ||
879 | &InsertUseConfig { | ||
783 | granularity, | 880 | granularity, |
784 | enforce_granularity: true, | 881 | enforce_granularity: true, |
785 | prefix_kind: PrefixKind::Plain, | 882 | prefix_kind: PrefixKind::Plain, |
786 | group, | 883 | group: true, |
884 | skip_glob_imports: true, | ||
787 | }, | 885 | }, |
788 | ); | 886 | ) |
789 | let result = file.as_syntax_node().to_string(); | ||
790 | assert_eq_text!(ra_fixture_after, &result); | ||
791 | } | 887 | } |
792 | 888 | ||
793 | fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 889 | fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
794 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate, false, true) | 890 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate) |
795 | } | 891 | } |
796 | 892 | ||
797 | fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 893 | fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
798 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module, false, true) | 894 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module) |
799 | } | 895 | } |
800 | 896 | ||
801 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 897 | fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
802 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item, false, true) | 898 | check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item) |
803 | } | 899 | } |
804 | 900 | ||
805 | fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { | 901 | fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { |
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 105607dca..bde8767dd 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -3,17 +3,21 @@ | |||
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | mod apply_change; | 5 | mod apply_change; |
6 | pub mod assists; | ||
6 | pub mod label; | 7 | pub mod label; |
7 | pub mod line_index; | 8 | pub mod line_index; |
8 | pub mod symbol_index; | 9 | pub mod symbol_index; |
9 | pub mod defs; | 10 | pub mod defs; |
10 | pub mod search; | ||
11 | pub mod items_locator; | 11 | pub mod items_locator; |
12 | pub mod source_change; | 12 | pub mod source_change; |
13 | pub mod ty_filter; | 13 | pub mod ty_filter; |
14 | pub mod traits; | 14 | pub mod traits; |
15 | pub mod call_info; | 15 | pub mod call_info; |
16 | pub mod helpers; | 16 | pub mod helpers; |
17 | pub mod path_transform; | ||
18 | |||
19 | pub mod search; | ||
20 | pub mod rename; | ||
17 | 21 | ||
18 | use std::{fmt, sync::Arc}; | 22 | use std::{fmt, sync::Arc}; |
19 | 23 | ||
diff --git a/crates/ide_assists/src/path_transform.rs b/crates/ide_db/src/path_transform.rs index 48a7fa06a..f3d7aa920 100644 --- a/crates/ide_assists/src/path_transform.rs +++ b/crates/ide_db/src/path_transform.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! See [`PathTransform`]. | 1 | //! See [`PathTransform`]. |
2 | 2 | ||
3 | use crate::helpers::mod_path_to_ast; | ||
3 | use hir::{HirDisplay, SemanticsScope}; | 4 | use hir::{HirDisplay, SemanticsScope}; |
4 | use ide_db::helpers::mod_path_to_ast; | ||
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use syntax::{ | 6 | use syntax::{ |
7 | ast::{self, AstNode}, | 7 | ast::{self, AstNode}, |
@@ -31,14 +31,14 @@ use syntax::{ | |||
31 | /// } | 31 | /// } |
32 | /// } | 32 | /// } |
33 | /// ``` | 33 | /// ``` |
34 | pub(crate) struct PathTransform<'a> { | 34 | pub struct PathTransform<'a> { |
35 | pub(crate) subst: (hir::Trait, ast::Impl), | 35 | pub subst: (hir::Trait, ast::Impl), |
36 | pub(crate) target_scope: &'a SemanticsScope<'a>, | 36 | pub target_scope: &'a SemanticsScope<'a>, |
37 | pub(crate) source_scope: &'a SemanticsScope<'a>, | 37 | pub source_scope: &'a SemanticsScope<'a>, |
38 | } | 38 | } |
39 | 39 | ||
40 | impl<'a> PathTransform<'a> { | 40 | impl<'a> PathTransform<'a> { |
41 | pub(crate) fn apply(&self, item: ast::AssocItem) { | 41 | pub fn apply(&self, item: ast::AssocItem) { |
42 | if let Some(ctx) = self.build_ctx() { | 42 | if let Some(ctx) = self.build_ctx() { |
43 | ctx.apply(item) | 43 | ctx.apply(item) |
44 | } | 44 | } |
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs new file mode 100644 index 000000000..643e67781 --- /dev/null +++ b/crates/ide_db/src/rename.rs | |||
@@ -0,0 +1,468 @@ | |||
1 | //! Rename infrastructure for rust-analyzer. It is used primarily for the | ||
2 | //! literal "rename" in the ide (look for tests there), but it is also available | ||
3 | //! as a general-purpose service. For example, it is used by the fix for the | ||
4 | //! "incorrect case" diagnostic. | ||
5 | //! | ||
6 | //! It leverages the [`crate::search`] functionality to find what needs to be | ||
7 | //! renamed. The actual renames are tricky -- field shorthands need special | ||
8 | //! attention, and, when renaming modules, you also want to rename files on the | ||
9 | //! file system. | ||
10 | //! | ||
11 | //! Another can of worms are macros: | ||
12 | //! | ||
13 | //! ``` | ||
14 | //! macro_rules! m { () => { fn f() {} } } | ||
15 | //! m!(); | ||
16 | //! fn main() { | ||
17 | //! f() // <- rename me | ||
18 | //! } | ||
19 | //! ``` | ||
20 | //! | ||
21 | //! The correct behavior in such cases is probably to show a dialog to the user. | ||
22 | //! Our current behavior is ¯\_(ツ)_/¯. | ||
23 | use std::fmt; | ||
24 | |||
25 | use base_db::{AnchoredPathBuf, FileId, FileRange}; | ||
26 | use either::Either; | ||
27 | use hir::{AsAssocItem, FieldSource, HasSource, InFile, ModuleSource, Semantics}; | ||
28 | use stdx::never; | ||
29 | use syntax::{ | ||
30 | ast::{self, NameOwner}, | ||
31 | lex_single_syntax_kind, AstNode, SyntaxKind, TextRange, T, | ||
32 | }; | ||
33 | use text_edit::TextEdit; | ||
34 | |||
35 | use crate::{ | ||
36 | defs::Definition, | ||
37 | search::FileReference, | ||
38 | source_change::{FileSystemEdit, SourceChange}, | ||
39 | RootDatabase, | ||
40 | }; | ||
41 | |||
42 | pub type Result<T, E = RenameError> = std::result::Result<T, E>; | ||
43 | |||
44 | #[derive(Debug)] | ||
45 | pub struct RenameError(pub String); | ||
46 | |||
47 | impl fmt::Display for RenameError { | ||
48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
49 | fmt::Display::fmt(&self.0, f) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | #[macro_export] | ||
54 | macro_rules! _format_err { | ||
55 | ($fmt:expr) => { RenameError(format!($fmt)) }; | ||
56 | ($fmt:expr, $($arg:tt)+) => { RenameError(format!($fmt, $($arg)+)) } | ||
57 | } | ||
58 | pub use _format_err as format_err; | ||
59 | |||
60 | #[macro_export] | ||
61 | macro_rules! _bail { | ||
62 | ($($tokens:tt)*) => { return Err(format_err!($($tokens)*)) } | ||
63 | } | ||
64 | pub use _bail as bail; | ||
65 | |||
66 | impl Definition { | ||
67 | pub fn rename(&self, sema: &Semantics<RootDatabase>, new_name: &str) -> Result<SourceChange> { | ||
68 | match *self { | ||
69 | Definition::ModuleDef(hir::ModuleDef::Module(module)) => { | ||
70 | rename_mod(sema, module, new_name) | ||
71 | } | ||
72 | Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => { | ||
73 | bail!("Cannot rename builtin type") | ||
74 | } | ||
75 | Definition::SelfType(_) => bail!("Cannot rename `Self`"), | ||
76 | def => rename_reference(sema, def, new_name), | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /// Textual range of the identifier which will change when renaming this | ||
81 | /// `Definition`. Note that some definitions, like buitin types, can't be | ||
82 | /// renamed. | ||
83 | pub fn range_for_rename(self, sema: &Semantics<RootDatabase>) -> Option<FileRange> { | ||
84 | // FIXME: the `original_file_range` calls here are wrong -- they never fail, | ||
85 | // and _fall back_ to the entirety of the macro call. Such fall back is | ||
86 | // incorrect for renames. The safe behavior would be to return an error for | ||
87 | // such cases. The correct behavior would be to return an auxiliary list of | ||
88 | // "can't rename these occurrences in macros" items, and then show some kind | ||
89 | // of a dialog to the user. See: | ||
90 | cov_mark::hit!(macros_are_broken_lol); | ||
91 | |||
92 | let res = match self { | ||
93 | Definition::Macro(mac) => { | ||
94 | let src = mac.source(sema.db)?; | ||
95 | let name = match &src.value { | ||
96 | Either::Left(it) => it.name()?, | ||
97 | Either::Right(it) => it.name()?, | ||
98 | }; | ||
99 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
100 | } | ||
101 | Definition::Field(field) => { | ||
102 | let src = field.source(sema.db)?; | ||
103 | |||
104 | match &src.value { | ||
105 | FieldSource::Named(record_field) => { | ||
106 | let name = record_field.name()?; | ||
107 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
108 | } | ||
109 | FieldSource::Pos(_) => { | ||
110 | return None; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | Definition::ModuleDef(module_def) => match module_def { | ||
115 | hir::ModuleDef::Module(module) => { | ||
116 | let src = module.declaration_source(sema.db)?; | ||
117 | let name = src.value.name()?; | ||
118 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
119 | } | ||
120 | hir::ModuleDef::Function(it) => name_range(it, sema)?, | ||
121 | hir::ModuleDef::Adt(adt) => match adt { | ||
122 | hir::Adt::Struct(it) => name_range(it, sema)?, | ||
123 | hir::Adt::Union(it) => name_range(it, sema)?, | ||
124 | hir::Adt::Enum(it) => name_range(it, sema)?, | ||
125 | }, | ||
126 | hir::ModuleDef::Variant(it) => name_range(it, sema)?, | ||
127 | hir::ModuleDef::Const(it) => name_range(it, sema)?, | ||
128 | hir::ModuleDef::Static(it) => name_range(it, sema)?, | ||
129 | hir::ModuleDef::Trait(it) => name_range(it, sema)?, | ||
130 | hir::ModuleDef::TypeAlias(it) => name_range(it, sema)?, | ||
131 | hir::ModuleDef::BuiltinType(_) => return None, | ||
132 | }, | ||
133 | Definition::SelfType(_) => return None, | ||
134 | Definition::Local(local) => { | ||
135 | let src = local.source(sema.db); | ||
136 | let name = match &src.value { | ||
137 | Either::Left(bind_pat) => bind_pat.name()?, | ||
138 | Either::Right(_) => return None, | ||
139 | }; | ||
140 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
141 | } | ||
142 | Definition::GenericParam(generic_param) => match generic_param { | ||
143 | hir::GenericParam::TypeParam(type_param) => { | ||
144 | let src = type_param.source(sema.db)?; | ||
145 | let name = match &src.value { | ||
146 | Either::Left(type_param) => type_param.name()?, | ||
147 | Either::Right(_trait) => return None, | ||
148 | }; | ||
149 | src.with_value(name.syntax()).original_file_range(sema.db) | ||
150 | } | ||
151 | hir::GenericParam::LifetimeParam(lifetime_param) => { | ||
152 | let src = lifetime_param.source(sema.db)?; | ||
153 | let lifetime = src.value.lifetime()?; | ||
154 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
155 | } | ||
156 | hir::GenericParam::ConstParam(it) => name_range(it, sema)?, | ||
157 | }, | ||
158 | Definition::Label(label) => { | ||
159 | let src = label.source(sema.db); | ||
160 | let lifetime = src.value.lifetime()?; | ||
161 | src.with_value(lifetime.syntax()).original_file_range(sema.db) | ||
162 | } | ||
163 | }; | ||
164 | return Some(res); | ||
165 | |||
166 | fn name_range<D>(def: D, sema: &Semantics<RootDatabase>) -> Option<FileRange> | ||
167 | where | ||
168 | D: HasSource, | ||
169 | D::Ast: ast::NameOwner, | ||
170 | { | ||
171 | let src = def.source(sema.db)?; | ||
172 | let name = src.value.name()?; | ||
173 | let res = src.with_value(name.syntax()).original_file_range(sema.db); | ||
174 | Some(res) | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | fn rename_mod( | ||
180 | sema: &Semantics<RootDatabase>, | ||
181 | module: hir::Module, | ||
182 | new_name: &str, | ||
183 | ) -> Result<SourceChange> { | ||
184 | if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { | ||
185 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); | ||
186 | } | ||
187 | |||
188 | let mut source_change = SourceChange::default(); | ||
189 | |||
190 | let InFile { file_id, value: def_source } = module.definition_source(sema.db); | ||
191 | let file_id = file_id.original_file(sema.db); | ||
192 | if let ModuleSource::SourceFile(..) = def_source { | ||
193 | // mod is defined in path/to/dir/mod.rs | ||
194 | let path = if module.is_mod_rs(sema.db) { | ||
195 | format!("../{}/mod.rs", new_name) | ||
196 | } else { | ||
197 | format!("{}.rs", new_name) | ||
198 | }; | ||
199 | let dst = AnchoredPathBuf { anchor: file_id, path }; | ||
200 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | ||
201 | source_change.push_file_system_edit(move_file); | ||
202 | } | ||
203 | |||
204 | if let Some(InFile { file_id, value: decl_source }) = module.declaration_source(sema.db) { | ||
205 | let file_id = file_id.original_file(sema.db); | ||
206 | match decl_source.name() { | ||
207 | Some(name) => source_change.insert_source_edit( | ||
208 | file_id, | ||
209 | TextEdit::replace(name.syntax().text_range(), new_name.to_string()), | ||
210 | ), | ||
211 | _ => never!("Module source node is missing a name"), | ||
212 | } | ||
213 | } | ||
214 | let def = Definition::ModuleDef(hir::ModuleDef::Module(module)); | ||
215 | let usages = def.usages(sema).all(); | ||
216 | let ref_edits = usages.iter().map(|(&file_id, references)| { | ||
217 | (file_id, source_edit_from_references(references, def, new_name)) | ||
218 | }); | ||
219 | source_change.extend(ref_edits); | ||
220 | |||
221 | Ok(source_change) | ||
222 | } | ||
223 | |||
224 | fn rename_reference( | ||
225 | sema: &Semantics<RootDatabase>, | ||
226 | mut def: Definition, | ||
227 | new_name: &str, | ||
228 | ) -> Result<SourceChange> { | ||
229 | let ident_kind = IdentifierKind::classify(new_name)?; | ||
230 | |||
231 | if matches!( | ||
232 | def, // is target a lifetime? | ||
233 | Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) | ||
234 | ) { | ||
235 | match ident_kind { | ||
236 | IdentifierKind::Ident | IdentifierKind::Underscore => { | ||
237 | cov_mark::hit!(rename_not_a_lifetime_ident_ref); | ||
238 | bail!("Invalid name `{}`: not a lifetime identifier", new_name); | ||
239 | } | ||
240 | IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime), | ||
241 | } | ||
242 | } else { | ||
243 | match (ident_kind, def) { | ||
244 | (IdentifierKind::Lifetime, _) => { | ||
245 | cov_mark::hit!(rename_not_an_ident_ref); | ||
246 | bail!("Invalid name `{}`: not an identifier", new_name); | ||
247 | } | ||
248 | (IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local), | ||
249 | (IdentifierKind::Underscore, _) => (), | ||
250 | } | ||
251 | } | ||
252 | |||
253 | def = match def { | ||
254 | // HACK: resolve trait impl items to the item def of the trait definition | ||
255 | // so that we properly resolve all trait item references | ||
256 | Definition::ModuleDef(mod_def) => mod_def | ||
257 | .as_assoc_item(sema.db) | ||
258 | .and_then(|it| it.containing_trait_impl(sema.db)) | ||
259 | .and_then(|it| { | ||
260 | it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) { | ||
261 | (hir::AssocItem::Function(trait_func), hir::ModuleDef::Function(func)) | ||
262 | if trait_func.name(sema.db) == func.name(sema.db) => | ||
263 | { | ||
264 | Some(Definition::ModuleDef(hir::ModuleDef::Function(trait_func))) | ||
265 | } | ||
266 | (hir::AssocItem::Const(trait_konst), hir::ModuleDef::Const(konst)) | ||
267 | if trait_konst.name(sema.db) == konst.name(sema.db) => | ||
268 | { | ||
269 | Some(Definition::ModuleDef(hir::ModuleDef::Const(trait_konst))) | ||
270 | } | ||
271 | ( | ||
272 | hir::AssocItem::TypeAlias(trait_type_alias), | ||
273 | hir::ModuleDef::TypeAlias(type_alias), | ||
274 | ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => { | ||
275 | Some(Definition::ModuleDef(hir::ModuleDef::TypeAlias(trait_type_alias))) | ||
276 | } | ||
277 | _ => None, | ||
278 | }) | ||
279 | }) | ||
280 | .unwrap_or(def), | ||
281 | _ => def, | ||
282 | }; | ||
283 | let usages = def.usages(sema).all(); | ||
284 | |||
285 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | ||
286 | cov_mark::hit!(rename_underscore_multiple); | ||
287 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
288 | } | ||
289 | let mut source_change = SourceChange::default(); | ||
290 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
291 | (file_id, source_edit_from_references(references, def, new_name)) | ||
292 | })); | ||
293 | |||
294 | let (file_id, edit) = source_edit_from_def(sema, def, new_name)?; | ||
295 | source_change.insert_source_edit(file_id, edit); | ||
296 | Ok(source_change) | ||
297 | } | ||
298 | |||
299 | pub fn source_edit_from_references( | ||
300 | references: &[FileReference], | ||
301 | def: Definition, | ||
302 | new_name: &str, | ||
303 | ) -> TextEdit { | ||
304 | let mut edit = TextEdit::builder(); | ||
305 | for reference in references { | ||
306 | let (range, replacement) = match &reference.name { | ||
307 | // if the ranges differ then the node is inside a macro call, we can't really attempt | ||
308 | // to make special rewrites like shorthand syntax and such, so just rename the node in | ||
309 | // the macro input | ||
310 | ast::NameLike::NameRef(name_ref) | ||
311 | if name_ref.syntax().text_range() == reference.range => | ||
312 | { | ||
313 | source_edit_from_name_ref(name_ref, new_name, def) | ||
314 | } | ||
315 | ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { | ||
316 | source_edit_from_name(name, new_name) | ||
317 | } | ||
318 | _ => None, | ||
319 | } | ||
320 | .unwrap_or_else(|| (reference.range, new_name.to_string())); | ||
321 | edit.replace(range, replacement); | ||
322 | } | ||
323 | edit.finish() | ||
324 | } | ||
325 | |||
326 | fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> { | ||
327 | if let Some(_) = ast::RecordPatField::for_field_name(name) { | ||
328 | if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | ||
329 | return Some(( | ||
330 | TextRange::empty(ident_pat.syntax().text_range().start()), | ||
331 | [new_name, ": "].concat(), | ||
332 | )); | ||
333 | } | ||
334 | } | ||
335 | None | ||
336 | } | ||
337 | |||
338 | fn source_edit_from_name_ref( | ||
339 | name_ref: &ast::NameRef, | ||
340 | new_name: &str, | ||
341 | def: Definition, | ||
342 | ) -> Option<(TextRange, String)> { | ||
343 | if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { | ||
344 | let rcf_name_ref = record_field.name_ref(); | ||
345 | let rcf_expr = record_field.expr(); | ||
346 | match (rcf_name_ref, rcf_expr.and_then(|it| it.name_ref())) { | ||
347 | // field: init-expr, check if we can use a field init shorthand | ||
348 | (Some(field_name), Some(init)) => { | ||
349 | if field_name == *name_ref { | ||
350 | if init.text() == new_name { | ||
351 | cov_mark::hit!(test_rename_field_put_init_shorthand); | ||
352 | // same names, we can use a shorthand here instead. | ||
353 | // we do not want to erase attributes hence this range start | ||
354 | let s = field_name.syntax().text_range().start(); | ||
355 | let e = record_field.syntax().text_range().end(); | ||
356 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
357 | } | ||
358 | } else if init == *name_ref { | ||
359 | if field_name.text() == new_name { | ||
360 | cov_mark::hit!(test_rename_local_put_init_shorthand); | ||
361 | // same names, we can use a shorthand here instead. | ||
362 | // we do not want to erase attributes hence this range start | ||
363 | let s = field_name.syntax().text_range().start(); | ||
364 | let e = record_field.syntax().text_range().end(); | ||
365 | return Some((TextRange::new(s, e), new_name.to_owned())); | ||
366 | } | ||
367 | } | ||
368 | None | ||
369 | } | ||
370 | // init shorthand | ||
371 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | ||
372 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | ||
373 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { | ||
374 | cov_mark::hit!(test_rename_field_in_field_shorthand); | ||
375 | let s = name_ref.syntax().text_range().start(); | ||
376 | Some((TextRange::empty(s), format!("{}: ", new_name))) | ||
377 | } | ||
378 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { | ||
379 | cov_mark::hit!(test_rename_local_in_field_shorthand); | ||
380 | let s = name_ref.syntax().text_range().end(); | ||
381 | Some((TextRange::empty(s), format!(": {}", new_name))) | ||
382 | } | ||
383 | _ => None, | ||
384 | } | ||
385 | } else if let Some(record_field) = ast::RecordPatField::for_field_name_ref(name_ref) { | ||
386 | let rcf_name_ref = record_field.name_ref(); | ||
387 | let rcf_pat = record_field.pat(); | ||
388 | match (rcf_name_ref, rcf_pat) { | ||
389 | // field: rename | ||
390 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { | ||
391 | // field name is being renamed | ||
392 | if pat.name().map_or(false, |it| it.text() == new_name) { | ||
393 | cov_mark::hit!(test_rename_field_put_init_shorthand_pat); | ||
394 | // same names, we can use a shorthand here instead/ | ||
395 | // we do not want to erase attributes hence this range start | ||
396 | let s = field_name.syntax().text_range().start(); | ||
397 | let e = record_field.syntax().text_range().end(); | ||
398 | Some((TextRange::new(s, e), pat.to_string())) | ||
399 | } else { | ||
400 | None | ||
401 | } | ||
402 | } | ||
403 | _ => None, | ||
404 | } | ||
405 | } else { | ||
406 | None | ||
407 | } | ||
408 | } | ||
409 | |||
410 | fn source_edit_from_def( | ||
411 | sema: &Semantics<RootDatabase>, | ||
412 | def: Definition, | ||
413 | new_name: &str, | ||
414 | ) -> Result<(FileId, TextEdit)> { | ||
415 | let frange = def | ||
416 | .range_for_rename(sema) | ||
417 | .ok_or_else(|| format_err!("No identifier available to rename"))?; | ||
418 | |||
419 | let mut replacement_text = String::new(); | ||
420 | let mut repl_range = frange.range; | ||
421 | if let Definition::Local(local) = def { | ||
422 | if let Either::Left(pat) = local.source(sema.db).value { | ||
423 | if matches!( | ||
424 | pat.syntax().parent().and_then(ast::RecordPatField::cast), | ||
425 | Some(pat_field) if pat_field.name_ref().is_none() | ||
426 | ) { | ||
427 | replacement_text.push_str(": "); | ||
428 | replacement_text.push_str(new_name); | ||
429 | repl_range = TextRange::new( | ||
430 | pat.syntax().text_range().end(), | ||
431 | pat.syntax().text_range().end(), | ||
432 | ); | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | if replacement_text.is_empty() { | ||
437 | replacement_text.push_str(new_name); | ||
438 | } | ||
439 | let edit = TextEdit::replace(repl_range, replacement_text); | ||
440 | Ok((frange.file_id, edit)) | ||
441 | } | ||
442 | |||
443 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
444 | pub enum IdentifierKind { | ||
445 | Ident, | ||
446 | Lifetime, | ||
447 | Underscore, | ||
448 | } | ||
449 | |||
450 | impl IdentifierKind { | ||
451 | pub fn classify(new_name: &str) -> Result<IdentifierKind> { | ||
452 | match lex_single_syntax_kind(new_name) { | ||
453 | Some(res) => match res { | ||
454 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
455 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
456 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
457 | Ok(IdentifierKind::Lifetime) | ||
458 | } | ||
459 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
460 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) | ||
461 | } | ||
462 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
463 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
464 | }, | ||
465 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
466 | } | ||
467 | } | ||
468 | } | ||
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml new file mode 100644 index 000000000..fa2adf212 --- /dev/null +++ b/crates/ide_diagnostics/Cargo.toml | |||
@@ -0,0 +1,29 @@ | |||
1 | [package] | ||
2 | name = "ide_diagnostics" | ||
3 | version = "0.0.0" | ||
4 | description = "TBD" | ||
5 | license = "MIT OR Apache-2.0" | ||
6 | authors = ["rust-analyzer developers"] | ||
7 | edition = "2018" | ||
8 | |||
9 | [lib] | ||
10 | doctest = false | ||
11 | |||
12 | [dependencies] | ||
13 | cov-mark = "2.0.0-pre.1" | ||
14 | itertools = "0.10.0" | ||
15 | rustc-hash = "1.1.0" | ||
16 | either = "1.5.3" | ||
17 | |||
18 | profile = { path = "../profile", version = "0.0.0" } | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | ||
20 | syntax = { path = "../syntax", version = "0.0.0" } | ||
21 | text_edit = { path = "../text_edit", version = "0.0.0" } | ||
22 | cfg = { path = "../cfg", version = "0.0.0" } | ||
23 | hir = { path = "../hir", version = "0.0.0" } | ||
24 | ide_db = { path = "../ide_db", version = "0.0.0" } | ||
25 | |||
26 | [dev-dependencies] | ||
27 | expect-test = "1.1" | ||
28 | |||
29 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ide/src/diagnostics/break_outside_of_loop.rs b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs index 80e68f3cc..d12594a4c 100644 --- a/crates/ide/src/diagnostics/break_outside_of_loop.rs +++ b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: break-outside-of-loop | 3 | // Diagnostic: break-outside-of-loop |
4 | // | 4 | // |
5 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. | 5 | // This diagnostic is triggered if the `break` keyword is used outside of a loop. |
6 | pub(super) fn break_outside_of_loop( | 6 | pub(crate) fn break_outside_of_loop( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::BreakOutsideOfLoop, | 8 | d: &hir::BreakOutsideOfLoop, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -16,14 +16,14 @@ pub(super) fn break_outside_of_loop( | |||
16 | 16 | ||
17 | #[cfg(test)] | 17 | #[cfg(test)] |
18 | mod tests { | 18 | mod tests { |
19 | use crate::diagnostics::tests::check_diagnostics; | 19 | use crate::tests::check_diagnostics; |
20 | 20 | ||
21 | #[test] | 21 | #[test] |
22 | fn break_outside_of_loop() { | 22 | fn break_outside_of_loop() { |
23 | check_diagnostics( | 23 | check_diagnostics( |
24 | r#" | 24 | r#" |
25 | fn foo() { break; } | 25 | fn foo() { break; } |
26 | //^^^^^ break outside of loop | 26 | //^^^^^ error: break outside of loop |
27 | "#, | 27 | "#, |
28 | ); | 28 | ); |
29 | } | 29 | } |
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs index c7f4dab8e..33152e284 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs | |||
@@ -5,9 +5,9 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; | |||
5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; | 5 | use syntax::{ast, match_ast, AstNode, SyntaxNode}; |
6 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
7 | 7 | ||
8 | use crate::{diagnostics::fix, Diagnostic, Severity}; | 8 | use crate::{fix, Diagnostic, Severity}; |
9 | 9 | ||
10 | pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { | 10 | pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { |
11 | match_ast! { | 11 | match_ast! { |
12 | match node { | 12 | match node { |
13 | ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), | 13 | ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), |
@@ -101,7 +101,7 @@ fn check_pat_field_shorthand( | |||
101 | 101 | ||
102 | #[cfg(test)] | 102 | #[cfg(test)] |
103 | mod tests { | 103 | mod tests { |
104 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 104 | use crate::tests::{check_diagnostics, check_fix}; |
105 | 105 | ||
106 | #[test] | 106 | #[test] |
107 | fn test_check_expr_field_shorthand() { | 107 | fn test_check_expr_field_shorthand() { |
diff --git a/crates/ide/src/diagnostics/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs index d9d3e88c1..dfd0e3351 100644 --- a/crates/ide/src/diagnostics/inactive_code.rs +++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs | |||
@@ -1,15 +1,12 @@ | |||
1 | use cfg::DnfExpr; | 1 | use cfg::DnfExpr; |
2 | use stdx::format_to; | 2 | use stdx::format_to; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
5 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
6 | Severity, | ||
7 | }; | ||
8 | 5 | ||
9 | // Diagnostic: inactive-code | 6 | // Diagnostic: inactive-code |
10 | // | 7 | // |
11 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | 8 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. |
12 | pub(super) fn inactive_code( | 9 | pub(crate) fn inactive_code( |
13 | ctx: &DiagnosticsContext<'_>, | 10 | ctx: &DiagnosticsContext<'_>, |
14 | d: &hir::InactiveCode, | 11 | d: &hir::InactiveCode, |
15 | ) -> Option<Diagnostic> { | 12 | ) -> Option<Diagnostic> { |
@@ -37,7 +34,7 @@ pub(super) fn inactive_code( | |||
37 | 34 | ||
38 | #[cfg(test)] | 35 | #[cfg(test)] |
39 | mod tests { | 36 | mod tests { |
40 | use crate::{diagnostics::tests::check_diagnostics_with_config, DiagnosticsConfig}; | 37 | use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; |
41 | 38 | ||
42 | pub(crate) fn check(ra_fixture: &str) { | 39 | pub(crate) fn check(ra_fixture: &str) { |
43 | let config = DiagnosticsConfig::default(); | 40 | let config = DiagnosticsConfig::default(); |
@@ -52,26 +49,26 @@ fn f() { | |||
52 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | 49 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: |
53 | 50 | ||
54 | #[cfg(a)] fn f() {} // Item statement | 51 | #[cfg(a)] fn f() {} // Item statement |
55 | //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 52 | //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
56 | #[cfg(a)] {} // Expression statement | 53 | #[cfg(a)] {} // Expression statement |
57 | //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 54 | //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
58 | #[cfg(a)] let x = 0; // let statement | 55 | #[cfg(a)] let x = 0; // let statement |
59 | //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 56 | //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
60 | 57 | ||
61 | abc(#[cfg(a)] 0); | 58 | abc(#[cfg(a)] 0); |
62 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 59 | //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
63 | let x = Struct { | 60 | let x = Struct { |
64 | #[cfg(a)] f: 0, | 61 | #[cfg(a)] f: 0, |
65 | //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 62 | //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
66 | }; | 63 | }; |
67 | match () { | 64 | match () { |
68 | () => (), | 65 | () => (), |
69 | #[cfg(a)] () => (), | 66 | #[cfg(a)] () => (), |
70 | //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 67 | //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
71 | } | 68 | } |
72 | 69 | ||
73 | #[cfg(a)] 0 // Trailing expression of block | 70 | #[cfg(a)] 0 // Trailing expression of block |
74 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | 71 | //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled |
75 | } | 72 | } |
76 | "#, | 73 | "#, |
77 | ); | 74 | ); |
@@ -84,16 +81,16 @@ fn f() { | |||
84 | check( | 81 | check( |
85 | r#" | 82 | r#" |
86 | #[cfg(no)] pub fn f() {} | 83 | #[cfg(no)] pub fn f() {} |
87 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 84 | //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
88 | 85 | ||
89 | #[cfg(no)] #[cfg(no2)] mod m; | 86 | #[cfg(no)] #[cfg(no2)] mod m; |
90 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | 87 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled |
91 | 88 | ||
92 | #[cfg(all(not(a), b))] enum E {} | 89 | #[cfg(all(not(a), b))] enum E {} |
93 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | 90 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled |
94 | 91 | ||
95 | #[cfg(feature = "std")] use std; | 92 | #[cfg(feature = "std")] use std; |
96 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | 93 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled |
97 | "#, | 94 | "#, |
98 | ); | 95 | ); |
99 | } | 96 | } |
@@ -105,14 +102,14 @@ fn f() { | |||
105 | check( | 102 | check( |
106 | r#" | 103 | r#" |
107 | #[cfg_attr(not(never), cfg(no))] fn f() {} | 104 | #[cfg_attr(not(never), cfg(no))] fn f() {} |
108 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 105 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
109 | 106 | ||
110 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | 107 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} |
111 | 108 | ||
112 | #[cfg_attr(never, cfg(no))] fn g() {} | 109 | #[cfg_attr(never, cfg(no))] fn g() {} |
113 | 110 | ||
114 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | 111 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} |
115 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled |
116 | "#, | 113 | "#, |
117 | ); | 114 | ); |
118 | } | 115 | } |
diff --git a/crates/ide/src/diagnostics/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs index 832394400..68f25f284 100644 --- a/crates/ide/src/diagnostics/incorrect_case.rs +++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs | |||
@@ -1,18 +1,19 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | 1 | use hir::{db::AstDatabase, InFile}; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, defs::NameClass}; |
3 | use ide_db::base_db::FilePosition; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::{ | 5 | use crate::{ |
7 | diagnostics::{unresolved_fix, Diagnostic, DiagnosticsContext}, | 6 | // references::rename::rename_with_semantics, |
8 | references::rename::rename_with_semantics, | 7 | unresolved_fix, |
8 | Diagnostic, | ||
9 | DiagnosticsContext, | ||
9 | Severity, | 10 | Severity, |
10 | }; | 11 | }; |
11 | 12 | ||
12 | // Diagnostic: incorrect-ident-case | 13 | // Diagnostic: incorrect-ident-case |
13 | // | 14 | // |
14 | // This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. | 15 | // This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. |
15 | pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { | 16 | pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { |
16 | Diagnostic::new( | 17 | Diagnostic::new( |
17 | "incorrect-ident-case", | 18 | "incorrect-ident-case", |
18 | format!( | 19 | format!( |
@@ -28,15 +29,15 @@ pub(super) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas | |||
28 | fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { | 29 | fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Assist>> { |
29 | let root = ctx.sema.db.parse_or_expand(d.file)?; | 30 | let root = ctx.sema.db.parse_or_expand(d.file)?; |
30 | let name_node = d.ident.to_node(&root); | 31 | let name_node = d.ident.to_node(&root); |
32 | let def = NameClass::classify(&ctx.sema, &name_node)?.defined(ctx.sema.db)?; | ||
31 | 33 | ||
32 | let name_node = InFile::new(d.file, name_node.syntax()); | 34 | let name_node = InFile::new(d.file, name_node.syntax()); |
33 | let frange = name_node.original_file_range(ctx.sema.db); | 35 | let frange = name_node.original_file_range(ctx.sema.db); |
34 | let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; | ||
35 | 36 | ||
36 | let label = format!("Rename to {}", d.suggested_text); | 37 | let label = format!("Rename to {}", d.suggested_text); |
37 | let mut res = unresolved_fix("change_case", &label, frange.range); | 38 | let mut res = unresolved_fix("change_case", &label, frange.range); |
38 | if ctx.resolve.should_resolve(&res.id) { | 39 | if ctx.resolve.should_resolve(&res.id) { |
39 | let source_change = rename_with_semantics(&ctx.sema, file_position, &d.suggested_text); | 40 | let source_change = def.rename(&ctx.sema, &d.suggested_text); |
40 | res.source_change = Some(source_change.ok().unwrap_or_default()); | 41 | res.source_change = Some(source_change.ok().unwrap_or_default()); |
41 | } | 42 | } |
42 | 43 | ||
@@ -45,10 +46,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass | |||
45 | 46 | ||
46 | #[cfg(test)] | 47 | #[cfg(test)] |
47 | mod change_case { | 48 | mod change_case { |
48 | use crate::{ | 49 | use crate::tests::{check_diagnostics, check_fix}; |
49 | diagnostics::tests::{check_diagnostics, check_fix}, | ||
50 | fixture, AssistResolveStrategy, DiagnosticsConfig, | ||
51 | }; | ||
52 | 50 | ||
53 | #[test] | 51 | #[test] |
54 | fn test_rename_incorrect_case() { | 52 | fn test_rename_incorrect_case() { |
@@ -116,7 +114,7 @@ fn some_fn() { | |||
116 | check_diagnostics( | 114 | check_diagnostics( |
117 | r#" | 115 | r#" |
118 | fn foo() { | 116 | fn foo() { |
119 | const ANOTHER_ITEM$0: &str = "some_item"; | 117 | const ANOTHER_ITEM: &str = "some_item"; |
120 | } | 118 | } |
121 | "#, | 119 | "#, |
122 | ); | 120 | ); |
@@ -148,20 +146,13 @@ impl TestStruct { | |||
148 | 146 | ||
149 | #[test] | 147 | #[test] |
150 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { | 148 | fn test_single_incorrect_case_diagnostic_in_function_name_issue_6970() { |
151 | let input = r#"fn FOO$0() {}"#; | 149 | check_diagnostics( |
152 | let expected = r#"fn foo() {}"#; | 150 | r#" |
153 | 151 | fn FOO() {} | |
154 | let (analysis, file_position) = fixture::position(input); | 152 | // ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo` |
155 | let diagnostics = analysis | 153 | "#, |
156 | .diagnostics( | 154 | ); |
157 | &DiagnosticsConfig::default(), | 155 | check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#); |
158 | AssistResolveStrategy::All, | ||
159 | file_position.file_id, | ||
160 | ) | ||
161 | .unwrap(); | ||
162 | assert_eq!(diagnostics.len(), 1); | ||
163 | |||
164 | check_fix(input, expected); | ||
165 | } | 156 | } |
166 | 157 | ||
167 | #[test] | 158 | #[test] |
@@ -169,7 +160,7 @@ impl TestStruct { | |||
169 | check_diagnostics( | 160 | check_diagnostics( |
170 | r#" | 161 | r#" |
171 | fn NonSnakeCaseName() {} | 162 | fn NonSnakeCaseName() {} |
172 | // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` | 163 | // ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` |
173 | "#, | 164 | "#, |
174 | ); | 165 | ); |
175 | } | 166 | } |
@@ -179,10 +170,10 @@ fn NonSnakeCaseName() {} | |||
179 | check_diagnostics( | 170 | check_diagnostics( |
180 | r#" | 171 | r#" |
181 | fn foo(SomeParam: u8) {} | 172 | fn foo(SomeParam: u8) {} |
182 | // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` | 173 | // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param` |
183 | 174 | ||
184 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | 175 | fn foo2(ok_param: &str, CAPS_PARAM: u8) {} |
185 | // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` | 176 | // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` |
186 | "#, | 177 | "#, |
187 | ); | 178 | ); |
188 | } | 179 | } |
@@ -193,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {} | |||
193 | r#" | 184 | r#" |
194 | fn foo() { | 185 | fn foo() { |
195 | let SOME_VALUE = 10; | 186 | let SOME_VALUE = 10; |
196 | // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` | 187 | // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` |
197 | let AnotherValue = 20; | 188 | let AnotherValue = 20; |
198 | // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` | 189 | // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value` |
199 | } | 190 | } |
200 | "#, | 191 | "#, |
201 | ); | 192 | ); |
@@ -206,10 +197,10 @@ fn foo() { | |||
206 | check_diagnostics( | 197 | check_diagnostics( |
207 | r#" | 198 | r#" |
208 | struct non_camel_case_name {} | 199 | struct non_camel_case_name {} |
209 | // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` | 200 | // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` |
210 | 201 | ||
211 | struct SCREAMING_CASE {} | 202 | struct SCREAMING_CASE {} |
212 | // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` | 203 | // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` |
213 | "#, | 204 | "#, |
214 | ); | 205 | ); |
215 | } | 206 | } |
@@ -228,7 +219,7 @@ struct AABB {} | |||
228 | check_diagnostics( | 219 | check_diagnostics( |
229 | r#" | 220 | r#" |
230 | struct SomeStruct { SomeField: u8 } | 221 | struct SomeStruct { SomeField: u8 } |
231 | // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` | 222 | // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field` |
232 | "#, | 223 | "#, |
233 | ); | 224 | ); |
234 | } | 225 | } |
@@ -238,10 +229,10 @@ struct SomeStruct { SomeField: u8 } | |||
238 | check_diagnostics( | 229 | check_diagnostics( |
239 | r#" | 230 | r#" |
240 | enum some_enum { Val(u8) } | 231 | enum some_enum { Val(u8) } |
241 | // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` | 232 | // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` |
242 | 233 | ||
243 | enum SOME_ENUM {} | 234 | enum SOME_ENUM {} |
244 | // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` | 235 | // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` |
245 | "#, | 236 | "#, |
246 | ); | 237 | ); |
247 | } | 238 | } |
@@ -260,7 +251,7 @@ enum AABB {} | |||
260 | check_diagnostics( | 251 | check_diagnostics( |
261 | r#" | 252 | r#" |
262 | enum SomeEnum { SOME_VARIANT(u8) } | 253 | enum SomeEnum { SOME_VARIANT(u8) } |
263 | // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` | 254 | // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` |
264 | "#, | 255 | "#, |
265 | ); | 256 | ); |
266 | } | 257 | } |
@@ -270,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) } | |||
270 | check_diagnostics( | 261 | check_diagnostics( |
271 | r#" | 262 | r#" |
272 | const some_weird_const: u8 = 10; | 263 | const some_weird_const: u8 = 10; |
273 | // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | 264 | // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` |
274 | "#, | 265 | "#, |
275 | ); | 266 | ); |
276 | } | 267 | } |
@@ -280,7 +271,7 @@ const some_weird_const: u8 = 10; | |||
280 | check_diagnostics( | 271 | check_diagnostics( |
281 | r#" | 272 | r#" |
282 | static some_weird_const: u8 = 10; | 273 | static some_weird_const: u8 = 10; |
283 | // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` | 274 | // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` |
284 | "#, | 275 | "#, |
285 | ); | 276 | ); |
286 | } | 277 | } |
@@ -290,13 +281,13 @@ static some_weird_const: u8 = 10; | |||
290 | check_diagnostics( | 281 | check_diagnostics( |
291 | r#" | 282 | r#" |
292 | struct someStruct; | 283 | struct someStruct; |
293 | // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` | 284 | // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` |
294 | 285 | ||
295 | impl someStruct { | 286 | impl someStruct { |
296 | fn SomeFunc(&self) { | 287 | fn SomeFunc(&self) { |
297 | // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` | 288 | // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func` |
298 | let WHY_VAR_IS_CAPS = 10; | 289 | let WHY_VAR_IS_CAPS = 10; |
299 | // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` | 290 | // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` |
300 | } | 291 | } |
301 | } | 292 | } |
302 | "#, | 293 | "#, |
@@ -328,7 +319,7 @@ enum Option { Some, None } | |||
328 | fn main() { | 319 | fn main() { |
329 | match Option::None { | 320 | match Option::None { |
330 | SOME_VAR @ None => (), | 321 | SOME_VAR @ None => (), |
331 | // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` | 322 | // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` |
332 | Some => (), | 323 | Some => (), |
333 | } | 324 | } |
334 | } | 325 | } |
@@ -350,43 +341,27 @@ mod F { | |||
350 | } | 341 | } |
351 | 342 | ||
352 | #[test] | 343 | #[test] |
353 | #[ignore] | 344 | fn complex_ignore() { |
354 | fn bug_trait_inside_fn() { | 345 | // FIXME: this should trigger errors for the second case. |
355 | // FIXME: | ||
356 | // This is broken, and in fact, should not even be looked at by this | ||
357 | // lint in the first place. There's weird stuff going on in the | ||
358 | // collection phase. | ||
359 | // It's currently being brought in by: | ||
360 | // * validate_func on `a` recursing into modules | ||
361 | // * then it finds the trait and then the function while iterating | ||
362 | // through modules | ||
363 | // * then validate_func is called on Dirty | ||
364 | // * ... which then proceeds to look at some unknown module taking no | ||
365 | // attrs from either the impl or the fn a, and then finally to the root | ||
366 | // module | ||
367 | // | ||
368 | // It should find the attribute on the trait, but it *doesn't even see | ||
369 | // the trait* as far as I can tell. | ||
370 | |||
371 | check_diagnostics( | 346 | check_diagnostics( |
372 | r#" | 347 | r#" |
373 | trait T { fn a(); } | 348 | trait T { fn a(); } |
374 | struct U {} | 349 | struct U {} |
375 | impl T for U { | 350 | impl T for U { |
376 | fn a() { | 351 | fn a() { |
377 | // this comes out of bitflags, mostly | ||
378 | #[allow(non_snake_case)] | 352 | #[allow(non_snake_case)] |
379 | trait __BitFlags { | 353 | trait __BitFlagsOk { |
380 | const HiImAlsoBad: u8 = 2; | 354 | const HiImAlsoBad: u8 = 2; |
381 | #[inline] | 355 | fn Dirty(&self) -> bool { false } |
382 | fn Dirty(&self) -> bool { | ||
383 | false | ||
384 | } | ||
385 | } | 356 | } |
386 | 357 | ||
358 | trait __BitFlagsBad { | ||
359 | const HiImAlsoBad: u8 = 2; | ||
360 | fn Dirty(&self) -> bool { false } | ||
361 | } | ||
387 | } | 362 | } |
388 | } | 363 | } |
389 | "#, | 364 | "#, |
390 | ); | 365 | ); |
391 | } | 366 | } |
392 | 367 | ||
@@ -423,18 +398,14 @@ extern { | |||
423 | } | 398 | } |
424 | 399 | ||
425 | #[test] | 400 | #[test] |
426 | #[ignore] | ||
427 | fn bug_traits_arent_checked() { | 401 | fn bug_traits_arent_checked() { |
428 | // FIXME: Traits and functions in traits aren't currently checked by | 402 | // FIXME: Traits and functions in traits aren't currently checked by |
429 | // r-a, even though rustc will complain about them. | 403 | // r-a, even though rustc will complain about them. |
430 | check_diagnostics( | 404 | check_diagnostics( |
431 | r#" | 405 | r#" |
432 | trait BAD_TRAIT { | 406 | trait BAD_TRAIT { |
433 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
434 | fn BAD_FUNCTION(); | 407 | fn BAD_FUNCTION(); |
435 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
436 | fn BadFunction(); | 408 | fn BadFunction(); |
437 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
438 | } | 409 | } |
439 | "#, | 410 | "#, |
440 | ); | 411 | ); |
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs index 5f97f190d..356f089b2 100644 --- a/crates/ide/src/diagnostics/macro_error.rs +++ b/crates/ide_diagnostics/src/handlers/macro_error.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: macro-error | 3 | // Diagnostic: macro-error |
4 | // | 4 | // |
5 | // This diagnostic is shown for macro expansion errors. | 5 | // This diagnostic is shown for macro expansion errors. |
6 | pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { | 6 | pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { |
7 | Diagnostic::new( | 7 | Diagnostic::new( |
8 | "macro-error", | 8 | "macro-error", |
9 | d.message.clone(), | 9 | d.message.clone(), |
@@ -15,7 +15,7 @@ pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> | |||
15 | #[cfg(test)] | 15 | #[cfg(test)] |
16 | mod tests { | 16 | mod tests { |
17 | use crate::{ | 17 | use crate::{ |
18 | diagnostics::tests::{check_diagnostics, check_diagnostics_with_config}, | 18 | tests::{check_diagnostics, check_diagnostics_with_config}, |
19 | DiagnosticsConfig, | 19 | DiagnosticsConfig, |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -27,7 +27,7 @@ mod tests { | |||
27 | macro_rules! include { () => {} } | 27 | macro_rules! include { () => {} } |
28 | 28 | ||
29 | include!("doesntexist"); | 29 | include!("doesntexist"); |
30 | //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` | 30 | //^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist` |
31 | "#, | 31 | "#, |
32 | ); | 32 | ); |
33 | } | 33 | } |
@@ -66,7 +66,7 @@ macro_rules! env { () => {} } | |||
66 | macro_rules! concat { () => {} } | 66 | macro_rules! concat { () => {} } |
67 | 67 | ||
68 | include!(concat!(env!("OUT_DIR"), "/out.rs")); | 68 | include!(concat!(env!("OUT_DIR"), "/out.rs")); |
69 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | 69 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix |
70 | "#, | 70 | "#, |
71 | ); | 71 | ); |
72 | } | 72 | } |
@@ -108,23 +108,23 @@ fn main() { | |||
108 | // Test a handful of built-in (eager) macros: | 108 | // Test a handful of built-in (eager) macros: |
109 | 109 | ||
110 | include!(invalid); | 110 | include!(invalid); |
111 | //^^^^^^^^^^^^^^^^^ could not convert tokens | 111 | //^^^^^^^^^^^^^^^^^ error: could not convert tokens |
112 | include!("does not exist"); | 112 | include!("does not exist"); |
113 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | 113 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist` |
114 | 114 | ||
115 | env!(invalid); | 115 | env!(invalid); |
116 | //^^^^^^^^^^^^^ could not convert tokens | 116 | //^^^^^^^^^^^^^ error: could not convert tokens |
117 | 117 | ||
118 | env!("OUT_DIR"); | 118 | env!("OUT_DIR"); |
119 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | 119 | //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix |
120 | 120 | ||
121 | compile_error!("compile_error works"); | 121 | compile_error!("compile_error works"); |
122 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | 122 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works |
123 | 123 | ||
124 | // Lazy: | 124 | // Lazy: |
125 | 125 | ||
126 | format_args!(); | 126 | format_args!(); |
127 | //^^^^^^^^^^^^^^ no rule matches input tokens | 127 | //^^^^^^^^^^^^^^ error: no rule matches input tokens |
128 | } | 128 | } |
129 | "#, | 129 | "#, |
130 | ); | 130 | ); |
@@ -141,7 +141,7 @@ fn f() { | |||
141 | m!(); | 141 | m!(); |
142 | 142 | ||
143 | m!(hi); | 143 | m!(hi); |
144 | //^^^^^^ leftover tokens | 144 | //^^^^^^ error: leftover tokens |
145 | } | 145 | } |
146 | "#, | 146 | "#, |
147 | ); | 147 | ); |
@@ -166,7 +166,7 @@ macro_rules! outer { | |||
166 | 166 | ||
167 | fn f() { | 167 | fn f() { |
168 | outer!(); | 168 | outer!(); |
169 | } //^^^^^^^^ leftover tokens | 169 | } //^^^^^^^^ error: leftover tokens |
170 | "#, | 170 | "#, |
171 | ) | 171 | ) |
172 | } | 172 | } |
diff --git a/crates/ide/src/diagnostics/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs index 08e1cfa5f..a9b6d3870 100644 --- a/crates/ide/src/diagnostics/mismatched_arg_count.rs +++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: mismatched-arg-count | 3 | // Diagnostic: mismatched-arg-count |
4 | // | 4 | // |
5 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | 5 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. |
6 | pub(super) fn mismatched_arg_count( | 6 | pub(crate) fn mismatched_arg_count( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::MismatchedArgCount, | 8 | d: &hir::MismatchedArgCount, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -18,7 +18,7 @@ pub(super) fn mismatched_arg_count( | |||
18 | 18 | ||
19 | #[cfg(test)] | 19 | #[cfg(test)] |
20 | mod tests { | 20 | mod tests { |
21 | use crate::diagnostics::tests::check_diagnostics; | 21 | use crate::tests::check_diagnostics; |
22 | 22 | ||
23 | #[test] | 23 | #[test] |
24 | fn simple_free_fn_zero() { | 24 | fn simple_free_fn_zero() { |
@@ -26,7 +26,7 @@ mod tests { | |||
26 | r#" | 26 | r#" |
27 | fn zero() {} | 27 | fn zero() {} |
28 | fn f() { zero(1); } | 28 | fn f() { zero(1); } |
29 | //^^^^^^^ expected 0 arguments, found 1 | 29 | //^^^^^^^ error: expected 0 arguments, found 1 |
30 | "#, | 30 | "#, |
31 | ); | 31 | ); |
32 | 32 | ||
@@ -44,7 +44,7 @@ fn f() { zero(); } | |||
44 | r#" | 44 | r#" |
45 | fn one(arg: u8) {} | 45 | fn one(arg: u8) {} |
46 | fn f() { one(); } | 46 | fn f() { one(); } |
47 | //^^^^^ expected 1 argument, found 0 | 47 | //^^^^^ error: expected 1 argument, found 0 |
48 | "#, | 48 | "#, |
49 | ); | 49 | ); |
50 | 50 | ||
@@ -65,7 +65,7 @@ impl S { fn method(&self) {} } | |||
65 | 65 | ||
66 | fn f() { | 66 | fn f() { |
67 | S::method(); | 67 | S::method(); |
68 | } //^^^^^^^^^^^ expected 1 argument, found 0 | 68 | } //^^^^^^^^^^^ error: expected 1 argument, found 0 |
69 | "#, | 69 | "#, |
70 | ); | 70 | ); |
71 | 71 | ||
@@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} } | |||
91 | 91 | ||
92 | fn f() { | 92 | fn f() { |
93 | S.method(); | 93 | S.method(); |
94 | } //^^^^^^^^^^ expected 1 argument, found 0 | 94 | } //^^^^^^^^^^ error: expected 1 argument, found 0 |
95 | "#, | 95 | "#, |
96 | ); | 96 | ); |
97 | 97 | ||
@@ -131,7 +131,7 @@ fn f() { | |||
131 | struct Tup(u8, u16); | 131 | struct Tup(u8, u16); |
132 | fn f() { | 132 | fn f() { |
133 | Tup(0); | 133 | Tup(0); |
134 | } //^^^^^^ expected 2 arguments, found 1 | 134 | } //^^^^^^ error: expected 2 arguments, found 1 |
135 | "#, | 135 | "#, |
136 | ) | 136 | ) |
137 | } | 137 | } |
@@ -143,7 +143,7 @@ fn f() { | |||
143 | enum En { Variant(u8, u16), } | 143 | enum En { Variant(u8, u16), } |
144 | fn f() { | 144 | fn f() { |
145 | En::Variant(0); | 145 | En::Variant(0); |
146 | } //^^^^^^^^^^^^^^ expected 2 arguments, found 1 | 146 | } //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1 |
147 | "#, | 147 | "#, |
148 | ) | 148 | ) |
149 | } | 149 | } |
@@ -162,9 +162,9 @@ impl Foo { | |||
162 | fn new() { | 162 | fn new() { |
163 | Foo::Bar(0); | 163 | Foo::Bar(0); |
164 | Foo::Bar(0, 1); | 164 | Foo::Bar(0, 1); |
165 | //^^^^^^^^^^^^^^ expected 1 argument, found 2 | 165 | //^^^^^^^^^^^^^^ error: expected 1 argument, found 2 |
166 | Foo::Bar(); | 166 | Foo::Bar(); |
167 | //^^^^^^^^^^ expected 1 argument, found 0 | 167 | //^^^^^^^^^^ error: expected 1 argument, found 0 |
168 | } | 168 | } |
169 | } | 169 | } |
170 | "#, | 170 | "#, |
@@ -185,7 +185,7 @@ fn f() { | |||
185 | unsafe { | 185 | unsafe { |
186 | fixed(0); | 186 | fixed(0); |
187 | fixed(0, 1); | 187 | fixed(0, 1); |
188 | //^^^^^^^^^^^ expected 1 argument, found 2 | 188 | //^^^^^^^^^^^ error: expected 1 argument, found 2 |
189 | varargs(0); | 189 | varargs(0); |
190 | varargs(0, 1); | 190 | varargs(0, 1); |
191 | varargs2(); | 191 | varargs2(); |
@@ -204,10 +204,10 @@ fn f() { | |||
204 | fn main() { | 204 | fn main() { |
205 | let f = |()| (); | 205 | let f = |()| (); |
206 | f(); | 206 | f(); |
207 | //^^^ expected 1 argument, found 0 | 207 | //^^^ error: expected 1 argument, found 0 |
208 | f(()); | 208 | f(()); |
209 | f((), ()); | 209 | f((), ()); |
210 | //^^^^^^^^^ expected 1 argument, found 2 | 210 | //^^^^^^^^^ error: expected 1 argument, found 2 |
211 | } | 211 | } |
212 | "#, | 212 | "#, |
213 | ) | 213 | ) |
diff --git a/crates/ide/src/diagnostics/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs index d01f05041..bc56e0342 100644 --- a/crates/ide/src/diagnostics/missing_fields.rs +++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{db::AstDatabase, InFile}; | 2 | use hir::{db::AstDatabase, InFile}; |
3 | use ide_assists::Assist; | 3 | use ide_db::{assists::Assist, source_change::SourceChange}; |
4 | use ide_db::source_change::SourceChange; | ||
5 | use stdx::format_to; | 4 | use stdx::format_to; |
6 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; | 5 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; |
7 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
8 | 7 | ||
9 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 8 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
10 | 9 | ||
11 | // Diagnostic: missing-fields | 10 | // Diagnostic: missing-fields |
12 | // | 11 | // |
@@ -19,8 +18,8 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | |||
19 | // | 18 | // |
20 | // let a = A { a: 10 }; | 19 | // let a = A { a: 10 }; |
21 | // ``` | 20 | // ``` |
22 | pub(super) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { | 21 | pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { |
23 | let mut message = String::from("Missing structure fields:\n"); | 22 | let mut message = String::from("missing structure fields:\n"); |
24 | for field in &d.missed_fields { | 23 | for field in &d.missed_fields { |
25 | format_to!(message, "- {}\n", field); | 24 | format_to!(message, "- {}\n", field); |
26 | } | 25 | } |
@@ -77,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass | |||
77 | 76 | ||
78 | #[cfg(test)] | 77 | #[cfg(test)] |
79 | mod tests { | 78 | mod tests { |
80 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 79 | use crate::tests::{check_diagnostics, check_fix}; |
81 | 80 | ||
82 | #[test] | 81 | #[test] |
83 | fn missing_record_pat_field_diagnostic() { | 82 | fn missing_record_pat_field_diagnostic() { |
@@ -86,7 +85,7 @@ mod tests { | |||
86 | struct S { foo: i32, bar: () } | 85 | struct S { foo: i32, bar: () } |
87 | fn baz(s: S) { | 86 | fn baz(s: S) { |
88 | let S { foo: _ } = s; | 87 | let S { foo: _ } = s; |
89 | //^ Missing structure fields: | 88 | //^ error: missing structure fields: |
90 | //| - bar | 89 | //| - bar |
91 | } | 90 | } |
92 | "#, | 91 | "#, |
@@ -324,4 +323,33 @@ fn f() { | |||
324 | "#, | 323 | "#, |
325 | ); | 324 | ); |
326 | } | 325 | } |
326 | |||
327 | #[test] | ||
328 | fn import_extern_crate_clash_with_inner_item() { | ||
329 | // This is more of a resolver test, but doesn't really work with the hir_def testsuite. | ||
330 | |||
331 | check_diagnostics( | ||
332 | r#" | ||
333 | //- /lib.rs crate:lib deps:jwt | ||
334 | mod permissions; | ||
335 | |||
336 | use permissions::jwt; | ||
337 | |||
338 | fn f() { | ||
339 | fn inner() {} | ||
340 | jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic | ||
341 | } | ||
342 | |||
343 | //- /permissions.rs | ||
344 | pub mod jwt { | ||
345 | pub struct Claims {} | ||
346 | } | ||
347 | |||
348 | //- /jwt/lib.rs crate:jwt | ||
349 | pub struct Claims { | ||
350 | field: u8, | ||
351 | } | ||
352 | "#, | ||
353 | ); | ||
354 | } | ||
327 | } | 355 | } |
diff --git a/crates/ide/src/diagnostics/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs index b636489b3..947b0f2e2 100644 --- a/crates/ide/src/diagnostics/missing_match_arms.rs +++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use hir::InFile; | 1 | use hir::InFile; |
2 | 2 | ||
3 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 3 | use crate::{Diagnostic, DiagnosticsContext}; |
4 | 4 | ||
5 | // Diagnostic: missing-match-arm | 5 | // Diagnostic: missing-match-arm |
6 | // | 6 | // |
7 | // This diagnostic is triggered if `match` block is missing one or more match arms. | 7 | // This diagnostic is triggered if `match` block is missing one or more match arms. |
8 | pub(super) fn missing_match_arms( | 8 | pub(crate) fn missing_match_arms( |
9 | ctx: &DiagnosticsContext<'_>, | 9 | ctx: &DiagnosticsContext<'_>, |
10 | d: &hir::MissingMatchArms, | 10 | d: &hir::MissingMatchArms, |
11 | ) -> Diagnostic { | 11 | ) -> Diagnostic { |
@@ -17,12 +17,12 @@ pub(super) fn missing_match_arms( | |||
17 | } | 17 | } |
18 | 18 | ||
19 | #[cfg(test)] | 19 | #[cfg(test)] |
20 | pub(super) mod tests { | 20 | mod tests { |
21 | use crate::diagnostics::tests::check_diagnostics; | 21 | use crate::tests::check_diagnostics; |
22 | 22 | ||
23 | fn check_diagnostics_no_bails(ra_fixture: &str) { | 23 | fn check_diagnostics_no_bails(ra_fixture: &str) { |
24 | cov_mark::check_count!(validate_match_bailed_out, 0); | 24 | cov_mark::check_count!(validate_match_bailed_out, 0); |
25 | crate::diagnostics::tests::check_diagnostics(ra_fixture) | 25 | crate::tests::check_diagnostics(ra_fixture) |
26 | } | 26 | } |
27 | 27 | ||
28 | #[test] | 28 | #[test] |
@@ -31,9 +31,9 @@ pub(super) mod tests { | |||
31 | r#" | 31 | r#" |
32 | fn main() { | 32 | fn main() { |
33 | match () { } | 33 | match () { } |
34 | //^^ missing match arm | 34 | //^^ error: missing match arm |
35 | match (()) { } | 35 | match (()) { } |
36 | //^^^^ missing match arm | 36 | //^^^^ error: missing match arm |
37 | 37 | ||
38 | match () { _ => (), } | 38 | match () { _ => (), } |
39 | match () { () => (), } | 39 | match () { () => (), } |
@@ -49,7 +49,7 @@ fn main() { | |||
49 | r#" | 49 | r#" |
50 | fn main() { | 50 | fn main() { |
51 | match ((), ()) { } | 51 | match ((), ()) { } |
52 | //^^^^^^^^ missing match arm | 52 | //^^^^^^^^ error: missing match arm |
53 | 53 | ||
54 | match ((), ()) { ((), ()) => (), } | 54 | match ((), ()) { ((), ()) => (), } |
55 | } | 55 | } |
@@ -63,21 +63,21 @@ fn main() { | |||
63 | r#" | 63 | r#" |
64 | fn test_main() { | 64 | fn test_main() { |
65 | match false { } | 65 | match false { } |
66 | //^^^^^ missing match arm | 66 | //^^^^^ error: missing match arm |
67 | match false { true => (), } | 67 | match false { true => (), } |
68 | //^^^^^ missing match arm | 68 | //^^^^^ error: missing match arm |
69 | match (false, true) {} | 69 | match (false, true) {} |
70 | //^^^^^^^^^^^^^ missing match arm | 70 | //^^^^^^^^^^^^^ error: missing match arm |
71 | match (false, true) { (true, true) => (), } | 71 | match (false, true) { (true, true) => (), } |
72 | //^^^^^^^^^^^^^ missing match arm | 72 | //^^^^^^^^^^^^^ error: missing match arm |
73 | match (false, true) { | 73 | match (false, true) { |
74 | //^^^^^^^^^^^^^ missing match arm | 74 | //^^^^^^^^^^^^^ error: missing match arm |
75 | (false, true) => (), | 75 | (false, true) => (), |
76 | (false, false) => (), | 76 | (false, false) => (), |
77 | (true, false) => (), | 77 | (true, false) => (), |
78 | } | 78 | } |
79 | match (false, true) { (true, _x) => (), } | 79 | match (false, true) { (true, _x) => (), } |
80 | //^^^^^^^^^^^^^ missing match arm | 80 | //^^^^^^^^^^^^^ error: missing match arm |
81 | 81 | ||
82 | match false { true => (), false => (), } | 82 | match false { true => (), false => (), } |
83 | match (false, true) { | 83 | match (false, true) { |
@@ -116,11 +116,11 @@ fn test_main() { | |||
116 | r#" | 116 | r#" |
117 | fn main() { | 117 | fn main() { |
118 | match (false, ((), false)) {} | 118 | match (false, ((), false)) {} |
119 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 119 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
120 | match (false, ((), false)) { (true, ((), true)) => (), } | 120 | match (false, ((), false)) { (true, ((), true)) => (), } |
121 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 121 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
122 | match (false, ((), false)) { (true, _) => (), } | 122 | match (false, ((), false)) { (true, _) => (), } |
123 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 123 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
124 | 124 | ||
125 | match (false, ((), false)) { | 125 | match (false, ((), false)) { |
126 | (true, ((), true)) => (), | 126 | (true, ((), true)) => (), |
@@ -146,12 +146,12 @@ enum Either { A, B, } | |||
146 | 146 | ||
147 | fn main() { | 147 | fn main() { |
148 | match Either::A { } | 148 | match Either::A { } |
149 | //^^^^^^^^^ missing match arm | 149 | //^^^^^^^^^ error: missing match arm |
150 | match Either::B { Either::A => (), } | 150 | match Either::B { Either::A => (), } |
151 | //^^^^^^^^^ missing match arm | 151 | //^^^^^^^^^ error: missing match arm |
152 | 152 | ||
153 | match &Either::B { | 153 | match &Either::B { |
154 | //^^^^^^^^^^ missing match arm | 154 | //^^^^^^^^^^ error: missing match arm |
155 | Either::A => (), | 155 | Either::A => (), |
156 | } | 156 | } |
157 | 157 | ||
@@ -174,9 +174,9 @@ enum Either { A(bool), B } | |||
174 | 174 | ||
175 | fn main() { | 175 | fn main() { |
176 | match Either::B { } | 176 | match Either::B { } |
177 | //^^^^^^^^^ missing match arm | 177 | //^^^^^^^^^ error: missing match arm |
178 | match Either::B { | 178 | match Either::B { |
179 | //^^^^^^^^^ missing match arm | 179 | //^^^^^^^^^ error: missing match arm |
180 | Either::A(true) => (), Either::B => () | 180 | Either::A(true) => (), Either::B => () |
181 | } | 181 | } |
182 | 182 | ||
@@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) } | |||
207 | 207 | ||
208 | fn main() { | 208 | fn main() { |
209 | match Either::A(false) { | 209 | match Either::A(false) { |
210 | //^^^^^^^^^^^^^^^^ missing match arm | 210 | //^^^^^^^^^^^^^^^^ error: missing match arm |
211 | Either::A(_) => (), | 211 | Either::A(_) => (), |
212 | Either::B(false, _) => (), | 212 | Either::B(false, _) => (), |
213 | } | 213 | } |
@@ -352,7 +352,7 @@ fn main() { | |||
352 | Either::A => (), | 352 | Either::A => (), |
353 | } | 353 | } |
354 | match loop { break Foo::A } { | 354 | match loop { break Foo::A } { |
355 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | 355 | //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
356 | Either::A => (), | 356 | Either::A => (), |
357 | } | 357 | } |
358 | match loop { break Foo::A } { | 358 | match loop { break Foo::A } { |
@@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B } | |||
390 | fn main() { | 390 | fn main() { |
391 | let a = Either::A { foo: true }; | 391 | let a = Either::A { foo: true }; |
392 | match a { } | 392 | match a { } |
393 | //^ missing match arm | 393 | //^ error: missing match arm |
394 | match a { Either::A { foo: true } => () } | 394 | match a { Either::A { foo: true } => () } |
395 | //^ missing match arm | 395 | //^ error: missing match arm |
396 | match a { | 396 | match a { |
397 | Either::A { } => (), | 397 | Either::A { } => (), |
398 | //^^^^^^^^^ Missing structure fields: | 398 | //^^^^^^^^^ error: missing structure fields: |
399 | // | - foo | 399 | // | - foo |
400 | Either::B => (), | 400 | Either::B => (), |
401 | } | 401 | } |
402 | match a { | 402 | match a { |
403 | //^ missing match arm | 403 | //^ error: missing match arm |
404 | Either::A { } => (), | 404 | Either::A { } => (), |
405 | } //^^^^^^^^^ Missing structure fields: | 405 | } //^^^^^^^^^ error: missing structure fields: |
406 | // | - foo | 406 | // | - foo |
407 | 407 | ||
408 | match a { | 408 | match a { |
@@ -431,7 +431,7 @@ enum Either { | |||
431 | fn main() { | 431 | fn main() { |
432 | let a = Either::A { foo: true, bar: () }; | 432 | let a = Either::A { foo: true, bar: () }; |
433 | match a { | 433 | match a { |
434 | //^ missing match arm | 434 | //^ error: missing match arm |
435 | Either::A { bar: (), foo: false } => (), | 435 | Either::A { bar: (), foo: false } => (), |
436 | Either::A { foo: true, bar: () } => (), | 436 | Either::A { foo: true, bar: () } => (), |
437 | } | 437 | } |
@@ -458,12 +458,12 @@ enum Either { | |||
458 | fn main() { | 458 | fn main() { |
459 | let a = Either::B; | 459 | let a = Either::B; |
460 | match a { | 460 | match a { |
461 | //^ missing match arm | 461 | //^ error: missing match arm |
462 | Either::A { foo: true, .. } => (), | 462 | Either::A { foo: true, .. } => (), |
463 | Either::B => (), | 463 | Either::B => (), |
464 | } | 464 | } |
465 | match a { | 465 | match a { |
466 | //^ missing match arm | 466 | //^ error: missing match arm |
467 | Either::A { .. } => (), | 467 | Either::A { .. } => (), |
468 | } | 468 | } |
469 | 469 | ||
@@ -493,14 +493,14 @@ enum Either { | |||
493 | 493 | ||
494 | fn main() { | 494 | fn main() { |
495 | match Either::B { | 495 | match Either::B { |
496 | //^^^^^^^^^ missing match arm | 496 | //^^^^^^^^^ error: missing match arm |
497 | Either::A(true, .., true) => (), | 497 | Either::A(true, .., true) => (), |
498 | Either::A(true, .., false) => (), | 498 | Either::A(true, .., false) => (), |
499 | Either::A(false, .., false) => (), | 499 | Either::A(false, .., false) => (), |
500 | Either::B => (), | 500 | Either::B => (), |
501 | } | 501 | } |
502 | match Either::B { | 502 | match Either::B { |
503 | //^^^^^^^^^ missing match arm | 503 | //^^^^^^^^^ error: missing match arm |
504 | Either::A(true, .., true) => (), | 504 | Either::A(true, .., true) => (), |
505 | Either::A(true, .., false) => (), | 505 | Either::A(true, .., false) => (), |
506 | Either::A(.., true) => (), | 506 | Either::A(.., true) => (), |
@@ -537,7 +537,7 @@ fn enum_(never: Never) { | |||
537 | } | 537 | } |
538 | fn enum_ref(never: &Never) { | 538 | fn enum_ref(never: &Never) { |
539 | match never {} | 539 | match never {} |
540 | //^^^^^ missing match arm | 540 | //^^^^^ error: missing match arm |
541 | } | 541 | } |
542 | fn bang(never: !) { | 542 | fn bang(never: !) { |
543 | match never {} | 543 | match never {} |
@@ -561,7 +561,7 @@ fn main() { | |||
561 | Some(never) => match never {}, | 561 | Some(never) => match never {}, |
562 | } | 562 | } |
563 | match Option::<Never>::None { | 563 | match Option::<Never>::None { |
564 | //^^^^^^^^^^^^^^^^^^^^^ missing match arm | 564 | //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
565 | Option::Some(_never) => {}, | 565 | Option::Some(_never) => {}, |
566 | } | 566 | } |
567 | } | 567 | } |
@@ -575,7 +575,7 @@ fn main() { | |||
575 | r#" | 575 | r#" |
576 | fn main() { | 576 | fn main() { |
577 | match (false, true, false) { | 577 | match (false, true, false) { |
578 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 578 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
579 | (false, ..) => (), | 579 | (false, ..) => (), |
580 | } | 580 | } |
581 | }"#, | 581 | }"#, |
@@ -588,7 +588,7 @@ fn main() { | |||
588 | r#" | 588 | r#" |
589 | fn main() { | 589 | fn main() { |
590 | match (false, true, false) { | 590 | match (false, true, false) { |
591 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 591 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
592 | (.., false) => (), | 592 | (.., false) => (), |
593 | } | 593 | } |
594 | }"#, | 594 | }"#, |
@@ -601,7 +601,7 @@ fn main() { | |||
601 | r#" | 601 | r#" |
602 | fn main() { | 602 | fn main() { |
603 | match (false, true, false) { | 603 | match (false, true, false) { |
604 | //^^^^^^^^^^^^^^^^^^^^ missing match arm | 604 | //^^^^^^^^^^^^^^^^^^^^ error: missing match arm |
605 | (true, .., false) => (), | 605 | (true, .., false) => (), |
606 | } | 606 | } |
607 | }"#, | 607 | }"#, |
@@ -614,11 +614,11 @@ fn main() { | |||
614 | r#"struct Foo { a: bool } | 614 | r#"struct Foo { a: bool } |
615 | fn main(f: Foo) { | 615 | fn main(f: Foo) { |
616 | match f {} | 616 | match f {} |
617 | //^ missing match arm | 617 | //^ error: missing match arm |
618 | match f { Foo { a: true } => () } | 618 | match f { Foo { a: true } => () } |
619 | //^ missing match arm | 619 | //^ error: missing match arm |
620 | match &f { Foo { a: true } => () } | 620 | match &f { Foo { a: true } => () } |
621 | //^^ missing match arm | 621 | //^^ error: missing match arm |
622 | match f { Foo { a: _ } => () } | 622 | match f { Foo { a: _ } => () } |
623 | match f { | 623 | match f { |
624 | Foo { a: true } => (), | 624 | Foo { a: true } => (), |
@@ -639,9 +639,9 @@ fn main(f: Foo) { | |||
639 | r#"struct Foo(bool); | 639 | r#"struct Foo(bool); |
640 | fn main(f: Foo) { | 640 | fn main(f: Foo) { |
641 | match f {} | 641 | match f {} |
642 | //^ missing match arm | 642 | //^ error: missing match arm |
643 | match f { Foo(true) => () } | 643 | match f { Foo(true) => () } |
644 | //^ missing match arm | 644 | //^ error: missing match arm |
645 | match f { | 645 | match f { |
646 | Foo(true) => (), | 646 | Foo(true) => (), |
647 | Foo(false) => (), | 647 | Foo(false) => (), |
@@ -657,7 +657,7 @@ fn main(f: Foo) { | |||
657 | r#"struct Foo; | 657 | r#"struct Foo; |
658 | fn main(f: Foo) { | 658 | fn main(f: Foo) { |
659 | match f {} | 659 | match f {} |
660 | //^ missing match arm | 660 | //^ error: missing match arm |
661 | match f { Foo => () } | 661 | match f { Foo => () } |
662 | } | 662 | } |
663 | "#, | 663 | "#, |
@@ -670,9 +670,9 @@ fn main(f: Foo) { | |||
670 | r#"struct Foo { foo: bool, bar: bool } | 670 | r#"struct Foo { foo: bool, bar: bool } |
671 | fn main(f: Foo) { | 671 | fn main(f: Foo) { |
672 | match f { Foo { foo: true, .. } => () } | 672 | match f { Foo { foo: true, .. } => () } |
673 | //^ missing match arm | 673 | //^ error: missing match arm |
674 | match f { | 674 | match f { |
675 | //^ missing match arm | 675 | //^ error: missing match arm |
676 | Foo { foo: true, .. } => (), | 676 | Foo { foo: true, .. } => (), |
677 | Foo { bar: false, .. } => () | 677 | Foo { bar: false, .. } => () |
678 | } | 678 | } |
@@ -693,7 +693,7 @@ fn main(f: Foo) { | |||
693 | fn main() { | 693 | fn main() { |
694 | enum Either { A(bool), B } | 694 | enum Either { A(bool), B } |
695 | match Either::B { | 695 | match Either::B { |
696 | //^^^^^^^^^ missing match arm | 696 | //^^^^^^^^^ error: missing match arm |
697 | Either::A(true | false) => (), | 697 | Either::A(true | false) => (), |
698 | } | 698 | } |
699 | } | 699 | } |
@@ -715,7 +715,7 @@ fn main(v: S) { | |||
715 | match v { S{..} => {} } | 715 | match v { S{..} => {} } |
716 | match v { _ => {} } | 716 | match v { _ => {} } |
717 | match v { } | 717 | match v { } |
718 | //^ missing match arm | 718 | //^ error: missing match arm |
719 | } | 719 | } |
720 | "#, | 720 | "#, |
721 | ); | 721 | ); |
@@ -731,7 +731,7 @@ fn main() { | |||
731 | false => {} | 731 | false => {} |
732 | } | 732 | } |
733 | match true { _x @ true => {} } | 733 | match true { _x @ true => {} } |
734 | //^^^^ missing match arm | 734 | //^^^^ error: missing match arm |
735 | } | 735 | } |
736 | "#, | 736 | "#, |
737 | ); | 737 | ); |
@@ -786,12 +786,12 @@ use lib::E; | |||
786 | fn main() { | 786 | fn main() { |
787 | match E::A { _ => {} } | 787 | match E::A { _ => {} } |
788 | match E::A { | 788 | match E::A { |
789 | //^^^^ missing match arm | 789 | //^^^^ error: missing match arm |
790 | E::A => {} | 790 | E::A => {} |
791 | E::B => {} | 791 | E::B => {} |
792 | } | 792 | } |
793 | match E::A { | 793 | match E::A { |
794 | //^^^^ missing match arm | 794 | //^^^^ error: missing match arm |
795 | E::A | E::B => {} | 795 | E::A | E::B => {} |
796 | } | 796 | } |
797 | } | 797 | } |
@@ -810,7 +810,7 @@ fn main() { | |||
810 | false => {} | 810 | false => {} |
811 | } | 811 | } |
812 | match true { | 812 | match true { |
813 | //^^^^ missing match arm | 813 | //^^^^ error: missing match arm |
814 | true if false => {} | 814 | true if false => {} |
815 | false => {} | 815 | false => {} |
816 | } | 816 | } |
diff --git a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs index 06005d156..c0edcd7d3 100644 --- a/crates/ide/src/diagnostics/missing_ok_or_some_in_tail_expr.rs +++ b/crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, source_change::SourceChange}; |
3 | use ide_db::source_change::SourceChange; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | use text_edit::TextEdit; | 4 | use text_edit::TextEdit; |
6 | 5 | ||
7 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 6 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
8 | 7 | ||
9 | // Diagnostic: missing-ok-or-some-in-tail-expr | 8 | // Diagnostic: missing-ok-or-some-in-tail-expr |
10 | // | 9 | // |
@@ -18,7 +17,7 @@ use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | |||
18 | // 10 | 17 | // 10 |
19 | // } | 18 | // } |
20 | // ``` | 19 | // ``` |
21 | pub(super) fn missing_ok_or_some_in_tail_expr( | 20 | pub(crate) fn missing_ok_or_some_in_tail_expr( |
22 | ctx: &DiagnosticsContext<'_>, | 21 | ctx: &DiagnosticsContext<'_>, |
23 | d: &hir::MissingOkOrSomeInTailExpr, | 22 | d: &hir::MissingOkOrSomeInTailExpr, |
24 | ) -> Diagnostic { | 23 | ) -> Diagnostic { |
@@ -44,32 +43,21 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Op | |||
44 | 43 | ||
45 | #[cfg(test)] | 44 | #[cfg(test)] |
46 | mod tests { | 45 | mod tests { |
47 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 46 | use crate::tests::{check_diagnostics, check_fix}; |
48 | 47 | ||
49 | #[test] | 48 | #[test] |
50 | fn test_wrap_return_type_option() { | 49 | fn test_wrap_return_type_option() { |
51 | check_fix( | 50 | check_fix( |
52 | r#" | 51 | r#" |
53 | //- /main.rs crate:main deps:core | 52 | //- minicore: option, result |
54 | use core::option::Option::{self, Some, None}; | ||
55 | |||
56 | fn div(x: i32, y: i32) -> Option<i32> { | 53 | fn div(x: i32, y: i32) -> Option<i32> { |
57 | if y == 0 { | 54 | if y == 0 { |
58 | return None; | 55 | return None; |
59 | } | 56 | } |
60 | x / y$0 | 57 | x / y$0 |
61 | } | 58 | } |
62 | //- /core/lib.rs crate:core | ||
63 | pub mod result { | ||
64 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
65 | } | ||
66 | pub mod option { | ||
67 | pub enum Option<T> { Some(T), None } | ||
68 | } | ||
69 | "#, | 59 | "#, |
70 | r#" | 60 | r#" |
71 | use core::option::Option::{self, Some, None}; | ||
72 | |||
73 | fn div(x: i32, y: i32) -> Option<i32> { | 61 | fn div(x: i32, y: i32) -> Option<i32> { |
74 | if y == 0 { | 62 | if y == 0 { |
75 | return None; | 63 | return None; |
@@ -84,26 +72,15 @@ fn div(x: i32, y: i32) -> Option<i32> { | |||
84 | fn test_wrap_return_type() { | 72 | fn test_wrap_return_type() { |
85 | check_fix( | 73 | check_fix( |
86 | r#" | 74 | r#" |
87 | //- /main.rs crate:main deps:core | 75 | //- minicore: option, result |
88 | use core::result::Result::{self, Ok, Err}; | ||
89 | |||
90 | fn div(x: i32, y: i32) -> Result<i32, ()> { | 76 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
91 | if y == 0 { | 77 | if y == 0 { |
92 | return Err(()); | 78 | return Err(()); |
93 | } | 79 | } |
94 | x / y$0 | 80 | x / y$0 |
95 | } | 81 | } |
96 | //- /core/lib.rs crate:core | ||
97 | pub mod result { | ||
98 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
99 | } | ||
100 | pub mod option { | ||
101 | pub enum Option<T> { Some(T), None } | ||
102 | } | ||
103 | "#, | 82 | "#, |
104 | r#" | 83 | r#" |
105 | use core::result::Result::{self, Ok, Err}; | ||
106 | |||
107 | fn div(x: i32, y: i32) -> Result<i32, ()> { | 84 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
108 | if y == 0 { | 85 | if y == 0 { |
109 | return Err(()); | 86 | return Err(()); |
@@ -118,26 +95,15 @@ fn div(x: i32, y: i32) -> Result<i32, ()> { | |||
118 | fn test_wrap_return_type_handles_generic_functions() { | 95 | fn test_wrap_return_type_handles_generic_functions() { |
119 | check_fix( | 96 | check_fix( |
120 | r#" | 97 | r#" |
121 | //- /main.rs crate:main deps:core | 98 | //- minicore: option, result |
122 | use core::result::Result::{self, Ok, Err}; | ||
123 | |||
124 | fn div<T>(x: T) -> Result<T, i32> { | 99 | fn div<T>(x: T) -> Result<T, i32> { |
125 | if x == 0 { | 100 | if x == 0 { |
126 | return Err(7); | 101 | return Err(7); |
127 | } | 102 | } |
128 | $0x | 103 | $0x |
129 | } | 104 | } |
130 | //- /core/lib.rs crate:core | ||
131 | pub mod result { | ||
132 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
133 | } | ||
134 | pub mod option { | ||
135 | pub enum Option<T> { Some(T), None } | ||
136 | } | ||
137 | "#, | 105 | "#, |
138 | r#" | 106 | r#" |
139 | use core::result::Result::{self, Ok, Err}; | ||
140 | |||
141 | fn div<T>(x: T) -> Result<T, i32> { | 107 | fn div<T>(x: T) -> Result<T, i32> { |
142 | if x == 0 { | 108 | if x == 0 { |
143 | return Err(7); | 109 | return Err(7); |
@@ -152,9 +118,7 @@ fn div<T>(x: T) -> Result<T, i32> { | |||
152 | fn test_wrap_return_type_handles_type_aliases() { | 118 | fn test_wrap_return_type_handles_type_aliases() { |
153 | check_fix( | 119 | check_fix( |
154 | r#" | 120 | r#" |
155 | //- /main.rs crate:main deps:core | 121 | //- minicore: option, result |
156 | use core::result::Result::{self, Ok, Err}; | ||
157 | |||
158 | type MyResult<T> = Result<T, ()>; | 122 | type MyResult<T> = Result<T, ()>; |
159 | 123 | ||
160 | fn div(x: i32, y: i32) -> MyResult<i32> { | 124 | fn div(x: i32, y: i32) -> MyResult<i32> { |
@@ -163,17 +127,8 @@ fn div(x: i32, y: i32) -> MyResult<i32> { | |||
163 | } | 127 | } |
164 | x $0/ y | 128 | x $0/ y |
165 | } | 129 | } |
166 | //- /core/lib.rs crate:core | ||
167 | pub mod result { | ||
168 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
169 | } | ||
170 | pub mod option { | ||
171 | pub enum Option<T> { Some(T), None } | ||
172 | } | ||
173 | "#, | 130 | "#, |
174 | r#" | 131 | r#" |
175 | use core::result::Result::{self, Ok, Err}; | ||
176 | |||
177 | type MyResult<T> = Result<T, ()>; | 132 | type MyResult<T> = Result<T, ()>; |
178 | 133 | ||
179 | fn div(x: i32, y: i32) -> MyResult<i32> { | 134 | fn div(x: i32, y: i32) -> MyResult<i32> { |
@@ -190,18 +145,8 @@ fn div(x: i32, y: i32) -> MyResult<i32> { | |||
190 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { | 145 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { |
191 | check_diagnostics( | 146 | check_diagnostics( |
192 | r#" | 147 | r#" |
193 | //- /main.rs crate:main deps:core | 148 | //- minicore: option, result |
194 | use core::result::Result::{self, Ok, Err}; | ||
195 | |||
196 | fn foo() -> Result<(), i32> { 0 } | 149 | fn foo() -> Result<(), i32> { 0 } |
197 | |||
198 | //- /core/lib.rs crate:core | ||
199 | pub mod result { | ||
200 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
201 | } | ||
202 | pub mod option { | ||
203 | pub enum Option<T> { Some(T), None } | ||
204 | } | ||
205 | "#, | 150 | "#, |
206 | ); | 151 | ); |
207 | } | 152 | } |
@@ -210,20 +155,10 @@ pub mod option { | |||
210 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { | 155 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { |
211 | check_diagnostics( | 156 | check_diagnostics( |
212 | r#" | 157 | r#" |
213 | //- /main.rs crate:main deps:core | 158 | //- minicore: option, result |
214 | use core::result::Result::{self, Ok, Err}; | ||
215 | |||
216 | enum SomeOtherEnum { Ok(i32), Err(String) } | 159 | enum SomeOtherEnum { Ok(i32), Err(String) } |
217 | 160 | ||
218 | fn foo() -> SomeOtherEnum { 0 } | 161 | fn foo() -> SomeOtherEnum { 0 } |
219 | |||
220 | //- /core/lib.rs crate:core | ||
221 | pub mod result { | ||
222 | pub enum Result<T, E> { Ok(T), Err(E) } | ||
223 | } | ||
224 | pub mod option { | ||
225 | pub enum Option<T> { Some(T), None } | ||
226 | } | ||
227 | "#, | 162 | "#, |
228 | ); | 163 | ); |
229 | } | 164 | } |
diff --git a/crates/ide/src/diagnostics/missing_unsafe.rs b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs index 5c47e8d0a..7acd9228a 100644 --- a/crates/ide/src/diagnostics/missing_unsafe.rs +++ b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: missing-unsafe | 3 | // Diagnostic: missing-unsafe |
4 | // | 4 | // |
5 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | 5 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. |
6 | pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { | 6 | pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { |
7 | Diagnostic::new( | 7 | Diagnostic::new( |
8 | "missing-unsafe", | 8 | "missing-unsafe", |
9 | "this operation is unsafe and requires an unsafe function or block", | 9 | "this operation is unsafe and requires an unsafe function or block", |
@@ -13,7 +13,7 @@ pub(super) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf | |||
13 | 13 | ||
14 | #[cfg(test)] | 14 | #[cfg(test)] |
15 | mod tests { | 15 | mod tests { |
16 | use crate::diagnostics::tests::check_diagnostics; | 16 | use crate::tests::check_diagnostics; |
17 | 17 | ||
18 | #[test] | 18 | #[test] |
19 | fn missing_unsafe_diagnostic_with_raw_ptr() { | 19 | fn missing_unsafe_diagnostic_with_raw_ptr() { |
@@ -23,7 +23,7 @@ fn main() { | |||
23 | let x = &5 as *const usize; | 23 | let x = &5 as *const usize; |
24 | unsafe { let y = *x; } | 24 | unsafe { let y = *x; } |
25 | let z = *x; | 25 | let z = *x; |
26 | } //^^ this operation is unsafe and requires an unsafe function or block | 26 | } //^^ error: this operation is unsafe and requires an unsafe function or block |
27 | "#, | 27 | "#, |
28 | ) | 28 | ) |
29 | } | 29 | } |
@@ -48,9 +48,9 @@ unsafe fn unsafe_fn() { | |||
48 | 48 | ||
49 | fn main() { | 49 | fn main() { |
50 | unsafe_fn(); | 50 | unsafe_fn(); |
51 | //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 51 | //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
52 | HasUnsafe.unsafe_fn(); | 52 | HasUnsafe.unsafe_fn(); |
53 | //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 53 | //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
54 | unsafe { | 54 | unsafe { |
55 | unsafe_fn(); | 55 | unsafe_fn(); |
56 | HasUnsafe.unsafe_fn(); | 56 | HasUnsafe.unsafe_fn(); |
@@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; | |||
72 | 72 | ||
73 | fn main() { | 73 | fn main() { |
74 | let x = STATIC_MUT.a; | 74 | let x = STATIC_MUT.a; |
75 | //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 75 | //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
76 | unsafe { | 76 | unsafe { |
77 | let x = STATIC_MUT.a; | 77 | let x = STATIC_MUT.a; |
78 | } | 78 | } |
@@ -93,7 +93,7 @@ extern "rust-intrinsic" { | |||
93 | fn main() { | 93 | fn main() { |
94 | let _ = bitreverse(12); | 94 | let _ = bitreverse(12); |
95 | let _ = floorf32(12.0); | 95 | let _ = floorf32(12.0); |
96 | //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block | 96 | //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block |
97 | } | 97 | } |
98 | "#, | 98 | "#, |
99 | ); | 99 | ); |
diff --git a/crates/ide/src/diagnostics/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs index edc63c246..92e8867f4 100644 --- a/crates/ide/src/diagnostics/no_such_field.rs +++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs | |||
@@ -6,15 +6,12 @@ use syntax::{ | |||
6 | }; | 6 | }; |
7 | use text_edit::TextEdit; | 7 | use text_edit::TextEdit; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
10 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
11 | Assist, | ||
12 | }; | ||
13 | 10 | ||
14 | // Diagnostic: no-such-field | 11 | // Diagnostic: no-such-field |
15 | // | 12 | // |
16 | // This diagnostic is triggered if created structure does not have field provided in record. | 13 | // This diagnostic is triggered if created structure does not have field provided in record. |
17 | pub(super) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { | 14 | pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { |
18 | Diagnostic::new( | 15 | Diagnostic::new( |
19 | "no-such-field", | 16 | "no-such-field", |
20 | "no such field", | 17 | "no such field", |
@@ -112,7 +109,7 @@ fn missing_record_expr_field_fixes( | |||
112 | 109 | ||
113 | #[cfg(test)] | 110 | #[cfg(test)] |
114 | mod tests { | 111 | mod tests { |
115 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 112 | use crate::tests::{check_diagnostics, check_fix}; |
116 | 113 | ||
117 | #[test] | 114 | #[test] |
118 | fn no_such_field_diagnostics() { | 115 | fn no_such_field_diagnostics() { |
@@ -122,11 +119,11 @@ struct S { foo: i32, bar: () } | |||
122 | impl S { | 119 | impl S { |
123 | fn new() -> S { | 120 | fn new() -> S { |
124 | S { | 121 | S { |
125 | //^ Missing structure fields: | 122 | //^ 💡 error: missing structure fields: |
126 | //| - bar | 123 | //| - bar |
127 | foo: 92, | 124 | foo: 92, |
128 | baz: 62, | 125 | baz: 62, |
129 | //^^^^^^^ no such field | 126 | //^^^^^^^ 💡 error: no such field |
130 | } | 127 | } |
131 | } | 128 | } |
132 | } | 129 | } |
diff --git a/crates/ide/src/diagnostics/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs index 814cb0f8c..4e639f214 100644 --- a/crates/ide/src/diagnostics/remove_this_semicolon.rs +++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs | |||
@@ -3,15 +3,12 @@ use ide_db::source_change::SourceChange; | |||
3 | use syntax::{ast, AstNode}; | 3 | use syntax::{ast, AstNode}; |
4 | use text_edit::TextEdit; | 4 | use text_edit::TextEdit; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
7 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
8 | Assist, | ||
9 | }; | ||
10 | 7 | ||
11 | // Diagnostic: remove-this-semicolon | 8 | // Diagnostic: remove-this-semicolon |
12 | // | 9 | // |
13 | // This diagnostic is triggered when there's an erroneous `;` at the end of the block. | 10 | // This diagnostic is triggered when there's an erroneous `;` at the end of the block. |
14 | pub(super) fn remove_this_semicolon( | 11 | pub(crate) fn remove_this_semicolon( |
15 | ctx: &DiagnosticsContext<'_>, | 12 | ctx: &DiagnosticsContext<'_>, |
16 | d: &hir::RemoveThisSemicolon, | 13 | d: &hir::RemoveThisSemicolon, |
17 | ) -> Diagnostic { | 14 | ) -> Diagnostic { |
@@ -45,14 +42,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::RemoveThisSemicolon) -> Option<V | |||
45 | 42 | ||
46 | #[cfg(test)] | 43 | #[cfg(test)] |
47 | mod tests { | 44 | mod tests { |
48 | use crate::diagnostics::tests::{check_diagnostics, check_fix}; | 45 | use crate::tests::{check_diagnostics, check_fix}; |
49 | 46 | ||
50 | #[test] | 47 | #[test] |
51 | fn missing_semicolon() { | 48 | fn missing_semicolon() { |
52 | check_diagnostics( | 49 | check_diagnostics( |
53 | r#" | 50 | r#" |
54 | fn test() -> i32 { 123; } | 51 | fn test() -> i32 { 123; } |
55 | //^^^ remove this semicolon | 52 | //^^^ 💡 error: remove this semicolon |
56 | "#, | 53 | "#, |
57 | ); | 54 | ); |
58 | } | 55 | } |
diff --git a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index f3b011495..839ceac03 100644 --- a/crates/ide/src/diagnostics/replace_filter_map_next_with_find_map.rs +++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs | |||
@@ -6,15 +6,12 @@ use syntax::{ | |||
6 | }; | 6 | }; |
7 | use text_edit::TextEdit; | 7 | use text_edit::TextEdit; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; |
10 | diagnostics::{fix, Diagnostic, DiagnosticsContext}, | ||
11 | Assist, Severity, | ||
12 | }; | ||
13 | 10 | ||
14 | // Diagnostic: replace-filter-map-next-with-find-map | 11 | // Diagnostic: replace-filter-map-next-with-find-map |
15 | // | 12 | // |
16 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. | 13 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. |
17 | pub(super) fn replace_filter_map_next_with_find_map( | 14 | pub(crate) fn replace_filter_map_next_with_find_map( |
18 | ctx: &DiagnosticsContext<'_>, | 15 | ctx: &DiagnosticsContext<'_>, |
19 | d: &hir::ReplaceFilterMapNextWithFindMap, | 16 | d: &hir::ReplaceFilterMapNextWithFindMap, |
20 | ) -> Diagnostic { | 17 | ) -> Diagnostic { |
@@ -58,44 +55,16 @@ fn fixes( | |||
58 | 55 | ||
59 | #[cfg(test)] | 56 | #[cfg(test)] |
60 | mod tests { | 57 | mod tests { |
61 | use crate::diagnostics::tests::check_fix; | 58 | use crate::tests::{check_diagnostics, check_fix}; |
62 | |||
63 | // Register the required standard library types to make the tests work | ||
64 | #[track_caller] | ||
65 | fn check_diagnostics(ra_fixture: &str) { | ||
66 | let prefix = r#" | ||
67 | //- /main.rs crate:main deps:core | ||
68 | use core::iter::Iterator; | ||
69 | use core::option::Option::{self, Some, None}; | ||
70 | "#; | ||
71 | let suffix = r#" | ||
72 | //- /core/lib.rs crate:core | ||
73 | pub mod option { | ||
74 | pub enum Option<T> { Some(T), None } | ||
75 | } | ||
76 | pub mod iter { | ||
77 | pub trait Iterator { | ||
78 | type Item; | ||
79 | fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap } | ||
80 | fn next(&mut self) -> Option<Self::Item>; | ||
81 | } | ||
82 | pub struct FilterMap {} | ||
83 | impl Iterator for FilterMap { | ||
84 | type Item = i32; | ||
85 | fn next(&mut self) -> i32 { 7 } | ||
86 | } | ||
87 | } | ||
88 | "#; | ||
89 | crate::diagnostics::tests::check_diagnostics(&format!("{}{}{}", prefix, ra_fixture, suffix)) | ||
90 | } | ||
91 | 59 | ||
92 | #[test] | 60 | #[test] |
93 | fn replace_filter_map_next_with_find_map2() { | 61 | fn replace_filter_map_next_with_find_map2() { |
94 | check_diagnostics( | 62 | check_diagnostics( |
95 | r#" | 63 | r#" |
96 | fn foo() { | 64 | //- minicore: iterators |
97 | let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | 65 | fn foo() { |
98 | } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) | 66 | let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); |
67 | } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..) | ||
99 | "#, | 68 | "#, |
100 | ); | 69 | ); |
101 | } | 70 | } |
@@ -104,11 +73,11 @@ pub mod iter { | |||
104 | fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { | 73 | fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() { |
105 | check_diagnostics( | 74 | check_diagnostics( |
106 | r#" | 75 | r#" |
76 | //- minicore: iterators | ||
107 | fn foo() { | 77 | fn foo() { |
108 | let m = [1, 2, 3] | 78 | let m = core::iter::repeat(()) |
109 | .iter() | 79 | .filter_map(|()| Some(92)) |
110 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | 80 | .count(); |
111 | .len(); | ||
112 | } | 81 | } |
113 | "#, | 82 | "#, |
114 | ); | 83 | ); |
@@ -118,12 +87,12 @@ fn foo() { | |||
118 | fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { | 87 | fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() { |
119 | check_diagnostics( | 88 | check_diagnostics( |
120 | r#" | 89 | r#" |
90 | //- minicore: iterators | ||
121 | fn foo() { | 91 | fn foo() { |
122 | let m = [1, 2, 3] | 92 | let m = core::iter::repeat(()) |
123 | .iter() | 93 | .filter_map(|()| Some(92)) |
124 | .filter_map(|x| if *x == 2 { Some (4) } else { None }) | ||
125 | .map(|x| x + 2) | 94 | .map(|x| x + 2) |
126 | .len(); | 95 | .next(); |
127 | } | 96 | } |
128 | "#, | 97 | "#, |
129 | ); | 98 | ); |
@@ -133,10 +102,10 @@ fn foo() { | |||
133 | fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { | 102 | fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() { |
134 | check_diagnostics( | 103 | check_diagnostics( |
135 | r#" | 104 | r#" |
105 | //- minicore: iterators | ||
136 | fn foo() { | 106 | fn foo() { |
137 | let m = [1, 2, 3] | 107 | let m = core::iter::repeat(()) |
138 | .iter() | 108 | .filter_map(|()| Some(92)); |
139 | .filter_map(|x| if *x == 2 { Some (4) } else { None }); | ||
140 | let n = m.next(); | 109 | let n = m.next(); |
141 | } | 110 | } |
142 | "#, | 111 | "#, |
@@ -147,34 +116,14 @@ fn foo() { | |||
147 | fn replace_with_wind_map() { | 116 | fn replace_with_wind_map() { |
148 | check_fix( | 117 | check_fix( |
149 | r#" | 118 | r#" |
150 | //- /main.rs crate:main deps:core | 119 | //- minicore: iterators |
151 | use core::iter::Iterator; | ||
152 | use core::option::Option::{self, Some, None}; | ||
153 | fn foo() { | 120 | fn foo() { |
154 | let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); | 121 | let m = core::iter::repeat(()).$0filter_map(|()| Some(92)).next(); |
155 | } | ||
156 | //- /core/lib.rs crate:core | ||
157 | pub mod option { | ||
158 | pub enum Option<T> { Some(T), None } | ||
159 | } | ||
160 | pub mod iter { | ||
161 | pub trait Iterator { | ||
162 | type Item; | ||
163 | fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap } | ||
164 | fn next(&mut self) -> Option<Self::Item>; | ||
165 | } | ||
166 | pub struct FilterMap {} | ||
167 | impl Iterator for FilterMap { | ||
168 | type Item = i32; | ||
169 | fn next(&mut self) -> i32 { 7 } | ||
170 | } | ||
171 | } | 122 | } |
172 | "#, | 123 | "#, |
173 | r#" | 124 | r#" |
174 | use core::iter::Iterator; | ||
175 | use core::option::Option::{self, Some, None}; | ||
176 | fn foo() { | 125 | fn foo() { |
177 | let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None }); | 126 | let m = core::iter::repeat(()).find_map(|()| Some(92)); |
178 | } | 127 | } |
179 | "#, | 128 | "#, |
180 | ) | 129 | ) |
diff --git a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs index 09faa3bbc..e879de75c 100644 --- a/crates/ide/src/diagnostics/unimplemented_builtin_macro.rs +++ b/crates/ide_diagnostics/src/handlers/unimplemented_builtin_macro.rs | |||
@@ -1,12 +1,9 @@ | |||
1 | use crate::{ | 1 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | 2 | ||
6 | // Diagnostic: unimplemented-builtin-macro | 3 | // Diagnostic: unimplemented-builtin-macro |
7 | // | 4 | // |
8 | // This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer | 5 | // This diagnostic is shown for builtin macros which are not yet implemented by rust-analyzer |
9 | pub(super) fn unimplemented_builtin_macro( | 6 | pub(crate) fn unimplemented_builtin_macro( |
10 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
11 | d: &hir::UnimplementedBuiltinMacro, | 8 | d: &hir::UnimplementedBuiltinMacro, |
12 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs index a5b2e3399..8e601fa48 100644 --- a/crates/ide/src/diagnostics/unlinked_file.rs +++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs | |||
@@ -12,37 +12,31 @@ use syntax::{ | |||
12 | }; | 12 | }; |
13 | use text_edit::TextEdit; | 13 | use text_edit::TextEdit; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
16 | diagnostics::{fix, DiagnosticsContext}, | ||
17 | Assist, Diagnostic, | ||
18 | }; | ||
19 | |||
20 | #[derive(Debug)] | ||
21 | pub(crate) struct UnlinkedFile { | ||
22 | pub(crate) file: FileId, | ||
23 | } | ||
24 | 16 | ||
25 | // Diagnostic: unlinked-file | 17 | // Diagnostic: unlinked-file |
26 | // | 18 | // |
27 | // This diagnostic is shown for files that are not included in any crate, or files that are part of | 19 | // This diagnostic is shown for files that are not included in any crate, or files that are part of |
28 | // crates rust-analyzer failed to discover. The file will not have IDE features available. | 20 | // crates rust-analyzer failed to discover. The file will not have IDE features available. |
29 | pub(super) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { | 21 | pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec<Diagnostic>, file_id: FileId) { |
30 | // Limit diagnostic to the first few characters in the file. This matches how VS Code | 22 | // Limit diagnostic to the first few characters in the file. This matches how VS Code |
31 | // renders it with the full span, but on other editors, and is less invasive. | 23 | // renders it with the full span, but on other editors, and is less invasive. |
32 | let range = ctx.sema.db.parse(d.file).syntax_node().text_range(); | 24 | let range = ctx.sema.db.parse(file_id).syntax_node().text_range(); |
33 | // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. | 25 | // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. |
34 | let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); | 26 | let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); |
35 | 27 | ||
36 | Diagnostic::new("unlinked-file", "file not included in module tree", range) | 28 | acc.push( |
37 | .with_fixes(fixes(ctx, d)) | 29 | Diagnostic::new("unlinked-file", "file not included in module tree", range) |
30 | .with_fixes(fixes(ctx, file_id)), | ||
31 | ); | ||
38 | } | 32 | } |
39 | 33 | ||
40 | fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { | 34 | fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option<Vec<Assist>> { |
41 | // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, | 35 | // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, |
42 | // suggest that as a fix. | 36 | // suggest that as a fix. |
43 | 37 | ||
44 | let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file)); | 38 | let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id)); |
45 | let our_path = source_root.path_for_file(&d.file)?; | 39 | let our_path = source_root.path_for_file(&file_id)?; |
46 | let module_name = our_path.name_and_extension()?.0; | 40 | let module_name = our_path.name_and_extension()?.0; |
47 | 41 | ||
48 | // Candidates to look for: | 42 | // Candidates to look for: |
@@ -71,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { | |||
71 | } | 65 | } |
72 | 66 | ||
73 | if module.origin.file_id() == Some(*parent_id) { | 67 | if module.origin.file_id() == Some(*parent_id) { |
74 | return make_fixes(ctx.sema.db, *parent_id, module_name, d.file); | 68 | return make_fixes(ctx.sema.db, *parent_id, module_name, file_id); |
75 | } | 69 | } |
76 | } | 70 | } |
77 | } | 71 | } |
@@ -164,7 +158,7 @@ fn make_fixes( | |||
164 | 158 | ||
165 | #[cfg(test)] | 159 | #[cfg(test)] |
166 | mod tests { | 160 | mod tests { |
167 | use crate::diagnostics::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; | 161 | use crate::tests::{check_diagnostics, check_fix, check_fixes, check_no_fix}; |
168 | 162 | ||
169 | #[test] | 163 | #[test] |
170 | fn unlinked_file_prepend_first_item() { | 164 | fn unlinked_file_prepend_first_item() { |
diff --git a/crates/ide/src/diagnostics/unresolved_extern_crate.rs b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs index 2ea79c2ee..74e4a69c6 100644 --- a/crates/ide/src/diagnostics/unresolved_extern_crate.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: unresolved-extern-crate | 3 | // Diagnostic: unresolved-extern-crate |
4 | // | 4 | // |
5 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. | 5 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. |
6 | pub(super) fn unresolved_extern_crate( | 6 | pub(crate) fn unresolved_extern_crate( |
7 | ctx: &DiagnosticsContext<'_>, | 7 | ctx: &DiagnosticsContext<'_>, |
8 | d: &hir::UnresolvedExternCrate, | 8 | d: &hir::UnresolvedExternCrate, |
9 | ) -> Diagnostic { | 9 | ) -> Diagnostic { |
@@ -16,7 +16,7 @@ pub(super) fn unresolved_extern_crate( | |||
16 | 16 | ||
17 | #[cfg(test)] | 17 | #[cfg(test)] |
18 | mod tests { | 18 | mod tests { |
19 | use crate::diagnostics::tests::check_diagnostics; | 19 | use crate::tests::check_diagnostics; |
20 | 20 | ||
21 | #[test] | 21 | #[test] |
22 | fn unresolved_extern_crate() { | 22 | fn unresolved_extern_crate() { |
@@ -25,7 +25,7 @@ mod tests { | |||
25 | //- /main.rs crate:main deps:core | 25 | //- /main.rs crate:main deps:core |
26 | extern crate core; | 26 | extern crate core; |
27 | extern crate doesnotexist; | 27 | extern crate doesnotexist; |
28 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 28 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
29 | //- /lib.rs crate:core | 29 | //- /lib.rs crate:core |
30 | "#, | 30 | "#, |
31 | ); | 31 | ); |
@@ -38,7 +38,7 @@ extern crate core; | |||
38 | r#" | 38 | r#" |
39 | //- /lib.rs | 39 | //- /lib.rs |
40 | extern crate doesnotexist; | 40 | extern crate doesnotexist; |
41 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 41 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
42 | // Should not error. | 42 | // Should not error. |
43 | extern crate self as foo; | 43 | extern crate self as foo; |
44 | struct Foo; | 44 | struct Foo; |
diff --git a/crates/ide/src/diagnostics/unresolved_import.rs b/crates/ide_diagnostics/src/handlers/unresolved_import.rs index 1cbf96ba1..e52a88459 100644 --- a/crates/ide/src/diagnostics/unresolved_import.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_import.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 1 | use crate::{Diagnostic, DiagnosticsContext}; |
2 | 2 | ||
3 | // Diagnostic: unresolved-import | 3 | // Diagnostic: unresolved-import |
4 | // | 4 | // |
5 | // This diagnostic is triggered if rust-analyzer is unable to resolve a path in | 5 | // This diagnostic is triggered if rust-analyzer is unable to resolve a path in |
6 | // a `use` declaration. | 6 | // a `use` declaration. |
7 | pub(super) fn unresolved_import( | 7 | pub(crate) fn unresolved_import( |
8 | ctx: &DiagnosticsContext<'_>, | 8 | ctx: &DiagnosticsContext<'_>, |
9 | d: &hir::UnresolvedImport, | 9 | d: &hir::UnresolvedImport, |
10 | ) -> Diagnostic { | 10 | ) -> Diagnostic { |
@@ -22,7 +22,7 @@ pub(super) fn unresolved_import( | |||
22 | 22 | ||
23 | #[cfg(test)] | 23 | #[cfg(test)] |
24 | mod tests { | 24 | mod tests { |
25 | use crate::diagnostics::tests::check_diagnostics; | 25 | use crate::tests::check_diagnostics; |
26 | 26 | ||
27 | #[test] | 27 | #[test] |
28 | fn unresolved_import() { | 28 | fn unresolved_import() { |
@@ -30,7 +30,7 @@ mod tests { | |||
30 | r#" | 30 | r#" |
31 | use does_exist; | 31 | use does_exist; |
32 | use does_not_exist; | 32 | use does_not_exist; |
33 | //^^^^^^^^^^^^^^ unresolved import | 33 | //^^^^^^^^^^^^^^ error: unresolved import |
34 | 34 | ||
35 | mod does_exist {} | 35 | mod does_exist {} |
36 | "#, | 36 | "#, |
@@ -43,18 +43,18 @@ mod does_exist {} | |||
43 | check_diagnostics( | 43 | check_diagnostics( |
44 | r#" | 44 | r#" |
45 | use does_exist::{Exists, DoesntExist}; | 45 | use does_exist::{Exists, DoesntExist}; |
46 | //^^^^^^^^^^^ unresolved import | 46 | //^^^^^^^^^^^ error: unresolved import |
47 | 47 | ||
48 | use {does_not_exist::*, does_exist}; | 48 | use {does_not_exist::*, does_exist}; |
49 | //^^^^^^^^^^^^^^^^^ unresolved import | 49 | //^^^^^^^^^^^^^^^^^ error: unresolved import |
50 | 50 | ||
51 | use does_not_exist::{ | 51 | use does_not_exist::{ |
52 | a, | 52 | a, |
53 | //^ unresolved import | 53 | //^ error: unresolved import |
54 | b, | 54 | b, |
55 | //^ unresolved import | 55 | //^ error: unresolved import |
56 | c, | 56 | c, |
57 | //^ unresolved import | 57 | //^ error: unresolved import |
58 | }; | 58 | }; |
59 | 59 | ||
60 | mod does_exist { | 60 | mod does_exist { |
@@ -71,18 +71,18 @@ mod does_exist { | |||
71 | //- /main.rs crate:main | 71 | //- /main.rs crate:main |
72 | mod a { | 72 | mod a { |
73 | extern crate doesnotexist; | 73 | extern crate doesnotexist; |
74 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 74 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate |
75 | 75 | ||
76 | // Should not error, since we already errored for the missing crate. | 76 | // Should not error, since we already errored for the missing crate. |
77 | use doesnotexist::{self, bla, *}; | 77 | use doesnotexist::{self, bla, *}; |
78 | 78 | ||
79 | use crate::doesnotexist; | 79 | use crate::doesnotexist; |
80 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 80 | //^^^^^^^^^^^^^^^^^^^ error: unresolved import |
81 | } | 81 | } |
82 | 82 | ||
83 | mod m { | 83 | mod m { |
84 | use super::doesnotexist; | 84 | use super::doesnotexist; |
85 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 85 | //^^^^^^^^^^^^^^^^^^^ error: unresolved import |
86 | } | 86 | } |
87 | "#, | 87 | "#, |
88 | ); | 88 | ); |
diff --git a/crates/ide/src/diagnostics/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs index 15b6a2730..f0f7725db 100644 --- a/crates/ide/src/diagnostics/unresolved_macro_call.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | 1 | use hir::{db::AstDatabase, InFile}; |
2 | use syntax::{AstNode, SyntaxNodePtr}; | 2 | use syntax::{AstNode, SyntaxNodePtr}; |
3 | 3 | ||
4 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | 4 | use crate::{Diagnostic, DiagnosticsContext}; |
5 | 5 | ||
6 | // Diagnostic: unresolved-macro-call | 6 | // Diagnostic: unresolved-macro-call |
7 | // | 7 | // |
8 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path | 8 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path |
9 | // to a macro in a macro invocation. | 9 | // to a macro in a macro invocation. |
10 | pub(super) fn unresolved_macro_call( | 10 | pub(crate) fn unresolved_macro_call( |
11 | ctx: &DiagnosticsContext<'_>, | 11 | ctx: &DiagnosticsContext<'_>, |
12 | d: &hir::UnresolvedMacroCall, | 12 | d: &hir::UnresolvedMacroCall, |
13 | ) -> Diagnostic { | 13 | ) -> Diagnostic { |
@@ -32,7 +32,7 @@ pub(super) fn unresolved_macro_call( | |||
32 | 32 | ||
33 | #[cfg(test)] | 33 | #[cfg(test)] |
34 | mod tests { | 34 | mod tests { |
35 | use crate::diagnostics::tests::check_diagnostics; | 35 | use crate::tests::check_diagnostics; |
36 | 36 | ||
37 | #[test] | 37 | #[test] |
38 | fn unresolved_macro_diag() { | 38 | fn unresolved_macro_diag() { |
@@ -40,7 +40,7 @@ mod tests { | |||
40 | r#" | 40 | r#" |
41 | fn f() { | 41 | fn f() { |
42 | m!(); | 42 | m!(); |
43 | } //^ unresolved macro `m!` | 43 | } //^ error: unresolved macro `m!` |
44 | 44 | ||
45 | "#, | 45 | "#, |
46 | ); | 46 | ); |
@@ -51,7 +51,7 @@ fn f() { | |||
51 | check_diagnostics( | 51 | check_diagnostics( |
52 | r#" | 52 | r#" |
53 | foo::bar!(92); | 53 | foo::bar!(92); |
54 | //^^^ unresolved macro `foo::bar!` | 54 | //^^^ error: unresolved macro `foo::bar!` |
55 | "#, | 55 | "#, |
56 | ); | 56 | ); |
57 | } | 57 | } |
@@ -63,7 +63,7 @@ foo::bar!(92); | |||
63 | macro_rules! m { () => {} } | 63 | macro_rules! m { () => {} } |
64 | 64 | ||
65 | m!(); m2!(); | 65 | m!(); m2!(); |
66 | //^^ unresolved macro `self::m2!` | 66 | //^^ error: unresolved macro `self::m2!` |
67 | "#, | 67 | "#, |
68 | ); | 68 | ); |
69 | } | 69 | } |
@@ -77,7 +77,7 @@ mod mac { | |||
77 | macro_rules! m { () => {} } } | 77 | macro_rules! m { () => {} } } |
78 | 78 | ||
79 | self::m!(); self::m2!(); | 79 | self::m!(); self::m2!(); |
80 | //^^ unresolved macro `self::m2!` | 80 | //^^ error: unresolved macro `self::m2!` |
81 | "#, | 81 | "#, |
82 | ); | 82 | ); |
83 | } | 83 | } |
diff --git a/crates/ide/src/diagnostics/unresolved_module.rs b/crates/ide_diagnostics/src/handlers/unresolved_module.rs index 977b46414..61fc43604 100644 --- a/crates/ide/src/diagnostics/unresolved_module.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_module.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; |
3 | use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit}; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::diagnostics::{fix, Diagnostic, DiagnosticsContext}; | 5 | use crate::{fix, Diagnostic, DiagnosticsContext}; |
7 | 6 | ||
8 | // Diagnostic: unresolved-module | 7 | // Diagnostic: unresolved-module |
9 | // | 8 | // |
10 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 9 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. |
11 | pub(super) fn unresolved_module( | 10 | pub(crate) fn unresolved_module( |
12 | ctx: &DiagnosticsContext<'_>, | 11 | ctx: &DiagnosticsContext<'_>, |
13 | d: &hir::UnresolvedModule, | 12 | d: &hir::UnresolvedModule, |
14 | ) -> Diagnostic { | 13 | ) -> Diagnostic { |
@@ -42,7 +41,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option<Vec< | |||
42 | mod tests { | 41 | mod tests { |
43 | use expect_test::expect; | 42 | use expect_test::expect; |
44 | 43 | ||
45 | use crate::diagnostics::tests::{check_diagnostics, check_expect}; | 44 | use crate::tests::{check_diagnostics, check_expect}; |
46 | 45 | ||
47 | #[test] | 46 | #[test] |
48 | fn unresolved_module() { | 47 | fn unresolved_module() { |
@@ -51,7 +50,7 @@ mod tests { | |||
51 | //- /lib.rs | 50 | //- /lib.rs |
52 | mod foo; | 51 | mod foo; |
53 | mod bar; | 52 | mod bar; |
54 | //^^^^^^^^ unresolved module | 53 | //^^^^^^^^ 💡 error: unresolved module |
55 | mod baz {} | 54 | mod baz {} |
56 | //- /foo.rs | 55 | //- /foo.rs |
57 | "#, | 56 | "#, |
diff --git a/crates/ide/src/diagnostics/unresolved_proc_macro.rs b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs index 3dc6ab451..fde1d1323 100644 --- a/crates/ide/src/diagnostics/unresolved_proc_macro.rs +++ b/crates/ide_diagnostics/src/handlers/unresolved_proc_macro.rs | |||
@@ -1,7 +1,4 @@ | |||
1 | use crate::{ | 1 | use crate::{Diagnostic, DiagnosticsContext, Severity}; |
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | 2 | ||
6 | // Diagnostic: unresolved-proc-macro | 3 | // Diagnostic: unresolved-proc-macro |
7 | // | 4 | // |
@@ -12,7 +9,7 @@ use crate::{ | |||
12 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | 9 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the |
13 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | 10 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can |
14 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | 11 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). |
15 | pub(super) fn unresolved_proc_macro( | 12 | pub(crate) fn unresolved_proc_macro( |
16 | ctx: &DiagnosticsContext<'_>, | 13 | ctx: &DiagnosticsContext<'_>, |
17 | d: &hir::UnresolvedProcMacro, | 14 | d: &hir::UnresolvedProcMacro, |
18 | ) -> Diagnostic { | 15 | ) -> Diagnostic { |
diff --git a/crates/ide_diagnostics/src/handlers/useless_braces.rs b/crates/ide_diagnostics/src/handlers/useless_braces.rs new file mode 100644 index 000000000..8b9330e04 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/useless_braces.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | use ide_db::{base_db::FileId, source_change::SourceChange}; | ||
2 | use itertools::Itertools; | ||
3 | use syntax::{ast, AstNode, SyntaxNode, TextRange}; | ||
4 | use text_edit::TextEdit; | ||
5 | |||
6 | use crate::{fix, Diagnostic, Severity}; | ||
7 | |||
8 | // Diagnostic: unnecessary-braces | ||
9 | // | ||
10 | // Diagnostic for unnecessary braces in `use` items. | ||
11 | pub(crate) fn useless_braces( | ||
12 | acc: &mut Vec<Diagnostic>, | ||
13 | file_id: FileId, | ||
14 | node: &SyntaxNode, | ||
15 | ) -> Option<()> { | ||
16 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | ||
17 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | ||
18 | // If there is a comment inside the bracketed `use`, | ||
19 | // assume it is a commented out module path and don't show diagnostic. | ||
20 | if use_tree_list.has_inner_comment() { | ||
21 | return Some(()); | ||
22 | } | ||
23 | |||
24 | let use_range = use_tree_list.syntax().text_range(); | ||
25 | let edit = remove_braces(&single_use_tree).unwrap_or_else(|| { | ||
26 | let to_replace = single_use_tree.syntax().text().to_string(); | ||
27 | let mut edit_builder = TextEdit::builder(); | ||
28 | edit_builder.delete(use_range); | ||
29 | edit_builder.insert(use_range.start(), to_replace); | ||
30 | edit_builder.finish() | ||
31 | }); | ||
32 | |||
33 | acc.push( | ||
34 | Diagnostic::new( | ||
35 | "unnecessary-braces", | ||
36 | "Unnecessary braces in use statement".to_string(), | ||
37 | use_range, | ||
38 | ) | ||
39 | .severity(Severity::WeakWarning) | ||
40 | .with_fixes(Some(vec![fix( | ||
41 | "remove_braces", | ||
42 | "Remove unnecessary braces", | ||
43 | SourceChange::from_text_edit(file_id, edit), | ||
44 | use_range, | ||
45 | )])), | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | Some(()) | ||
50 | } | ||
51 | |||
52 | fn remove_braces(single_use_tree: &ast::UseTree) -> Option<TextEdit> { | ||
53 | let use_tree_list_node = single_use_tree.syntax().parent()?; | ||
54 | if single_use_tree.path()?.segment()?.self_token().is_some() { | ||
55 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | ||
56 | let end = use_tree_list_node.text_range().end(); | ||
57 | return Some(TextEdit::delete(TextRange::new(start, end))); | ||
58 | } | ||
59 | None | ||
60 | } | ||
61 | |||
62 | #[cfg(test)] | ||
63 | mod tests { | ||
64 | use crate::tests::{check_diagnostics, check_fix}; | ||
65 | |||
66 | #[test] | ||
67 | fn test_check_unnecessary_braces_in_use_statement() { | ||
68 | check_diagnostics( | ||
69 | r#" | ||
70 | use a; | ||
71 | use a::{c, d::e}; | ||
72 | |||
73 | mod a { | ||
74 | mod c {} | ||
75 | mod d { | ||
76 | mod e {} | ||
77 | } | ||
78 | } | ||
79 | "#, | ||
80 | ); | ||
81 | check_diagnostics( | ||
82 | r#" | ||
83 | use a; | ||
84 | use a::{ | ||
85 | c, | ||
86 | // d::e | ||
87 | }; | ||
88 | |||
89 | mod a { | ||
90 | mod c {} | ||
91 | mod d { | ||
92 | mod e {} | ||
93 | } | ||
94 | } | ||
95 | "#, | ||
96 | ); | ||
97 | check_fix( | ||
98 | r#" | ||
99 | mod b {} | ||
100 | use {$0b}; | ||
101 | "#, | ||
102 | r#" | ||
103 | mod b {} | ||
104 | use b; | ||
105 | "#, | ||
106 | ); | ||
107 | check_fix( | ||
108 | r#" | ||
109 | mod b {} | ||
110 | use {b$0}; | ||
111 | "#, | ||
112 | r#" | ||
113 | mod b {} | ||
114 | use b; | ||
115 | "#, | ||
116 | ); | ||
117 | check_fix( | ||
118 | r#" | ||
119 | mod a { mod c {} } | ||
120 | use a::{c$0}; | ||
121 | "#, | ||
122 | r#" | ||
123 | mod a { mod c {} } | ||
124 | use a::c; | ||
125 | "#, | ||
126 | ); | ||
127 | check_fix( | ||
128 | r#" | ||
129 | mod a {} | ||
130 | use a::{self$0}; | ||
131 | "#, | ||
132 | r#" | ||
133 | mod a {} | ||
134 | use a; | ||
135 | "#, | ||
136 | ); | ||
137 | check_fix( | ||
138 | r#" | ||
139 | mod a { mod c {} mod d { mod e {} } } | ||
140 | use a::{c, d::{e$0}}; | ||
141 | "#, | ||
142 | r#" | ||
143 | mod a { mod c {} mod d { mod e {} } } | ||
144 | use a::{c, d::e}; | ||
145 | "#, | ||
146 | ); | ||
147 | } | ||
148 | } | ||
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs new file mode 100644 index 000000000..6ad1b4373 --- /dev/null +++ b/crates/ide_diagnostics/src/lib.rs | |||
@@ -0,0 +1,374 @@ | |||
1 | //! Diagnostics rendering and fixits. | ||
2 | //! | ||
3 | //! Most of the diagnostics originate from the dark depth of the compiler, and | ||
4 | //! are originally expressed in term of IR. When we emit the diagnostic, we are | ||
5 | //! usually not in the position to decide how to best "render" it in terms of | ||
6 | //! user-authored source code. We are especially not in the position to offer | ||
7 | //! fixits, as the compiler completely lacks the infrastructure to edit the | ||
8 | //! source code. | ||
9 | //! | ||
10 | //! Instead, we "bubble up" raw, structured diagnostics until the `hir` crate, | ||
11 | //! where we "cook" them so that each diagnostic is formulated in terms of `hir` | ||
12 | //! types. Well, at least that's the aspiration, the "cooking" is somewhat | ||
13 | //! ad-hoc at the moment. Anyways, we get a bunch of ide-friendly diagnostic | ||
14 | //! structs from hir, and we want to render them to unified serializable | ||
15 | //! representation (span, level, message) here. If we can, we also provide | ||
16 | //! fixits. By the way, that's why we want to keep diagnostics structured | ||
17 | //! internally -- so that we have all the info to make fixes. | ||
18 | //! | ||
19 | //! We have one "handler" module per diagnostic code. Such a module contains | ||
20 | //! rendering, optional fixes and tests. It's OK if some low-level compiler | ||
21 | //! functionality ends up being tested via a diagnostic. | ||
22 | //! | ||
23 | //! There are also a couple of ad-hoc diagnostics implemented directly here, we | ||
24 | //! don't yet have a great pattern for how to do them properly. | ||
25 | |||
26 | mod handlers { | ||
27 | pub(crate) mod break_outside_of_loop; | ||
28 | pub(crate) mod inactive_code; | ||
29 | pub(crate) mod incorrect_case; | ||
30 | pub(crate) mod macro_error; | ||
31 | pub(crate) mod mismatched_arg_count; | ||
32 | pub(crate) mod missing_fields; | ||
33 | pub(crate) mod missing_match_arms; | ||
34 | pub(crate) mod missing_ok_or_some_in_tail_expr; | ||
35 | pub(crate) mod missing_unsafe; | ||
36 | pub(crate) mod no_such_field; | ||
37 | pub(crate) mod remove_this_semicolon; | ||
38 | pub(crate) mod replace_filter_map_next_with_find_map; | ||
39 | pub(crate) mod unimplemented_builtin_macro; | ||
40 | pub(crate) mod unresolved_extern_crate; | ||
41 | pub(crate) mod unresolved_import; | ||
42 | pub(crate) mod unresolved_macro_call; | ||
43 | pub(crate) mod unresolved_module; | ||
44 | pub(crate) mod unresolved_proc_macro; | ||
45 | |||
46 | // The handlers bellow are unusual, the implement the diagnostics as well. | ||
47 | pub(crate) mod field_shorthand; | ||
48 | pub(crate) mod useless_braces; | ||
49 | pub(crate) mod unlinked_file; | ||
50 | } | ||
51 | |||
52 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | ||
53 | use ide_db::{ | ||
54 | assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, | ||
55 | base_db::{FileId, SourceDatabase}, | ||
56 | label::Label, | ||
57 | source_change::SourceChange, | ||
58 | RootDatabase, | ||
59 | }; | ||
60 | use rustc_hash::FxHashSet; | ||
61 | use syntax::{ast::AstNode, TextRange}; | ||
62 | |||
63 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
64 | pub struct DiagnosticCode(pub &'static str); | ||
65 | |||
66 | impl DiagnosticCode { | ||
67 | pub fn as_str(&self) -> &str { | ||
68 | self.0 | ||
69 | } | ||
70 | } | ||
71 | |||
72 | #[derive(Debug)] | ||
73 | pub struct Diagnostic { | ||
74 | pub code: DiagnosticCode, | ||
75 | pub message: String, | ||
76 | pub range: TextRange, | ||
77 | pub severity: Severity, | ||
78 | pub unused: bool, | ||
79 | pub experimental: bool, | ||
80 | pub fixes: Option<Vec<Assist>>, | ||
81 | } | ||
82 | |||
83 | impl Diagnostic { | ||
84 | fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic { | ||
85 | let message = message.into(); | ||
86 | Diagnostic { | ||
87 | code: DiagnosticCode(code), | ||
88 | message, | ||
89 | range, | ||
90 | severity: Severity::Error, | ||
91 | unused: false, | ||
92 | experimental: false, | ||
93 | fixes: None, | ||
94 | } | ||
95 | } | ||
96 | |||
97 | fn experimental(mut self) -> Diagnostic { | ||
98 | self.experimental = true; | ||
99 | self | ||
100 | } | ||
101 | |||
102 | fn severity(mut self, severity: Severity) -> Diagnostic { | ||
103 | self.severity = severity; | ||
104 | self | ||
105 | } | ||
106 | |||
107 | fn with_fixes(mut self, fixes: Option<Vec<Assist>>) -> Diagnostic { | ||
108 | self.fixes = fixes; | ||
109 | self | ||
110 | } | ||
111 | |||
112 | fn with_unused(mut self, unused: bool) -> Diagnostic { | ||
113 | self.unused = unused; | ||
114 | self | ||
115 | } | ||
116 | } | ||
117 | |||
118 | #[derive(Debug, Copy, Clone)] | ||
119 | pub enum Severity { | ||
120 | Error, | ||
121 | // We don't actually emit this one yet, but we should at some point. | ||
122 | // Warning, | ||
123 | WeakWarning, | ||
124 | } | ||
125 | |||
126 | #[derive(Default, Debug, Clone)] | ||
127 | pub struct DiagnosticsConfig { | ||
128 | pub disable_experimental: bool, | ||
129 | pub disabled: FxHashSet<String>, | ||
130 | } | ||
131 | |||
132 | struct DiagnosticsContext<'a> { | ||
133 | config: &'a DiagnosticsConfig, | ||
134 | sema: Semantics<'a, RootDatabase>, | ||
135 | resolve: &'a AssistResolveStrategy, | ||
136 | } | ||
137 | |||
138 | pub fn diagnostics( | ||
139 | db: &RootDatabase, | ||
140 | config: &DiagnosticsConfig, | ||
141 | resolve: &AssistResolveStrategy, | ||
142 | file_id: FileId, | ||
143 | ) -> Vec<Diagnostic> { | ||
144 | let _p = profile::span("diagnostics"); | ||
145 | let sema = Semantics::new(db); | ||
146 | let parse = db.parse(file_id); | ||
147 | let mut res = Vec::new(); | ||
148 | |||
149 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | ||
150 | res.extend( | ||
151 | parse.errors().iter().take(128).map(|err| { | ||
152 | Diagnostic::new("syntax-error", format!("Syntax Error: {}", err), err.range()) | ||
153 | }), | ||
154 | ); | ||
155 | |||
156 | for node in parse.tree().syntax().descendants() { | ||
157 | handlers::useless_braces::useless_braces(&mut res, file_id, &node); | ||
158 | handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); | ||
159 | } | ||
160 | |||
161 | let module = sema.to_module_def(file_id); | ||
162 | |||
163 | let ctx = DiagnosticsContext { config, sema, resolve }; | ||
164 | if module.is_none() { | ||
165 | handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id); | ||
166 | } | ||
167 | |||
168 | let mut diags = Vec::new(); | ||
169 | if let Some(m) = module { | ||
170 | m.diagnostics(db, &mut diags) | ||
171 | } | ||
172 | |||
173 | for diag in diags { | ||
174 | #[rustfmt::skip] | ||
175 | let d = match diag { | ||
176 | AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d), | ||
177 | AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d), | ||
178 | AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), | ||
179 | AnyDiagnostic::MismatchedArgCount(d) => handlers::mismatched_arg_count::mismatched_arg_count(&ctx, &d), | ||
180 | AnyDiagnostic::MissingFields(d) => handlers::missing_fields::missing_fields(&ctx, &d), | ||
181 | AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d), | ||
182 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => handlers::missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), | ||
183 | AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d), | ||
184 | AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d), | ||
185 | AnyDiagnostic::RemoveThisSemicolon(d) => handlers::remove_this_semicolon::remove_this_semicolon(&ctx, &d), | ||
186 | AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => handlers::replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d), | ||
187 | AnyDiagnostic::UnimplementedBuiltinMacro(d) => handlers::unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), | ||
188 | AnyDiagnostic::UnresolvedExternCrate(d) => handlers::unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | ||
189 | AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), | ||
190 | AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), | ||
191 | AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), | ||
192 | AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | ||
193 | |||
194 | AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { | ||
195 | Some(it) => it, | ||
196 | None => continue, | ||
197 | } | ||
198 | }; | ||
199 | res.push(d) | ||
200 | } | ||
201 | |||
202 | res.retain(|d| { | ||
203 | !ctx.config.disabled.contains(d.code.as_str()) | ||
204 | && !(ctx.config.disable_experimental && d.experimental) | ||
205 | }); | ||
206 | |||
207 | res | ||
208 | } | ||
209 | |||
210 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | ||
211 | let mut res = unresolved_fix(id, label, target); | ||
212 | res.source_change = Some(source_change); | ||
213 | res | ||
214 | } | ||
215 | |||
216 | fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | ||
217 | assert!(!id.contains(' ')); | ||
218 | Assist { | ||
219 | id: AssistId(id, AssistKind::QuickFix), | ||
220 | label: Label::new(label), | ||
221 | group: None, | ||
222 | target, | ||
223 | source_change: None, | ||
224 | } | ||
225 | } | ||
226 | |||
227 | #[cfg(test)] | ||
228 | mod tests { | ||
229 | use expect_test::Expect; | ||
230 | use ide_db::{ | ||
231 | assists::AssistResolveStrategy, | ||
232 | base_db::{fixture::WithFixture, SourceDatabaseExt}, | ||
233 | RootDatabase, | ||
234 | }; | ||
235 | use stdx::trim_indent; | ||
236 | use test_utils::{assert_eq_text, extract_annotations}; | ||
237 | |||
238 | use crate::{DiagnosticsConfig, Severity}; | ||
239 | |||
240 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
241 | /// and checks that: | ||
242 | /// * a diagnostic is produced | ||
243 | /// * the first diagnostic fix trigger range touches the input cursor position | ||
244 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | ||
245 | #[track_caller] | ||
246 | pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
247 | check_nth_fix(0, ra_fixture_before, ra_fixture_after); | ||
248 | } | ||
249 | /// Takes a multi-file input fixture with annotated cursor positions, | ||
250 | /// and checks that: | ||
251 | /// * a diagnostic is produced | ||
252 | /// * every diagnostic fixes trigger range touches the input cursor position | ||
253 | /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied | ||
254 | pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { | ||
255 | for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { | ||
256 | check_nth_fix(i, ra_fixture_before, ra_fixture_after) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | #[track_caller] | ||
261 | fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
262 | let after = trim_indent(ra_fixture_after); | ||
263 | |||
264 | let (db, file_position) = RootDatabase::with_position(ra_fixture_before); | ||
265 | let diagnostic = super::diagnostics( | ||
266 | &db, | ||
267 | &DiagnosticsConfig::default(), | ||
268 | &AssistResolveStrategy::All, | ||
269 | file_position.file_id, | ||
270 | ) | ||
271 | .pop() | ||
272 | .expect("no diagnostics"); | ||
273 | let fix = &diagnostic.fixes.expect("diagnostic misses fixes")[nth]; | ||
274 | let actual = { | ||
275 | let source_change = fix.source_change.as_ref().unwrap(); | ||
276 | let file_id = *source_change.source_file_edits.keys().next().unwrap(); | ||
277 | let mut actual = db.file_text(file_id).to_string(); | ||
278 | |||
279 | for edit in source_change.source_file_edits.values() { | ||
280 | edit.apply(&mut actual); | ||
281 | } | ||
282 | actual | ||
283 | }; | ||
284 | |||
285 | assert_eq_text!(&after, &actual); | ||
286 | assert!( | ||
287 | fix.target.contains_inclusive(file_position.offset), | ||
288 | "diagnostic fix range {:?} does not touch cursor position {:?}", | ||
289 | fix.target, | ||
290 | file_position.offset | ||
291 | ); | ||
292 | } | ||
293 | |||
294 | /// Checks that there's a diagnostic *without* fix at `$0`. | ||
295 | pub(crate) fn check_no_fix(ra_fixture: &str) { | ||
296 | let (db, file_position) = RootDatabase::with_position(ra_fixture); | ||
297 | let diagnostic = super::diagnostics( | ||
298 | &db, | ||
299 | &DiagnosticsConfig::default(), | ||
300 | &AssistResolveStrategy::All, | ||
301 | file_position.file_id, | ||
302 | ) | ||
303 | .pop() | ||
304 | .unwrap(); | ||
305 | assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic); | ||
306 | } | ||
307 | |||
308 | pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) { | ||
309 | let (db, file_id) = RootDatabase::with_single_file(ra_fixture); | ||
310 | let diagnostics = super::diagnostics( | ||
311 | &db, | ||
312 | &DiagnosticsConfig::default(), | ||
313 | &AssistResolveStrategy::All, | ||
314 | file_id, | ||
315 | ); | ||
316 | expect.assert_debug_eq(&diagnostics) | ||
317 | } | ||
318 | |||
319 | #[track_caller] | ||
320 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | ||
321 | let mut config = DiagnosticsConfig::default(); | ||
322 | config.disabled.insert("inactive-code".to_string()); | ||
323 | check_diagnostics_with_config(config, ra_fixture) | ||
324 | } | ||
325 | |||
326 | #[track_caller] | ||
327 | pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { | ||
328 | let (db, files) = RootDatabase::with_many_files(ra_fixture); | ||
329 | for file_id in files { | ||
330 | let diagnostics = | ||
331 | super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); | ||
332 | |||
333 | let expected = extract_annotations(&*db.file_text(file_id)); | ||
334 | let mut actual = diagnostics | ||
335 | .into_iter() | ||
336 | .map(|d| { | ||
337 | let mut annotation = String::new(); | ||
338 | if let Some(fixes) = &d.fixes { | ||
339 | assert!(!fixes.is_empty()); | ||
340 | annotation.push_str("💡 ") | ||
341 | } | ||
342 | annotation.push_str(match d.severity { | ||
343 | Severity::Error => "error", | ||
344 | Severity::WeakWarning => "weak", | ||
345 | }); | ||
346 | annotation.push_str(": "); | ||
347 | annotation.push_str(&d.message); | ||
348 | (d.range, annotation) | ||
349 | }) | ||
350 | .collect::<Vec<_>>(); | ||
351 | actual.sort_by_key(|(range, _)| range.start()); | ||
352 | assert_eq!(expected, actual); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn test_disabled_diagnostics() { | ||
358 | let mut config = DiagnosticsConfig::default(); | ||
359 | config.disabled.insert("unresolved-module".into()); | ||
360 | |||
361 | let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); | ||
362 | |||
363 | let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); | ||
364 | assert!(diagnostics.is_empty()); | ||
365 | |||
366 | let diagnostics = super::diagnostics( | ||
367 | &db, | ||
368 | &DiagnosticsConfig::default(), | ||
369 | &AssistResolveStrategy::All, | ||
370 | file_id, | ||
371 | ); | ||
372 | assert!(!diagnostics.is_empty()); | ||
373 | } | ||
374 | } | ||
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index c2a9a38c9..b4f2fe9a4 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs | |||
@@ -804,33 +804,17 @@ impl<'a> TtIter<'a> { | |||
804 | }; | 804 | }; |
805 | 805 | ||
806 | match (punct.char, second, third) { | 806 | match (punct.char, second, third) { |
807 | ('.', '.', Some('.')) | 807 | ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => { |
808 | | ('.', '.', Some('=')) | ||
809 | | ('<', '<', Some('=')) | ||
810 | | ('>', '>', Some('=')) => { | ||
811 | let tt2 = self.next().unwrap().clone(); | 808 | let tt2 = self.next().unwrap().clone(); |
812 | let tt3 = self.next().unwrap().clone(); | 809 | let tt3 = self.next().unwrap().clone(); |
813 | Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) | 810 | Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into()) |
814 | } | 811 | } |
815 | ('-', '=', _) | 812 | ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) |
816 | | ('-', '>', _) | 813 | | ('-' | '=' | '>', '>', _) |
817 | | (':', ':', _) | 814 | | (':', ':', _) |
818 | | ('!', '=', _) | ||
819 | | ('.', '.', _) | 815 | | ('.', '.', _) |
820 | | ('*', '=', _) | ||
821 | | ('/', '=', _) | ||
822 | | ('&', '&', _) | 816 | | ('&', '&', _) |
823 | | ('&', '=', _) | ||
824 | | ('%', '=', _) | ||
825 | | ('^', '=', _) | ||
826 | | ('+', '=', _) | ||
827 | | ('<', '<', _) | 817 | | ('<', '<', _) |
828 | | ('<', '=', _) | ||
829 | | ('=', '=', _) | ||
830 | | ('=', '>', _) | ||
831 | | ('>', '=', _) | ||
832 | | ('>', '>', _) | ||
833 | | ('|', '=', _) | ||
834 | | ('|', '|', _) => { | 818 | | ('|', '|', _) => { |
835 | let tt2 = self.next().unwrap().clone(); | 819 | let tt2 = self.next().unwrap().clone(); |
836 | Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) | 820 | Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2] }.into()) |
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs index 01ee26a53..5a78675fb 100644 --- a/crates/parser/src/grammar/params.rs +++ b/crates/parser/src/grammar/params.rs | |||
@@ -184,8 +184,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> { | |||
184 | if !matches!( | 184 | if !matches!( |
185 | (p.current(), la1, la2, la3), | 185 | (p.current(), la1, la2, la3), |
186 | (T![&], T![self], _, _) | 186 | (T![&], T![self], _, _) |
187 | | (T![&], T![mut], T![self], _) | 187 | | (T![&], T![mut] | LIFETIME_IDENT, T![self], _) |
188 | | (T![&], LIFETIME_IDENT, T![self], _) | ||
189 | | (T![&], LIFETIME_IDENT, T![mut], T![self]) | 188 | | (T![&], LIFETIME_IDENT, T![mut], T![self]) |
190 | ) { | 189 | ) { |
191 | return Err(m); | 190 | return Err(m); |
diff --git a/crates/proc_macro_api/src/version.rs b/crates/proc_macro_api/src/version.rs index 28a4ac086..434decc7e 100644 --- a/crates/proc_macro_api/src/version.rs +++ b/crates/proc_macro_api/src/version.rs | |||
@@ -28,23 +28,23 @@ pub fn read_dylib_info(dylib_path: &Path) -> io::Result<RustCInfo> { | |||
28 | 28 | ||
29 | let ver_str = read_version(dylib_path)?; | 29 | let ver_str = read_version(dylib_path)?; |
30 | let mut items = ver_str.split_whitespace(); | 30 | let mut items = ver_str.split_whitespace(); |
31 | let tag = items.next().ok_or(err!("version format error"))?; | 31 | let tag = items.next().ok_or_else(|| err!("version format error"))?; |
32 | if tag != "rustc" { | 32 | if tag != "rustc" { |
33 | return Err(err!("version format error (No rustc tag)")); | 33 | return Err(err!("version format error (No rustc tag)")); |
34 | } | 34 | } |
35 | 35 | ||
36 | let version_part = items.next().ok_or(err!("no version string"))?; | 36 | let version_part = items.next().ok_or_else(|| err!("no version string"))?; |
37 | let mut version_parts = version_part.split('-'); | 37 | let mut version_parts = version_part.split('-'); |
38 | let version = version_parts.next().ok_or(err!("no version"))?; | 38 | let version = version_parts.next().ok_or_else(|| err!("no version"))?; |
39 | let channel = version_parts.next().unwrap_or_default().to_string(); | 39 | let channel = version_parts.next().unwrap_or_default().to_string(); |
40 | 40 | ||
41 | let commit = items.next().ok_or(err!("no commit info"))?; | 41 | let commit = items.next().ok_or_else(|| err!("no commit info"))?; |
42 | // remove ( | 42 | // remove ( |
43 | if commit.len() == 0 { | 43 | if commit.len() == 0 { |
44 | return Err(err!("commit format error")); | 44 | return Err(err!("commit format error")); |
45 | } | 45 | } |
46 | let commit = commit[1..].to_string(); | 46 | let commit = commit[1..].to_string(); |
47 | let date = items.next().ok_or(err!("no date info"))?; | 47 | let date = items.next().ok_or_else(|| err!("no date info"))?; |
48 | // remove ) | 48 | // remove ) |
49 | if date.len() == 0 { | 49 | if date.len() == 0 { |
50 | return Err(err!("date format error")); | 50 | return Err(err!("date format error")); |
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index 53cb4bae7..45bbb08dc 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -187,7 +187,7 @@ impl WorkspaceBuildData { | |||
187 | let mut deserializer = serde_json::Deserializer::from_str(line); | 187 | let mut deserializer = serde_json::Deserializer::from_str(line); |
188 | deserializer.disable_recursion_limit(); | 188 | deserializer.disable_recursion_limit(); |
189 | let message = Message::deserialize(&mut deserializer) | 189 | let message = Message::deserialize(&mut deserializer) |
190 | .unwrap_or(Message::TextLine(line.to_string())); | 190 | .unwrap_or_else(|_| Message::TextLine(line.to_string())); |
191 | 191 | ||
192 | match message { | 192 | match message { |
193 | Message::BuildScriptExecuted(BuildScript { | 193 | Message::BuildScriptExecuted(BuildScript { |
@@ -229,7 +229,7 @@ impl WorkspaceBuildData { | |||
229 | Message::CompilerArtifact(message) => { | 229 | Message::CompilerArtifact(message) => { |
230 | progress(format!("metadata {}", message.target.name)); | 230 | progress(format!("metadata {}", message.target.name)); |
231 | 231 | ||
232 | if message.target.kind.contains(&"proc-macro".to_string()) { | 232 | if message.target.kind.iter().any(|k| k == "proc-macro") { |
233 | let package_id = message.package_id; | 233 | let package_id = message.package_id; |
234 | // Skip rmeta file | 234 | // Skip rmeta file |
235 | if let Some(filename) = | 235 | if let Some(filename) = |
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index ac079f83e..0935ea967 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! See [`CargoWorkspace`]. | 1 | //! See [`CargoWorkspace`]. |
2 | 2 | ||
3 | use std::iter; | ||
3 | use std::path::PathBuf; | 4 | use std::path::PathBuf; |
4 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; | 5 | use std::{convert::TryInto, ops, process::Command, sync::Arc}; |
5 | 6 | ||
@@ -12,6 +13,7 @@ use rustc_hash::FxHashMap; | |||
12 | use serde::Deserialize; | 13 | use serde::Deserialize; |
13 | use serde_json::from_value; | 14 | use serde_json::from_value; |
14 | 15 | ||
16 | use crate::CfgOverrides; | ||
15 | use crate::{build_data::BuildDataConfig, utf8_stdout}; | 17 | use crate::{build_data::BuildDataConfig, utf8_stdout}; |
16 | 18 | ||
17 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo | 19 | /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo |
@@ -76,6 +78,21 @@ pub struct CargoConfig { | |||
76 | 78 | ||
77 | /// rustc private crate source | 79 | /// rustc private crate source |
78 | pub rustc_source: Option<RustcSource>, | 80 | pub rustc_source: Option<RustcSource>, |
81 | |||
82 | /// crates to disable `#[cfg(test)]` on | ||
83 | pub unset_test_crates: Vec<String>, | ||
84 | } | ||
85 | |||
86 | impl CargoConfig { | ||
87 | pub fn cfg_overrides(&self) -> CfgOverrides { | ||
88 | self.unset_test_crates | ||
89 | .iter() | ||
90 | .cloned() | ||
91 | .zip(iter::repeat_with(|| { | ||
92 | cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap() | ||
93 | })) | ||
94 | .collect() | ||
95 | } | ||
79 | } | 96 | } |
80 | 97 | ||
81 | pub type Package = Idx<PackageData>; | 98 | pub type Package = Idx<PackageData>; |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 8c6cf94c2..1d408dff2 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -41,7 +41,7 @@ pub use crate::{ | |||
41 | }, | 41 | }, |
42 | project_json::{ProjectJson, ProjectJsonData}, | 42 | project_json::{ProjectJson, ProjectJsonData}, |
43 | sysroot::Sysroot, | 43 | sysroot::Sysroot, |
44 | workspace::{PackageRoot, ProjectWorkspace}, | 44 | workspace::{CfgOverrides, PackageRoot, ProjectWorkspace}, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | pub use proc_macro_api::ProcMacroClient; | 47 | pub use proc_macro_api::ProcMacroClient; |
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index a22f79c15..006263da8 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -68,8 +68,9 @@ impl Sysroot { | |||
68 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { | 68 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { |
69 | let mut sysroot = Sysroot { crates: Arena::default() }; | 69 | let mut sysroot = Sysroot { crates: Arena::default() }; |
70 | 70 | ||
71 | for name in SYSROOT_CRATES.trim().lines() { | 71 | for path in SYSROOT_CRATES.trim().lines() { |
72 | let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)] | 72 | let name = path.split('/').last().unwrap(); |
73 | let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)] | ||
73 | .iter() | 74 | .iter() |
74 | .map(|it| sysroot_src_dir.join(it)) | 75 | .map(|it| sysroot_src_dir.join(it)) |
75 | .find(|it| it.exists()); | 76 | .find(|it| it.exists()); |
@@ -191,9 +192,8 @@ panic_abort | |||
191 | panic_unwind | 192 | panic_unwind |
192 | proc_macro | 193 | proc_macro |
193 | profiler_builtins | 194 | profiler_builtins |
194 | rtstartup | ||
195 | std | 195 | std |
196 | stdarch | 196 | stdarch/crates/std_detect |
197 | term | 197 | term |
198 | test | 198 | test |
199 | unwind"; | 199 | unwind"; |
@@ -204,9 +204,8 @@ core | |||
204 | panic_abort | 204 | panic_abort |
205 | panic_unwind | 205 | panic_unwind |
206 | profiler_builtins | 206 | profiler_builtins |
207 | rtstartup | ||
208 | proc_macro | 207 | proc_macro |
209 | stdarch | 208 | std_detect |
210 | term | 209 | term |
211 | test | 210 | test |
212 | unwind"; | 211 | unwind"; |
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs index ef0f3c9e4..d8217f714 100644 --- a/crates/project_model/src/workspace.rs +++ b/crates/project_model/src/workspace.rs | |||
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command}; | |||
7 | use anyhow::{format_err, Context, Result}; | 7 | use anyhow::{format_err, Context, Result}; |
8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; | 8 | use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro}; |
9 | use cargo_workspace::DepKind; | 9 | use cargo_workspace::DepKind; |
10 | use cfg::CfgOptions; | 10 | use cfg::{CfgDiff, CfgOptions}; |
11 | use paths::{AbsPath, AbsPathBuf}; | 11 | use paths::{AbsPath, AbsPathBuf}; |
12 | use proc_macro_api::ProcMacroClient; | 12 | use proc_macro_api::ProcMacroClient; |
13 | use rustc_hash::{FxHashMap, FxHashSet}; | 13 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -22,6 +22,8 @@ use crate::{ | |||
22 | Sysroot, TargetKind, | 22 | Sysroot, TargetKind, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub type CfgOverrides = FxHashMap<String, CfgDiff>; | ||
26 | |||
25 | /// `PackageRoot` describes a package root folder. | 27 | /// `PackageRoot` describes a package root folder. |
26 | /// Which may be an external dependency, or a member of | 28 | /// Which may be an external dependency, or a member of |
27 | /// the current workspace. | 29 | /// the current workspace. |
@@ -46,6 +48,7 @@ pub enum ProjectWorkspace { | |||
46 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a | 48 | /// FIXME: make this a per-crate map, as, eg, build.rs might have a |
47 | /// different target. | 49 | /// different target. |
48 | rustc_cfg: Vec<CfgFlag>, | 50 | rustc_cfg: Vec<CfgFlag>, |
51 | cfg_overrides: CfgOverrides, | ||
49 | }, | 52 | }, |
50 | /// Project workspace was manually specified using a `rust-project.json` file. | 53 | /// Project workspace was manually specified using a `rust-project.json` file. |
51 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, | 54 | Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> }, |
@@ -67,7 +70,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
67 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 70 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
68 | // Make sure this isn't too verbose. | 71 | // Make sure this isn't too verbose. |
69 | match self { | 72 | match self { |
70 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => f | 73 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f |
71 | .debug_struct("Cargo") | 74 | .debug_struct("Cargo") |
72 | .field("root", &cargo.workspace_root().file_name()) | 75 | .field("root", &cargo.workspace_root().file_name()) |
73 | .field("n_packages", &cargo.packages().len()) | 76 | .field("n_packages", &cargo.packages().len()) |
@@ -77,6 +80,7 @@ impl fmt::Debug for ProjectWorkspace { | |||
77 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | 80 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), |
78 | ) | 81 | ) |
79 | .field("n_rustc_cfg", &rustc_cfg.len()) | 82 | .field("n_rustc_cfg", &rustc_cfg.len()) |
83 | .field("n_cfg_overrides", &cfg_overrides.len()) | ||
80 | .finish(), | 84 | .finish(), |
81 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { | 85 | ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { |
82 | let mut debug_struct = f.debug_struct("Json"); | 86 | let mut debug_struct = f.debug_struct("Json"); |
@@ -164,7 +168,9 @@ impl ProjectWorkspace { | |||
164 | }; | 168 | }; |
165 | 169 | ||
166 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); | 170 | let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref()); |
167 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } | 171 | |
172 | let cfg_overrides = config.cfg_overrides(); | ||
173 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } | ||
168 | } | 174 | } |
169 | }; | 175 | }; |
170 | 176 | ||
@@ -213,43 +219,45 @@ impl ProjectWorkspace { | |||
213 | }) | 219 | }) |
214 | })) | 220 | })) |
215 | .collect::<Vec<_>>(), | 221 | .collect::<Vec<_>>(), |
216 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _ } => cargo | 222 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => { |
217 | .packages() | 223 | cargo |
218 | .map(|pkg| { | 224 | .packages() |
219 | let is_member = cargo[pkg].is_member; | 225 | .map(|pkg| { |
220 | let pkg_root = cargo[pkg].root().to_path_buf(); | 226 | let is_member = cargo[pkg].is_member; |
221 | 227 | let pkg_root = cargo[pkg].root().to_path_buf(); | |
222 | let mut include = vec![pkg_root.clone()]; | 228 | |
223 | include.extend( | 229 | let mut include = vec![pkg_root.clone()]; |
224 | build_data | 230 | include.extend( |
225 | .and_then(|it| it.get(cargo.workspace_root())) | 231 | build_data |
226 | .and_then(|map| map.get(&cargo[pkg].id)) | 232 | .and_then(|it| it.get(cargo.workspace_root())) |
227 | .and_then(|it| it.out_dir.clone()), | 233 | .and_then(|map| map.get(&cargo[pkg].id)) |
228 | ); | 234 | .and_then(|it| it.out_dir.clone()), |
235 | ); | ||
229 | 236 | ||
230 | let mut exclude = vec![pkg_root.join(".git")]; | 237 | let mut exclude = vec![pkg_root.join(".git")]; |
231 | if is_member { | 238 | if is_member { |
232 | exclude.push(pkg_root.join("target")); | 239 | exclude.push(pkg_root.join("target")); |
233 | } else { | 240 | } else { |
234 | exclude.push(pkg_root.join("tests")); | 241 | exclude.push(pkg_root.join("tests")); |
235 | exclude.push(pkg_root.join("examples")); | 242 | exclude.push(pkg_root.join("examples")); |
236 | exclude.push(pkg_root.join("benches")); | 243 | exclude.push(pkg_root.join("benches")); |
237 | } | 244 | } |
238 | PackageRoot { is_member, include, exclude } | 245 | PackageRoot { is_member, include, exclude } |
239 | }) | 246 | }) |
240 | .chain(sysroot.crates().map(|krate| PackageRoot { | 247 | .chain(sysroot.crates().map(|krate| PackageRoot { |
241 | is_member: false, | ||
242 | include: vec![sysroot[krate].root_dir().to_path_buf()], | ||
243 | exclude: Vec::new(), | ||
244 | })) | ||
245 | .chain(rustc.into_iter().flat_map(|rustc| { | ||
246 | rustc.packages().map(move |krate| PackageRoot { | ||
247 | is_member: false, | 248 | is_member: false, |
248 | include: vec![rustc[krate].root().to_path_buf()], | 249 | include: vec![sysroot[krate].root_dir().to_path_buf()], |
249 | exclude: Vec::new(), | 250 | exclude: Vec::new(), |
250 | }) | 251 | })) |
251 | })) | 252 | .chain(rustc.into_iter().flat_map(|rustc| { |
252 | .collect(), | 253 | rustc.packages().map(move |krate| PackageRoot { |
254 | is_member: false, | ||
255 | include: vec![rustc[krate].root().to_path_buf()], | ||
256 | exclude: Vec::new(), | ||
257 | }) | ||
258 | })) | ||
259 | .collect() | ||
260 | } | ||
253 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files | 261 | ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files |
254 | .into_iter() | 262 | .into_iter() |
255 | .map(|detached_file| PackageRoot { | 263 | .map(|detached_file| PackageRoot { |
@@ -299,16 +307,22 @@ impl ProjectWorkspace { | |||
299 | project, | 307 | project, |
300 | sysroot, | 308 | sysroot, |
301 | ), | 309 | ), |
302 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg } => cargo_to_crate_graph( | 310 | ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => { |
303 | rustc_cfg.clone(), | 311 | cargo_to_crate_graph( |
304 | &proc_macro_loader, | 312 | rustc_cfg.clone(), |
305 | load, | 313 | cfg_overrides, |
306 | cargo, | 314 | &proc_macro_loader, |
307 | build_data.and_then(|it| it.get(cargo.workspace_root())), | 315 | load, |
308 | sysroot, | 316 | cargo, |
309 | rustc, | 317 | build_data.and_then(|it| it.get(cargo.workspace_root())), |
310 | rustc.as_ref().zip(build_data).and_then(|(it, map)| map.get(it.workspace_root())), | 318 | sysroot, |
311 | ), | 319 | rustc, |
320 | rustc | ||
321 | .as_ref() | ||
322 | .zip(build_data) | ||
323 | .and_then(|(it, map)| map.get(it.workspace_root())), | ||
324 | ) | ||
325 | } | ||
312 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { | 326 | ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { |
313 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) | 327 | detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) |
314 | } | 328 | } |
@@ -398,6 +412,7 @@ fn project_json_to_crate_graph( | |||
398 | 412 | ||
399 | fn cargo_to_crate_graph( | 413 | fn cargo_to_crate_graph( |
400 | rustc_cfg: Vec<CfgFlag>, | 414 | rustc_cfg: Vec<CfgFlag>, |
415 | override_cfg: &CfgOverrides, | ||
401 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, | 416 | proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, |
402 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | 417 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
403 | cargo: &CargoWorkspace, | 418 | cargo: &CargoWorkspace, |
@@ -425,6 +440,21 @@ fn cargo_to_crate_graph( | |||
425 | let mut has_private = false; | 440 | let mut has_private = false; |
426 | // Next, create crates for each package, target pair | 441 | // Next, create crates for each package, target pair |
427 | for pkg in cargo.packages() { | 442 | for pkg in cargo.packages() { |
443 | let mut cfg_options = &cfg_options; | ||
444 | let mut replaced_cfg_options; | ||
445 | if let Some(overrides) = override_cfg.get(&cargo[pkg].name) { | ||
446 | // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen | ||
447 | // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while | ||
448 | // working on rust-lang/rust as that's the only time it appears outside sysroot). | ||
449 | // | ||
450 | // A more ideal solution might be to reanalyze crates based on where the cursor is and | ||
451 | // figure out the set of cfgs that would have to apply to make it active. | ||
452 | |||
453 | replaced_cfg_options = cfg_options.clone(); | ||
454 | replaced_cfg_options.apply_diff(overrides.clone()); | ||
455 | cfg_options = &replaced_cfg_options; | ||
456 | }; | ||
457 | |||
428 | has_private |= cargo[pkg].metadata.rustc_private; | 458 | has_private |= cargo[pkg].metadata.rustc_private; |
429 | let mut lib_tgt = None; | 459 | let mut lib_tgt = None; |
430 | for &tgt in cargo[pkg].targets.iter() { | 460 | for &tgt in cargo[pkg].targets.iter() { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index fa72a9bfb..3aeca8839 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -44,6 +44,9 @@ config_data! { | |||
44 | assist_importPrefix: ImportPrefixDef = "\"plain\"", | 44 | assist_importPrefix: ImportPrefixDef = "\"plain\"", |
45 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. | 45 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. |
46 | assist_importGroup: bool = "true", | 46 | assist_importGroup: bool = "true", |
47 | /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. | ||
48 | assist_allowMergingIntoGlobImports: bool = "true", | ||
49 | |||
47 | /// Show function name and docs in parameter hints. | 50 | /// Show function name and docs in parameter hints. |
48 | callInfo_full: bool = "true", | 51 | callInfo_full: bool = "true", |
49 | 52 | ||
@@ -52,6 +55,8 @@ config_data! { | |||
52 | cargo_autoreload: bool = "true", | 55 | cargo_autoreload: bool = "true", |
53 | /// Activate all available features (`--all-features`). | 56 | /// Activate all available features (`--all-features`). |
54 | cargo_allFeatures: bool = "false", | 57 | cargo_allFeatures: bool = "false", |
58 | /// Unsets `#[cfg(test)]` for the specified crates. | ||
59 | cargo_unsetTest: Vec<String> = "[\"core\"]", | ||
55 | /// List of features to activate. | 60 | /// List of features to activate. |
56 | cargo_features: Vec<String> = "[]", | 61 | cargo_features: Vec<String> = "[]", |
57 | /// Run build scripts (`build.rs`) for more precise code analysis. | 62 | /// Run build scripts (`build.rs`) for more precise code analysis. |
@@ -596,8 +601,10 @@ impl Config { | |||
596 | target: self.data.cargo_target.clone(), | 601 | target: self.data.cargo_target.clone(), |
597 | rustc_source, | 602 | rustc_source, |
598 | no_sysroot: self.data.cargo_noSysroot, | 603 | no_sysroot: self.data.cargo_noSysroot, |
604 | unset_test_crates: self.data.cargo_unsetTest.clone(), | ||
599 | } | 605 | } |
600 | } | 606 | } |
607 | |||
601 | pub fn rustfmt(&self) -> RustfmtConfig { | 608 | pub fn rustfmt(&self) -> RustfmtConfig { |
602 | match &self.data.rustfmt_overrideCommand { | 609 | match &self.data.rustfmt_overrideCommand { |
603 | Some(args) if !args.is_empty() => { | 610 | Some(args) if !args.is_empty() => { |
@@ -676,6 +683,7 @@ impl Config { | |||
676 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | 683 | ImportPrefixDef::BySelf => PrefixKind::BySelf, |
677 | }, | 684 | }, |
678 | group: self.data.assist_importGroup, | 685 | group: self.data.assist_importGroup, |
686 | skip_glob_imports: !self.data.assist_allowMergingIntoGlobImports, | ||
679 | } | 687 | } |
680 | } | 688 | } |
681 | pub fn completion(&self) -> CompletionConfig { | 689 | pub fn completion(&self) -> CompletionConfig { |
@@ -806,7 +814,9 @@ enum ImportGranularityDef { | |||
806 | #[serde(rename_all = "snake_case")] | 814 | #[serde(rename_all = "snake_case")] |
807 | enum ImportPrefixDef { | 815 | enum ImportPrefixDef { |
808 | Plain, | 816 | Plain, |
817 | #[serde(alias = "self")] | ||
809 | BySelf, | 818 | BySelf, |
819 | #[serde(alias = "crate")] | ||
810 | ByCrate, | 820 | ByCrate, |
811 | } | 821 | } |
812 | 822 | ||
@@ -993,13 +1003,13 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
993 | "type": "string", | 1003 | "type": "string", |
994 | "enum": [ | 1004 | "enum": [ |
995 | "plain", | 1005 | "plain", |
996 | "by_self", | 1006 | "self", |
997 | "by_crate" | 1007 | "crate" |
998 | ], | 1008 | ], |
999 | "enumDescriptions": [ | 1009 | "enumDescriptions": [ |
1000 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 1010 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
1001 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", | 1011 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", |
1002 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 1012 | "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." |
1003 | ], | 1013 | ], |
1004 | }, | 1014 | }, |
1005 | "Vec<ManifestOrProjectJson>" => set! { | 1015 | "Vec<ManifestOrProjectJson>" => set! { |
@@ -1069,8 +1079,8 @@ mod tests { | |||
1069 | let package_json_path = project_root().join("editors/code/package.json"); | 1079 | let package_json_path = project_root().join("editors/code/package.json"); |
1070 | let mut package_json = fs::read_to_string(&package_json_path).unwrap(); | 1080 | let mut package_json = fs::read_to_string(&package_json_path).unwrap(); |
1071 | 1081 | ||
1072 | let start_marker = " \"$generated-start\": false,\n"; | 1082 | let start_marker = " \"$generated-start\": {},\n"; |
1073 | let end_marker = " \"$generated-end\": false\n"; | 1083 | let end_marker = " \"$generated-end\": {}\n"; |
1074 | 1084 | ||
1075 | let start = package_json.find(start_marker).unwrap() + start_marker.len(); | 1085 | let start = package_json.find(start_marker).unwrap() + start_marker.len(); |
1076 | let end = package_json.find(end_marker).unwrap(); | 1086 | let end = package_json.find(end_marker).unwrap(); |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt index d5ab03576..a7f936a70 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt | |||
@@ -54,7 +54,7 @@ | |||
54 | source: Some( | 54 | source: Some( |
55 | "rustc", | 55 | "rustc", |
56 | ), | 56 | ), |
57 | message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", | 57 | message: "can't compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", |
58 | related_information: None, | 58 | related_information: None, |
59 | tags: None, | 59 | tags: None, |
60 | data: None, | 60 | data: None, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt index ada540ea6..afc562a0e 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt | |||
@@ -54,7 +54,7 @@ | |||
54 | source: Some( | 54 | source: Some( |
55 | "rustc", | 55 | "rustc", |
56 | ), | 56 | ), |
57 | message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`", | 57 | message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`", |
58 | related_information: None, | 58 | related_information: None, |
59 | tags: None, | 59 | tags: None, |
60 | data: None, | 60 | data: None, |
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 8ddeb59f7..f8afc930a 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs | |||
@@ -143,6 +143,7 @@ fn integrated_completion_benchmark() { | |||
143 | prefix_kind: hir::PrefixKind::ByCrate, | 143 | prefix_kind: hir::PrefixKind::ByCrate, |
144 | enforce_granularity: true, | 144 | enforce_granularity: true, |
145 | group: true, | 145 | group: true, |
146 | skip_glob_imports: true, | ||
146 | }, | 147 | }, |
147 | }; | 148 | }; |
148 | let position = | 149 | let position = |
@@ -178,6 +179,7 @@ fn integrated_completion_benchmark() { | |||
178 | prefix_kind: hir::PrefixKind::ByCrate, | 179 | prefix_kind: hir::PrefixKind::ByCrate, |
179 | enforce_granularity: true, | 180 | enforce_granularity: true, |
180 | group: true, | 181 | group: true, |
182 | skip_glob_imports: true, | ||
181 | }, | 183 | }, |
182 | }; | 184 | }; |
183 | let position = | 185 | let position = |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e53cd3c7b..310d8c6d2 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -1187,6 +1187,7 @@ mod tests { | |||
1187 | prefix_kind: PrefixKind::Plain, | 1187 | prefix_kind: PrefixKind::Plain, |
1188 | enforce_granularity: true, | 1188 | enforce_granularity: true, |
1189 | group: true, | 1189 | group: true, |
1190 | skip_glob_imports: true, | ||
1190 | }, | 1191 | }, |
1191 | }, | 1192 | }, |
1192 | ide_db::base_db::FilePosition { file_id, offset }, | 1193 | ide_db::base_db::FilePosition { file_id, offset }, |
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index e22c295f9..260a504e7 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs | |||
@@ -75,7 +75,9 @@ impl<'a> Project<'a> { | |||
75 | profile::init_from(crate::PROFILE); | 75 | profile::init_from(crate::PROFILE); |
76 | }); | 76 | }); |
77 | 77 | ||
78 | for entry in Fixture::parse(self.fixture) { | 78 | let (mini_core, fixtures) = Fixture::parse(self.fixture); |
79 | assert!(mini_core.is_none()); | ||
80 | for entry in fixtures { | ||
79 | let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); | 81 | let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]); |
80 | fs::create_dir_all(path.parent().unwrap()).unwrap(); | 82 | fs::create_dir_all(path.parent().unwrap()).unwrap(); |
81 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); | 83 | fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 3d27d2c1a..e33e5bb03 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -8,7 +8,7 @@ use parser::SyntaxKind; | |||
8 | use rowan::{GreenNodeData, GreenTokenData}; | 8 | use rowan::{GreenNodeData, GreenTokenData}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, | 11 | ast::{self, support, AstChildren, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, |
12 | NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, | 12 | NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -45,6 +45,12 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> { | |||
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
48 | impl ast::BlockExpr { | ||
49 | pub fn items(&self) -> AstChildren<ast::Item> { | ||
50 | support::children(self.syntax()) | ||
51 | } | ||
52 | } | ||
53 | |||
48 | #[derive(Debug, PartialEq, Eq, Clone)] | 54 | #[derive(Debug, PartialEq, Eq, Clone)] |
49 | pub enum Macro { | 55 | pub enum Macro { |
50 | MacroRules(ast::MacroRules), | 56 | MacroRules(ast::MacroRules), |
@@ -281,6 +287,15 @@ impl ast::Path { | |||
281 | successors(self.qualifier(), |p| p.qualifier()) | 287 | successors(self.qualifier(), |p| p.qualifier()) |
282 | } | 288 | } |
283 | } | 289 | } |
290 | |||
291 | impl ast::Use { | ||
292 | pub fn is_simple_glob(&self) -> bool { | ||
293 | self.use_tree() | ||
294 | .map(|use_tree| use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()) | ||
295 | .unwrap_or(false) | ||
296 | } | ||
297 | } | ||
298 | |||
284 | impl ast::UseTree { | 299 | impl ast::UseTree { |
285 | pub fn is_simple_path(&self) -> bool { | 300 | pub fn is_simple_path(&self) -> bool { |
286 | self.use_tree_list().is_none() && self.star_token().is_none() | 301 | self.use_tree_list().is_none() && self.star_token().is_none() |
@@ -325,6 +340,15 @@ impl ast::Impl { | |||
325 | let second = types.next(); | 340 | let second = types.next(); |
326 | (first, second) | 341 | (first, second) |
327 | } | 342 | } |
343 | |||
344 | pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> { | ||
345 | let this = name_ref.syntax().ancestors().find_map(ast::Impl::cast)?; | ||
346 | if this.trait_()?.syntax().text_range().start() == name_ref.syntax().text_range().start() { | ||
347 | Some(this) | ||
348 | } else { | ||
349 | None | ||
350 | } | ||
351 | } | ||
328 | } | 352 | } |
329 | 353 | ||
330 | #[derive(Debug, Clone, PartialEq, Eq)] | 354 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -666,6 +690,14 @@ impl ast::LifetimeParam { | |||
666 | } | 690 | } |
667 | } | 691 | } |
668 | 692 | ||
693 | impl ast::Module { | ||
694 | /// Returns the parent ast::Module, this is different than the semantic parent in that this only | ||
695 | /// considers parent declarations in the AST | ||
696 | pub fn parent(&self) -> Option<ast::Module> { | ||
697 | self.syntax().ancestors().nth(2).and_then(ast::Module::cast) | ||
698 | } | ||
699 | } | ||
700 | |||
669 | impl ast::RangePat { | 701 | impl ast::RangePat { |
670 | pub fn start(&self) -> Option<ast::Pat> { | 702 | pub fn start(&self) -> Option<ast::Pat> { |
671 | self.syntax() | 703 | self.syntax() |
diff --git a/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt b/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt index 4d5ad74df..135f49552 100644 --- a/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt +++ b/crates/syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 1 "\'" | 1 | CHAR 1 "'" |
2 | > error0..1 token("\'") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..1 token("'") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt b/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt index eafdb3c7c..cc3933d95 100644 --- a/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt +++ b/crates/syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 5 "\'🦀" | 1 | CHAR 5 "'🦀" |
2 | > error0..5 token("\'🦀") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..5 token("'🦀") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt b/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt index cc2b4866a..21d990e6f 100644 --- a/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt +++ b/crates/syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 5 "\'\\x7f" | 1 | CHAR 5 "'\\x7f" |
2 | > error0..5 token("\'\\x7f") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..5 token("'\\x7f") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt b/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt index a6d422cb3..055dba64c 100644 --- a/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt +++ b/crates/syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 9 "\'\\u{20AA}" | 1 | CHAR 9 "'\\u{20AA}" |
2 | > error0..9 token("\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..9 token("'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt b/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt index 47e7baa70..9ee5e93fa 100644 --- a/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt +++ b/crates/syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 2 "\' " | 1 | CHAR 2 "' " |
2 | > error0..2 token("\' ") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..2 token("' ") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt b/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt index 511029d80..dc3a596f6 100644 --- a/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt +++ b/crates/syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 2 "\'\\" | 1 | CHAR 2 "'\\" |
2 | > error0..2 token("\'\\") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..2 token("'\\") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt b/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt index d2ba5742c..e46edea98 100644 --- a/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt +++ b/crates/syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 3 "\'\\n" | 1 | CHAR 3 "'\\n" |
2 | > error0..3 token("\'\\n") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..3 token("'\\n") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt b/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt index ae9a7f0e2..8ad1e913a 100644 --- a/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt +++ b/crates/syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | CHAR 3 "\'\\\'" | 1 | CHAR 3 "'\\'" |
2 | > error0..3 token("\'\\\'") msg(Missing trailing `'` symbol to terminate the character literal) | 2 | > error0..3 token("'\\'") msg(Missing trailing `'` symbol to terminate the character literal) |
diff --git a/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt b/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt index ff1504592..9d30c7466 100644 --- a/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt +++ b/crates/syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 2 "b\'" | 1 | BYTE 2 "b'" |
2 | > error0..2 token("b\'") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..2 token("b'") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt b/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt index 34f7bd6d4..9dbf4203e 100644 --- a/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt +++ b/crates/syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 6 "b\'🦀" | 1 | BYTE 6 "b'🦀" |
2 | > error0..6 token("b\'🦀") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..6 token("b'🦀") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt b/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt index c964d0f00..d5d9c2ef7 100644 --- a/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt +++ b/crates/syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 6 "b\'\\x7f" | 1 | BYTE 6 "b'\\x7f" |
2 | > error0..6 token("b\'\\x7f") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..6 token("b'\\x7f") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt b/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt index cc65fb86f..a99b9666a 100644 --- a/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt +++ b/crates/syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 10 "b\'\\u{20AA}" | 1 | BYTE 10 "b'\\u{20AA}" |
2 | > error0..10 token("b\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..10 token("b'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt b/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt index 800834a14..8a344f712 100644 --- a/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt +++ b/crates/syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 3 "b\' " | 1 | BYTE 3 "b' " |
2 | > error0..3 token("b\' ") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..3 token("b' ") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt b/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt index 7b85ee646..b78a43c02 100644 --- a/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt +++ b/crates/syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 3 "b\'\\" | 1 | BYTE 3 "b'\\" |
2 | > error0..3 token("b\'\\") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..3 token("b'\\") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt b/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt index 4b9a63117..5147363ba 100644 --- a/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt +++ b/crates/syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 4 "b\'\\n" | 1 | BYTE 4 "b'\\n" |
2 | > error0..4 token("b\'\\n") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..4 token("b'\\n") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt b/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt index fe337f8d3..261c0894f 100644 --- a/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt +++ b/crates/syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt | |||
@@ -1,2 +1,2 @@ | |||
1 | BYTE 4 "b\'\\\'" | 1 | BYTE 4 "b'\\'" |
2 | > error0..4 token("b\'\\\'") msg(Missing trailing `'` symbol to terminate the byte literal) | 2 | > error0..4 token("b'\\'") msg(Missing trailing `'` symbol to terminate the byte literal) |
diff --git a/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt b/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt index 11e0ae14a..b746404d2 100644 --- a/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt +++ b/crates/syntax/test_data/lexer/err/0057_lifetime_starts_with_a_number.txt | |||
@@ -1,6 +1,6 @@ | |||
1 | LIFETIME_IDENT 2 "\'1" | 1 | LIFETIME_IDENT 2 "'1" |
2 | WHITESPACE 1 "\n" | 2 | WHITESPACE 1 "\n" |
3 | LIFETIME_IDENT 10 "\'1lifetime" | 3 | LIFETIME_IDENT 10 "'1lifetime" |
4 | WHITESPACE 1 "\n" | 4 | WHITESPACE 1 "\n" |
5 | > error0..2 token("\'1") msg(Lifetime name cannot start with a number) | 5 | > error0..2 token("'1") msg(Lifetime name cannot start with a number) |
6 | > error3..13 token("\'1lifetime") msg(Lifetime name cannot start with a number) | 6 | > error3..13 token("'1lifetime") msg(Lifetime name cannot start with a number) |
diff --git a/crates/syntax/test_data/lexer/ok/0006_chars.txt b/crates/syntax/test_data/lexer/ok/0006_chars.txt index 950954fbc..756477dc9 100644 --- a/crates/syntax/test_data/lexer/ok/0006_chars.txt +++ b/crates/syntax/test_data/lexer/ok/0006_chars.txt | |||
@@ -1,16 +1,16 @@ | |||
1 | CHAR 3 "\'x\'" | 1 | CHAR 3 "'x'" |
2 | WHITESPACE 1 " " | 2 | WHITESPACE 1 " " |
3 | CHAR 3 "\' \'" | 3 | CHAR 3 "' '" |
4 | WHITESPACE 1 " " | 4 | WHITESPACE 1 " " |
5 | CHAR 3 "\'0\'" | 5 | CHAR 3 "'0'" |
6 | WHITESPACE 1 " " | 6 | WHITESPACE 1 " " |
7 | CHAR 7 "\'hello\'" | 7 | CHAR 7 "'hello'" |
8 | WHITESPACE 1 " " | 8 | WHITESPACE 1 " " |
9 | CHAR 6 "\'\\x7f\'" | 9 | CHAR 6 "'\\x7f'" |
10 | WHITESPACE 1 " " | 10 | WHITESPACE 1 " " |
11 | CHAR 4 "\'\\n\'" | 11 | CHAR 4 "'\\n'" |
12 | WHITESPACE 1 " " | 12 | WHITESPACE 1 " " |
13 | CHAR 4 "\'\\\\\'" | 13 | CHAR 4 "'\\\\'" |
14 | WHITESPACE 1 " " | 14 | WHITESPACE 1 " " |
15 | CHAR 4 "\'\\\'\'" | 15 | CHAR 4 "'\\''" |
16 | WHITESPACE 1 "\n" | 16 | WHITESPACE 1 "\n" |
diff --git a/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt b/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt index 4d6625c3a..32ed9ed50 100644 --- a/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt +++ b/crates/syntax/test_data/lexer/ok/0007_lifetimes.txt | |||
@@ -1,8 +1,8 @@ | |||
1 | LIFETIME_IDENT 2 "\'a" | 1 | LIFETIME_IDENT 2 "'a" |
2 | WHITESPACE 1 " " | 2 | WHITESPACE 1 " " |
3 | LIFETIME_IDENT 4 "\'foo" | 3 | LIFETIME_IDENT 4 "'foo" |
4 | WHITESPACE 1 " " | 4 | WHITESPACE 1 " " |
5 | LIFETIME_IDENT 12 "\'foo_bar_baz" | 5 | LIFETIME_IDENT 12 "'foo_bar_baz" |
6 | WHITESPACE 1 " " | 6 | WHITESPACE 1 " " |
7 | LIFETIME_IDENT 2 "\'_" | 7 | LIFETIME_IDENT 2 "'_" |
8 | WHITESPACE 1 "\n" | 8 | WHITESPACE 1 "\n" |
diff --git a/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt b/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt index e61ad99be..06d6bdd1f 100644 --- a/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt +++ b/crates/syntax/test_data/lexer/ok/0008_byte_strings.txt | |||
@@ -1,22 +1,22 @@ | |||
1 | BYTE 3 "b\'\'" | 1 | BYTE 3 "b''" |
2 | WHITESPACE 1 " " | 2 | WHITESPACE 1 " " |
3 | BYTE 4 "b\'x\'" | 3 | BYTE 4 "b'x'" |
4 | WHITESPACE 1 " " | 4 | WHITESPACE 1 " " |
5 | BYTE_STRING 6 "b\"foo\"" | 5 | BYTE_STRING 6 "b\"foo\"" |
6 | WHITESPACE 1 " " | 6 | WHITESPACE 1 " " |
7 | BYTE_STRING 4 "br\"\"" | 7 | BYTE_STRING 4 "br\"\"" |
8 | WHITESPACE 1 "\n" | 8 | WHITESPACE 1 "\n" |
9 | BYTE 6 "b\'\'suf" | 9 | BYTE 6 "b''suf" |
10 | WHITESPACE 1 " " | 10 | WHITESPACE 1 " " |
11 | BYTE_STRING 5 "b\"\"ix" | 11 | BYTE_STRING 5 "b\"\"ix" |
12 | WHITESPACE 1 " " | 12 | WHITESPACE 1 " " |
13 | BYTE_STRING 6 "br\"\"br" | 13 | BYTE_STRING 6 "br\"\"br" |
14 | WHITESPACE 1 "\n" | 14 | WHITESPACE 1 "\n" |
15 | BYTE 5 "b\'\\n\'" | 15 | BYTE 5 "b'\\n'" |
16 | WHITESPACE 1 " " | 16 | WHITESPACE 1 " " |
17 | BYTE 5 "b\'\\\\\'" | 17 | BYTE 5 "b'\\\\'" |
18 | WHITESPACE 1 " " | 18 | WHITESPACE 1 " " |
19 | BYTE 5 "b\'\\\'\'" | 19 | BYTE 5 "b'\\''" |
20 | WHITESPACE 1 " " | 20 | WHITESPACE 1 " " |
21 | BYTE 8 "b\'hello\'" | 21 | BYTE 8 "b'hello'" |
22 | WHITESPACE 1 "\n" | 22 | WHITESPACE 1 "\n" |
diff --git a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast index 4c4ddf5ec..be4a62940 100644 --- a/crates/syntax/test_data/parser/err/0024_many_type_parens.rast +++ b/crates/syntax/test_data/parser/err/0024_many_type_parens.rast | |||
@@ -43,7 +43,7 @@ [email protected] | |||
43 | [email protected] "<" | 43 | [email protected] "<" |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] "\'a" | 46 | [email protected] "'a" |
47 | [email protected] ">" | 47 | [email protected] ">" |
48 | [email protected] " " | 48 | [email protected] " " |
49 | [email protected] | 49 | [email protected] |
@@ -55,7 +55,7 @@ [email protected] | |||
55 | [email protected] "<" | 55 | [email protected] "<" |
56 | [email protected] | 56 | [email protected] |
57 | [email protected] | 57 | [email protected] |
58 | [email protected] "\'a" | 58 | [email protected] "'a" |
59 | [email protected] ">" | 59 | [email protected] ">" |
60 | [email protected] ")" | 60 | [email protected] ")" |
61 | [email protected] ">" | 61 | [email protected] ">" |
@@ -128,7 +128,7 @@ [email protected] | |||
128 | [email protected] "<" | 128 | [email protected] "<" |
129 | [email protected] | 129 | [email protected] |
130 | [email protected] | 130 | [email protected] |
131 | [email protected] "\'a" | 131 | [email protected] "'a" |
132 | [email protected] ">" | 132 | [email protected] ">" |
133 | [email protected] " " | 133 | [email protected] " " |
134 | [email protected] | 134 | [email protected] |
@@ -140,7 +140,7 @@ [email protected] | |||
140 | [email protected] "<" | 140 | [email protected] "<" |
141 | [email protected] | 141 | [email protected] |
142 | [email protected] | 142 | [email protected] |
143 | [email protected] "\'a" | 143 | [email protected] "'a" |
144 | [email protected] ">" | 144 | [email protected] ">" |
145 | [email protected] ")" | 145 | [email protected] ")" |
146 | [email protected] | 146 | [email protected] |
@@ -191,7 +191,7 @@ [email protected] | |||
191 | [email protected] | 191 | [email protected] |
192 | [email protected] "<" | 192 | [email protected] "<" |
193 | [email protected] | 193 | [email protected] |
194 | [email protected] "\'a" | 194 | [email protected] "'a" |
195 | [email protected] ">" | 195 | [email protected] ">" |
196 | [email protected] " " | 196 | [email protected] " " |
197 | [email protected] | 197 | [email protected] |
@@ -205,7 +205,7 @@ [email protected] | |||
205 | [email protected] "Trait" | 205 | [email protected] "Trait" |
206 | [email protected] "<" | 206 | [email protected] "<" |
207 | [email protected] | 207 | [email protected] |
208 | [email protected] "\'a" | 208 | [email protected] "'a" |
209 | [email protected] ">" | 209 | [email protected] ">" |
210 | [email protected] | 210 | [email protected] |
211 | [email protected] ")" | 211 | [email protected] ")" |
@@ -250,7 +250,7 @@ [email protected] | |||
250 | [email protected] "<" | 250 | [email protected] "<" |
251 | [email protected] | 251 | [email protected] |
252 | [email protected] | 252 | [email protected] |
253 | [email protected] "\'a" | 253 | [email protected] "'a" |
254 | [email protected] ">" | 254 | [email protected] ">" |
255 | [email protected] " " | 255 | [email protected] " " |
256 | [email protected] | 256 | [email protected] |
@@ -262,7 +262,7 @@ [email protected] | |||
262 | [email protected] "<" | 262 | [email protected] "<" |
263 | [email protected] | 263 | [email protected] |
264 | [email protected] | 264 | [email protected] |
265 | [email protected] "\'a" | 265 | [email protected] "'a" |
266 | [email protected] ">" | 266 | [email protected] ">" |
267 | [email protected] ")" | 267 | [email protected] ")" |
268 | [email protected] " " | 268 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast b/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast index c5215d6b1..b021783fc 100644 --- a/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast +++ b/crates/syntax/test_data/parser/err/0027_incomplere_where_for.rast | |||
@@ -17,7 +17,7 @@ [email protected] | |||
17 | [email protected] "<" | 17 | [email protected] "<" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "\'a" | 20 | [email protected] "'a" |
21 | [email protected] ">" | 21 | [email protected] ">" |
22 | [email protected] "\n" | 22 | [email protected] "\n" |
23 | [email protected] | 23 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast index e73bd1aea..e24f01e29 100644 --- a/crates/syntax/test_data/parser/err/0043_weird_blocks.rast +++ b/crates/syntax/test_data/parser/err/0043_weird_blocks.rast | |||
@@ -55,7 +55,7 @@ [email protected] | |||
55 | [email protected] | 55 | [email protected] |
56 | [email protected] | 56 | [email protected] |
57 | [email protected] | 57 | [email protected] |
58 | [email protected] "\'label" | 58 | [email protected] "'label" |
59 | [email protected] ":" | 59 | [email protected] ":" |
60 | [email protected] " " | 60 | [email protected] " " |
61 | [email protected] | 61 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast b/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast index cc54185e5..a2460a7ec 100644 --- a/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast +++ b/crates/syntax/test_data/parser/err/0044_unexpected_for_type.rast | |||
@@ -13,13 +13,13 @@ [email protected] | |||
13 | [email protected] "<" | 13 | [email protected] "<" |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "\'a" | 16 | [email protected] "'a" |
17 | [email protected] ">" | 17 | [email protected] ">" |
18 | [email protected] " " | 18 | [email protected] " " |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "&" | 20 | [email protected] "&" |
21 | [email protected] | 21 | [email protected] |
22 | [email protected] "\'a" | 22 | [email protected] "'a" |
23 | [email protected] " " | 23 | [email protected] " " |
24 | [email protected] | 24 | [email protected] |
25 | [email protected] | 25 | [email protected] |
@@ -42,7 +42,7 @@ [email protected] | |||
42 | [email protected] "<" | 42 | [email protected] "<" |
43 | [email protected] | 43 | [email protected] |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] "\'a" | 45 | [email protected] "'a" |
46 | [email protected] ">" | 46 | [email protected] ">" |
47 | [email protected] " " | 47 | [email protected] " " |
48 | [email protected] | 48 | [email protected] |
@@ -50,7 +50,7 @@ [email protected] | |||
50 | [email protected] | 50 | [email protected] |
51 | [email protected] "&" | 51 | [email protected] "&" |
52 | [email protected] | 52 | [email protected] |
53 | [email protected] "\'a" | 53 | [email protected] "'a" |
54 | [email protected] " " | 54 | [email protected] " " |
55 | [email protected] | 55 | [email protected] |
56 | [email protected] | 56 | [email protected] |
@@ -75,7 +75,7 @@ [email protected] | |||
75 | [email protected] "<" | 75 | [email protected] "<" |
76 | [email protected] | 76 | [email protected] |
77 | [email protected] | 77 | [email protected] |
78 | [email protected] "\'a" | 78 | [email protected] "'a" |
79 | [email protected] ">" | 79 | [email protected] ">" |
80 | [email protected] " " | 80 | [email protected] " " |
81 | [email protected] | 81 | [email protected] |
@@ -102,7 +102,7 @@ [email protected] | |||
102 | [email protected] "<" | 102 | [email protected] "<" |
103 | [email protected] | 103 | [email protected] |
104 | [email protected] | 104 | [email protected] |
105 | [email protected] "\'a" | 105 | [email protected] "'a" |
106 | [email protected] ">" | 106 | [email protected] ">" |
107 | [email protected] " " | 107 | [email protected] " " |
108 | [email protected] | 108 | [email protected] |
@@ -111,7 +111,7 @@ [email protected] | |||
111 | [email protected] "<" | 111 | [email protected] "<" |
112 | [email protected] | 112 | [email protected] |
113 | [email protected] | 113 | [email protected] |
114 | [email protected] "\'b" | 114 | [email protected] "'b" |
115 | [email protected] ">" | 115 | [email protected] ">" |
116 | [email protected] " " | 116 | [email protected] " " |
117 | [email protected] | 117 | [email protected] |
@@ -122,7 +122,7 @@ [email protected] | |||
122 | [email protected] | 122 | [email protected] |
123 | [email protected] "&" | 123 | [email protected] "&" |
124 | [email protected] | 124 | [email protected] |
125 | [email protected] "\'a" | 125 | [email protected] "'a" |
126 | [email protected] " " | 126 | [email protected] " " |
127 | [email protected] | 127 | [email protected] |
128 | [email protected] | 128 | [email protected] |
@@ -135,7 +135,7 @@ [email protected] | |||
135 | [email protected] | 135 | [email protected] |
136 | [email protected] "&" | 136 | [email protected] "&" |
137 | [email protected] | 137 | [email protected] |
138 | [email protected] "\'b" | 138 | [email protected] "'b" |
139 | [email protected] " " | 139 | [email protected] " " |
140 | [email protected] | 140 | [email protected] |
141 | [email protected] | 141 | [email protected] |
@@ -169,7 +169,7 @@ [email protected] | |||
169 | [email protected] "<" | 169 | [email protected] "<" |
170 | [email protected] | 170 | [email protected] |
171 | [email protected] | 171 | [email protected] |
172 | [email protected] "\'a" | 172 | [email protected] "'a" |
173 | [email protected] ">" | 173 | [email protected] ">" |
174 | [email protected] " " | 174 | [email protected] " " |
175 | [email protected] | 175 | [email protected] |
@@ -178,7 +178,7 @@ [email protected] | |||
178 | [email protected] "<" | 178 | [email protected] "<" |
179 | [email protected] | 179 | [email protected] |
180 | [email protected] | 180 | [email protected] |
181 | [email protected] "\'b" | 181 | [email protected] "'b" |
182 | [email protected] ">" | 182 | [email protected] ">" |
183 | [email protected] " " | 183 | [email protected] " " |
184 | [email protected] | 184 | [email protected] |
@@ -187,7 +187,7 @@ [email protected] | |||
187 | [email protected] "<" | 187 | [email protected] "<" |
188 | [email protected] | 188 | [email protected] |
189 | [email protected] | 189 | [email protected] |
190 | [email protected] "\'c" | 190 | [email protected] "'c" |
191 | [email protected] ">" | 191 | [email protected] ">" |
192 | [email protected] " " | 192 | [email protected] " " |
193 | [email protected] | 193 | [email protected] |
@@ -198,7 +198,7 @@ [email protected] | |||
198 | [email protected] | 198 | [email protected] |
199 | [email protected] "&" | 199 | [email protected] "&" |
200 | [email protected] | 200 | [email protected] |
201 | [email protected] "\'a" | 201 | [email protected] "'a" |
202 | [email protected] " " | 202 | [email protected] " " |
203 | [email protected] | 203 | [email protected] |
204 | [email protected] | 204 | [email protected] |
@@ -211,7 +211,7 @@ [email protected] | |||
211 | [email protected] | 211 | [email protected] |
212 | [email protected] "&" | 212 | [email protected] "&" |
213 | [email protected] | 213 | [email protected] |
214 | [email protected] "\'b" | 214 | [email protected] "'b" |
215 | [email protected] " " | 215 | [email protected] " " |
216 | [email protected] | 216 | [email protected] |
217 | [email protected] | 217 | [email protected] |
@@ -224,7 +224,7 @@ [email protected] | |||
224 | [email protected] | 224 | [email protected] |
225 | [email protected] "&" | 225 | [email protected] "&" |
226 | [email protected] | 226 | [email protected] |
227 | [email protected] "\'c" | 227 | [email protected] "'c" |
228 | [email protected] " " | 228 | [email protected] " " |
229 | [email protected] | 229 | [email protected] |
230 | [email protected] | 230 | [email protected] |
diff --git a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast index 7049f4734..6eaa32b96 100644 --- a/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast +++ b/crates/syntax/test_data/parser/err/0046_ambiguous_trait_object.rast | |||
@@ -8,7 +8,7 @@ [email protected] | |||
8 | [email protected] "<" | 8 | [email protected] "<" |
9 | [email protected] | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "\'a" | 11 | [email protected] "'a" |
12 | [email protected] ">" | 12 | [email protected] ">" |
13 | [email protected] " " | 13 | [email protected] " " |
14 | [email protected] "=" | 14 | [email protected] "=" |
@@ -16,7 +16,7 @@ [email protected] | |||
16 | [email protected] | 16 | [email protected] |
17 | [email protected] "&" | 17 | [email protected] "&" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] "\'a" | 19 | [email protected] "'a" |
20 | [email protected] " " | 20 | [email protected] " " |
21 | [email protected] | 21 | [email protected] |
22 | [email protected] "dyn" | 22 | [email protected] "dyn" |
@@ -104,7 +104,7 @@ [email protected] | |||
104 | [email protected] " " | 104 | [email protected] " " |
105 | [email protected] | 105 | [email protected] |
106 | [email protected] | 106 | [email protected] |
107 | [email protected] "\'static" | 107 | [email protected] "'static" |
108 | [email protected] ";" | 108 | [email protected] ";" |
109 | [email protected] "\n" | 109 | [email protected] "\n" |
110 | [email protected] | 110 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast index 0adf2cd5a..97bb5059d 100644 --- a/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast +++ b/crates/syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast | |||
@@ -15,7 +15,7 @@ [email protected] | |||
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "\'loop" | 18 | [email protected] "'loop" |
19 | [email protected] ":" | 19 | [email protected] ":" |
20 | [email protected] " " | 20 | [email protected] " " |
21 | [email protected] | 21 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast b/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast index 6cdfd058b..12f5040f9 100644 --- a/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast +++ b/crates/syntax/test_data/parser/inline/ok/0003_where_pred_for.rast | |||
@@ -23,7 +23,7 @@ [email protected] | |||
23 | [email protected] "<" | 23 | [email protected] "<" |
24 | [email protected] | 24 | [email protected] |
25 | [email protected] | 25 | [email protected] |
26 | [email protected] "\'a" | 26 | [email protected] "'a" |
27 | [email protected] ">" | 27 | [email protected] ">" |
28 | [email protected] " " | 28 | [email protected] " " |
29 | [email protected] | 29 | [email protected] |
@@ -46,7 +46,7 @@ [email protected] | |||
46 | [email protected] | 46 | [email protected] |
47 | [email protected] "&" | 47 | [email protected] "&" |
48 | [email protected] | 48 | [email protected] |
49 | [email protected] "\'a" | 49 | [email protected] "'a" |
50 | [email protected] " " | 50 | [email protected] " " |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] | 52 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast b/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast index f0d152d33..d4c8b9d67 100644 --- a/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast +++ b/crates/syntax/test_data/parser/inline/ok/0006_self_param.rast | |||
@@ -55,7 +55,7 @@ [email protected] | |||
55 | [email protected] | 55 | [email protected] |
56 | [email protected] "&" | 56 | [email protected] "&" |
57 | [email protected] | 57 | [email protected] |
58 | [email protected] "\'a" | 58 | [email protected] "'a" |
59 | [email protected] " " | 59 | [email protected] " " |
60 | [email protected] | 60 | [email protected] |
61 | [email protected] "self" | 61 | [email protected] "self" |
@@ -76,7 +76,7 @@ [email protected] | |||
76 | [email protected] | 76 | [email protected] |
77 | [email protected] "&" | 77 | [email protected] "&" |
78 | [email protected] | 78 | [email protected] |
79 | [email protected] "\'a" | 79 | [email protected] "'a" |
80 | [email protected] " " | 80 | [email protected] " " |
81 | [email protected] "mut" | 81 | [email protected] "mut" |
82 | [email protected] " " | 82 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast index 075b438d2..121c3966a 100644 --- a/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast +++ b/crates/syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast | |||
@@ -14,7 +14,7 @@ [email protected] | |||
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] "\'a" | 17 | [email protected] "'a" |
18 | [email protected] " " | 18 | [email protected] " " |
19 | [email protected] "+" | 19 | [email protected] "+" |
20 | [email protected] " " | 20 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast b/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast index b9e92b57a..b67ea2682 100644 --- a/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0015_continue_expr.rast | |||
@@ -27,7 +27,7 @@ [email protected] | |||
27 | [email protected] "continue" | 27 | [email protected] "continue" |
28 | [email protected] " " | 28 | [email protected] " " |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] "\'l" | 30 | [email protected] "'l" |
31 | [email protected] ";" | 31 | [email protected] ";" |
32 | [email protected] "\n " | 32 | [email protected] "\n " |
33 | [email protected] "}" | 33 | [email protected] "}" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast b/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast index dad4362b7..b44f46f05 100644 --- a/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast | |||
@@ -32,7 +32,7 @@ [email protected] | |||
32 | [email protected] "<" | 32 | [email protected] "<" |
33 | [email protected] | 33 | [email protected] |
34 | [email protected] | 34 | [email protected] |
35 | [email protected] "\'a" | 35 | [email protected] "'a" |
36 | [email protected] ">" | 36 | [email protected] ">" |
37 | [email protected] ">" | 37 | [email protected] ">" |
38 | [email protected] " " | 38 | [email protected] " " |
@@ -40,6 +40,6 @@ [email protected] | |||
40 | [email protected] " " | 40 | [email protected] " " |
41 | [email protected] | 41 | [email protected] |
42 | [email protected] | 42 | [email protected] |
43 | [email protected] "\'a" | 43 | [email protected] "'a" |
44 | [email protected] ";" | 44 | [email protected] ";" |
45 | [email protected] "\n" | 45 | [email protected] "\n" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast b/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast index ac0299268..7cb288bf0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast +++ b/crates/syntax/test_data/parser/inline/ok/0033_reference_type;.rast | |||
@@ -25,7 +25,7 @@ [email protected] | |||
25 | [email protected] | 25 | [email protected] |
26 | [email protected] "&" | 26 | [email protected] "&" |
27 | [email protected] | 27 | [email protected] |
28 | [email protected] "\'static" | 28 | [email protected] "'static" |
29 | [email protected] " " | 29 | [email protected] " " |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "(" | 31 | [email protected] "(" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast b/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast index 828013d45..783b25338 100644 --- a/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0034_break_expr.rast | |||
@@ -27,7 +27,7 @@ [email protected] | |||
27 | [email protected] "break" | 27 | [email protected] "break" |
28 | [email protected] " " | 28 | [email protected] " " |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] "\'l" | 30 | [email protected] "'l" |
31 | [email protected] ";" | 31 | [email protected] ";" |
32 | [email protected] "\n " | 32 | [email protected] "\n " |
33 | [email protected] | 33 | [email protected] |
@@ -43,7 +43,7 @@ [email protected] | |||
43 | [email protected] "break" | 43 | [email protected] "break" |
44 | [email protected] " " | 44 | [email protected] " " |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] "\'l" | 46 | [email protected] "'l" |
47 | [email protected] " " | 47 | [email protected] " " |
48 | [email protected] | 48 | [email protected] |
49 | [email protected] "92" | 49 | [email protected] "92" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast index 68c0f1c66..11efa23a4 100644 --- a/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast +++ b/crates/syntax/test_data/parser/inline/ok/0039_type_arg.rast | |||
@@ -16,7 +16,7 @@ [email protected] | |||
16 | [email protected] "<" | 16 | [email protected] "<" |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] "\'static" | 19 | [email protected] "'static" |
20 | [email protected] "," | 20 | [email protected] "," |
21 | [email protected] " " | 21 | [email protected] " " |
22 | [email protected] | 22 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast b/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast index b6f5a5689..abc258b33 100644 --- a/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast +++ b/crates/syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast | |||
@@ -34,7 +34,7 @@ [email protected] | |||
34 | [email protected] "<" | 34 | [email protected] "<" |
35 | [email protected] | 35 | [email protected] |
36 | [email protected] | 36 | [email protected] |
37 | [email protected] "\'a" | 37 | [email protected] "'a" |
38 | [email protected] ">" | 38 | [email protected] ">" |
39 | [email protected] ")" | 39 | [email protected] ")" |
40 | [email protected] ">" | 40 | [email protected] ">" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast index 7df6e190a..e1b88c5db 100644 --- a/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast +++ b/crates/syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast | |||
@@ -32,7 +32,7 @@ [email protected] | |||
32 | [email protected] " " | 32 | [email protected] " " |
33 | [email protected] | 33 | [email protected] |
34 | [email protected] | 34 | [email protected] |
35 | [email protected] "\'f" | 35 | [email protected] "'f" |
36 | [email protected] ">" | 36 | [email protected] ">" |
37 | [email protected] " " | 37 | [email protected] " " |
38 | [email protected] | 38 | [email protected] |
@@ -74,7 +74,7 @@ [email protected] | |||
74 | [email protected] " " | 74 | [email protected] " " |
75 | [email protected] | 75 | [email protected] |
76 | [email protected] | 76 | [email protected] |
77 | [email protected] "\'f" | 77 | [email protected] "'f" |
78 | [email protected] ">" | 78 | [email protected] ">" |
79 | [email protected] " " | 79 | [email protected] " " |
80 | [email protected] | 80 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast b/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast index 68bb43852..acf18fc2b 100644 --- a/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast +++ b/crates/syntax/test_data/parser/inline/ok/0055_literal_pattern.rast | |||
@@ -49,7 +49,7 @@ [email protected] | |||
49 | [email protected] | 49 | [email protected] |
50 | [email protected] | 50 | [email protected] |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] "\'c\'" | 52 | [email protected] "'c'" |
53 | [email protected] " " | 53 | [email protected] " " |
54 | [email protected] "=>" | 54 | [email protected] "=>" |
55 | [email protected] " " | 55 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast b/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast index 61dea413d..d42a7e295 100644 --- a/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast +++ b/crates/syntax/test_data/parser/inline/ok/0056_where_clause.rast | |||
@@ -13,19 +13,19 @@ [email protected] | |||
13 | [email protected] "\n " | 13 | [email protected] "\n " |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "\'a" | 16 | [email protected] "'a" |
17 | [email protected] ":" | 17 | [email protected] ":" |
18 | [email protected] " " | 18 | [email protected] " " |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] | 20 | [email protected] |
21 | [email protected] | 21 | [email protected] |
22 | [email protected] "\'b" | 22 | [email protected] "'b" |
23 | [email protected] " " | 23 | [email protected] " " |
24 | [email protected] "+" | 24 | [email protected] "+" |
25 | [email protected] " " | 25 | [email protected] " " |
26 | [email protected] | 26 | [email protected] |
27 | [email protected] | 27 | [email protected] |
28 | [email protected] "\'c" | 28 | [email protected] "'c" |
29 | [email protected] "," | 29 | [email protected] "," |
30 | [email protected] "\n " | 30 | [email protected] "\n " |
31 | [email protected] | 31 | [email protected] |
@@ -57,7 +57,7 @@ [email protected] | |||
57 | [email protected] " " | 57 | [email protected] " " |
58 | [email protected] | 58 | [email protected] |
59 | [email protected] | 59 | [email protected] |
60 | [email protected] "\'static" | 60 | [email protected] "'static" |
61 | [email protected] "," | 61 | [email protected] "," |
62 | [email protected] "\n " | 62 | [email protected] "\n " |
63 | [email protected] | 63 | [email protected] |
@@ -76,7 +76,7 @@ [email protected] | |||
76 | [email protected] | 76 | [email protected] |
77 | [email protected] | 77 | [email protected] |
78 | [email protected] | 78 | [email protected] |
79 | [email protected] "\'a" | 79 | [email protected] "'a" |
80 | [email protected] "," | 80 | [email protected] "," |
81 | [email protected] "\n " | 81 | [email protected] "\n " |
82 | [email protected] | 82 | [email protected] |
@@ -108,7 +108,7 @@ [email protected] | |||
108 | [email protected] | 108 | [email protected] |
109 | [email protected] | 109 | [email protected] |
110 | [email protected] | 110 | [email protected] |
111 | [email protected] "\'a" | 111 | [email protected] "'a" |
112 | [email protected] "\n" | 112 | [email protected] "\n" |
113 | [email protected] | 113 | [email protected] |
114 | [email protected] "{" | 114 | [email protected] "{" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast b/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast index 49d26cef4..8f76177d1 100644 --- a/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast | |||
@@ -32,7 +32,7 @@ [email protected] | |||
32 | [email protected] "<" | 32 | [email protected] "<" |
33 | [email protected] | 33 | [email protected] |
34 | [email protected] | 34 | [email protected] |
35 | [email protected] "\'a" | 35 | [email protected] "'a" |
36 | [email protected] ">" | 36 | [email protected] ">" |
37 | [email protected] ">" | 37 | [email protected] ">" |
38 | [email protected] " " | 38 | [email protected] " " |
@@ -40,6 +40,6 @@ [email protected] | |||
40 | [email protected] " " | 40 | [email protected] " " |
41 | [email protected] | 41 | [email protected] |
42 | [email protected] | 42 | [email protected] |
43 | [email protected] "\'a" | 43 | [email protected] "'a" |
44 | [email protected] ";" | 44 | [email protected] ";" |
45 | [email protected] "\n" | 45 | [email protected] "\n" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast b/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast index 8c909b5af..7958e32e5 100644 --- a/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0081_for_type.rast | |||
@@ -13,7 +13,7 @@ [email protected] | |||
13 | [email protected] "<" | 13 | [email protected] "<" |
14 | [email protected] | 14 | [email protected] |
15 | [email protected] | 15 | [email protected] |
16 | [email protected] "\'a" | 16 | [email protected] "'a" |
17 | [email protected] ">" | 17 | [email protected] ">" |
18 | [email protected] " " | 18 | [email protected] " " |
19 | [email protected] | 19 | [email protected] |
@@ -44,7 +44,7 @@ [email protected] | |||
44 | [email protected] "<" | 44 | [email protected] "<" |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] | 46 | [email protected] |
47 | [email protected] "\'a" | 47 | [email protected] "'a" |
48 | [email protected] ">" | 48 | [email protected] ">" |
49 | [email protected] " " | 49 | [email protected] " " |
50 | [email protected] | 50 | [email protected] |
@@ -62,7 +62,7 @@ [email protected] | |||
62 | [email protected] | 62 | [email protected] |
63 | [email protected] "&" | 63 | [email protected] "&" |
64 | [email protected] | 64 | [email protected] |
65 | [email protected] "\'a" | 65 | [email protected] "'a" |
66 | [email protected] " " | 66 | [email protected] " " |
67 | [email protected] | 67 | [email protected] |
68 | [email protected] "(" | 68 | [email protected] "(" |
@@ -91,7 +91,7 @@ [email protected] | |||
91 | [email protected] "<" | 91 | [email protected] "<" |
92 | [email protected] | 92 | [email protected] |
93 | [email protected] | 93 | [email protected] |
94 | [email protected] "\'a" | 94 | [email protected] "'a" |
95 | [email protected] ">" | 95 | [email protected] ">" |
96 | [email protected] " " | 96 | [email protected] " " |
97 | [email protected] | 97 | [email protected] |
@@ -105,7 +105,7 @@ [email protected] | |||
105 | [email protected] | 105 | [email protected] |
106 | [email protected] "&" | 106 | [email protected] "&" |
107 | [email protected] | 107 | [email protected] |
108 | [email protected] "\'a" | 108 | [email protected] "'a" |
109 | [email protected] " " | 109 | [email protected] " " |
110 | [email protected] | 110 | [email protected] |
111 | [email protected] | 111 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast b/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast index ae838105d..f784e96e0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast +++ b/crates/syntax/test_data/parser/inline/ok/0085_expr_literals.rast | |||
@@ -68,7 +68,7 @@ [email protected] | |||
68 | [email protected] "=" | 68 | [email protected] "=" |
69 | [email protected] " " | 69 | [email protected] " " |
70 | [email protected] | 70 | [email protected] |
71 | [email protected] "b\'a\'" | 71 | [email protected] "b'a'" |
72 | [email protected] ";" | 72 | [email protected] ";" |
73 | [email protected] "\n " | 73 | [email protected] "\n " |
74 | [email protected] | 74 | [email protected] |
@@ -80,7 +80,7 @@ [email protected] | |||
80 | [email protected] "=" | 80 | [email protected] "=" |
81 | [email protected] " " | 81 | [email protected] " " |
82 | [email protected] | 82 | [email protected] |
83 | [email protected] "\'b\'" | 83 | [email protected] "'b'" |
84 | [email protected] ";" | 84 | [email protected] ";" |
85 | [email protected] "\n " | 85 | [email protected] "\n " |
86 | [email protected] | 86 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0109_label.rast b/crates/syntax/test_data/parser/inline/ok/0109_label.rast index 860dfe608..8540b8520 100644 --- a/crates/syntax/test_data/parser/inline/ok/0109_label.rast +++ b/crates/syntax/test_data/parser/inline/ok/0109_label.rast | |||
@@ -15,7 +15,7 @@ [email protected] | |||
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "\'a" | 18 | [email protected] "'a" |
19 | [email protected] ":" | 19 | [email protected] ":" |
20 | [email protected] " " | 20 | [email protected] " " |
21 | [email protected] "loop" | 21 | [email protected] "loop" |
@@ -28,7 +28,7 @@ [email protected] | |||
28 | [email protected] | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "\'b" | 31 | [email protected] "'b" |
32 | [email protected] ":" | 32 | [email protected] ":" |
33 | [email protected] " " | 33 | [email protected] " " |
34 | [email protected] "while" | 34 | [email protected] "while" |
@@ -44,7 +44,7 @@ [email protected] | |||
44 | [email protected] | 44 | [email protected] |
45 | [email protected] | 45 | [email protected] |
46 | [email protected] | 46 | [email protected] |
47 | [email protected] "\'c" | 47 | [email protected] "'c" |
48 | [email protected] ":" | 48 | [email protected] ":" |
49 | [email protected] " " | 49 | [email protected] " " |
50 | [email protected] "for" | 50 | [email protected] "for" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast index 840181383..5682bd28c 100644 --- a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast +++ b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast | |||
@@ -22,7 +22,7 @@ [email protected] | |||
22 | [email protected] "]" | 22 | [email protected] "]" |
23 | [email protected] " " | 23 | [email protected] " " |
24 | [email protected] | 24 | [email protected] |
25 | [email protected] "\'a" | 25 | [email protected] "'a" |
26 | [email protected] "," | 26 | [email protected] "," |
27 | [email protected] " " | 27 | [email protected] " " |
28 | [email protected] | 28 | [email protected] |
@@ -53,7 +53,7 @@ [email protected] | |||
53 | [email protected] | 53 | [email protected] |
54 | [email protected] "&" | 54 | [email protected] "&" |
55 | [email protected] | 55 | [email protected] |
56 | [email protected] "\'a" | 56 | [email protected] "'a" |
57 | [email protected] " " | 57 | [email protected] " " |
58 | [email protected] | 58 | [email protected] |
59 | [email protected] | 59 | [email protected] |
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast index edfcb288c..860684b29 100644 --- a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast | |||
@@ -16,7 +16,7 @@ [email protected] | |||
16 | [email protected] "<" | 16 | [email protected] "<" |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] "\'a" | 19 | [email protected] "'a" |
20 | [email protected] ">" | 20 | [email protected] ">" |
21 | [email protected] " " | 21 | [email protected] " " |
22 | [email protected] | 22 | [email protected] |
@@ -28,7 +28,7 @@ [email protected] | |||
28 | [email protected] "<" | 28 | [email protected] "<" |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "\'a" | 31 | [email protected] "'a" |
32 | [email protected] ">" | 32 | [email protected] ">" |
33 | [email protected] " " | 33 | [email protected] " " |
34 | [email protected] "+" | 34 | [email protected] "+" |
diff --git a/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast b/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast index c2dea1cc1..47e8859ed 100644 --- a/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast +++ b/crates/syntax/test_data/parser/inline/ok/0161_labeled_block.rast | |||
@@ -15,7 +15,7 @@ [email protected] | |||
15 | [email protected] | 15 | [email protected] |
16 | [email protected] | 16 | [email protected] |
17 | [email protected] | 17 | [email protected] |
18 | [email protected] "\'label" | 18 | [email protected] "'label" |
19 | [email protected] ":" | 19 | [email protected] ":" |
20 | [email protected] " " | 20 | [email protected] " " |
21 | [email protected] | 21 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast index ff5877a7b..31f76589d 100644 --- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast +++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast | |||
@@ -21,7 +21,7 @@ [email protected] | |||
21 | [email protected] | 21 | [email protected] |
22 | [email protected] | 22 | [email protected] |
23 | [email protected] | 23 | [email protected] |
24 | [email protected] "ignore" | 24 | [email protected] "Ignore" |
25 | [email protected] "]" | 25 | [email protected] "]" |
26 | [email protected] "\n" | 26 | [email protected] "\n" |
27 | [email protected] "fn" | 27 | [email protected] "fn" |
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs index 3d2e01d5c..6f04cb171 100644 --- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs +++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | #[cfg(test)] | 1 | #[cfg(test)] |
2 | #[ignore] | 2 | #[Ignore] |
3 | fn foo() {} | 3 | fn foo() {} |
4 | 4 | ||
5 | #[path = "a.rs"] | 5 | #[path = "a.rs"] |
diff --git a/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast b/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast index 83e17757b..f845d5cff 100644 --- a/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast +++ b/crates/syntax/test_data/parser/ok/0018_struct_type_params.rast | |||
@@ -81,7 +81,7 @@ [email protected] | |||
81 | [email protected] "<" | 81 | [email protected] "<" |
82 | [email protected] | 82 | [email protected] |
83 | [email protected] | 83 | [email protected] |
84 | [email protected] "\'a" | 84 | [email protected] "'a" |
85 | [email protected] ">" | 85 | [email protected] ">" |
86 | [email protected] ";" | 86 | [email protected] ";" |
87 | [email protected] "\n" | 87 | [email protected] "\n" |
@@ -94,7 +94,7 @@ [email protected] | |||
94 | [email protected] "<" | 94 | [email protected] "<" |
95 | [email protected] | 95 | [email protected] |
96 | [email protected] | 96 | [email protected] |
97 | [email protected] "\'a" | 97 | [email protected] "'a" |
98 | [email protected] ":" | 98 | [email protected] ":" |
99 | [email protected] ">" | 99 | [email protected] ">" |
100 | [email protected] ";" | 100 | [email protected] ";" |
@@ -108,11 +108,11 @@ [email protected] | |||
108 | [email protected] "<" | 108 | [email protected] "<" |
109 | [email protected] | 109 | [email protected] |
110 | [email protected] | 110 | [email protected] |
111 | [email protected] "\'a" | 111 | [email protected] "'a" |
112 | [email protected] ":" | 112 | [email protected] ":" |
113 | [email protected] " " | 113 | [email protected] " " |
114 | [email protected] | 114 | [email protected] |
115 | [email protected] "\'b" | 115 | [email protected] "'b" |
116 | [email protected] ">" | 116 | [email protected] ">" |
117 | [email protected] ";" | 117 | [email protected] ";" |
118 | [email protected] "\n" | 118 | [email protected] "\n" |
@@ -125,11 +125,11 @@ [email protected] | |||
125 | [email protected] "<" | 125 | [email protected] "<" |
126 | [email protected] | 126 | [email protected] |
127 | [email protected] | 127 | [email protected] |
128 | [email protected] "\'a" | 128 | [email protected] "'a" |
129 | [email protected] ":" | 129 | [email protected] ":" |
130 | [email protected] " " | 130 | [email protected] " " |
131 | [email protected] | 131 | [email protected] |
132 | [email protected] "\'b" | 132 | [email protected] "'b" |
133 | [email protected] " " | 133 | [email protected] " " |
134 | [email protected] "+" | 134 | [email protected] "+" |
135 | [email protected] " " | 135 | [email protected] " " |
@@ -145,16 +145,16 @@ [email protected] | |||
145 | [email protected] "<" | 145 | [email protected] "<" |
146 | [email protected] | 146 | [email protected] |
147 | [email protected] | 147 | [email protected] |
148 | [email protected] "\'a" | 148 | [email protected] "'a" |
149 | [email protected] ":" | 149 | [email protected] ":" |
150 | [email protected] " " | 150 | [email protected] " " |
151 | [email protected] | 151 | [email protected] |
152 | [email protected] "\'b" | 152 | [email protected] "'b" |
153 | [email protected] " " | 153 | [email protected] " " |
154 | [email protected] "+" | 154 | [email protected] "+" |
155 | [email protected] " " | 155 | [email protected] " " |
156 | [email protected] | 156 | [email protected] |
157 | [email protected] "\'c" | 157 | [email protected] "'c" |
158 | [email protected] ">" | 158 | [email protected] ">" |
159 | [email protected] ";" | 159 | [email protected] ";" |
160 | [email protected] "\n" | 160 | [email protected] "\n" |
@@ -167,7 +167,7 @@ [email protected] | |||
167 | [email protected] "<" | 167 | [email protected] "<" |
168 | [email protected] | 168 | [email protected] |
169 | [email protected] | 169 | [email protected] |
170 | [email protected] "\'a" | 170 | [email protected] "'a" |
171 | [email protected] "," | 171 | [email protected] "," |
172 | [email protected] ">" | 172 | [email protected] ">" |
173 | [email protected] ";" | 173 | [email protected] ";" |
@@ -181,12 +181,12 @@ [email protected] | |||
181 | [email protected] "<" | 181 | [email protected] "<" |
182 | [email protected] | 182 | [email protected] |
183 | [email protected] | 183 | [email protected] |
184 | [email protected] "\'a" | 184 | [email protected] "'a" |
185 | [email protected] "," | 185 | [email protected] "," |
186 | [email protected] " " | 186 | [email protected] " " |
187 | [email protected] | 187 | [email protected] |
188 | [email protected] | 188 | [email protected] |
189 | [email protected] "\'b" | 189 | [email protected] "'b" |
190 | [email protected] ">" | 190 | [email protected] ">" |
191 | [email protected] ";" | 191 | [email protected] ";" |
192 | [email protected] "\n" | 192 | [email protected] "\n" |
@@ -199,21 +199,21 @@ [email protected] | |||
199 | [email protected] "<" | 199 | [email protected] "<" |
200 | [email protected] | 200 | [email protected] |
201 | [email protected] | 201 | [email protected] |
202 | [email protected] "\'a" | 202 | [email protected] "'a" |
203 | [email protected] ":" | 203 | [email protected] ":" |
204 | [email protected] " " | 204 | [email protected] " " |
205 | [email protected] | 205 | [email protected] |
206 | [email protected] "\'b" | 206 | [email protected] "'b" |
207 | [email protected] "+" | 207 | [email protected] "+" |
208 | [email protected] "," | 208 | [email protected] "," |
209 | [email protected] " " | 209 | [email protected] " " |
210 | [email protected] | 210 | [email protected] |
211 | [email protected] | 211 | [email protected] |
212 | [email protected] "\'b" | 212 | [email protected] "'b" |
213 | [email protected] ":" | 213 | [email protected] ":" |
214 | [email protected] " " | 214 | [email protected] " " |
215 | [email protected] | 215 | [email protected] |
216 | [email protected] "\'c" | 216 | [email protected] "'c" |
217 | [email protected] "," | 217 | [email protected] "," |
218 | [email protected] ">" | 218 | [email protected] ">" |
219 | [email protected] ";" | 219 | [email protected] ";" |
@@ -258,7 +258,7 @@ [email protected] | |||
258 | [email protected] "<" | 258 | [email protected] "<" |
259 | [email protected] | 259 | [email protected] |
260 | [email protected] | 260 | [email protected] |
261 | [email protected] "\'a" | 261 | [email protected] "'a" |
262 | [email protected] "," | 262 | [email protected] "," |
263 | [email protected] " " | 263 | [email protected] " " |
264 | [email protected] | 264 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast index 21c564a20..9d4b001ae 100644 --- a/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast +++ b/crates/syntax/test_data/parser/ok/0020_type_param_bounds.rast | |||
@@ -42,7 +42,7 @@ [email protected] | |||
42 | [email protected] | 42 | [email protected] |
43 | [email protected] | 43 | [email protected] |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] "\'a" | 45 | [email protected] "'a" |
46 | [email protected] ">" | 46 | [email protected] ">" |
47 | [email protected] ";" | 47 | [email protected] ";" |
48 | [email protected] "\n" | 48 | [email protected] "\n" |
@@ -61,7 +61,7 @@ [email protected] | |||
61 | [email protected] | 61 | [email protected] |
62 | [email protected] | 62 | [email protected] |
63 | [email protected] | 63 | [email protected] |
64 | [email protected] "\'a" | 64 | [email protected] "'a" |
65 | [email protected] " " | 65 | [email protected] " " |
66 | [email protected] "+" | 66 | [email protected] "+" |
67 | [email protected] " " | 67 | [email protected] " " |
@@ -83,13 +83,13 @@ [email protected] | |||
83 | [email protected] | 83 | [email protected] |
84 | [email protected] | 84 | [email protected] |
85 | [email protected] | 85 | [email protected] |
86 | [email protected] "\'a" | 86 | [email protected] "'a" |
87 | [email protected] " " | 87 | [email protected] " " |
88 | [email protected] "+" | 88 | [email protected] "+" |
89 | [email protected] " " | 89 | [email protected] " " |
90 | [email protected] | 90 | [email protected] |
91 | [email protected] | 91 | [email protected] |
92 | [email protected] "\'d" | 92 | [email protected] "'d" |
93 | [email protected] " " | 93 | [email protected] " " |
94 | [email protected] ">" | 94 | [email protected] ">" |
95 | [email protected] ";" | 95 | [email protected] ";" |
@@ -109,13 +109,13 @@ [email protected] | |||
109 | [email protected] | 109 | [email protected] |
110 | [email protected] | 110 | [email protected] |
111 | [email protected] | 111 | [email protected] |
112 | [email protected] "\'a" | 112 | [email protected] "'a" |
113 | [email protected] " " | 113 | [email protected] " " |
114 | [email protected] "+" | 114 | [email protected] "+" |
115 | [email protected] " " | 115 | [email protected] " " |
116 | [email protected] | 116 | [email protected] |
117 | [email protected] | 117 | [email protected] |
118 | [email protected] "\'d" | 118 | [email protected] "'d" |
119 | [email protected] " " | 119 | [email protected] " " |
120 | [email protected] "+" | 120 | [email protected] "+" |
121 | [email protected] " " | 121 | [email protected] " " |
@@ -198,7 +198,7 @@ [email protected] | |||
198 | [email protected] " " | 198 | [email protected] " " |
199 | [email protected] | 199 | [email protected] |
200 | [email protected] | 200 | [email protected] |
201 | [email protected] "\'a" | 201 | [email protected] "'a" |
202 | [email protected] ">" | 202 | [email protected] ">" |
203 | [email protected] ";" | 203 | [email protected] ";" |
204 | [email protected] "\n" | 204 | [email protected] "\n" |
@@ -234,25 +234,25 @@ [email protected] | |||
234 | [email protected] "<" | 234 | [email protected] "<" |
235 | [email protected] | 235 | [email protected] |
236 | [email protected] | 236 | [email protected] |
237 | [email protected] "\'a" | 237 | [email protected] "'a" |
238 | [email protected] ":" | 238 | [email protected] ":" |
239 | [email protected] " " | 239 | [email protected] " " |
240 | [email protected] | 240 | [email protected] |
241 | [email protected] "\'d" | 241 | [email protected] "'d" |
242 | [email protected] "," | 242 | [email protected] "," |
243 | [email protected] " " | 243 | [email protected] " " |
244 | [email protected] | 244 | [email protected] |
245 | [email protected] | 245 | [email protected] |
246 | [email protected] "\'d" | 246 | [email protected] "'d" |
247 | [email protected] ":" | 247 | [email protected] ":" |
248 | [email protected] " " | 248 | [email protected] " " |
249 | [email protected] | 249 | [email protected] |
250 | [email protected] "\'a" | 250 | [email protected] "'a" |
251 | [email protected] " " | 251 | [email protected] " " |
252 | [email protected] "+" | 252 | [email protected] "+" |
253 | [email protected] " " | 253 | [email protected] " " |
254 | [email protected] | 254 | [email protected] |
255 | [email protected] "\'b" | 255 | [email protected] "'b" |
256 | [email protected] "," | 256 | [email protected] "," |
257 | [email protected] " " | 257 | [email protected] " " |
258 | [email protected] | 258 | [email protected] |
@@ -263,13 +263,13 @@ [email protected] | |||
263 | [email protected] | 263 | [email protected] |
264 | [email protected] | 264 | [email protected] |
265 | [email protected] | 265 | [email protected] |
266 | [email protected] "\'a" | 266 | [email protected] "'a" |
267 | [email protected] " " | 267 | [email protected] " " |
268 | [email protected] "+" | 268 | [email protected] "+" |
269 | [email protected] " " | 269 | [email protected] " " |
270 | [email protected] | 270 | [email protected] |
271 | [email protected] | 271 | [email protected] |
272 | [email protected] "\'d" | 272 | [email protected] "'d" |
273 | [email protected] " " | 273 | [email protected] " " |
274 | [email protected] "+" | 274 | [email protected] "+" |
275 | [email protected] " " | 275 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast b/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast index 80f7f5942..115861585 100644 --- a/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast +++ b/crates/syntax/test_data/parser/ok/0030_string_suffixes.rast | |||
@@ -20,7 +20,7 @@ [email protected] | |||
20 | [email protected] "=" | 20 | [email protected] "=" |
21 | [email protected] " " | 21 | [email protected] " " |
22 | [email protected] | 22 | [email protected] |
23 | [email protected] "\'c\'u32" | 23 | [email protected] "'c'u32" |
24 | [email protected] ";" | 24 | [email protected] ";" |
25 | [email protected] "\n " | 25 | [email protected] "\n " |
26 | [email protected] | 26 | [email protected] |
@@ -44,7 +44,7 @@ [email protected] | |||
44 | [email protected] "=" | 44 | [email protected] "=" |
45 | [email protected] " " | 45 | [email protected] " " |
46 | [email protected] | 46 | [email protected] |
47 | [email protected] "b\'b\'_suff" | 47 | [email protected] "b'b'_suff" |
48 | [email protected] ";" | 48 | [email protected] ";" |
49 | [email protected] "\n " | 49 | [email protected] "\n " |
50 | [email protected] | 50 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0032_where_for.rast b/crates/syntax/test_data/parser/ok/0032_where_for.rast index 0cb2eca33..b527cc3ac 100644 --- a/crates/syntax/test_data/parser/ok/0032_where_for.rast +++ b/crates/syntax/test_data/parser/ok/0032_where_for.rast | |||
@@ -42,7 +42,7 @@ [email protected] | |||
42 | [email protected] "<" | 42 | [email protected] "<" |
43 | [email protected] | 43 | [email protected] |
44 | [email protected] | 44 | [email protected] |
45 | [email protected] "\'de" | 45 | [email protected] "'de" |
46 | [email protected] ">" | 46 | [email protected] ">" |
47 | [email protected] " " | 47 | [email protected] " " |
48 | [email protected] | 48 | [email protected] |
@@ -54,7 +54,7 @@ [email protected] | |||
54 | [email protected] "<" | 54 | [email protected] "<" |
55 | [email protected] | 55 | [email protected] |
56 | [email protected] | 56 | [email protected] |
57 | [email protected] "\'de" | 57 | [email protected] "'de" |
58 | [email protected] ">" | 58 | [email protected] ">" |
59 | [email protected] " " | 59 | [email protected] " " |
60 | [email protected] "+" | 60 | [email protected] "+" |
diff --git a/crates/syntax/test_data/parser/ok/0033_label_break.rast b/crates/syntax/test_data/parser/ok/0033_label_break.rast index 487e073ba..4b0f0997e 100644 --- a/crates/syntax/test_data/parser/ok/0033_label_break.rast +++ b/crates/syntax/test_data/parser/ok/0033_label_break.rast | |||
@@ -17,7 +17,7 @@ [email protected] | |||
17 | [email protected] | 17 | [email protected] |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] | 19 | [email protected] |
20 | [email protected] "\'empty_block" | 20 | [email protected] "'empty_block" |
21 | [email protected] ":" | 21 | [email protected] ":" |
22 | [email protected] " " | 22 | [email protected] " " |
23 | [email protected] | 23 | [email protected] |
@@ -28,7 +28,7 @@ [email protected] | |||
28 | [email protected] | 28 | [email protected] |
29 | [email protected] | 29 | [email protected] |
30 | [email protected] | 30 | [email protected] |
31 | [email protected] "\'block" | 31 | [email protected] "'block" |
32 | [email protected] ":" | 32 | [email protected] ":" |
33 | [email protected] " " | 33 | [email protected] " " |
34 | [email protected] | 34 | [email protected] |
@@ -69,7 +69,7 @@ [email protected] | |||
69 | [email protected] "break" | 69 | [email protected] "break" |
70 | [email protected] " " | 70 | [email protected] " " |
71 | [email protected] | 71 | [email protected] |
72 | [email protected] "\'block" | 72 | [email protected] "'block" |
73 | [email protected] ";" | 73 | [email protected] ";" |
74 | [email protected] "\n " | 74 | [email protected] "\n " |
75 | [email protected] "}" | 75 | [email protected] "}" |
@@ -109,7 +109,7 @@ [email protected] | |||
109 | [email protected] "break" | 109 | [email protected] "break" |
110 | [email protected] " " | 110 | [email protected] " " |
111 | [email protected] | 111 | [email protected] |
112 | [email protected] "\'block" | 112 | [email protected] "'block" |
113 | [email protected] ";" | 113 | [email protected] ";" |
114 | [email protected] "\n " | 114 | [email protected] "\n " |
115 | [email protected] "}" | 115 | [email protected] "}" |
@@ -140,7 +140,7 @@ [email protected] | |||
140 | [email protected] | 140 | [email protected] |
141 | [email protected] | 141 | [email protected] |
142 | [email protected] | 142 | [email protected] |
143 | [email protected] "\'block" | 143 | [email protected] "'block" |
144 | [email protected] ":" | 144 | [email protected] ":" |
145 | [email protected] " " | 145 | [email protected] " " |
146 | [email protected] | 146 | [email protected] |
@@ -171,7 +171,7 @@ [email protected] | |||
171 | [email protected] "break" | 171 | [email protected] "break" |
172 | [email protected] " " | 172 | [email protected] " " |
173 | [email protected] | 173 | [email protected] |
174 | [email protected] "\'block" | 174 | [email protected] "'block" |
175 | [email protected] " " | 175 | [email protected] " " |
176 | [email protected] | 176 | [email protected] |
177 | [email protected] "1" | 177 | [email protected] "1" |
@@ -204,7 +204,7 @@ [email protected] | |||
204 | [email protected] "break" | 204 | [email protected] "break" |
205 | [email protected] " " | 205 | [email protected] " " |
206 | [email protected] | 206 | [email protected] |
207 | [email protected] "\'block" | 207 | [email protected] "'block" |
208 | [email protected] " " | 208 | [email protected] " " |
209 | [email protected] | 209 | [email protected] |
210 | [email protected] "2" | 210 | [email protected] "2" |
diff --git a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast index 20675dbf5..2fa46ad2d 100644 --- a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast +++ b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast | |||
@@ -1378,14 +1378,14 @@ [email protected] | |||
1378 | [email protected] " " | 1378 | [email protected] " " |
1379 | [email protected] "u8" | 1379 | [email protected] "u8" |
1380 | [email protected] "<" | 1380 | [email protected] "<" |
1381 | [email protected] "\'u8" | 1381 | [email protected] "'u8" |
1382 | [email protected] ":" | 1382 | [email protected] ":" |
1383 | [email protected] " " | 1383 | [email protected] " " |
1384 | [email protected] "\'u8" | 1384 | [email protected] "'u8" |
1385 | [email protected] " " | 1385 | [email protected] " " |
1386 | [email protected] "+" | 1386 | [email protected] "+" |
1387 | [email protected] " " | 1387 | [email protected] " " |
1388 | [email protected] "\'u8" | 1388 | [email protected] "'u8" |
1389 | [email protected] ">" | 1389 | [email protected] ">" |
1390 | [email protected] | 1390 | [email protected] |
1391 | [email protected] "(" | 1391 | [email protected] "(" |
@@ -1393,7 +1393,7 @@ [email protected] | |||
1393 | [email protected] ":" | 1393 | [email protected] ":" |
1394 | [email protected] " " | 1394 | [email protected] " " |
1395 | [email protected] "&" | 1395 | [email protected] "&" |
1396 | [email protected] "\'u8" | 1396 | [email protected] "'u8" |
1397 | [email protected] " " | 1397 | [email protected] " " |
1398 | [email protected] "u8" | 1398 | [email protected] "u8" |
1399 | [email protected] ")" | 1399 | [email protected] ")" |
@@ -1402,7 +1402,7 @@ [email protected] | |||
1402 | [email protected] ">" | 1402 | [email protected] ">" |
1403 | [email protected] " " | 1403 | [email protected] " " |
1404 | [email protected] "&" | 1404 | [email protected] "&" |
1405 | [email protected] "\'u8" | 1405 | [email protected] "'u8" |
1406 | [email protected] " " | 1406 | [email protected] " " |
1407 | [email protected] "u8" | 1407 | [email protected] "u8" |
1408 | [email protected] " " | 1408 | [email protected] " " |
@@ -1574,7 +1574,7 @@ [email protected] | |||
1574 | [email protected] "<" | 1574 | [email protected] "<" |
1575 | [email protected] | 1575 | [email protected] |
1576 | [email protected] | 1576 | [email protected] |
1577 | [email protected] "\'union" | 1577 | [email protected] "'union" |
1578 | [email protected] ">" | 1578 | [email protected] ">" |
1579 | [email protected] " " | 1579 | [email protected] " " |
1580 | [email protected] | 1580 | [email protected] |
@@ -1588,7 +1588,7 @@ [email protected] | |||
1588 | [email protected] | 1588 | [email protected] |
1589 | [email protected] "&" | 1589 | [email protected] "&" |
1590 | [email protected] | 1590 | [email protected] |
1591 | [email protected] "\'union" | 1591 | [email protected] "'union" |
1592 | [email protected] " " | 1592 | [email protected] " " |
1593 | [email protected] | 1593 | [email protected] |
1594 | [email protected] | 1594 | [email protected] |
@@ -1599,7 +1599,7 @@ [email protected] | |||
1599 | [email protected] "<" | 1599 | [email protected] "<" |
1600 | [email protected] | 1600 | [email protected] |
1601 | [email protected] | 1601 | [email protected] |
1602 | [email protected] "\'union" | 1602 | [email protected] "'union" |
1603 | [email protected] ">" | 1603 | [email protected] ">" |
1604 | [email protected] "," | 1604 | [email protected] "," |
1605 | [email protected] " " | 1605 | [email protected] " " |
@@ -1681,7 +1681,7 @@ [email protected] | |||
1681 | [email protected] "\"\\\\\"" | 1681 | [email protected] "\"\\\\\"" |
1682 | [email protected] "," | 1682 | [email protected] "," |
1683 | [email protected] | 1683 | [email protected] |
1684 | [email protected] "\'🤔\'" | 1684 | [email protected] "'🤔'" |
1685 | [email protected] ")" | 1685 | [email protected] ")" |
1686 | [email protected] "/**/" | 1686 | [email protected] "/**/" |
1687 | [email protected] "," | 1687 | [email protected] "," |
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast index f935a0df5..a7f0f7bc6 100644 --- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast | |||
@@ -181,7 +181,7 @@ [email protected] | |||
181 | [email protected] "<" | 181 | [email protected] "<" |
182 | [email protected] | 182 | [email protected] |
183 | [email protected] | 183 | [email protected] |
184 | [email protected] "\'a" | 184 | [email protected] "'a" |
185 | [email protected] ">" | 185 | [email protected] ">" |
186 | [email protected] ")" | 186 | [email protected] ")" |
187 | [email protected] ">" | 187 | [email protected] ">" |
@@ -359,7 +359,7 @@ [email protected] | |||
359 | [email protected] "<" | 359 | [email protected] "<" |
360 | [email protected] | 360 | [email protected] |
361 | [email protected] | 361 | [email protected] |
362 | [email protected] "\'a" | 362 | [email protected] "'a" |
363 | [email protected] ">" | 363 | [email protected] ">" |
364 | [email protected] | 364 | [email protected] |
365 | [email protected] "(" | 365 | [email protected] "(" |
@@ -394,7 +394,7 @@ [email protected] | |||
394 | [email protected] "<" | 394 | [email protected] "<" |
395 | [email protected] | 395 | [email protected] |
396 | [email protected] | 396 | [email protected] |
397 | [email protected] "\'a" | 397 | [email protected] "'a" |
398 | [email protected] ">" | 398 | [email protected] ">" |
399 | [email protected] | 399 | [email protected] |
400 | [email protected] "(" | 400 | [email protected] "(" |
@@ -411,7 +411,7 @@ [email protected] | |||
411 | [email protected] " " | 411 | [email protected] " " |
412 | [email protected] "&" | 412 | [email protected] "&" |
413 | [email protected] | 413 | [email protected] |
414 | [email protected] "\'a" | 414 | [email protected] "'a" |
415 | [email protected] " " | 415 | [email protected] " " |
416 | [email protected] | 416 | [email protected] |
417 | [email protected] "self" | 417 | [email protected] "self" |
@@ -430,7 +430,7 @@ [email protected] | |||
430 | [email protected] "<" | 430 | [email protected] "<" |
431 | [email protected] | 431 | [email protected] |
432 | [email protected] | 432 | [email protected] |
433 | [email protected] "\'a" | 433 | [email protected] "'a" |
434 | [email protected] ">" | 434 | [email protected] ">" |
435 | [email protected] | 435 | [email protected] |
436 | [email protected] "(" | 436 | [email protected] "(" |
@@ -447,7 +447,7 @@ [email protected] | |||
447 | [email protected] " " | 447 | [email protected] " " |
448 | [email protected] "&" | 448 | [email protected] "&" |
449 | [email protected] | 449 | [email protected] |
450 | [email protected] "\'a" | 450 | [email protected] "'a" |
451 | [email protected] " " | 451 | [email protected] " " |
452 | [email protected] "mut" | 452 | [email protected] "mut" |
453 | [email protected] " " | 453 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast b/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast index 325e9e655..79e2b2867 100644 --- a/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast +++ b/crates/syntax/test_data/parser/ok/0067_where_for_pred.rast | |||
@@ -23,7 +23,7 @@ [email protected] | |||
23 | [email protected] "<" | 23 | [email protected] "<" |
24 | [email protected] | 24 | [email protected] |
25 | [email protected] | 25 | [email protected] |
26 | [email protected] "\'a" | 26 | [email protected] "'a" |
27 | [email protected] ">" | 27 | [email protected] ">" |
28 | [email protected] " " | 28 | [email protected] " " |
29 | [email protected] | 29 | [email protected] |
@@ -46,7 +46,7 @@ [email protected] | |||
46 | [email protected] | 46 | [email protected] |
47 | [email protected] "&" | 47 | [email protected] "&" |
48 | [email protected] | 48 | [email protected] |
49 | [email protected] "\'a" | 49 | [email protected] "'a" |
50 | [email protected] " " | 50 | [email protected] " " |
51 | [email protected] | 51 | [email protected] |
52 | [email protected] | 52 | [email protected] |
@@ -85,13 +85,13 @@ [email protected] | |||
85 | [email protected] "<" | 85 | [email protected] "<" |
86 | [email protected] | 86 | [email protected] |
87 | [email protected] | 87 | [email protected] |
88 | [email protected] "\'a" | 88 | [email protected] "'a" |
89 | [email protected] ">" | 89 | [email protected] ">" |
90 | [email protected] " " | 90 | [email protected] " " |
91 | [email protected] | 91 | [email protected] |
92 | [email protected] "&" | 92 | [email protected] "&" |
93 | [email protected] | 93 | [email protected] |
94 | [email protected] "\'a" | 94 | [email protected] "'a" |
95 | [email protected] " " | 95 | [email protected] " " |
96 | [email protected] | 96 | [email protected] |
97 | [email protected] | 97 | [email protected] |
@@ -138,7 +138,7 @@ [email protected] | |||
138 | [email protected] "<" | 138 | [email protected] "<" |
139 | [email protected] | 139 | [email protected] |
140 | [email protected] | 140 | [email protected] |
141 | [email protected] "\'a" | 141 | [email protected] "'a" |
142 | [email protected] ">" | 142 | [email protected] ">" |
143 | [email protected] " " | 143 | [email protected] " " |
144 | [email protected] | 144 | [email protected] |
@@ -146,7 +146,7 @@ [email protected] | |||
146 | [email protected] | 146 | [email protected] |
147 | [email protected] "&" | 147 | [email protected] "&" |
148 | [email protected] | 148 | [email protected] |
149 | [email protected] "\'a" | 149 | [email protected] "'a" |
150 | [email protected] " " | 150 | [email protected] " " |
151 | [email protected] | 151 | [email protected] |
152 | [email protected] | 152 | [email protected] |
@@ -169,7 +169,7 @@ [email protected] | |||
169 | [email protected] | 169 | [email protected] |
170 | [email protected] "&" | 170 | [email protected] "&" |
171 | [email protected] | 171 | [email protected] |
172 | [email protected] "\'a" | 172 | [email protected] "'a" |
173 | [email protected] " " | 173 | [email protected] " " |
174 | [email protected] | 174 | [email protected] |
175 | [email protected] | 175 | [email protected] |
@@ -208,7 +208,7 @@ [email protected] | |||
208 | [email protected] "<" | 208 | [email protected] "<" |
209 | [email protected] | 209 | [email protected] |
210 | [email protected] | 210 | [email protected] |
211 | [email protected] "\'a" | 211 | [email protected] "'a" |
212 | [email protected] ">" | 212 | [email protected] ">" |
213 | [email protected] " " | 213 | [email protected] " " |
214 | [email protected] | 214 | [email protected] |
@@ -216,7 +216,7 @@ [email protected] | |||
216 | [email protected] | 216 | [email protected] |
217 | [email protected] "&" | 217 | [email protected] "&" |
218 | [email protected] | 218 | [email protected] |
219 | [email protected] "\'a" | 219 | [email protected] "'a" |
220 | [email protected] " " | 220 | [email protected] " " |
221 | [email protected] | 221 | [email protected] |
222 | [email protected] | 222 | [email protected] |
@@ -277,7 +277,7 @@ [email protected] | |||
277 | [email protected] "<" | 277 | [email protected] "<" |
278 | [email protected] | 278 | [email protected] |
279 | [email protected] | 279 | [email protected] |
280 | [email protected] "\'a" | 280 | [email protected] "'a" |
281 | [email protected] ">" | 281 | [email protected] ">" |
282 | [email protected] " " | 282 | [email protected] " " |
283 | [email protected] | 283 | [email protected] |
@@ -288,7 +288,7 @@ [email protected] | |||
288 | [email protected] | 288 | [email protected] |
289 | [email protected] "&" | 289 | [email protected] "&" |
290 | [email protected] | 290 | [email protected] |
291 | [email protected] "\'a" | 291 | [email protected] "'a" |
292 | [email protected] " " | 292 | [email protected] " " |
293 | [email protected] | 293 | [email protected] |
294 | [email protected] | 294 | [email protected] |
@@ -348,7 +348,7 @@ [email protected] | |||
348 | [email protected] "<" | 348 | [email protected] "<" |
349 | [email protected] | 349 | [email protected] |
350 | [email protected] | 350 | [email protected] |
351 | [email protected] "\'a" | 351 | [email protected] "'a" |
352 | [email protected] ">" | 352 | [email protected] ">" |
353 | [email protected] " " | 353 | [email protected] " " |
354 | [email protected] | 354 | [email protected] |
@@ -357,7 +357,7 @@ [email protected] | |||
357 | [email protected] "<" | 357 | [email protected] "<" |
358 | [email protected] | 358 | [email protected] |
359 | [email protected] | 359 | [email protected] |
360 | [email protected] "\'b" | 360 | [email protected] "'b" |
361 | [email protected] ">" | 361 | [email protected] ">" |
362 | [email protected] " " | 362 | [email protected] " " |
363 | [email protected] | 363 | [email protected] |
@@ -368,7 +368,7 @@ [email protected] | |||
368 | [email protected] | 368 | [email protected] |
369 | [email protected] "&" | 369 | [email protected] "&" |
370 | [email protected] | 370 | [email protected] |
371 | [email protected] "\'a" | 371 | [email protected] "'a" |
372 | [email protected] " " | 372 | [email protected] " " |
373 | [email protected] | 373 | [email protected] |
374 | [email protected] | 374 | [email protected] |
@@ -381,7 +381,7 @@ [email protected] | |||
381 | [email protected] | 381 | [email protected] |
382 | [email protected] "&" | 382 | [email protected] "&" |
383 | [email protected] | 383 | [email protected] |
384 | [email protected] "\'b" | 384 | [email protected] "'b" |
385 | [email protected] " " | 385 | [email protected] " " |
386 | [email protected] | 386 | [email protected] |
387 | [email protected] | 387 | [email protected] |
diff --git a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast index 8d3e187ae..026c776e2 100644 --- a/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast +++ b/crates/syntax/test_data/parser/ok/0069_multi_trait_object.rast | |||
@@ -8,7 +8,7 @@ [email protected] | |||
8 | [email protected] "<" | 8 | [email protected] "<" |
9 | [email protected] | 9 | [email protected] |
10 | [email protected] | 10 | [email protected] |
11 | [email protected] "\'a" | 11 | [email protected] "'a" |
12 | [email protected] ">" | 12 | [email protected] ">" |
13 | [email protected] " " | 13 | [email protected] " " |
14 | [email protected] "=" | 14 | [email protected] "=" |
@@ -16,7 +16,7 @@ [email protected] | |||
16 | [email protected] | 16 | [email protected] |
17 | [email protected] "&" | 17 | [email protected] "&" |
18 | [email protected] | 18 | [email protected] |
19 | [email protected] "\'a" | 19 | [email protected] "'a" |
20 | [email protected] " " | 20 | [email protected] " " |
21 | [email protected] | 21 | [email protected] |
22 | [email protected] "(" | 22 | [email protected] "(" |
@@ -112,7 +112,7 @@ [email protected] | |||
112 | [email protected] " " | 112 | [email protected] " " |
113 | [email protected] | 113 | [email protected] |
114 | [email protected] | 114 | [email protected] |
115 | [email protected] "\'static" | 115 | [email protected] "'static" |
116 | [email protected] ")" | 116 | [email protected] ")" |
117 | [email protected] ";" | 117 | [email protected] ";" |
118 | [email protected] "\n" | 118 | [email protected] "\n" |
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index d0bddf7d8..44656267f 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs | |||
@@ -77,6 +77,11 @@ pub struct Fixture { | |||
77 | pub introduce_new_source_root: bool, | 77 | pub introduce_new_source_root: bool, |
78 | } | 78 | } |
79 | 79 | ||
80 | pub struct MiniCore { | ||
81 | activated_flags: Vec<String>, | ||
82 | valid_flags: Vec<String>, | ||
83 | } | ||
84 | |||
80 | impl Fixture { | 85 | impl Fixture { |
81 | /// Parses text which looks like this: | 86 | /// Parses text which looks like this: |
82 | /// | 87 | /// |
@@ -86,12 +91,28 @@ impl Fixture { | |||
86 | /// line 2 | 91 | /// line 2 |
87 | /// //- other meta | 92 | /// //- other meta |
88 | /// ``` | 93 | /// ``` |
89 | pub fn parse(ra_fixture: &str) -> Vec<Fixture> { | 94 | /// |
95 | /// Fixture can also start with a minicore declaration: | ||
96 | /// | ||
97 | /// ``` | ||
98 | /// //- minicore: sized | ||
99 | /// ``` | ||
100 | /// | ||
101 | /// That will include a subset of `libcore` into the fixture, see | ||
102 | /// `minicore.rs` for what's available. | ||
103 | pub fn parse(ra_fixture: &str) -> (Option<MiniCore>, Vec<Fixture>) { | ||
90 | let fixture = trim_indent(ra_fixture); | 104 | let fixture = trim_indent(ra_fixture); |
91 | 105 | let mut fixture = fixture.as_str(); | |
106 | let mut mini_core = None; | ||
92 | let mut res: Vec<Fixture> = Vec::new(); | 107 | let mut res: Vec<Fixture> = Vec::new(); |
93 | 108 | ||
94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; | 109 | if fixture.starts_with("//- minicore:") { |
110 | let first_line = fixture.split_inclusive('\n').next().unwrap(); | ||
111 | mini_core = Some(MiniCore::parse(first_line)); | ||
112 | fixture = &fixture[first_line.len()..]; | ||
113 | } | ||
114 | |||
115 | let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") }; | ||
95 | 116 | ||
96 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { | 117 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { |
97 | if line.contains("//-") { | 118 | if line.contains("//-") { |
@@ -108,12 +129,22 @@ impl Fixture { | |||
108 | if line.starts_with("//-") { | 129 | if line.starts_with("//-") { |
109 | let meta = Fixture::parse_meta_line(line); | 130 | let meta = Fixture::parse_meta_line(line); |
110 | res.push(meta) | 131 | res.push(meta) |
111 | } else if let Some(entry) = res.last_mut() { | 132 | } else { |
112 | entry.text.push_str(line); | 133 | if line.starts_with("// ") |
134 | && line.contains(':') | ||
135 | && !line.contains("::") | ||
136 | && line.chars().all(|it| !it.is_uppercase()) | ||
137 | { | ||
138 | panic!("looks like invalid metadata line: {:?}", line) | ||
139 | } | ||
140 | |||
141 | if let Some(entry) = res.last_mut() { | ||
142 | entry.text.push_str(line); | ||
143 | } | ||
113 | } | 144 | } |
114 | } | 145 | } |
115 | 146 | ||
116 | res | 147 | (mini_core, res) |
117 | } | 148 | } |
118 | 149 | ||
119 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo | 150 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo |
@@ -123,7 +154,7 @@ impl Fixture { | |||
123 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 154 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); |
124 | 155 | ||
125 | let path = components[0].to_string(); | 156 | let path = components[0].to_string(); |
126 | assert!(path.starts_with('/')); | 157 | assert!(path.starts_with('/'), "fixture path does not start with `/`: {:?}", path); |
127 | 158 | ||
128 | let mut krate = None; | 159 | let mut krate = None; |
129 | let mut deps = Vec::new(); | 160 | let mut deps = Vec::new(); |
@@ -133,7 +164,9 @@ impl Fixture { | |||
133 | let mut env = FxHashMap::default(); | 164 | let mut env = FxHashMap::default(); |
134 | let mut introduce_new_source_root = false; | 165 | let mut introduce_new_source_root = false; |
135 | for component in components[1..].iter() { | 166 | for component in components[1..].iter() { |
136 | let (key, value) = component.split_once(':').unwrap(); | 167 | let (key, value) = component |
168 | .split_once(':') | ||
169 | .unwrap_or_else(|| panic!("invalid meta line: {:?}", meta)); | ||
137 | match key { | 170 | match key { |
138 | "crate" => krate = Some(value.to_string()), | 171 | "crate" => krate = Some(value.to_string()), |
139 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | 172 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), |
@@ -172,6 +205,139 @@ impl Fixture { | |||
172 | } | 205 | } |
173 | } | 206 | } |
174 | 207 | ||
208 | impl MiniCore { | ||
209 | fn has_flag(&self, flag: &str) -> bool { | ||
210 | self.activated_flags.iter().any(|it| it == flag) | ||
211 | } | ||
212 | |||
213 | #[track_caller] | ||
214 | fn assert_valid_flag(&self, flag: &str) { | ||
215 | if !self.valid_flags.iter().any(|it| it == flag) { | ||
216 | panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | fn parse(line: &str) -> MiniCore { | ||
221 | let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() }; | ||
222 | |||
223 | let line = line.strip_prefix("//- minicore:").unwrap().trim(); | ||
224 | for entry in line.split(", ") { | ||
225 | if res.has_flag(entry) { | ||
226 | panic!("duplicate minicore flag: {:?}", entry) | ||
227 | } | ||
228 | res.activated_flags.push(entry.to_string()) | ||
229 | } | ||
230 | |||
231 | res | ||
232 | } | ||
233 | |||
234 | /// Strips parts of minicore.rs which are flagged by inactive flags. | ||
235 | /// | ||
236 | /// This is probably over-engineered to support flags dependencies. | ||
237 | pub fn source_code(mut self) -> String { | ||
238 | let mut buf = String::new(); | ||
239 | let raw_mini_core = include_str!("./minicore.rs"); | ||
240 | let mut lines = raw_mini_core.split_inclusive('\n'); | ||
241 | |||
242 | let mut parsing_flags = false; | ||
243 | let mut implications = Vec::new(); | ||
244 | |||
245 | // Parse `//!` preamble and extract flags and dependencies. | ||
246 | for line in lines.by_ref() { | ||
247 | let line = match line.strip_prefix("//!") { | ||
248 | Some(it) => it, | ||
249 | None => { | ||
250 | assert!(line.trim().is_empty()); | ||
251 | break; | ||
252 | } | ||
253 | }; | ||
254 | |||
255 | if parsing_flags { | ||
256 | let (flag, deps) = line.split_once(':').unwrap(); | ||
257 | let flag = flag.trim(); | ||
258 | self.valid_flags.push(flag.to_string()); | ||
259 | for dep in deps.split(", ") { | ||
260 | let dep = dep.trim(); | ||
261 | if !dep.is_empty() { | ||
262 | self.assert_valid_flag(dep); | ||
263 | implications.push((flag, dep)); | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if line.contains("Available flags:") { | ||
269 | parsing_flags = true; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | for flag in &self.activated_flags { | ||
274 | self.assert_valid_flag(flag); | ||
275 | } | ||
276 | |||
277 | // Fixed point loop to compute transitive closure of flags. | ||
278 | loop { | ||
279 | let mut changed = false; | ||
280 | for &(u, v) in implications.iter() { | ||
281 | if self.has_flag(u) && !self.has_flag(v) { | ||
282 | self.activated_flags.push(v.to_string()); | ||
283 | changed = true; | ||
284 | } | ||
285 | } | ||
286 | if !changed { | ||
287 | break; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | let mut active_regions = Vec::new(); | ||
292 | let mut seen_regions = Vec::new(); | ||
293 | for line in lines { | ||
294 | let trimmed = line.trim(); | ||
295 | if let Some(region) = trimmed.strip_prefix("// region:") { | ||
296 | active_regions.push(region); | ||
297 | continue; | ||
298 | } | ||
299 | if let Some(region) = trimmed.strip_prefix("// endregion:") { | ||
300 | let prev = active_regions.pop().unwrap(); | ||
301 | assert_eq!(prev, region); | ||
302 | continue; | ||
303 | } | ||
304 | |||
305 | let mut line_region = false; | ||
306 | if let Some(idx) = trimmed.find("// :") { | ||
307 | line_region = true; | ||
308 | active_regions.push(&trimmed[idx + "// :".len()..]); | ||
309 | } | ||
310 | |||
311 | let mut keep = true; | ||
312 | for ®ion in &active_regions { | ||
313 | assert!( | ||
314 | !region.starts_with(' '), | ||
315 | "region marker starts with a space: {:?}", | ||
316 | region | ||
317 | ); | ||
318 | self.assert_valid_flag(region); | ||
319 | seen_regions.push(region); | ||
320 | keep &= self.has_flag(region); | ||
321 | } | ||
322 | |||
323 | if keep { | ||
324 | buf.push_str(line) | ||
325 | } | ||
326 | if line_region { | ||
327 | active_regions.pop().unwrap(); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | for flag in &self.valid_flags { | ||
332 | if !seen_regions.iter().any(|it| it == flag) { | ||
333 | panic!("unused minicore flag: {:?}", flag); | ||
334 | } | ||
335 | } | ||
336 | format!("{}", buf); | ||
337 | buf | ||
338 | } | ||
339 | } | ||
340 | |||
175 | #[test] | 341 | #[test] |
176 | #[should_panic] | 342 | #[should_panic] |
177 | fn parse_fixture_checks_further_indented_metadata() { | 343 | fn parse_fixture_checks_further_indented_metadata() { |
@@ -189,12 +355,14 @@ fn parse_fixture_checks_further_indented_metadata() { | |||
189 | 355 | ||
190 | #[test] | 356 | #[test] |
191 | fn parse_fixture_gets_full_meta() { | 357 | fn parse_fixture_gets_full_meta() { |
192 | let parsed = Fixture::parse( | 358 | let (mini_core, parsed) = Fixture::parse( |
193 | r" | 359 | r#" |
194 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo | 360 | //- minicore: coerce_unsized |
195 | mod m; | 361 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo |
196 | ", | 362 | mod m; |
363 | "#, | ||
197 | ); | 364 | ); |
365 | assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]); | ||
198 | assert_eq!(1, parsed.len()); | 366 | assert_eq!(1, parsed.len()); |
199 | 367 | ||
200 | let meta = &parsed[0]; | 368 | let meta = &parsed[0]; |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index b2fe25f82..d9c22c180 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -11,6 +11,7 @@ mod fixture; | |||
11 | mod assert_linear; | 11 | mod assert_linear; |
12 | 12 | ||
13 | use std::{ | 13 | use std::{ |
14 | collections::BTreeMap, | ||
14 | convert::{TryFrom, TryInto}, | 15 | convert::{TryFrom, TryInto}, |
15 | env, fs, | 16 | env, fs, |
16 | path::{Path, PathBuf}, | 17 | path::{Path, PathBuf}, |
@@ -23,7 +24,10 @@ use text_size::{TextRange, TextSize}; | |||
23 | pub use dissimilar::diff as __diff; | 24 | pub use dissimilar::diff as __diff; |
24 | pub use rustc_hash::FxHashMap; | 25 | pub use rustc_hash::FxHashMap; |
25 | 26 | ||
26 | pub use crate::{assert_linear::AssertLinear, fixture::Fixture}; | 27 | pub use crate::{ |
28 | assert_linear::AssertLinear, | ||
29 | fixture::{Fixture, MiniCore}, | ||
30 | }; | ||
27 | 31 | ||
28 | pub const CURSOR_MARKER: &str = "$0"; | 32 | pub const CURSOR_MARKER: &str = "$0"; |
29 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; | 33 | pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; |
@@ -202,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String { | |||
202 | /// | 206 | /// |
203 | /// // ^^^ first line | 207 | /// // ^^^ first line |
204 | /// // | second line | 208 | /// // | second line |
209 | /// | ||
210 | /// Annotations point to the last line that actually was long enough for the | ||
211 | /// range, not counting annotations themselves. So overlapping annotations are | ||
212 | /// possible: | ||
213 | /// ```no_run | ||
214 | /// // stuff other stuff | ||
215 | /// // ^^ 'st' | ||
216 | /// // ^^^^^ 'stuff' | ||
217 | /// // ^^^^^^^^^^^ 'other stuff' | ||
218 | /// ``` | ||
205 | pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | 219 | pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { |
206 | let mut res = Vec::new(); | 220 | let mut res = Vec::new(); |
207 | let mut prev_line_start: Option<TextSize> = Some(0.into()); | 221 | // map from line length to beginning of last line that had that length |
222 | let mut line_start_map = BTreeMap::new(); | ||
208 | let mut line_start: TextSize = 0.into(); | 223 | let mut line_start: TextSize = 0.into(); |
209 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); | 224 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); |
210 | for line in text.split_inclusive('\n') { | 225 | for line in text.split_inclusive('\n') { |
211 | let mut this_line_annotations = Vec::new(); | 226 | let mut this_line_annotations = Vec::new(); |
212 | if let Some(idx) = line.find("//") { | 227 | let line_length = if let Some(idx) = line.find("//") { |
213 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); | 228 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); |
214 | for annotation in extract_line_annotations(&line[idx + "//".len()..]) { | 229 | for annotation in extract_line_annotations(&line[idx + "//".len()..]) { |
215 | match annotation { | 230 | match annotation { |
@@ -219,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
219 | let range = if file { | 234 | let range = if file { |
220 | TextRange::up_to(TextSize::of(text)) | 235 | TextRange::up_to(TextSize::of(text)) |
221 | } else { | 236 | } else { |
222 | range + prev_line_start.unwrap() | 237 | let line_start = line_start_map.range(range.end()..).next().unwrap(); |
238 | |||
239 | range + line_start.1 | ||
223 | }; | 240 | }; |
224 | res.push((range, content)) | 241 | res.push((range, content)) |
225 | } | 242 | } |
@@ -235,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
235 | } | 252 | } |
236 | } | 253 | } |
237 | } | 254 | } |
238 | } | 255 | idx.try_into().unwrap() |
256 | } else { | ||
257 | TextSize::of(line) | ||
258 | }; | ||
259 | |||
260 | line_start_map = line_start_map.split_off(&line_length); | ||
261 | line_start_map.insert(line_length, line_start); | ||
239 | 262 | ||
240 | prev_line_start = Some(line_start); | ||
241 | line_start += TextSize::of(line); | 263 | line_start += TextSize::of(line); |
242 | 264 | ||
243 | prev_line_annotations = this_line_annotations; | 265 | prev_line_annotations = this_line_annotations; |
@@ -293,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> { | |||
293 | } | 315 | } |
294 | 316 | ||
295 | #[test] | 317 | #[test] |
296 | fn test_extract_annotations() { | 318 | fn test_extract_annotations_1() { |
297 | let text = stdx::trim_indent( | 319 | let text = stdx::trim_indent( |
298 | r#" | 320 | r#" |
299 | fn main() { | 321 | fn main() { |
@@ -318,6 +340,25 @@ fn main() { | |||
318 | assert_eq!(res[3].0.len(), 115); | 340 | assert_eq!(res[3].0.len(), 115); |
319 | } | 341 | } |
320 | 342 | ||
343 | #[test] | ||
344 | fn test_extract_annotations_2() { | ||
345 | let text = stdx::trim_indent( | ||
346 | r#" | ||
347 | fn main() { | ||
348 | (x, y); | ||
349 | //^ a | ||
350 | // ^ b | ||
351 | //^^^^^^^^ c | ||
352 | }"#, | ||
353 | ); | ||
354 | let res = extract_annotations(&text) | ||
355 | .into_iter() | ||
356 | .map(|(range, ann)| (&text[range], ann)) | ||
357 | .collect::<Vec<_>>(); | ||
358 | |||
359 | assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]); | ||
360 | } | ||
361 | |||
321 | /// Returns `false` if slow tests should not run, otherwise returns `true` and | 362 | /// Returns `false` if slow tests should not run, otherwise returns `true` and |
322 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag | 363 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag |
323 | /// that slow tests did run. | 364 | /// that slow tests did run. |
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs new file mode 100644 index 000000000..ce6ad8541 --- /dev/null +++ b/crates/test_utils/src/minicore.rs | |||
@@ -0,0 +1,549 @@ | |||
1 | //! This is a fixture we use for tests that need lang items. | ||
2 | //! | ||
3 | //! We want to include the minimal subset of core for each test, so this file | ||
4 | //! supports "conditional compilation". Tests use the following syntax to include minicore: | ||
5 | //! | ||
6 | //! //- minicore: flag1, flag2 | ||
7 | //! | ||
8 | //! We then strip all the code marked with other flags. | ||
9 | //! | ||
10 | //! Available flags: | ||
11 | //! sized: | ||
12 | //! unsize: sized | ||
13 | //! coerce_unsized: unsize | ||
14 | //! slice: | ||
15 | //! range: | ||
16 | //! deref: sized | ||
17 | //! deref_mut: deref | ||
18 | //! index: sized | ||
19 | //! fn: | ||
20 | //! pin: | ||
21 | //! future: pin | ||
22 | //! option: | ||
23 | //! result: | ||
24 | //! iterator: option | ||
25 | //! iterators: iterator, fn | ||
26 | //! default: sized | ||
27 | //! clone: sized | ||
28 | //! copy: clone | ||
29 | //! from: sized | ||
30 | //! eq: sized | ||
31 | //! ord: eq, option | ||
32 | //! derive: | ||
33 | |||
34 | pub mod marker { | ||
35 | // region:sized | ||
36 | #[lang = "sized"] | ||
37 | #[fundamental] | ||
38 | #[rustc_specialization_trait] | ||
39 | pub trait Sized {} | ||
40 | // endregion:sized | ||
41 | |||
42 | // region:unsize | ||
43 | #[lang = "unsize"] | ||
44 | pub trait Unsize<T: ?Sized> {} | ||
45 | // endregion:unsize | ||
46 | |||
47 | // region:copy | ||
48 | #[lang = "copy"] | ||
49 | pub trait Copy: Clone {} | ||
50 | // region:derive | ||
51 | #[rustc_builtin_macro] | ||
52 | pub macro Copy($item:item) {} | ||
53 | // endregion:derive | ||
54 | |||
55 | mod copy_impls { | ||
56 | use super::Copy; | ||
57 | |||
58 | macro_rules! impl_copy { | ||
59 | ($($t:ty)*) => { | ||
60 | $( | ||
61 | impl Copy for $t {} | ||
62 | )* | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl_copy! { | ||
67 | usize u8 u16 u32 u64 u128 | ||
68 | isize i8 i16 i32 i64 i128 | ||
69 | f32 f64 | ||
70 | bool char | ||
71 | } | ||
72 | |||
73 | impl<T: ?Sized> Copy for *const T {} | ||
74 | impl<T: ?Sized> Copy for *mut T {} | ||
75 | impl<T: ?Sized> Copy for &T {} | ||
76 | } | ||
77 | // endregion:copy | ||
78 | } | ||
79 | |||
80 | // region:default | ||
81 | pub mod default { | ||
82 | pub trait Default: Sized { | ||
83 | fn default() -> Self; | ||
84 | } | ||
85 | } | ||
86 | // endregion:default | ||
87 | |||
88 | // region:clone | ||
89 | pub mod clone { | ||
90 | #[lang = "clone"] | ||
91 | pub trait Clone: Sized { | ||
92 | fn clone(&self) -> Self; | ||
93 | } | ||
94 | // region:derive | ||
95 | #[rustc_builtin_macro] | ||
96 | pub macro Clone($item:item) {} | ||
97 | // endregion:derive | ||
98 | } | ||
99 | // endregion:clone | ||
100 | |||
101 | // region:from | ||
102 | pub mod convert { | ||
103 | pub trait From<T>: Sized { | ||
104 | fn from(_: T) -> Self; | ||
105 | } | ||
106 | pub trait Into<T>: Sized { | ||
107 | fn into(self) -> T; | ||
108 | } | ||
109 | |||
110 | impl<T, U> Into<U> for T | ||
111 | where | ||
112 | U: From<T>, | ||
113 | { | ||
114 | fn into(self) -> U { | ||
115 | U::from(self) | ||
116 | } | ||
117 | } | ||
118 | |||
119 | impl<T> From<T> for T { | ||
120 | fn from(t: T) -> T { | ||
121 | t | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | // endregion:from | ||
126 | |||
127 | pub mod ops { | ||
128 | // region:coerce_unsized | ||
129 | mod unsize { | ||
130 | use crate::marker::Unsize; | ||
131 | |||
132 | #[lang = "coerce_unsized"] | ||
133 | pub trait CoerceUnsized<T: ?Sized> {} | ||
134 | |||
135 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} | ||
136 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} | ||
137 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} | ||
138 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} | ||
139 | |||
140 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
141 | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {} | ||
142 | |||
143 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
144 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} | ||
145 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} | ||
146 | } | ||
147 | pub use self::unsize::CoerceUnsized; | ||
148 | // endregion:coerce_unsized | ||
149 | |||
150 | // region:deref | ||
151 | mod deref { | ||
152 | #[lang = "deref"] | ||
153 | pub trait Deref { | ||
154 | #[lang = "deref_target"] | ||
155 | type Target: ?Sized; | ||
156 | fn deref(&self) -> &Self::Target; | ||
157 | } | ||
158 | // region:deref_mut | ||
159 | #[lang = "deref_mut"] | ||
160 | pub trait DerefMut: Deref { | ||
161 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
162 | } | ||
163 | // endregion:deref_mut | ||
164 | } | ||
165 | pub use self::deref::{ | ||
166 | Deref, | ||
167 | DerefMut, // :deref_mut | ||
168 | }; | ||
169 | // endregion:deref | ||
170 | |||
171 | // region:index | ||
172 | mod index { | ||
173 | #[lang = "index"] | ||
174 | pub trait Index<Idx: ?Sized> { | ||
175 | type Output: ?Sized; | ||
176 | fn index(&self, index: Idx) -> &Self::Output; | ||
177 | } | ||
178 | #[lang = "index_mut"] | ||
179 | pub trait IndexMut<Idx: ?Sized>: Index<Idx> { | ||
180 | fn index_mut(&mut self, index: Idx) -> &mut Self::Output; | ||
181 | } | ||
182 | |||
183 | // region:slice | ||
184 | impl<T, I> Index<I> for [T] | ||
185 | where | ||
186 | I: SliceIndex<[T]>, | ||
187 | { | ||
188 | type Output = I::Output; | ||
189 | fn index(&self, index: I) -> &I::Output { | ||
190 | loop {} | ||
191 | } | ||
192 | } | ||
193 | impl<T, I> IndexMut<I> for [T] | ||
194 | where | ||
195 | I: SliceIndex<[T]>, | ||
196 | { | ||
197 | fn index_mut(&mut self, index: I) -> &mut I::Output { | ||
198 | loop {} | ||
199 | } | ||
200 | } | ||
201 | |||
202 | pub unsafe trait SliceIndex<T: ?Sized> { | ||
203 | type Output: ?Sized; | ||
204 | } | ||
205 | unsafe impl<T> SliceIndex<[T]> for usize { | ||
206 | type Output = T; | ||
207 | } | ||
208 | // endregion:slice | ||
209 | } | ||
210 | pub use self::index::{Index, IndexMut}; | ||
211 | // endregion:index | ||
212 | |||
213 | // region:range | ||
214 | mod range { | ||
215 | #[lang = "RangeFull"] | ||
216 | pub struct RangeFull; | ||
217 | |||
218 | #[lang = "Range"] | ||
219 | pub struct Range<Idx> { | ||
220 | pub start: Idx, | ||
221 | pub end: Idx, | ||
222 | } | ||
223 | |||
224 | #[lang = "RangeFrom"] | ||
225 | pub struct RangeFrom<Idx> { | ||
226 | pub start: Idx, | ||
227 | } | ||
228 | |||
229 | #[lang = "RangeTo"] | ||
230 | pub struct RangeTo<Idx> { | ||
231 | pub end: Idx, | ||
232 | } | ||
233 | |||
234 | #[lang = "RangeInclusive"] | ||
235 | pub struct RangeInclusive<Idx> { | ||
236 | pub(crate) start: Idx, | ||
237 | pub(crate) end: Idx, | ||
238 | pub(crate) exhausted: bool, | ||
239 | } | ||
240 | |||
241 | #[lang = "RangeToInclusive"] | ||
242 | pub struct RangeToInclusive<Idx> { | ||
243 | pub end: Idx, | ||
244 | } | ||
245 | } | ||
246 | pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; | ||
247 | pub use self::range::{RangeInclusive, RangeToInclusive}; | ||
248 | // endregion:range | ||
249 | |||
250 | // region:fn | ||
251 | mod function { | ||
252 | #[lang = "fn"] | ||
253 | #[fundamental] | ||
254 | pub trait Fn<Args>: FnMut<Args> {} | ||
255 | |||
256 | #[lang = "fn_mut"] | ||
257 | #[fundamental] | ||
258 | pub trait FnMut<Args>: FnOnce<Args> {} | ||
259 | |||
260 | #[lang = "fn_once"] | ||
261 | #[fundamental] | ||
262 | pub trait FnOnce<Args> { | ||
263 | #[lang = "fn_once_output"] | ||
264 | type Output; | ||
265 | } | ||
266 | } | ||
267 | pub use self::function::{Fn, FnMut, FnOnce}; | ||
268 | // endregion:fn | ||
269 | } | ||
270 | |||
271 | // region:eq | ||
272 | pub mod cmp { | ||
273 | #[lang = "eq"] | ||
274 | pub trait PartialEq<Rhs: ?Sized = Self> { | ||
275 | fn eq(&self, other: &Rhs) -> bool; | ||
276 | } | ||
277 | |||
278 | pub trait Eq: PartialEq<Self> {} | ||
279 | |||
280 | // region:derive | ||
281 | #[rustc_builtin_macro] | ||
282 | pub macro PartialEq($item:item) {} | ||
283 | #[rustc_builtin_macro] | ||
284 | pub macro Eq($item:item) {} | ||
285 | // endregion:derive | ||
286 | |||
287 | // region:ord | ||
288 | #[lang = "partial_ord"] | ||
289 | pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { | ||
290 | fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; | ||
291 | } | ||
292 | |||
293 | pub trait Ord: Eq + PartialOrd<Self> { | ||
294 | fn cmp(&self, other: &Self) -> Ordering; | ||
295 | } | ||
296 | |||
297 | pub enum Ordering { | ||
298 | Less = -1, | ||
299 | Equal = 0, | ||
300 | Greater = 1, | ||
301 | } | ||
302 | |||
303 | // region:derive | ||
304 | #[rustc_builtin_macro] | ||
305 | pub macro PartialOrd($item:item) {} | ||
306 | #[rustc_builtin_macro] | ||
307 | pub macro Ord($item:item) {} | ||
308 | // endregion:derive | ||
309 | |||
310 | // endregion:ord | ||
311 | } | ||
312 | // endregion:eq | ||
313 | |||
314 | // region:slice | ||
315 | pub mod slice { | ||
316 | #[lang = "slice"] | ||
317 | impl<T> [T] { | ||
318 | pub fn len(&self) -> usize { | ||
319 | loop {} | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | // endregion:slice | ||
324 | |||
325 | // region:option | ||
326 | pub mod option { | ||
327 | pub enum Option<T> { | ||
328 | #[lang = "None"] | ||
329 | None, | ||
330 | #[lang = "Some"] | ||
331 | Some(T), | ||
332 | } | ||
333 | } | ||
334 | // endregion:option | ||
335 | |||
336 | // region:result | ||
337 | pub mod result { | ||
338 | pub enum Result<T, E> { | ||
339 | #[lang = "Ok"] | ||
340 | Ok(T), | ||
341 | #[lang = "Err"] | ||
342 | Err(E), | ||
343 | } | ||
344 | } | ||
345 | // endregion:result | ||
346 | |||
347 | // region:pin | ||
348 | pub mod pin { | ||
349 | #[lang = "pin"] | ||
350 | #[fundamental] | ||
351 | pub struct Pin<P> { | ||
352 | pointer: P, | ||
353 | } | ||
354 | } | ||
355 | // endregion:pin | ||
356 | |||
357 | // region:future | ||
358 | pub mod future { | ||
359 | use crate::{ | ||
360 | pin::Pin, | ||
361 | task::{Context, Poll}, | ||
362 | }; | ||
363 | |||
364 | #[lang = "future_trait"] | ||
365 | pub trait Future { | ||
366 | type Output; | ||
367 | #[lang = "poll"] | ||
368 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; | ||
369 | } | ||
370 | } | ||
371 | pub mod task { | ||
372 | pub enum Poll<T> { | ||
373 | #[lang = "Ready"] | ||
374 | Ready(T), | ||
375 | #[lang = "Pending"] | ||
376 | Pending, | ||
377 | } | ||
378 | |||
379 | pub struct Context<'a> { | ||
380 | waker: &'a (), | ||
381 | } | ||
382 | } | ||
383 | // endregion:future | ||
384 | |||
385 | // region:iterator | ||
386 | pub mod iter { | ||
387 | // region:iterators | ||
388 | mod adapters { | ||
389 | pub struct Take<I> { | ||
390 | iter: I, | ||
391 | n: usize, | ||
392 | } | ||
393 | impl<I> Iterator for Take<I> | ||
394 | where | ||
395 | I: Iterator, | ||
396 | { | ||
397 | type Item = <I as Iterator>::Item; | ||
398 | |||
399 | fn next(&mut self) -> Option<<I as Iterator>::Item> { | ||
400 | loop {} | ||
401 | } | ||
402 | } | ||
403 | |||
404 | pub struct FilterMap<I, F> { | ||
405 | iter: I, | ||
406 | f: F, | ||
407 | } | ||
408 | impl<B, I: Iterator, F> Iterator for FilterMap<I, F> | ||
409 | where | ||
410 | F: FnMut(I::Item) -> Option<B>, | ||
411 | { | ||
412 | type Item = B; | ||
413 | |||
414 | #[inline] | ||
415 | fn next(&mut self) -> Option<B> { | ||
416 | loop {} | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | pub use self::adapters::Take; | ||
421 | |||
422 | mod sources { | ||
423 | mod repeat { | ||
424 | pub fn repeat<T>(elt: T) -> Repeat<T> { | ||
425 | loop {} | ||
426 | } | ||
427 | |||
428 | pub struct Repeat<A> { | ||
429 | element: A, | ||
430 | } | ||
431 | |||
432 | impl<A> Iterator for Repeat<A> { | ||
433 | type Item = A; | ||
434 | |||
435 | fn next(&mut self) -> Option<A> { | ||
436 | loop {} | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | pub use self::repeat::{repeat, Repeat}; | ||
441 | } | ||
442 | pub use self::sources::{repeat, Repeat}; | ||
443 | // endregion:iterators | ||
444 | |||
445 | mod traits { | ||
446 | mod iterator { | ||
447 | use super::super::Take; | ||
448 | |||
449 | pub trait Iterator { | ||
450 | type Item; | ||
451 | #[lang = "next"] | ||
452 | fn next(&mut self) -> Option<Self::Item>; | ||
453 | fn nth(&mut self, n: usize) -> Option<Self::Item> { | ||
454 | loop {} | ||
455 | } | ||
456 | fn by_ref(&mut self) -> &mut Self | ||
457 | where | ||
458 | Self: Sized, | ||
459 | { | ||
460 | self | ||
461 | } | ||
462 | // region:iterators | ||
463 | fn take(self, n: usize) -> crate::iter::Take<Self> { | ||
464 | loop {} | ||
465 | } | ||
466 | fn filter_map<B, F>(self, f: F) -> crate::iter::FilterMap<Self, F> | ||
467 | where | ||
468 | Self: Sized, | ||
469 | F: FnMut(Self::Item) -> Option<B>, | ||
470 | { | ||
471 | loop {} | ||
472 | } | ||
473 | // endregion:iterators | ||
474 | } | ||
475 | impl<I: Iterator + ?Sized> Iterator for &mut I { | ||
476 | type Item = I::Item; | ||
477 | fn next(&mut self) -> Option<I::Item> { | ||
478 | (**self).next() | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | pub use self::iterator::Iterator; | ||
483 | |||
484 | mod collect { | ||
485 | pub trait IntoIterator { | ||
486 | type Item; | ||
487 | type IntoIter: Iterator<Item = Self::Item>; | ||
488 | #[lang = "into_iter"] | ||
489 | fn into_iter(self) -> Self::IntoIter; | ||
490 | } | ||
491 | impl<I: Iterator> IntoIterator for I { | ||
492 | type Item = I::Item; | ||
493 | type IntoIter = I; | ||
494 | fn into_iter(self) -> I { | ||
495 | self | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | pub use self::collect::IntoIterator; | ||
500 | } | ||
501 | pub use self::traits::{IntoIterator, Iterator}; | ||
502 | } | ||
503 | // endregion:iterator | ||
504 | |||
505 | // region:derive | ||
506 | mod macros { | ||
507 | pub(crate) mod builtin { | ||
508 | #[rustc_builtin_macro] | ||
509 | pub macro derive($item:item) { | ||
510 | /* compiler built-in */ | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | // endregion:derive | ||
515 | |||
516 | pub mod prelude { | ||
517 | pub mod v1 { | ||
518 | pub use crate::{ | ||
519 | clone::Clone, // :clone | ||
520 | cmp::{Eq, PartialEq}, // :eq | ||
521 | cmp::{Ord, PartialOrd}, // :ord | ||
522 | convert::{From, Into}, // :from | ||
523 | default::Default, // :default | ||
524 | iter::{IntoIterator, Iterator}, // :iterator | ||
525 | macros::builtin::derive, // :derive | ||
526 | marker::Copy, // :copy | ||
527 | marker::Sized, // :sized | ||
528 | ops::{Fn, FnMut, FnOnce}, // :fn | ||
529 | option::Option::{self, None, Some}, // :option | ||
530 | result::Result::{self, Err, Ok}, // :result | ||
531 | }; | ||
532 | } | ||
533 | |||
534 | pub mod rust_2015 { | ||
535 | pub use super::v1::*; | ||
536 | } | ||
537 | |||
538 | pub mod rust_2018 { | ||
539 | pub use super::v1::*; | ||
540 | } | ||
541 | |||
542 | pub mod rust_2021 { | ||
543 | pub use super::v1::*; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | #[prelude_import] | ||
548 | #[allow(unused)] | ||
549 | use prelude::v1::*; | ||
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs index 2b3d7fd84..ef2d7657a 100644 --- a/crates/vfs/src/vfs_path.rs +++ b/crates/vfs/src/vfs_path.rs | |||
@@ -389,7 +389,7 @@ impl VirtualPath { | |||
389 | 389 | ||
390 | match (file_stem, extension) { | 390 | match (file_stem, extension) { |
391 | (None, None) => None, | 391 | (None, None) => None, |
392 | (None, Some(_)) | (Some(""), Some(_)) => Some((file_name, None)), | 392 | (None | Some(""), Some(_)) => Some((file_name, None)), |
393 | (Some(file_stem), extension) => Some((file_stem, extension)), | 393 | (Some(file_stem), extension) => Some((file_stem, extension)), |
394 | } | 394 | } |
395 | } | 395 | } |
diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index 5876e71bc..48caec1d8 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md | |||
@@ -65,6 +65,11 @@ If you need to debug the server from the very beginning, including its initializ | |||
65 | } | 65 | } |
66 | ``` | 66 | ``` |
67 | 67 | ||
68 | However for this to work, you will need to enable debug_assertions in your build | ||
69 | ```rust | ||
70 | RUSTFLAGS='--cfg debug_assertions' cargo build --release | ||
71 | ``` | ||
72 | |||
68 | ## Demo | 73 | ## Demo |
69 | 74 | ||
70 | - [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). | 75 | - [Debugging TypeScript VScode extension](https://www.youtube.com/watch?v=T-hvpK6s4wM). |
diff --git a/docs/dev/style.md b/docs/dev/style.md index 96dd684b3..84485ea28 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -174,6 +174,13 @@ Instead, explicitly check for `None`, `Err`, etc. | |||
174 | `rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics. | 174 | `rust-analyzer` is not a library, we don't need to test for API misuse, and we have to handle any user input without panics. |
175 | Panic messages in the logs from the `#[should_panic]` tests are confusing. | 175 | Panic messages in the logs from the `#[should_panic]` tests are confusing. |
176 | 176 | ||
177 | ## `#[ignore]` | ||
178 | |||
179 | Do not `#[ignore]` tests. | ||
180 | If the test currently does not work, assert the wrong behavior and add a fixme explaining why it is wrong. | ||
181 | |||
182 | **Rationale:** noticing when the behavior is fixed, making sure that even the wrong behavior is acceptable (ie, not a panic). | ||
183 | |||
177 | ## Function Preconditions | 184 | ## Function Preconditions |
178 | 185 | ||
179 | Express function preconditions in types and force the caller to provide them (rather than checking in callee): | 186 | Express function preconditions in types and force the caller to provide them (rather than checking in callee): |
diff --git a/docs/user/.gitignore b/docs/user/.gitignore new file mode 100644 index 000000000..c32b1bcec --- /dev/null +++ b/docs/user/.gitignore | |||
@@ -0,0 +1 @@ | |||
manual.html | |||
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 4105d784f..cc7fdd38f 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -18,6 +18,11 @@ The path structure for newly inserted paths to use. | |||
18 | -- | 18 | -- |
19 | Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. | 19 | Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. |
20 | -- | 20 | -- |
21 | [[rust-analyzer.assist.allowMergingIntoGlobImports]]rust-analyzer.assist.allowMergingIntoGlobImports (default: `true`):: | ||
22 | + | ||
23 | -- | ||
24 | Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. | ||
25 | -- | ||
21 | [[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: | 26 | [[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: |
22 | + | 27 | + |
23 | -- | 28 | -- |
@@ -34,6 +39,11 @@ Automatically refresh project info via `cargo metadata` on | |||
34 | -- | 39 | -- |
35 | Activate all available features (`--all-features`). | 40 | Activate all available features (`--all-features`). |
36 | -- | 41 | -- |
42 | [[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`):: | ||
43 | + | ||
44 | -- | ||
45 | Unsets `#[cfg(test)]` for the specified crates. | ||
46 | -- | ||
37 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: | 47 | [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`):: |
38 | + | 48 | + |
39 | -- | 49 | -- |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 9a8d76700..816e094c2 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -201,6 +201,15 @@ $ eselect repository enable guru && emaint sync -r guru | |||
201 | $ emerge rust-analyzer-bin | 201 | $ emerge rust-analyzer-bin |
202 | ---- | 202 | ---- |
203 | 203 | ||
204 | ==== macOS | ||
205 | |||
206 | The `rust-analyzer` binary can be installed via https://brew.sh/[Homebrew]. | ||
207 | |||
208 | [source,bash] | ||
209 | ---- | ||
210 | $ brew install rust-analyzer | ||
211 | ---- | ||
212 | |||
204 | === Emacs | 213 | === Emacs |
205 | 214 | ||
206 | Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm]. | 215 | Note this excellent https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/[guide] from https://github.com/rksm[@rksm]. |
@@ -609,9 +618,14 @@ Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrar | |||
609 | * VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself. | 618 | * VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself. |
610 | * rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety. | 619 | * rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety. |
611 | 620 | ||
612 | rust-analyzer itself doesn't access the network. | 621 | == Privacy |
613 | The VS Code plugin doesn't access the network unless the nightly channel is selected in the settings. | 622 | |
614 | In that case, the plugin uses the GitHub API to check for and download updates. | 623 | The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies. |
624 | If enabled (the default), build scripts and procedural macros can do anything. | ||
625 | |||
626 | The Code extension automatically connects to GitHub to download updated LSP binaries and, if the nightly channel is selected, to perform update checks using the GitHub API. For `rust-analyzer` developers, using `cargo xtask release` uses the same API to put together the release notes. | ||
627 | |||
628 | Any other editor plugins are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers. | ||
615 | 629 | ||
616 | == Features | 630 | == Features |
617 | 631 | ||
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 52ffc0f9f..d22c80754 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json | |||
@@ -986,9 +986,9 @@ | |||
986 | } | 986 | } |
987 | }, | 987 | }, |
988 | "node_modules/css-what": { | 988 | "node_modules/css-what": { |
989 | "version": "5.0.0", | 989 | "version": "5.0.1", |
990 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz", | 990 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", |
991 | "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==", | 991 | "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", |
992 | "dev": true, | 992 | "dev": true, |
993 | "engines": { | 993 | "engines": { |
994 | "node": ">= 6" | 994 | "node": ">= 6" |
@@ -4345,9 +4345,9 @@ | |||
4345 | } | 4345 | } |
4346 | }, | 4346 | }, |
4347 | "css-what": { | 4347 | "css-what": { |
4348 | "version": "5.0.0", | 4348 | "version": "5.0.1", |
4349 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.0.tgz", | 4349 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", |
4350 | "integrity": "sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==", | 4350 | "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", |
4351 | "dev": true | 4351 | "dev": true |
4352 | }, | 4352 | }, |
4353 | "debug": { | 4353 | "debug": { |
diff --git a/editors/code/package.json b/editors/code/package.json index 43a5cc2b5..666016ae4 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -313,7 +313,7 @@ | |||
313 | }, | 313 | }, |
314 | "rust-analyzer.updates.askBeforeDownload": { | 314 | "rust-analyzer.updates.askBeforeDownload": { |
315 | "type": "boolean", | 315 | "type": "boolean", |
316 | "default": true, | 316 | "default": false, |
317 | "description": "Whether to ask for permission before downloading any files from the Internet." | 317 | "description": "Whether to ask for permission before downloading any files from the Internet." |
318 | }, | 318 | }, |
319 | "rust-analyzer.server.path": { | 319 | "rust-analyzer.server.path": { |
@@ -389,7 +389,7 @@ | |||
389 | "default": {}, | 389 | "default": {}, |
390 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" | 390 | "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" |
391 | }, | 391 | }, |
392 | "$generated-start": false, | 392 | "$generated-start": {}, |
393 | "rust-analyzer.assist.importGranularity": { | 393 | "rust-analyzer.assist.importGranularity": { |
394 | "markdownDescription": "How imports should be grouped into use statements.", | 394 | "markdownDescription": "How imports should be grouped into use statements.", |
395 | "default": "crate", | 395 | "default": "crate", |
@@ -418,13 +418,13 @@ | |||
418 | "type": "string", | 418 | "type": "string", |
419 | "enum": [ | 419 | "enum": [ |
420 | "plain", | 420 | "plain", |
421 | "by_self", | 421 | "self", |
422 | "by_crate" | 422 | "crate" |
423 | ], | 423 | ], |
424 | "enumDescriptions": [ | 424 | "enumDescriptions": [ |
425 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 425 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
426 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", | 426 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item. Prefixes `self` in front of the path if it starts with a module.", |
427 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 427 | "Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from." |
428 | ] | 428 | ] |
429 | }, | 429 | }, |
430 | "rust-analyzer.assist.importGroup": { | 430 | "rust-analyzer.assist.importGroup": { |
@@ -432,6 +432,11 @@ | |||
432 | "default": true, | 432 | "default": true, |
433 | "type": "boolean" | 433 | "type": "boolean" |
434 | }, | 434 | }, |
435 | "rust-analyzer.assist.allowMergingIntoGlobImports": { | ||
436 | "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.", | ||
437 | "default": true, | ||
438 | "type": "boolean" | ||
439 | }, | ||
435 | "rust-analyzer.callInfo.full": { | 440 | "rust-analyzer.callInfo.full": { |
436 | "markdownDescription": "Show function name and docs in parameter hints.", | 441 | "markdownDescription": "Show function name and docs in parameter hints.", |
437 | "default": true, | 442 | "default": true, |
@@ -447,6 +452,16 @@ | |||
447 | "default": false, | 452 | "default": false, |
448 | "type": "boolean" | 453 | "type": "boolean" |
449 | }, | 454 | }, |
455 | "rust-analyzer.cargo.unsetTest": { | ||
456 | "markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", | ||
457 | "default": [ | ||
458 | "core" | ||
459 | ], | ||
460 | "type": "array", | ||
461 | "items": { | ||
462 | "type": "string" | ||
463 | } | ||
464 | }, | ||
450 | "rust-analyzer.cargo.features": { | 465 | "rust-analyzer.cargo.features": { |
451 | "markdownDescription": "List of features to activate.", | 466 | "markdownDescription": "List of features to activate.", |
452 | "default": [], | 467 | "default": [], |
@@ -846,7 +861,7 @@ | |||
846 | "Search for all symbols kinds" | 861 | "Search for all symbols kinds" |
847 | ] | 862 | ] |
848 | }, | 863 | }, |
849 | "$generated-end": false | 864 | "$generated-end": {} |
850 | } | 865 | } |
851 | }, | 866 | }, |
852 | "problemPatterns": [ | 867 | "problemPatterns": [ |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index f58d26215..15f2151ad 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -158,7 +158,7 @@ export async function deactivate() { | |||
158 | } | 158 | } |
159 | 159 | ||
160 | async function bootstrap(config: Config, state: PersistentState): Promise<string> { | 160 | async function bootstrap(config: Config, state: PersistentState): Promise<string> { |
161 | await vscode.workspace.fs.createDirectory(config.globalStorageUri); | 161 | await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); |
162 | 162 | ||
163 | if (!config.currentExtensionIsNightly) { | 163 | if (!config.currentExtensionIsNightly) { |
164 | await state.updateNightlyReleaseId(undefined); | 164 | await state.updateNightlyReleaseId(undefined); |
@@ -277,11 +277,11 @@ async function patchelf(dest: vscode.Uri): Promise<void> { | |||
277 | ''; | 277 | ''; |
278 | } | 278 | } |
279 | `; | 279 | `; |
280 | const origFile = vscode.Uri.file(dest.path + "-orig"); | 280 | const origFile = vscode.Uri.file(dest.fsPath + "-orig"); |
281 | await vscode.workspace.fs.rename(dest, origFile); | 281 | await vscode.workspace.fs.rename(dest, origFile); |
282 | progress.report({ message: "Patching executable", increment: 20 }); | 282 | progress.report({ message: "Patching executable", increment: 20 }); |
283 | await new Promise((resolve, reject) => { | 283 | await new Promise((resolve, reject) => { |
284 | const handle = exec(`nix-build -E - --argstr srcStr '${origFile.path}' -o '${dest.path}'`, | 284 | const handle = exec(`nix-build -E - --argstr srcStr '${origFile.fsPath}' -o '${dest.fsPath}'`, |
285 | (err, stdout, stderr) => { | 285 | (err, stdout, stderr) => { |
286 | if (err != null) { | 286 | if (err != null) { |
287 | reject(Error(stderr)); | 287 | reject(Error(stderr)); |
@@ -338,14 +338,14 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
338 | await state.updateServerVersion(undefined); | 338 | await state.updateServerVersion(undefined); |
339 | } | 339 | } |
340 | 340 | ||
341 | if (state.serverVersion === config.package.version) return dest.path; | 341 | if (state.serverVersion === config.package.version) return dest.fsPath; |
342 | 342 | ||
343 | if (config.askBeforeDownload) { | 343 | if (config.askBeforeDownload) { |
344 | const userResponse = await vscode.window.showInformationMessage( | 344 | const userResponse = await vscode.window.showInformationMessage( |
345 | `Language server version ${config.package.version} for rust-analyzer is not installed.`, | 345 | `Language server version ${config.package.version} for rust-analyzer is not installed.`, |
346 | "Download now" | 346 | "Download now" |
347 | ); | 347 | ); |
348 | if (userResponse !== "Download now") return dest.path; | 348 | if (userResponse !== "Download now") return dest.fsPath; |
349 | } | 349 | } |
350 | 350 | ||
351 | const releaseTag = config.package.releaseTag; | 351 | const releaseTag = config.package.releaseTag; |
@@ -372,7 +372,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
372 | } | 372 | } |
373 | 373 | ||
374 | await state.updateServerVersion(config.package.version); | 374 | await state.updateServerVersion(config.package.version); |
375 | return dest.path; | 375 | return dest.fsPath; |
376 | } | 376 | } |
377 | 377 | ||
378 | function serverPath(config: Config): string | null { | 378 | function serverPath(config: Config): string | null { |
@@ -383,7 +383,7 @@ async function isNixOs(): Promise<boolean> { | |||
383 | try { | 383 | try { |
384 | const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString(); | 384 | const contents = (await vscode.workspace.fs.readFile(vscode.Uri.file("/etc/os-release"))).toString(); |
385 | return contents.indexOf("ID=nixos") !== -1; | 385 | return contents.indexOf("ID=nixos") !== -1; |
386 | } catch (e) { | 386 | } catch { |
387 | return false; | 387 | return false; |
388 | } | 388 | } |
389 | } | 389 | } |
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts index 747c02db9..722dab756 100644 --- a/editors/code/src/net.ts +++ b/editors/code/src/net.ts | |||
@@ -91,7 +91,7 @@ export async function download(opts: DownloadOpts) { | |||
91 | // to prevent partially downloaded files when user kills vscode | 91 | // to prevent partially downloaded files when user kills vscode |
92 | // This also avoids overwriting running executables | 92 | // This also avoids overwriting running executables |
93 | const randomHex = crypto.randomBytes(5).toString("hex"); | 93 | const randomHex = crypto.randomBytes(5).toString("hex"); |
94 | const rawDest = path.parse(opts.dest.path); | 94 | const rawDest = path.parse(opts.dest.fsPath); |
95 | const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`); | 95 | const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`); |
96 | 96 | ||
97 | await vscode.window.withProgress( | 97 | await vscode.window.withProgress( |
@@ -116,7 +116,7 @@ export async function download(opts: DownloadOpts) { | |||
116 | } | 116 | } |
117 | ); | 117 | ); |
118 | 118 | ||
119 | await vscode.workspace.fs.rename(tempFilePath, opts.dest); | 119 | await vscode.workspace.fs.rename(tempFilePath, opts.dest, { overwrite: true }); |
120 | } | 120 | } |
121 | 121 | ||
122 | async function downloadFile( | 122 | async function downloadFile( |
@@ -127,17 +127,19 @@ async function downloadFile( | |||
127 | httpProxy: string | null | undefined, | 127 | httpProxy: string | null | undefined, |
128 | onProgress: (readBytes: number, totalBytes: number) => void | 128 | onProgress: (readBytes: number, totalBytes: number) => void |
129 | ): Promise<void> { | 129 | ): Promise<void> { |
130 | const urlString = url.toString(); | ||
131 | |||
130 | const res = await (() => { | 132 | const res = await (() => { |
131 | if (httpProxy) { | 133 | if (httpProxy) { |
132 | log.debug(`Downloading ${url.path} via proxy: ${httpProxy}`); | 134 | log.debug(`Downloading ${urlString} via proxy: ${httpProxy}`); |
133 | return fetch(url.path, { agent: new HttpsProxyAgent(httpProxy) }); | 135 | return fetch(urlString, { agent: new HttpsProxyAgent(httpProxy) }); |
134 | } | 136 | } |
135 | 137 | ||
136 | return fetch(url.path); | 138 | return fetch(urlString); |
137 | })(); | 139 | })(); |
138 | 140 | ||
139 | if (!res.ok) { | 141 | if (!res.ok) { |
140 | log.error("Error", res.status, "while downloading file from", url.path); | 142 | log.error("Error", res.status, "while downloading file from", urlString); |
141 | log.error({ body: await res.text(), headers: res.headers }); | 143 | log.error({ body: await res.text(), headers: res.headers }); |
142 | 144 | ||
143 | throw new Error(`Got response ${res.status} when trying to download a file.`); | 145 | throw new Error(`Got response ${res.status} when trying to download a file.`); |
@@ -146,7 +148,7 @@ async function downloadFile( | |||
146 | const totalBytes = Number(res.headers.get('content-length')); | 148 | const totalBytes = Number(res.headers.get('content-length')); |
147 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); | 149 | assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); |
148 | 150 | ||
149 | log.debug("Downloading file of", totalBytes, "bytes size from", url.path, "to", destFilePath.path); | 151 | log.debug("Downloading file of", totalBytes, "bytes size from", urlString, "to", destFilePath.fsPath); |
150 | 152 | ||
151 | let readBytes = 0; | 153 | let readBytes = 0; |
152 | res.body.on("data", (chunk: Buffer) => { | 154 | res.body.on("data", (chunk: Buffer) => { |
@@ -154,7 +156,7 @@ async function downloadFile( | |||
154 | onProgress(readBytes, totalBytes); | 156 | onProgress(readBytes, totalBytes); |
155 | }); | 157 | }); |
156 | 158 | ||
157 | const destFileStream = fs.createWriteStream(destFilePath.path, { mode }); | 159 | const destFileStream = fs.createWriteStream(destFilePath.fsPath, { mode }); |
158 | const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; | 160 | const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body; |
159 | 161 | ||
160 | await pipeline(srcStream, destFileStream); | 162 | await pipeline(srcStream, destFileStream); |
diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index 902d0ddda..355dd76fe 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts | |||
@@ -159,7 +159,7 @@ export const getPathForExecutable = memoize( | |||
159 | // it is not mentioned in docs and cannot be infered by the type signature... | 159 | // it is not mentioned in docs and cannot be infered by the type signature... |
160 | const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName); | 160 | const standardPath = vscode.Uri.joinPath(vscode.Uri.file(os.homedir()), ".cargo", "bin", executableName); |
161 | 161 | ||
162 | if (isFile(standardPath.path)) return standardPath.path; | 162 | if (isFileAtUri(standardPath)) return standardPath.fsPath; |
163 | } catch (err) { | 163 | } catch (err) { |
164 | log.error("Failed to read the fs info", err); | 164 | log.error("Failed to read the fs info", err); |
165 | } | 165 | } |
@@ -177,9 +177,17 @@ function lookupInPath(exec: string): boolean { | |||
177 | : [candidate]; | 177 | : [candidate]; |
178 | }); | 178 | }); |
179 | 179 | ||
180 | return candidates.some(isFile); | 180 | return candidates.some(isFileAtPath); |
181 | } | 181 | } |
182 | 182 | ||
183 | async function isFile(path: string): Promise<boolean> { | 183 | async function isFileAtPath(path: string): Promise<boolean> { |
184 | return ((await vscode.workspace.fs.stat(vscode.Uri.file(path))).type & vscode.FileType.File) !== 0; | 184 | return isFileAtUri(vscode.Uri.file(path)); |
185 | } | ||
186 | |||
187 | async function isFileAtUri(uri: vscode.Uri): Promise<boolean> { | ||
188 | try { | ||
189 | return ((await vscode.workspace.fs.stat(uri)).type & vscode.FileType.File) !== 0; | ||
190 | } catch { | ||
191 | return false; | ||
192 | } | ||
185 | } | 193 | } |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index 3a67294c5..c7363688a 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -45,8 +45,8 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
45 | patch | 45 | patch |
46 | .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) | 46 | .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) |
47 | .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)) | 47 | .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)) |
48 | .replace(r#""$generated-start": false,"#, "") | 48 | .replace(r#""$generated-start": {},"#, "") |
49 | .replace(",\n \"$generated-end\": false", ""); | 49 | .replace(",\n \"$generated-end\": {}", ""); |
50 | 50 | ||
51 | if nightly { | 51 | if nightly { |
52 | patch.replace( | 52 | patch.replace( |
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index 7e2dccdfe..64ab12b42 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
@@ -8,7 +8,7 @@ use xshell::{cmd, pushd}; | |||
8 | use crate::flags; | 8 | use crate::flags; |
9 | 9 | ||
10 | // Latest stable, feel free to send a PR if this lags behind. | 10 | // Latest stable, feel free to send a PR if this lags behind. |
11 | const REQUIRED_RUST_VERSION: u32 = 52; | 11 | const REQUIRED_RUST_VERSION: u32 = 53; |
12 | 12 | ||
13 | impl flags::Install { | 13 | impl flags::Install { |
14 | pub(crate) fn run(self) -> Result<()> { | 14 | pub(crate) fn run(self) -> Result<()> { |
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs index f2ba8efef..a9d434e20 100644 --- a/xtask/src/tidy.rs +++ b/xtask/src/tidy.rs | |||
@@ -89,6 +89,7 @@ fn rust_files_are_tidy() { | |||
89 | let text = read_file(&path).unwrap(); | 89 | let text = read_file(&path).unwrap(); |
90 | check_todo(&path, &text); | 90 | check_todo(&path, &text); |
91 | check_dbg(&path, &text); | 91 | check_dbg(&path, &text); |
92 | check_test_attrs(&path, &text); | ||
92 | check_trailing_ws(&path, &text); | 93 | check_trailing_ws(&path, &text); |
93 | deny_clippy(&path, &text); | 94 | deny_clippy(&path, &text); |
94 | tidy_docs.visit(&path, &text); | 95 | tidy_docs.visit(&path, &text); |
@@ -334,13 +335,43 @@ fn check_dbg(path: &Path, text: &str) { | |||
334 | } | 335 | } |
335 | } | 336 | } |
336 | 337 | ||
338 | fn check_test_attrs(path: &Path, text: &str) { | ||
339 | let ignore_rule = | ||
340 | "https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/style.md#ignore"; | ||
341 | let need_ignore: &[&str] = &[ | ||
342 | // Special case to run `#[ignore]` tests | ||
343 | "ide/src/runnables.rs", | ||
344 | // A legit test which needs to be ignored, as it takes too long to run | ||
345 | // :( | ||
346 | "hir_def/src/nameres/collector.rs", | ||
347 | // Obviously needs ignore. | ||
348 | "ide_assists/src/handlers/toggle_ignore.rs", | ||
349 | // See above. | ||
350 | "ide_assists/src/tests/generated.rs", | ||
351 | ]; | ||
352 | if text.contains("#[ignore") && !need_ignore.iter().any(|p| path.ends_with(p)) { | ||
353 | panic!("\ndon't `#[ignore]` tests, see:\n\n {}\n\n {}\n", ignore_rule, path.display(),) | ||
354 | } | ||
355 | |||
356 | let panic_rule = | ||
357 | "https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/style.md#should_panic"; | ||
358 | let need_panic: &[&str] = &["test_utils/src/fixture.rs"]; | ||
359 | if text.contains("#[should_panic") && !need_panic.iter().any(|p| path.ends_with(p)) { | ||
360 | panic!( | ||
361 | "\ndon't add `#[should_panic]` tests, see:\n\n {}\n\n {}\n", | ||
362 | panic_rule, | ||
363 | path.display(), | ||
364 | ) | ||
365 | } | ||
366 | } | ||
367 | |||
337 | fn check_trailing_ws(path: &Path, text: &str) { | 368 | fn check_trailing_ws(path: &Path, text: &str) { |
338 | if is_exclude_dir(path, &["test_data"]) { | 369 | if is_exclude_dir(path, &["test_data"]) { |
339 | return; | 370 | return; |
340 | } | 371 | } |
341 | for (line_number, line) in text.lines().enumerate() { | 372 | for (line_number, line) in text.lines().enumerate() { |
342 | if line.chars().last().map(char::is_whitespace) == Some(true) { | 373 | if line.chars().last().map(char::is_whitespace) == Some(true) { |
343 | panic!("Trailing whitespace in {} at line {}", path.display(), line_number) | 374 | panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1) |
344 | } | 375 | } |
345 | } | 376 | } |
346 | } | 377 | } |