aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock76
-rw-r--r--Cargo.toml11
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/chalk_db.rs8
-rw-r--r--crates/hir_ty/src/tests/traits.rs31
-rw-r--r--crates/ide_completion/src/completions.rs27
-rw-r--r--crates/ide_completion/src/completions/attribute.rs37
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs15
-rw-r--r--crates/ide_completion/src/completions/keyword.rs18
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs7
-rw-r--r--crates/ide_completion/src/completions/macro_in_item_position.rs4
-rw-r--r--crates/ide_completion/src/completions/mod_.rs6
-rw-r--r--crates/ide_completion/src/completions/pattern.rs2
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs38
-rw-r--r--crates/ide_completion/src/completions/record.rs20
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs8
-rw-r--r--crates/ide_completion/src/context.rs99
-rw-r--r--crates/ide_completion/src/patterns.rs151
-rw-r--r--crates/ide_completion/src/render.rs143
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs55
-rw-r--r--crates/ide_completion/src/render/function.rs14
-rw-r--r--crates/ide_completion/src/render/macro_.rs9
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs87
-rw-r--r--crates/syntax/Cargo.toml2
24 files changed, 477 insertions, 397 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 192f0efc2..15ccf4146 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -146,9 +146,9 @@ dependencies = [
146 146
147[[package]] 147[[package]]
148name = "cc" 148name = "cc"
149version = "1.0.67" 149version = "1.0.68"
150source = "registry+https://github.com/rust-lang/crates.io-index" 150source = "registry+https://github.com/rust-lang/crates.io-index"
151checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 151checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
152 152
153[[package]] 153[[package]]
154name = "cfg" 154name = "cfg"
@@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
169 169
170[[package]] 170[[package]]
171name = "chalk-derive" 171name = "chalk-derive"
172version = "0.67.0" 172version = "0.68.0"
173source = "registry+https://github.com/rust-lang/crates.io-index" 173source = "registry+https://github.com/rust-lang/crates.io-index"
174checksum = "751a3cd9eeb24d7165e9f90daf1f10a23ffa16a7986f349027f8dfb60f51ee0c" 174checksum = "ea1552e7666a857f5417e6051ce705ea6856ab2cda39be7605e5b626fa47416b"
175dependencies = [ 175dependencies = [
176 "proc-macro2", 176 "proc-macro2",
177 "quote", 177 "quote",
@@ -181,9 +181,9 @@ dependencies = [
181 181
182[[package]] 182[[package]]
183name = "chalk-ir" 183name = "chalk-ir"
184version = "0.67.0" 184version = "0.68.0"
185source = "registry+https://github.com/rust-lang/crates.io-index" 185source = "registry+https://github.com/rust-lang/crates.io-index"
186checksum = "4236da905504740d3f72cc8f0509aa01321cc236208e2c33b55eda2db74bc495" 186checksum = "19d7d5f1448dbac493541e97221f7f4c32326c4c76c6ecf543daf72a1dd93e66"
187dependencies = [ 187dependencies = [
188 "bitflags", 188 "bitflags",
189 "chalk-derive", 189 "chalk-derive",
@@ -192,9 +192,9 @@ dependencies = [
192 192
193[[package]] 193[[package]]
194name = "chalk-recursive" 194name = "chalk-recursive"
195version = "0.67.0" 195version = "0.68.0"
196source = "registry+https://github.com/rust-lang/crates.io-index" 196source = "registry+https://github.com/rust-lang/crates.io-index"
197checksum = "7d0b123fe45a34c4cd5cb329650a0d163525d2acbe9d754a4538d3340884002e" 197checksum = "e0df406d2927321021b48acd193459dd33c913732155c93442d03f5ae8275385"
198dependencies = [ 198dependencies = [
199 "chalk-derive", 199 "chalk-derive",
200 "chalk-ir", 200 "chalk-ir",
@@ -205,9 +205,9 @@ dependencies = [
205 205
206[[package]] 206[[package]]
207name = "chalk-solve" 207name = "chalk-solve"
208version = "0.67.0" 208version = "0.68.0"
209source = "registry+https://github.com/rust-lang/crates.io-index" 209source = "registry+https://github.com/rust-lang/crates.io-index"
210checksum = "9c54788f0ae3b38e2bb2266f395d462d988c64f92dbd55c68219908fd1ce7ddc" 210checksum = "0cbfcd5daa5ab8b1c9e5e10e83b0ac26271480f6ae5b5f35e5b19e1f6a0e6e37"
211dependencies = [ 211dependencies = [
212 "chalk-derive", 212 "chalk-derive",
213 "chalk-ir", 213 "chalk-ir",
@@ -281,9 +281,9 @@ dependencies = [
281 281
282[[package]] 282[[package]]
283name = "crossbeam-epoch" 283name = "crossbeam-epoch"
284version = "0.9.4" 284version = "0.9.5"
285source = "registry+https://github.com/rust-lang/crates.io-index" 285source = "registry+https://github.com/rust-lang/crates.io-index"
286checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94" 286checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
287dependencies = [ 287dependencies = [
288 "cfg-if", 288 "cfg-if",
289 "crossbeam-utils", 289 "crossbeam-utils",
@@ -294,11 +294,10 @@ dependencies = [
294 294
295[[package]] 295[[package]]
296name = "crossbeam-utils" 296name = "crossbeam-utils"
297version = "0.8.4" 297version = "0.8.5"
298source = "registry+https://github.com/rust-lang/crates.io-index" 298source = "registry+https://github.com/rust-lang/crates.io-index"
299checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" 299checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
300dependencies = [ 300dependencies = [
301 "autocfg",
302 "cfg-if", 301 "cfg-if",
303 "lazy_static", 302 "lazy_static",
304] 303]
@@ -426,20 +425,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
426checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" 425checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
427 426
428[[package]] 427[[package]]
429name = "fsevent"
430version = "2.0.2"
431source = "registry+https://github.com/rust-lang/crates.io-index"
432checksum = "97f347202c95c98805c216f9e1df210e8ebaec9fdb2365700a43c10797a35e63"
433dependencies = [
434 "bitflags",
435 "fsevent-sys",
436]
437
438[[package]]
439name = "fsevent-sys" 428name = "fsevent-sys"
440version = "3.1.0" 429version = "4.0.0"
441source = "registry+https://github.com/rust-lang/crates.io-index" 430source = "registry+https://github.com/rust-lang/crates.io-index"
442checksum = "ca6f5e6817058771c10f0eb0f05ddf1e35844266f972004fe8e4b21fda295bd5" 431checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a"
443dependencies = [ 432dependencies = [
444 "libc", 433 "libc",
445] 434]
@@ -776,9 +765,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
776 765
777[[package]] 766[[package]]
778name = "libc" 767name = "libc"
779version = "0.2.94" 768version = "0.2.95"
780source = "registry+https://github.com/rust-lang/crates.io-index" 769source = "registry+https://github.com/rust-lang/crates.io-index"
781checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" 770checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
782 771
783[[package]] 772[[package]]
784name = "libloading" 773name = "libloading"
@@ -881,18 +870,18 @@ checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
881 870
882[[package]] 871[[package]]
883name = "memmap2" 872name = "memmap2"
884version = "0.2.2" 873version = "0.2.3"
885source = "registry+https://github.com/rust-lang/crates.io-index" 874source = "registry+https://github.com/rust-lang/crates.io-index"
886checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" 875checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4"
887dependencies = [ 876dependencies = [
888 "libc", 877 "libc",
889] 878]
890 879
891[[package]] 880[[package]]
892name = "memoffset" 881name = "memoffset"
893version = "0.6.3" 882version = "0.6.4"
894source = "registry+https://github.com/rust-lang/crates.io-index" 883source = "registry+https://github.com/rust-lang/crates.io-index"
895checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" 884checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
896dependencies = [ 885dependencies = [
897 "autocfg", 886 "autocfg",
898] 887]
@@ -940,14 +929,13 @@ dependencies = [
940 929
941[[package]] 930[[package]]
942name = "notify" 931name = "notify"
943version = "5.0.0-pre.8" 932version = "5.0.0-pre.9"
944source = "registry+https://github.com/rust-lang/crates.io-index" 933source = "registry+https://github.com/rust-lang/crates.io-index"
945checksum = "46bbbcd078f1f00ddb7a9abe70b96e91229b44b0b3afdec610f8e5137f8f014b" 934checksum = "b89869d77edd64db917d7903abeadc166f93686b342c56cc0ca51acb68441d09"
946dependencies = [ 935dependencies = [
947 "bitflags", 936 "bitflags",
948 "crossbeam-channel", 937 "crossbeam-channel",
949 "filetime", 938 "filetime",
950 "fsevent",
951 "fsevent-sys", 939 "fsevent-sys",
952 "inotify", 940 "inotify",
953 "libc", 941 "libc",
@@ -1360,9 +1348,9 @@ dependencies = [
1360 1348
1361[[package]] 1349[[package]]
1362name = "rustc-ap-rustc_lexer" 1350name = "rustc-ap-rustc_lexer"
1363version = "720.0.0" 1351version = "721.0.0"
1364source = "registry+https://github.com/rust-lang/crates.io-index" 1352source = "registry+https://github.com/rust-lang/crates.io-index"
1365checksum = "a025b453b0ae85335336f991f920ca9af5c0dc851171cb9035a16cea5619e9b2" 1353checksum = "2ba1f60e2942dc7dc5ea64edeaae01cfba2303871b14936e1af0f54d5420b3d1"
1366dependencies = [ 1354dependencies = [
1367 "unicode-xid", 1355 "unicode-xid",
1368] 1356]
@@ -1828,9 +1816,9 @@ dependencies = [
1828 1816
1829[[package]] 1817[[package]]
1830name = "unicode-normalization" 1818name = "unicode-normalization"
1831version = "0.1.17" 1819version = "0.1.18"
1832source = "registry+https://github.com/rust-lang/crates.io-index" 1820source = "registry+https://github.com/rust-lang/crates.io-index"
1833checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 1821checksum = "33717dca7ac877f497014e10d73f3acf948c342bee31b5ca7892faf94ccc6b49"
1834dependencies = [ 1822dependencies = [
1835 "tinyvec", 1823 "tinyvec",
1836] 1824]
@@ -1958,18 +1946,18 @@ dependencies = [
1958 1946
1959[[package]] 1947[[package]]
1960name = "xshell" 1948name = "xshell"
1961version = "0.1.13" 1949version = "0.1.14"
1962source = "registry+https://github.com/rust-lang/crates.io-index" 1950source = "registry+https://github.com/rust-lang/crates.io-index"
1963checksum = "eb15bb1b41eb14efe628006294c294e10c366e03a0283b9c2063fc27d97934c6" 1951checksum = "c640362f1b150e186b76e88606e4b01a7b2f1d56cc50fcc184ddb683fb567c23"
1964dependencies = [ 1952dependencies = [
1965 "xshell-macros", 1953 "xshell-macros",
1966] 1954]
1967 1955
1968[[package]] 1956[[package]]
1969name = "xshell-macros" 1957name = "xshell-macros"
1970version = "0.1.13" 1958version = "0.1.14"
1971source = "registry+https://github.com/rust-lang/crates.io-index" 1959source = "registry+https://github.com/rust-lang/crates.io-index"
1972checksum = "cf7ed94a2c75b9bcc57031229be2b57ee47ba71122f71aabef8610ec66a97e52" 1960checksum = "0607c095c96c1d8420ce4a018a0954fb15d73d5eb59b521a05a0f04cffc05059"
1973 1961
1974[[package]] 1962[[package]]
1975name = "xtask" 1963name = "xtask"
diff --git a/Cargo.toml b/Cargo.toml
index 498cf7d62..32ba3923b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,10 +3,6 @@ resolver = "2"
3members = ["xtask/", "lib/*", "crates/*"] 3members = ["xtask/", "lib/*", "crates/*"]
4 4
5[profile.dev] 5[profile.dev]
6# We do want incremental builds, but they are broken at the moment :(
7# https://github.com/rust-lang/rust/issues/85003#issuecomment-833796289
8incremental = false
9
10# Disabling debug info speeds up builds a bunch, 6# Disabling debug info speeds up builds a bunch,
11# and we don't rely on it for debugging that much. 7# and we don't rely on it for debugging that much.
12debug = 0 8debug = 0
@@ -21,14 +17,9 @@ text-size.opt-level = 3
21miniz_oxide.opt-level = 3 17miniz_oxide.opt-level = 3
22 18
23[profile.release] 19[profile.release]
24# We do want incremental release builds, but they are broken at the moment :( 20incremental = true
25# https://github.com/rust-lang/rust/issues/85003#issuecomment-833796289
26incremental = false
27debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. 21debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
28 22
29[profile.test]
30incremental = false
31
32[patch.'crates-io'] 23[patch.'crates-io']
33# rowan = { path = "../rowan" } 24# rowan = { path = "../rowan" }
34 25
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index a9994082a..c3d02424d 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
18log = "0.4.8" 18log = "0.4.8"
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20scoped-tls = "1" 20scoped-tls = "1"
21chalk-solve = { version = "0.67", default-features = false } 21chalk-solve = { version = "0.68", default-features = false }
22chalk-ir = "0.67" 22chalk-ir = "0.68"
23chalk-recursive = "0.67" 23chalk-recursive = "0.68"
24la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
25 25
26stdx = { path = "../stdx", version = "0.0.0" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index b108fd559..4e042bf42 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -383,7 +383,7 @@ pub(crate) fn associated_ty_data_query(
383 // Lower bounds -- we could/should maybe move this to a separate query in `lower` 383 // Lower bounds -- we could/should maybe move this to a separate query in `lower`
384 let type_alias_data = db.type_alias_data(type_alias); 384 let type_alias_data = db.type_alias_data(type_alias);
385 let generic_params = generics(db.upcast(), type_alias.into()); 385 let generic_params = generics(db.upcast(), type_alias.into());
386 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); 386 // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
387 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); 387 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
388 let ctx = crate::TyLoweringContext::new(db, &resolver) 388 let ctx = crate::TyLoweringContext::new(db, &resolver)
389 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); 389 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -396,8 +396,10 @@ pub(crate) fn associated_ty_data_query(
396 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) 396 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
397 .collect(); 397 .collect();
398 398
399 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 399 // FIXME: Re-enable where clauses on associated types when an upstream chalk bug is fixed.
400 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; 400 // (rust-analyzer#9052)
401 // let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
402 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses: vec![] };
401 let datum = AssociatedTyDatum { 403 let datum = AssociatedTyDatum {
402 trait_id: to_chalk_trait_id(trait_), 404 trait_id: to_chalk_trait_id(trait_),
403 id, 405 id,
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 7c0ff2170..49add4ab9 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -161,7 +161,7 @@ mod result {
161} 161}
162 162
163#[test] 163#[test]
164fn infer_tryv2() { 164fn infer_try_trait_v2() {
165 check_types( 165 check_types(
166 r#" 166 r#"
167//- /main.rs crate:main deps:core 167//- /main.rs crate:main deps:core
@@ -172,26 +172,41 @@ fn test() {
172} //^ i32 172} //^ i32
173 173
174//- /core.rs crate:core 174//- /core.rs crate:core
175#[prelude_import] use ops::*;
176mod ops { 175mod ops {
177 trait Try { 176 mod try_trait {
178 type Output; 177 pub trait Try: FromResidual {
179 type Residual; 178 type Output;
179 type Residual;
180 }
181 pub trait FromResidual<R = <Self as Try>::Residual> {}
180 } 182 }
183
184 pub use self::try_trait::FromResidual;
185 pub use self::try_trait::Try;
186}
187
188mov convert {
189 pub trait From<T> {}
190 impl<T> From<T> for T {}
181} 191}
182 192
183#[prelude_import] use result::*; 193#[prelude_import] use result::*;
184mod result { 194mod result {
185 enum Infallible {} 195 use crate::convert::From;
186 enum Result<O, E> { 196 use crate::ops::{Try, FromResidual};
197
198 pub enum Infallible {}
199 pub enum Result<O, E> {
187 Ok(O), 200 Ok(O),
188 Err(E) 201 Err(E)
189 } 202 }
190 203
191 impl<O, E> crate::ops::Try for Result<O, E> { 204 impl<O, E> Try for Result<O, E> {
192 type Output = O; 205 type Output = O;
193 type Error = Result<Infallible, E>; 206 type Error = Result<Infallible, E>;
194 } 207 }
208
209 impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
195} 210}
196"#, 211"#,
197 ); 212 );
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index 78154bf3e..151bf3783 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -18,7 +18,7 @@ pub(crate) mod unqualified_path;
18 18
19use std::iter; 19use std::iter;
20 20
21use hir::{known, ModPath, ScopeDef, Type}; 21use hir::known;
22use ide_db::SymbolKind; 22use ide_db::SymbolKind;
23 23
24use crate::{ 24use crate::{
@@ -69,12 +69,17 @@ impl Completions {
69 items.into_iter().for_each(|item| self.add(item.into())) 69 items.into_iter().for_each(|item| self.add(item.into()))
70 } 70 }
71 71
72 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { 72 pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &hir::Type) {
73 let item = render_field(RenderContext::new(ctx), field, ty); 73 let item = render_field(RenderContext::new(ctx), field, ty);
74 self.add(item); 74 self.add(item);
75 } 75 }
76 76
77 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { 77 pub(crate) fn add_tuple_field(
78 &mut self,
79 ctx: &CompletionContext,
80 field: usize,
81 ty: &hir::Type,
82 ) {
78 let item = render_tuple_field(RenderContext::new(ctx), field, ty); 83 let item = render_tuple_field(RenderContext::new(ctx), field, ty);
79 self.add(item); 84 self.add(item);
80 } 85 }
@@ -89,8 +94,8 @@ impl Completions {
89 pub(crate) fn add_resolution( 94 pub(crate) fn add_resolution(
90 &mut self, 95 &mut self,
91 ctx: &CompletionContext, 96 ctx: &CompletionContext,
92 local_name: String, 97 local_name: hir::Name,
93 resolution: &ScopeDef, 98 resolution: &hir::ScopeDef,
94 ) { 99 ) {
95 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { 100 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) {
96 self.add(item); 101 self.add(item);
@@ -100,7 +105,7 @@ impl Completions {
100 pub(crate) fn add_macro( 105 pub(crate) fn add_macro(
101 &mut self, 106 &mut self,
102 ctx: &CompletionContext, 107 ctx: &CompletionContext,
103 name: Option<String>, 108 name: Option<hir::Name>,
104 macro_: hir::MacroDef, 109 macro_: hir::MacroDef,
105 ) { 110 ) {
106 let name = match name { 111 let name = match name {
@@ -116,7 +121,7 @@ impl Completions {
116 &mut self, 121 &mut self,
117 ctx: &CompletionContext, 122 ctx: &CompletionContext,
118 func: hir::Function, 123 func: hir::Function,
119 local_name: Option<String>, 124 local_name: Option<hir::Name>,
120 ) { 125 ) {
121 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { 126 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
122 self.add(item) 127 self.add(item)
@@ -127,7 +132,7 @@ impl Completions {
127 &mut self, 132 &mut self,
128 ctx: &CompletionContext, 133 ctx: &CompletionContext,
129 func: hir::Function, 134 func: hir::Function,
130 local_name: Option<String>, 135 local_name: Option<hir::Name>,
131 ) { 136 ) {
132 if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) { 137 if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) {
133 self.add(item) 138 self.add(item)
@@ -149,7 +154,7 @@ impl Completions {
149 &mut self, 154 &mut self,
150 ctx: &CompletionContext, 155 ctx: &CompletionContext,
151 variant: hir::Variant, 156 variant: hir::Variant,
152 path: ModPath, 157 path: hir::ModPath,
153 ) { 158 ) {
154 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { 159 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) {
155 self.add(item); 160 self.add(item);
@@ -183,7 +188,7 @@ impl Completions {
183 &mut self, 188 &mut self,
184 ctx: &CompletionContext, 189 ctx: &CompletionContext,
185 variant: hir::Variant, 190 variant: hir::Variant,
186 path: ModPath, 191 path: hir::ModPath,
187 ) { 192 ) {
188 let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); 193 let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path));
189 self.add(item); 194 self.add(item);
@@ -193,7 +198,7 @@ impl Completions {
193 &mut self, 198 &mut self,
194 ctx: &CompletionContext, 199 ctx: &CompletionContext,
195 variant: hir::Variant, 200 variant: hir::Variant,
196 local_name: Option<String>, 201 local_name: Option<hir::Name>,
197 ) { 202 ) {
198 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); 203 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
199 self.add(item); 204 self.add(item);
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 13d5b90c9..76d926157 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -219,8 +219,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[
219 ), 219 ),
220 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), 220 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
221 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), 221 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
222 // FIXME: resolve through macro resolution? 222 attr("global_allocator", None, None),
223 attr("global_allocator", None, None).prefer_inner(),
224 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), 223 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
225 attr("inline", Some("inline"), Some("inline")), 224 attr("inline", Some("inline"), Some("inline")),
226 attr("link", None, None), 225 attr("link", None, None),
@@ -239,7 +238,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[
239 attr("no_mangle", None, None), 238 attr("no_mangle", None, None),
240 attr("no_std", None, None).prefer_inner(), 239 attr("no_std", None, None).prefer_inner(),
241 attr("non_exhaustive", None, None), 240 attr("non_exhaustive", None, None),
242 attr("panic_handler", None, None).prefer_inner(), 241 attr("panic_handler", None, None),
243 attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)), 242 attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)),
244 attr("proc_macro", None, None), 243 attr("proc_macro", None, None),
245 attr("proc_macro_attribute", None, None), 244 attr("proc_macro_attribute", None, None),
@@ -609,6 +608,7 @@ mod tests {
609 at export_name = "…" 608 at export_name = "…"
610 at link_name = "…" 609 at link_name = "…"
611 at link_section = "…" 610 at link_section = "…"
611 at global_allocator
612 at used 612 at used
613 "#]], 613 "#]],
614 ); 614 );
@@ -732,9 +732,9 @@ mod tests {
732 } 732 }
733 733
734 #[test] 734 #[test]
735 fn complete_attribute_on_expr() { 735 fn complete_attribute_on_fn() {
736 check( 736 check(
737 r#"fn main() { #[$0] foo() }"#, 737 r#"#[$0] fn main() {}"#,
738 expect![[r#" 738 expect![[r#"
739 at allow(…) 739 at allow(…)
740 at cfg(…) 740 at cfg(…)
@@ -742,10 +742,35 @@ mod tests {
742 at deny(…) 742 at deny(…)
743 at forbid(…) 743 at forbid(…)
744 at warn(…) 744 at warn(…)
745 at deprecated
746 at doc = "…"
747 at doc(hidden)
748 at doc(alias = "…")
749 at must_use
750 at no_mangle
751 at export_name = "…"
752 at link_name = "…"
753 at link_section = "…"
754 at cold
755 at ignore = "…"
756 at inline
757 at must_use
758 at panic_handler
759 at proc_macro
760 at proc_macro_derive(…)
761 at proc_macro_attribute
762 at should_panic
763 at target_feature = "…"
764 at test
765 at track_caller
745 "#]], 766 "#]],
746 ); 767 );
768 }
769
770 #[test]
771 fn complete_attribute_on_expr() {
747 check( 772 check(
748 r#"fn main() { #[$0] foo(); }"#, 773 r#"fn main() { #[$0] foo() }"#,
749 expect![[r#" 774 expect![[r#"
750 at allow(…) 775 at allow(…)
751 at cfg(…) 776 at cfg(…)
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 0ea558489..cb90e8a3e 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -128,4 +128,19 @@ fn outer(text: String) {
128 "#]], 128 "#]],
129 ) 129 )
130 } 130 }
131
132 #[test]
133 fn completes_non_ident_pat_param() {
134 check(
135 r#"
136struct Bar { bar: u32 }
137
138fn foo(Bar { bar }: Bar) {}
139fn foo2($0) {}
140"#,
141 expect![[r#"
142 bn Bar { bar }: Bar
143 "#]],
144 )
145 }
131} 146}
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index e71a04b6e..0d035c611 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -4,7 +4,10 @@ use std::iter;
4 4
5use syntax::{SyntaxKind, T}; 5use syntax::{SyntaxKind, T};
6 6
7use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 7use crate::{
8 patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
9 CompletionKind, Completions,
10};
8 11
9pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
10 // complete keyword "crate" in use stmt 13 // complete keyword "crate" in use stmt
@@ -44,7 +47,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
44 cov_mark::hit!(no_keyword_completion_in_comments); 47 cov_mark::hit!(no_keyword_completion_in_comments);
45 return; 48 return;
46 } 49 }
47 if ctx.record_lit_syntax.is_some() { 50 if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
48 cov_mark::hit!(no_keyword_completion_in_record_lit); 51 cov_mark::hit!(no_keyword_completion_in_record_lit);
49 return; 52 return;
50 } 53 }
@@ -55,7 +58,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
55 let expects_item = ctx.expects_item(); 58 let expects_item = ctx.expects_item();
56 59
57 if ctx.has_impl_or_trait_prev_sibling() { 60 if ctx.has_impl_or_trait_prev_sibling() {
58 // FIXME this also incorrectly shows up after a complete trait/impl
59 add_keyword("where", "where "); 61 add_keyword("where", "where ");
60 return; 62 return;
61 } 63 }
@@ -77,11 +79,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
77 add_keyword("pub", "pub "); 79 add_keyword("pub", "pub ");
78 } 80 }
79 81
80 if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm {
81 add_keyword("unsafe", "unsafe ");
82 }
83
84 if expects_item || expects_assoc_item || has_block_expr_parent { 82 if expects_item || expects_assoc_item || has_block_expr_parent {
83 add_keyword("unsafe", "unsafe ");
85 add_keyword("fn", "fn $1($2) {\n $0\n}"); 84 add_keyword("fn", "fn $1($2) {\n $0\n}");
86 add_keyword("const", "const $0"); 85 add_keyword("const", "const $0");
87 add_keyword("type", "type $0"); 86 add_keyword("type", "type $0");
@@ -103,6 +102,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
103 } 102 }
104 103
105 if ctx.expects_expression() { 104 if ctx.expects_expression() {
105 if !has_block_expr_parent {
106 add_keyword("unsafe", "unsafe {\n $0\n}");
107 }
106 add_keyword("match", "match $1 {\n $0\n}"); 108 add_keyword("match", "match $1 {\n $0\n}");
107 add_keyword("while", "while $1 {\n $0\n}"); 109 add_keyword("while", "while $1 {\n $0\n}");
108 add_keyword("while let", "while let $1 = $2 {\n $0\n}"); 110 add_keyword("while let", "while let $1 = $2 {\n $0\n}");
@@ -574,6 +576,7 @@ pub mod future {
574 check( 576 check(
575 r#"fn main() { let _ = $0 }"#, 577 r#"fn main() { let _ = $0 }"#,
576 expect![[r#" 578 expect![[r#"
579 kw unsafe
577 kw match 580 kw match
578 kw while 581 kw while
579 kw while let 582 kw while let
@@ -634,6 +637,7 @@ fn foo() {
634} 637}
635"#, 638"#,
636 expect![[r#" 639 expect![[r#"
640 kw unsafe
637 kw match 641 kw match
638 kw while 642 kw while
639 kw while let 643 kw while let
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs
index 5f6285b84..8ccccb646 100644
--- a/crates/ide_completion/src/completions/lifetime.rs
+++ b/crates/ide_completion/src/completions/lifetime.rs
@@ -16,15 +16,14 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
16 (Some(lt), Some(lp)) if lp == lt.clone() => return, 16 (Some(lt), Some(lp)) if lp == lt.clone() => return,
17 (Some(_), Some(lp)) => { 17 (Some(_), Some(lp)) => {
18 lp_string = lp.to_string(); 18 lp_string = lp.to_string();
19 Some(&lp_string) 19 Some(&*lp_string)
20 } 20 }
21 _ => None, 21 _ => None,
22 }; 22 };
23 23
24 ctx.scope.process_all_names(&mut |name, res| { 24 ctx.scope.process_all_names(&mut |name, res| {
25 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 25 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
26 let name = name.to_string(); 26 if param_lifetime != Some(&*name.to_string()) {
27 if param_lifetime != Some(&name) {
28 acc.add_resolution(ctx, name, &res); 27 acc.add_resolution(ctx, name, &res);
29 } 28 }
30 } 29 }
@@ -41,7 +40,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
41 } 40 }
42 ctx.scope.process_all_names(&mut |name, res| { 41 ctx.scope.process_all_names(&mut |name, res| {
43 if let ScopeDef::Label(_) = res { 42 if let ScopeDef::Label(_) = res {
44 acc.add_resolution(ctx, name.to_string(), &res); 43 acc.add_resolution(ctx, name, &res);
45 } 44 }
46 }); 45 });
47} 46}
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs
index ec57aee30..202e71215 100644
--- a/crates/ide_completion/src/completions/macro_in_item_position.rs
+++ b/crates/ide_completion/src/completions/macro_in_item_position.rs
@@ -11,11 +11,11 @@ pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
11 11
12 ctx.scope.process_all_names(&mut |name, res| { 12 ctx.scope.process_all_names(&mut |name, res| {
13 if let hir::ScopeDef::MacroDef(mac) = res { 13 if let hir::ScopeDef::MacroDef(mac) = res {
14 acc.add_macro(ctx, Some(name.to_string()), mac); 14 acc.add_macro(ctx, Some(name.clone()), mac);
15 } 15 }
16 // FIXME: This should be done in qualified_path/unqualified_path instead? 16 // FIXME: This should be done in qualified_path/unqualified_path instead?
17 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { 17 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
18 acc.add_resolution(ctx, name.to_string(), &res); 18 acc.add_resolution(ctx, name, &res);
19 } 19 }
20 }) 20 })
21} 21}
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 4f9415736..6a5746fb9 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -9,14 +9,14 @@ use ide_db::{
9}; 9};
10use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
11 11
12use crate::CompletionItem; 12use crate::{patterns::ImmediateLocation, CompletionItem};
13 13
14use crate::{context::CompletionContext, item::CompletionKind, Completions}; 14use crate::{context::CompletionContext, item::CompletionKind, Completions};
15 15
16/// Complete mod declaration, i.e. `mod $0 ;` 16/// Complete mod declaration, i.e. `mod $0 ;`
17pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 17pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
18 let mod_under_caret = match &ctx.mod_declaration_under_caret { 18 let mod_under_caret = match &ctx.completion_location {
19 Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret, 19 Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret,
20 _ => return None, 20 _ => return None,
21 }; 21 };
22 22
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index b84e9a967..8a728c67e 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -51,7 +51,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
51 _ => false, 51 _ => false,
52 }; 52 };
53 if add_resolution { 53 if add_resolution {
54 acc.add_resolution(ctx, name.to_string(), &res); 54 acc.add_resolution(ctx, name, &res);
55 } 55 }
56 }); 56 });
57} 57}
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 7a0e1ead3..de58ce1cd 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -1,6 +1,6 @@
1//! Completion of paths, i.e. `some::prefix::$0`. 1//! Completion of paths, i.e. `some::prefix::$0`.
2 2
3use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; 3use hir::HasVisibility;
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use syntax::AstNode; 5use syntax::AstNode;
6 6
@@ -21,14 +21,14 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
21 }; 21 };
22 let context_module = ctx.scope.module(); 22 let context_module = ctx.scope.module();
23 if ctx.expects_assoc_item() { 23 if ctx.expects_assoc_item() {
24 if let PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { 24 if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
25 let module_scope = module.scope(ctx.db, context_module); 25 let module_scope = module.scope(ctx.db, context_module);
26 for (name, def) in module_scope { 26 for (name, def) in module_scope {
27 if let ScopeDef::MacroDef(macro_def) = def { 27 if let hir::ScopeDef::MacroDef(macro_def) = def {
28 acc.add_macro(ctx, Some(name.to_string()), macro_def); 28 acc.add_macro(ctx, Some(name.clone()), macro_def);
29 } 29 }
30 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { 30 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
31 acc.add_resolution(ctx, name.to_string(), &def); 31 acc.add_resolution(ctx, name, &def);
32 } 32 }
33 } 33 }
34 } 34 }
@@ -42,11 +42,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
42 }); 42 });
43 43
44 match resolution { 44 match resolution {
45 PathResolution::Def(hir::ModuleDef::Module(module)) => { 45 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
46 let module_scope = module.scope(ctx.db, context_module); 46 let module_scope = module.scope(ctx.db, context_module);
47 for (name, def) in module_scope { 47 for (name, def) in module_scope {
48 if ctx.use_item_syntax.is_some() { 48 if ctx.use_item_syntax.is_some() {
49 if let ScopeDef::Unknown = def { 49 if let hir::ScopeDef::Unknown = def {
50 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 50 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
51 if name_ref.syntax().text() == name.to_string().as_str() { 51 if name_ref.syntax().text() == name.to_string().as_str() {
52 // for `use self::foo$0`, don't suggest `foo` as a completion 52 // for `use self::foo$0`, don't suggest `foo` as a completion
@@ -57,20 +57,20 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
57 } 57 }
58 } 58 }
59 59
60 acc.add_resolution(ctx, name.to_string(), &def); 60 acc.add_resolution(ctx, name, &def);
61 } 61 }
62 } 62 }
63 PathResolution::Def(def @ hir::ModuleDef::Adt(_)) 63 hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_))
64 | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) 64 | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_))
65 | PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { 65 | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => {
66 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { 66 if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
67 add_enum_variants(ctx, acc, e); 67 add_enum_variants(ctx, acc, e);
68 } 68 }
69 let ty = match def { 69 let ty = match def {
70 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), 70 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
71 hir::ModuleDef::TypeAlias(a) => { 71 hir::ModuleDef::TypeAlias(a) => {
72 let ty = a.ty(ctx.db); 72 let ty = a.ty(ctx.db);
73 if let Some(Adt::Enum(e)) = ty.as_adt() { 73 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
74 cov_mark::hit!(completes_variant_through_alias); 74 cov_mark::hit!(completes_variant_through_alias);
75 add_enum_variants(ctx, acc, e); 75 add_enum_variants(ctx, acc, e);
76 } 76 }
@@ -117,7 +117,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
117 }); 117 });
118 } 118 }
119 } 119 }
120 PathResolution::Def(hir::ModuleDef::Trait(t)) => { 120 hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
121 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`. 121 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
122 for item in t.items(ctx.db) { 122 for item in t.items(ctx.db) {
123 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { 123 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
@@ -130,15 +130,15 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
130 } 130 }
131 } 131 }
132 } 132 }
133 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { 133 hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
134 if let Some(krate) = ctx.krate { 134 if let Some(krate) = ctx.krate {
135 let ty = match resolution { 135 let ty = match resolution {
136 PathResolution::TypeParam(param) => param.ty(ctx.db), 136 hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
137 PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), 137 hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
138 _ => return, 138 _ => return,
139 }; 139 };
140 140
141 if let Some(Adt::Enum(e)) = ty.as_adt() { 141 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
142 add_enum_variants(ctx, acc, e); 142 add_enum_variants(ctx, acc, e);
143 } 143 }
144 144
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index e1526b70b..227c08d01 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -2,21 +2,21 @@
2use ide_db::{helpers::FamousDefs, SymbolKind}; 2use ide_db::{helpers::FamousDefs, SymbolKind};
3use syntax::ast::Expr; 3use syntax::ast::Expr;
4 4
5use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions}; 5use crate::{
6 item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
7 Completions,
8};
6 9
7pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 10pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
8 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 11 let missing_fields = match &ctx.completion_location {
9 (None, None) => return None, 12 Some(ImmediateLocation::RecordExpr(record_expr)) => {
10 (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"), 13 let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
11 (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
12 (_, Some(record_lit)) => {
13 let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
14 let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); 14 let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
15 let impl_default_trait = default_trait 15 let impl_default_trait = default_trait
16 .zip(ty) 16 .zip(ty)
17 .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); 17 .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[]));
18 18
19 let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); 19 let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
20 if impl_default_trait && !missing_fields.is_empty() { 20 if impl_default_trait && !missing_fields.is_empty() {
21 let completion_text = "..Default::default()"; 21 let completion_text = "..Default::default()";
22 let mut item = CompletionItem::new( 22 let mut item = CompletionItem::new(
@@ -32,6 +32,10 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
32 32
33 missing_fields 33 missing_fields
34 } 34 }
35 Some(ImmediateLocation::RecordPat(record_pat)) => {
36 ctx.sema.record_pattern_missing_fields(record_pat)
37 }
38 _ => return None,
35 }; 39 };
36 40
37 for (field, ty) in missing_fields { 41 for (field, ty) in missing_fields {
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index ede07f605..9db8516d0 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -14,10 +14,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
14 if ctx.expects_assoc_item() { 14 if ctx.expects_assoc_item() {
15 ctx.scope.process_all_names(&mut |name, def| { 15 ctx.scope.process_all_names(&mut |name, def| {
16 if let ScopeDef::MacroDef(macro_def) = def { 16 if let ScopeDef::MacroDef(macro_def) = def {
17 acc.add_macro(ctx, Some(name.to_string()), macro_def); 17 acc.add_macro(ctx, Some(name.clone()), macro_def);
18 } 18 }
19 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { 19 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
20 acc.add_resolution(ctx, name.to_string(), &def); 20 acc.add_resolution(ctx, name, &def);
21 } 21 }
22 }); 22 });
23 return; 23 return;
@@ -27,7 +27,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
27 cov_mark::hit!(only_completes_modules_in_import); 27 cov_mark::hit!(only_completes_modules_in_import);
28 ctx.scope.process_all_names(&mut |name, res| { 28 ctx.scope.process_all_names(&mut |name, res| {
29 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { 29 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
30 acc.add_resolution(ctx, name.to_string(), &res); 30 acc.add_resolution(ctx, name, &res);
31 } 31 }
32 }); 32 });
33 return; 33 return;
@@ -45,7 +45,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
45 cov_mark::hit!(skip_lifetime_completion); 45 cov_mark::hit!(skip_lifetime_completion);
46 return; 46 return;
47 } 47 }
48 acc.add_resolution(ctx, name.to_string(), &res); 48 acc.add_resolution(ctx, name, &res);
49 }); 49 });
50} 50}
51 51
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 8d6440cb2..7c46c815d 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -18,7 +18,7 @@ use text_edit::Indel;
18use crate::{ 18use crate::{
19 patterns::{ 19 patterns::{
20 determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block, 20 determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block,
21 is_in_loop_body, is_match_arm, previous_token, ImmediateLocation, ImmediatePrevSibling, 21 is_in_loop_body, previous_token, ImmediateLocation, ImmediatePrevSibling,
22 }, 22 },
23 CompletionConfig, 23 CompletionConfig,
24}; 24};
@@ -54,11 +54,6 @@ pub(crate) struct CompletionContext<'a> {
54 /// The parent impl of the cursor position if it exists. 54 /// The parent impl of the cursor position if it exists.
55 pub(super) impl_def: Option<ast::Impl>, 55 pub(super) impl_def: Option<ast::Impl>,
56 56
57 /// RecordExpr the token is a field of
58 pub(super) record_lit_syntax: Option<ast::RecordExpr>,
59 /// RecordPat the token is a field of
60 pub(super) record_pat_syntax: Option<ast::RecordPat>,
61
62 // potentially set if we are completing a lifetime 57 // potentially set if we are completing a lifetime
63 pub(super) lifetime_syntax: Option<ast::Lifetime>, 58 pub(super) lifetime_syntax: Option<ast::Lifetime>,
64 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, 59 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -71,6 +66,7 @@ pub(crate) struct CompletionContext<'a> {
71 66
72 pub(super) completion_location: Option<ImmediateLocation>, 67 pub(super) completion_location: Option<ImmediateLocation>,
73 pub(super) prev_sibling: Option<ImmediatePrevSibling>, 68 pub(super) prev_sibling: Option<ImmediatePrevSibling>,
69 pub(super) attribute_under_caret: Option<ast::Attr>,
74 70
75 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 71 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
76 pub(super) active_parameter: Option<ActiveParameter>, 72 pub(super) active_parameter: Option<ActiveParameter>,
@@ -95,14 +91,10 @@ pub(crate) struct CompletionContext<'a> {
95 pub(super) is_macro_call: bool, 91 pub(super) is_macro_call: bool,
96 pub(super) is_path_type: bool, 92 pub(super) is_path_type: bool,
97 pub(super) has_type_args: bool, 93 pub(super) has_type_args: bool,
98 pub(super) attribute_under_caret: Option<ast::Attr>,
99 pub(super) mod_declaration_under_caret: Option<ast::Module>,
100 pub(super) locals: Vec<(String, Local)>, 94 pub(super) locals: Vec<(String, Local)>,
101 95
102 // keyword patterns
103 pub(super) previous_token: Option<SyntaxToken>, 96 pub(super) previous_token: Option<SyntaxToken>,
104 pub(super) in_loop_body: bool, 97 pub(super) in_loop_body: bool,
105 pub(super) is_match_arm: bool,
106 pub(super) incomplete_let: bool, 98 pub(super) incomplete_let: bool,
107 99
108 no_completion_required: bool, 100 no_completion_required: bool,
@@ -157,8 +149,6 @@ impl<'a> CompletionContext<'a> {
157 lifetime_param_syntax: None, 149 lifetime_param_syntax: None,
158 function_def: None, 150 function_def: None,
159 use_item_syntax: None, 151 use_item_syntax: None,
160 record_lit_syntax: None,
161 record_pat_syntax: None,
162 impl_def: None, 152 impl_def: None,
163 active_parameter: ActiveParameter::at(db, position), 153 active_parameter: ActiveParameter::at(db, position),
164 is_label_ref: false, 154 is_label_ref: false,
@@ -176,15 +166,13 @@ impl<'a> CompletionContext<'a> {
176 is_macro_call: false, 166 is_macro_call: false,
177 is_path_type: false, 167 is_path_type: false,
178 has_type_args: false, 168 has_type_args: false,
179 attribute_under_caret: None,
180 mod_declaration_under_caret: None,
181 previous_token: None, 169 previous_token: None,
182 in_loop_body: false, 170 in_loop_body: false,
183 completion_location: None, 171 completion_location: None,
184 prev_sibling: None, 172 prev_sibling: None,
185 is_match_arm: false,
186 no_completion_required: false, 173 no_completion_required: false,
187 incomplete_let: false, 174 incomplete_let: false,
175 attribute_under_caret: None,
188 locals, 176 locals,
189 }; 177 };
190 178
@@ -227,7 +215,6 @@ impl<'a> CompletionContext<'a> {
227 break; 215 break;
228 } 216 }
229 } 217 }
230 ctx.fill_keyword_patterns(&speculative_file, offset);
231 ctx.fill(&original_file, speculative_file, offset); 218 ctx.fill(&original_file, speculative_file, offset);
232 Some(ctx) 219 Some(ctx)
233 } 220 }
@@ -311,31 +298,13 @@ impl<'a> CompletionContext<'a> {
311 } 298 }
312 299
313 pub(crate) fn is_path_disallowed(&self) -> bool { 300 pub(crate) fn is_path_disallowed(&self) -> bool {
314 self.record_lit_syntax.is_some() 301 matches!(
315 || self.record_pat_syntax.is_some() 302 self.completion_location,
316 || self.attribute_under_caret.is_some() 303 Some(ImmediateLocation::Attribute(_))
317 || self.mod_declaration_under_caret.is_some() 304 | Some(ImmediateLocation::ModDeclaration(_))
318 } 305 | Some(ImmediateLocation::RecordPat(_))
319 306 | Some(ImmediateLocation::RecordExpr(_))
320 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 307 ) || self.attribute_under_caret.is_some()
321 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
322 let syntax_element = NodeOrToken::Token(fake_ident_token);
323 self.previous_token = previous_token(syntax_element.clone());
324 self.in_loop_body = is_in_loop_body(syntax_element.clone());
325 self.is_match_arm = is_match_arm(syntax_element.clone());
326
327 self.mod_declaration_under_caret =
328 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
329 .filter(|module| module.item_list().is_none());
330 self.incomplete_let =
331 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
332 it.syntax().text_range().end() == syntax_element.text_range().end()
333 });
334
335 let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
336 let fn_is_prev = self.previous_token_is(T![fn]);
337 let for_is_prev2 = for_is_prev2(syntax_element.clone());
338 self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2;
339 } 308 }
340 309
341 fn fill_impl_def(&mut self) { 310 fn fill_impl_def(&mut self) {
@@ -453,25 +422,43 @@ impl<'a> CompletionContext<'a> {
453 file_with_fake_ident: SyntaxNode, 422 file_with_fake_ident: SyntaxNode,
454 offset: TextSize, 423 offset: TextSize,
455 ) { 424 ) {
425 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
426 let syntax_element = NodeOrToken::Token(fake_ident_token);
427 self.previous_token = previous_token(syntax_element.clone());
428 self.attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
429 self.no_completion_required = {
430 let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
431 let fn_is_prev = self.previous_token_is(T![fn]);
432 let for_is_prev2 = for_is_prev2(syntax_element.clone());
433 (fn_is_prev && !inside_impl_trait_block) || for_is_prev2
434 };
435 self.in_loop_body = is_in_loop_body(syntax_element.clone());
436
437 self.incomplete_let =
438 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
439 it.syntax().text_range().end() == syntax_element.text_range().end()
440 });
441
456 let (expected_type, expected_name) = self.expected_type_and_name(); 442 let (expected_type, expected_name) = self.expected_type_and_name();
457 self.expected_type = expected_type; 443 self.expected_type = expected_type;
458 self.expected_name = expected_name; 444 self.expected_name = expected_name;
459 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); 445
460 let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { 446 let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) {
461 Some(it) => it, 447 Some(it) => it,
462 None => return, 448 None => return,
463 }; 449 };
464 self.completion_location = determine_location(&name_like); 450 self.completion_location =
451 determine_location(&self.sema, original_file, offset, &name_like);
465 self.prev_sibling = determine_prev_sibling(&name_like); 452 self.prev_sibling = determine_prev_sibling(&name_like);
466 match name_like { 453 match name_like {
467 ast::NameLike::Lifetime(lifetime) => { 454 ast::NameLike::Lifetime(lifetime) => {
468 self.classify_lifetime(original_file, lifetime, offset); 455 self.classify_lifetime(original_file, lifetime, offset);
469 } 456 }
470 ast::NameLike::NameRef(name_ref) => { 457 ast::NameLike::NameRef(name_ref) => {
471 self.classify_name_ref(original_file, name_ref, offset); 458 self.classify_name_ref(original_file, name_ref);
472 } 459 }
473 ast::NameLike::Name(name) => { 460 ast::NameLike::Name(name) => {
474 self.classify_name(original_file, name, offset); 461 self.classify_name(name);
475 } 462 }
476 } 463 }
477 } 464 }
@@ -505,7 +492,7 @@ impl<'a> CompletionContext<'a> {
505 } 492 }
506 } 493 }
507 494
508 fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) { 495 fn classify_name(&mut self, name: ast::Name) {
509 if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { 496 if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
510 self.is_pat_or_const = Some(PatternRefutability::Refutable); 497 self.is_pat_or_const = Some(PatternRefutability::Refutable);
511 // if any of these is here our bind pat can't be a const pat anymore 498 // if any of these is here our bind pat can't be a const pat anymore
@@ -543,28 +530,12 @@ impl<'a> CompletionContext<'a> {
543 530
544 self.fill_impl_def(); 531 self.fill_impl_def();
545 } 532 }
533
546 self.is_param |= is_node::<ast::Param>(name.syntax()); 534 self.is_param |= is_node::<ast::Param>(name.syntax());
547 if ast::RecordPatField::for_field_name(&name).is_some() {
548 self.record_pat_syntax =
549 self.sema.find_node_at_offset_with_macros(&original_file, offset);
550 }
551 } 535 }
552 536
553 fn classify_name_ref( 537 fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
554 &mut self,
555 original_file: &SyntaxNode,
556 name_ref: ast::NameRef,
557 offset: TextSize,
558 ) {
559 self.fill_impl_def(); 538 self.fill_impl_def();
560 if ast::RecordExprField::for_field_name(&name_ref).is_some() {
561 self.record_lit_syntax =
562 self.sema.find_node_at_offset_with_macros(original_file, offset);
563 }
564 if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() {
565 self.record_pat_syntax =
566 self.sema.find_node_at_offset_with_macros(&original_file, offset);
567 }
568 539
569 self.name_ref_syntax = 540 self.name_ref_syntax =
570 find_node_at_offset(original_file, name_ref.syntax().text_range().start()); 541 find_node_at_offset(original_file, name_ref.syntax().text_range().start());
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index caf0ef39f..26516046b 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -1,15 +1,18 @@
1//! Patterns telling us certain facts about current syntax element, they are used in completion context 1//! Patterns telling us certain facts about current syntax element, they are used in completion context
2 2
3use hir::Semantics;
4use ide_db::RootDatabase;
3use syntax::{ 5use syntax::{
4 algo::non_trivia_sibling, 6 algo::non_trivia_sibling,
5 ast::{self, LoopBodyOwner}, 7 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, 8 match_ast, AstNode, Direction, SyntaxElement,
7 SyntaxKind::*, 9 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, T, 10 SyntaxNode, SyntaxToken, TextSize, T,
9}; 11};
10 12
11#[cfg(test)] 13#[cfg(test)]
12use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; 14use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable};
15
13/// Direct parent container of the cursor position 16/// Direct parent container of the cursor position
14#[derive(Copy, Clone, Debug, PartialEq, Eq)] 17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub(crate) enum ImmediatePrevSibling { 18pub(crate) enum ImmediatePrevSibling {
@@ -19,7 +22,7 @@ pub(crate) enum ImmediatePrevSibling {
19} 22}
20 23
21/// Direct parent container of the cursor position 24/// Direct parent container of the cursor position
22#[derive(Copy, Clone, Debug, PartialEq, Eq)] 25#[derive(Clone, Debug, PartialEq, Eq)]
23pub(crate) enum ImmediateLocation { 26pub(crate) enum ImmediateLocation {
24 Use, 27 Use,
25 Impl, 28 Impl,
@@ -29,10 +32,24 @@ pub(crate) enum ImmediateLocation {
29 IdentPat, 32 IdentPat,
30 BlockExpr, 33 BlockExpr,
31 ItemList, 34 ItemList,
35 // Fake file ast node
36 Attribute(ast::Attr),
37 // Fake file ast node
38 ModDeclaration(ast::Module),
39 // Original file ast node
40 /// The record expr of the field name we are completing
41 RecordExpr(ast::RecordExpr),
42 // Original file ast node
43 /// The record pat of the field name we are completing
44 RecordPat(ast::RecordPat),
32} 45}
33 46
34pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> { 47pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> {
35 let node = maximize_name_ref(name_like)?; 48 let node = match name_like {
49 ast::NameLike::NameRef(name_ref) => maximize_name_ref(name_ref),
50 ast::NameLike::Name(n) => n.syntax().clone(),
51 ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
52 };
36 let node = match node.parent().and_then(ast::MacroCall::cast) { 53 let node = match node.parent().and_then(ast::MacroCall::cast) {
37 // When a path is being typed after the name of a trait/type of an impl it is being 54 // When a path is being typed after the name of a trait/type of an impl it is being
38 // parsed as a macro, so when the trait/impl has a block following it an we are between the 55 // parsed as a macro, so when the trait/impl has a block following it an we are between the
@@ -77,8 +94,37 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi
77 Some(res) 94 Some(res)
78} 95}
79 96
80pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateLocation> { 97pub(crate) fn determine_location(
81 let node = maximize_name_ref(name_like)?; 98 sema: &Semantics<RootDatabase>,
99 original_file: &SyntaxNode,
100 offset: TextSize,
101 name_like: &ast::NameLike,
102) -> Option<ImmediateLocation> {
103 let node = match name_like {
104 ast::NameLike::NameRef(name_ref) => {
105 if ast::RecordExprField::for_field_name(&name_ref).is_some() {
106 return sema
107 .find_node_at_offset_with_macros(original_file, offset)
108 .map(ImmediateLocation::RecordExpr);
109 }
110 if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() {
111 return sema
112 .find_node_at_offset_with_macros(original_file, offset)
113 .map(ImmediateLocation::RecordPat);
114 }
115 maximize_name_ref(name_ref)
116 }
117 ast::NameLike::Name(name) => {
118 if ast::RecordPatField::for_field_name(&name).is_some() {
119 return sema
120 .find_node_at_offset_with_macros(original_file, offset)
121 .map(ImmediateLocation::RecordPat);
122 }
123 name.syntax().clone()
124 }
125 ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
126 };
127
82 let parent = match node.parent() { 128 let parent = match node.parent() {
83 Some(parent) => match ast::MacroCall::cast(parent.clone()) { 129 Some(parent) => match ast::MacroCall::cast(parent.clone()) {
84 // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call. 130 // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call.
@@ -103,6 +149,7 @@ pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateL
103 } 149 }
104 } 150 }
105 }; 151 };
152
106 let res = match_ast! { 153 let res = match_ast! {
107 match parent { 154 match parent {
108 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 155 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
@@ -117,36 +164,34 @@ pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateL
117 Some(TRAIT) => ImmediateLocation::Trait, 164 Some(TRAIT) => ImmediateLocation::Trait,
118 _ => return None, 165 _ => return None,
119 }, 166 },
167 ast::Module(it) => if it.item_list().is_none() {
168 ImmediateLocation::ModDeclaration(it)
169 } else {
170 return None
171 },
172 ast::Attr(it) => ImmediateLocation::Attribute(it),
120 _ => return None, 173 _ => return None,
121 } 174 }
122 }; 175 };
123 Some(res) 176 Some(res)
124} 177}
125 178
126fn maximize_name_ref(name_like: &ast::NameLike) -> Option<SyntaxNode> { 179fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode {
127 // First walk the element we are completing up to its highest node that has the same text range 180 // Maximize a nameref to its enclosing path if its the last segment of said path
128 // as the element so that we can check in what context it immediately lies. We only do this for 181 if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
129 // NameRef -> Path as that's the only thing that makes sense to being "expanded" semantically. 182 let p = segment.parent_path();
130 // We only wanna do this if the NameRef is the last segment of the path. 183 if p.parent_path().is_none() {
131 let node = match name_like { 184 if let Some(it) = p
132 ast::NameLike::NameRef(name_ref) => { 185 .syntax()
133 if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) { 186 .ancestors()
134 let p = segment.parent_path(); 187 .take_while(|it| it.text_range() == p.syntax().text_range())
135 if p.parent_path().is_none() { 188 .last()
136 p.syntax() 189 {
137 .ancestors() 190 return it;
138 .take_while(|it| it.text_range() == p.syntax().text_range())
139 .last()?
140 } else {
141 return None;
142 }
143 } else {
144 return None;
145 } 191 }
146 } 192 }
147 it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(), 193 }
148 }; 194 name_ref.syntax().clone()
149 Some(node)
150} 195}
151 196
152pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { 197pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
@@ -167,18 +212,6 @@ fn test_inside_impl_trait_block() {
167 check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block); 212 check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block);
168} 213}
169 214
170pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
171 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
172 && previous_sibling_or_ancestor_sibling(element)
173 .and_then(|it| it.into_token())
174 .filter(|it| it.kind() == FAT_ARROW)
175 .is_some()
176}
177#[test]
178fn test_is_match_arm() {
179 check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm);
180}
181
182pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { 215pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
183 element.into_token().and_then(|it| previous_non_trivia_token(it)) 216 element.into_token().and_then(|it| previous_non_trivia_token(it))
184} 217}
@@ -216,10 +249,6 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
216 .is_some() 249 .is_some()
217} 250}
218 251
219pub(crate) fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
220 element.ancestors().skip_while(|it| it.text_range() == element.text_range()).next()
221}
222
223fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { 252fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
224 let mut token = token.prev_token(); 253 let mut token = token.prev_token();
225 while let Some(inner) = token.clone() { 254 while let Some(inner) = token.clone() {
@@ -232,31 +261,25 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
232 None 261 None
233} 262}
234 263
235fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
236 let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
237 if let Some(sibling) = token_sibling {
238 Some(sibling)
239 } else {
240 // if not trying to find first ancestor which has such a sibling
241 let range = element.text_range();
242 let top_node = element.ancestors().take_while(|it| it.text_range() == range).last()?;
243 let prev_sibling_node = top_node.ancestors().find(|it| {
244 non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
245 })?;
246 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
247 }
248}
249
250#[cfg(test)] 264#[cfg(test)]
251mod tests { 265mod tests {
266 use syntax::algo::find_node_at_offset;
267
268 use crate::test_utils::position;
269
252 use super::*; 270 use super::*;
253 271
254 fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) { 272 fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) {
255 check_pattern_is_applicable(code, |e| { 273 let (db, pos) = position(code);
256 let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); 274
257 assert_eq!(determine_location(name), loc.into()); 275 let sema = Semantics::new(&db);
258 true 276 let original_file = sema.parse(pos.file_id);
259 }); 277
278 let name_like = find_node_at_offset(original_file.syntax(), pos.offset).unwrap();
279 assert_eq!(
280 determine_location(&sema, original_file.syntax(), pos.offset, &name_like),
281 loc.into()
282 );
260 } 283 }
261 284
262 fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) { 285 fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 91300c56e..425dd0247 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -10,9 +10,7 @@ pub(crate) mod type_alias;
10 10
11mod builder_ext; 11mod builder_ext;
12 12
13use hir::{ 13use hir::{AsAssocItem, HasAttrs, HirDisplay};
14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15};
16use ide_db::{ 14use ide_db::{
17 helpers::{item_name, SnippetCap}, 15 helpers::{item_name, SnippetCap},
18 RootDatabase, SymbolKind, 16 RootDatabase, SymbolKind,
@@ -21,31 +19,30 @@ use syntax::TextRange;
21 19
22use crate::{ 20use crate::{
23 item::{CompletionRelevanceTypeMatch, ImportEdit}, 21 item::{CompletionRelevanceTypeMatch, ImportEdit},
22 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 23 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
25}; 24};
26 25
27use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
28
29pub(crate) fn render_field<'a>( 26pub(crate) fn render_field<'a>(
30 ctx: RenderContext<'a>, 27 ctx: RenderContext<'a>,
31 field: hir::Field, 28 field: hir::Field,
32 ty: &Type, 29 ty: &hir::Type,
33) -> CompletionItem { 30) -> CompletionItem {
34 Render::new(ctx).add_field(field, ty) 31 Render::new(ctx).render_field(field, ty)
35} 32}
36 33
37pub(crate) fn render_tuple_field<'a>( 34pub(crate) fn render_tuple_field<'a>(
38 ctx: RenderContext<'a>, 35 ctx: RenderContext<'a>,
39 field: usize, 36 field: usize,
40 ty: &Type, 37 ty: &hir::Type,
41) -> CompletionItem { 38) -> CompletionItem {
42 Render::new(ctx).add_tuple_field(field, ty) 39 Render::new(ctx).render_tuple_field(field, ty)
43} 40}
44 41
45pub(crate) fn render_resolution<'a>( 42pub(crate) fn render_resolution<'a>(
46 ctx: RenderContext<'a>, 43 ctx: RenderContext<'a>,
47 local_name: String, 44 local_name: hir::Name,
48 resolution: &ScopeDef, 45 resolution: &hir::ScopeDef,
49) -> Option<CompletionItem> { 46) -> Option<CompletionItem> {
50 Render::new(ctx).render_resolution(local_name, None, resolution) 47 Render::new(ctx).render_resolution(local_name, None, resolution)
51} 48}
@@ -54,12 +51,12 @@ pub(crate) fn render_resolution_with_import<'a>(
54 ctx: RenderContext<'a>, 51 ctx: RenderContext<'a>,
55 import_edit: ImportEdit, 52 import_edit: ImportEdit,
56) -> Option<CompletionItem> { 53) -> Option<CompletionItem> {
57 let resolution = ScopeDef::from(import_edit.import.original_item); 54 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
58 let local_name = match resolution { 55 let local_name = match resolution {
59 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), 56 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
60 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), 57 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
61 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), 58 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
62 _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(), 59 _ => item_name(ctx.db(), import_edit.import.original_item)?,
63 }; 60 };
64 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( 61 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map(
65 |mut item| { 62 |mut item| {
@@ -113,7 +110,7 @@ impl<'a> RenderContext<'a> {
113 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) 110 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false)
114 } 111 }
115 112
116 fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { 113 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
117 node.docs(self.db()) 114 node.docs(self.db())
118 } 115 }
119} 116}
@@ -129,14 +126,11 @@ impl<'a> Render<'a> {
129 Render { ctx } 126 Render { ctx }
130 } 127 }
131 128
132 fn add_field(&mut self, field: hir::Field, ty: &Type) -> CompletionItem { 129 fn render_field(&self, field: hir::Field, ty: &hir::Type) -> CompletionItem {
133 let is_deprecated = self.ctx.is_deprecated(field); 130 let is_deprecated = self.ctx.is_deprecated(field);
134 let name = field.name(self.ctx.db()); 131 let name = field.name(self.ctx.db()).to_string();
135 let mut item = CompletionItem::new( 132 let mut item =
136 CompletionKind::Reference, 133 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
137 self.ctx.source_range(),
138 name.to_string(),
139 );
140 item.kind(SymbolKind::Field) 134 item.kind(SymbolKind::Field)
141 .detail(ty.display(self.ctx.db()).to_string()) 135 .detail(ty.display(self.ctx.db()).to_string())
142 .set_documentation(field.docs(self.ctx.db())) 136 .set_documentation(field.docs(self.ctx.db()))
@@ -144,7 +138,7 @@ impl<'a> Render<'a> {
144 138
145 item.set_relevance(CompletionRelevance { 139 item.set_relevance(CompletionRelevance {
146 type_match: compute_type_match(self.ctx.completion, ty), 140 type_match: compute_type_match(self.ctx.completion, ty),
147 exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()), 141 exact_name_match: compute_exact_name_match(self.ctx.completion, &name),
148 ..CompletionRelevance::default() 142 ..CompletionRelevance::default()
149 }); 143 });
150 144
@@ -157,7 +151,7 @@ impl<'a> Render<'a> {
157 item.build() 151 item.build()
158 } 152 }
159 153
160 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem { 154 fn render_tuple_field(&self, field: usize, ty: &hir::Type) -> CompletionItem {
161 let mut item = CompletionItem::new( 155 let mut item = CompletionItem::new(
162 CompletionKind::Reference, 156 CompletionKind::Reference,
163 self.ctx.source_range(), 157 self.ctx.source_range(),
@@ -171,71 +165,82 @@ impl<'a> Render<'a> {
171 165
172 fn render_resolution( 166 fn render_resolution(
173 self, 167 self,
174 local_name: String, 168 local_name: hir::Name,
175 import_to_add: Option<ImportEdit>, 169 import_to_add: Option<ImportEdit>,
176 resolution: &ScopeDef, 170 resolution: &hir::ScopeDef,
177 ) -> Option<CompletionItem> { 171 ) -> Option<CompletionItem> {
178 let _p = profile::span("render_resolution"); 172 let _p = profile::span("render_resolution");
179 use hir::ModuleDef::*; 173 use hir::ModuleDef::*;
180 174
181 let completion_kind = match resolution { 175 let completion_kind = match resolution {
182 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, 176 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
183 _ => CompletionKind::Reference, 177 _ => CompletionKind::Reference,
184 }; 178 };
185 179
186 let kind = match resolution { 180 let kind = match resolution {
187 ScopeDef::ModuleDef(Function(func)) => { 181 hir::ScopeDef::ModuleDef(Function(func)) => {
188 return render_fn(self.ctx, import_to_add, Some(local_name), *func); 182 return render_fn(self.ctx, import_to_add, Some(local_name), *func);
189 } 183 }
190 ScopeDef::ModuleDef(Variant(_)) if self.ctx.completion.is_pat_or_const.is_some() => { 184 hir::ScopeDef::ModuleDef(Variant(_))
185 if self.ctx.completion.is_pat_or_const.is_some() =>
186 {
191 CompletionItemKind::SymbolKind(SymbolKind::Variant) 187 CompletionItemKind::SymbolKind(SymbolKind::Variant)
192 } 188 }
193 ScopeDef::ModuleDef(Variant(var)) => { 189 hir::ScopeDef::ModuleDef(Variant(var)) => {
194 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 190 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None);
195 return Some(item); 191 return Some(item);
196 } 192 }
197 ScopeDef::MacroDef(mac) => { 193 hir::ScopeDef::MacroDef(mac) => {
198 let item = render_macro(self.ctx, import_to_add, local_name, *mac); 194 let item = render_macro(self.ctx, import_to_add, local_name, *mac);
199 return item; 195 return item;
200 } 196 }
201 197
202 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), 198 hir::ScopeDef::ModuleDef(Module(..)) => {
203 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { 199 CompletionItemKind::SymbolKind(SymbolKind::Module)
200 }
201 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
204 hir::Adt::Struct(_) => SymbolKind::Struct, 202 hir::Adt::Struct(_) => SymbolKind::Struct,
205 hir::Adt::Union(_) => SymbolKind::Union, 203 hir::Adt::Union(_) => SymbolKind::Union,
206 hir::Adt::Enum(_) => SymbolKind::Enum, 204 hir::Adt::Enum(_) => SymbolKind::Enum,
207 }), 205 }),
208 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), 206 hir::ScopeDef::ModuleDef(Const(..)) => {
209 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static), 207 CompletionItemKind::SymbolKind(SymbolKind::Const)
210 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait), 208 }
211 ScopeDef::ModuleDef(TypeAlias(..)) => { 209 hir::ScopeDef::ModuleDef(Static(..)) => {
210 CompletionItemKind::SymbolKind(SymbolKind::Static)
211 }
212 hir::ScopeDef::ModuleDef(Trait(..)) => {
213 CompletionItemKind::SymbolKind(SymbolKind::Trait)
214 }
215 hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
212 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) 216 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
213 } 217 }
214 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 218 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
215 ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { 219 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
216 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, 220 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
217 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, 221 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
218 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, 222 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
219 }), 223 }),
220 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), 224 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
221 ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), 225 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
222 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => { 226 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
223 CompletionItemKind::SymbolKind(SymbolKind::SelfParam) 227 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
224 } 228 }
225 ScopeDef::Unknown => { 229 hir::ScopeDef::Unknown => {
226 let mut item = CompletionItem::new( 230 let mut item = CompletionItem::new(
227 CompletionKind::Reference, 231 CompletionKind::Reference,
228 self.ctx.source_range(), 232 self.ctx.source_range(),
229 local_name, 233 local_name.to_string(),
230 ); 234 );
231 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add); 235 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
232 return Some(item.build()); 236 return Some(item.build());
233 } 237 }
234 }; 238 };
235 239
240 let local_name = local_name.to_string();
236 let mut item = 241 let mut item =
237 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 242 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone());
238 if let ScopeDef::Local(local) = resolution { 243 if let hir::ScopeDef::Local(local) = resolution {
239 let ty = local.ty(self.ctx.db()); 244 let ty = local.ty(self.ctx.db());
240 if !ty.is_unknown() { 245 if !ty.is_unknown() {
241 item.detail(ty.display(self.ctx.db()).to_string()); 246 item.detail(ty.display(self.ctx.db()).to_string());
@@ -260,8 +265,10 @@ impl<'a> Render<'a> {
260 { 265 {
261 if let Some(cap) = self.ctx.snippet_cap() { 266 if let Some(cap) = self.ctx.snippet_cap() {
262 let has_non_default_type_params = match resolution { 267 let has_non_default_type_params = match resolution {
263 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(self.ctx.db()), 268 hir::ScopeDef::ModuleDef(Adt(it)) => {
264 ScopeDef::ModuleDef(TypeAlias(it)) => { 269 it.has_non_default_type_params(self.ctx.db())
270 }
271 hir::ScopeDef::ModuleDef(TypeAlias(it)) => {
265 it.has_non_default_type_params(self.ctx.db()) 272 it.has_non_default_type_params(self.ctx.db())
266 } 273 }
267 _ => false, 274 _ => false,
@@ -281,26 +288,26 @@ impl<'a> Render<'a> {
281 Some(item.build()) 288 Some(item.build())
282 } 289 }
283 290
284 fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { 291 fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
285 use hir::ModuleDef::*; 292 use hir::ModuleDef::*;
286 match resolution { 293 match resolution {
287 ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), 294 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()),
288 ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), 295 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()),
289 ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), 296 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()),
290 ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), 297 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()),
291 ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), 298 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()),
292 ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), 299 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()),
293 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), 300 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()),
294 _ => None, 301 _ => None,
295 } 302 }
296 } 303 }
297 304
298 fn is_deprecated(&self, resolution: &ScopeDef) -> bool { 305 fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool {
299 match resolution { 306 match resolution {
300 ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), 307 hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it),
301 ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), 308 hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it),
302 ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), 309 hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it),
303 ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), 310 hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it),
304 _ => false, 311 _ => false,
305 } 312 }
306 } 313 }
@@ -327,21 +334,23 @@ fn compute_type_match(
327 } 334 }
328} 335}
329 336
330fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool { 337fn compute_exact_name_match(ctx: &CompletionContext, completion_name: &str) -> bool {
331 let completion_name = completion_name.into();
332 ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name) 338 ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name)
333} 339}
334 340
335fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> { 341fn compute_ref_match(
342 ctx: &CompletionContext,
343 completion_ty: &hir::Type,
344) -> Option<hir::Mutability> {
336 let expected_type = ctx.expected_type.as_ref()?; 345 let expected_type = ctx.expected_type.as_ref()?;
337 if completion_ty != expected_type { 346 if completion_ty != expected_type {
338 let expected_type_without_ref = expected_type.remove_ref()?; 347 let expected_type_without_ref = expected_type.remove_ref()?;
339 if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) { 348 if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
340 cov_mark::hit!(suggest_ref); 349 cov_mark::hit!(suggest_ref);
341 let mutability = if expected_type.is_mutable_reference() { 350 let mutability = if expected_type.is_mutable_reference() {
342 Mutability::Mut 351 hir::Mutability::Mut
343 } else { 352 } else {
344 Mutability::Shared 353 hir::Mutability::Shared
345 }; 354 };
346 return Some(mutability); 355 return Some(mutability);
347 }; 356 };
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
index 0c0c71134..28f056e77 100644
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ b/crates/ide_completion/src/render/enum_variant.rs
@@ -1,6 +1,8 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use std::iter;
4
5use hir::{HasAttrs, HirDisplay};
4use ide_db::SymbolKind; 6use ide_db::SymbolKind;
5use itertools::Itertools; 7use itertools::Itertools;
6 8
@@ -13,9 +15,9 @@ use crate::{
13pub(crate) fn render_variant<'a>( 15pub(crate) fn render_variant<'a>(
14 ctx: RenderContext<'a>, 16 ctx: RenderContext<'a>,
15 import_to_add: Option<ImportEdit>, 17 import_to_add: Option<ImportEdit>,
16 local_name: Option<String>, 18 local_name: Option<hir::Name>,
17 variant: hir::Variant, 19 variant: hir::Variant,
18 path: Option<ModPath>, 20 path: Option<hir::ModPath>,
19) -> CompletionItem { 21) -> CompletionItem {
20 let _p = profile::span("render_enum_variant"); 22 let _p = profile::span("render_enum_variant");
21 EnumRender::new(ctx, local_name, variant, path).render(import_to_add) 23 EnumRender::new(ctx, local_name, variant, path).render(import_to_add)
@@ -24,42 +26,45 @@ pub(crate) fn render_variant<'a>(
24#[derive(Debug)] 26#[derive(Debug)]
25struct EnumRender<'a> { 27struct EnumRender<'a> {
26 ctx: RenderContext<'a>, 28 ctx: RenderContext<'a>,
27 name: String, 29 name: hir::Name,
28 variant: hir::Variant, 30 variant: hir::Variant,
29 path: Option<ModPath>, 31 path: Option<hir::ModPath>,
30 qualified_name: String, 32 qualified_name: hir::ModPath,
31 short_qualified_name: String, 33 short_qualified_name: hir::ModPath,
32 variant_kind: StructKind, 34 variant_kind: hir::StructKind,
33} 35}
34 36
35impl<'a> EnumRender<'a> { 37impl<'a> EnumRender<'a> {
36 fn new( 38 fn new(
37 ctx: RenderContext<'a>, 39 ctx: RenderContext<'a>,
38 local_name: Option<String>, 40 local_name: Option<hir::Name>,
39 variant: hir::Variant, 41 variant: hir::Variant,
40 path: Option<ModPath>, 42 path: Option<hir::ModPath>,
41 ) -> EnumRender<'a> { 43 ) -> EnumRender<'a> {
42 let name = local_name.unwrap_or_else(|| variant.name(ctx.db()).to_string()); 44 let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
43 let variant_kind = variant.kind(ctx.db()); 45 let variant_kind = variant.kind(ctx.db());
44 46
45 let (qualified_name, short_qualified_name) = match &path { 47 let (qualified_name, short_qualified_name) = match &path {
46 Some(path) => { 48 Some(path) => {
47 let full = path.to_string(); 49 let short = hir::ModPath::from_segments(
48 let segments = path.segments(); 50 hir::PathKind::Plain,
49 let short = segments[segments.len().saturating_sub(2)..].iter().join("::"); 51 path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
50 (full, short) 52 );
53 (path.clone(), short)
51 } 54 }
52 None => (name.to_string(), name.to_string()), 55 None => (
56 hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
57 hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())),
58 ),
53 }; 59 };
54 60
55 EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind } 61 EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind }
56 } 62 }
57
58 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { 63 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
59 let mut item = CompletionItem::new( 64 let mut item = CompletionItem::new(
60 CompletionKind::Reference, 65 CompletionKind::Reference,
61 self.ctx.source_range(), 66 self.ctx.source_range(),
62 self.qualified_name.clone(), 67 self.qualified_name.to_string(),
63 ); 68 );
64 item.kind(SymbolKind::Variant) 69 item.kind(SymbolKind::Variant)
65 .set_documentation(self.variant.docs(self.ctx.db())) 70 .set_documentation(self.variant.docs(self.ctx.db()))
@@ -67,12 +72,16 @@ impl<'a> EnumRender<'a> {
67 .add_import(import_to_add) 72 .add_import(import_to_add)
68 .detail(self.detail()); 73 .detail(self.detail());
69 74
70 if self.variant_kind == StructKind::Tuple { 75 if self.variant_kind == hir::StructKind::Tuple {
71 cov_mark::hit!(inserts_parens_for_tuple_enums); 76 cov_mark::hit!(inserts_parens_for_tuple_enums);
72 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); 77 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len());
73 item.add_call_parens(self.ctx.completion, self.short_qualified_name, params); 78 item.add_call_parens(
79 self.ctx.completion,
80 self.short_qualified_name.to_string(),
81 params,
82 );
74 } else if self.path.is_some() { 83 } else if self.path.is_some() {
75 item.lookup_by(self.short_qualified_name); 84 item.lookup_by(self.short_qualified_name.to_string());
76 } 85 }
77 86
78 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); 87 let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
@@ -96,11 +105,11 @@ impl<'a> EnumRender<'a> {
96 .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db()))); 105 .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db())));
97 106
98 match self.variant_kind { 107 match self.variant_kind {
99 StructKind::Tuple | StructKind::Unit => format!( 108 hir::StructKind::Tuple | hir::StructKind::Unit => format!(
100 "({})", 109 "({})",
101 detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") 110 detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ")
102 ), 111 ),
103 StructKind::Record => format!( 112 hir::StructKind::Record => format!(
104 "{{ {} }}", 113 "{{ {} }}",
105 detail_types 114 detail_types
106 .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) 115 .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string()))
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index d681e2c91..63bd66926 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -1,6 +1,6 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, HirDisplay, Type}; 3use hir::{HasSource, HirDisplay};
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use itertools::Itertools; 5use itertools::Itertools;
6use syntax::ast::Fn; 6use syntax::ast::Fn;
@@ -16,7 +16,7 @@ use crate::{
16pub(crate) fn render_fn<'a>( 16pub(crate) fn render_fn<'a>(
17 ctx: RenderContext<'a>, 17 ctx: RenderContext<'a>,
18 import_to_add: Option<ImportEdit>, 18 import_to_add: Option<ImportEdit>,
19 local_name: Option<String>, 19 local_name: Option<hir::Name>,
20 fn_: hir::Function, 20 fn_: hir::Function,
21) -> Option<CompletionItem> { 21) -> Option<CompletionItem> {
22 let _p = profile::span("render_fn"); 22 let _p = profile::span("render_fn");
@@ -26,7 +26,7 @@ pub(crate) fn render_fn<'a>(
26pub(crate) fn render_method<'a>( 26pub(crate) fn render_method<'a>(
27 ctx: RenderContext<'a>, 27 ctx: RenderContext<'a>,
28 import_to_add: Option<ImportEdit>, 28 import_to_add: Option<ImportEdit>,
29 local_name: Option<String>, 29 local_name: Option<hir::Name>,
30 fn_: hir::Function, 30 fn_: hir::Function,
31) -> Option<CompletionItem> { 31) -> Option<CompletionItem> {
32 let _p = profile::span("render_method"); 32 let _p = profile::span("render_method");
@@ -45,11 +45,11 @@ struct FunctionRender<'a> {
45impl<'a> FunctionRender<'a> { 45impl<'a> FunctionRender<'a> {
46 fn new( 46 fn new(
47 ctx: RenderContext<'a>, 47 ctx: RenderContext<'a>,
48 local_name: Option<String>, 48 local_name: Option<hir::Name>,
49 fn_: hir::Function, 49 fn_: hir::Function,
50 is_method: bool, 50 is_method: bool,
51 ) -> Option<FunctionRender<'a>> { 51 ) -> Option<FunctionRender<'a>> {
52 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); 52 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string();
53 let ast_node = fn_.source(ctx.db())?.value; 53 let ast_node = fn_.source(ctx.db())?.value;
54 54
55 Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method }) 55 Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method })
@@ -74,7 +74,7 @@ impl<'a> FunctionRender<'a> {
74 let ret_type = self.func.ret_type(self.ctx.db()); 74 let ret_type = self.func.ret_type(self.ctx.db());
75 item.set_relevance(CompletionRelevance { 75 item.set_relevance(CompletionRelevance {
76 type_match: compute_type_match(self.ctx.completion, &ret_type), 76 type_match: compute_type_match(self.ctx.completion, &ret_type),
77 exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), 77 exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name),
78 ..CompletionRelevance::default() 78 ..CompletionRelevance::default()
79 }); 79 });
80 80
@@ -129,7 +129,7 @@ impl<'a> FunctionRender<'a> {
129 format!("-> {}", ret_ty.display(self.ctx.db())) 129 format!("-> {}", ret_ty.display(self.ctx.db()))
130 } 130 }
131 131
132 fn add_arg(&self, arg: &str, ty: &Type) -> String { 132 fn add_arg(&self, arg: &str, ty: &hir::Type) -> String {
133 if let Some(derefed_ty) = ty.remove_ref() { 133 if let Some(derefed_ty) = ty.remove_ref() {
134 for (name, local) in self.ctx.completion.locals.iter() { 134 for (name, local) in self.ctx.completion.locals.iter() {
135 if name == arg && local.ty(self.ctx.db()) == derefed_ty { 135 if name == arg && local.ty(self.ctx.db()) == derefed_ty {
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index b90fd3890..0dfba8acc 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -1,6 +1,6 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use hir::HasSource;
4use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use syntax::display::macro_label; 5use syntax::display::macro_label;
6 6
@@ -12,7 +12,7 @@ use crate::{
12pub(crate) fn render_macro<'a>( 12pub(crate) fn render_macro<'a>(
13 ctx: RenderContext<'a>, 13 ctx: RenderContext<'a>,
14 import_to_add: Option<ImportEdit>, 14 import_to_add: Option<ImportEdit>,
15 name: String, 15 name: hir::Name,
16 macro_: hir::MacroDef, 16 macro_: hir::MacroDef,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 let _p = profile::span("render_macro"); 18 let _p = profile::span("render_macro");
@@ -24,13 +24,14 @@ struct MacroRender<'a> {
24 ctx: RenderContext<'a>, 24 ctx: RenderContext<'a>,
25 name: String, 25 name: String,
26 macro_: hir::MacroDef, 26 macro_: hir::MacroDef,
27 docs: Option<Documentation>, 27 docs: Option<hir::Documentation>,
28 bra: &'static str, 28 bra: &'static str,
29 ket: &'static str, 29 ket: &'static str,
30} 30}
31 31
32impl<'a> MacroRender<'a> { 32impl<'a> MacroRender<'a> {
33 fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> { 33 fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
34 let name = name.to_string();
34 let docs = ctx.docs(macro_); 35 let docs = ctx.docs(macro_);
35 let docs_str = docs.as_ref().map_or("", |s| s.as_str()); 36 let docs_str = docs.as_ref().map_or("", |s| s.as_str());
36 let (bra, ket) = guess_macro_braces(&name, docs_str); 37 let (bra, ket) = guess_macro_braces(&name, docs_str);
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 3f3134562..14dbbb20d 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -11,9 +11,9 @@ use hir::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, 12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
13}; 13};
14use hir_def::FunctionId; 14use hir_def::{body::BodySourceMap, expr::ExprId, FunctionId};
15use hir_ty::{TyExt, TypeWalk}; 15use hir_ty::{TyExt, TypeWalk};
16use ide::{AnalysisHost, RootDatabase}; 16use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
17use ide_db::base_db::{ 17use ide_db::base_db::{
18 salsa::{self, ParallelDatabase}, 18 salsa::{self, ParallelDatabase},
19 SourceDatabaseExt, 19 SourceDatabaseExt,
@@ -25,7 +25,7 @@ use rayon::prelude::*;
25use rustc_hash::FxHashSet; 25use rustc_hash::FxHashSet;
26use stdx::format_to; 26use stdx::format_to;
27use syntax::AstNode; 27use syntax::AstNode;
28use vfs::Vfs; 28use vfs::{Vfs, VfsPath};
29 29
30use crate::cli::{ 30use crate::cli::{
31 load_cargo::{load_workspace_at, LoadCargoConfig}, 31 load_cargo::{load_workspace_at, LoadCargoConfig},
@@ -191,6 +191,7 @@ impl AnalysisStatsCmd {
191 let mut num_exprs_unknown = 0; 191 let mut num_exprs_unknown = 0;
192 let mut num_exprs_partially_unknown = 0; 192 let mut num_exprs_partially_unknown = 0;
193 let mut num_type_mismatches = 0; 193 let mut num_type_mismatches = 0;
194 let analysis = host.analysis();
194 for f in funcs.iter().copied() { 195 for f in funcs.iter().copied() {
195 let name = f.name(db); 196 let name = f.name(db);
196 let full_name = f 197 let full_name = f
@@ -220,7 +221,7 @@ impl AnalysisStatsCmd {
220 } 221 }
221 bar.set_message(&msg); 222 bar.set_message(&msg);
222 let f_id = FunctionId::from(f); 223 let f_id = FunctionId::from(f);
223 let body = db.body(f_id.into()); 224 let (body, sm) = db.body_with_source_map(f_id.into());
224 let inference_result = db.infer(f_id.into()); 225 let inference_result = db.infer(f_id.into());
225 let (previous_exprs, previous_unknown, previous_partially_unknown) = 226 let (previous_exprs, previous_unknown, previous_partially_unknown) =
226 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown); 227 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
@@ -229,6 +230,22 @@ impl AnalysisStatsCmd {
229 num_exprs += 1; 230 num_exprs += 1;
230 if ty.is_unknown() { 231 if ty.is_unknown() {
231 num_exprs_unknown += 1; 232 num_exprs_unknown += 1;
233 if verbosity.is_spammy() {
234 if let Some((path, start, end)) =
235 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
236 {
237 bar.println(format!(
238 "{} {}:{}-{}:{}: Unknown type",
239 path,
240 start.line + 1,
241 start.col,
242 end.line + 1,
243 end.col,
244 ));
245 } else {
246 bar.println(format!("{}: Unknown type", name,));
247 }
248 }
232 } else { 249 } else {
233 let mut is_partially_unknown = false; 250 let mut is_partially_unknown = false;
234 ty.walk(&mut |ty| { 251 ty.walk(&mut |ty| {
@@ -242,20 +259,9 @@ impl AnalysisStatsCmd {
242 } 259 }
243 if self.only.is_some() && verbosity.is_spammy() { 260 if self.only.is_some() && verbosity.is_spammy() {
244 // in super-verbose mode for just one function, we print every single expression 261 // in super-verbose mode for just one function, we print every single expression
245 let (_, sm) = db.body_with_source_map(f_id.into()); 262 if let Some((_, start, end)) =
246 let src = sm.expr_syntax(expr_id); 263 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
247 if let Ok(src) = src { 264 {
248 let node = {
249 let root = db.parse_or_expand(src.file_id).unwrap();
250 src.value.to_node(&root)
251 };
252 let original_file = src.file_id.original_file(db);
253 let line_index = host.analysis().file_line_index(original_file).unwrap();
254 let text_range = node.syntax().text_range();
255 let (start, end) = (
256 line_index.line_col(text_range.start()),
257 line_index.line_col(text_range.end()),
258 );
259 bar.println(format!( 265 bar.println(format!(
260 "{}:{}-{}:{}: {}", 266 "{}:{}-{}:{}: {}",
261 start.line + 1, 267 start.line + 1,
@@ -271,22 +277,9 @@ impl AnalysisStatsCmd {
271 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 277 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
272 num_type_mismatches += 1; 278 num_type_mismatches += 1;
273 if verbosity.is_verbose() { 279 if verbosity.is_verbose() {
274 let (_, sm) = db.body_with_source_map(f_id.into()); 280 if let Some((path, start, end)) =
275 let src = sm.expr_syntax(expr_id); 281 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
276 if let Ok(src) = src { 282 {
277 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
278 // But also, we should just turn the type mismatches into diagnostics and provide these
279 let root = db.parse_or_expand(src.file_id).unwrap();
280 let node = src.map(|e| e.to_node(&root).syntax().clone());
281 let original_range = node.as_ref().original_file_range(db);
282 let path = vfs.file_path(original_range.file_id);
283 let line_index =
284 host.analysis().file_line_index(original_range.file_id).unwrap();
285 let text_range = original_range.range;
286 let (start, end) = (
287 line_index.line_col(text_range.start()),
288 line_index.line_col(text_range.end()),
289 );
290 bar.println(format!( 283 bar.println(format!(
291 "{} {}:{}-{}:{}: Expected {}, got {}", 284 "{} {}:{}-{}:{}: Expected {}, got {}",
292 path, 285 path,
@@ -319,6 +312,7 @@ impl AnalysisStatsCmd {
319 } 312 }
320 bar.inc(1); 313 bar.inc(1);
321 } 314 }
315
322 bar.finish_and_clear(); 316 bar.finish_and_clear();
323 eprintln!( 317 eprintln!(
324 " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", 318 " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}",
@@ -340,6 +334,31 @@ impl AnalysisStatsCmd {
340 } 334 }
341} 335}
342 336
337fn expr_syntax_range(
338 db: &RootDatabase,
339 analysis: &Analysis,
340 vfs: &Vfs,
341 sm: &BodySourceMap,
342 expr_id: ExprId,
343) -> Option<(VfsPath, LineCol, LineCol)> {
344 let src = sm.expr_syntax(expr_id);
345 if let Ok(src) = src {
346 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
347 // But also, we should just turn the type mismatches into diagnostics and provide these
348 let root = db.parse_or_expand(src.file_id).unwrap();
349 let node = src.map(|e| e.to_node(&root).syntax().clone());
350 let original_range = node.as_ref().original_file_range(db);
351 let path = vfs.file_path(original_range.file_id);
352 let line_index = analysis.file_line_index(original_range.file_id).unwrap();
353 let text_range = original_range.range;
354 let (start, end) =
355 (line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
356 Some((path, start, end))
357 } else {
358 None
359 }
360}
361
343fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) { 362fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
344 for i in 0..slice.len() { 363 for i in 0..slice.len() {
345 randomize_first(rng, &mut slice[i..]); 364 randomize_first(rng, &mut slice[i..]);
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index a6c294245..2106732cd 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -14,7 +14,7 @@ doctest = false
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "=0.13.0-pre.6" 16rowan = "=0.13.0-pre.6"
17rustc_lexer = { version = "720.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.7" 19arrayvec = "0.7"
20once_cell = "1.3.1" 20once_cell = "1.3.1"