aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock37
-rw-r--r--crates/hir/src/lib.rs50
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_def/src/adt.rs21
-rw-r--r--crates/hir_def/src/attr.rs2
-rw-r--r--crates/hir_def/src/body.rs11
-rw-r--r--crates/hir_def/src/body/lower.rs157
-rw-r--r--crates/hir_def/src/child_by_source.rs50
-rw-r--r--crates/hir_def/src/data.rs4
-rw-r--r--crates/hir_def/src/generics.rs4
-rw-r--r--crates/hir_def/src/item_scope.rs31
-rw-r--r--crates/hir_def/src/lib.rs56
-rw-r--r--crates/hir_def/src/nameres/collector.rs29
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs16
-rw-r--r--crates/hir_def/src/resolver.rs29
-rw-r--r--crates/hir_expand/Cargo.toml6
-rw-r--r--crates/hir_expand/src/builtin_derive.rs66
-rw-r--r--crates/hir_expand/src/builtin_macro.rs92
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/hir_expand/src/quote.rs5
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/hir_ty/src/diagnostics.rs29
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs11
-rw-r--r--crates/hir_ty/src/display.rs4
-rw-r--r--crates/hir_ty/src/infer/path.rs2
-rw-r--r--crates/hir_ty/src/lower.rs4
-rw-r--r--crates/hir_ty/src/method_resolution.rs4
-rw-r--r--crates/hir_ty/src/tests.rs20
-rw-r--r--crates/hir_ty/src/tests/traits.rs33
-rw-r--r--crates/hir_ty/src/traits/chalk.rs4
-rw-r--r--crates/hir_ty/src/utils.rs2
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/display/short_label.rs6
-rw-r--r--crates/ide/src/hover.rs62
-rw-r--r--crates/ide/src/lib.rs10
-rw-r--r--crates/ide/src/references/rename.rs55
-rw-r--r--crates/ide/src/ssr.rs259
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs5
-rw-r--r--crates/ide_assists/Cargo.toml2
-rw-r--r--crates/ide_assists/src/handlers/add_turbo_fish.rs33
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs14
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs18
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions/attribute.rs35
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs7
-rw-r--r--crates/ide_completion/src/completions/keyword.rs44
-rw-r--r--crates/ide_completion/src/completions/mod_.rs6
-rw-r--r--crates/ide_completion/src/completions/postfix.rs7
-rw-r--r--crates/ide_completion/src/completions/record.rs15
-rw-r--r--crates/ide_completion/src/completions/snippet.rs25
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs32
-rw-r--r--crates/ide_completion/src/item.rs211
-rw-r--r--crates/ide_completion/src/lib.rs2
-rw-r--r--crates/ide_completion/src/render.rs234
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs6
-rw-r--r--crates/ide_completion/src/render/const_.rs10
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs21
-rw-r--r--crates/ide_completion/src/render/function.rs13
-rw-r--r--crates/ide_completion/src/render/macro_.rs26
-rw-r--r--crates/ide_completion/src/render/pattern.rs18
-rw-r--r--crates/ide_completion/src/render/type_alias.rs10
-rw-r--r--crates/ide_db/Cargo.toml2
-rw-r--r--crates/ide_ssr/Cargo.toml2
-rw-r--r--crates/ide_ssr/src/from_comment.rs32
-rw-r--r--crates/ide_ssr/src/lib.rs11
-rw-r--r--crates/mbe/Cargo.toml2
-rw-r--r--crates/parser/src/grammar.rs2
-rw-r--r--crates/proc_macro_api/Cargo.toml3
-rw-r--r--crates/proc_macro_api/src/lib.rs22
-rw-r--r--crates/proc_macro_api/src/version.rs132
-rw-r--r--crates/proc_macro_srv/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/handlers.rs33
-rw-r--r--crates/rust-analyzer/src/to_proto.rs94
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--docs/dev/architecture.md6
-rw-r--r--docs/user/manual.adoc2
-rw-r--r--xtask/src/codegen.rs2
-rw-r--r--xtask/src/main.rs2
79 files changed, 1468 insertions, 860 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 51a07abe3..b1fef2e80 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -107,9 +107,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
107 107
108[[package]] 108[[package]]
109name = "byteorder" 109name = "byteorder"
110version = "1.4.2" 110version = "1.4.3"
111source = "registry+https://github.com/rust-lang/crates.io-index" 111source = "registry+https://github.com/rust-lang/crates.io-index"
112checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" 112checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
113 113
114[[package]] 114[[package]]
115name = "camino" 115name = "camino"
@@ -524,7 +524,9 @@ name = "hir_expand"
524version = "0.0.0" 524version = "0.0.0"
525dependencies = [ 525dependencies = [
526 "base_db", 526 "base_db",
527 "cfg",
527 "either", 528 "either",
529 "expect-test",
528 "la-arena", 530 "la-arena",
529 "log", 531 "log",
530 "mbe", 532 "mbe",
@@ -897,6 +899,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
897checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 899checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
898 900
899[[package]] 901[[package]]
902name = "memmap"
903version = "0.7.0"
904source = "registry+https://github.com/rust-lang/crates.io-index"
905checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
906dependencies = [
907 "libc",
908 "winapi",
909]
910
911[[package]]
900name = "memmap2" 912name = "memmap2"
901version = "0.2.1" 913version = "0.2.1"
902source = "registry+https://github.com/rust-lang/crates.io-index" 914source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1159,8 +1171,11 @@ dependencies = [
1159 "crossbeam-channel", 1171 "crossbeam-channel",
1160 "jod-thread", 1172 "jod-thread",
1161 "log", 1173 "log",
1174 "memmap",
1175 "object",
1162 "serde", 1176 "serde",
1163 "serde_json", 1177 "serde_json",
1178 "snap",
1164 "stdx", 1179 "stdx",
1165 "tt", 1180 "tt",
1166] 1181]
@@ -1375,9 +1390,9 @@ dependencies = [
1375 1390
1376[[package]] 1391[[package]]
1377name = "rustc-ap-rustc_lexer" 1392name = "rustc-ap-rustc_lexer"
1378version = "709.0.0" 1393version = "710.0.0"
1379source = "registry+https://github.com/rust-lang/crates.io-index" 1394source = "registry+https://github.com/rust-lang/crates.io-index"
1380checksum = "f69f83314702aaccf29c7401cc63bb0d9fa7869a185a23b8379f08c91514b3f3" 1395checksum = "b0bba1ca6787b6d4af505b7a940eae9ecb084dd03e07f03bf3ddbf78e738b617"
1381dependencies = [ 1396dependencies = [
1382 "unicode-xid", 1397 "unicode-xid",
1383] 1398]
@@ -1546,6 +1561,12 @@ dependencies = [
1546] 1561]
1547 1562
1548[[package]] 1563[[package]]
1564name = "snap"
1565version = "1.0.4"
1566source = "registry+https://github.com/rust-lang/crates.io-index"
1567checksum = "dc725476a1398f0480d56cd0ad381f6f32acf2642704456f8f59a35df464b59a"
1568
1569[[package]]
1549name = "socket2" 1570name = "socket2"
1550version = "0.3.19" 1571version = "0.3.19"
1551source = "registry+https://github.com/rust-lang/crates.io-index" 1572source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1566,9 +1587,9 @@ dependencies = [
1566 1587
1567[[package]] 1588[[package]]
1568name = "syn" 1589name = "syn"
1569version = "1.0.62" 1590version = "1.0.63"
1570source = "registry+https://github.com/rust-lang/crates.io-index" 1591source = "registry+https://github.com/rust-lang/crates.io-index"
1571checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" 1592checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717"
1572dependencies = [ 1593dependencies = [
1573 "proc-macro2", 1594 "proc-macro2",
1574 "quote", 1595 "quote",
@@ -1761,9 +1782,9 @@ dependencies = [
1761 1782
1762[[package]] 1783[[package]]
1763name = "tracing-tree" 1784name = "tracing-tree"
1764version = "0.1.8" 1785version = "0.1.9"
1765source = "registry+https://github.com/rust-lang/crates.io-index" 1786source = "registry+https://github.com/rust-lang/crates.io-index"
1766checksum = "1a60657cfbf397c603257a8230b3f427e6a2a4e5911a59331b9bb4dffff5b608" 1787checksum = "1712b40907f8d9bc2bc66763ab61dec914b7123d7149e59feb0d4e2a95fc4967"
1767dependencies = [ 1788dependencies = [
1768 "ansi_term", 1789 "ansi_term",
1769 "atty", 1790 "atty",
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d5a3d9034..58adc8fd3 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -305,7 +305,6 @@ impl ModuleDef {
305 ModuleDef::Module(it) => it.name(db), 305 ModuleDef::Module(it) => it.name(db),
306 ModuleDef::Const(it) => it.name(db), 306 ModuleDef::Const(it) => it.name(db),
307 ModuleDef::Static(it) => it.name(db), 307 ModuleDef::Static(it) => it.name(db),
308
309 ModuleDef::BuiltinType(it) => Some(it.name()), 308 ModuleDef::BuiltinType(it) => Some(it.name()),
310 } 309 }
311 } 310 }
@@ -535,7 +534,7 @@ pub struct Struct {
535 534
536impl Struct { 535impl Struct {
537 pub fn module(self, db: &dyn HirDatabase) -> Module { 536 pub fn module(self, db: &dyn HirDatabase) -> Module {
538 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } 537 Module { id: self.id.lookup(db.upcast()).container }
539 } 538 }
540 539
541 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { 540 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
@@ -556,11 +555,7 @@ impl Struct {
556 } 555 }
557 556
558 pub fn ty(self, db: &dyn HirDatabase) -> Type { 557 pub fn ty(self, db: &dyn HirDatabase) -> Type {
559 Type::from_def( 558 Type::from_def(db, self.id.lookup(db.upcast()).container.krate(), self.id)
560 db,
561 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
562 self.id,
563 )
564 } 559 }
565 560
566 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { 561 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
@@ -587,15 +582,11 @@ impl Union {
587 } 582 }
588 583
589 pub fn module(self, db: &dyn HirDatabase) -> Module { 584 pub fn module(self, db: &dyn HirDatabase) -> Module {
590 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } 585 Module { id: self.id.lookup(db.upcast()).container }
591 } 586 }
592 587
593 pub fn ty(self, db: &dyn HirDatabase) -> Type { 588 pub fn ty(self, db: &dyn HirDatabase) -> Type {
594 Type::from_def( 589 Type::from_def(db, self.id.lookup(db.upcast()).container.krate(), self.id)
595 db,
596 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
597 self.id,
598 )
599 } 590 }
600 591
601 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { 592 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
@@ -619,7 +610,7 @@ pub struct Enum {
619 610
620impl Enum { 611impl Enum {
621 pub fn module(self, db: &dyn HirDatabase) -> Module { 612 pub fn module(self, db: &dyn HirDatabase) -> Module {
622 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } 613 Module { id: self.id.lookup(db.upcast()).container }
623 } 614 }
624 615
625 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { 616 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
@@ -635,11 +626,7 @@ impl Enum {
635 } 626 }
636 627
637 pub fn ty(self, db: &dyn HirDatabase) -> Type { 628 pub fn ty(self, db: &dyn HirDatabase) -> Type {
638 Type::from_def( 629 Type::from_def(db, self.id.lookup(db.upcast()).container.krate(), self.id)
639 db,
640 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
641 self.id,
642 )
643 } 630 }
644} 631}
645 632
@@ -1001,7 +988,7 @@ pub struct Trait {
1001 988
1002impl Trait { 989impl Trait {
1003 pub fn module(self, db: &dyn HirDatabase) -> Module { 990 pub fn module(self, db: &dyn HirDatabase) -> Module {
1004 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } 991 Module { id: self.id.lookup(db.upcast()).container }
1005 } 992 }
1006 993
1007 pub fn name(self, db: &dyn HirDatabase) -> Name { 994 pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -1157,7 +1144,7 @@ where
1157{ 1144{
1158 match id.lookup(db.upcast()).container { 1145 match id.lookup(db.upcast()).container {
1159 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), 1146 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
1160 AssocContainerId::ContainerId(_) => None, 1147 AssocContainerId::ModuleId(_) => None,
1161 } 1148 }
1162} 1149}
1163 1150
@@ -1185,7 +1172,7 @@ impl AssocItem {
1185 match container { 1172 match container {
1186 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), 1173 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
1187 AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()), 1174 AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
1188 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), 1175 AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
1189 } 1176 }
1190 } 1177 }
1191 1178
@@ -1296,13 +1283,7 @@ impl Local {
1296 1283
1297 pub fn is_mut(self, db: &dyn HirDatabase) -> bool { 1284 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
1298 let body = db.body(self.parent.into()); 1285 let body = db.body(self.parent.into());
1299 match &body[self.pat_id] { 1286 matches!(&body[self.pat_id], Pat::Bind { mode: BindingAnnotation::Mutable, .. })
1300 Pat::Bind { mode, .. } => match mode {
1301 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
1302 _ => false,
1303 },
1304 _ => false,
1305 }
1306 } 1287 }
1307 1288
1308 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { 1289 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
@@ -1516,7 +1497,7 @@ impl Impl {
1516 pub fn target_ty(self, db: &dyn HirDatabase) -> Type { 1497 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1517 let impl_data = db.impl_data(self.id); 1498 let impl_data = db.impl_data(self.id);
1518 let resolver = self.id.resolver(db.upcast()); 1499 let resolver = self.id.resolver(db.upcast());
1519 let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); 1500 let krate = self.id.lookup(db.upcast()).container.krate();
1520 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 1501 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1521 let ty = Ty::from_hir(&ctx, &impl_data.target_type); 1502 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1522 Type::new_with_resolver_inner(db, krate, &resolver, ty) 1503 Type::new_with_resolver_inner(db, krate, &resolver, ty)
@@ -1531,7 +1512,7 @@ impl Impl {
1531 } 1512 }
1532 1513
1533 pub fn module(self, db: &dyn HirDatabase) -> Module { 1514 pub fn module(self, db: &dyn HirDatabase) -> Module {
1534 self.id.lookup(db.upcast()).container.module(db.upcast()).into() 1515 self.id.lookup(db.upcast()).container.into()
1535 } 1516 }
1536 1517
1537 pub fn krate(self, db: &dyn HirDatabase) -> Crate { 1518 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
@@ -1614,10 +1595,9 @@ impl Type {
1614 } 1595 }
1615 1596
1616 pub fn remove_ref(&self) -> Option<Type> { 1597 pub fn remove_ref(&self) -> Option<Type> {
1617 if let Ty::Ref(.., substs) = &self.ty.value { 1598 match &self.ty.value {
1618 Some(self.derived(substs[0].clone())) 1599 Ty::Ref(.., substs) => Some(self.derived(substs[0].clone())),
1619 } else { 1600 _ => None,
1620 None
1621 } 1601 }
1622 } 1602 }
1623 1603
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 2f07b6d01..c2d99280f 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -28,10 +28,10 @@ base_db = { path = "../base_db", version = "0.0.0" }
28syntax = { path = "../syntax", version = "0.0.0" } 28syntax = { path = "../syntax", version = "0.0.0" }
29profile = { path = "../profile", version = "0.0.0" } 29profile = { path = "../profile", version = "0.0.0" }
30hir_expand = { path = "../hir_expand", version = "0.0.0" } 30hir_expand = { path = "../hir_expand", version = "0.0.0" }
31test_utils = { path = "../test_utils", version = "0.0.0" }
32mbe = { path = "../mbe", version = "0.0.0" } 31mbe = { path = "../mbe", version = "0.0.0" }
33cfg = { path = "../cfg", version = "0.0.0" } 32cfg = { path = "../cfg", version = "0.0.0" }
34tt = { path = "../tt", version = "0.0.0" } 33tt = { path = "../tt", version = "0.0.0" }
35 34
36[dev-dependencies] 35[dev-dependencies]
36test_utils = { path = "../test_utils" }
37expect-test = "1.1" 37expect-test = "1.1"
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index ed36c3109..efbde17d8 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -21,8 +21,7 @@ use crate::{
21 trace::Trace, 21 trace::Trace,
22 type_ref::TypeRef, 22 type_ref::TypeRef,
23 visibility::RawVisibility, 23 visibility::RawVisibility,
24 EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, 24 EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
25 VariantId,
26}; 25};
27use cfg::CfgOptions; 26use cfg::CfgOptions;
28 27
@@ -92,10 +91,10 @@ fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
92impl StructData { 91impl StructData {
93 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 92 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
94 let loc = id.lookup(db); 93 let loc = id.lookup(db);
95 let krate = loc.container.module(db).krate; 94 let krate = loc.container.krate;
96 let item_tree = db.item_tree(loc.id.file_id); 95 let item_tree = db.item_tree(loc.id.file_id);
97 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); 96 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
98 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 97 let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
99 98
100 let strukt = &item_tree[loc.id.value]; 99 let strukt = &item_tree[loc.id.value];
101 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None); 100 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
@@ -107,10 +106,10 @@ impl StructData {
107 } 106 }
108 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 107 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
109 let loc = id.lookup(db); 108 let loc = id.lookup(db);
110 let krate = loc.container.module(db).krate; 109 let krate = loc.container.krate;
111 let item_tree = db.item_tree(loc.id.file_id); 110 let item_tree = db.item_tree(loc.id.file_id);
112 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); 111 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
113 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 112 let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
114 113
115 let union = &item_tree[loc.id.value]; 114 let union = &item_tree[loc.id.value];
116 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None); 115 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
@@ -126,7 +125,7 @@ impl StructData {
126impl EnumData { 125impl EnumData {
127 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { 126 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
128 let loc = e.lookup(db); 127 let loc = e.lookup(db);
129 let krate = loc.container.module(db).krate; 128 let krate = loc.container.krate;
130 let item_tree = db.item_tree(loc.id.file_id); 129 let item_tree = db.item_tree(loc.id.file_id);
131 let cfg_options = db.crate_graph()[krate].cfg_options.clone(); 130 let cfg_options = db.crate_graph()[krate].cfg_options.clone();
132 131
@@ -168,7 +167,7 @@ impl HasChildSource<LocalEnumVariantId> for EnumId {
168 ) -> InFile<ArenaMap<LocalEnumVariantId, Self::Value>> { 167 ) -> InFile<ArenaMap<LocalEnumVariantId, Self::Value>> {
169 let src = self.lookup(db).source(db); 168 let src = self.lookup(db).source(db);
170 let mut trace = Trace::new_for_map(); 169 let mut trace = Trace::new_for_map();
171 lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db)); 170 lower_enum(db, &mut trace, &src, self.lookup(db).container);
172 src.with_value(trace.into_map()) 171 src.with_value(trace.into_map())
173 } 172 }
174} 173}
@@ -238,10 +237,10 @@ impl HasChildSource<LocalFieldId> for VariantId {
238 // I don't really like the fact that we call into parent source 237 // I don't really like the fact that we call into parent source
239 // here, this might add to more queries then necessary. 238 // here, this might add to more queries then necessary.
240 let src = it.parent.child_source(db); 239 let src = it.parent.child_source(db);
241 (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db)) 240 (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container)
242 } 241 }
243 VariantId::StructId(it) => { 242 VariantId::StructId(it) => {
244 (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db)) 243 (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container)
245 } 244 }
246 VariantId::UnionId(it) => ( 245 VariantId::UnionId(it) => (
247 it.lookup(db).source(db).map(|it| { 246 it.lookup(db).source(db).map(|it| {
@@ -249,7 +248,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
249 .map(ast::StructKind::Record) 248 .map(ast::StructKind::Record)
250 .unwrap_or(ast::StructKind::Unit) 249 .unwrap_or(ast::StructKind::Unit)
251 }), 250 }),
252 it.lookup(db).container.module(db), 251 it.lookup(db).container,
253 ), 252 ),
254 }; 253 };
255 let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); 254 let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index b716d5f6e..97cdbbb9e 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -267,7 +267,7 @@ impl Attrs {
267 db: &dyn DefDatabase, 267 db: &dyn DefDatabase,
268 e: EnumId, 268 e: EnumId,
269 ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> { 269 ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> {
270 let krate = e.lookup(db).container.module(db).krate; 270 let krate = e.lookup(db).container.krate;
271 let src = e.child_source(db); 271 let src = e.child_source(db);
272 let mut res = ArenaMap::default(); 272 let mut res = ArenaMap::default();
273 273
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index b1a3fe1cb..19c4eb521 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -28,11 +28,10 @@ use crate::{
28 db::DefDatabase, 28 db::DefDatabase,
29 expr::{Expr, ExprId, Label, LabelId, Pat, PatId}, 29 expr::{Expr, ExprId, Label, LabelId, Pat, PatId},
30 item_scope::BuiltinShadowMode, 30 item_scope::BuiltinShadowMode,
31 item_scope::ItemScope,
32 nameres::DefMap, 31 nameres::DefMap,
33 path::{ModPath, Path}, 32 path::{ModPath, Path},
34 src::HasSource, 33 src::HasSource,
35 AsMacroCall, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId, 34 AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId,
36}; 35};
37 36
38/// A subset of Expander that only deals with cfg attributes. We only need it to 37/// A subset of Expander that only deals with cfg attributes. We only need it to
@@ -226,7 +225,8 @@ pub struct Body {
226 pub params: Vec<PatId>, 225 pub params: Vec<PatId>,
227 /// The `ExprId` of the actual body expression. 226 /// The `ExprId` of the actual body expression.
228 pub body_expr: ExprId, 227 pub body_expr: ExprId,
229 pub item_scope: ItemScope, 228 /// Block expressions in this body that may contain inner items.
229 pub block_scopes: Vec<BlockId>,
230 _c: Count<Self>, 230 _c: Count<Self>,
231} 231}
232 232
@@ -295,7 +295,7 @@ impl Body {
295 } 295 }
296 }; 296 };
297 let expander = Expander::new(db, file_id, module); 297 let expander = Expander::new(db, file_id, module);
298 let (body, source_map) = Body::new(db, def, expander, params, body); 298 let (body, source_map) = Body::new(db, expander, params, body);
299 (Arc::new(body), Arc::new(source_map)) 299 (Arc::new(body), Arc::new(source_map))
300 } 300 }
301 301
@@ -305,12 +305,11 @@ impl Body {
305 305
306 fn new( 306 fn new(
307 db: &dyn DefDatabase, 307 db: &dyn DefDatabase,
308 def: DefWithBodyId,
309 expander: Expander, 308 expander: Expander,
310 params: Option<ast::ParamList>, 309 params: Option<ast::ParamList>,
311 body: Option<ast::Expr>, 310 body: Option<ast::Expr>,
312 ) -> (Body, BodySourceMap) { 311 ) -> (Body, BodySourceMap) {
313 lower::lower(db, def, expander, params, body) 312 lower::lower(db, expander, params, body)
314 } 313 }
315} 314}
316 315
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index d4abe819d..8c8eb8007 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,17 +1,16 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::{any::type_name, mem, sync::Arc}; 4use std::mem;
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
8 hygiene::Hygiene, 8 hygiene::Hygiene,
9 name::{name, AsName, Name}, 9 name::{name, AsName, Name},
10 ExpandError, HirFileId, MacroDefId, MacroDefKind, 10 ExpandError, HirFileId,
11}; 11};
12use la_arena::Arena; 12use la_arena::Arena;
13use profile::Count; 13use profile::Count;
14use rustc_hash::FxHashMap;
15use syntax::{ 14use syntax::{
16 ast::{ 15 ast::{
17 self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner, 16 self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
@@ -32,11 +31,9 @@ use crate::{
32 Statement, 31 Statement,
33 }, 32 },
34 item_scope::BuiltinShadowMode, 33 item_scope::BuiltinShadowMode,
35 item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
36 path::{GenericArgs, Path}, 34 path::{GenericArgs, Path},
37 type_ref::{Mutability, Rawness, TypeRef}, 35 type_ref::{Mutability, Rawness, TypeRef},
38 AdtId, BlockLoc, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, 36 AdtId, BlockLoc, ModuleDefId,
39 ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
40}; 37};
41 38
42use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
@@ -60,15 +57,12 @@ impl LowerCtx {
60 57
61pub(super) fn lower( 58pub(super) fn lower(
62 db: &dyn DefDatabase, 59 db: &dyn DefDatabase,
63 def: DefWithBodyId,
64 expander: Expander, 60 expander: Expander,
65 params: Option<ast::ParamList>, 61 params: Option<ast::ParamList>,
66 body: Option<ast::Expr>, 62 body: Option<ast::Expr>,
67) -> (Body, BodySourceMap) { 63) -> (Body, BodySourceMap) {
68 let item_tree = db.item_tree(expander.current_file_id);
69 ExprCollector { 64 ExprCollector {
70 db, 65 db,
71 def,
72 source_map: BodySourceMap::default(), 66 source_map: BodySourceMap::default(),
73 body: Body { 67 body: Body {
74 exprs: Arena::default(), 68 exprs: Arena::default(),
@@ -76,14 +70,9 @@ pub(super) fn lower(
76 labels: Arena::default(), 70 labels: Arena::default(),
77 params: Vec::new(), 71 params: Vec::new(),
78 body_expr: dummy_expr_id(), 72 body_expr: dummy_expr_id(),
79 item_scope: Default::default(), 73 block_scopes: Vec::new(),
80 _c: Count::new(), 74 _c: Count::new(),
81 }, 75 },
82 item_trees: {
83 let mut map = FxHashMap::default();
84 map.insert(expander.current_file_id, item_tree);
85 map
86 },
87 expander, 76 expander,
88 } 77 }
89 .collect(params, body) 78 .collect(params, body)
@@ -91,12 +80,9 @@ pub(super) fn lower(
91 80
92struct ExprCollector<'a> { 81struct ExprCollector<'a> {
93 db: &'a dyn DefDatabase, 82 db: &'a dyn DefDatabase,
94 def: DefWithBodyId,
95 expander: Expander, 83 expander: Expander,
96 body: Body, 84 body: Body,
97 source_map: BodySourceMap, 85 source_map: BodySourceMap,
98
99 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
100} 86}
101 87
102impl ExprCollector<'_> { 88impl ExprCollector<'_> {
@@ -593,9 +579,6 @@ impl ExprCollector<'_> {
593 } else { 579 } else {
594 self.source_map.expansions.insert(macro_call, self.expander.current_file_id); 580 self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
595 581
596 let item_tree = self.db.item_tree(self.expander.current_file_id);
597 self.item_trees.insert(self.expander.current_file_id, item_tree);
598
599 let id = collector(self, Some(expansion)); 582 let id = collector(self, Some(expansion));
600 self.expander.exit(self.db, mark); 583 self.expander.exit(self.db, mark);
601 id 584 id
@@ -605,32 +588,6 @@ impl ExprCollector<'_> {
605 } 588 }
606 } 589 }
607 590
608 fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
609 let id = self.expander.ast_id(ast);
610 let tree = &self.item_trees[&id.file_id];
611
612 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
613
614 // Root file (non-macro).
615 let item_tree_id = tree
616 .all_inner_items()
617 .chain(tree.top_level_items().iter().copied())
618 .filter_map(|mod_item| mod_item.downcast::<N>())
619 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
620 .or_else(|| {
621 log::debug!(
622 "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
623 type_name::<N>(),
624 id,
625 ast.syntax(),
626 ast.syntax(),
627 );
628 None
629 })?;
630
631 Some(ItemTreeId::new(id.file_id, item_tree_id))
632 }
633
634 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 591 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
635 if let Some(expr) = expr { 592 if let Some(expr) = expr {
636 self.collect_expr(expr) 593 self.collect_expr(expr)
@@ -662,7 +619,6 @@ impl ExprCollector<'_> {
662 match expansion { 619 match expansion {
663 Some(expansion) => { 620 Some(expansion) => {
664 let statements: ast::MacroStmts = expansion; 621 let statements: ast::MacroStmts = expansion;
665 this.collect_stmts_items(statements.statements());
666 622
667 statements.statements().for_each(|stmt| { 623 statements.statements().for_each(|stmt| {
668 if let Some(mut r) = this.collect_stmt(stmt) { 624 if let Some(mut r) = this.collect_stmt(stmt) {
@@ -700,6 +656,8 @@ impl ExprCollector<'_> {
700 let block_loc = 656 let block_loc =
701 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; 657 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
702 let block_id = self.db.intern_block(block_loc); 658 let block_id = self.db.intern_block(block_loc);
659 self.body.block_scopes.push(block_id);
660
703 let opt_def_map = self.db.block_def_map(block_id); 661 let opt_def_map = self.db.block_def_map(block_id);
704 let has_def_map = opt_def_map.is_some(); 662 let has_def_map = opt_def_map.is_some();
705 let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone()); 663 let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone());
@@ -707,7 +665,6 @@ impl ExprCollector<'_> {
707 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); 665 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
708 let prev_local_module = mem::replace(&mut self.expander.module, module); 666 let prev_local_module = mem::replace(&mut self.expander.module, module);
709 667
710 self.collect_stmts_items(block.statements());
711 let statements = 668 let statements =
712 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); 669 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
713 let tail = block.tail_expr().map(|e| self.collect_expr(e)); 670 let tail = block.tail_expr().map(|e| self.collect_expr(e));
@@ -722,108 +679,6 @@ impl ExprCollector<'_> {
722 expr_id 679 expr_id
723 } 680 }
724 681
725 fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
726 let container = ContainerId::DefWithBodyId(self.def);
727
728 let items = stmts
729 .filter_map(|stmt| match stmt {
730 ast::Stmt::Item(it) => Some(it),
731 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
732 })
733 .filter_map(|item| {
734 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
735 ast::Item::Fn(def) => {
736 let id = self.find_inner_item(&def)?;
737 (
738 FunctionLoc { container: container.into(), id }.intern(self.db).into(),
739 def.name(),
740 )
741 }
742 ast::Item::TypeAlias(def) => {
743 let id = self.find_inner_item(&def)?;
744 (
745 TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
746 def.name(),
747 )
748 }
749 ast::Item::Const(def) => {
750 let id = self.find_inner_item(&def)?;
751 (
752 ConstLoc { container: container.into(), id }.intern(self.db).into(),
753 def.name(),
754 )
755 }
756 ast::Item::Static(def) => {
757 let id = self.find_inner_item(&def)?;
758 (StaticLoc { container, id }.intern(self.db).into(), def.name())
759 }
760 ast::Item::Struct(def) => {
761 let id = self.find_inner_item(&def)?;
762 (StructLoc { container, id }.intern(self.db).into(), def.name())
763 }
764 ast::Item::Enum(def) => {
765 let id = self.find_inner_item(&def)?;
766 (EnumLoc { container, id }.intern(self.db).into(), def.name())
767 }
768 ast::Item::Union(def) => {
769 let id = self.find_inner_item(&def)?;
770 (UnionLoc { container, id }.intern(self.db).into(), def.name())
771 }
772 ast::Item::Trait(def) => {
773 let id = self.find_inner_item(&def)?;
774 (TraitLoc { container, id }.intern(self.db).into(), def.name())
775 }
776 ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
777 ast::Item::Impl(_)
778 | ast::Item::Use(_)
779 | ast::Item::ExternCrate(_)
780 | ast::Item::Module(_)
781 | ast::Item::MacroCall(_) => return None,
782 ast::Item::MacroRules(def) => {
783 return Some(Either::Right(ast::Macro::from(def)));
784 }
785 ast::Item::MacroDef(def) => {
786 return Some(Either::Right(ast::Macro::from(def)));
787 }
788 };
789
790 Some(Either::Left((def, name)))
791 })
792 .collect::<Vec<_>>();
793
794 for either in items {
795 match either {
796 Either::Left((def, name)) => {
797 self.body.item_scope.define_def(def);
798 if let Some(name) = name {
799 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
800 let has_constructor = match def {
801 ModuleDefId::AdtId(AdtId::StructId(s)) => {
802 self.db.struct_data(s).variant_data.kind() != StructKind::Record
803 }
804 _ => true,
805 };
806 self.body.item_scope.push_res(
807 name.as_name(),
808 crate::per_ns::PerNs::from_def(def, vis, has_constructor),
809 );
810 }
811 }
812 Either::Right(e) => {
813 let mac = MacroDefId {
814 krate: self.expander.def_map.krate(),
815 ast_id: Some(self.expander.ast_id(&e)),
816 kind: MacroDefKind::Declarative,
817 local_inner: false,
818 };
819 if let Some(name) = e.name() {
820 self.body.item_scope.define_legacy_macro(name.as_name(), mac);
821 }
822 }
823 }
824 }
825 }
826
827 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { 682 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
828 if let Some(block) = expr { 683 if let Some(block) = expr {
829 self.collect_block(block) 684 self.collect_block(block)
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 75c2d756b..2a331dcaf 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -17,13 +17,16 @@ use crate::{
17}; 17};
18 18
19pub trait ChildBySource { 19pub trait ChildBySource {
20 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap;
21}
22
23impl ChildBySource for TraitId {
24 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 20 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
25 let mut res = DynMap::default(); 21 let mut res = DynMap::default();
22 self.child_by_source_to(db, &mut res);
23 res
24 }
25 fn child_by_source_to(&self, db: &dyn DefDatabase, map: &mut DynMap);
26}
26 27
28impl ChildBySource for TraitId {
29 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
27 let data = db.trait_data(*self); 30 let data = db.trait_data(*self);
28 for (_name, item) in data.items.iter() { 31 for (_name, item) in data.items.iter() {
29 match *item { 32 match *item {
@@ -41,15 +44,11 @@ impl ChildBySource for TraitId {
41 } 44 }
42 } 45 }
43 } 46 }
44
45 res
46 } 47 }
47} 48}
48 49
49impl ChildBySource for ImplId { 50impl ChildBySource for ImplId {
50 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 51 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
51 let mut res = DynMap::default();
52
53 let data = db.impl_data(*self); 52 let data = db.impl_data(*self);
54 for &item in data.items.iter() { 53 for &item in data.items.iter() {
55 match item { 54 match item {
@@ -67,25 +66,21 @@ impl ChildBySource for ImplId {
67 } 66 }
68 } 67 }
69 } 68 }
70
71 res
72 } 69 }
73} 70}
74 71
75impl ChildBySource for ModuleId { 72impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 73 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
77 let def_map = self.def_map(db); 74 let def_map = self.def_map(db);
78 let module_data = &def_map[self.local_id]; 75 let module_data = &def_map[self.local_id];
79 module_data.scope.child_by_source(db) 76 module_data.scope.child_by_source_to(db, res);
80 } 77 }
81} 78}
82 79
83impl ChildBySource for ItemScope { 80impl ChildBySource for ItemScope {
84 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
85 let mut res = DynMap::default(); 82 self.declarations().for_each(|item| add_module_def(db, res, item));
86 self.declarations().for_each(|item| add_module_def(db, &mut res, item)); 83 self.impls().for_each(|imp| add_impl(db, res, imp));
87 self.impls().for_each(|imp| add_impl(db, &mut res, imp));
88 return res;
89 84
90 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 85 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
91 match item { 86 match item {
@@ -134,9 +129,7 @@ impl ChildBySource for ItemScope {
134} 129}
135 130
136impl ChildBySource for VariantId { 131impl ChildBySource for VariantId {
137 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 132 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
138 let mut res = DynMap::default();
139
140 let arena_map = self.child_source(db); 133 let arena_map = self.child_source(db);
141 let arena_map = arena_map.as_ref(); 134 let arena_map = arena_map.as_ref();
142 for (local_id, source) in arena_map.value.iter() { 135 for (local_id, source) in arena_map.value.iter() {
@@ -150,28 +143,27 @@ impl ChildBySource for VariantId {
150 } 143 }
151 } 144 }
152 } 145 }
153 res
154 } 146 }
155} 147}
156 148
157impl ChildBySource for EnumId { 149impl ChildBySource for EnumId {
158 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 150 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
159 let mut res = DynMap::default();
160
161 let arena_map = self.child_source(db); 151 let arena_map = self.child_source(db);
162 let arena_map = arena_map.as_ref(); 152 let arena_map = arena_map.as_ref();
163 for (local_id, source) in arena_map.value.iter() { 153 for (local_id, source) in arena_map.value.iter() {
164 let id = EnumVariantId { parent: *self, local_id }; 154 let id = EnumVariantId { parent: *self, local_id };
165 res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id) 155 res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
166 } 156 }
167
168 res
169 } 157 }
170} 158}
171 159
172impl ChildBySource for DefWithBodyId { 160impl ChildBySource for DefWithBodyId {
173 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 161 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
174 let body = db.body(*self); 162 let body = db.body(*self);
175 body.item_scope.child_by_source(db) 163 for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
164 // All block expressions are merged into the same map, because they logically all add
165 // inner items to the containing `DefWithBodyId`.
166 def_map[def_map.root()].scope.child_by_source_to(db, res);
167 }
176 } 168 }
177} 169}
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index d3380e0f4..aea53d527 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -97,7 +97,7 @@ impl TraitData {
97 let tr_def = &item_tree[tr_loc.id.value]; 97 let tr_def = &item_tree[tr_loc.id.value];
98 let name = tr_def.name.clone(); 98 let name = tr_def.name.clone();
99 let auto = tr_def.auto; 99 let auto = tr_def.auto;
100 let module_id = tr_loc.container.module(db); 100 let module_id = tr_loc.container;
101 let container = AssocContainerId::TraitId(tr); 101 let container = AssocContainerId::TraitId(tr);
102 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); 102 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
103 103
@@ -147,7 +147,7 @@ impl ImplData {
147 let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); 147 let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
148 let target_type = item_tree[impl_def.target_type].clone(); 148 let target_type = item_tree[impl_def.target_type].clone();
149 let is_negative = impl_def.is_negative; 149 let is_negative = impl_def.is_negative;
150 let module_id = impl_loc.container.module(db); 150 let module_id = impl_loc.container;
151 let container = AssocContainerId::ImplId(id); 151 let container = AssocContainerId::ImplId(id);
152 let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); 152 let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
153 153
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 3ace3be1f..a056ab797 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -421,8 +421,7 @@ impl HasChildSource<LocalConstParamId> for GenericDefId {
421} 421}
422 422
423impl ChildBySource for GenericDefId { 423impl ChildBySource for GenericDefId {
424 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 424 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
425 let mut res = DynMap::default();
426 let (_, sm) = GenericParams::new(db, *self); 425 let (_, sm) = GenericParams::new(db, *self);
427 426
428 let sm = sm.as_ref(); 427 let sm = sm.as_ref();
@@ -440,6 +439,5 @@ impl ChildBySource for GenericDefId {
440 let id = ConstParamId { parent: *self, local_id }; 439 let id = ConstParamId { parent: *self, local_id };
441 res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id); 440 res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id);
442 } 441 }
443 res
444 } 442 }
445} 443}
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 919933813..aafd73b60 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -168,37 +168,6 @@ impl ItemScope {
168 self.unnamed_trait_imports.insert(tr, vis); 168 self.unnamed_trait_imports.insert(tr, vis);
169 } 169 }
170 170
171 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
172 let mut changed = false;
173
174 if let Some(types) = def.types {
175 self.types.entry(name.clone()).or_insert_with(|| {
176 changed = true;
177 types
178 });
179 }
180 if let Some(values) = def.values {
181 self.values.entry(name.clone()).or_insert_with(|| {
182 changed = true;
183 values
184 });
185 }
186 if let Some(macros) = def.macros {
187 self.macros.entry(name.clone()).or_insert_with(|| {
188 changed = true;
189 macros
190 });
191 }
192
193 if def.is_none() {
194 if self.unresolved.insert(name) {
195 changed = true;
196 }
197 }
198
199 changed
200 }
201
202 pub(crate) fn push_res_with_import( 171 pub(crate) fn push_res_with_import(
203 &mut self, 172 &mut self,
204 glob_imports: &mut PerNsGlobImports, 173 glob_imports: &mut PerNsGlobImports,
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 4498d94bb..6d11c5be4 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -108,7 +108,7 @@ pub type LocalModuleId = Idx<nameres::ModuleData>;
108 108
109#[derive(Debug)] 109#[derive(Debug)]
110pub struct ItemLoc<N: ItemTreeNode> { 110pub struct ItemLoc<N: ItemTreeNode> {
111 pub container: ContainerId, 111 pub container: ModuleId,
112 pub id: ItemTreeId<N>, 112 pub id: ItemTreeId<N>,
113} 113}
114 114
@@ -279,18 +279,12 @@ pub struct ConstParamId {
279pub type LocalConstParamId = Idx<generics::ConstParamData>; 279pub type LocalConstParamId = Idx<generics::ConstParamData>;
280 280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
282pub enum ContainerId {
283 ModuleId(ModuleId),
284 DefWithBodyId(DefWithBodyId),
285}
286
287#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
288pub enum AssocContainerId { 282pub enum AssocContainerId {
289 ContainerId(ContainerId), 283 ModuleId(ModuleId),
290 ImplId(ImplId), 284 ImplId(ImplId),
291 TraitId(TraitId), 285 TraitId(TraitId),
292} 286}
293impl_from!(ContainerId for AssocContainerId); 287impl_from!(ModuleId for AssocContainerId);
294 288
295/// A Data Type 289/// A Data Type
296#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 290#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -447,21 +441,12 @@ pub trait HasModule {
447 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId; 441 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId;
448} 442}
449 443
450impl HasModule for ContainerId {
451 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
452 match *self {
453 ContainerId::ModuleId(it) => it,
454 ContainerId::DefWithBodyId(it) => it.module(db),
455 }
456 }
457}
458
459impl HasModule for AssocContainerId { 444impl HasModule for AssocContainerId {
460 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 445 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
461 match *self { 446 match *self {
462 AssocContainerId::ContainerId(it) => it.module(db), 447 AssocContainerId::ModuleId(it) => it,
463 AssocContainerId::ImplId(it) => it.lookup(db).container.module(db), 448 AssocContainerId::ImplId(it) => it.lookup(db).container,
464 AssocContainerId::TraitId(it) => it.lookup(db).container.module(db), 449 AssocContainerId::TraitId(it) => it.lookup(db).container,
465 } 450 }
466 } 451 }
467} 452}
@@ -479,16 +464,15 @@ impl HasModule for AdtId {
479 AdtId::UnionId(it) => it.lookup(db).container, 464 AdtId::UnionId(it) => it.lookup(db).container,
480 AdtId::EnumId(it) => it.lookup(db).container, 465 AdtId::EnumId(it) => it.lookup(db).container,
481 } 466 }
482 .module(db)
483 } 467 }
484} 468}
485 469
486impl HasModule for VariantId { 470impl HasModule for VariantId {
487 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 471 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
488 match self { 472 match self {
489 VariantId::EnumVariantId(it) => it.parent.lookup(db).container.module(db), 473 VariantId::EnumVariantId(it) => it.parent.lookup(db).container,
490 VariantId::StructId(it) => it.lookup(db).container.module(db), 474 VariantId::StructId(it) => it.lookup(db).container,
491 VariantId::UnionId(it) => it.lookup(db).container.module(db), 475 VariantId::UnionId(it) => it.lookup(db).container,
492 } 476 }
493 } 477 }
494} 478}
@@ -518,18 +502,18 @@ impl HasModule for GenericDefId {
518 match self { 502 match self {
519 GenericDefId::FunctionId(it) => it.lookup(db).module(db), 503 GenericDefId::FunctionId(it) => it.lookup(db).module(db),
520 GenericDefId::AdtId(it) => it.module(db), 504 GenericDefId::AdtId(it) => it.module(db),
521 GenericDefId::TraitId(it) => it.lookup(db).container.module(db), 505 GenericDefId::TraitId(it) => it.lookup(db).container,
522 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), 506 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
523 GenericDefId::ImplId(it) => it.lookup(db).container.module(db), 507 GenericDefId::ImplId(it) => it.lookup(db).container,
524 GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db), 508 GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container,
525 GenericDefId::ConstId(it) => it.lookup(db).module(db), 509 GenericDefId::ConstId(it) => it.lookup(db).module(db),
526 } 510 }
527 } 511 }
528} 512}
529 513
530impl HasModule for StaticLoc { 514impl HasModule for StaticLoc {
531 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { 515 fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
532 self.container.module(db) 516 self.container
533 } 517 }
534} 518}
535 519
@@ -542,10 +526,10 @@ impl ModuleDefId {
542 ModuleDefId::ModuleId(id) => *id, 526 ModuleDefId::ModuleId(id) => *id,
543 ModuleDefId::FunctionId(id) => id.lookup(db).module(db), 527 ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
544 ModuleDefId::AdtId(id) => id.module(db), 528 ModuleDefId::AdtId(id) => id.module(db),
545 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db), 529 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container,
546 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db), 530 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
547 ModuleDefId::StaticId(id) => id.lookup(db).container.module(db), 531 ModuleDefId::StaticId(id) => id.lookup(db).container,
548 ModuleDefId::TraitId(id) => id.lookup(db).container.module(db), 532 ModuleDefId::TraitId(id) => id.lookup(db).container,
549 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db), 533 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
550 ModuleDefId::BuiltinType(_) => return None, 534 ModuleDefId::BuiltinType(_) => return None,
551 }) 535 })
@@ -559,12 +543,12 @@ impl AttrDefId {
559 AttrDefId::FieldId(it) => it.parent.module(db).krate, 543 AttrDefId::FieldId(it) => it.parent.module(db).krate,
560 AttrDefId::AdtId(it) => it.module(db).krate, 544 AttrDefId::AdtId(it) => it.module(db).krate,
561 AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate, 545 AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
562 AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db).krate, 546 AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.krate,
563 AttrDefId::StaticId(it) => it.lookup(db).module(db).krate, 547 AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
564 AttrDefId::ConstId(it) => it.lookup(db).module(db).krate, 548 AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
565 AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, 549 AttrDefId::TraitId(it) => it.lookup(db).container.krate,
566 AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, 550 AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
567 AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, 551 AttrDefId::ImplId(it) => it.lookup(db).container.krate,
568 AttrDefId::GenericParamId(it) => { 552 AttrDefId::GenericParamId(it) => {
569 match it { 553 match it {
570 GenericParamId::TypeParamId(it) => it.parent, 554 GenericParamId::TypeParamId(it) => it.parent,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 3bb69d935..9ed48c506 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -37,9 +37,9 @@ use crate::{
37 path::{ImportAlias, ModPath, PathKind}, 37 path::{ImportAlias, ModPath, PathKind},
38 per_ns::PerNs, 38 per_ns::PerNs,
39 visibility::{RawVisibility, Visibility}, 39 visibility::{RawVisibility, Visibility},
40 AdtId, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, 40 AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
41 ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, 41 LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
42 UnionLoc, UnresolvedMacro, 42 UnresolvedMacro,
43}; 43};
44 44
45const GLOB_RECURSION_LIMIT: usize = 100; 45const GLOB_RECURSION_LIMIT: usize = 100;
@@ -1042,7 +1042,6 @@ impl ModCollector<'_, '_> {
1042 } 1042 }
1043 } 1043 }
1044 let module = self.def_collector.def_map.module_id(self.module_id); 1044 let module = self.def_collector.def_map.module_id(self.module_id);
1045 let container = ContainerId::ModuleId(module);
1046 1045
1047 let mut def = None; 1046 let mut def = None;
1048 match item { 1047 match item {
@@ -1109,9 +1108,9 @@ impl ModCollector<'_, '_> {
1109 } 1108 }
1110 ModItem::Impl(imp) => { 1109 ModItem::Impl(imp) => {
1111 let module = self.def_collector.def_map.module_id(self.module_id); 1110 let module = self.def_collector.def_map.module_id(self.module_id);
1112 let container = ContainerId::ModuleId(module); 1111 let impl_id =
1113 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) } 1112 ImplLoc { container: module, id: ItemTreeId::new(self.file_id, imp) }
1114 .intern(self.def_collector.db); 1113 .intern(self.def_collector.db);
1115 self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) 1114 self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
1116 } 1115 }
1117 ModItem::Function(id) => { 1116 ModItem::Function(id) => {
@@ -1121,7 +1120,7 @@ impl ModCollector<'_, '_> {
1121 1120
1122 def = Some(DefData { 1121 def = Some(DefData {
1123 id: FunctionLoc { 1122 id: FunctionLoc {
1124 container: container.into(), 1123 container: module.into(),
1125 id: ItemTreeId::new(self.file_id, id), 1124 id: ItemTreeId::new(self.file_id, id),
1126 } 1125 }
1127 .intern(self.def_collector.db) 1126 .intern(self.def_collector.db)
@@ -1140,7 +1139,7 @@ impl ModCollector<'_, '_> {
1140 self.collect_derives(&attrs, it.ast_id.upcast()); 1139 self.collect_derives(&attrs, it.ast_id.upcast());
1141 1140
1142 def = Some(DefData { 1141 def = Some(DefData {
1143 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } 1142 id: StructLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1144 .intern(self.def_collector.db) 1143 .intern(self.def_collector.db)
1145 .into(), 1144 .into(),
1146 name: &it.name, 1145 name: &it.name,
@@ -1157,7 +1156,7 @@ impl ModCollector<'_, '_> {
1157 self.collect_derives(&attrs, it.ast_id.upcast()); 1156 self.collect_derives(&attrs, it.ast_id.upcast());
1158 1157
1159 def = Some(DefData { 1158 def = Some(DefData {
1160 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } 1159 id: UnionLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1161 .intern(self.def_collector.db) 1160 .intern(self.def_collector.db)
1162 .into(), 1161 .into(),
1163 name: &it.name, 1162 name: &it.name,
@@ -1174,7 +1173,7 @@ impl ModCollector<'_, '_> {
1174 self.collect_derives(&attrs, it.ast_id.upcast()); 1173 self.collect_derives(&attrs, it.ast_id.upcast());
1175 1174
1176 def = Some(DefData { 1175 def = Some(DefData {
1177 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } 1176 id: EnumLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1178 .intern(self.def_collector.db) 1177 .intern(self.def_collector.db)
1179 .into(), 1178 .into(),
1180 name: &it.name, 1179 name: &it.name,
@@ -1188,7 +1187,7 @@ impl ModCollector<'_, '_> {
1188 if let Some(name) = &it.name { 1187 if let Some(name) = &it.name {
1189 def = Some(DefData { 1188 def = Some(DefData {
1190 id: ConstLoc { 1189 id: ConstLoc {
1191 container: container.into(), 1190 container: module.into(),
1192 id: ItemTreeId::new(self.file_id, id), 1191 id: ItemTreeId::new(self.file_id, id),
1193 } 1192 }
1194 .intern(self.def_collector.db) 1193 .intern(self.def_collector.db)
@@ -1203,7 +1202,7 @@ impl ModCollector<'_, '_> {
1203 let it = &self.item_tree[id]; 1202 let it = &self.item_tree[id];
1204 1203
1205 def = Some(DefData { 1204 def = Some(DefData {
1206 id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) } 1205 id: StaticLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1207 .intern(self.def_collector.db) 1206 .intern(self.def_collector.db)
1208 .into(), 1207 .into(),
1209 name: &it.name, 1208 name: &it.name,
@@ -1215,7 +1214,7 @@ impl ModCollector<'_, '_> {
1215 let it = &self.item_tree[id]; 1214 let it = &self.item_tree[id];
1216 1215
1217 def = Some(DefData { 1216 def = Some(DefData {
1218 id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) } 1217 id: TraitLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1219 .intern(self.def_collector.db) 1218 .intern(self.def_collector.db)
1220 .into(), 1219 .into(),
1221 name: &it.name, 1220 name: &it.name,
@@ -1228,7 +1227,7 @@ impl ModCollector<'_, '_> {
1228 1227
1229 def = Some(DefData { 1228 def = Some(DefData {
1230 id: TypeAliasLoc { 1229 id: TypeAliasLoc {
1231 container: container.into(), 1230 container: module.into(),
1232 id: ItemTreeId::new(self.file_id, id), 1231 id: ItemTreeId::new(self.file_id, id),
1233 } 1232 }
1234 .intern(self.def_collector.db) 1233 .intern(self.def_collector.db)
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 8258dcffb..db459b1ed 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -156,7 +156,7 @@ impl DefMap {
156 } 156 }
157 } 157 }
158 158
159 pub(super) fn resolve_path_fp_with_macro_single( 159 fn resolve_path_fp_with_macro_single(
160 &self, 160 &self,
161 db: &dyn DefDatabase, 161 db: &dyn DefDatabase,
162 mode: ResolveMode, 162 mode: ResolveMode,
@@ -384,10 +384,16 @@ impl DefMap {
384 } 384 }
385 } 385 }
386 }; 386 };
387 let from_extern_prelude = self 387 // Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude
388 .extern_prelude 388 // from the crate DefMap.
389 .get(name) 389 let from_extern_prelude = match self.block {
390 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); 390 Some(_) => PerNs::none(),
391 None => self
392 .extern_prelude
393 .get(name)
394 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395 };
396
391 let from_prelude = self.resolve_in_prelude(db, name); 397 let from_prelude = self.resolve_in_prelude(db, name);
392 398
393 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) 399 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 77ff21739..42736171e 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -19,10 +19,10 @@ use crate::{
19 path::{ModPath, PathKind}, 19 path::{ModPath, PathKind},
20 per_ns::PerNs, 20 per_ns::PerNs,
21 visibility::{RawVisibility, Visibility}, 21 visibility::{RawVisibility, Visibility},
22 AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId, 22 AdtId, AssocContainerId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
23 EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId, 23 FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId, LocalModuleId,
24 LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 24 Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
25 TypeParamId, VariantId, 25 VariantId,
26}; 26};
27 27
28#[derive(Debug, Clone, Default)] 28#[derive(Debug, Clone, Default)]
@@ -342,6 +342,16 @@ impl Resolver {
342 traits.extend(prelude_def_map[prelude.local_id].scope.traits()); 342 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
343 } 343 }
344 traits.extend(m.def_map[m.module_id].scope.traits()); 344 traits.extend(m.def_map[m.module_id].scope.traits());
345
346 // Add all traits that are in scope because of the containing DefMaps
347 m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
348 if let Some(prelude) = def_map.prelude() {
349 let prelude_def_map = prelude.def_map(db);
350 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
351 }
352 traits.extend(def_map[module].scope.traits());
353 None::<()>
354 });
345 } 355 }
346 } 356 }
347 traits 357 traits
@@ -678,19 +688,10 @@ impl HasResolver for DefWithBodyId {
678 } 688 }
679} 689}
680 690
681impl HasResolver for ContainerId {
682 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
683 match self {
684 ContainerId::ModuleId(it) => it.resolver(db),
685 ContainerId::DefWithBodyId(it) => it.module(db).resolver(db),
686 }
687 }
688}
689
690impl HasResolver for AssocContainerId { 691impl HasResolver for AssocContainerId {
691 fn resolver(self, db: &dyn DefDatabase) -> Resolver { 692 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
692 match self { 693 match self {
693 AssocContainerId::ContainerId(it) => it.resolver(db), 694 AssocContainerId::ModuleId(it) => it.resolver(db),
694 AssocContainerId::TraitId(it) => it.resolver(db), 695 AssocContainerId::TraitId(it) => it.resolver(db),
695 AssocContainerId::ImplId(it) => it.resolver(db), 696 AssocContainerId::ImplId(it) => it.resolver(db),
696 } 697 }
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index 5271110d2..f649ab925 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -16,9 +16,13 @@ rustc-hash = "1.0.0"
16la-arena = { version = "0.2.0", path = "../../lib/arena" } 16la-arena = { version = "0.2.0", path = "../../lib/arena" }
17 17
18base_db = { path = "../base_db", version = "0.0.0" } 18base_db = { path = "../base_db", version = "0.0.0" }
19cfg = { path = "../cfg", version = "0.0.0" }
19syntax = { path = "../syntax", version = "0.0.0" } 20syntax = { path = "../syntax", version = "0.0.0" }
20parser = { path = "../parser", version = "0.0.0" } 21parser = { path = "../parser", version = "0.0.0" }
21profile = { path = "../profile", version = "0.0.0" } 22profile = { path = "../profile", version = "0.0.0" }
22tt = { path = "../tt", version = "0.0.0" } 23tt = { path = "../tt", version = "0.0.0" }
23mbe = { path = "../mbe", version = "0.0.0" } 24mbe = { path = "../mbe", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" } 25
26[dev-dependencies]
27test_utils = { path = "../test_utils" }
28expect-test = "1.1"
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index b7f1aae8f..dfdb9cf59 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -267,13 +267,14 @@ fn partial_ord_expand(
267#[cfg(test)] 267#[cfg(test)]
268mod tests { 268mod tests {
269 use base_db::{fixture::WithFixture, CrateId, SourceDatabase}; 269 use base_db::{fixture::WithFixture, CrateId, SourceDatabase};
270 use expect_test::{expect, Expect};
270 use name::{known, Name}; 271 use name::{known, Name};
271 272
272 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; 273 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
273 274
274 use super::*; 275 use super::*;
275 276
276 fn expand_builtin_derive(s: &str, name: Name) -> String { 277 fn expand_builtin_derive(ra_fixture: &str, name: Name) -> String {
277 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); 278 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
278 let fixture = format!( 279 let fixture = format!(
279 r#"//- /main.rs crate:main deps:core 280 r#"//- /main.rs crate:main deps:core
@@ -282,7 +283,7 @@ $0
282//- /lib.rs crate:core 283//- /lib.rs crate:core
283// empty 284// empty
284"#, 285"#,
285 s 286 ra_fixture
286 ); 287 );
287 288
288 let (db, file_pos) = TestDB::with_position(&fixture); 289 let (db, file_pos) = TestDB::with_position(&fixture);
@@ -314,66 +315,57 @@ $0
314 parsed.text().to_string() 315 parsed.text().to_string()
315 } 316 }
316 317
318 fn check_derive(ra_fixture: &str, name: Name, expected: Expect) {
319 let expanded = expand_builtin_derive(ra_fixture, name);
320 expected.assert_eq(&expanded);
321 }
322
317 #[test] 323 #[test]
318 fn test_copy_expand_simple() { 324 fn test_copy_expand_simple() {
319 let expanded = expand_builtin_derive( 325 check_derive(
320 r#" 326 r#"
321 #[derive(Copy)] 327 #[derive(Copy)]
322 struct Foo; 328 struct Foo;
323"#, 329 "#,
324 known::Copy, 330 known::Copy,
331 expect![["impl< >core::marker::CopyforFoo< >{}"]],
325 ); 332 );
326
327 assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}");
328 } 333 }
329 334
330 #[test] 335 #[test]
331 fn test_copy_expand_with_type_params() { 336 fn test_copy_expand_with_type_params() {
332 let expanded = expand_builtin_derive( 337 check_derive(
333 r#" 338 r#"
334 #[derive(Copy)] 339 #[derive(Copy)]
335 struct Foo<A, B>; 340 struct Foo<A, B>;
336"#, 341 "#,
337 known::Copy, 342 known::Copy,
338 ); 343 expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
339
340 assert_eq!(
341 expanded,
342 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
343 ); 344 );
344 } 345 }
345 346
346 #[test] 347 #[test]
347 fn test_copy_expand_with_lifetimes() { 348 fn test_copy_expand_with_lifetimes() {
348 let expanded = expand_builtin_derive( 349 check_derive(
349 r#" 350 r#"
350 #[derive(Copy)] 351 #[derive(Copy)]
351 struct Foo<A, B, 'a, 'b>; 352 struct Foo<A, B, 'a, 'b>;
352"#, 353 "#,
353 known::Copy, 354 known::Copy,
354 ); 355 // We currently just ignore lifetimes
355 356 expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
356 // We currently just ignore lifetimes
357
358 assert_eq!(
359 expanded,
360 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
361 ); 357 );
362 } 358 }
363 359
364 #[test] 360 #[test]
365 fn test_clone_expand() { 361 fn test_clone_expand() {
366 let expanded = expand_builtin_derive( 362 check_derive(
367 r#" 363 r#"
368 #[derive(Clone)] 364 #[derive(Clone)]
369 struct Foo<A, B>; 365 struct Foo<A, B>;
370"#, 366 "#,
371 known::Clone, 367 known::Clone,
372 ); 368 expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]],
373
374 assert_eq!(
375 expanded,
376 "impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"
377 ); 369 );
378 } 370 }
379} 371}
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index eb57ea7d6..2a79c892b 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -5,6 +5,7 @@ use crate::{
5}; 5};
6 6
7use base_db::{AnchoredPath, FileId}; 7use base_db::{AnchoredPath, FileId};
8use cfg::CfgExpr;
8use either::Either; 9use either::Either;
9use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; 10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 11use parser::FragmentKind;
@@ -97,6 +98,7 @@ register_builtin! {
97 (format_args_nl, FormatArgsNl) => format_args_expand, 98 (format_args_nl, FormatArgsNl) => format_args_expand,
98 (llvm_asm, LlvmAsm) => asm_expand, 99 (llvm_asm, LlvmAsm) => asm_expand,
99 (asm, Asm) => asm_expand, 100 (asm, Asm) => asm_expand,
101 (cfg, Cfg) => cfg_expand,
100 102
101 EAGER: 103 EAGER:
102 (compile_error, CompileError) => compile_error_expand, 104 (compile_error, CompileError) => compile_error_expand,
@@ -258,6 +260,18 @@ fn asm_expand(
258 ExpandResult::ok(expanded) 260 ExpandResult::ok(expanded)
259} 261}
260 262
263fn cfg_expand(
264 db: &dyn AstDatabase,
265 id: LazyMacroId,
266 tt: &tt::Subtree,
267) -> ExpandResult<tt::Subtree> {
268 let loc = db.lookup_intern_macro(id);
269 let expr = CfgExpr::parse(tt);
270 let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
271 let expanded = if enabled { quote!(true) } else { quote!(false) };
272 ExpandResult::ok(expanded)
273}
274
261fn unquote_str(lit: &tt::Literal) -> Option<String> { 275fn unquote_str(lit: &tt::Literal) -> Option<String> {
262 let lit = ast::make::tokens::literal(&lit.to_string()); 276 let lit = ast::make::tokens::literal(&lit.to_string());
263 let token = ast::String::cast(lit)?; 277 let token = ast::String::cast(lit)?;
@@ -477,6 +491,7 @@ mod tests {
477 MacroCallLoc, 491 MacroCallLoc,
478 }; 492 };
479 use base_db::{fixture::WithFixture, SourceDatabase}; 493 use base_db::{fixture::WithFixture, SourceDatabase};
494 use expect_test::{expect, Expect};
480 use std::sync::Arc; 495 use std::sync::Arc;
481 use syntax::ast::NameOwner; 496 use syntax::ast::NameOwner;
482 497
@@ -560,87 +575,86 @@ mod tests {
560 db.parse_or_expand(file_id).unwrap().to_string() 575 db.parse_or_expand(file_id).unwrap().to_string()
561 } 576 }
562 577
578 fn check_expansion(ra_fixture: &str, expect: Expect) {
579 let expansion = expand_builtin_macro(ra_fixture);
580 expect.assert_eq(&expansion);
581 }
582
563 #[test] 583 #[test]
564 fn test_column_expand() { 584 fn test_column_expand() {
565 let expanded = expand_builtin_macro( 585 check_expansion(
566 r#" 586 r#"
567 #[rustc_builtin_macro] 587 #[rustc_builtin_macro]
568 macro_rules! column {() => {}} 588 macro_rules! column {() => {}}
569 column!() 589 column!()
570 "#, 590 "#,
591 expect![["0"]],
571 ); 592 );
572
573 assert_eq!(expanded, "0");
574 } 593 }
575 594
576 #[test] 595 #[test]
577 fn test_line_expand() { 596 fn test_line_expand() {
578 let expanded = expand_builtin_macro( 597 check_expansion(
579 r#" 598 r#"
580 #[rustc_builtin_macro] 599 #[rustc_builtin_macro]
581 macro_rules! line {() => {}} 600 macro_rules! line {() => {}}
582 line!() 601 line!()
583 "#, 602 "#,
603 expect![["0"]],
584 ); 604 );
585
586 assert_eq!(expanded, "0");
587 } 605 }
588 606
589 #[test] 607 #[test]
590 fn test_stringify_expand() { 608 fn test_stringify_expand() {
591 let expanded = expand_builtin_macro( 609 check_expansion(
592 r#" 610 r#"
593 #[rustc_builtin_macro] 611 #[rustc_builtin_macro]
594 macro_rules! stringify {() => {}} 612 macro_rules! stringify {() => {}}
595 stringify!(a b c) 613 stringify!(a b c)
596 "#, 614 "#,
615 expect![["\"a b c\""]],
597 ); 616 );
598
599 assert_eq!(expanded, "\"a b c\"");
600 } 617 }
601 618
602 #[test] 619 #[test]
603 fn test_env_expand() { 620 fn test_env_expand() {
604 let expanded = expand_builtin_macro( 621 check_expansion(
605 r#" 622 r#"
606 #[rustc_builtin_macro] 623 #[rustc_builtin_macro]
607 macro_rules! env {() => {}} 624 macro_rules! env {() => {}}
608 env!("TEST_ENV_VAR") 625 env!("TEST_ENV_VAR")
609 "#, 626 "#,
627 expect![["\"__RA_UNIMPLEMENTED__\""]],
610 ); 628 );
611
612 assert_eq!(expanded, "\"__RA_UNIMPLEMENTED__\"");
613 } 629 }
614 630
615 #[test] 631 #[test]
616 fn test_option_env_expand() { 632 fn test_option_env_expand() {
617 let expanded = expand_builtin_macro( 633 check_expansion(
618 r#" 634 r#"
619 #[rustc_builtin_macro] 635 #[rustc_builtin_macro]
620 macro_rules! option_env {() => {}} 636 macro_rules! option_env {() => {}}
621 option_env!("TEST_ENV_VAR") 637 option_env!("TEST_ENV_VAR")
622 "#, 638 "#,
639 expect![["std::option::Option::None:: < &str>"]],
623 ); 640 );
624
625 assert_eq!(expanded, "std::option::Option::None:: < &str>");
626 } 641 }
627 642
628 #[test] 643 #[test]
629 fn test_file_expand() { 644 fn test_file_expand() {
630 let expanded = expand_builtin_macro( 645 check_expansion(
631 r#" 646 r#"
632 #[rustc_builtin_macro] 647 #[rustc_builtin_macro]
633 macro_rules! file {() => {}} 648 macro_rules! file {() => {}}
634 file!() 649 file!()
635 "#, 650 "#,
651 expect![[r#""""#]],
636 ); 652 );
637
638 assert_eq!(expanded, "\"\"");
639 } 653 }
640 654
641 #[test] 655 #[test]
642 fn test_assert_expand() { 656 fn test_assert_expand() {
643 let expanded = expand_builtin_macro( 657 check_expansion(
644 r#" 658 r#"
645 #[rustc_builtin_macro] 659 #[rustc_builtin_macro]
646 macro_rules! assert { 660 macro_rules! assert {
@@ -649,14 +663,13 @@ mod tests {
649 } 663 }
650 assert!(true, "{} {:?}", arg1(a, b, c), arg2); 664 assert!(true, "{} {:?}", arg1(a, b, c), arg2);
651 "#, 665 "#,
666 expect![["{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}"]],
652 ); 667 );
653
654 assert_eq!(expanded, "{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}");
655 } 668 }
656 669
657 #[test] 670 #[test]
658 fn test_compile_error_expand() { 671 fn test_compile_error_expand() {
659 let expanded = expand_builtin_macro( 672 check_expansion(
660 r#" 673 r#"
661 #[rustc_builtin_macro] 674 #[rustc_builtin_macro]
662 macro_rules! compile_error { 675 macro_rules! compile_error {
@@ -665,15 +678,14 @@ mod tests {
665 } 678 }
666 compile_error!("error!"); 679 compile_error!("error!");
667 "#, 680 "#,
681 // This expands to nothing (since it's in item position), but emits an error.
682 expect![[""]],
668 ); 683 );
669
670 // This expands to nothing (since it's in item position), but emits an error.
671 assert_eq!(expanded, "");
672 } 684 }
673 685
674 #[test] 686 #[test]
675 fn test_format_args_expand() { 687 fn test_format_args_expand() {
676 let expanded = expand_builtin_macro( 688 check_expansion(
677 r#" 689 r#"
678 #[rustc_builtin_macro] 690 #[rustc_builtin_macro]
679 macro_rules! format_args { 691 macro_rules! format_args {
@@ -682,17 +694,15 @@ mod tests {
682 } 694 }
683 format_args!("{} {:?}", arg1(a, b, c), arg2); 695 format_args!("{} {:?}", arg1(a, b, c), arg2);
684 "#, 696 "#,
685 ); 697 expect![[
686 698 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
687 assert_eq!( 699 ]],
688 expanded,
689 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
690 ); 700 );
691 } 701 }
692 702
693 #[test] 703 #[test]
694 fn test_format_args_expand_with_comma_exprs() { 704 fn test_format_args_expand_with_comma_exprs() {
695 let expanded = expand_builtin_macro( 705 check_expansion(
696 r#" 706 r#"
697 #[rustc_builtin_macro] 707 #[rustc_builtin_macro]
698 macro_rules! format_args { 708 macro_rules! format_args {
@@ -701,17 +711,15 @@ mod tests {
701 } 711 }
702 format_args!("{} {:?}", a::<A,B>(), b); 712 format_args!("{} {:?}", a::<A,B>(), b);
703 "#, 713 "#,
704 ); 714 expect![[
705 715 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"#
706 assert_eq!( 716 ]],
707 expanded,
708 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"#
709 ); 717 );
710 } 718 }
711 719
712 #[test] 720 #[test]
713 fn test_include_bytes_expand() { 721 fn test_include_bytes_expand() {
714 let expanded = expand_builtin_macro( 722 check_expansion(
715 r#" 723 r#"
716 #[rustc_builtin_macro] 724 #[rustc_builtin_macro]
717 macro_rules! include_bytes { 725 macro_rules! include_bytes {
@@ -720,21 +728,19 @@ mod tests {
720 } 728 }
721 include_bytes("foo"); 729 include_bytes("foo");
722 "#, 730 "#,
731 expect![[r#"b"""#]],
723 ); 732 );
724
725 assert_eq!(expanded, r#"b"""#);
726 } 733 }
727 734
728 #[test] 735 #[test]
729 fn test_concat_expand() { 736 fn test_concat_expand() {
730 let expanded = expand_builtin_macro( 737 check_expansion(
731 r##" 738 r##"
732 #[rustc_builtin_macro] 739 #[rustc_builtin_macro]
733 macro_rules! concat {} 740 macro_rules! concat {}
734 concat!("foo", "r", 0, r#"bar"#, false); 741 concat!("foo", "r", 0, r#"bar"#, false);
735 "##, 742 "##,
743 expect![[r#""foor0barfalse""#]],
736 ); 744 );
737
738 assert_eq!(expanded, r#""foor0barfalse""#);
739 } 745 }
740} 746}
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index c94fb580a..e833e032c 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -154,6 +154,7 @@ pub mod known {
154 macro_rules, 154 macro_rules,
155 derive, 155 derive,
156 doc, 156 doc,
157 cfg,
157 cfg_attr, 158 cfg_attr,
158 // Components of known path (value or mod name) 159 // Components of known path (value or mod name)
159 std, 160 std,
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs
index 219bc2097..08bc5aa49 100644
--- a/crates/hir_expand/src/quote.rs
+++ b/crates/hir_expand/src/quote.rs
@@ -188,8 +188,9 @@ macro_rules! impl_to_to_tokentrees {
188 188
189impl_to_to_tokentrees! { 189impl_to_to_tokentrees! {
190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; 190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}}; 191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}}; 192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
193 bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
193 tt::Leaf => self { self }; 194 tt::Leaf => self { self };
194 tt::Literal => self { self }; 195 tt::Literal => self { self };
195 tt::Ident => self { self }; 196 tt::Ident => self { self };
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 6131ebee8..b9c93f56f 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -29,9 +29,9 @@ hir_expand = { path = "../hir_expand", version = "0.0.0" }
29base_db = { path = "../base_db", version = "0.0.0" } 29base_db = { path = "../base_db", version = "0.0.0" }
30profile = { path = "../profile", version = "0.0.0" } 30profile = { path = "../profile", version = "0.0.0" }
31syntax = { path = "../syntax", version = "0.0.0" } 31syntax = { path = "../syntax", version = "0.0.0" }
32test_utils = { path = "../test_utils", version = "0.0.0" }
33 32
34[dev-dependencies] 33[dev-dependencies]
34test_utils = { path = "../test_utils" }
35expect-test = "1.1" 35expect-test = "1.1"
36tracing = "0.1" 36tracing = "0.1"
37tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 37tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 6bca7aa0d..86f937e1d 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -706,6 +706,35 @@ fn x(a: S) {
706 } 706 }
707 707
708 #[test] 708 #[test]
709 fn import_extern_crate_clash_with_inner_item() {
710 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
711
712 check_diagnostics(
713 r#"
714//- /lib.rs crate:lib deps:jwt
715mod permissions;
716
717use permissions::jwt;
718
719fn f() {
720 fn inner() {}
721 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
722}
723
724//- /permissions.rs
725pub mod jwt {
726 pub struct Claims {}
727}
728
729//- /jwt/lib.rs crate:jwt
730pub struct Claims {
731 field: u8,
732}
733 "#,
734 );
735 }
736
737 #[test]
709 fn break_outside_of_loop() { 738 fn break_outside_of_loop() {
710 check_diagnostics( 739 check_diagnostics(
711 r#" 740 r#"
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index e230f9765..3605ca581 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -99,9 +99,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
99 let body = self.db.body(func.into()); 99 let body = self.db.body(func.into());
100 100
101 // Recursively validate inner scope items, such as static variables and constants. 101 // Recursively validate inner scope items, such as static variables and constants.
102 for (item_id, _) in body.item_scope.values() { 102 let db = self.db;
103 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 103 for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
104 validator.validate_item(item_id); 104 for (_, module) in block_def_map.modules() {
105 for (def_id, _) in module.scope.values() {
106 let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
107 validator.validate_item(def_id);
108 }
109 }
105 } 110 }
106 111
107 // Check whether non-snake case identifiers are allowed for this function. 112 // Check whether non-snake case identifiers are allowed for this function.
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index a0882a2a1..ab51cb0a6 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -6,7 +6,7 @@ use arrayvec::ArrayVec;
6use chalk_ir::Mutability; 6use chalk_ir::Mutability;
7use hir_def::{ 7use hir_def::{
8 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, 8 db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
9 AssocContainerId, HasModule, Lookup, ModuleId, TraitId, 9 AssocContainerId, Lookup, ModuleId, TraitId,
10}; 10};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
@@ -611,7 +611,7 @@ impl HirDisplay for CallableSig {
611} 611}
612 612
613fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { 613fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
614 let krate = trait_.lookup(db).container.module(db).krate(); 614 let krate = trait_.lookup(db).container.krate();
615 let fn_traits = [ 615 let fn_traits = [
616 db.lang_item(krate, "fn".into()), 616 db.lang_item(krate, "fn".into()),
617 db.lang_item(krate, "fn_mut".into()), 617 db.lang_item(krate, "fn_mut".into()),
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 5d541104e..ae3554bac 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -260,7 +260,7 @@ impl<'a> InferenceContext<'a> {
260 })); 260 }));
261 Some(trait_substs) 261 Some(trait_substs)
262 } 262 }
263 AssocContainerId::ContainerId(_) => None, 263 AssocContainerId::ModuleId(_) => None,
264 }; 264 };
265 265
266 self.write_assoc_resolution(id, item); 266 self.write_assoc_resolution(id, item);
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index b90fdc382..5fa83567b 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -1130,8 +1130,8 @@ impl CallableDefId {
1130 let db = db.upcast(); 1130 let db = db.upcast();
1131 match self { 1131 match self {
1132 CallableDefId::FunctionId(f) => f.lookup(db).module(db), 1132 CallableDefId::FunctionId(f) => f.lookup(db).module(db),
1133 CallableDefId::StructId(s) => s.lookup(db).container.module(db), 1133 CallableDefId::StructId(s) => s.lookup(db).container,
1134 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db), 1134 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container,
1135 } 1135 }
1136 .krate() 1136 .krate()
1137 } 1137 }
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 24db33c49..ccc12c075 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -267,7 +267,7 @@ impl Ty {
267 LangItemTarget::ImplDefId(it) => Some(it), 267 LangItemTarget::ImplDefId(it) => Some(it),
268 _ => None, 268 _ => None,
269 }) 269 })
270 .map(|it| it.lookup(db.upcast()).container.module(db.upcast()).krate()) 270 .map(|it| it.lookup(db.upcast()).container.krate())
271 .collect(); 271 .collect();
272 Some(res) 272 Some(res)
273 } 273 }
@@ -715,7 +715,7 @@ fn transform_receiver_ty(
715 .fill_with_unknown() 715 .fill_with_unknown()
716 .build() 716 .build()
717 } 717 }
718 AssocContainerId::ContainerId(_) => unreachable!(), 718 AssocContainerId::ModuleId(_) => unreachable!(),
719 }; 719 };
720 let sig = db.callable_item_signature(function_id.into()); 720 let sig = db.callable_item_signature(function_id.into());
721 Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) 721 Some(sig.value.params()[0].clone().subst_bound_vars(&substs))
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 7386a4e7b..fc770ea60 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -13,7 +13,7 @@ use std::{env, sync::Arc};
13use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 13use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
14use expect_test::Expect; 14use expect_test::Expect;
15use hir_def::{ 15use hir_def::{
16 body::{BodySourceMap, SyntheticSyntax}, 16 body::{Body, BodySourceMap, SyntheticSyntax},
17 child_by_source::ChildBySource, 17 child_by_source::ChildBySource,
18 db::DefDatabase, 18 db::DefDatabase,
19 item_scope::ItemScope, 19 item_scope::ItemScope,
@@ -234,13 +234,13 @@ fn visit_module(
234 let def = it.into(); 234 let def = it.into();
235 cb(def); 235 cb(def);
236 let body = db.body(def); 236 let body = db.body(def);
237 visit_scope(db, crate_def_map, &body.item_scope, cb); 237 visit_body(db, &body, cb);
238 } 238 }
239 AssocItemId::ConstId(it) => { 239 AssocItemId::ConstId(it) => {
240 let def = it.into(); 240 let def = it.into();
241 cb(def); 241 cb(def);
242 let body = db.body(def); 242 let body = db.body(def);
243 visit_scope(db, crate_def_map, &body.item_scope, cb); 243 visit_body(db, &body, cb);
244 } 244 }
245 AssocItemId::TypeAliasId(_) => (), 245 AssocItemId::TypeAliasId(_) => (),
246 } 246 }
@@ -259,19 +259,19 @@ fn visit_module(
259 let def = it.into(); 259 let def = it.into();
260 cb(def); 260 cb(def);
261 let body = db.body(def); 261 let body = db.body(def);
262 visit_scope(db, crate_def_map, &body.item_scope, cb); 262 visit_body(db, &body, cb);
263 } 263 }
264 ModuleDefId::ConstId(it) => { 264 ModuleDefId::ConstId(it) => {
265 let def = it.into(); 265 let def = it.into();
266 cb(def); 266 cb(def);
267 let body = db.body(def); 267 let body = db.body(def);
268 visit_scope(db, crate_def_map, &body.item_scope, cb); 268 visit_body(db, &body, cb);
269 } 269 }
270 ModuleDefId::StaticId(it) => { 270 ModuleDefId::StaticId(it) => {
271 let def = it.into(); 271 let def = it.into();
272 cb(def); 272 cb(def);
273 let body = db.body(def); 273 let body = db.body(def);
274 visit_scope(db, crate_def_map, &body.item_scope, cb); 274 visit_body(db, &body, cb);
275 } 275 }
276 ModuleDefId::TraitId(it) => { 276 ModuleDefId::TraitId(it) => {
277 let trait_data = db.trait_data(it); 277 let trait_data = db.trait_data(it);
@@ -288,6 +288,14 @@ fn visit_module(
288 } 288 }
289 } 289 }
290 } 290 }
291
292 fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) {
293 for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
294 for (mod_id, _) in def_map.modules() {
295 visit_module(db, &def_map, mod_id, cb);
296 }
297 }
298 }
291} 299}
292 300
293fn ellipsize(mut text: String, max_len: usize) -> String { 301fn ellipsize(mut text: String, max_len: usize) -> String {
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 528092082..e185b1c0a 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3174,6 +3174,39 @@ fn f() {
3174} 3174}
3175 3175
3176#[test] 3176#[test]
3177fn trait_in_scope_with_inner_item() {
3178 check_infer(
3179 r#"
3180mod m {
3181 pub trait Tr {
3182 fn method(&self) -> u8 { 0 }
3183 }
3184
3185 impl Tr for () {}
3186}
3187
3188use m::Tr;
3189
3190fn f() {
3191 fn inner() {
3192 ().method();
3193 //^^^^^^^^^^^ u8
3194 }
3195}
3196 "#,
3197 expect![[r#"
3198 46..50 'self': &Self
3199 58..63 '{ 0 }': u8
3200 60..61 '0': u8
3201 115..185 '{ ... } }': ()
3202 132..183 '{ ... }': ()
3203 142..144 '()': ()
3204 142..153 '().method()': u8
3205 "#]],
3206 );
3207}
3208
3209#[test]
3177fn inner_use_in_block() { 3210fn inner_use_in_block() {
3178 check_types( 3211 check_types(
3179 r#" 3212 r#"
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 4378a9723..565672b6b 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -424,7 +424,7 @@ pub(crate) fn trait_datum_query(
424 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 424 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
425 let flags = rust_ir::TraitFlags { 425 let flags = rust_ir::TraitFlags {
426 auto: trait_data.auto, 426 auto: trait_data.auto,
427 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate() != krate, 427 upstream: trait_.lookup(db.upcast()).container.krate() != krate,
428 non_enumerable: true, 428 non_enumerable: true,
429 coinductive: false, // only relevant for Chalk testing 429 coinductive: false, // only relevant for Chalk testing
430 // FIXME: set these flags correctly 430 // FIXME: set these flags correctly
@@ -548,7 +548,7 @@ fn impl_def_datum(
548 let generic_params = generics(db.upcast(), impl_id.into()); 548 let generic_params = generics(db.upcast(), impl_id.into());
549 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 549 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
550 let trait_ = trait_ref.trait_; 550 let trait_ = trait_ref.trait_;
551 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate() == krate { 551 let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
552 rust_ir::ImplType::Local 552 rust_ir::ImplType::Local
553 } else { 553 } else {
554 rust_ir::ImplType::External 554 rust_ir::ImplType::External
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 65b79df0d..7351e4e54 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -259,6 +259,6 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
259 match container { 259 match container {
260 AssocContainerId::ImplId(it) => Some(it.into()), 260 AssocContainerId::ImplId(it) => Some(it.into()),
261 AssocContainerId::TraitId(it) => Some(it.into()), 261 AssocContainerId::TraitId(it) => Some(it.into()),
262 AssocContainerId::ContainerId(_) => None, 262 AssocContainerId::ModuleId(_) => None,
263 } 263 }
264} 264}
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f7c5efaf3..107bd8432 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -27,7 +27,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
27ide_db = { path = "../ide_db", version = "0.0.0" } 27ide_db = { path = "../ide_db", version = "0.0.0" }
28cfg = { path = "../cfg", version = "0.0.0" } 28cfg = { path = "../cfg", version = "0.0.0" }
29profile = { path = "../profile", version = "0.0.0" } 29profile = { path = "../profile", version = "0.0.0" }
30test_utils = { path = "../test_utils", version = "0.0.0" }
31ide_assists = { path = "../ide_assists", version = "0.0.0" } 30ide_assists = { path = "../ide_assists", version = "0.0.0" }
32ide_ssr = { path = "../ide_ssr", version = "0.0.0" } 31ide_ssr = { path = "../ide_ssr", version = "0.0.0" }
33ide_completion = { path = "../ide_completion", version = "0.0.0" } 32ide_completion = { path = "../ide_completion", version = "0.0.0" }
@@ -37,4 +36,5 @@ ide_completion = { path = "../ide_completion", version = "0.0.0" }
37hir = { path = "../hir", version = "0.0.0" } 36hir = { path = "../hir", version = "0.0.0" }
38 37
39[dev-dependencies] 38[dev-dependencies]
39test_utils = { path = "../test_utils" }
40expect-test = "1.1" 40expect-test = "1.1"
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs
index 84b8883de..2df9266b4 100644
--- a/crates/ide/src/display/short_label.rs
+++ b/crates/ide/src/display/short_label.rs
@@ -71,11 +71,7 @@ impl ShortLabel for ast::TypeAlias {
71 71
72impl ShortLabel for ast::Const { 72impl ShortLabel for ast::Const {
73 fn short_label(&self) -> Option<String> { 73 fn short_label(&self) -> Option<String> {
74 let mut new_buf = short_label_from_ty(self, self.ty(), "const ")?; 74 short_label_from_ty(self, self.ty(), "const ")
75 if let Some(expr) = self.body() {
76 format_to!(new_buf, " = {}", expr.syntax());
77 }
78 Some(new_buf)
79 } 75 }
80} 76}
81 77
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 5d1cc2052..ea45086ce 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,3 +1,4 @@
1use either::Either;
1use hir::{ 2use hir::{
2 Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource, 3 Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
3 HirDisplay, Module, ModuleDef, ModuleSource, Semantics, 4 HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
@@ -366,7 +367,7 @@ fn hover_for_definition(
366 .and_then(|fd| hover_for_builtin(fd, it)) 367 .and_then(|fd| hover_for_builtin(fd, it))
367 .or_else(|| Some(Markup::fenced_block(&it.name()))), 368 .or_else(|| Some(Markup::fenced_block(&it.name()))),
368 }, 369 },
369 Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), 370 Definition::Local(it) => hover_for_local(it, db),
370 Definition::SelfType(impl_def) => { 371 Definition::SelfType(impl_def) => {
371 impl_def.target_ty(db).as_adt().and_then(|adt| match adt { 372 impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
372 Adt::Struct(it) => from_def_source(db, it, mod_path), 373 Adt::Struct(it) => from_def_source(db, it, mod_path),
@@ -405,6 +406,29 @@ fn hover_for_definition(
405 } 406 }
406} 407}
407 408
409fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
410 let ty = it.ty(db);
411 let ty = ty.display(db);
412 let is_mut = if it.is_mut(db) { "mut " } else { "" };
413 let desc = match it.source(db).value {
414 Either::Left(ident) => {
415 let name = it.name(db).unwrap();
416 let let_kw = if ident
417 .syntax()
418 .parent()
419 .map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION)
420 {
421 "let "
422 } else {
423 ""
424 };
425 format!("{}{}{}: {}", let_kw, is_mut, name, ty)
426 }
427 Either::Right(_) => format!("{}self: {}", is_mut, ty),
428 };
429 hover_markup(None, Some(desc), None)
430}
431
408fn hover_for_keyword( 432fn hover_for_keyword(
409 sema: &Semantics<RootDatabase>, 433 sema: &Semantics<RootDatabase>,
410 links_in_hover: bool, 434 links_in_hover: bool,
@@ -574,7 +598,7 @@ fn main() {
574 *iter* 598 *iter*
575 599
576 ```rust 600 ```rust
577 Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>> 601 let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
578 ``` 602 ```
579 "#]], 603 "#]],
580 ); 604 );
@@ -798,7 +822,7 @@ fn main() {
798 ``` 822 ```
799 823
800 ```rust 824 ```rust
801 const foo: u32 = 123 825 const foo: u32
802 ``` 826 ```
803 "#]], 827 "#]],
804 ); 828 );
@@ -831,7 +855,7 @@ fn main() {
831 *zz* 855 *zz*
832 856
833 ```rust 857 ```rust
834 Test<i32, u8> 858 let zz: Test<i32, u8>
835 ``` 859 ```
836 "#]], 860 "#]],
837 ); 861 );
@@ -870,7 +894,7 @@ fn main() { let b$0ar = Some(12); }
870 *bar* 894 *bar*
871 895
872 ```rust 896 ```rust
873 Option<i32> 897 let bar: Option<i32>
874 ``` 898 ```
875 "#]], 899 "#]],
876 ); 900 );
@@ -938,7 +962,7 @@ fn main() {
938 *foo* 962 *foo*
939 963
940 ```rust 964 ```rust
941 i32 965 foo: i32
942 ``` 966 ```
943 "#]], 967 "#]],
944 ) 968 )
@@ -952,7 +976,7 @@ fn main() {
952 *foo* 976 *foo*
953 977
954 ```rust 978 ```rust
955 i32 979 foo: i32
956 ``` 980 ```
957 "#]], 981 "#]],
958 ) 982 )
@@ -966,7 +990,7 @@ fn main() {
966 *foo* 990 *foo*
967 991
968 ```rust 992 ```rust
969 i32 993 foo: i32
970 ``` 994 ```
971 "#]], 995 "#]],
972 ) 996 )
@@ -980,7 +1004,7 @@ fn main() {
980 *foo* 1004 *foo*
981 1005
982 ```rust 1006 ```rust
983 i32 1007 foo: i32
984 ``` 1008 ```
985 "#]], 1009 "#]],
986 ) 1010 )
@@ -1000,7 +1024,7 @@ fn main() {
1000 *_x* 1024 *_x*
1001 1025
1002 ```rust 1026 ```rust
1003 impl Deref<Target = u8> + DerefMut<Target = u8> 1027 _x: impl Deref<Target = u8> + DerefMut<Target = u8>
1004 ``` 1028 ```
1005 "#]], 1029 "#]],
1006 ) 1030 )
@@ -1022,7 +1046,7 @@ fn main() { let foo_$0test = Thing::new(); }
1022 *foo_test* 1046 *foo_test*
1023 1047
1024 ```rust 1048 ```rust
1025 Thing 1049 let foo_test: Thing
1026 ``` 1050 ```
1027 "#]], 1051 "#]],
1028 ) 1052 )
@@ -1081,7 +1105,7 @@ fn main() {
1081 ``` 1105 ```
1082 1106
1083 ```rust 1107 ```rust
1084 const C: u32 = 1 1108 const C: u32
1085 ``` 1109 ```
1086 "#]], 1110 "#]],
1087 ) 1111 )
@@ -1182,7 +1206,7 @@ fn y() {
1182 *x* 1206 *x*
1183 1207
1184 ```rust 1208 ```rust
1185 i32 1209 let x: i32
1186 ``` 1210 ```
1187 "#]], 1211 "#]],
1188 ) 1212 )
@@ -1259,7 +1283,7 @@ fn foo(bar:u32) { let a = id!(ba$0r); }
1259 *bar* 1283 *bar*
1260 1284
1261 ```rust 1285 ```rust
1262 u32 1286 bar: u32
1263 ``` 1287 ```
1264 "#]], 1288 "#]],
1265 ); 1289 );
@@ -1277,7 +1301,7 @@ fn foo(bar:u32) { let a = id!(ba$0r); }
1277 *bar* 1301 *bar*
1278 1302
1279 ```rust 1303 ```rust
1280 u32 1304 bar: u32
1281 ``` 1305 ```
1282 "#]], 1306 "#]],
1283 ); 1307 );
@@ -3302,7 +3326,7 @@ fn main() {
3302 *f* 3326 *f*
3303 3327
3304 ```rust 3328 ```rust
3305 &i32 3329 f: &i32
3306 ``` 3330 ```
3307 "#]], 3331 "#]],
3308 ); 3332 );
@@ -3321,7 +3345,7 @@ impl Foo {
3321 *self* 3345 *self*
3322 3346
3323 ```rust 3347 ```rust
3324 &Foo 3348 self: &Foo
3325 ``` 3349 ```
3326 "#]], 3350 "#]],
3327 ); 3351 );
@@ -3341,7 +3365,7 @@ impl Foo {
3341 *self* 3365 *self*
3342 3366
3343 ```rust 3367 ```rust
3344 Arc<Foo> 3368 self: Arc<Foo>
3345 ``` 3369 ```
3346 "#]], 3370 "#]],
3347 ); 3371 );
@@ -3537,7 +3561,7 @@ fn foo() {
3537 ``` 3561 ```
3538 3562
3539 ```rust 3563 ```rust
3540 const FOO: usize = 3 3564 const FOO: usize
3541 ``` 3565 ```
3542 3566
3543 --- 3567 ---
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f83ed65d5..0a493d2f3 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -41,6 +41,7 @@ mod parent_module;
41mod references; 41mod references;
42mod fn_references; 42mod fn_references;
43mod runnables; 43mod runnables;
44mod ssr;
44mod status; 45mod status;
45mod syntax_highlighting; 46mod syntax_highlighting;
46mod syntax_tree; 47mod syntax_tree;
@@ -51,6 +52,7 @@ mod doc_links;
51use std::sync::Arc; 52use std::sync::Arc;
52 53
53use cfg::CfgOptions; 54use cfg::CfgOptions;
55
54use ide_db::base_db::{ 56use ide_db::base_db::{
55 salsa::{self, ParallelDatabase}, 57 salsa::{self, ParallelDatabase},
56 CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath, 58 CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
@@ -85,7 +87,7 @@ pub use crate::{
85pub use hir::{Documentation, Semantics}; 87pub use hir::{Documentation, Semantics};
86pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind}; 88pub use ide_assists::{Assist, AssistConfig, AssistId, AssistKind};
87pub use ide_completion::{ 89pub use ide_completion::{
88 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, 90 CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit,
89 InsertTextFormat, 91 InsertTextFormat,
90}; 92};
91pub use ide_db::{ 93pub use ide_db::{
@@ -502,7 +504,11 @@ impl Analysis {
502 resolve: bool, 504 resolve: bool,
503 frange: FileRange, 505 frange: FileRange,
504 ) -> Cancelable<Vec<Assist>> { 506 ) -> Cancelable<Vec<Assist>> {
505 self.with_db(|db| Assist::get(db, config, resolve, frange)) 507 self.with_db(|db| {
508 let mut acc = Assist::get(db, config, resolve, frange);
509 ssr::add_ssr_assist(db, &mut acc, resolve, frange);
510 acc
511 })
506 } 512 }
507 513
508 /// Computes the set of diagnostics for the given file. 514 /// Computes the set of diagnostics for the given file.
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 05c73de88..1e378279d 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -21,7 +21,7 @@ use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceCh
21 21
22type RenameResult<T> = Result<T, RenameError>; 22type RenameResult<T> = Result<T, RenameError>;
23#[derive(Debug)] 23#[derive(Debug)]
24pub struct RenameError(pub(crate) String); 24pub struct RenameError(String);
25 25
26impl fmt::Display for RenameError { 26impl fmt::Display for RenameError {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -47,16 +47,15 @@ pub(crate) fn prepare_rename(
47 let sema = Semantics::new(db); 47 let sema = Semantics::new(db);
48 let source_file = sema.parse(position.file_id); 48 let source_file = sema.parse(position.file_id);
49 let syntax = source_file.syntax(); 49 let syntax = source_file.syntax();
50 let range = match &sema 50 let name_like = sema
51 .find_node_at_offset_with_descend(&syntax, position.offset) 51 .find_node_at_offset_with_descend(&syntax, position.offset)
52 .ok_or_else(|| format_err!("No references found at position"))? 52 .ok_or_else(|| format_err!("No references found at position"))?;
53 { 53 let node = match &name_like {
54 ast::NameLike::Name(it) => it.syntax(), 54 ast::NameLike::Name(it) => it.syntax(),
55 ast::NameLike::NameRef(it) => it.syntax(), 55 ast::NameLike::NameRef(it) => it.syntax(),
56 ast::NameLike::Lifetime(it) => it.syntax(), 56 ast::NameLike::Lifetime(it) => it.syntax(),
57 } 57 };
58 .text_range(); 58 Ok(RangeInfo::new(sema.original_range(node).range, ()))
59 Ok(RangeInfo::new(range, ()))
60} 59}
61 60
62// Feature: Rename 61// Feature: Rename
@@ -94,6 +93,7 @@ pub(crate) fn rename_with_semantics(
94 } 93 }
95} 94}
96 95
96/// Called by the client when it is about to rename a file.
97pub(crate) fn will_rename_file( 97pub(crate) fn will_rename_file(
98 db: &RootDatabase, 98 db: &RootDatabase,
99 file_id: FileId, 99 file_id: FileId,
@@ -545,6 +545,8 @@ mod tests {
545 545
546 use crate::{fixture, FileId}; 546 use crate::{fixture, FileId};
547 547
548 use super::{RangeInfo, RenameError};
549
548 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 550 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
549 let ra_fixture_after = &trim_indent(ra_fixture_after); 551 let ra_fixture_after = &trim_indent(ra_fixture_after);
550 let (analysis, position) = fixture::position(ra_fixture_before); 552 let (analysis, position) = fixture::position(ra_fixture_before);
@@ -590,6 +592,45 @@ mod tests {
590 expect.assert_debug_eq(&source_change) 592 expect.assert_debug_eq(&source_change)
591 } 593 }
592 594
595 fn check_prepare(ra_fixture: &str, expect: Expect) {
596 let (analysis, position) = fixture::position(ra_fixture);
597 let result = analysis
598 .prepare_rename(position)
599 .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {}", err));
600 match result {
601 Ok(RangeInfo { range, info: () }) => {
602 let source = analysis.file_text(position.file_id).unwrap();
603 expect.assert_eq(&format!("{:?}: {}", range, &source[range]))
604 }
605 Err(RenameError(err)) => expect.assert_eq(&err),
606 };
607 }
608
609 #[test]
610 fn test_prepare_rename_namelikes() {
611 check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]);
612 check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]);
613 check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"23..27: name"#]]);
614 }
615
616 #[test]
617 fn test_prepare_rename_in_macro() {
618 check_prepare(
619 r"macro_rules! foo {
620 ($ident:ident) => {
621 pub struct $ident;
622 }
623}
624foo!(Foo$0);",
625 expect![[r#"83..86: Foo"#]],
626 );
627 }
628
629 #[test]
630 fn test_prepare_rename_keyword() {
631 check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]);
632 }
633
593 #[test] 634 #[test]
594 fn test_rename_to_underscore() { 635 fn test_rename_to_underscore() {
595 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); 636 check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#);
diff --git a/crates/ide/src/ssr.rs b/crates/ide/src/ssr.rs
new file mode 100644
index 000000000..f3638d928
--- /dev/null
+++ b/crates/ide/src/ssr.rs
@@ -0,0 +1,259 @@
1//! This module provides an SSR assist. It is not desirable to include this
2//! assist in ide_assists because that would require the ide_assists crate
3//! depend on the ide_ssr crate.
4
5use ide_assists::{Assist, AssistId, AssistKind, GroupLabel};
6use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase};
7
8pub(crate) fn add_ssr_assist(
9 db: &RootDatabase,
10 base: &mut Vec<Assist>,
11 resolve: bool,
12 frange: FileRange,
13) -> Option<()> {
14 let (match_finder, comment_range) = ide_ssr::ssr_from_comment(db, frange)?;
15
16 let (source_change_for_file, source_change_for_workspace) = if resolve {
17 let edits = match_finder.edits();
18
19 let source_change_for_file = {
20 let text_edit_for_file = edits.get(&frange.file_id).cloned().unwrap_or_default();
21 SourceChange::from_text_edit(frange.file_id, text_edit_for_file)
22 };
23
24 let source_change_for_workspace = SourceChange::from(match_finder.edits());
25
26 (Some(source_change_for_file), Some(source_change_for_workspace))
27 } else {
28 (None, None)
29 };
30
31 let assists = vec![
32 ("Apply SSR in file", source_change_for_file),
33 ("Apply SSR in workspace", source_change_for_workspace),
34 ];
35
36 for (label, source_change) in assists.into_iter() {
37 let assist = Assist {
38 id: AssistId("ssr", AssistKind::RefactorRewrite),
39 label: Label::new(label),
40 group: Some(GroupLabel("Apply SSR".into())),
41 target: comment_range,
42 source_change,
43 };
44
45 base.push(assist);
46 }
47 Some(())
48}
49
50#[cfg(test)]
51mod tests {
52 use std::sync::Arc;
53
54 use expect_test::expect;
55 use ide_assists::Assist;
56 use ide_db::{
57 base_db::{fixture::WithFixture, salsa::Durability, FileRange},
58 symbol_index::SymbolsDatabase,
59 RootDatabase,
60 };
61 use rustc_hash::FxHashSet;
62
63 use super::add_ssr_assist;
64
65 fn get_assists(ra_fixture: &str, resolve: bool) -> Vec<Assist> {
66 let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
67 let mut local_roots = FxHashSet::default();
68 local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
69 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
70
71 let mut assists = vec![];
72
73 add_ssr_assist(
74 &db,
75 &mut assists,
76 resolve,
77 FileRange { file_id, range: range_or_offset.into() },
78 );
79
80 assists
81 }
82
83 #[test]
84 fn not_applicable_comment_not_ssr() {
85 let ra_fixture = r#"
86 //- /lib.rs
87
88 // This is foo $0
89 fn foo() {}
90 "#;
91 let resolve = true;
92
93 let assists = get_assists(ra_fixture, resolve);
94
95 assert_eq!(0, assists.len());
96 }
97
98 #[test]
99 fn resolve_edits_true() {
100 let resolve = true;
101 let assists = get_assists(
102 r#"
103 //- /lib.rs
104 mod bar;
105
106 // 2 ==>> 3$0
107 fn foo() { 2 }
108
109 //- /bar.rs
110 fn bar() { 2 }
111 "#,
112 resolve,
113 );
114
115 assert_eq!(2, assists.len());
116 let mut assists = assists.into_iter();
117
118 let apply_in_file_assist = assists.next().unwrap();
119 expect![[r#"
120 Assist {
121 id: AssistId(
122 "ssr",
123 RefactorRewrite,
124 ),
125 label: "Apply SSR in file",
126 group: Some(
127 GroupLabel(
128 "Apply SSR",
129 ),
130 ),
131 target: 10..21,
132 source_change: Some(
133 SourceChange {
134 source_file_edits: {
135 FileId(
136 0,
137 ): TextEdit {
138 indels: [
139 Indel {
140 insert: "3",
141 delete: 33..34,
142 },
143 ],
144 },
145 },
146 file_system_edits: [],
147 is_snippet: false,
148 },
149 ),
150 }
151 "#]]
152 .assert_debug_eq(&apply_in_file_assist);
153
154 let apply_in_workspace_assist = assists.next().unwrap();
155 expect![[r#"
156 Assist {
157 id: AssistId(
158 "ssr",
159 RefactorRewrite,
160 ),
161 label: "Apply SSR in workspace",
162 group: Some(
163 GroupLabel(
164 "Apply SSR",
165 ),
166 ),
167 target: 10..21,
168 source_change: Some(
169 SourceChange {
170 source_file_edits: {
171 FileId(
172 0,
173 ): TextEdit {
174 indels: [
175 Indel {
176 insert: "3",
177 delete: 33..34,
178 },
179 ],
180 },
181 FileId(
182 1,
183 ): TextEdit {
184 indels: [
185 Indel {
186 insert: "3",
187 delete: 11..12,
188 },
189 ],
190 },
191 },
192 file_system_edits: [],
193 is_snippet: false,
194 },
195 ),
196 }
197 "#]]
198 .assert_debug_eq(&apply_in_workspace_assist);
199 }
200
201 #[test]
202 fn resolve_edits_false() {
203 let resolve = false;
204 let assists = get_assists(
205 r#"
206 //- /lib.rs
207 mod bar;
208
209 // 2 ==>> 3$0
210 fn foo() { 2 }
211
212 //- /bar.rs
213 fn bar() { 2 }
214 "#,
215 resolve,
216 );
217
218 assert_eq!(2, assists.len());
219 let mut assists = assists.into_iter();
220
221 let apply_in_file_assist = assists.next().unwrap();
222 expect![[r#"
223 Assist {
224 id: AssistId(
225 "ssr",
226 RefactorRewrite,
227 ),
228 label: "Apply SSR in file",
229 group: Some(
230 GroupLabel(
231 "Apply SSR",
232 ),
233 ),
234 target: 10..21,
235 source_change: None,
236 }
237 "#]]
238 .assert_debug_eq(&apply_in_file_assist);
239
240 let apply_in_workspace_assist = assists.next().unwrap();
241 expect![[r#"
242 Assist {
243 id: AssistId(
244 "ssr",
245 RefactorRewrite,
246 ),
247 label: "Apply SSR in workspace",
248 group: Some(
249 GroupLabel(
250 "Apply SSR",
251 ),
252 ),
253 target: 10..21,
254 source_change: None,
255 }
256 "#]]
257 .assert_debug_eq(&apply_in_workspace_assist);
258 }
259}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 24fcbb584..b0cfdd8b7 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -330,10 +330,11 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
330 HlTag::Symbol(SymbolKind::Local) 330 HlTag::Symbol(SymbolKind::Local)
331 }; 331 };
332 let mut h = Highlight::new(tag); 332 let mut h = Highlight::new(tag);
333 if local.is_mut(db) || local.ty(db).is_mutable_reference() { 333 let ty = local.ty(db);
334 if local.is_mut(db) || ty.is_mutable_reference() {
334 h |= HlMod::Mutable; 335 h |= HlMod::Mutable;
335 } 336 }
336 if local.ty(db).as_callable(db).is_some() || local.ty(db).impls_fnonce(db) { 337 if ty.as_callable(db).is_some() || ty.impls_fnonce(db) {
337 h |= HlMod::Callable; 338 h |= HlMod::Callable;
338 } 339 }
339 return h; 340 return h;
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index 3bf0099a9..dd9aa27c6 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -21,7 +21,7 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
21profile = { path = "../profile", version = "0.0.0" } 21profile = { path = "../profile", version = "0.0.0" }
22ide_db = { path = "../ide_db", version = "0.0.0" } 22ide_db = { path = "../ide_db", version = "0.0.0" }
23hir = { path = "../hir", version = "0.0.0" } 23hir = { path = "../hir", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" }
25 24
26[dev-dependencies] 25[dev-dependencies]
26test_utils = { path = "../test_utils" }
27expect-test = "1.1" 27expect-test = "1.1"
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs
index 3b6efbab4..ee879c151 100644
--- a/crates/ide_assists/src/handlers/add_turbo_fish.rs
+++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs
@@ -56,13 +56,20 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
56 if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() { 56 if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
57 if let_stmt.colon_token().is_none() { 57 if let_stmt.colon_token().is_none() {
58 let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end(); 58 let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();
59 let semi_pos = let_stmt.syntax().last_token()?.text_range().end();
60
59 acc.add( 61 acc.add(
60 AssistId("add_type_ascription", AssistKind::RefactorRewrite), 62 AssistId("add_type_ascription", AssistKind::RefactorRewrite),
61 "Add `: _` before assignment operator", 63 "Add `: _` before assignment operator",
62 ident.text_range(), 64 ident.text_range(),
63 |builder| match ctx.config.snippet_cap { 65 |builder| {
64 Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"), 66 if let_stmt.semicolon_token().is_none() {
65 None => builder.insert(type_pos, ": _"), 67 builder.insert(semi_pos, ";");
68 }
69 match ctx.config.snippet_cap {
70 Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
71 None => builder.insert(type_pos, ": _"),
72 }
66 }, 73 },
67 )? 74 )?
68 } else { 75 } else {
@@ -265,4 +272,24 @@ fn main() {
265"#, 272"#,
266 ); 273 );
267 } 274 }
275
276 #[test]
277 fn add_type_ascription_append_semicolon() {
278 check_assist_by_label(
279 add_turbo_fish,
280 r#"
281fn make<T>() -> T {}
282fn main() {
283 let x = make$0()
284}
285"#,
286 r#"
287fn make<T>() -> T {}
288fn main() {
289 let x: ${0:_} = make();
290}
291"#,
292 "Add `: _` before assignment operator",
293 );
294 }
268} 295}
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 7caee8df0..7019039b9 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -1,7 +1,7 @@
1use ide_db::helpers::{ 1use ide_db::helpers::{
2 import_assets::{ImportAssets, ImportCandidate}, 2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope}, 3 insert_use::{insert_use, ImportScope},
4 item_name, mod_path_to_ast, 4 mod_path_to_ast,
5}; 5};
6use syntax::{ast, AstNode, SyntaxNode}; 6use syntax::{ast, AstNode, SyntaxNode};
7 7
@@ -90,17 +90,13 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
90 } 90 }
91 91
92 let range = ctx.sema.original_range(&syntax_under_caret).range; 92 let range = ctx.sema.original_range(&syntax_under_caret).range;
93 let group = import_group_message(import_assets.import_candidate()); 93 let group_label = group_label(import_assets.import_candidate());
94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; 94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95 for import in proposed_imports { 95 for import in proposed_imports {
96 let name = match item_name(ctx.db(), import.original_item) {
97 Some(name) => name,
98 None => continue,
99 };
100 acc.add_group( 96 acc.add_group(
101 &group, 97 &group_label,
102 AssistId("auto_import", AssistKind::QuickFix), 98 AssistId("auto_import", AssistKind::QuickFix),
103 format!("Import `{}`", name), 99 format!("Import `{}`", import.import_path),
104 range, 100 range,
105 |builder| { 101 |builder| {
106 let rewriter = 102 let rewriter =
@@ -126,7 +122,7 @@ pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets,
126 } 122 }
127} 123}
128 124
129fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { 125fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
130 let name = match import_candidate { 126 let name = match import_candidate {
131 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), 127 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
132 ImportCandidate::TraitAssocItem(candidate) => { 128 ImportCandidate::TraitAssocItem(candidate) => {
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 272874ae3..30b23da6c 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -3,7 +3,7 @@ use std::iter;
3use hir::AsAssocItem; 3use hir::AsAssocItem;
4use ide_db::helpers::{ 4use ide_db::helpers::{
5 import_assets::{ImportCandidate, LocatedImport}, 5 import_assets::{ImportCandidate, LocatedImport},
6 item_name, mod_path_to_ast, 6 mod_path_to_ast,
7}; 7};
8use ide_db::RootDatabase; 8use ide_db::RootDatabase;
9use syntax::{ 9use syntax::{
@@ -78,7 +78,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
78 acc.add_group( 78 acc.add_group(
79 &group_label, 79 &group_label,
80 AssistId("qualify_path", AssistKind::QuickFix), 80 AssistId("qualify_path", AssistKind::QuickFix),
81 label(ctx.db(), candidate, &import), 81 label(candidate, &import),
82 range, 82 range,
83 |builder| { 83 |builder| {
84 qualify_candidate.qualify( 84 qualify_candidate.qualify(
@@ -199,21 +199,17 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
199 GroupLabel(format!("Qualify {}", name)) 199 GroupLabel(format!("Qualify {}", name))
200} 200}
201 201
202fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { 202fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
203 let display_path = match item_name(db, import.original_item) {
204 Some(display_path) => display_path.to_string(),
205 None => "{unknown}".to_string(),
206 };
207 match candidate { 203 match candidate {
208 ImportCandidate::Path(candidate) => { 204 ImportCandidate::Path(candidate) => {
209 if candidate.qualifier.is_some() { 205 if candidate.qualifier.is_some() {
210 format!("Qualify with `{}`", display_path) 206 format!("Qualify with `{}`", import.import_path)
211 } else { 207 } else {
212 format!("Qualify as `{}`", display_path) 208 format!("Qualify as `{}`", import.import_path)
213 } 209 }
214 } 210 }
215 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", display_path), 211 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", import.import_path),
216 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", display_path), 212 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", import.import_path),
217 } 213 }
218} 214}
219 215
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index 84aa40736..585ecca50 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -22,11 +22,11 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
22base_db = { path = "../base_db", version = "0.0.0" } 22base_db = { path = "../base_db", version = "0.0.0" }
23ide_db = { path = "../ide_db", version = "0.0.0" } 23ide_db = { path = "../ide_db", version = "0.0.0" }
24profile = { path = "../profile", version = "0.0.0" } 24profile = { path = "../profile", version = "0.0.0" }
25test_utils = { path = "../test_utils", version = "0.0.0" }
26 25
27# completions crate should depend only on the top-level `hir` package. if you need 26# completions crate should depend only on the top-level `hir` package. if you need
28# something from some `hir_xxx` subpackage, reexport the API via `hir`. 27# something from some `hir_xxx` subpackage, reexport the API via `hir`.
29hir = { path = "../hir", version = "0.0.0" } 28hir = { path = "../hir", version = "0.0.0" }
30 29
31[dev-dependencies] 30[dev-dependencies]
31test_utils = { path = "../test_utils" }
32expect-test = "1.1" 32expect-test = "1.1"
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index cb05e85fc..e846678b4 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -45,15 +45,15 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
45 CompletionKind::Attribute, 45 CompletionKind::Attribute,
46 ctx.source_range(), 46 ctx.source_range(),
47 attr_completion.label, 47 attr_completion.label,
48 ) 48 );
49 .kind(CompletionItemKind::Attribute); 49 item.kind(CompletionItemKind::Attribute);
50 50
51 if let Some(lookup) = attr_completion.lookup { 51 if let Some(lookup) = attr_completion.lookup {
52 item = item.lookup_by(lookup); 52 item.lookup_by(lookup);
53 } 53 }
54 54
55 if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) { 55 if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) {
56 item = item.insert_snippet(cap, snippet); 56 item.insert_snippet(cap, snippet);
57 } 57 }
58 58
59 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { 59 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
@@ -168,16 +168,20 @@ fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input:
168 ); 168 );
169 let lookup = components.join(", "); 169 let lookup = components.join(", ");
170 let label = components.iter().rev().join(", "); 170 let label = components.iter().rev().join(", ");
171 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label) 171 let mut item =
172 .lookup_by(lookup) 172 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
173 .kind(CompletionItemKind::Attribute) 173 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
174 .add_to(acc) 174 item.add_to(acc);
175 } 175 }
176 176
177 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) { 177 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
178 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), custom_derive_name) 178 let mut item = CompletionItem::new(
179 .kind(CompletionItemKind::Attribute) 179 CompletionKind::Attribute,
180 .add_to(acc) 180 ctx.source_range(),
181 custom_derive_name,
182 );
183 item.kind(CompletionItemKind::Attribute);
184 item.add_to(acc);
181 } 185 }
182 } 186 }
183} 187}
@@ -193,14 +197,13 @@ fn complete_lint(
193 .into_iter() 197 .into_iter()
194 .filter(|completion| !existing_lints.contains(completion.label)) 198 .filter(|completion| !existing_lints.contains(completion.label))
195 { 199 {
196 CompletionItem::new( 200 let mut item = CompletionItem::new(
197 CompletionKind::Attribute, 201 CompletionKind::Attribute,
198 ctx.source_range(), 202 ctx.source_range(),
199 lint_completion.label, 203 lint_completion.label,
200 ) 204 );
201 .kind(CompletionItemKind::Attribute) 205 item.kind(CompletionItemKind::Attribute).detail(lint_completion.description);
202 .detail(lint_completion.description) 206 item.add_to(acc)
203 .add_to(acc)
204 } 207 }
205 } 208 }
206} 209}
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 1bcc8727f..0243dce56 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -54,10 +54,9 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
54 } 54 }
55 55
56 params.into_iter().for_each(|(label, lookup)| { 56 params.into_iter().for_each(|(label, lookup)| {
57 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 57 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label);
58 .kind(CompletionItemKind::Binding) 58 item.kind(CompletionItemKind::Binding).lookup_by(lookup);
59 .lookup_by(lookup) 59 item.add_to(acc)
60 .add_to(acc)
61 }); 60 });
62} 61}
63 62
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 80aa9fb06..b635e0ca3 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -12,21 +12,19 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
12 12
13 if ctx.use_item_syntax.is_some() { 13 if ctx.use_item_syntax.is_some() {
14 if ctx.path_qual.is_none() { 14 if ctx.path_qual.is_none() {
15 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::") 15 let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, "crate::");
16 .kind(CompletionItemKind::Keyword) 16 item.kind(CompletionItemKind::Keyword).insert_text("crate::");
17 .insert_text("crate::") 17 item.add_to(acc);
18 .add_to(acc);
19 } 18 }
20 CompletionItem::new(CompletionKind::Keyword, source_range, "self") 19 let mut item = CompletionItem::new(CompletionKind::Keyword, source_range, "self");
21 .kind(CompletionItemKind::Keyword)