diff options
149 files changed, 4248 insertions, 3578 deletions
diff --git a/Cargo.lock b/Cargo.lock index c392a8907..51a07abe3 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | |||
168 | 168 | ||
169 | [[package]] | 169 | [[package]] |
170 | name = "chalk-derive" | 170 | name = "chalk-derive" |
171 | version = "0.59.0" | 171 | version = "0.60.0" |
172 | source = "registry+https://github.com/rust-lang/crates.io-index" | 172 | source = "registry+https://github.com/rust-lang/crates.io-index" |
173 | checksum = "4b9000fbcb67353dc8973ab9fd136277d321d85b79bd36b8756bb3ae0979a94a" | 173 | checksum = "ab0f74445d4fbeaf0217bc1d23978cc73b95b28e8a738b81894580dd646822d2" |
174 | dependencies = [ | 174 | dependencies = [ |
175 | "proc-macro2", | 175 | "proc-macro2", |
176 | "quote", | 176 | "quote", |
@@ -180,9 +180,9 @@ dependencies = [ | |||
180 | 180 | ||
181 | [[package]] | 181 | [[package]] |
182 | name = "chalk-ir" | 182 | name = "chalk-ir" |
183 | version = "0.59.0" | 183 | version = "0.60.0" |
184 | source = "registry+https://github.com/rust-lang/crates.io-index" | 184 | source = "registry+https://github.com/rust-lang/crates.io-index" |
185 | checksum = "b23528d61b3557c676eccf508fa0771a38453b379f0b780154eaa7f70afe8dfc" | 185 | checksum = "294b1fc6210a5b3bd06c1d01dda48a581e2cafec80b8d659139ce45456644be2" |
186 | dependencies = [ | 186 | dependencies = [ |
187 | "bitflags", | 187 | "bitflags", |
188 | "chalk-derive", | 188 | "chalk-derive", |
@@ -191,9 +191,9 @@ dependencies = [ | |||
191 | 191 | ||
192 | [[package]] | 192 | [[package]] |
193 | name = "chalk-recursive" | 193 | name = "chalk-recursive" |
194 | version = "0.59.0" | 194 | version = "0.60.0" |
195 | source = "registry+https://github.com/rust-lang/crates.io-index" | 195 | source = "registry+https://github.com/rust-lang/crates.io-index" |
196 | checksum = "a8bdd37afc666b771de8b4429fe014363d0e74aae5cc26f320f60a3eab34d744" | 196 | checksum = "1b9386936070be4545bfa22b094b7065af79aa2aeaccc945438f1c5ffe74c30a" |
197 | dependencies = [ | 197 | dependencies = [ |
198 | "chalk-derive", | 198 | "chalk-derive", |
199 | "chalk-ir", | 199 | "chalk-ir", |
@@ -204,9 +204,9 @@ dependencies = [ | |||
204 | 204 | ||
205 | [[package]] | 205 | [[package]] |
206 | name = "chalk-solve" | 206 | name = "chalk-solve" |
207 | version = "0.59.0" | 207 | version = "0.60.0" |
208 | source = "registry+https://github.com/rust-lang/crates.io-index" | 208 | source = "registry+https://github.com/rust-lang/crates.io-index" |
209 | checksum = "4182c42ca319cb71c89898ebc3d2671d1fa7d928123b171b66f1797a2000b9c8" | 209 | checksum = "7c12a1ec7e850b50a049f27ef9cf5df3056bbd1acbb3eeb44d024e501a641f3a" |
210 | dependencies = [ | 210 | dependencies = [ |
211 | "chalk-derive", | 211 | "chalk-derive", |
212 | "chalk-ir", | 212 | "chalk-ir", |
@@ -232,15 +232,6 @@ dependencies = [ | |||
232 | ] | 232 | ] |
233 | 233 | ||
234 | [[package]] | 234 | [[package]] |
235 | name = "cmake" | ||
236 | version = "0.1.45" | ||
237 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
238 | checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" | ||
239 | dependencies = [ | ||
240 | "cc", | ||
241 | ] | ||
242 | |||
243 | [[package]] | ||
244 | name = "countme" | 235 | name = "countme" |
245 | version = "2.0.4" | 236 | version = "2.0.4" |
246 | source = "registry+https://github.com/rust-lang/crates.io-index" | 237 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -252,6 +243,12 @@ dependencies = [ | |||
252 | ] | 243 | ] |
253 | 244 | ||
254 | [[package]] | 245 | [[package]] |
246 | name = "cov-mark" | ||
247 | version = "1.1.0" | ||
248 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
249 | checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3" | ||
250 | |||
251 | [[package]] | ||
255 | name = "crc32fast" | 252 | name = "crc32fast" |
256 | version = "1.2.1" | 253 | version = "1.2.1" |
257 | source = "registry+https://github.com/rust-lang/crates.io-index" | 254 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -501,6 +498,7 @@ dependencies = [ | |||
501 | "anymap", | 498 | "anymap", |
502 | "base_db", | 499 | "base_db", |
503 | "cfg", | 500 | "cfg", |
501 | "cov-mark", | ||
504 | "drop_bomb", | 502 | "drop_bomb", |
505 | "either", | 503 | "either", |
506 | "expect-test", | 504 | "expect-test", |
@@ -547,6 +545,7 @@ dependencies = [ | |||
547 | "chalk-ir", | 545 | "chalk-ir", |
548 | "chalk-recursive", | 546 | "chalk-recursive", |
549 | "chalk-solve", | 547 | "chalk-solve", |
548 | "cov-mark", | ||
550 | "ena", | 549 | "ena", |
551 | "expect-test", | 550 | "expect-test", |
552 | "hir_def", | 551 | "hir_def", |
@@ -581,6 +580,7 @@ name = "ide" | |||
581 | version = "0.0.0" | 580 | version = "0.0.0" |
582 | dependencies = [ | 581 | dependencies = [ |
583 | "cfg", | 582 | "cfg", |
583 | "cov-mark", | ||
584 | "either", | 584 | "either", |
585 | "expect-test", | 585 | "expect-test", |
586 | "hir", | 586 | "hir", |
@@ -607,6 +607,7 @@ dependencies = [ | |||
607 | name = "ide_assists" | 607 | name = "ide_assists" |
608 | version = "0.0.0" | 608 | version = "0.0.0" |
609 | dependencies = [ | 609 | dependencies = [ |
610 | "cov-mark", | ||
610 | "either", | 611 | "either", |
611 | "expect-test", | 612 | "expect-test", |
612 | "hir", | 613 | "hir", |
@@ -625,6 +626,7 @@ name = "ide_completion" | |||
625 | version = "0.0.0" | 626 | version = "0.0.0" |
626 | dependencies = [ | 627 | dependencies = [ |
627 | "base_db", | 628 | "base_db", |
629 | "cov-mark", | ||
628 | "either", | 630 | "either", |
629 | "expect-test", | 631 | "expect-test", |
630 | "hir", | 632 | "hir", |
@@ -644,6 +646,7 @@ name = "ide_db" | |||
644 | version = "0.0.0" | 646 | version = "0.0.0" |
645 | dependencies = [ | 647 | dependencies = [ |
646 | "base_db", | 648 | "base_db", |
649 | "cov-mark", | ||
647 | "either", | 650 | "either", |
648 | "expect-test", | 651 | "expect-test", |
649 | "fst", | 652 | "fst", |
@@ -664,6 +667,7 @@ dependencies = [ | |||
664 | name = "ide_ssr" | 667 | name = "ide_ssr" |
665 | version = "0.0.0" | 668 | version = "0.0.0" |
666 | dependencies = [ | 669 | dependencies = [ |
670 | "cov-mark", | ||
667 | "expect-test", | 671 | "expect-test", |
668 | "hir", | 672 | "hir", |
669 | "ide_db", | 673 | "ide_db", |
@@ -687,9 +691,9 @@ dependencies = [ | |||
687 | 691 | ||
688 | [[package]] | 692 | [[package]] |
689 | name = "indexmap" | 693 | name = "indexmap" |
690 | version = "1.6.1" | 694 | version = "1.6.2" |
691 | source = "registry+https://github.com/rust-lang/crates.io-index" | 695 | source = "registry+https://github.com/rust-lang/crates.io-index" |
692 | checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" | 696 | checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" |
693 | dependencies = [ | 697 | dependencies = [ |
694 | "autocfg", | 698 | "autocfg", |
695 | "hashbrown", | 699 | "hashbrown", |
@@ -805,11 +809,11 @@ dependencies = [ | |||
805 | 809 | ||
806 | [[package]] | 810 | [[package]] |
807 | name = "libmimalloc-sys" | 811 | name = "libmimalloc-sys" |
808 | version = "0.1.20" | 812 | version = "0.1.21" |
809 | source = "registry+https://github.com/rust-lang/crates.io-index" | 813 | source = "registry+https://github.com/rust-lang/crates.io-index" |
810 | checksum = "e58f42b6424a0ed536678c65fd97cd64b4344bcf86251e284f7c0ce9eee40e64" | 814 | checksum = "2396cf99d2f58611cd69f0efeee4af3d2e2c7b61bed433515029163aa567e65c" |
811 | dependencies = [ | 815 | dependencies = [ |
812 | "cmake", | 816 | "cc", |
813 | ] | 817 | ] |
814 | 818 | ||
815 | [[package]] | 819 | [[package]] |
@@ -874,6 +878,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" | |||
874 | name = "mbe" | 878 | name = "mbe" |
875 | version = "0.0.0" | 879 | version = "0.0.0" |
876 | dependencies = [ | 880 | dependencies = [ |
881 | "cov-mark", | ||
877 | "log", | 882 | "log", |
878 | "parser", | 883 | "parser", |
879 | "profile", | 884 | "profile", |
@@ -911,9 +916,9 @@ dependencies = [ | |||
911 | 916 | ||
912 | [[package]] | 917 | [[package]] |
913 | name = "mimalloc" | 918 | name = "mimalloc" |
914 | version = "0.1.24" | 919 | version = "0.1.25" |
915 | source = "registry+https://github.com/rust-lang/crates.io-index" | 920 | source = "registry+https://github.com/rust-lang/crates.io-index" |
916 | checksum = "757efec188b3d2088949d912e01ea2fe87164ed6376b6c5d7dd4f3ce1668a93d" | 921 | checksum = "1e7c6b11afd1e5e689ac96b6d18b1fc763398fe3d7eed99e8773426bc2033dfb" |
917 | dependencies = [ | 922 | dependencies = [ |
918 | "libmimalloc-sys", | 923 | "libmimalloc-sys", |
919 | ] | 924 | ] |
@@ -1466,18 +1471,18 @@ dependencies = [ | |||
1466 | 1471 | ||
1467 | [[package]] | 1472 | [[package]] |
1468 | name = "serde" | 1473 | name = "serde" |
1469 | version = "1.0.123" | 1474 | version = "1.0.124" |
1470 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1475 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1471 | checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" | 1476 | checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" |
1472 | dependencies = [ | 1477 | dependencies = [ |
1473 | "serde_derive", | 1478 | "serde_derive", |
1474 | ] | 1479 | ] |
1475 | 1480 | ||
1476 | [[package]] | 1481 | [[package]] |
1477 | name = "serde_derive" | 1482 | name = "serde_derive" |
1478 | version = "1.0.123" | 1483 | version = "1.0.124" |
1479 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1484 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1480 | checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" | 1485 | checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" |
1481 | dependencies = [ | 1486 | dependencies = [ |
1482 | "proc-macro2", | 1487 | "proc-macro2", |
1483 | "quote", | 1488 | "quote", |
@@ -1561,9 +1566,9 @@ dependencies = [ | |||
1561 | 1566 | ||
1562 | [[package]] | 1567 | [[package]] |
1563 | name = "syn" | 1568 | name = "syn" |
1564 | version = "1.0.61" | 1569 | version = "1.0.62" |
1565 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1570 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1566 | checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" | 1571 | checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" |
1567 | dependencies = [ | 1572 | dependencies = [ |
1568 | "proc-macro2", | 1573 | "proc-macro2", |
1569 | "quote", | 1574 | "quote", |
@@ -1587,6 +1592,7 @@ name = "syntax" | |||
1587 | version = "0.0.0" | 1592 | version = "0.0.0" |
1588 | dependencies = [ | 1593 | dependencies = [ |
1589 | "arrayvec", | 1594 | "arrayvec", |
1595 | "cov-mark", | ||
1590 | "expect-test", | 1596 | "expect-test", |
1591 | "indexmap", | 1597 | "indexmap", |
1592 | "itertools", | 1598 | "itertools", |
@@ -1621,7 +1627,6 @@ dependencies = [ | |||
1621 | "dissimilar", | 1627 | "dissimilar", |
1622 | "profile", | 1628 | "profile", |
1623 | "rustc-hash", | 1629 | "rustc-hash", |
1624 | "serde_json", | ||
1625 | "stdx", | 1630 | "stdx", |
1626 | "text-size", | 1631 | "text-size", |
1627 | ] | 1632 | ] |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs deleted file mode 100644 index 9ee4b3059..000000000 --- a/crates/hir/src/code_model.rs +++ /dev/null | |||
@@ -1,2095 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | use std::{iter, sync::Arc}; | ||
3 | |||
4 | use arrayvec::ArrayVec; | ||
5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | ||
6 | use either::Either; | ||
7 | use hir_def::{ | ||
8 | adt::{ReprKind, StructKind, VariantData}, | ||
9 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | ||
10 | import_map, | ||
11 | item_tree::ItemTreeNode, | ||
12 | lang_item::LangItemTarget, | ||
13 | path::ModPath, | ||
14 | per_ns::PerNs, | ||
15 | resolver::{HasResolver, Resolver}, | ||
16 | src::HasSource as _, | ||
17 | type_ref::TypeRef, | ||
18 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | ||
19 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | ||
20 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | ||
21 | TypeParamId, UnionId, | ||
22 | }; | ||
23 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; | ||
24 | use hir_expand::{ | ||
25 | diagnostics::DiagnosticSink, | ||
26 | name::{name, AsName}, | ||
27 | MacroDefId, MacroDefKind, | ||
28 | }; | ||
29 | use hir_ty::{ | ||
30 | autoderef, | ||
31 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, | ||
32 | method_resolution, | ||
33 | traits::{FnTrait, Solution, SolutionVariables}, | ||
34 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | ||
35 | InEnvironment, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, | ||
36 | TraitEnvironment, Ty, TyDefId, TyVariableKind, | ||
37 | }; | ||
38 | use rustc_hash::FxHashSet; | ||
39 | use stdx::{format_to, impl_from}; | ||
40 | use syntax::{ | ||
41 | ast::{self, AttrsOwner, NameOwner}, | ||
42 | AstNode, SmolStr, | ||
43 | }; | ||
44 | use tt::{Ident, Leaf, Literal, TokenTree}; | ||
45 | |||
46 | use crate::{ | ||
47 | db::{DefDatabase, HirDatabase}, | ||
48 | has_source::HasSource, | ||
49 | HirDisplay, InFile, Name, | ||
50 | }; | ||
51 | |||
52 | /// hir::Crate describes a single crate. It's the main interface with which | ||
53 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | ||
54 | /// root module. | ||
55 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
56 | pub struct Crate { | ||
57 | pub(crate) id: CrateId, | ||
58 | } | ||
59 | |||
60 | #[derive(Debug)] | ||
61 | pub struct CrateDependency { | ||
62 | pub krate: Crate, | ||
63 | pub name: Name, | ||
64 | } | ||
65 | |||
66 | impl Crate { | ||
67 | pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> { | ||
68 | db.crate_graph()[self.id] | ||
69 | .dependencies | ||
70 | .iter() | ||
71 | .map(|dep| { | ||
72 | let krate = Crate { id: dep.crate_id }; | ||
73 | let name = dep.as_name(); | ||
74 | CrateDependency { krate, name } | ||
75 | }) | ||
76 | .collect() | ||
77 | } | ||
78 | |||
79 | // FIXME: add `transitive_reverse_dependencies`. | ||
80 | pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> { | ||
81 | let crate_graph = db.crate_graph(); | ||
82 | crate_graph | ||
83 | .iter() | ||
84 | .filter(|&krate| { | ||
85 | crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id) | ||
86 | }) | ||
87 | .map(|id| Crate { id }) | ||
88 | .collect() | ||
89 | } | ||
90 | |||
91 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { | ||
92 | let def_map = db.crate_def_map(self.id); | ||
93 | Module { id: def_map.module_id(def_map.root()) } | ||
94 | } | ||
95 | |||
96 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { | ||
97 | db.crate_graph()[self.id].root_file_id | ||
98 | } | ||
99 | |||
100 | pub fn edition(self, db: &dyn HirDatabase) -> Edition { | ||
101 | db.crate_graph()[self.id].edition | ||
102 | } | ||
103 | |||
104 | pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> { | ||
105 | db.crate_graph()[self.id].display_name.clone() | ||
106 | } | ||
107 | |||
108 | pub fn query_external_importables( | ||
109 | self, | ||
110 | db: &dyn DefDatabase, | ||
111 | query: import_map::Query, | ||
112 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
113 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | ||
114 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
115 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
116 | }) | ||
117 | } | ||
118 | |||
119 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | ||
120 | db.crate_graph().iter().map(|id| Crate { id }).collect() | ||
121 | } | ||
122 | |||
123 | /// Try to get the root URL of the documentation of a crate. | ||
124 | pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { | ||
125 | // Look for #![doc(html_root_url = "...")] | ||
126 | let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into())); | ||
127 | let doc_attr_q = attrs.by_key("doc"); | ||
128 | |||
129 | if !doc_attr_q.exists() { | ||
130 | return None; | ||
131 | } | ||
132 | |||
133 | let doc_url = doc_attr_q.tt_values().map(|tt| { | ||
134 | let name = tt.token_trees.iter() | ||
135 | .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) | ||
136 | .skip(2) | ||
137 | .next(); | ||
138 | |||
139 | match name { | ||
140 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | ||
141 | _ => None | ||
142 | } | ||
143 | }).flat_map(|t| t).next(); | ||
144 | |||
145 | doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") | ||
146 | } | ||
147 | } | ||
148 | |||
149 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
150 | pub struct Module { | ||
151 | pub(crate) id: ModuleId, | ||
152 | } | ||
153 | |||
154 | /// The defs which can be visible in the module. | ||
155 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
156 | pub enum ModuleDef { | ||
157 | Module(Module), | ||
158 | Function(Function), | ||
159 | Adt(Adt), | ||
160 | // Can't be directly declared, but can be imported. | ||
161 | Variant(Variant), | ||
162 | Const(Const), | ||
163 | Static(Static), | ||
164 | Trait(Trait), | ||
165 | TypeAlias(TypeAlias), | ||
166 | BuiltinType(BuiltinType), | ||
167 | } | ||
168 | impl_from!( | ||
169 | Module, | ||
170 | Function, | ||
171 | Adt(Struct, Enum, Union), | ||
172 | Variant, | ||
173 | Const, | ||
174 | Static, | ||
175 | Trait, | ||
176 | TypeAlias, | ||
177 | BuiltinType | ||
178 | for ModuleDef | ||
179 | ); | ||
180 | |||
181 | impl From<VariantDef> for ModuleDef { | ||
182 | fn from(var: VariantDef) -> Self { | ||
183 | match var { | ||
184 | VariantDef::Struct(t) => Adt::from(t).into(), | ||
185 | VariantDef::Union(t) => Adt::from(t).into(), | ||
186 | VariantDef::Variant(t) => t.into(), | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | impl ModuleDef { | ||
192 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
193 | match self { | ||
194 | ModuleDef::Module(it) => it.parent(db), | ||
195 | ModuleDef::Function(it) => Some(it.module(db)), | ||
196 | ModuleDef::Adt(it) => Some(it.module(db)), | ||
197 | ModuleDef::Variant(it) => Some(it.module(db)), | ||
198 | ModuleDef::Const(it) => Some(it.module(db)), | ||
199 | ModuleDef::Static(it) => Some(it.module(db)), | ||
200 | ModuleDef::Trait(it) => Some(it.module(db)), | ||
201 | ModuleDef::TypeAlias(it) => Some(it.module(db)), | ||
202 | ModuleDef::BuiltinType(_) => None, | ||
203 | } | ||
204 | } | ||
205 | |||
206 | pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> { | ||
207 | let mut segments = Vec::new(); | ||
208 | segments.push(self.name(db)?.to_string()); | ||
209 | for m in self.module(db)?.path_to_root(db) { | ||
210 | segments.extend(m.name(db).map(|it| it.to_string())) | ||
211 | } | ||
212 | segments.reverse(); | ||
213 | Some(segments.join("::")) | ||
214 | } | ||
215 | |||
216 | pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> { | ||
217 | let module = match self { | ||
218 | ModuleDef::Module(it) => it.parent(db)?, | ||
219 | ModuleDef::Function(it) => return Some(it.visibility(db)), | ||
220 | ModuleDef::Adt(it) => it.module(db), | ||
221 | ModuleDef::Variant(it) => { | ||
222 | let parent = it.parent_enum(db); | ||
223 | let module = it.module(db); | ||
224 | return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent))); | ||
225 | } | ||
226 | ModuleDef::Const(it) => return Some(it.visibility(db)), | ||
227 | ModuleDef::Static(it) => it.module(db), | ||
228 | ModuleDef::Trait(it) => it.module(db), | ||
229 | ModuleDef::TypeAlias(it) => return Some(it.visibility(db)), | ||
230 | ModuleDef::BuiltinType(_) => return None, | ||
231 | }; | ||
232 | |||
233 | module.visibility_of(db, self) | ||
234 | } | ||
235 | |||
236 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
237 | match self { | ||
238 | ModuleDef::Adt(it) => Some(it.name(db)), | ||
239 | ModuleDef::Trait(it) => Some(it.name(db)), | ||
240 | ModuleDef::Function(it) => Some(it.name(db)), | ||
241 | ModuleDef::Variant(it) => Some(it.name(db)), | ||
242 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | ||
243 | ModuleDef::Module(it) => it.name(db), | ||
244 | ModuleDef::Const(it) => it.name(db), | ||
245 | ModuleDef::Static(it) => it.name(db), | ||
246 | |||
247 | ModuleDef::BuiltinType(it) => Some(it.name()), | ||
248 | } | ||
249 | } | ||
250 | |||
251 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
252 | let id = match self { | ||
253 | ModuleDef::Adt(it) => match it { | ||
254 | Adt::Struct(it) => it.id.into(), | ||
255 | Adt::Enum(it) => it.id.into(), | ||
256 | Adt::Union(it) => it.id.into(), | ||
257 | }, | ||
258 | ModuleDef::Trait(it) => it.id.into(), | ||
259 | ModuleDef::Function(it) => it.id.into(), | ||
260 | ModuleDef::TypeAlias(it) => it.id.into(), | ||
261 | ModuleDef::Module(it) => it.id.into(), | ||
262 | ModuleDef::Const(it) => it.id.into(), | ||
263 | ModuleDef::Static(it) => it.id.into(), | ||
264 | _ => return, | ||
265 | }; | ||
266 | |||
267 | let module = match self.module(db) { | ||
268 | Some(it) => it, | ||
269 | None => return, | ||
270 | }; | ||
271 | |||
272 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | ||
273 | } | ||
274 | } | ||
275 | |||
276 | impl Module { | ||
277 | /// Name of this module. | ||
278 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
279 | let def_map = self.id.def_map(db.upcast()); | ||
280 | let parent = def_map[self.id.local_id].parent?; | ||
281 | def_map[parent].children.iter().find_map(|(name, module_id)| { | ||
282 | if *module_id == self.id.local_id { | ||
283 | Some(name.clone()) | ||
284 | } else { | ||
285 | None | ||
286 | } | ||
287 | }) | ||
288 | } | ||
289 | |||
290 | /// Returns the crate this module is part of. | ||
291 | pub fn krate(self) -> Crate { | ||
292 | Crate { id: self.id.krate() } | ||
293 | } | ||
294 | |||
295 | /// Topmost parent of this module. Every module has a `crate_root`, but some | ||
296 | /// might be missing `krate`. This can happen if a module's file is not included | ||
297 | /// in the module tree of any target in `Cargo.toml`. | ||
298 | pub fn crate_root(self, db: &dyn HirDatabase) -> Module { | ||
299 | let def_map = db.crate_def_map(self.id.krate()); | ||
300 | Module { id: def_map.module_id(def_map.root()) } | ||
301 | } | ||
302 | |||
303 | /// Iterates over all child modules. | ||
304 | pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { | ||
305 | let def_map = self.id.def_map(db.upcast()); | ||
306 | let children = def_map[self.id.local_id] | ||
307 | .children | ||
308 | .iter() | ||
309 | .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) }) | ||
310 | .collect::<Vec<_>>(); | ||
311 | children.into_iter() | ||
312 | } | ||
313 | |||
314 | /// Finds a parent module. | ||
315 | pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { | ||
316 | // FIXME: handle block expressions as modules (their parent is in a different DefMap) | ||
317 | let def_map = self.id.def_map(db.upcast()); | ||
318 | let parent_id = def_map[self.id.local_id].parent?; | ||
319 | Some(Module { id: def_map.module_id(parent_id) }) | ||
320 | } | ||
321 | |||
322 | pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> { | ||
323 | let mut res = vec![self]; | ||
324 | let mut curr = self; | ||
325 | while let Some(next) = curr.parent(db) { | ||
326 | res.push(next); | ||
327 | curr = next | ||
328 | } | ||
329 | res | ||
330 | } | ||
331 | |||
332 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
333 | pub fn scope( | ||
334 | self, | ||
335 | db: &dyn HirDatabase, | ||
336 | visible_from: Option<Module>, | ||
337 | ) -> Vec<(Name, ScopeDef)> { | ||
338 | self.id.def_map(db.upcast())[self.id.local_id] | ||
339 | .scope | ||
340 | .entries() | ||
341 | .filter_map(|(name, def)| { | ||
342 | if let Some(m) = visible_from { | ||
343 | let filtered = | ||
344 | def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id)); | ||
345 | if filtered.is_none() && !def.is_none() { | ||
346 | None | ||
347 | } else { | ||
348 | Some((name, filtered)) | ||
349 | } | ||
350 | } else { | ||
351 | Some((name, def)) | ||
352 | } | ||
353 | }) | ||
354 | .flat_map(|(name, def)| { | ||
355 | ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) | ||
356 | }) | ||
357 | .collect() | ||
358 | } | ||
359 | |||
360 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | ||
361 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | ||
362 | } | ||
363 | |||
364 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
365 | let _p = profile::span("Module::diagnostics").detail(|| { | ||
366 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | ||
367 | }); | ||
368 | let def_map = self.id.def_map(db.upcast()); | ||
369 | def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); | ||
370 | for decl in self.declarations(db) { | ||
371 | match decl { | ||
372 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | ||
373 | crate::ModuleDef::Module(m) => { | ||
374 | // Only add diagnostics from inline modules | ||
375 | if def_map[m.id.local_id].origin.is_inline() { | ||
376 | m.diagnostics(db, sink) | ||
377 | } | ||
378 | } | ||
379 | _ => { | ||
380 | decl.diagnostics(db, sink); | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | for impl_def in self.impl_defs(db) { | ||
386 | for item in impl_def.items(db) { | ||
387 | if let AssocItem::Function(f) = item { | ||
388 | f.diagnostics(db, sink); | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | |||
394 | pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { | ||
395 | let def_map = self.id.def_map(db.upcast()); | ||
396 | def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() | ||
397 | } | ||
398 | |||
399 | pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { | ||
400 | let def_map = self.id.def_map(db.upcast()); | ||
401 | def_map[self.id.local_id].scope.impls().map(Impl::from).collect() | ||
402 | } | ||
403 | |||
404 | /// Finds a path that can be used to refer to the given item from within | ||
405 | /// this module, if possible. | ||
406 | pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> { | ||
407 | hir_def::find_path::find_path(db, item.into(), self.into()) | ||
408 | } | ||
409 | |||
410 | /// Finds a path that can be used to refer to the given item from within | ||
411 | /// this module, if possible. This is used for returning import paths for use-statements. | ||
412 | pub fn find_use_path_prefixed( | ||
413 | self, | ||
414 | db: &dyn DefDatabase, | ||
415 | item: impl Into<ItemInNs>, | ||
416 | prefix_kind: PrefixKind, | ||
417 | ) -> Option<ModPath> { | ||
418 | hir_def::find_path::find_path_prefixed(db, item.into(), self.into(), prefix_kind) | ||
419 | } | ||
420 | } | ||
421 | |||
422 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
423 | pub struct Field { | ||
424 | pub(crate) parent: VariantDef, | ||
425 | pub(crate) id: LocalFieldId, | ||
426 | } | ||
427 | |||
428 | #[derive(Debug, PartialEq, Eq)] | ||
429 | pub enum FieldSource { | ||
430 | Named(ast::RecordField), | ||
431 | Pos(ast::TupleField), | ||
432 | } | ||
433 | |||
434 | impl Field { | ||
435 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
436 | self.parent.variant_data(db).fields()[self.id].name.clone() | ||
437 | } | ||
438 | |||
439 | /// Returns the type as in the signature of the struct (i.e., with | ||
440 | /// placeholder types for type parameters). This is good for showing | ||
441 | /// signature help, but not so good to actually get the type of the field | ||
442 | /// when you actually have a variable of the struct. | ||
443 | pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type { | ||
444 | let var_id = self.parent.into(); | ||
445 | let generic_def_id: GenericDefId = match self.parent { | ||
446 | VariantDef::Struct(it) => it.id.into(), | ||
447 | VariantDef::Union(it) => it.id.into(), | ||
448 | VariantDef::Variant(it) => it.parent.id.into(), | ||
449 | }; | ||
450 | let substs = Substs::type_params(db, generic_def_id); | ||
451 | let ty = db.field_types(var_id)[self.id].clone().subst(&substs); | ||
452 | Type::new(db, self.parent.module(db).id.krate(), var_id, ty) | ||
453 | } | ||
454 | |||
455 | pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { | ||
456 | self.parent | ||
457 | } | ||
458 | } | ||
459 | |||
460 | impl HasVisibility for Field { | ||
461 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
462 | let variant_data = self.parent.variant_data(db); | ||
463 | let visibility = &variant_data.fields()[self.id].visibility; | ||
464 | let parent_id: hir_def::VariantId = self.parent.into(); | ||
465 | visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast())) | ||
466 | } | ||
467 | } | ||
468 | |||
469 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
470 | pub struct Struct { | ||
471 | pub(crate) id: StructId, | ||
472 | } | ||
473 | |||
474 | impl Struct { | ||
475 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
476 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
477 | } | ||
478 | |||
479 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
480 | Some(self.module(db).krate()) | ||
481 | } | ||
482 | |||
483 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
484 | db.struct_data(self.id).name.clone() | ||
485 | } | ||
486 | |||
487 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
488 | db.struct_data(self.id) | ||
489 | .variant_data | ||
490 | .fields() | ||
491 | .iter() | ||
492 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
493 | .collect() | ||
494 | } | ||
495 | |||
496 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
497 | Type::from_def( | ||
498 | db, | ||
499 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
500 | self.id, | ||
501 | ) | ||
502 | } | ||
503 | |||
504 | pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { | ||
505 | db.struct_data(self.id).repr.clone() | ||
506 | } | ||
507 | |||
508 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
509 | self.variant_data(db).kind() | ||
510 | } | ||
511 | |||
512 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
513 | db.struct_data(self.id).variant_data.clone() | ||
514 | } | ||
515 | } | ||
516 | |||
517 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
518 | pub struct Union { | ||
519 | pub(crate) id: UnionId, | ||
520 | } | ||
521 | |||
522 | impl Union { | ||
523 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
524 | db.union_data(self.id).name.clone() | ||
525 | } | ||
526 | |||
527 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
528 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
529 | } | ||
530 | |||
531 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
532 | Type::from_def( | ||
533 | db, | ||
534 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
535 | self.id, | ||
536 | ) | ||
537 | } | ||
538 | |||
539 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
540 | db.union_data(self.id) | ||
541 | .variant_data | ||
542 | .fields() | ||
543 | .iter() | ||
544 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
545 | .collect() | ||
546 | } | ||
547 | |||
548 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
549 | db.union_data(self.id).variant_data.clone() | ||
550 | } | ||
551 | } | ||
552 | |||
553 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
554 | pub struct Enum { | ||
555 | pub(crate) id: EnumId, | ||
556 | } | ||
557 | |||
558 | impl Enum { | ||
559 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
560 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
561 | } | ||
562 | |||
563 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
564 | Some(self.module(db).krate()) | ||
565 | } | ||
566 | |||
567 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
568 | db.enum_data(self.id).name.clone() | ||
569 | } | ||
570 | |||
571 | pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> { | ||
572 | db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() | ||
573 | } | ||
574 | |||
575 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
576 | Type::from_def( | ||
577 | db, | ||
578 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
579 | self.id, | ||
580 | ) | ||
581 | } | ||
582 | } | ||
583 | |||
584 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
585 | pub struct Variant { | ||
586 | pub(crate) parent: Enum, | ||
587 | pub(crate) id: LocalEnumVariantId, | ||
588 | } | ||
589 | |||
590 | impl Variant { | ||
591 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
592 | self.parent.module(db) | ||
593 | } | ||
594 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { | ||
595 | self.parent | ||
596 | } | ||
597 | |||
598 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
599 | db.enum_data(self.parent.id).variants[self.id].name.clone() | ||
600 | } | ||
601 | |||
602 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
603 | self.variant_data(db) | ||
604 | .fields() | ||
605 | .iter() | ||
606 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
607 | .collect() | ||
608 | } | ||
609 | |||
610 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
611 | self.variant_data(db).kind() | ||
612 | } | ||
613 | |||
614 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
615 | db.enum_data(self.parent.id).variants[self.id].variant_data.clone() | ||
616 | } | ||
617 | } | ||
618 | |||
619 | /// A Data Type | ||
620 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
621 | pub enum Adt { | ||
622 | Struct(Struct), | ||
623 | Union(Union), | ||
624 | Enum(Enum), | ||
625 | } | ||
626 | impl_from!(Struct, Union, Enum for Adt); | ||
627 | |||
628 | impl Adt { | ||
629 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
630 | let subst = db.generic_defaults(self.into()); | ||
631 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
632 | } | ||
633 | |||
634 | /// Turns this ADT into a type. Any type parameters of the ADT will be | ||
635 | /// turned into unknown types, which is good for e.g. finding the most | ||
636 | /// general set of completions, but will not look very nice when printed. | ||
637 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
638 | let id = AdtId::from(self); | ||
639 | Type::from_def(db, id.module(db.upcast()).krate(), id) | ||
640 | } | ||
641 | |||
642 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
643 | match self { | ||
644 | Adt::Struct(s) => s.module(db), | ||
645 | Adt::Union(s) => s.module(db), | ||
646 | Adt::Enum(e) => e.module(db), | ||
647 | } | ||
648 | } | ||
649 | |||
650 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
651 | Some(self.module(db).krate()) | ||
652 | } | ||
653 | |||
654 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
655 | match self { | ||
656 | Adt::Struct(s) => s.name(db), | ||
657 | Adt::Union(u) => u.name(db), | ||
658 | Adt::Enum(e) => e.name(db), | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | |||
663 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
664 | pub enum VariantDef { | ||
665 | Struct(Struct), | ||
666 | Union(Union), | ||
667 | Variant(Variant), | ||
668 | } | ||
669 | impl_from!(Struct, Union, Variant for VariantDef); | ||
670 | |||
671 | impl VariantDef { | ||
672 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
673 | match self { | ||
674 | VariantDef::Struct(it) => it.fields(db), | ||
675 | VariantDef::Union(it) => it.fields(db), | ||
676 | VariantDef::Variant(it) => it.fields(db), | ||
677 | } | ||
678 | } | ||
679 | |||
680 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
681 | match self { | ||
682 | VariantDef::Struct(it) => it.module(db), | ||
683 | VariantDef::Union(it) => it.module(db), | ||
684 | VariantDef::Variant(it) => it.module(db), | ||
685 | } | ||
686 | } | ||
687 | |||
688 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
689 | match self { | ||
690 | VariantDef::Struct(s) => s.name(db), | ||
691 | VariantDef::Union(u) => u.name(db), | ||
692 | VariantDef::Variant(e) => e.name(db), | ||
693 | } | ||
694 | } | ||
695 | |||
696 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
697 | match self { | ||
698 | VariantDef::Struct(it) => it.variant_data(db), | ||
699 | VariantDef::Union(it) => it.variant_data(db), | ||
700 | VariantDef::Variant(it) => it.variant_data(db), | ||
701 | } | ||
702 | } | ||
703 | } | ||
704 | |||
705 | /// The defs which have a body. | ||
706 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
707 | pub enum DefWithBody { | ||
708 | Function(Function), | ||
709 | Static(Static), | ||
710 | Const(Const), | ||
711 | } | ||
712 | impl_from!(Function, Const, Static for DefWithBody); | ||
713 | |||
714 | impl DefWithBody { | ||
715 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
716 | match self { | ||
717 | DefWithBody::Const(c) => c.module(db), | ||
718 | DefWithBody::Function(f) => f.module(db), | ||
719 | DefWithBody::Static(s) => s.module(db), | ||
720 | } | ||
721 | } | ||
722 | |||
723 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
724 | match self { | ||
725 | DefWithBody::Function(f) => Some(f.name(db)), | ||
726 | DefWithBody::Static(s) => s.name(db), | ||
727 | DefWithBody::Const(c) => c.name(db), | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | |||
732 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
733 | pub struct Function { | ||
734 | pub(crate) id: FunctionId, | ||
735 | } | ||
736 | |||
737 | impl Function { | ||
738 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
739 | self.id.lookup(db.upcast()).module(db.upcast()).into() | ||
740 | } | ||
741 | |||
742 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
743 | Some(self.module(db).krate()) | ||
744 | } | ||
745 | |||
746 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
747 | db.function_data(self.id).name.clone() | ||
748 | } | ||
749 | |||
750 | /// Get this function's return type | ||
751 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
752 | let resolver = self.id.resolver(db.upcast()); | ||
753 | let ret_type = &db.function_data(self.id).ret_type; | ||
754 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
755 | let environment = TraitEnvironment::lower(db, &resolver); | ||
756 | Type { | ||
757 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
758 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
759 | } | ||
760 | } | ||
761 | |||
762 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | ||
763 | if !db.function_data(self.id).has_self_param { | ||
764 | return None; | ||
765 | } | ||
766 | Some(SelfParam { func: self.id }) | ||
767 | } | ||
768 | |||
769 | pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { | ||
770 | let resolver = self.id.resolver(db.upcast()); | ||
771 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
772 | let environment = TraitEnvironment::lower(db, &resolver); | ||
773 | db.function_data(self.id) | ||
774 | .params | ||
775 | .iter() | ||
776 | .map(|type_ref| { | ||
777 | let ty = Type { | ||
778 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
779 | ty: InEnvironment { | ||
780 | value: Ty::from_hir_ext(&ctx, type_ref).0, | ||
781 | environment: environment.clone(), | ||
782 | }, | ||
783 | }; | ||
784 | Param { ty } | ||
785 | }) | ||
786 | .collect() | ||
787 | } | ||
788 | pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> { | ||
789 | if self.self_param(db).is_none() { | ||
790 | return None; | ||
791 | } | ||
792 | let mut res = self.assoc_fn_params(db); | ||
793 | res.remove(0); | ||
794 | Some(res) | ||
795 | } | ||
796 | |||
797 | pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { | ||
798 | db.function_data(self.id).is_unsafe | ||
799 | } | ||
800 | |||
801 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
802 | let krate = self.module(db).id.krate(); | ||
803 | hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); | ||
804 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | ||
805 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | ||
806 | } | ||
807 | |||
808 | /// Whether this function declaration has a definition. | ||
809 | /// | ||
810 | /// This is false in the case of required (not provided) trait methods. | ||
811 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | ||
812 | db.function_data(self.id).has_body | ||
813 | } | ||
814 | |||
815 | /// A textual representation of the HIR of this function for debugging purposes. | ||
816 | pub fn debug_hir(self, db: &dyn HirDatabase) -> String { | ||
817 | let body = db.body(self.id.into()); | ||
818 | |||
819 | let mut result = String::new(); | ||
820 | format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); | ||
821 | for (id, expr) in body.exprs.iter() { | ||
822 | format_to!(result, "{:?}: {:?}\n", id, expr); | ||
823 | } | ||
824 | |||
825 | result | ||
826 | } | ||
827 | } | ||
828 | |||
829 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. | ||
830 | pub enum Access { | ||
831 | Shared, | ||
832 | Exclusive, | ||
833 | Owned, | ||
834 | } | ||
835 | |||
836 | impl From<Mutability> for Access { | ||
837 | fn from(mutability: Mutability) -> Access { | ||
838 | match mutability { | ||
839 | Mutability::Not => Access::Shared, | ||
840 | Mutability::Mut => Access::Exclusive, | ||
841 | } | ||
842 | } | ||
843 | } | ||
844 | |||
845 | #[derive(Debug)] | ||
846 | pub struct Param { | ||
847 | ty: Type, | ||
848 | } | ||
849 | |||
850 | impl Param { | ||
851 | pub fn ty(&self) -> &Type { | ||
852 | &self.ty | ||
853 | } | ||
854 | } | ||
855 | |||
856 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
857 | pub struct SelfParam { | ||
858 | func: FunctionId, | ||
859 | } | ||
860 | |||
861 | impl SelfParam { | ||
862 | pub fn access(self, db: &dyn HirDatabase) -> Access { | ||
863 | let func_data = db.function_data(self.func); | ||
864 | func_data | ||
865 | .params | ||
866 | .first() | ||
867 | .map(|param| match *param { | ||
868 | TypeRef::Reference(.., mutability) => match mutability { | ||
869 | hir_def::type_ref::Mutability::Shared => Access::Shared, | ||
870 | hir_def::type_ref::Mutability::Mut => Access::Exclusive, | ||
871 | }, | ||
872 | _ => Access::Owned, | ||
873 | }) | ||
874 | .unwrap_or(Access::Owned) | ||
875 | } | ||
876 | } | ||
877 | |||
878 | impl HasVisibility for Function { | ||
879 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
880 | let function_data = db.function_data(self.id); | ||
881 | let visibility = &function_data.visibility; | ||
882 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
883 | } | ||
884 | } | ||
885 | |||
886 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
887 | pub struct Const { | ||
888 | pub(crate) id: ConstId, | ||
889 | } | ||
890 | |||
891 | impl Const { | ||
892 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
893 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
894 | } | ||
895 | |||
896 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
897 | Some(self.module(db).krate()) | ||
898 | } | ||
899 | |||
900 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
901 | db.const_data(self.id).name.clone() | ||
902 | } | ||
903 | } | ||
904 | |||
905 | impl HasVisibility for Const { | ||
906 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
907 | let function_data = db.const_data(self.id); | ||
908 | let visibility = &function_data.visibility; | ||
909 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
910 | } | ||
911 | } | ||
912 | |||
913 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
914 | pub struct Static { | ||
915 | pub(crate) id: StaticId, | ||
916 | } | ||
917 | |||
918 | impl Static { | ||
919 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
920 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
921 | } | ||
922 | |||
923 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
924 | Some(self.module(db).krate()) | ||
925 | } | ||
926 | |||
927 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
928 | db.static_data(self.id).name.clone() | ||
929 | } | ||
930 | |||
931 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
932 | db.static_data(self.id).mutable | ||
933 | } | ||
934 | } | ||
935 | |||
936 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
937 | pub struct Trait { | ||
938 | pub(crate) id: TraitId, | ||
939 | } | ||
940 | |||
941 | impl Trait { | ||
942 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
943 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
944 | } | ||
945 | |||
946 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
947 | db.trait_data(self.id).name.clone() | ||
948 | } | ||
949 | |||
950 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
951 | db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() | ||
952 | } | ||
953 | |||
954 | pub fn is_auto(self, db: &dyn HirDatabase) -> bool { | ||
955 | db.trait_data(self.id).auto | ||
956 | } | ||
957 | } | ||
958 | |||
959 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
960 | pub struct TypeAlias { | ||
961 | pub(crate) id: TypeAliasId, | ||
962 | } | ||
963 | |||
964 | impl TypeAlias { | ||
965 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
966 | let subst = db.generic_defaults(self.id.into()); | ||
967 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
968 | } | ||
969 | |||
970 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
971 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
972 | } | ||
973 | |||
974 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
975 | Some(self.module(db).krate()) | ||
976 | } | ||
977 | |||
978 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
979 | db.type_alias_data(self.id).type_ref.clone() | ||
980 | } | ||
981 | |||
982 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
983 | Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id) | ||
984 | } | ||
985 | |||
986 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
987 | db.type_alias_data(self.id).name.clone() | ||
988 | } | ||
989 | } | ||
990 | |||
991 | impl HasVisibility for TypeAlias { | ||
992 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
993 | let function_data = db.type_alias_data(self.id); | ||
994 | let visibility = &function_data.visibility; | ||
995 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
996 | } | ||
997 | } | ||
998 | |||
999 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1000 | pub struct BuiltinType { | ||
1001 | pub(crate) inner: hir_def::builtin_type::BuiltinType, | ||
1002 | } | ||
1003 | |||
1004 | impl BuiltinType { | ||
1005 | pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { | ||
1006 | let resolver = module.id.resolver(db.upcast()); | ||
1007 | Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner)) | ||
1008 | .expect("crate not present in resolver") | ||
1009 | } | ||
1010 | |||
1011 | pub fn name(self) -> Name { | ||
1012 | self.inner.as_name() | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1017 | pub struct MacroDef { | ||
1018 | pub(crate) id: MacroDefId, | ||
1019 | } | ||
1020 | |||
1021 | impl MacroDef { | ||
1022 | /// FIXME: right now, this just returns the root module of the crate that | ||
1023 | /// defines this macro. The reasons for this is that macros are expanded | ||
1024 | /// early, in `hir_expand`, where modules simply do not exist yet. | ||
1025 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
1026 | let krate = self.id.krate; | ||
1027 | let def_map = db.crate_def_map(krate); | ||
1028 | let module_id = def_map.root(); | ||
1029 | Some(Module { id: def_map.module_id(module_id) }) | ||
1030 | } | ||
1031 | |||
1032 | /// XXX: this parses the file | ||
1033 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1034 | self.source(db)?.value.name().map(|it| it.as_name()) | ||
1035 | } | ||
1036 | |||
1037 | /// Indicate it is a proc-macro | ||
1038 | pub fn is_proc_macro(&self) -> bool { | ||
1039 | matches!(self.id.kind, MacroDefKind::ProcMacro(_)) | ||
1040 | } | ||
1041 | |||
1042 | /// Indicate it is a derive macro | ||
1043 | pub fn is_derive_macro(&self) -> bool { | ||
1044 | matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_)) | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | /// Invariant: `inner.as_assoc_item(db).is_some()` | ||
1049 | /// We do not actively enforce this invariant. | ||
1050 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
1051 | pub enum AssocItem { | ||
1052 | Function(Function), | ||
1053 | Const(Const), | ||
1054 | TypeAlias(TypeAlias), | ||
1055 | } | ||
1056 | pub enum AssocItemContainer { | ||
1057 | Trait(Trait), | ||
1058 | Impl(Impl), | ||
1059 | } | ||
1060 | pub trait AsAssocItem { | ||
1061 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>; | ||
1062 | } | ||
1063 | |||
1064 | impl AsAssocItem for Function { | ||
1065 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1066 | as_assoc_item(db, AssocItem::Function, self.id) | ||
1067 | } | ||
1068 | } | ||
1069 | impl AsAssocItem for Const { | ||
1070 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1071 | as_assoc_item(db, AssocItem::Const, self.id) | ||
1072 | } | ||
1073 | } | ||
1074 | impl AsAssocItem for TypeAlias { | ||
1075 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1076 | as_assoc_item(db, AssocItem::TypeAlias, self.id) | ||
1077 | } | ||
1078 | } | ||
1079 | impl AsAssocItem for ModuleDef { | ||
1080 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1081 | match self { | ||
1082 | ModuleDef::Function(it) => it.as_assoc_item(db), | ||
1083 | ModuleDef::Const(it) => it.as_assoc_item(db), | ||
1084 | ModuleDef::TypeAlias(it) => it.as_assoc_item(db), | ||
1085 | _ => None, | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> | ||
1090 | where | ||
1091 | ID: Lookup<Data = AssocItemLoc<AST>>, | ||
1092 | DEF: From<ID>, | ||
1093 | CTOR: FnOnce(DEF) -> AssocItem, | ||
1094 | AST: ItemTreeNode, | ||
1095 | { | ||
1096 | match id.lookup(db.upcast()).container { | ||
1097 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | ||
1098 | AssocContainerId::ContainerId(_) => None, | ||
1099 | } | ||
1100 | } | ||
1101 | |||
1102 | impl AssocItem { | ||
1103 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1104 | match self { | ||
1105 | AssocItem::Function(it) => Some(it.name(db)), | ||
1106 | AssocItem::Const(it) => it.name(db), | ||
1107 | AssocItem::TypeAlias(it) => Some(it.name(db)), | ||
1108 | } | ||
1109 | } | ||
1110 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1111 | match self { | ||
1112 | AssocItem::Function(f) => f.module(db), | ||
1113 | AssocItem::Const(c) => c.module(db), | ||
1114 | AssocItem::TypeAlias(t) => t.module(db), | ||
1115 | } | ||
1116 | } | ||
1117 | pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { | ||
1118 | let container = match self { | ||
1119 | AssocItem::Function(it) => it.id.lookup(db.upcast()).container, | ||
1120 | AssocItem::Const(it) => it.id.lookup(db.upcast()).container, | ||
1121 | AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container, | ||
1122 | }; | ||
1123 | match container { | ||
1124 | AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), | ||
1125 | AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()), | ||
1126 | AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1131 | match self.container(db) { | ||
1132 | AssocItemContainer::Trait(t) => Some(t), | ||
1133 | _ => None, | ||
1134 | } | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | impl HasVisibility for AssocItem { | ||
1139 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
1140 | match self { | ||
1141 | AssocItem::Function(f) => f.visibility(db), | ||
1142 | AssocItem::Const(c) => c.visibility(db), | ||
1143 | AssocItem::TypeAlias(t) => t.visibility(db), | ||
1144 | } | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | ||
1149 | pub enum GenericDef { | ||
1150 | Function(Function), | ||
1151 | Adt(Adt), | ||
1152 | Trait(Trait), | ||
1153 | TypeAlias(TypeAlias), | ||
1154 | Impl(Impl), | ||
1155 | // enum variants cannot have generics themselves, but their parent enums | ||
1156 | // can, and this makes some code easier to write | ||
1157 | Variant(Variant), | ||
1158 | // consts can have type parameters from their parents (i.e. associated consts of traits) | ||
1159 | Const(Const), | ||
1160 | } | ||
1161 | impl_from!( | ||
1162 | Function, | ||
1163 | Adt(Struct, Enum, Union), | ||
1164 | Trait, | ||
1165 | TypeAlias, | ||
1166 | Impl, | ||
1167 | Variant, | ||
1168 | Const | ||
1169 | for GenericDef | ||
1170 | ); | ||
1171 | |||
1172 | impl GenericDef { | ||
1173 | pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { | ||
1174 | let generics = db.generic_params(self.into()); | ||
1175 | let ty_params = generics | ||
1176 | .types | ||
1177 | .iter() | ||
1178 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1179 | .map(GenericParam::TypeParam); | ||
1180 | let lt_params = generics | ||
1181 | .lifetimes | ||
1182 | .iter() | ||
1183 | .map(|(local_id, _)| LifetimeParam { | ||
1184 | id: LifetimeParamId { parent: self.into(), local_id }, | ||
1185 | }) | ||
1186 | .map(GenericParam::LifetimeParam); | ||
1187 | let const_params = generics | ||
1188 | .consts | ||
1189 | .iter() | ||
1190 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1191 | .map(GenericParam::ConstParam); | ||
1192 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1193 | } | ||
1194 | |||
1195 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | ||
1196 | let generics = db.generic_params(self.into()); | ||
1197 | generics | ||
1198 | .types | ||
1199 | .iter() | ||
1200 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1201 | .collect() | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1206 | pub struct Local { | ||
1207 | pub(crate) parent: DefWithBodyId, | ||
1208 | pub(crate) pat_id: PatId, | ||
1209 | } | ||
1210 | |||
1211 | impl Local { | ||
1212 | pub fn is_param(self, db: &dyn HirDatabase) -> bool { | ||
1213 | let src = self.source(db); | ||
1214 | match src.value { | ||
1215 | Either::Left(bind_pat) => { | ||
1216 | bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind())) | ||
1217 | } | ||
1218 | Either::Right(_self_param) => true, | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | // FIXME: why is this an option? It shouldn't be? | ||
1223 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1224 | let body = db.body(self.parent.into()); | ||
1225 | match &body[self.pat_id] { | ||
1226 | Pat::Bind { name, .. } => Some(name.clone()), | ||
1227 | _ => None, | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | pub fn is_self(self, db: &dyn HirDatabase) -> bool { | ||
1232 | self.name(db) == Some(name![self]) | ||
1233 | } | ||
1234 | |||
1235 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
1236 | let body = db.body(self.parent.into()); | ||
1237 | match &body[self.pat_id] { | ||
1238 | Pat::Bind { mode, .. } => match mode { | ||
1239 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | ||
1240 | _ => false, | ||
1241 | }, | ||
1242 | _ => false, | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1247 | self.parent.into() | ||
1248 | } | ||
1249 | |||
1250 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1251 | self.parent(db).module(db) | ||
1252 | } | ||
1253 | |||
1254 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1255 | let def = DefWithBodyId::from(self.parent); | ||
1256 | let infer = db.infer(def); | ||
1257 | let ty = infer[self.pat_id].clone(); | ||
1258 | let krate = def.module(db.upcast()).krate(); | ||
1259 | Type::new(db, krate, def, ty) | ||
1260 | } | ||
1261 | |||
1262 | pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> { | ||
1263 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1264 | let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... | ||
1265 | let root = src.file_syntax(db.upcast()); | ||
1266 | src.map(|ast| { | ||
1267 | ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) | ||
1268 | }) | ||
1269 | } | ||
1270 | } | ||
1271 | |||
1272 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1273 | pub struct Label { | ||
1274 | pub(crate) parent: DefWithBodyId, | ||
1275 | pub(crate) label_id: LabelId, | ||
1276 | } | ||
1277 | |||
1278 | impl Label { | ||
1279 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1280 | self.parent(db).module(db) | ||
1281 | } | ||
1282 | |||
1283 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1284 | self.parent.into() | ||
1285 | } | ||
1286 | |||
1287 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1288 | let body = db.body(self.parent.into()); | ||
1289 | body[self.label_id].name.clone() | ||
1290 | } | ||
1291 | |||
1292 | pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> { | ||
1293 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1294 | let src = source_map.label_syntax(self.label_id); | ||
1295 | let root = src.file_syntax(db.upcast()); | ||
1296 | src.map(|ast| ast.to_node(&root)) | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1301 | pub enum GenericParam { | ||
1302 | TypeParam(TypeParam), | ||
1303 | LifetimeParam(LifetimeParam), | ||
1304 | ConstParam(ConstParam), | ||
1305 | } | ||
1306 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); | ||
1307 | |||
1308 | impl GenericParam { | ||
1309 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1310 | match self { | ||
1311 | GenericParam::TypeParam(it) => it.module(db), | ||
1312 | GenericParam::LifetimeParam(it) => it.module(db), | ||
1313 | GenericParam::ConstParam(it) => it.module(db), | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1318 | match self { | ||
1319 | GenericParam::TypeParam(it) => it.name(db), | ||
1320 | GenericParam::LifetimeParam(it) => it.name(db), | ||
1321 | GenericParam::ConstParam(it) => it.name(db), | ||
1322 | } | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1327 | pub struct TypeParam { | ||
1328 | pub(crate) id: TypeParamId, | ||
1329 | } | ||
1330 | |||
1331 | impl TypeParam { | ||
1332 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1333 | let params = db.generic_params(self.id.parent); | ||
1334 | params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing) | ||
1335 | } | ||
1336 | |||
1337 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1338 | self.id.parent.module(db.upcast()).into() | ||
1339 | } | ||
1340 | |||
1341 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1342 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1343 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1344 | let ty = Ty::Placeholder(self.id); | ||
1345 | Type { | ||
1346 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1347 | ty: InEnvironment { value: ty, environment }, | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1352 | db.generic_predicates_for_param(self.id) | ||
1353 | .into_iter() | ||
1354 | .filter_map(|pred| match &pred.value { | ||
1355 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1356 | Some(Trait::from(trait_ref.trait_)) | ||
1357 | } | ||
1358 | _ => None, | ||
1359 | }) | ||
1360 | .collect() | ||
1361 | } | ||
1362 | |||
1363 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | ||
1364 | let params = db.generic_defaults(self.id.parent); | ||
1365 | let local_idx = hir_ty::param_idx(db, self.id)?; | ||
1366 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1367 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1368 | let ty = params.get(local_idx)?.clone(); | ||
1369 | let subst = Substs::type_params(db, self.id.parent); | ||
1370 | let ty = ty.subst(&subst.prefix(local_idx)); | ||
1371 | Some(Type { | ||
1372 | krate: self.id.parent.module(db.upcast()).krate(), | ||
1373 | ty: InEnvironment { value: ty, environment }, | ||
1374 | }) | ||
1375 | } | ||
1376 | } | ||
1377 | |||
1378 | impl HirDisplay for TypeParam { | ||
1379 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1380 | write!(f, "{}", self.name(f.db))?; | ||
1381 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1382 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1383 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1384 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1385 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; | ||
1386 | } | ||
1387 | Ok(()) | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1392 | pub struct LifetimeParam { | ||
1393 | pub(crate) id: LifetimeParamId, | ||
1394 | } | ||
1395 | |||
1396 | impl LifetimeParam { | ||
1397 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1398 | let params = db.generic_params(self.id.parent); | ||
1399 | params.lifetimes[self.id.local_id].name.clone() | ||
1400 | } | ||
1401 | |||
1402 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1403 | self.id.parent.module(db.upcast()).into() | ||
1404 | } | ||
1405 | |||
1406 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1407 | self.id.parent.into() | ||
1408 | } | ||
1409 | } | ||
1410 | |||
1411 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1412 | pub struct ConstParam { | ||
1413 | pub(crate) id: ConstParamId, | ||
1414 | } | ||
1415 | |||
1416 | impl ConstParam { | ||
1417 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1418 | let params = db.generic_params(self.id.parent); | ||
1419 | params.consts[self.id.local_id].name.clone() | ||
1420 | } | ||
1421 | |||
1422 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1423 | self.id.parent.module(db.upcast()).into() | ||
1424 | } | ||
1425 | |||
1426 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1427 | self.id.parent.into() | ||
1428 | } | ||
1429 | |||
1430 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1431 | let def = self.id.parent; | ||
1432 | let krate = def.module(db.upcast()).krate(); | ||
1433 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1434 | } | ||
1435 | } | ||
1436 | |||
1437 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1438 | pub struct Impl { | ||
1439 | pub(crate) id: ImplId, | ||
1440 | } | ||
1441 | |||
1442 | impl Impl { | ||
1443 | pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> { | ||
1444 | let inherent = db.inherent_impls_in_crate(krate.id); | ||
1445 | let trait_ = db.trait_impls_in_crate(krate.id); | ||
1446 | |||
1447 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() | ||
1448 | } | ||
1449 | pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { | ||
1450 | let impls = db.trait_impls_in_crate(krate.id); | ||
1451 | impls.for_trait(trait_.id).map(Self::from).collect() | ||
1452 | } | ||
1453 | |||
1454 | // FIXME: the return type is wrong. This should be a hir version of | ||
1455 | // `TraitRef` (ie, resolved `TypeRef`). | ||
1456 | pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
1457 | db.impl_data(self.id).target_trait.clone() | ||
1458 | } | ||
1459 | |||
1460 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { | ||
1461 | let impl_data = db.impl_data(self.id); | ||
1462 | let resolver = self.id.resolver(db.upcast()); | ||
1463 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
1464 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1465 | let ty = Ty::from_hir(&ctx, &impl_data.target_type); | ||
1466 | Type { | ||
1467 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
1468 | ty: InEnvironment { value: ty, environment }, | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
1473 | db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() | ||
1474 | } | ||
1475 | |||
1476 | pub fn is_negative(self, db: &dyn HirDatabase) -> bool { | ||
1477 | db.impl_data(self.id).is_negative | ||
1478 | } | ||
1479 | |||
1480 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1481 | self.id.lookup(db.upcast()).container.module(db.upcast()).into() | ||
1482 | } | ||
1483 | |||
1484 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1485 | Crate { id: self.module(db).id.krate() } | ||
1486 | } | ||
1487 | |||
1488 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | ||
1489 | let src = self.source(db)?; | ||
1490 | let item = src.file_id.is_builtin_derive(db.upcast())?; | ||
1491 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | ||
1492 | |||
1493 | // FIXME: handle `cfg_attr` | ||
1494 | let attr = item | ||
1495 | .value | ||
1496 | .attrs() | ||
1497 | .filter_map(|it| { | ||
1498 | let path = ModPath::from_src(it.path()?, &hygenic)?; | ||
1499 | if path.as_ident()?.to_string() == "derive" { | ||
1500 | Some(it) | ||
1501 | } else { | ||
1502 | None | ||
1503 | } | ||
1504 | }) | ||
1505 | .last()?; | ||
1506 | |||
1507 | Some(item.with_value(attr)) | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
1512 | pub struct Type { | ||
1513 | krate: CrateId, | ||
1514 | ty: InEnvironment<Ty>, | ||
1515 | } | ||
1516 | |||
1517 | impl Type { | ||
1518 | pub(crate) fn new_with_resolver( | ||
1519 | db: &dyn HirDatabase, | ||
1520 | resolver: &Resolver, | ||
1521 | ty: Ty, | ||
1522 | ) -> Option<Type> { | ||
1523 | let krate = resolver.krate()?; | ||
1524 | Some(Type::new_with_resolver_inner(db, krate, resolver, ty)) | ||
1525 | } | ||
1526 | pub(crate) fn new_with_resolver_inner( | ||
1527 | db: &dyn HirDatabase, | ||
1528 | krate: CrateId, | ||
1529 | resolver: &Resolver, | ||
1530 | ty: Ty, | ||
1531 | ) -> Type { | ||
1532 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1533 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1534 | } | ||
1535 | |||
1536 | fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { | ||
1537 | let resolver = lexical_env.resolver(db.upcast()); | ||
1538 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1539 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1540 | } | ||
1541 | |||
1542 | fn from_def( | ||
1543 | db: &dyn HirDatabase, | ||
1544 | krate: CrateId, | ||
1545 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | ||
1546 | ) -> Type { | ||
1547 | let substs = Substs::build_for_def(db, def).fill_with_unknown().build(); | ||
1548 | let ty = db.ty(def.into()).subst(&substs); | ||
1549 | Type::new(db, krate, def, ty) | ||
1550 | } | ||
1551 | |||
1552 | pub fn is_unit(&self) -> bool { | ||
1553 | matches!(self.ty.value, Ty::Tuple(0, ..)) | ||
1554 | } | ||
1555 | pub fn is_bool(&self) -> bool { | ||
1556 | matches!(self.ty.value, Ty::Scalar(Scalar::Bool)) | ||
1557 | } | ||
1558 | |||
1559 | pub fn is_mutable_reference(&self) -> bool { | ||
1560 | matches!(self.ty.value, Ty::Ref(Mutability::Mut, ..)) | ||
1561 | } | ||
1562 | |||
1563 | pub fn remove_ref(&self) -> Option<Type> { | ||
1564 | if let Ty::Ref(.., substs) = &self.ty.value { | ||
1565 | Some(self.derived(substs[0].clone())) | ||
1566 | } else { | ||
1567 | None | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1571 | pub fn is_unknown(&self) -> bool { | ||
1572 | matches!(self.ty.value, Ty::Unknown) | ||
1573 | } | ||
1574 | |||
1575 | /// Checks that particular type `ty` implements `std::future::Future`. | ||
1576 | /// This function is used in `.await` syntax completion. | ||
1577 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { | ||
1578 | // No special case for the type of async block, since Chalk can figure it out. | ||
1579 | |||
1580 | let krate = self.krate; | ||
1581 | |||
1582 | let std_future_trait = | ||
1583 | db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait()); | ||
1584 | let std_future_trait = match std_future_trait { | ||
1585 | Some(it) => it, | ||
1586 | None => return false, | ||
1587 | }; | ||
1588 | |||
1589 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1590 | method_resolution::implements_trait( | ||
1591 | &canonical_ty, | ||
1592 | db, | ||
1593 | self.ty.environment.clone(), | ||
1594 | krate, | ||
1595 | std_future_trait, | ||
1596 | ) | ||
1597 | } | ||
1598 | |||
1599 | /// Checks that particular type `ty` implements `std::ops::FnOnce`. | ||
1600 | /// | ||
1601 | /// This function can be used to check if a particular type is callable, since FnOnce is a | ||
1602 | /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. | ||
1603 | pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool { | ||
1604 | let krate = self.krate; | ||
1605 | |||
1606 | let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) { | ||
1607 | Some(it) => it, | ||
1608 | None => return false, | ||
1609 | }; | ||
1610 | |||
1611 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1612 | method_resolution::implements_trait_unique( | ||
1613 | &canonical_ty, | ||
1614 | db, | ||
1615 | self.ty.environment.clone(), | ||
1616 | krate, | ||
1617 | fnonce_trait, | ||
1618 | ) | ||
1619 | } | ||
1620 | |||
1621 | pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { | ||
1622 | let trait_ref = hir_ty::TraitRef { | ||
1623 | trait_: trait_.id, | ||
1624 | substs: Substs::build_for_def(db, trait_.id) | ||
1625 | .push(self.ty.value.clone()) | ||
1626 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1627 | .build(), | ||
1628 | }; | ||
1629 | |||
1630 | let goal = Canonical { | ||
1631 | value: hir_ty::InEnvironment::new( | ||
1632 | self.ty.environment.clone(), | ||
1633 | hir_ty::Obligation::Trait(trait_ref), | ||
1634 | ), | ||
1635 | kinds: Arc::new([]), | ||
1636 | }; | ||
1637 | |||
1638 | db.trait_solve(self.krate, goal).is_some() | ||
1639 | } | ||
1640 | |||
1641 | pub fn normalize_trait_assoc_type( | ||
1642 | &self, | ||
1643 | db: &dyn HirDatabase, | ||
1644 | trait_: Trait, | ||
1645 | args: &[Type], | ||
1646 | alias: TypeAlias, | ||
1647 | ) -> Option<Type> { | ||
1648 | let subst = Substs::build_for_def(db, trait_.id) | ||
1649 | .push(self.ty.value.clone()) | ||
1650 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1651 | .build(); | ||
1652 | let predicate = ProjectionPredicate { | ||
1653 | projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst }, | ||
1654 | ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)), | ||
1655 | }; | ||
1656 | let goal = Canonical { | ||
1657 | value: InEnvironment::new( | ||
1658 | self.ty.environment.clone(), | ||
1659 | Obligation::Projection(predicate), | ||
1660 | ), | ||
1661 | kinds: Arc::new([TyVariableKind::General]), | ||
1662 | }; | ||
1663 | |||
1664 | match db.trait_solve(self.krate, goal)? { | ||
1665 | Solution::Unique(SolutionVariables(subst)) => subst.value.first().cloned(), | ||
1666 | Solution::Ambig(_) => None, | ||
1667 | } | ||
1668 | .map(|ty| Type { | ||
1669 | krate: self.krate, | ||
1670 | ty: InEnvironment { value: ty, environment: Arc::clone(&self.ty.environment) }, | ||
1671 | }) | ||
1672 | } | ||
1673 | |||
1674 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | ||
1675 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); | ||
1676 | let copy_trait = match lang_item { | ||
1677 | Some(LangItemTarget::TraitId(it)) => it, | ||
1678 | _ => return false, | ||
1679 | }; | ||
1680 | self.impls_trait(db, copy_trait.into(), &[]) | ||
1681 | } | ||
1682 | |||
1683 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { | ||
1684 | let def = match self.ty.value { | ||
1685 | Ty::FnDef(def, _) => Some(def), | ||
1686 | _ => None, | ||
1687 | }; | ||
1688 | |||
1689 | let sig = self.ty.value.callable_sig(db)?; | ||
1690 | Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) | ||
1691 | } | ||
1692 | |||
1693 | pub fn is_closure(&self) -> bool { | ||
1694 | matches!(&self.ty.value, Ty::Closure { .. }) | ||
1695 | } | ||
1696 | |||
1697 | pub fn is_fn(&self) -> bool { | ||
1698 | matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. }) | ||
1699 | } | ||
1700 | |||
1701 | pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { | ||
1702 | let adt_id = match self.ty.value { | ||
1703 | Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, | ||
1704 | _ => return false, | ||
1705 | }; | ||
1706 | |||
1707 | let adt = adt_id.into(); | ||
1708 | match adt { | ||
1709 | Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), | ||
1710 | _ => false, | ||
1711 | } | ||
1712 | } | ||
1713 | |||
1714 | pub fn is_raw_ptr(&self) -> bool { | ||
1715 | matches!(&self.ty.value, Ty::Raw(..)) | ||
1716 | } | ||
1717 | |||
1718 | pub fn contains_unknown(&self) -> bool { | ||
1719 | return go(&self.ty.value); | ||
1720 | |||
1721 | fn go(ty: &Ty) -> bool { | ||
1722 | match ty { | ||
1723 | Ty::Unknown => true, | ||
1724 | _ => ty.substs().map_or(false, |substs| substs.iter().any(go)), | ||
1725 | } | ||
1726 | } | ||
1727 | } | ||
1728 | |||
1729 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { | ||
1730 | let (variant_id, substs) = match self.ty.value { | ||
1731 | Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), | ||
1732 | Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), | ||
1733 | _ => return Vec::new(), | ||
1734 | }; | ||
1735 | |||
1736 | db.field_types(variant_id) | ||
1737 | .iter() | ||
1738 | .map(|(local_id, ty)| { | ||
1739 | let def = Field { parent: variant_id.into(), id: local_id }; | ||
1740 | let ty = ty.clone().subst(substs); | ||
1741 | (def, self.derived(ty)) | ||
1742 | }) | ||
1743 | .collect() | ||
1744 | } | ||
1745 | |||
1746 | pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> { | ||
1747 | if let Ty::Tuple(_, substs) = &self.ty.value { | ||
1748 | substs.iter().map(|ty| self.derived(ty.clone())).collect() | ||
1749 | } else { | ||
1750 | Vec::new() | ||
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { | ||
1755 | // There should be no inference vars in types passed here | ||
1756 | // FIXME check that? | ||
1757 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1758 | let environment = self.ty.environment.clone(); | ||
1759 | let ty = InEnvironment { value: canonical, environment }; | ||
1760 | autoderef(db, Some(self.krate), ty) | ||
1761 | .map(|canonical| canonical.value) | ||
1762 | .map(move |ty| self.derived(ty)) | ||
1763 | } | ||
1764 | |||
1765 | // This would be nicer if it just returned an iterator, but that runs into | ||
1766 | // lifetime problems, because we need to borrow temp `CrateImplDefs`. | ||
1767 | pub fn iterate_assoc_items<T>( | ||
1768 | self, | ||
1769 | db: &dyn HirDatabase, | ||
1770 | krate: Crate, | ||
1771 | mut callback: impl FnMut(AssocItem) -> Option<T>, | ||
1772 | ) -> Option<T> { | ||
1773 | for krate in self.ty.value.def_crates(db, krate.id)? { | ||
1774 | let impls = db.inherent_impls_in_crate(krate); | ||
1775 | |||
1776 | for impl_def in impls.for_self_ty(&self.ty.value) { | ||
1777 | for &item in db.impl_data(*impl_def).items.iter() { | ||
1778 | if let Some(result) = callback(item.into()) { | ||
1779 | return Some(result); | ||
1780 | } | ||
1781 | } | ||
1782 | } | ||
1783 | } | ||
1784 | None | ||
1785 | } | ||
1786 | |||
1787 | pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { | ||
1788 | self.ty | ||
1789 | .value | ||
1790 | .strip_references() | ||
1791 | .substs() | ||
1792 | .into_iter() | ||
1793 | .flat_map(|substs| substs.iter()) | ||
1794 | .map(move |ty| self.derived(ty.clone())) | ||
1795 | } | ||
1796 | |||
1797 | pub fn iterate_method_candidates<T>( | ||
1798 | &self, | ||
1799 | db: &dyn HirDatabase, | ||
1800 | krate: Crate, | ||
1801 | traits_in_scope: &FxHashSet<TraitId>, | ||
1802 | name: Option<&Name>, | ||
1803 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | ||
1804 | ) -> Option<T> { | ||
1805 | // There should be no inference vars in types passed here | ||
1806 | // FIXME check that? | ||
1807 | // FIXME replace Unknown by bound vars here | ||
1808 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1809 | |||
1810 | let env = self.ty.environment.clone(); | ||
1811 | let krate = krate.id; | ||
1812 | |||
1813 | method_resolution::iterate_method_candidates( | ||
1814 | &canonical, | ||
1815 | db, | ||
1816 | env, | ||
1817 | krate, | ||
1818 | traits_in_scope, | ||
1819 | name, | ||
1820 | method_resolution::LookupMode::MethodCall, | ||
1821 | |ty, it| match it { | ||
1822 | AssocItemId::FunctionId(f) => callback(ty, f.into()), | ||
1823 | _ => None, | ||
1824 | }, | ||
1825 | ) | ||
1826 | } | ||
1827 | |||
1828 | pub fn iterate_path_candidates<T>( | ||
1829 | &self, | ||
1830 | db: &dyn HirDatabase, | ||
1831 | krate: Crate, | ||
1832 | traits_in_scope: &FxHashSet<TraitId>, | ||
1833 | name: Option<&Name>, | ||
1834 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
1835 | ) -> Option<T> { | ||
1836 | // There should be no inference vars in types passed here | ||
1837 | // FIXME check that? | ||
1838 | // FIXME replace Unknown by bound vars here | ||
1839 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1840 | |||
1841 | let env = self.ty.environment.clone(); | ||
1842 | let krate = krate.id; | ||
1843 | |||
1844 | method_resolution::iterate_method_candidates( | ||
1845 | &canonical, | ||
1846 | db, | ||
1847 | env, | ||
1848 | krate, | ||
1849 | traits_in_scope, | ||
1850 | name, | ||
1851 | method_resolution::LookupMode::Path, | ||
1852 | |ty, it| callback(ty, it.into()), | ||
1853 | ) | ||
1854 | } | ||
1855 | |||
1856 | pub fn as_adt(&self) -> Option<Adt> { | ||
1857 | let (adt, _subst) = self.ty.value.as_adt()?; | ||
1858 | Some(adt.into()) | ||
1859 | } | ||
1860 | |||
1861 | pub fn as_dyn_trait(&self) -> Option<Trait> { | ||
1862 | self.ty.value.dyn_trait().map(Into::into) | ||
1863 | } | ||
1864 | |||
1865 | pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { | ||
1866 | self.ty.value.impl_trait_bounds(db).map(|it| { | ||
1867 | it.into_iter() | ||
1868 | .filter_map(|pred| match pred { | ||
1869 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1870 | Some(Trait::from(trait_ref.trait_)) | ||
1871 | } | ||
1872 | _ => None, | ||
1873 | }) | ||
1874 | .collect() | ||
1875 | }) | ||
1876 | } | ||
1877 | |||
1878 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1879 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | ||
1880 | } | ||
1881 | |||
1882 | // FIXME: provide required accessors such that it becomes implementable from outside. | ||
1883 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | ||
1884 | let rref = other.remove_ref(); | ||
1885 | self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value)) | ||
1886 | } | ||
1887 | |||
1888 | fn derived(&self, ty: Ty) -> Type { | ||
1889 | Type { | ||
1890 | krate: self.krate, | ||
1891 | ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, | ||
1892 | } | ||
1893 | } | ||
1894 | |||
1895 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { | ||
1896 | // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. | ||
1897 | // We need a different order here. | ||
1898 | |||
1899 | fn walk_substs( | ||
1900 | db: &dyn HirDatabase, | ||
1901 | type_: &Type, | ||
1902 | substs: &Substs, | ||
1903 | cb: &mut impl FnMut(Type), | ||
1904 | ) { | ||
1905 | for ty in substs.iter() { | ||
1906 | walk_type(db, &type_.derived(ty.clone()), cb); | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | fn walk_bounds( | ||
1911 | db: &dyn HirDatabase, | ||
1912 | type_: &Type, | ||
1913 | bounds: &[GenericPredicate], | ||
1914 | cb: &mut impl FnMut(Type), | ||
1915 | ) { | ||
1916 | for pred in bounds { | ||
1917 | match pred { | ||
1918 | GenericPredicate::Implemented(trait_ref) => { | ||
1919 | cb(type_.clone()); | ||
1920 | walk_substs(db, type_, &trait_ref.substs, cb); | ||
1921 | } | ||
1922 | _ => (), | ||
1923 | } | ||
1924 | } | ||
1925 | } | ||
1926 | |||
1927 | fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { | ||
1928 | let ty = type_.ty.value.strip_references(); | ||
1929 | match ty { | ||
1930 | Ty::Adt(..) => { | ||
1931 | cb(type_.derived(ty.clone())); | ||
1932 | } | ||
1933 | Ty::AssociatedType(..) => { | ||
1934 | if let Some(_) = ty.associated_type_parent_trait(db) { | ||
1935 | cb(type_.derived(ty.clone())); | ||
1936 | } | ||
1937 | } | ||
1938 | Ty::OpaqueType(..) => { | ||
1939 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1940 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1941 | } | ||
1942 | } | ||
1943 | Ty::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
1944 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1945 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1946 | } | ||
1947 | |||
1948 | walk_substs(db, type_, &opaque_ty.parameters, cb); | ||
1949 | } | ||
1950 | Ty::Placeholder(_) => { | ||
1951 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1952 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1953 | } | ||
1954 | } | ||
1955 | Ty::Dyn(bounds) => { | ||
1956 | walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); | ||
1957 | } | ||
1958 | |||
1959 | _ => {} | ||
1960 | } | ||
1961 | if let Some(substs) = ty.substs() { | ||
1962 | walk_substs(db, type_, &substs, cb); | ||
1963 | } | ||
1964 | } | ||
1965 | |||
1966 | walk_type(db, self, &mut cb); | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1970 | impl HirDisplay for Type { | ||
1971 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1972 | self.ty.value.hir_fmt(f) | ||
1973 | } | ||
1974 | } | ||
1975 | |||
1976 | // FIXME: closures | ||
1977 | #[derive(Debug)] | ||
1978 | pub struct Callable { | ||
1979 | ty: Type, | ||
1980 | sig: CallableSig, | ||
1981 | def: Option<CallableDefId>, | ||
1982 | pub(crate) is_bound_method: bool, | ||
1983 | } | ||
1984 | |||
1985 | pub enum CallableKind { | ||
1986 | Function(Function), | ||
1987 | TupleStruct(Struct), | ||
1988 | TupleEnumVariant(Variant), | ||
1989 | Closure, | ||
1990 | } | ||
1991 | |||
1992 | impl Callable { | ||
1993 | pub fn kind(&self) -> CallableKind { | ||
1994 | match self.def { | ||
1995 | Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), | ||
1996 | Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), | ||
1997 | Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), | ||
1998 | None => CallableKind::Closure, | ||
1999 | } | ||
2000 | } | ||
2001 | pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { | ||
2002 | let func = match self.def { | ||
2003 | Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it, | ||
2004 | _ => return None, | ||
2005 | }; | ||
2006 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2007 | let param_list = src.value.param_list()?; | ||
2008 | param_list.self_param() | ||
2009 | } | ||
2010 | pub fn n_params(&self) -> usize { | ||
2011 | self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } | ||
2012 | } | ||
2013 | pub fn params( | ||
2014 | &self, | ||
2015 | db: &dyn HirDatabase, | ||
2016 | ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> { | ||
2017 | let types = self | ||
2018 | .sig | ||
2019 | .params() | ||
2020 | .iter() | ||
2021 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
2022 | .map(|ty| self.ty.derived(ty.clone())); | ||
2023 | let patterns = match self.def { | ||
2024 | Some(CallableDefId::FunctionId(func)) => { | ||
2025 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2026 | src.value.param_list().map(|param_list| { | ||
2027 | param_list | ||
2028 | .self_param() | ||
2029 | .map(|it| Some(Either::Left(it))) | ||
2030 | .filter(|_| !self.is_bound_method) | ||
2031 | .into_iter() | ||
2032 | .chain(param_list.params().map(|it| it.pat().map(Either::Right))) | ||
2033 | }) | ||
2034 | } | ||
2035 | _ => None, | ||
2036 | }; | ||
2037 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
2038 | } | ||
2039 | pub fn return_type(&self) -> Type { | ||
2040 | self.ty.derived(self.sig.ret().clone()) | ||
2041 | } | ||
2042 | } | ||
2043 | |||
2044 | /// For IDE only | ||
2045 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
2046 | pub enum ScopeDef { | ||
2047 | ModuleDef(ModuleDef), | ||
2048 | MacroDef(MacroDef), | ||
2049 | GenericParam(GenericParam), | ||
2050 | ImplSelfType(Impl), | ||
2051 | AdtSelfType(Adt), | ||
2052 | Local(Local), | ||
2053 | Unknown, | ||
2054 | } | ||
2055 | |||
2056 | impl ScopeDef { | ||
2057 | pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> { | ||
2058 | let mut items = ArrayVec::new(); | ||
2059 | |||
2060 | match (def.take_types(), def.take_values()) { | ||
2061 | (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), | ||
2062 | (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), | ||
2063 | (Some(m1), Some(m2)) => { | ||
2064 | // Some items, like unit structs and enum variants, are | ||
2065 | // returned as both a type and a value. Here we want | ||
2066 | // to de-duplicate them. | ||
2067 | if m1 != m2 { | ||
2068 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2069 | items.push(ScopeDef::ModuleDef(m2.into())); | ||
2070 | } else { | ||
2071 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2072 | } | ||
2073 | } | ||
2074 | (None, None) => {} | ||
2075 | }; | ||
2076 | |||
2077 | if let Some(macro_def_id) = def.take_macros() { | ||
2078 | items.push(ScopeDef::MacroDef(macro_def_id.into())); | ||
2079 | } | ||
2080 | |||
2081 | if items.is_empty() { | ||
2082 | items.push(ScopeDef::Unknown); | ||
2083 | } | ||
2084 | |||
2085 | items | ||
2086 | } | ||
2087 | } | ||
2088 | |||
2089 | pub trait HasVisibility { | ||
2090 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility; | ||
2091 | fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool { | ||
2092 | let vis = self.visibility(db); | ||
2093 | vis.is_visible_from(db.upcast(), module.id) | ||
2094 | } | ||
2095 | } | ||
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index b5814da11..179b9d51e 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs | |||
@@ -11,9 +11,8 @@ use hir_def::{ | |||
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | code_model::{BuiltinType, GenericParam}, | 14 | Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, Label, Local, |
15 | Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, | 15 | MacroDef, ModuleDef, Variant, VariantDef, |
16 | VariantDef, | ||
17 | }; | 16 | }; |
18 | 17 | ||
19 | macro_rules! from_id { | 18 | macro_rules! from_id { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 69fcdab07..d5a3d9034 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -20,49 +20,2137 @@ | |||
20 | #![recursion_limit = "512"] | 20 | #![recursion_limit = "512"] |
21 | 21 | ||
22 | mod semantics; | 22 | mod semantics; |
23 | pub mod db; | ||
24 | mod source_analyzer; | 23 | mod source_analyzer; |
25 | 24 | ||
26 | pub mod diagnostics; | ||
27 | |||
28 | mod from_id; | 25 | mod from_id; |
29 | mod code_model; | ||
30 | mod attrs; | 26 | mod attrs; |
31 | mod has_source; | 27 | mod has_source; |
32 | 28 | ||
29 | pub mod diagnostics; | ||
30 | pub mod db; | ||
31 | |||
32 | use std::{iter, sync::Arc}; | ||
33 | |||
34 | use arrayvec::ArrayVec; | ||
35 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | ||
36 | use either::Either; | ||
37 | use hir_def::{ | ||
38 | adt::{ReprKind, VariantData}, | ||
39 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | ||
40 | item_tree::ItemTreeNode, | ||
41 | lang_item::LangItemTarget, | ||
42 | per_ns::PerNs, | ||
43 | resolver::{HasResolver, Resolver}, | ||
44 | src::HasSource as _, | ||
45 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | ||
46 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | ||
47 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | ||
48 | TypeParamId, UnionId, | ||
49 | }; | ||
50 | use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | ||
51 | use hir_ty::{ | ||
52 | autoderef, | ||
53 | display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter}, | ||
54 | method_resolution, | ||
55 | traits::{FnTrait, Solution, SolutionVariables}, | ||
56 | AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate, | ||
57 | InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment, | ||
58 | Ty, TyDefId, TyVariableKind, | ||
59 | }; | ||
60 | use rustc_hash::FxHashSet; | ||
61 | use stdx::{format_to, impl_from}; | ||
62 | use syntax::{ | ||
63 | ast::{self, AttrsOwner, NameOwner}, | ||
64 | AstNode, SmolStr, | ||
65 | }; | ||
66 | use tt::{Ident, Leaf, Literal, TokenTree}; | ||
67 | |||
68 | use crate::db::{DefDatabase, HirDatabase}; | ||
69 | |||
33 | pub use crate::{ | 70 | pub use crate::{ |
34 | attrs::{HasAttrs, Namespace}, | 71 | attrs::{HasAttrs, Namespace}, |
35 | code_model::{ | ||
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, BuiltinType, Callable, | ||
37 | CallableKind, Const, ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, | ||
38 | FieldSource, Function, GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, | ||
39 | Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, | ||
40 | TypeParam, Union, Variant, VariantDef, | ||
41 | }, | ||
42 | has_source::HasSource, | 72 | has_source::HasSource, |
43 | semantics::{PathResolution, Semantics, SemanticsScope}, | 73 | semantics::{PathResolution, Semantics, SemanticsScope}, |
44 | }; | 74 | }; |
45 | 75 | ||
46 | pub use hir_def::{ | 76 | // Be careful with these re-exports. |
47 | adt::StructKind, | 77 | // |
48 | attr::{Attrs, Documentation}, | 78 | // `hir` is the boundary between the compiler and the IDE. It should try hard to |
49 | body::scope::ExprScopes, | 79 | // isolate the compiler from the ide, to allow the two to be refactored |
50 | find_path::PrefixKind, | 80 | // independently. Re-exporting something from the compiler is the sure way to |
51 | import_map, | 81 | // breach the boundary. |
52 | item_scope::ItemInNs, | 82 | // |
53 | nameres::ModuleSource, | 83 | // Generally, a refactoring which *removes* a name from this list is a good |
54 | path::{ModPath, PathKind}, | 84 | // idea! |
55 | type_ref::{Mutability, TypeRef}, | 85 | pub use { |
56 | visibility::Visibility, | 86 | hir_def::{ |
57 | }; | 87 | adt::StructKind, |
58 | pub use hir_expand::{ | 88 | attr::{Attrs, Documentation}, |
59 | name::{known, AsName, Name}, | 89 | body::scope::ExprScopes, |
60 | ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, | 90 | find_path::PrefixKind, |
61 | MacroFile, Origin, | 91 | import_map, |
92 | item_scope::ItemInNs, | ||
93 | nameres::ModuleSource, | ||
94 | path::{ModPath, PathKind}, | ||
95 | type_ref::{Mutability, TypeRef}, | ||
96 | visibility::Visibility, | ||
97 | }, | ||
98 | hir_expand::{ | ||
99 | name::{known, Name}, | ||
100 | ExpandResult, HirFileId, InFile, MacroCallId, MacroCallLoc, /* FIXME */ MacroDefId, | ||
101 | MacroFile, Origin, | ||
102 | }, | ||
103 | hir_ty::display::HirDisplay, | ||
62 | }; | 104 | }; |
63 | pub use hir_ty::display::HirDisplay; | ||
64 | 105 | ||
65 | // These are negative re-exports: pub using these names is forbidden, they | 106 | // These are negative re-exports: pub using these names is forbidden, they |
66 | // should remain private to hir internals. | 107 | // should remain private to hir internals. |
67 | #[allow(unused)] | 108 | #[allow(unused)] |
68 | use {hir_def::path::Path, hir_expand::hygiene::Hygiene}; | 109 | use { |
110 | hir_def::path::Path, | ||
111 | hir_expand::{hygiene::Hygiene, name::AsName}, | ||
112 | }; | ||
113 | |||
114 | /// hir::Crate describes a single crate. It's the main interface with which | ||
115 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | ||
116 | /// root module. | ||
117 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
118 | pub struct Crate { | ||
119 | pub(crate) id: CrateId, | ||
120 | } | ||
121 | |||
122 | #[derive(Debug)] | ||
123 | pub struct CrateDependency { | ||
124 | pub krate: Crate, | ||
125 | pub name: Name, | ||
126 | } | ||
127 | |||
128 | impl Crate { | ||
129 | pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> { | ||
130 | db.crate_graph()[self.id] | ||
131 | .dependencies | ||
132 | .iter() | ||
133 | .map(|dep| { | ||
134 | let krate = Crate { id: dep.crate_id }; | ||
135 | let name = dep.as_name(); | ||
136 | CrateDependency { krate, name } | ||
137 | }) | ||
138 | .collect() | ||
139 | } | ||
140 | |||
141 | // FIXME: add `transitive_reverse_dependencies`. | ||
142 | pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> { | ||
143 | let crate_graph = db.crate_graph(); | ||
144 | crate_graph | ||
145 | .iter() | ||
146 | .filter(|&krate| { | ||
147 | crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id) | ||
148 | }) | ||
149 | .map(|id| Crate { id }) | ||
150 | .collect() | ||
151 | } | ||
152 | |||
153 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { | ||
154 | let def_map = db.crate_def_map(self.id); | ||
155 | Module { id: def_map.module_id(def_map.root()) } | ||
156 | } | ||
157 | |||
158 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { | ||
159 | db.crate_graph()[self.id].root_file_id | ||
160 | } | ||
161 | |||
162 | pub fn edition(self, db: &dyn HirDatabase) -> Edition { | ||
163 | db.crate_graph()[self.id].edition | ||
164 | } | ||
165 | |||
166 | pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> { | ||
167 | db.crate_graph()[self.id].display_name.clone() | ||
168 | } | ||
169 | |||
170 | pub fn query_external_importables( | ||
171 | self, | ||
172 | db: &dyn DefDatabase, | ||
173 | query: import_map::Query, | ||
174 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
175 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | ||
176 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
177 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
178 | }) | ||
179 | } | ||
180 | |||
181 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | ||
182 | db.crate_graph().iter().map(|id| Crate { id }).collect() | ||
183 | } | ||
184 | |||
185 | /// Try to get the root URL of the documentation of a crate. | ||
186 | pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { | ||
187 | // Look for #![doc(html_root_url = "...")] | ||
188 | let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into())); | ||
189 | let doc_attr_q = attrs.by_key("doc"); | ||
190 | |||
191 | if !doc_attr_q.exists() { | ||
192 | return None; | ||
193 | } | ||
194 | |||
195 | let doc_url = doc_attr_q.tt_values().map(|tt| { | ||
196 | let name = tt.token_trees.iter() | ||
197 | .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url")) | ||
198 | .skip(2) | ||
199 | .next(); | ||
200 | |||
201 | match name { | ||
202 | Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text), | ||
203 | _ => None | ||
204 | } | ||
205 | }).flat_map(|t| t).next(); | ||
206 | |||
207 | doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") | ||
208 | } | ||
209 | } | ||
210 | |||
211 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
212 | pub struct Module { | ||
213 | pub(crate) id: ModuleId, | ||
214 | } | ||
215 | |||
216 | /// The defs which can be visible in the module. | ||
217 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
218 | pub enum ModuleDef { | ||
219 | Module(Module), | ||
220 | Function(Function), | ||
221 | Adt(Adt), | ||
222 | // Can't be directly declared, but can be imported. | ||
223 | Variant(Variant), | ||
224 | Const(Const), | ||
225 | Static(Static), | ||
226 | Trait(Trait), | ||
227 | TypeAlias(TypeAlias), | ||
228 | BuiltinType(BuiltinType), | ||
229 | } | ||
230 | impl_from!( | ||
231 | Module, | ||
232 | Function, | ||
233 | Adt(Struct, Enum, Union), | ||
234 | Variant, | ||
235 | Const, | ||
236 | Static, | ||
237 | Trait, | ||
238 | TypeAlias, | ||
239 | BuiltinType | ||
240 | for ModuleDef | ||
241 | ); | ||
242 | |||
243 | impl From<VariantDef> for ModuleDef { | ||
244 | fn from(var: VariantDef) -> Self { | ||
245 | match var { | ||
246 | VariantDef::Struct(t) => Adt::from(t).into(), | ||
247 | VariantDef::Union(t) => Adt::from(t).into(), | ||
248 | VariantDef::Variant(t) => t.into(), | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | impl ModuleDef { | ||
254 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
255 | match self { | ||
256 | ModuleDef::Module(it) => it.parent(db), | ||
257 | ModuleDef::Function(it) => Some(it.module(db)), | ||
258 | ModuleDef::Adt(it) => Some(it.module(db)), | ||
259 | ModuleDef::Variant(it) => Some(it.module(db)), | ||
260 | ModuleDef::Const(it) => Some(it.module(db)), | ||
261 | ModuleDef::Static(it) => Some(it.module(db)), | ||
262 | ModuleDef::Trait(it) => Some(it.module(db)), | ||
263 | ModuleDef::TypeAlias(it) => Some(it.module(db)), | ||
264 | ModuleDef::BuiltinType(_) => None, | ||
265 | } | ||
266 | } | ||
267 | |||
268 | pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option<String> { | ||
269 | let mut segments = Vec::new(); | ||
270 | segments.push(self.name(db)?.to_string()); | ||
271 | for m in self.module(db)?.path_to_root(db) { | ||
272 | segments.extend(m.name(db).map(|it| it.to_string())) | ||
273 | } | ||
274 | segments.reverse(); | ||
275 | Some(segments.join("::")) | ||
276 | } | ||
277 | |||
278 | pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> { | ||
279 | let module = match self { | ||
280 | ModuleDef::Module(it) => it.parent(db)?, | ||
281 | ModuleDef::Function(it) => return Some(it.visibility(db)), | ||
282 | ModuleDef::Adt(it) => it.module(db), | ||
283 | ModuleDef::Variant(it) => { | ||
284 | let parent = it.parent_enum(db); | ||
285 | let module = it.module(db); | ||
286 | return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent))); | ||
287 | } | ||
288 | ModuleDef::Const(it) => return Some(it.visibility(db)), | ||
289 | ModuleDef::Static(it) => it.module(db), | ||
290 | ModuleDef::Trait(it) => it.module(db), | ||
291 | ModuleDef::TypeAlias(it) => return Some(it.visibility(db)), | ||
292 | ModuleDef::BuiltinType(_) => return None, | ||
293 | }; | ||
294 | |||
295 | module.visibility_of(db, self) | ||
296 | } | ||
297 | |||
298 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
299 | match self { | ||
300 | ModuleDef::Adt(it) => Some(it.name(db)), | ||
301 | ModuleDef::Trait(it) => Some(it.name(db)), | ||
302 | ModuleDef::Function(it) => Some(it.name(db)), | ||
303 | ModuleDef::Variant(it) => Some(it.name(db)), | ||
304 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | ||
305 | ModuleDef::Module(it) => it.name(db), | ||
306 | ModuleDef::Const(it) => it.name(db), | ||
307 | ModuleDef::Static(it) => it.name(db), | ||
308 | |||
309 | ModuleDef::BuiltinType(it) => Some(it.name()), | ||
310 | } | ||
311 | } | ||
312 | |||
313 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
314 | let id = match self { | ||
315 | ModuleDef::Adt(it) => match it { | ||
316 | Adt::Struct(it) => it.id.into(), | ||
317 | Adt::Enum(it) => it.id.into(), | ||
318 | Adt::Union(it) => it.id.into(), | ||
319 | }, | ||
320 | ModuleDef::Trait(it) => it.id.into(), | ||
321 | ModuleDef::Function(it) => it.id.into(), | ||
322 | ModuleDef::TypeAlias(it) => it.id.into(), | ||
323 | ModuleDef::Module(it) => it.id.into(), | ||
324 | ModuleDef::Const(it) => it.id.into(), | ||
325 | ModuleDef::Static(it) => it.id.into(), | ||
326 | _ => return, | ||
327 | }; | ||
328 | |||
329 | let module = match self.module(db) { | ||
330 | Some(it) => it, | ||
331 | None => return, | ||
332 | }; | ||
333 | |||
334 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | ||
335 | } | ||
336 | } | ||
337 | |||
338 | impl Module { | ||
339 | /// Name of this module. | ||
340 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
341 | let def_map = self.id.def_map(db.upcast()); | ||
342 | let parent = def_map[self.id.local_id].parent?; | ||
343 | def_map[parent].children.iter().find_map(|(name, module_id)| { | ||
344 | if *module_id == self.id.local_id { | ||
345 | Some(name.clone()) | ||
346 | } else { | ||
347 | None | ||
348 | } | ||
349 | }) | ||
350 | } | ||
351 | |||
352 | /// Returns the crate this module is part of. | ||
353 | pub fn krate(self) -> Crate { | ||
354 | Crate { id: self.id.krate() } | ||
355 | } | ||
356 | |||
357 | /// Topmost parent of this module. Every module has a `crate_root`, but some | ||
358 | /// might be missing `krate`. This can happen if a module's file is not included | ||
359 | /// in the module tree of any target in `Cargo.toml`. | ||
360 | pub fn crate_root(self, db: &dyn HirDatabase) -> Module { | ||
361 | let def_map = db.crate_def_map(self.id.krate()); | ||
362 | Module { id: def_map.module_id(def_map.root()) } | ||
363 | } | ||
364 | |||
365 | /// Iterates over all child modules. | ||
366 | pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { | ||
367 | let def_map = self.id.def_map(db.upcast()); | ||
368 | let children = def_map[self.id.local_id] | ||
369 | .children | ||
370 | .iter() | ||
371 | .map(|(_, module_id)| Module { id: def_map.module_id(*module_id) }) | ||
372 | .collect::<Vec<_>>(); | ||
373 | children.into_iter() | ||
374 | } | ||
375 | |||
376 | /// Finds a parent module. | ||
377 | pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { | ||
378 | // FIXME: handle block expressions as modules (their parent is in a different DefMap) | ||
379 | let def_map = self.id.def_map(db.upcast()); | ||
380 | let parent_id = def_map[self.id.local_id].parent?; | ||
381 | Some(Module { id: def_map.module_id(parent_id) }) | ||
382 | } | ||
383 | |||
384 | pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> { | ||
385 | let mut res = vec![self]; | ||
386 | let mut curr = self; | ||
387 | while let Some(next) = curr.parent(db) { | ||
388 | res.push(next); | ||
389 | curr = next | ||
390 | } | ||
391 | res | ||
392 | } | ||
393 | |||
394 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
395 | pub fn scope( | ||
396 | self, | ||
397 | db: &dyn HirDatabase, | ||
398 | visible_from: Option<Module>, | ||
399 | ) -> Vec<(Name, ScopeDef)> { | ||
400 | self.id.def_map(db.upcast())[self.id.local_id] | ||
401 | .scope | ||
402 | .entries() | ||
403 | .filter_map(|(name, def)| { | ||
404 | if let Some(m) = visible_from { | ||
405 | let filtered = | ||
406 | def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id)); | ||
407 | if filtered.is_none() && !def.is_none() { | ||
408 | None | ||
409 | } else { | ||
410 | Some((name, filtered)) | ||
411 | } | ||
412 | } else { | ||
413 | Some((name, def)) | ||
414 | } | ||
415 | }) | ||
416 | .flat_map(|(name, def)| { | ||
417 | ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) | ||
418 | }) | ||
419 | .collect() | ||
420 | } | ||
421 | |||
422 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | ||
423 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | ||
424 | } | ||
425 | |||
426 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
427 | let _p = profile::span("Module::diagnostics").detail(|| { | ||
428 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | ||
429 | }); | ||
430 | let def_map = self.id.def_map(db.upcast()); | ||
431 | def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); | ||
432 | for decl in self.declarations(db) { | ||
433 | match decl { | ||
434 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | ||
435 | crate::ModuleDef::Module(m) => { | ||
436 | // Only add diagnostics from inline modules | ||
437 | if def_map[m.id.local_id].origin.is_inline() { | ||
438 | m.diagnostics(db, sink) | ||
439 | } | ||
440 | } | ||
441 | _ => { | ||
442 | decl.diagnostics(db, sink); | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | for impl_def in self.impl_defs(db) { | ||
448 | for item in impl_def.items(db) { | ||
449 | if let AssocItem::Function(f) = item { | ||
450 | f.diagnostics(db, sink); | ||
451 | } | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { | ||
457 | let def_map = self.id.def_map(db.upcast()); | ||
458 | def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() | ||
459 | } | ||
460 | |||
461 | pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { | ||
462 | let def_map = self.id.def_map(db.upcast()); | ||
463 | def_map[self.id.local_id].scope.impls().map(Impl::from).collect() | ||
464 | } | ||
465 | |||
466 | /// Finds a path that can be used to refer to the given item from within | ||
467 | /// this module, if possible. | ||
468 | pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> { | ||
469 | hir_def::find_path::find_path(db, item.into(), self.into()) | ||
470 | } | ||
471 | |||
472 | /// Finds a path that can be used to refer to the given item from within | ||
473 | /// this module, if possible. This is used for returning import paths for use-statements. | ||
474 | pub fn find_use_path_prefixed( | ||
475 | self, | ||
476 | db: &dyn DefDatabase, | ||
477 | item: impl Into<ItemInNs>, | ||
478 | prefix_kind: PrefixKind, | ||
479 | ) -> Option<ModPath> { | ||
480 | hir_def::find_path::find_path_prefixed(db, item.into(), self.into(), prefix_kind) | ||
481 | } | ||
482 | } | ||
483 | |||
484 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
485 | pub struct Field { | ||
486 | pub(crate) parent: VariantDef, | ||
487 | pub(crate) id: LocalFieldId, | ||
488 | } | ||
489 | |||
490 | #[derive(Debug, PartialEq, Eq)] | ||
491 | pub enum FieldSource { | ||
492 | Named(ast::RecordField), | ||
493 | Pos(ast::TupleField), | ||
494 | } | ||
495 | |||
496 | impl Field { | ||
497 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
498 | self.parent.variant_data(db).fields()[self.id].name.clone() | ||
499 | } | ||
500 | |||
501 | /// Returns the type as in the signature of the struct (i.e., with | ||
502 | /// placeholder types for type parameters). This is good for showing | ||
503 | /// signature help, but not so good to actually get the type of the field | ||
504 | /// when you actually have a variable of the struct. | ||
505 | pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type { | ||
506 | let var_id = self.parent.into(); | ||
507 | let generic_def_id: GenericDefId = match self.parent { | ||
508 | VariantDef::Struct(it) => it.id.into(), | ||
509 | VariantDef::Union(it) => it.id.into(), | ||
510 | VariantDef::Variant(it) => it.parent.id.into(), | ||
511 | }; | ||
512 | let substs = Substs::type_params(db, generic_def_id); | ||
513 | let ty = db.field_types(var_id)[self.id].clone().subst(&substs); | ||
514 | Type::new(db, self.parent.module(db).id.krate(), var_id, ty) | ||
515 | } | ||
516 | |||
517 | pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { | ||
518 | self.parent | ||
519 | } | ||
520 | } | ||
521 | |||
522 | impl HasVisibility for Field { | ||
523 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
524 | let variant_data = self.parent.variant_data(db); | ||
525 | let visibility = &variant_data.fields()[self.id].visibility; | ||
526 | let parent_id: hir_def::VariantId = self.parent.into(); | ||
527 | visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast())) | ||
528 | } | ||
529 | } | ||
530 | |||
531 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
532 | pub struct Struct { | ||
533 | pub(crate) id: StructId, | ||
534 | } | ||
535 | |||
536 | impl Struct { | ||
537 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
538 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
539 | } | ||
540 | |||
541 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
542 | Some(self.module(db).krate()) | ||
543 | } | ||
544 | |||
545 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
546 | db.struct_data(self.id).name.clone() | ||
547 | } | ||
548 | |||
549 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
550 | db.struct_data(self.id) | ||
551 | .variant_data | ||
552 | .fields() | ||
553 | .iter() | ||
554 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
555 | .collect() | ||
556 | } | ||
557 | |||
558 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
559 | Type::from_def( | ||
560 | db, | ||
561 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
562 | self.id, | ||
563 | ) | ||
564 | } | ||
565 | |||
566 | pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { | ||
567 | db.struct_data(self.id).repr.clone() | ||
568 | } | ||
569 | |||
570 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
571 | self.variant_data(db).kind() | ||
572 | } | ||
573 | |||
574 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
575 | db.struct_data(self.id).variant_data.clone() | ||
576 | } | ||
577 | } | ||
578 | |||
579 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
580 | pub struct Union { | ||
581 | pub(crate) id: UnionId, | ||
582 | } | ||
583 | |||
584 | impl Union { | ||
585 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
586 | db.union_data(self.id).name.clone() | ||
587 | } | ||
588 | |||
589 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
590 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
591 | } | ||
592 | |||
593 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
594 | Type::from_def( | ||
595 | db, | ||
596 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
597 | self.id, | ||
598 | ) | ||
599 | } | ||
600 | |||
601 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
602 | db.union_data(self.id) | ||
603 | .variant_data | ||
604 | .fields() | ||
605 | .iter() | ||
606 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
607 | .collect() | ||
608 | } | ||
609 | |||
610 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
611 | db.union_data(self.id).variant_data.clone() | ||
612 | } | ||
613 | } | ||
614 | |||
615 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
616 | pub struct Enum { | ||
617 | pub(crate) id: EnumId, | ||
618 | } | ||
619 | |||
620 | impl Enum { | ||
621 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
622 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
623 | } | ||
624 | |||
625 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
626 | Some(self.module(db).krate()) | ||
627 | } | ||
628 | |||
629 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
630 | db.enum_data(self.id).name.clone() | ||
631 | } | ||
632 | |||
633 | pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> { | ||
634 | db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect() | ||
635 | } | ||
636 | |||
637 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
638 | Type::from_def( | ||
639 | db, | ||
640 | self.id.lookup(db.upcast()).container.module(db.upcast()).krate(), | ||
641 | self.id, | ||
642 | ) | ||
643 | } | ||
644 | } | ||
645 | |||
646 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
647 | pub struct Variant { | ||
648 | pub(crate) parent: Enum, | ||
649 | pub(crate) id: LocalEnumVariantId, | ||
650 | } | ||
651 | |||
652 | impl Variant { | ||
653 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
654 | self.parent.module(db) | ||
655 | } | ||
656 | pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { | ||
657 | self.parent | ||
658 | } | ||
659 | |||
660 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
661 | db.enum_data(self.parent.id).variants[self.id].name.clone() | ||
662 | } | ||
663 | |||
664 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
665 | self.variant_data(db) | ||
666 | .fields() | ||
667 | .iter() | ||
668 | .map(|(id, _)| Field { parent: self.into(), id }) | ||
669 | .collect() | ||
670 | } | ||
671 | |||
672 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
673 | self.variant_data(db).kind() | ||
674 | } | ||
675 | |||
676 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
677 | db.enum_data(self.parent.id).variants[self.id].variant_data.clone() | ||
678 | } | ||
679 | } | ||
680 | |||
681 | /// A Data Type | ||
682 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
683 | pub enum Adt { | ||
684 | Struct(Struct), | ||
685 | Union(Union), | ||
686 | Enum(Enum), | ||
687 | } | ||
688 | impl_from!(Struct, Union, Enum for Adt); | ||
689 | |||
690 | impl Adt { | ||
691 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
692 | let subst = db.generic_defaults(self.into()); | ||
693 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
694 | } | ||
695 | |||
696 | /// Turns this ADT into a type. Any type parameters of the ADT will be | ||
697 | /// turned into unknown types, which is good for e.g. finding the most | ||
698 | /// general set of completions, but will not look very nice when printed. | ||
699 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
700 | let id = AdtId::from(self); | ||
701 | Type::from_def(db, id.module(db.upcast()).krate(), id) | ||
702 | } | ||
703 | |||
704 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
705 | match self { | ||
706 | Adt::Struct(s) => s.module(db), | ||
707 | Adt::Union(s) => s.module(db), | ||
708 | Adt::Enum(e) => e.module(db), | ||
709 | } | ||
710 | } | ||
711 | |||
712 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
713 | Some(self.module(db).krate()) | ||
714 | } | ||
715 | |||
716 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
717 | match self { | ||
718 | Adt::Struct(s) => s.name(db), | ||
719 | Adt::Union(u) => u.name(db), | ||
720 | Adt::Enum(e) => e.name(db), | ||
721 | } | ||
722 | } | ||
723 | } | ||
724 | |||
725 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
726 | pub enum VariantDef { | ||
727 | Struct(Struct), | ||
728 | Union(Union), | ||
729 | Variant(Variant), | ||
730 | } | ||
731 | impl_from!(Struct, Union, Variant for VariantDef); | ||
732 | |||
733 | impl VariantDef { | ||
734 | pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { | ||
735 | match self { | ||
736 | VariantDef::Struct(it) => it.fields(db), | ||
737 | VariantDef::Union(it) => it.fields(db), | ||
738 | VariantDef::Variant(it) => it.fields(db), | ||
739 | } | ||
740 | } | ||
741 | |||
742 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
743 | match self { | ||
744 | VariantDef::Struct(it) => it.module(db), | ||
745 | VariantDef::Union(it) => it.module(db), | ||
746 | VariantDef::Variant(it) => it.module(db), | ||
747 | } | ||
748 | } | ||
749 | |||
750 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | ||
751 | match self { | ||
752 | VariantDef::Struct(s) => s.name(db), | ||
753 | VariantDef::Union(u) => u.name(db), | ||
754 | VariantDef::Variant(e) => e.name(db), | ||
755 | } | ||
756 | } | ||
757 | |||
758 | pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | ||
759 | match self { | ||
760 | VariantDef::Struct(it) => it.variant_data(db), | ||
761 | VariantDef::Union(it) => it.variant_data(db), | ||
762 | VariantDef::Variant(it) => it.variant_data(db), | ||
763 | } | ||
764 | } | ||
765 | } | ||
766 | |||
767 | /// The defs which have a body. | ||
768 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
769 | pub enum DefWithBody { | ||
770 | Function(Function), | ||
771 | Static(Static), | ||
772 | Const(Const), | ||
773 | } | ||
774 | impl_from!(Function, Const, Static for DefWithBody); | ||
775 | |||
776 | impl DefWithBody { | ||
777 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
778 | match self { | ||
779 | DefWithBody::Const(c) => c.module(db), | ||
780 | DefWithBody::Function(f) => f.module(db), | ||
781 | DefWithBody::Static(s) => s.module(db), | ||
782 | } | ||
783 | } | ||
784 | |||
785 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
786 | match self { | ||
787 | DefWithBody::Function(f) => Some(f.name(db)), | ||
788 | DefWithBody::Static(s) => s.name(db), | ||
789 | DefWithBody::Const(c) => c.name(db), | ||
790 | } | ||
791 | } | ||
792 | } | ||
793 | |||
794 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
795 | pub struct Function { | ||
796 | pub(crate) id: FunctionId, | ||
797 | } | ||
798 | |||
799 | impl Function { | ||
800 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
801 | self.id.lookup(db.upcast()).module(db.upcast()).into() | ||
802 | } | ||
803 | |||
804 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
805 | Some(self.module(db).krate()) | ||
806 | } | ||
807 | |||
808 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
809 | db.function_data(self.id).name.clone() | ||
810 | } | ||
811 | |||
812 | /// Get this function's return type | ||
813 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
814 | let resolver = self.id.resolver(db.upcast()); | ||
815 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
816 | let ret_type = &db.function_data(self.id).ret_type; | ||
817 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
818 | let ty = Ty::from_hir_ext(&ctx, ret_type).0; | ||
819 | Type::new_with_resolver_inner(db, krate, &resolver, ty) | ||
820 | } | ||
821 | |||
822 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | ||
823 | if !db.function_data(self.id).has_self_param { | ||
824 | return None; | ||
825 | } | ||
826 | Some(SelfParam { func: self.id }) | ||
827 | } | ||
828 | |||
829 | pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> { | ||
830 | let resolver = self.id.resolver(db.upcast()); | ||
831 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
832 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
833 | let environment = TraitEnvironment::lower(db, &resolver); | ||
834 | db.function_data(self.id) | ||
835 | .params | ||
836 | .iter() | ||
837 | .map(|type_ref| { | ||
838 | let ty = Type { | ||
839 | krate, | ||
840 | ty: InEnvironment { | ||
841 | value: Ty::from_hir_ext(&ctx, type_ref).0, | ||
842 | environment: environment.clone(), | ||
843 | }, | ||
844 | }; | ||
845 | Param { ty } | ||
846 | }) | ||
847 | .collect() | ||
848 | } | ||
849 | pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> { | ||
850 | if self.self_param(db).is_none() { | ||
851 | return None; | ||
852 | } | ||
853 | let mut res = self.assoc_fn_params(db); | ||
854 | res.remove(0); | ||
855 | Some(res) | ||
856 | } | ||
857 | |||
858 | pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { | ||
859 | db.function_data(self.id).is_unsafe | ||
860 | } | ||
861 | |||
862 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | ||
863 | let krate = self.module(db).id.krate(); | ||
864 | hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); | ||
865 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | ||
866 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | ||
867 | } | ||
868 | |||
869 | /// Whether this function declaration has a definition. | ||
870 | /// | ||
871 | /// This is false in the case of required (not provided) trait methods. | ||
872 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | ||
873 | db.function_data(self.id).has_body | ||
874 | } | ||
875 | |||
876 | /// A textual representation of the HIR of this function for debugging purposes. | ||
877 | pub fn debug_hir(self, db: &dyn HirDatabase) -> String { | ||
878 | let body = db.body(self.id.into()); | ||
879 | |||
880 | let mut result = String::new(); | ||
881 | format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); | ||
882 | for (id, expr) in body.exprs.iter() { | ||
883 | format_to!(result, "{:?}: {:?}\n", id, expr); | ||
884 | } | ||
885 | |||
886 | result | ||
887 | } | ||
888 | } | ||
889 | |||
890 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. | ||
891 | pub enum Access { | ||
892 | Shared, | ||
893 | Exclusive, | ||
894 | Owned, | ||
895 | } | ||
896 | |||
897 | impl From<hir_ty::Mutability> for Access { | ||
898 | fn from(mutability: hir_ty::Mutability) -> Access { | ||
899 | match mutability { | ||
900 | hir_ty::Mutability::Not => Access::Shared, | ||
901 | hir_ty::Mutability::Mut => Access::Exclusive, | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | |||
906 | #[derive(Debug)] | ||
907 | pub struct Param { | ||
908 | ty: Type, | ||
909 | } | ||
910 | |||
911 | impl Param { | ||
912 | pub fn ty(&self) -> &Type { | ||
913 | &self.ty | ||
914 | } | ||
915 | } | ||
916 | |||
917 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
918 | pub struct SelfParam { | ||
919 | func: FunctionId, | ||
920 | } | ||
921 | |||
922 | impl SelfParam { | ||
923 | pub fn access(self, db: &dyn HirDatabase) -> Access { | ||
924 | let func_data = db.function_data(self.func); | ||
925 | func_data | ||
926 | .params | ||
927 | .first() | ||
928 | .map(|param| match *param { | ||
929 | TypeRef::Reference(.., mutability) => match mutability { | ||
930 | hir_def::type_ref::Mutability::Shared => Access::Shared, | ||
931 | hir_def::type_ref::Mutability::Mut => Access::Exclusive, | ||
932 | }, | ||
933 | _ => Access::Owned, | ||
934 | }) | ||
935 | .unwrap_or(Access::Owned) | ||
936 | } | ||
937 | } | ||
938 | |||
939 | impl HasVisibility for Function { | ||
940 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
941 | let function_data = db.function_data(self.id); | ||
942 | let visibility = &function_data.visibility; | ||
943 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
944 | } | ||
945 | } | ||
946 | |||
947 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
948 | pub struct Const { | ||
949 | pub(crate) id: ConstId, | ||
950 | } | ||
951 | |||
952 | impl Const { | ||
953 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
954 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
955 | } | ||
956 | |||
957 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
958 | Some(self.module(db).krate()) | ||
959 | } | ||
960 | |||
961 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
962 | db.const_data(self.id).name.clone() | ||
963 | } | ||
964 | } | ||
965 | |||
966 | impl HasVisibility for Const { | ||
967 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
968 | let function_data = db.const_data(self.id); | ||
969 | let visibility = &function_data.visibility; | ||
970 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
971 | } | ||
972 | } | ||
973 | |||
974 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
975 | pub struct Static { | ||
976 | pub(crate) id: StaticId, | ||
977 | } | ||
978 | |||
979 | impl Static { | ||
980 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
981 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
982 | } | ||
983 | |||
984 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
985 | Some(self.module(db).krate()) | ||
986 | } | ||
987 | |||
988 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
989 | db.static_data(self.id).name.clone() | ||
990 | } | ||
991 | |||
992 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
993 | db.static_data(self.id).mutable | ||
994 | } | ||
995 | } | ||
996 | |||
997 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
998 | pub struct Trait { | ||
999 | pub(crate) id: TraitId, | ||
1000 | } | ||
1001 | |||
1002 | impl Trait { | ||
1003 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1004 | Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) } | ||
1005 | } | ||
1006 | |||
1007 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1008 | db.trait_data(self.id).name.clone() | ||
1009 | } | ||
1010 | |||
1011 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
1012 | db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() | ||
1013 | } | ||
1014 | |||
1015 | pub fn is_auto(self, db: &dyn HirDatabase) -> bool { | ||
1016 | db.trait_data(self.id).auto | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1021 | pub struct TypeAlias { | ||
1022 | pub(crate) id: TypeAliasId, | ||
1023 | } | ||
1024 | |||
1025 | impl TypeAlias { | ||
1026 | pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { | ||
1027 | let subst = db.generic_defaults(self.id.into()); | ||
1028 | subst.iter().any(|ty| &ty.value == &Ty::Unknown) | ||
1029 | } | ||
1030 | |||
1031 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1032 | Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } | ||
1033 | } | ||
1034 | |||
1035 | pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> { | ||
1036 | Some(self.module(db).krate()) | ||
1037 | } | ||
1038 | |||
1039 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
1040 | db.type_alias_data(self.id).type_ref.clone() | ||
1041 | } | ||
1042 | |||
1043 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1044 | Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id) | ||
1045 | } | ||
1046 | |||
1047 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1048 | db.type_alias_data(self.id).name.clone() | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | impl HasVisibility for TypeAlias { | ||
1053 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
1054 | let function_data = db.type_alias_data(self.id); | ||
1055 | let visibility = &function_data.visibility; | ||
1056 | visibility.resolve(db.upcast(), &self.id.resolver(db.upcast())) | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1061 | pub struct BuiltinType { | ||
1062 | pub(crate) inner: hir_def::builtin_type::BuiltinType, | ||
1063 | } | ||
1064 | |||
1065 | impl BuiltinType { | ||
1066 | pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { | ||
1067 | let resolver = module.id.resolver(db.upcast()); | ||
1068 | Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner)) | ||
1069 | .expect("crate not present in resolver") | ||
1070 | } | ||
1071 | |||
1072 | pub fn name(self) -> Name { | ||
1073 | self.inner.as_name() | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1078 | pub struct MacroDef { | ||
1079 | pub(crate) id: MacroDefId, | ||
1080 | } | ||
1081 | |||
1082 | impl MacroDef { | ||
1083 | /// FIXME: right now, this just returns the root module of the crate that | ||
1084 | /// defines this macro. The reasons for this is that macros are expanded | ||
1085 | /// early, in `hir_expand`, where modules simply do not exist yet. | ||
1086 | pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { | ||
1087 | let krate = self.id.krate; | ||
1088 | let def_map = db.crate_def_map(krate); | ||
1089 | let module_id = def_map.root(); | ||
1090 | Some(Module { id: def_map.module_id(module_id) }) | ||
1091 | } | ||
1092 | |||
1093 | /// XXX: this parses the file | ||
1094 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1095 | self.source(db)?.value.name().map(|it| it.as_name()) | ||
1096 | } | ||
1097 | |||
1098 | /// Indicate it is a proc-macro | ||
1099 | pub fn is_proc_macro(&self) -> bool { | ||
1100 | matches!(self.id.kind, MacroDefKind::ProcMacro(_)) | ||
1101 | } | ||
1102 | |||
1103 | /// Indicate it is a derive macro | ||
1104 | pub fn is_derive_macro(&self) -> bool { | ||
1105 | matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_)) | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | /// Invariant: `inner.as_assoc_item(db).is_some()` | ||
1110 | /// We do not actively enforce this invariant. | ||
1111 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
1112 | pub enum AssocItem { | ||
1113 | Function(Function), | ||
1114 | Const(Const), | ||
1115 | TypeAlias(TypeAlias), | ||
1116 | } | ||
1117 | #[derive(Debug)] | ||
1118 | pub enum AssocItemContainer { | ||
1119 | Trait(Trait), | ||
1120 | Impl(Impl), | ||
1121 | } | ||
1122 | pub trait AsAssocItem { | ||
1123 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>; | ||
1124 | } | ||
1125 | |||
1126 | impl AsAssocItem for Function { | ||
1127 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1128 | as_assoc_item(db, AssocItem::Function, self.id) | ||
1129 | } | ||
1130 | } | ||
1131 | impl AsAssocItem for Const { | ||
1132 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1133 | as_assoc_item(db, AssocItem::Const, self.id) | ||
1134 | } | ||
1135 | } | ||
1136 | impl AsAssocItem for TypeAlias { | ||
1137 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1138 | as_assoc_item(db, AssocItem::TypeAlias, self.id) | ||
1139 | } | ||
1140 | } | ||
1141 | impl AsAssocItem for ModuleDef { | ||
1142 | fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> { | ||
1143 | match self { | ||
1144 | ModuleDef::Function(it) => it.as_assoc_item(db), | ||
1145 | ModuleDef::Const(it) => it.as_assoc_item(db), | ||
1146 | ModuleDef::TypeAlias(it) => it.as_assoc_item(db), | ||
1147 | _ => None, | ||
1148 | } | ||
1149 | } | ||
1150 | } | ||
1151 | fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> | ||
1152 | where | ||
1153 | ID: Lookup<Data = AssocItemLoc<AST>>, | ||
1154 | DEF: From<ID>, | ||
1155 | CTOR: FnOnce(DEF) -> AssocItem, | ||
1156 | AST: ItemTreeNode, | ||
1157 | { | ||
1158 | match id.lookup(db.upcast()).container { | ||
1159 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | ||
1160 | AssocContainerId::ContainerId(_) => None, | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | impl AssocItem { | ||
1165 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1166 | match self { | ||
1167 | AssocItem::Function(it) => Some(it.name(db)), | ||
1168 | AssocItem::Const(it) => it.name(db), | ||
1169 | AssocItem::TypeAlias(it) => Some(it.name(db)), | ||
1170 | } | ||
1171 | } | ||
1172 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1173 | match self { | ||
1174 | AssocItem::Function(f) => f.module(db), | ||
1175 | AssocItem::Const(c) => c.module(db), | ||
1176 | AssocItem::TypeAlias(t) => t.module(db), | ||
1177 | } | ||
1178 | } | ||
1179 | pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer { | ||
1180 | let container = match self { | ||
1181 | AssocItem::Function(it) => it.id.lookup(db.upcast()).container, | ||
1182 | AssocItem::Const(it) => it.id.lookup(db.upcast()).container, | ||
1183 | AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container, | ||
1184 | }; | ||
1185 | match container { | ||
1186 | AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()), | ||
1187 | AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()), | ||
1188 | AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1193 | match self.container(db) { | ||
1194 | AssocItemContainer::Trait(t) => Some(t), | ||
1195 | _ => None, | ||
1196 | } | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | impl HasVisibility for AssocItem { | ||
1201 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility { | ||
1202 | match self { | ||
1203 | AssocItem::Function(f) => f.visibility(db), | ||
1204 | AssocItem::Const(c) => c.visibility(db), | ||
1205 | AssocItem::TypeAlias(t) => t.visibility(db), | ||
1206 | } | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | ||
1211 | pub enum GenericDef { | ||
1212 | Function(Function), | ||
1213 | Adt(Adt), | ||
1214 | Trait(Trait), | ||
1215 | TypeAlias(TypeAlias), | ||
1216 | Impl(Impl), | ||
1217 | // enum variants cannot have generics themselves, but their parent enums | ||
1218 | // can, and this makes some code easier to write | ||
1219 | Variant(Variant), | ||
1220 | // consts can have type parameters from their parents (i.e. associated consts of traits) | ||
1221 | Const(Const), | ||
1222 | } | ||
1223 | impl_from!( | ||
1224 | Function, | ||
1225 | Adt(Struct, Enum, Union), | ||
1226 | Trait, | ||
1227 | TypeAlias, | ||
1228 | Impl, | ||
1229 | Variant, | ||
1230 | Const | ||
1231 | for GenericDef | ||
1232 | ); | ||
1233 | |||
1234 | impl GenericDef { | ||
1235 | pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { | ||
1236 | let generics = db.generic_params(self.into()); | ||
1237 | let ty_params = generics | ||
1238 | .types | ||
1239 | .iter() | ||
1240 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1241 | .map(GenericParam::TypeParam); | ||
1242 | let lt_params = generics | ||
1243 | .lifetimes | ||
1244 | .iter() | ||
1245 | .map(|(local_id, _)| LifetimeParam { | ||
1246 | id: LifetimeParamId { parent: self.into(), local_id }, | ||
1247 | }) | ||
1248 | .map(GenericParam::LifetimeParam); | ||
1249 | let const_params = generics | ||
1250 | .consts | ||
1251 | .iter() | ||
1252 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1253 | .map(GenericParam::ConstParam); | ||
1254 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1255 | } | ||
1256 | |||
1257 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | ||
1258 | let generics = db.generic_params(self.into()); | ||
1259 | generics | ||
1260 | .types | ||
1261 | .iter() | ||
1262 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
1263 | .collect() | ||
1264 | } | ||
1265 | } | ||
1266 | |||
1267 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1268 | pub struct Local { | ||
1269 | pub(crate) parent: DefWithBodyId, | ||
1270 | pub(crate) pat_id: PatId, | ||
1271 | } | ||
1272 | |||
1273 | impl Local { | ||
1274 | pub fn is_param(self, db: &dyn HirDatabase) -> bool { | ||
1275 | let src = self.source(db); | ||
1276 | match src.value { | ||
1277 | Either::Left(bind_pat) => { | ||
1278 | bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind())) | ||
1279 | } | ||
1280 | Either::Right(_self_param) => true, | ||
1281 | } | ||
1282 | } | ||
1283 | |||
1284 | // FIXME: why is this an option? It shouldn't be? | ||
1285 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
1286 | let body = db.body(self.parent.into()); | ||
1287 | match &body[self.pat_id] { | ||
1288 | Pat::Bind { name, .. } => Some(name.clone()), | ||
1289 | _ => None, | ||
1290 | } | ||
1291 | } | ||
1292 | |||
1293 | pub fn is_self(self, db: &dyn HirDatabase) -> bool { | ||
1294 | self.name(db) == Some(name![self]) | ||
1295 | } | ||
1296 | |||
1297 | pub fn is_mut(self, db: &dyn HirDatabase) -> bool { | ||
1298 | let body = db.body(self.parent.into()); | ||
1299 | match &body[self.pat_id] { | ||
1300 | Pat::Bind { mode, .. } => match mode { | ||
1301 | BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, | ||
1302 | _ => false, | ||
1303 | }, | ||
1304 | _ => false, | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1309 | self.parent.into() | ||
1310 | } | ||
1311 | |||
1312 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1313 | self.parent(db).module(db) | ||
1314 | } | ||
1315 | |||
1316 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1317 | let def = DefWithBodyId::from(self.parent); | ||
1318 | let infer = db.infer(def); | ||
1319 | let ty = infer[self.pat_id].clone(); | ||
1320 | let krate = def.module(db.upcast()).krate(); | ||
1321 | Type::new(db, krate, def, ty) | ||
1322 | } | ||
1323 | |||
1324 | pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::SelfParam>> { | ||
1325 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1326 | let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... | ||
1327 | let root = src.file_syntax(db.upcast()); | ||
1328 | src.map(|ast| { | ||
1329 | ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) | ||
1330 | }) | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1335 | pub struct Label { | ||
1336 | pub(crate) parent: DefWithBodyId, | ||
1337 | pub(crate) label_id: LabelId, | ||
1338 | } | ||
1339 | |||
1340 | impl Label { | ||
1341 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1342 | self.parent(db).module(db) | ||
1343 | } | ||
1344 | |||
1345 | pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { | ||
1346 | self.parent.into() | ||
1347 | } | ||
1348 | |||
1349 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1350 | let body = db.body(self.parent.into()); | ||
1351 | body[self.label_id].name.clone() | ||
1352 | } | ||
1353 | |||
1354 | pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> { | ||
1355 | let (_body, source_map) = db.body_with_source_map(self.parent.into()); | ||
1356 | let src = source_map.label_syntax(self.label_id); | ||
1357 | let root = src.file_syntax(db.upcast()); | ||
1358 | src.map(|ast| ast.to_node(&root)) | ||
1359 | } | ||
1360 | } | ||
1361 | |||
1362 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1363 | pub enum GenericParam { | ||
1364 | TypeParam(TypeParam), | ||
1365 | LifetimeParam(LifetimeParam), | ||
1366 | ConstParam(ConstParam), | ||
1367 | } | ||
1368 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); | ||
1369 | |||
1370 | impl GenericParam { | ||
1371 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1372 | match self { | ||
1373 | GenericParam::TypeParam(it) => it.module(db), | ||
1374 | GenericParam::LifetimeParam(it) => it.module(db), | ||
1375 | GenericParam::ConstParam(it) => it.module(db), | ||
1376 | } | ||
1377 | } | ||
1378 | |||
1379 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1380 | match self { | ||
1381 | GenericParam::TypeParam(it) => it.name(db), | ||
1382 | GenericParam::LifetimeParam(it) => it.name(db), | ||
1383 | GenericParam::ConstParam(it) => it.name(db), | ||
1384 | } | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1389 | pub struct TypeParam { | ||
1390 | pub(crate) id: TypeParamId, | ||
1391 | } | ||
1392 | |||
1393 | impl TypeParam { | ||
1394 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1395 | let params = db.generic_params(self.id.parent); | ||
1396 | params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing) | ||
1397 | } | ||
1398 | |||
1399 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1400 | self.id.parent.module(db.upcast()).into() | ||
1401 | } | ||
1402 | |||
1403 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1404 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1405 | let krate = self.id.parent.module(db.upcast()).krate(); | ||
1406 | let ty = Ty::Placeholder(self.id); | ||
1407 | Type::new_with_resolver_inner(db, krate, &resolver, ty) | ||
1408 | } | ||
1409 | |||
1410 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1411 | db.generic_predicates_for_param(self.id) | ||
1412 | .into_iter() | ||
1413 | .filter_map(|pred| match &pred.value { | ||
1414 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1415 | Some(Trait::from(trait_ref.trait_)) | ||
1416 | } | ||
1417 | _ => None, | ||
1418 | }) | ||
1419 | .collect() | ||
1420 | } | ||
1421 | |||
1422 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | ||
1423 | let params = db.generic_defaults(self.id.parent); | ||
1424 | let local_idx = hir_ty::param_idx(db, self.id)?; | ||
1425 | let resolver = self.id.parent.resolver(db.upcast()); | ||
1426 | let krate = self.id.parent.module(db.upcast()).krate(); | ||
1427 | let ty = params.get(local_idx)?.clone(); | ||
1428 | let subst = Substs::type_params(db, self.id.parent); | ||
1429 | let ty = ty.subst(&subst.prefix(local_idx)); | ||
1430 | Some(Type::new_with_resolver_inner(db, krate, &resolver, ty)) | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | impl HirDisplay for TypeParam { | ||
1435 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1436 | write!(f, "{}", self.name(f.db))?; | ||
1437 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1438 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1439 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1440 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1441 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; | ||
1442 | } | ||
1443 | Ok(()) | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1447 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1448 | pub struct LifetimeParam { | ||
1449 | pub(crate) id: LifetimeParamId, | ||
1450 | } | ||
1451 | |||
1452 | impl LifetimeParam { | ||
1453 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1454 | let params = db.generic_params(self.id.parent); | ||
1455 | params.lifetimes[self.id.local_id].name.clone() | ||
1456 | } | ||
1457 | |||
1458 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1459 | self.id.parent.module(db.upcast()).into() | ||
1460 | } | ||
1461 | |||
1462 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1463 | self.id.parent.into() | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1468 | pub struct ConstParam { | ||
1469 | pub(crate) id: ConstParamId, | ||
1470 | } | ||
1471 | |||
1472 | impl ConstParam { | ||
1473 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1474 | let params = db.generic_params(self.id.parent); | ||
1475 | params.consts[self.id.local_id].name.clone() | ||
1476 | } | ||
1477 | |||
1478 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1479 | self.id.parent.module(db.upcast()).into() | ||
1480 | } | ||
1481 | |||
1482 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1483 | self.id.parent.into() | ||
1484 | } | ||
1485 | |||
1486 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1487 | let def = self.id.parent; | ||
1488 | let krate = def.module(db.upcast()).krate(); | ||
1489 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1494 | pub struct Impl { | ||
1495 | pub(crate) id: ImplId, | ||
1496 | } | ||
1497 | |||
1498 | impl Impl { | ||
1499 | pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<Impl> { | ||
1500 | let inherent = db.inherent_impls_in_crate(krate.id); | ||
1501 | let trait_ = db.trait_impls_in_crate(krate.id); | ||
1502 | |||
1503 | inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() | ||
1504 | } | ||
1505 | pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<Impl> { | ||
1506 | let impls = db.trait_impls_in_crate(krate.id); | ||
1507 | impls.for_trait(trait_.id).map(Self::from).collect() | ||
1508 | } | ||
1509 | |||
1510 | // FIXME: the return type is wrong. This should be a hir version of | ||
1511 | // `TraitRef` (ie, resolved `TypeRef`). | ||
1512 | pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { | ||
1513 | db.impl_data(self.id).target_trait.clone() | ||
1514 | } | ||
1515 | |||
1516 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { | ||
1517 | let impl_data = db.impl_data(self.id); | ||
1518 | let resolver = self.id.resolver(db.upcast()); | ||
1519 | let krate = self.id.lookup(db.upcast()).container.module(db.upcast()).krate(); | ||
1520 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
1521 | let ty = Ty::from_hir(&ctx, &impl_data.target_type); | ||
1522 | Type::new_with_resolver_inner(db, krate, &resolver, ty) | ||
1523 | } | ||
1524 | |||
1525 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { | ||
1526 | db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() | ||
1527 | } | ||
1528 | |||
1529 | pub fn is_negative(self, db: &dyn HirDatabase) -> bool { | ||
1530 | db.impl_data(self.id).is_negative | ||
1531 | } | ||
1532 | |||
1533 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1534 | self.id.lookup(db.upcast()).container.module(db.upcast()).into() | ||
1535 | } | ||
1536 | |||
1537 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { | ||
1538 | Crate { id: self.module(db).id.krate() } | ||
1539 | } | ||
1540 | |||
1541 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | ||
1542 | let src = self.source(db)?; | ||
1543 | let item = src.file_id.is_builtin_derive(db.upcast())?; | ||
1544 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | ||
1545 | |||
1546 | // FIXME: handle `cfg_attr` | ||
1547 | let attr = item | ||
1548 | .value | ||
1549 | .attrs() | ||
1550 | .filter_map(|it| { | ||
1551 | let path = ModPath::from_src(it.path()?, &hygenic)?; | ||
1552 | if path.as_ident()?.to_string() == "derive" { | ||
1553 | Some(it) | ||
1554 | } else { | ||
1555 | None | ||
1556 | } | ||
1557 | }) | ||
1558 | .last()?; | ||
1559 | |||
1560 | Some(item.with_value(attr)) | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
1565 | pub struct Type { | ||
1566 | krate: CrateId, | ||
1567 | ty: InEnvironment<Ty>, | ||
1568 | } | ||
1569 | |||
1570 | impl Type { | ||
1571 | pub(crate) fn new_with_resolver( | ||
1572 | db: &dyn HirDatabase, | ||
1573 | resolver: &Resolver, | ||
1574 | ty: Ty, | ||
1575 | ) -> Option<Type> { | ||
1576 | let krate = resolver.krate()?; | ||
1577 | Some(Type::new_with_resolver_inner(db, krate, resolver, ty)) | ||
1578 | } | ||
1579 | pub(crate) fn new_with_resolver_inner( | ||
1580 | db: &dyn HirDatabase, | ||
1581 | krate: CrateId, | ||
1582 | resolver: &Resolver, | ||
1583 | ty: Ty, | ||
1584 | ) -> Type { | ||
1585 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1586 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1587 | } | ||
1588 | |||
1589 | fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { | ||
1590 | let resolver = lexical_env.resolver(db.upcast()); | ||
1591 | let environment = TraitEnvironment::lower(db, &resolver); | ||
1592 | Type { krate, ty: InEnvironment { value: ty, environment } } | ||
1593 | } | ||
1594 | |||
1595 | fn from_def( | ||
1596 | db: &dyn HirDatabase, | ||
1597 | krate: CrateId, | ||
1598 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | ||
1599 | ) -> Type { | ||
1600 | let substs = Substs::build_for_def(db, def).fill_with_unknown().build(); | ||
1601 | let ty = db.ty(def.into()).subst(&substs); | ||
1602 | Type::new(db, krate, def, ty) | ||
1603 | } | ||
1604 | |||
1605 | pub fn is_unit(&self) -> bool { | ||
1606 | matches!(self.ty.value, Ty::Tuple(0, ..)) | ||
1607 | } | ||
1608 | pub fn is_bool(&self) -> bool { | ||
1609 | matches!(self.ty.value, Ty::Scalar(Scalar::Bool)) | ||
1610 | } | ||
1611 | |||
1612 | pub fn is_mutable_reference(&self) -> bool { | ||
1613 | matches!(self.ty.value, Ty::Ref(hir_ty::Mutability::Mut, ..)) | ||
1614 | } | ||
1615 | |||
1616 | pub fn remove_ref(&self) -> Option<Type> { | ||
1617 | if let Ty::Ref(.., substs) = &self.ty.value { | ||
1618 | Some(self.derived(substs[0].clone())) | ||
1619 | } else { | ||
1620 | None | ||
1621 | } | ||
1622 | } | ||
1623 | |||
1624 | pub fn is_unknown(&self) -> bool { | ||
1625 | matches!(self.ty.value, Ty::Unknown) | ||
1626 | } | ||
1627 | |||
1628 | /// Checks that particular type `ty` implements `std::future::Future`. | ||
1629 | /// This function is used in `.await` syntax completion. | ||
1630 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { | ||
1631 | // No special case for the type of async block, since Chalk can figure it out. | ||
1632 | |||
1633 | let krate = self.krate; | ||
1634 | |||
1635 | let std_future_trait = | ||
1636 | db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait()); | ||
1637 | let std_future_trait = match std_future_trait { | ||
1638 | Some(it) => it, | ||
1639 | None => return false, | ||
1640 | }; | ||
1641 | |||
1642 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1643 | method_resolution::implements_trait( | ||
1644 | &canonical_ty, | ||
1645 | db, | ||
1646 | self.ty.environment.clone(), | ||
1647 | krate, | ||
1648 | std_future_trait, | ||
1649 | ) | ||
1650 | } | ||
1651 | |||
1652 | /// Checks that particular type `ty` implements `std::ops::FnOnce`. | ||
1653 | /// | ||
1654 | /// This function can be used to check if a particular type is callable, since FnOnce is a | ||
1655 | /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce. | ||
1656 | pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool { | ||
1657 | let krate = self.krate; | ||
1658 | |||
1659 | let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) { | ||
1660 | Some(it) => it, | ||
1661 | None => return false, | ||
1662 | }; | ||
1663 | |||
1664 | let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1665 | method_resolution::implements_trait_unique( | ||
1666 | &canonical_ty, | ||
1667 | db, | ||
1668 | self.ty.environment.clone(), | ||
1669 | krate, | ||
1670 | fnonce_trait, | ||
1671 | ) | ||
1672 | } | ||
1673 | |||
1674 | pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { | ||
1675 | let trait_ref = hir_ty::TraitRef { | ||
1676 | trait_: trait_.id, | ||
1677 | substs: Substs::build_for_def(db, trait_.id) | ||
1678 | .push(self.ty.value.clone()) | ||
1679 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1680 | .build(), | ||
1681 | }; | ||
1682 | |||
1683 | let goal = Canonical { | ||
1684 | value: hir_ty::InEnvironment::new( | ||
1685 | self.ty.environment.clone(), | ||
1686 | hir_ty::Obligation::Trait(trait_ref), | ||
1687 | ), | ||
1688 | kinds: Arc::new([]), | ||
1689 | }; | ||
1690 | |||
1691 | db.trait_solve(self.krate, goal).is_some() | ||
1692 | } | ||
1693 | |||
1694 | pub fn normalize_trait_assoc_type( | ||
1695 | &self, | ||
1696 | db: &dyn HirDatabase, | ||
1697 | trait_: Trait, | ||
1698 | args: &[Type], | ||
1699 | alias: TypeAlias, | ||
1700 | ) -> Option<Type> { | ||
1701 | let subst = Substs::build_for_def(db, trait_.id) | ||
1702 | .push(self.ty.value.clone()) | ||
1703 | .fill(args.iter().map(|t| t.ty.value.clone())) | ||
1704 | .build(); | ||
1705 | let predicate = ProjectionPredicate { | ||
1706 | projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst }, | ||
1707 | ty: Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)), | ||
1708 | }; | ||
1709 | let goal = Canonical { | ||
1710 | value: InEnvironment::new( | ||
1711 | self.ty.environment.clone(), | ||
1712 | Obligation::Projection(predicate), | ||
1713 | ), | ||
1714 | kinds: Arc::new([TyVariableKind::General]), | ||
1715 | }; | ||
1716 | |||
1717 | match db.trait_solve(self.krate, goal)? { | ||
1718 | Solution::Unique(SolutionVariables(subst)) => { | ||
1719 | subst.value.first().map(|ty| self.derived(ty.clone())) | ||
1720 | } | ||
1721 | Solution::Ambig(_) => None, | ||
1722 | } | ||
1723 | } | ||
1724 | |||
1725 | pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { | ||
1726 | let lang_item = db.lang_item(self.krate, SmolStr::new("copy")); | ||
1727 | let copy_trait = match lang_item { | ||
1728 | Some(LangItemTarget::TraitId(it)) => it, | ||
1729 | _ => return false, | ||
1730 | }; | ||
1731 | self.impls_trait(db, copy_trait.into(), &[]) | ||
1732 | } | ||
1733 | |||
1734 | pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { | ||
1735 | let def = match self.ty.value { | ||
1736 | Ty::FnDef(def, _) => Some(def), | ||
1737 | _ => None, | ||
1738 | }; | ||
1739 | |||
1740 | let sig = self.ty.value.callable_sig(db)?; | ||
1741 | Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) | ||
1742 | } | ||
1743 | |||
1744 | pub fn is_closure(&self) -> bool { | ||
1745 | matches!(&self.ty.value, Ty::Closure { .. }) | ||
1746 | } | ||
1747 | |||
1748 | pub fn is_fn(&self) -> bool { | ||
1749 | matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. }) | ||
1750 | } | ||
1751 | |||
1752 | pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { | ||
1753 | let adt_id = match self.ty.value { | ||
1754 | Ty::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, | ||
1755 | _ => return false, | ||
1756 | }; | ||
1757 | |||
1758 | let adt = adt_id.into(); | ||
1759 | match adt { | ||
1760 | Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), | ||
1761 | _ => false, | ||
1762 | } | ||
1763 | } | ||
1764 | |||
1765 | pub fn is_raw_ptr(&self) -> bool { | ||
1766 | matches!(&self.ty.value, Ty::Raw(..)) | ||
1767 | } | ||
1768 | |||
1769 | pub fn contains_unknown(&self) -> bool { | ||
1770 | return go(&self.ty.value); | ||
1771 | |||
1772 | fn go(ty: &Ty) -> bool { | ||
1773 | match ty { | ||
1774 | Ty::Unknown => true, | ||
1775 | _ => ty.substs().map_or(false, |substs| substs.iter().any(go)), | ||
1776 | } | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { | ||
1781 | let (variant_id, substs) = match self.ty.value { | ||
1782 | Ty::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), | ||
1783 | Ty::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), | ||
1784 | _ => return Vec::new(), | ||
1785 | }; | ||
1786 | |||
1787 | db.field_types(variant_id) | ||
1788 | .iter() | ||
1789 | .map(|(local_id, ty)| { | ||
1790 | let def = Field { parent: variant_id.into(), id: local_id }; | ||
1791 | let ty = ty.clone().subst(substs); | ||
1792 | (def, self.derived(ty)) | ||
1793 | }) | ||
1794 | .collect() | ||
1795 | } | ||
1796 | |||
1797 | pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> { | ||
1798 | if let Ty::Tuple(_, substs) = &self.ty.value { | ||
1799 | substs.iter().map(|ty| self.derived(ty.clone())).collect() | ||
1800 | } else { | ||
1801 | Vec::new() | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { | ||
1806 | // There should be no inference vars in types passed here | ||
1807 | // FIXME check that? | ||
1808 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1809 | let environment = self.ty.environment.clone(); | ||
1810 | let ty = InEnvironment { value: canonical, environment }; | ||
1811 | autoderef(db, Some(self.krate), ty) | ||
1812 | .map(|canonical| canonical.value) | ||
1813 | .map(move |ty| self.derived(ty)) | ||
1814 | } | ||
1815 | |||
1816 | // This would be nicer if it just returned an iterator, but that runs into | ||
1817 | // lifetime problems, because we need to borrow temp `CrateImplDefs`. | ||
1818 | pub fn iterate_assoc_items<T>( | ||
1819 | self, | ||
1820 | db: &dyn HirDatabase, | ||
1821 | krate: Crate, | ||
1822 | mut callback: impl FnMut(AssocItem) -> Option<T>, | ||
1823 | ) -> Option<T> { | ||
1824 | for krate in self.ty.value.def_crates(db, krate.id)? { | ||
1825 | let impls = db.inherent_impls_in_crate(krate); | ||
1826 | |||
1827 | for impl_def in impls.for_self_ty(&self.ty.value) { | ||
1828 | for &item in db.impl_data(*impl_def).items.iter() { | ||
1829 | if let Some(result) = callback(item.into()) { | ||
1830 | return Some(result); | ||
1831 | } | ||
1832 | } | ||
1833 | } | ||
1834 | } | ||
1835 | None | ||
1836 | } | ||
1837 | |||
1838 | pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { | ||
1839 | self.ty | ||
1840 | .value | ||
1841 | .strip_references() | ||
1842 | .substs() | ||
1843 | .into_iter() | ||
1844 | .flat_map(|substs| substs.iter()) | ||
1845 | .map(move |ty| self.derived(ty.clone())) | ||
1846 | } | ||
1847 | |||
1848 | pub fn iterate_method_candidates<T>( | ||
1849 | &self, | ||
1850 | db: &dyn HirDatabase, | ||
1851 | krate: Crate, | ||
1852 | traits_in_scope: &FxHashSet<TraitId>, | ||
1853 | name: Option<&Name>, | ||
1854 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | ||
1855 | ) -> Option<T> { | ||
1856 | // There should be no inference vars in types passed here | ||
1857 | // FIXME check that? | ||
1858 | // FIXME replace Unknown by bound vars here | ||
1859 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1860 | |||
1861 | let env = self.ty.environment.clone(); | ||
1862 | let krate = krate.id; | ||
1863 | |||
1864 | method_resolution::iterate_method_candidates( | ||
1865 | &canonical, | ||
1866 | db, | ||
1867 | env, | ||
1868 | krate, | ||
1869 | traits_in_scope, | ||
1870 | name, | ||
1871 | method_resolution::LookupMode::MethodCall, | ||
1872 | |ty, it| match it { | ||
1873 | AssocItemId::FunctionId(f) => callback(ty, f.into()), | ||
1874 | _ => None, | ||
1875 | }, | ||
1876 | ) | ||
1877 | } | ||
1878 | |||
1879 | pub fn iterate_path_candidates<T>( | ||
1880 | &self, | ||
1881 | db: &dyn HirDatabase, | ||
1882 | krate: Crate, | ||
1883 | traits_in_scope: &FxHashSet<TraitId>, | ||
1884 | name: Option<&Name>, | ||
1885 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
1886 | ) -> Option<T> { | ||
1887 | // There should be no inference vars in types passed here | ||
1888 | // FIXME check that? | ||
1889 | // FIXME replace Unknown by bound vars here | ||
1890 | let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; | ||
1891 | |||
1892 | let env = self.ty.environment.clone(); | ||
1893 | let krate = krate.id; | ||
1894 | |||
1895 | method_resolution::iterate_method_candidates( | ||
1896 | &canonical, | ||
1897 | db, | ||
1898 | env, | ||
1899 | krate, | ||
1900 | traits_in_scope, | ||
1901 | name, | ||
1902 | method_resolution::LookupMode::Path, | ||
1903 | |ty, it| callback(ty, it.into()), | ||
1904 | ) | ||
1905 | } | ||
1906 | |||
1907 | pub fn as_adt(&self) -> Option<Adt> { | ||
1908 | let (adt, _subst) = self.ty.value.as_adt()?; | ||
1909 | Some(adt.into()) | ||
1910 | } | ||
1911 | |||
1912 | pub fn as_dyn_trait(&self) -> Option<Trait> { | ||
1913 | self.ty.value.dyn_trait().map(Into::into) | ||
1914 | } | ||
1915 | |||
1916 | pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { | ||
1917 | self.ty.value.impl_trait_bounds(db).map(|it| { | ||
1918 | it.into_iter() | ||
1919 | .filter_map(|pred| match pred { | ||
1920 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1921 | Some(Trait::from(trait_ref.trait_)) | ||
1922 | } | ||
1923 | _ => None, | ||
1924 | }) | ||
1925 | .collect() | ||
1926 | }) | ||
1927 | } | ||
1928 | |||
1929 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1930 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | ||
1931 | } | ||
1932 | |||
1933 | // FIXME: provide required accessors such that it becomes implementable from outside. | ||
1934 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | ||
1935 | let rref = other.remove_ref(); | ||
1936 | self.ty.value.equals_ctor(rref.as_ref().map_or(&other.ty.value, |it| &it.ty.value)) | ||
1937 | } | ||
1938 | |||
1939 | fn derived(&self, ty: Ty) -> Type { | ||
1940 | Type { | ||
1941 | krate: self.krate, | ||
1942 | ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, | ||
1943 | } | ||
1944 | } | ||
1945 | |||
1946 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { | ||
1947 | // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. | ||
1948 | // We need a different order here. | ||
1949 | |||
1950 | fn walk_substs( | ||
1951 | db: &dyn HirDatabase, | ||
1952 | type_: &Type, | ||
1953 | substs: &Substs, | ||
1954 | cb: &mut impl FnMut(Type), | ||
1955 | ) { | ||
1956 | for ty in substs.iter() { | ||
1957 | walk_type(db, &type_.derived(ty.clone()), cb); | ||
1958 | } | ||
1959 | } | ||
1960 | |||
1961 | fn walk_bounds( | ||
1962 | db: &dyn HirDatabase, | ||
1963 | type_: &Type, | ||
1964 | bounds: &[GenericPredicate], | ||
1965 | cb: &mut impl FnMut(Type), | ||
1966 | ) { | ||
1967 | for pred in bounds { | ||
1968 | match pred { | ||
1969 | GenericPredicate::Implemented(trait_ref) => { | ||
1970 | cb(type_.clone()); | ||
1971 | walk_substs(db, type_, &trait_ref.substs, cb); | ||
1972 | } | ||
1973 | _ => (), | ||
1974 | } | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1978 | fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { | ||
1979 | let ty = type_.ty.value.strip_references(); | ||
1980 | match ty { | ||
1981 | Ty::Adt(..) => { | ||
1982 | cb(type_.derived(ty.clone())); | ||
1983 | } | ||
1984 | Ty::AssociatedType(..) => { | ||
1985 | if let Some(_) = ty.associated_type_parent_trait(db) { | ||
1986 | cb(type_.derived(ty.clone())); | ||
1987 | } | ||
1988 | } | ||
1989 | Ty::OpaqueType(..) => { | ||
1990 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1991 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1992 | } | ||
1993 | } | ||
1994 | Ty::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
1995 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1996 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1997 | } | ||
1998 | |||
1999 | walk_substs(db, type_, &opaque_ty.parameters, cb); | ||
2000 | } | ||
2001 | Ty::Placeholder(_) => { | ||
2002 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
2003 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
2004 | } | ||
2005 | } | ||
2006 | Ty::Dyn(bounds) => { | ||
2007 | walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); | ||
2008 | } | ||
2009 | |||
2010 | _ => {} | ||
2011 | } | ||
2012 | if let Some(substs) = ty.substs() { | ||
2013 | walk_substs(db, type_, &substs, cb); | ||
2014 | } | ||
2015 | } | ||
2016 | |||
2017 | walk_type(db, self, &mut cb); | ||
2018 | } | ||
2019 | } | ||
2020 | |||
2021 | impl HirDisplay for Type { | ||
2022 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
2023 | self.ty.value.hir_fmt(f) | ||
2024 | } | ||
2025 | } | ||
2026 | |||
2027 | // FIXME: closures | ||
2028 | #[derive(Debug)] | ||
2029 | pub struct Callable { | ||
2030 | ty: Type, | ||
2031 | sig: CallableSig, | ||
2032 | def: Option<CallableDefId>, | ||
2033 | pub(crate) is_bound_method: bool, | ||
2034 | } | ||
2035 | |||
2036 | pub enum CallableKind { | ||
2037 | Function(Function), | ||
2038 | TupleStruct(Struct), | ||
2039 | TupleEnumVariant(Variant), | ||
2040 | Closure, | ||
2041 | } | ||
2042 | |||
2043 | impl Callable { | ||
2044 | pub fn kind(&self) -> CallableKind { | ||
2045 | match self.def { | ||
2046 | Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), | ||
2047 | Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), | ||
2048 | Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), | ||
2049 | None => CallableKind::Closure, | ||
2050 | } | ||
2051 | } | ||
2052 | pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { | ||
2053 | let func = match self.def { | ||
2054 | Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it, | ||
2055 | _ => return None, | ||
2056 | }; | ||
2057 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2058 | let param_list = src.value.param_list()?; | ||
2059 | param_list.self_param() | ||
2060 | } | ||
2061 | pub fn n_params(&self) -> usize { | ||
2062 | self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } | ||
2063 | } | ||
2064 | pub fn params( | ||
2065 | &self, | ||
2066 | db: &dyn HirDatabase, | ||
2067 | ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> { | ||
2068 | let types = self | ||
2069 | .sig | ||
2070 | .params() | ||
2071 | .iter() | ||
2072 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
2073 | .map(|ty| self.ty.derived(ty.clone())); | ||
2074 | let patterns = match self.def { | ||
2075 | Some(CallableDefId::FunctionId(func)) => { | ||
2076 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
2077 | src.value.param_list().map(|param_list| { | ||
2078 | param_list | ||
2079 | .self_param() | ||
2080 | .map(|it| Some(Either::Left(it))) | ||
2081 | .filter(|_| !self.is_bound_method) | ||
2082 | .into_iter() | ||
2083 | .chain(param_list.params().map(|it| it.pat().map(Either::Right))) | ||
2084 | }) | ||
2085 | } | ||
2086 | _ => None, | ||
2087 | }; | ||
2088 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
2089 | } | ||
2090 | pub fn return_type(&self) -> Type { | ||
2091 | self.ty.derived(self.sig.ret().clone()) | ||
2092 | } | ||
2093 | } | ||
2094 | |||
2095 | /// For IDE only | ||
2096 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
2097 | pub enum ScopeDef { | ||
2098 | ModuleDef(ModuleDef), | ||
2099 | MacroDef(MacroDef), | ||
2100 | GenericParam(GenericParam), | ||
2101 | ImplSelfType(Impl), | ||
2102 | AdtSelfType(Adt), | ||
2103 | Local(Local), | ||
2104 | Unknown, | ||
2105 | } | ||
2106 | |||
2107 | impl ScopeDef { | ||
2108 | pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> { | ||
2109 | let mut items = ArrayVec::new(); | ||
2110 | |||
2111 | match (def.take_types(), def.take_values()) { | ||
2112 | (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), | ||
2113 | (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), | ||
2114 | (Some(m1), Some(m2)) => { | ||
2115 | // Some items, like unit structs and enum variants, are | ||
2116 | // returned as both a type and a value. Here we want | ||
2117 | // to de-duplicate them. | ||
2118 | if m1 != m2 { | ||
2119 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2120 | items.push(ScopeDef::ModuleDef(m2.into())); | ||
2121 | } else { | ||
2122 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
2123 | } | ||
2124 | } | ||
2125 | (None, None) => {} | ||
2126 | }; | ||
2127 | |||
2128 | if let Some(macro_def_id) = def.take_macros() { | ||
2129 | items.push(ScopeDef::MacroDef(macro_def_id.into())); | ||
2130 | } | ||
2131 | |||
2132 | if items.is_empty() { | ||
2133 | items.push(ScopeDef::Unknown); | ||
2134 | } | ||
2135 | |||
2136 | items | ||
2137 | } | ||
2138 | } | ||
2139 | |||
2140 | impl From<ItemInNs> for ScopeDef { | ||
2141 | fn from(item: ItemInNs) -> Self { | ||
2142 | match item { | ||
2143 | ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), | ||
2144 | ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), | ||
2145 | ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), | ||
2146 | } | ||
2147 | } | ||
2148 | } | ||
2149 | |||
2150 | pub trait HasVisibility { | ||
2151 | fn visibility(&self, db: &dyn HirDatabase) -> Visibility; | ||
2152 | fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool { | ||
2153 | let vis = self.visibility(db); | ||
2154 | vis.is_visible_from(db.upcast(), module.id) | ||
2155 | } | ||
2156 | } | ||
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 144851f83..945638cc5 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -20,12 +20,11 @@ use syntax::{ | |||
20 | }; | 20 | }; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | code_model::Access, | ||
24 | db::HirDatabase, | 23 | db::HirDatabase, |
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 24 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 25 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
27 | AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label, | 26 | Access, AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, |
28 | LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, | 27 | Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, |
29 | TypeAlias, TypeParam, VariantDef, | 28 | TypeAlias, TypeParam, VariantDef, |
30 | }; | 29 | }; |
31 | 30 | ||
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 64ce4add1..d546512cb 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -28,9 +28,8 @@ use syntax::{ | |||
28 | }; | 28 | }; |
29 | 29 | ||
30 | use crate::{ | 30 | use crate::{ |
31 | code_model::BuiltinType, db::HirDatabase, semantics::PathResolution, Adt, Const, Field, | 31 | db::HirDatabase, semantics::PathResolution, Adt, BuiltinType, Const, Field, Function, Local, |
32 | Function, Local, MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, | 32 | MacroDef, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Variant, |
33 | Variant, | ||
34 | }; | 33 | }; |
35 | use base_db::CrateId; | 34 | use base_db::CrateId; |
36 | 35 | ||
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 535221294..2f07b6d01 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -10,6 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = "1.1" | ||
13 | log = "0.4.8" | 14 | log = "0.4.8" |
14 | once_cell = "1.3.1" | 15 | once_cell = "1.3.1" |
15 | rustc-hash = "1.1.0" | 16 | rustc-hash = "1.1.0" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 24ffa6c3a..b716d5f6e 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -13,7 +13,6 @@ use syntax::{ | |||
13 | ast::{self, AstNode, AttrsOwner}, | 13 | ast::{self, AstNode, AttrsOwner}, |
14 | match_ast, AstToken, SmolStr, SyntaxNode, | 14 | match_ast, AstToken, SmolStr, SyntaxNode, |
15 | }; | 15 | }; |
16 | use test_utils::mark; | ||
17 | use tt::Subtree; | 16 | use tt::Subtree; |
18 | 17 | ||
19 | use crate::{ | 18 | use crate::{ |
@@ -177,7 +176,7 @@ impl RawAttrs { | |||
177 | if cfg_options.check(&cfg) == Some(false) { | 176 | if cfg_options.check(&cfg) == Some(false) { |
178 | None | 177 | None |
179 | } else { | 178 | } else { |
180 | mark::hit!(cfg_attr_active); | 179 | cov_mark::hit!(cfg_attr_active); |
181 | 180 | ||
182 | let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; | 181 | let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; |
183 | let hygiene = Hygiene::new_unhygienic(); // FIXME | 182 | let hygiene = Hygiene::new_unhygienic(); // FIXME |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 16e1bac40..b1a3fe1cb 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -20,7 +20,6 @@ use la_arena::{Arena, ArenaMap}; | |||
20 | use profile::Count; | 20 | use profile::Count; |
21 | use rustc_hash::FxHashMap; | 21 | use rustc_hash::FxHashMap; |
22 | use syntax::{ast, AstNode, AstPtr}; | 22 | use syntax::{ast, AstNode, AstPtr}; |
23 | use test_utils::mark; | ||
24 | 23 | ||
25 | pub(crate) use lower::LowerCtx; | 24 | pub(crate) use lower::LowerCtx; |
26 | 25 | ||
@@ -105,7 +104,7 @@ impl Expander { | |||
105 | macro_call: ast::MacroCall, | 104 | macro_call: ast::MacroCall, |
106 | ) -> ExpandResult<Option<(Mark, T)>> { | 105 | ) -> ExpandResult<Option<(Mark, T)>> { |
107 | if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { | 106 | if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { |
108 | mark::hit!(your_stack_belongs_to_me); | 107 | cov_mark::hit!(your_stack_belongs_to_me); |
109 | return ExpandResult::str_err("reached recursion limit during macro expansion".into()); | 108 | return ExpandResult::str_err("reached recursion limit during macro expansion".into()); |
110 | } | 109 | } |
111 | 110 | ||
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 40beb2f7a..d4abe819d 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -19,7 +19,6 @@ use syntax::{ | |||
19 | }, | 19 | }, |
20 | AstNode, AstPtr, SyntaxNodePtr, | 20 | AstNode, AstPtr, SyntaxNodePtr, |
21 | }; | 21 | }; |
22 | use test_utils::mark; | ||
23 | 22 | ||
24 | use crate::{ | 23 | use crate::{ |
25 | adt::StructKind, | 24 | adt::StructKind, |
@@ -286,7 +285,7 @@ impl ExprCollector<'_> { | |||
286 | None => self.collect_expr_opt(condition.expr()), | 285 | None => self.collect_expr_opt(condition.expr()), |
287 | // if let -- desugar to match | 286 | // if let -- desugar to match |
288 | Some(pat) => { | 287 | Some(pat) => { |
289 | mark::hit!(infer_resolve_while_let); | 288 | cov_mark::hit!(infer_resolve_while_let); |
290 | let pat = self.collect_pat(pat); | 289 | let pat = self.collect_pat(pat); |
291 | let match_expr = self.collect_expr_opt(condition.expr()); | 290 | let match_expr = self.collect_expr_opt(condition.expr()); |
292 | let placeholder_pat = self.missing_pat(); | 291 | let placeholder_pat = self.missing_pat(); |
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 210b4a617..1bbb54fc6 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs | |||
@@ -186,7 +186,7 @@ mod tests { | |||
186 | use base_db::{fixture::WithFixture, FileId, SourceDatabase}; | 186 | use base_db::{fixture::WithFixture, FileId, SourceDatabase}; |
187 | use hir_expand::{name::AsName, InFile}; | 187 | use hir_expand::{name::AsName, InFile}; |
188 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 188 | use syntax::{algo::find_node_at_offset, ast, AstNode}; |
189 | use test_utils::{assert_eq_text, extract_offset, mark}; | 189 | use test_utils::{assert_eq_text, extract_offset}; |
190 | 190 | ||
191 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; | 191 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; |
192 | 192 | ||
@@ -454,7 +454,7 @@ fn foo() { | |||
454 | 454 | ||
455 | #[test] | 455 | #[test] |
456 | fn while_let_desugaring() { | 456 | fn while_let_desugaring() { |
457 | mark::check!(infer_resolve_while_let); | 457 | cov_mark::check!(infer_resolve_while_let); |
458 | do_check_local_name( | 458 | do_check_local_name( |
459 | r#" | 459 | r#" |
460 | fn test() { | 460 | fn test() { |
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index bb43569d7..991a32b15 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs | |||
@@ -2,7 +2,6 @@ mod block; | |||
2 | 2 | ||
3 | use base_db::{fixture::WithFixture, SourceDatabase}; | 3 | use base_db::{fixture::WithFixture, SourceDatabase}; |
4 | use expect_test::Expect; | 4 | use expect_test::Expect; |
5 | use test_utils::mark; | ||
6 | 5 | ||
7 | use crate::{test_db::TestDB, ModuleDefId}; | 6 | use crate::{test_db::TestDB, ModuleDefId}; |
8 | 7 | ||
@@ -48,7 +47,7 @@ fn check_at(ra_fixture: &str, expect: Expect) { | |||
48 | 47 | ||
49 | #[test] | 48 | #[test] |
50 | fn your_stack_belongs_to_me() { | 49 | fn your_stack_belongs_to_me() { |
51 | mark::check!(your_stack_belongs_to_me); | 50 | cov_mark::check!(your_stack_belongs_to_me); |
52 | lower( | 51 | lower( |
53 | " | 52 | " |
54 | macro_rules! n_nuple { | 53 | macro_rules! n_nuple { |
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs index 8bca72a17..3b6ba4cde 100644 --- a/crates/hir_def/src/body/tests/block.rs +++ b/crates/hir_def/src/body/tests/block.rs | |||
@@ -165,16 +165,16 @@ fn macro_resolve() { | |||
165 | check_at( | 165 | check_at( |
166 | r#" | 166 | r#" |
167 | //- /lib.rs crate:lib deps:core | 167 | //- /lib.rs crate:lib deps:core |
168 | use core::mark; | 168 | use core::cov_mark; |
169 | 169 | ||
170 | fn f() { | 170 | fn f() { |
171 | fn nested() { | 171 | fn nested() { |
172 | mark::hit!(Hit); | 172 | cov_mark::hit!(Hit); |
173 | $0 | 173 | $0 |
174 | } | 174 | } |
175 | } | 175 | } |
176 | //- /core.rs crate:core | 176 | //- /core.rs crate:core |
177 | pub mod mark { | 177 | pub mod cov_mark { |
178 | #[macro_export] | 178 | #[macro_export] |
179 | macro_rules! _hit { | 179 | macro_rules! _hit { |
180 | ($name:ident) => { | 180 | ($name:ident) => { |
@@ -193,8 +193,8 @@ pub mod mark { | |||
193 | nested: v | 193 | nested: v |
194 | 194 | ||
195 | crate | 195 | crate |
196 | cov_mark: t | ||
196 | f: v | 197 | f: v |
197 | mark: t | ||
198 | "#]], | 198 | "#]], |
199 | ); | 199 | ); |
200 | } | 200 | } |
@@ -264,7 +264,7 @@ fn main() { | |||
264 | fn underscore_import() { | 264 | fn underscore_import() { |
265 | // This used to panic, because the default (private) visibility inside block expressions would | 265 | // This used to panic, because the default (private) visibility inside block expressions would |
266 | // point into the containing `DefMap`, which visibilities should never be able to do. | 266 | // point into the containing `DefMap`, which visibilities should never be able to do. |
267 | mark::check!(adjust_vis_in_block_def_map); | 267 | cov_mark::check!(adjust_vis_in_block_def_map); |
268 | check_at( | 268 | check_at( |
269 | r#" | 269 | r#" |
270 | mod m { | 270 | mod m { |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index 3a98ffbaa..de08e2737 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -4,7 +4,6 @@ use std::iter; | |||
4 | 4 | ||
5 | use hir_expand::name::{known, AsName, Name}; | 5 | use hir_expand::name::{known, AsName, Name}; |
6 | use rustc_hash::FxHashSet; | 6 | use rustc_hash::FxHashSet; |
7 | use test_utils::mark; | ||
8 | 7 | ||
9 | use crate::nameres::DefMap; | 8 | use crate::nameres::DefMap; |
10 | use crate::{ | 9 | use crate::{ |
@@ -215,7 +214,7 @@ fn find_path_inner( | |||
215 | best_path_len - 1, | 214 | best_path_len - 1, |
216 | prefixed, | 215 | prefixed, |
217 | )?; | 216 | )?; |
218 | mark::hit!(partially_imported); | 217 | cov_mark::hit!(partially_imported); |
219 | path.push_segment(info.path.segments.last().unwrap().clone()); | 218 | path.push_segment(info.path.segments.last().unwrap().clone()); |
220 | Some(path) | 219 | Some(path) |
221 | }) | 220 | }) |
@@ -235,7 +234,7 @@ fn find_path_inner( | |||
235 | // that correctly (FIXME). | 234 | // that correctly (FIXME). |
236 | if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) { | 235 | if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) { |
237 | if item_module.def_map(db).block_id().is_some() && prefixed.is_some() { | 236 | if item_module.def_map(db).block_id().is_some() && prefixed.is_some() { |
238 | mark::hit!(prefixed_in_block_expression); | 237 | cov_mark::hit!(prefixed_in_block_expression); |
239 | prefixed = Some(PrefixKind::Plain); | 238 | prefixed = Some(PrefixKind::Plain); |
240 | } | 239 | } |
241 | } | 240 | } |
@@ -252,18 +251,18 @@ fn find_path_inner( | |||
252 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { | 251 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { |
253 | if old_path.starts_with_std() && new_path.can_start_with_std() { | 252 | if old_path.starts_with_std() && new_path.can_start_with_std() { |
254 | if prefer_no_std { | 253 | if prefer_no_std { |
255 | mark::hit!(prefer_no_std_paths); | 254 | cov_mark::hit!(prefer_no_std_paths); |
256 | new_path | 255 | new_path |
257 | } else { | 256 | } else { |
258 | mark::hit!(prefer_std_paths); | 257 | cov_mark::hit!(prefer_std_paths); |
259 | old_path | 258 | old_path |
260 | } | 259 | } |
261 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { | 260 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { |
262 | if prefer_no_std { | 261 | if prefer_no_std { |
263 | mark::hit!(prefer_no_std_paths); | 262 | cov_mark::hit!(prefer_no_std_paths); |
264 | old_path | 263 | old_path |
265 | } else { | 264 | } else { |
266 | mark::hit!(prefer_std_paths); | 265 | cov_mark::hit!(prefer_std_paths); |
267 | new_path | 266 | new_path |
268 | } | 267 | } |
269 | } else if new_path.len() < old_path.len() { | 268 | } else if new_path.len() < old_path.len() { |
@@ -364,7 +363,6 @@ mod tests { | |||
364 | use base_db::fixture::WithFixture; | 363 | use base_db::fixture::WithFixture; |
365 | use hir_expand::hygiene::Hygiene; | 364 | use hir_expand::hygiene::Hygiene; |
366 | use syntax::ast::AstNode; | 365 | use syntax::ast::AstNode; |
367 | use test_utils::mark; | ||
368 | 366 | ||
369 | use crate::test_db::TestDB; | 367 | use crate::test_db::TestDB; |
370 | 368 | ||
@@ -522,7 +520,7 @@ mod tests { | |||
522 | 520 | ||
523 | #[test] | 521 | #[test] |
524 | fn partially_imported() { | 522 | fn partially_imported() { |
525 | mark::check!(partially_imported); | 523 | cov_mark::check!(partially_imported); |
526 | // Tests that short paths are used even for external items, when parts of the path are | 524 | // Tests that short paths are used even for external items, when parts of the path are |
527 | // already in scope. | 525 | // already in scope. |
528 | let code = r#" | 526 | let code = r#" |
@@ -686,7 +684,7 @@ mod tests { | |||
686 | 684 | ||
687 | #[test] | 685 | #[test] |
688 | fn prefer_std_paths_over_alloc() { | 686 | fn prefer_std_paths_over_alloc() { |
689 | mark::check!(prefer_std_paths); | 687 | cov_mark::check!(prefer_std_paths); |
690 | let code = r#" | 688 | let code = r#" |
691 | //- /main.rs crate:main deps:alloc,std | 689 | //- /main.rs crate:main deps:alloc,std |
692 | $0 | 690 | $0 |
@@ -712,7 +710,7 @@ mod tests { | |||
712 | 710 | ||
713 | #[test] | 711 | #[test] |
714 | fn prefer_core_paths_over_std() { | 712 | fn prefer_core_paths_over_std() { |
715 | mark::check!(prefer_no_std_paths); | 713 | cov_mark::check!(prefer_no_std_paths); |
716 | let code = r#" | 714 | let code = r#" |
717 | //- /main.rs crate:main deps:core,std | 715 | //- /main.rs crate:main deps:core,std |
718 | #![no_std] | 716 | #![no_std] |
@@ -842,7 +840,7 @@ mod tests { | |||
842 | 840 | ||
843 | #[test] | 841 | #[test] |
844 | fn inner_items_from_inner_module() { | 842 | fn inner_items_from_inner_module() { |
845 | mark::check!(prefixed_in_block_expression); | 843 | cov_mark::check!(prefixed_in_block_expression); |
846 | check_found_path( | 844 | check_found_path( |
847 | r#" | 845 | r#" |
848 | fn main() { | 846 | fn main() { |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 0a3dc7956..369bc3350 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -8,7 +8,6 @@ use hir_expand::name::Name; | |||
8 | use indexmap::{map::Entry, IndexMap}; | 8 | use indexmap::{map::Entry, IndexMap}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use rustc_hash::{FxHashSet, FxHasher}; | 10 | use rustc_hash::{FxHashSet, FxHasher}; |
11 | use test_utils::mark; | ||
12 | 11 | ||
13 | use crate::{ | 12 | use crate::{ |
14 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, | 13 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, |
@@ -193,7 +192,7 @@ impl ImportMap { | |||
193 | // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` | 192 | // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` |
194 | // qualifier, ergo no need to store it for imports in import_map | 193 | // qualifier, ergo no need to store it for imports in import_map |
195 | AssocItemId::TypeAliasId(_) => { | 194 | AssocItemId::TypeAliasId(_) => { |
196 | mark::hit!(type_aliases_ignored); | 195 | cov_mark::hit!(type_aliases_ignored); |
197 | continue; | 196 | continue; |
198 | } | 197 | } |
199 | }; | 198 | }; |
@@ -388,7 +387,7 @@ pub fn search_dependencies<'a>( | |||
388 | db: &'a dyn DefDatabase, | 387 | db: &'a dyn DefDatabase, |
389 | krate: CrateId, | 388 | krate: CrateId, |
390 | query: Query, | 389 | query: Query, |
391 | ) -> Vec<ItemInNs> { | 390 | ) -> FxHashSet<ItemInNs> { |
392 | let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query)); | 391 | let _p = profile::span("search_dependencies").detail(|| format!("{:?}", query)); |
393 | 392 | ||
394 | let graph = db.crate_graph(); | 393 | let graph = db.crate_graph(); |
@@ -403,41 +402,42 @@ pub fn search_dependencies<'a>( | |||
403 | } | 402 | } |
404 | 403 | ||
405 | let mut stream = op.union(); | 404 | let mut stream = op.union(); |
406 | let mut res = Vec::new(); | 405 | |
406 | let mut all_indexed_values = FxHashSet::default(); | ||
407 | while let Some((_, indexed_values)) = stream.next() { | 407 | while let Some((_, indexed_values)) = stream.next() { |
408 | for indexed_value in indexed_values { | 408 | all_indexed_values.extend(indexed_values.iter().copied()); |
409 | let import_map = &import_maps[indexed_value.index]; | 409 | } |
410 | let importables = &import_map.importables[indexed_value.value as usize..]; | ||
411 | 410 | ||
412 | let common_importable_data = &import_map.map[&importables[0]]; | 411 | let mut res = FxHashSet::default(); |
413 | if !query.import_matches(common_importable_data, true) { | 412 | for indexed_value in all_indexed_values { |
414 | continue; | 413 | let import_map = &import_maps[indexed_value.index]; |
415 | } | 414 | let importables = &import_map.importables[indexed_value.value as usize..]; |
416 | 415 | ||
417 | // Path shared by the importable items in this group. | 416 | let common_importable_data = &import_map.map[&importables[0]]; |
418 | let common_importables_path_fst = fst_path(&common_importable_data.path); | 417 | if !query.import_matches(common_importable_data, true) { |
419 | // Add the items from this `ModPath` group. Those are all subsequent items in | 418 | continue; |
420 | // `importables` whose paths match `path`. | 419 | } |
421 | let iter = importables | 420 | |
422 | .iter() | 421 | // Path shared by the importable items in this group. |
423 | .copied() | 422 | let common_importables_path_fst = fst_path(&common_importable_data.path); |
424 | .take_while(|item| { | 423 | // Add the items from this `ModPath` group. Those are all subsequent items in |
425 | common_importables_path_fst == fst_path(&import_map.map[item].path) | 424 | // `importables` whose paths match `path`. |
426 | }) | 425 | let iter = importables |
427 | .filter(|&item| match item_import_kind(item) { | 426 | .iter() |
428 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | 427 | .copied() |
429 | None => true, | 428 | .take_while(|item| common_importables_path_fst == fst_path(&import_map.map[item].path)) |
430 | }) | 429 | .filter(|&item| match item_import_kind(item) { |
431 | .filter(|item| { | 430 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), |
432 | !query.case_sensitive // we've already checked the common importables path case-insensitively | 431 | None => true, |
432 | }) | ||
433 | .filter(|item| { | ||
434 | !query.case_sensitive // we've already checked the common importables path case-insensitively | ||
433 | || query.import_matches(&import_map.map[item], false) | 435 | || query.import_matches(&import_map.map[item], false) |
434 | }); | 436 | }); |
435 | res.extend(iter); | 437 | res.extend(iter); |
436 | 438 | ||
437 | if res.len() >= query.limit { | 439 | if res.len() >= query.limit { |
438 | res.truncate(query.limit); | 440 | return res; |
439 | return res; | ||
440 | } | ||
441 | } | 441 | } |
442 | } | 442 | } |
443 | 443 | ||
@@ -462,7 +462,6 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { | |||
462 | mod tests { | 462 | mod tests { |
463 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 463 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
464 | use expect_test::{expect, Expect}; | 464 | use expect_test::{expect, Expect}; |
465 | use test_utils::mark; | ||
466 | 465 | ||
467 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; | 466 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; |
468 | 467 | ||
@@ -800,7 +799,7 @@ mod tests { | |||
800 | 799 | ||
801 | #[test] | 800 | #[test] |
802 | fn fuzzy_import_trait_and_assoc_items() { | 801 | fn fuzzy_import_trait_and_assoc_items() { |
803 | mark::check!(type_aliases_ignored); | 802 | cov_mark::check!(type_aliases_ignored); |
804 | let ra_fixture = r#" | 803 | let ra_fixture = r#" |
805 | //- /main.rs crate:main deps:dep | 804 | //- /main.rs crate:main deps:dep |
806 | //- /dep.rs crate:dep | 805 | //- /dep.rs crate:dep |
@@ -821,10 +820,10 @@ mod tests { | |||
821 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), | 820 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), |
822 | expect![[r#" | 821 | expect![[r#" |
823 | dep::fmt (t) | 822 | dep::fmt (t) |
823 | dep::fmt::Display::format_method (a) | ||
824 | dep::fmt::Display (t) | 824 | dep::fmt::Display (t) |
825 | dep::fmt::Display::FMT_CONST (a) | 825 | dep::fmt::Display::FMT_CONST (a) |
826 | dep::fmt::Display::format_function (a) | 826 | dep::fmt::Display::format_function (a) |
827 | dep::fmt::Display::format_method (a) | ||
828 | "#]], | 827 | "#]], |
829 | ); | 828 | ); |
830 | } | 829 | } |
@@ -850,9 +849,9 @@ mod tests { | |||
850 | "main", | 849 | "main", |
851 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(), | 850 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(), |
852 | expect![[r#" | 851 | expect![[r#" |
852 | dep::fmt::Display::format_method (a) | ||
853 | dep::fmt::Display::FMT_CONST (a) | 853 | dep::fmt::Display::FMT_CONST (a) |
854 | dep::fmt::Display::format_function (a) | 854 | dep::fmt::Display::format_function (a) |
855 | dep::fmt::Display::format_method (a) | ||
856 | "#]], | 855 | "#]], |
857 | ); | 856 | ); |
858 | 857 | ||
@@ -911,12 +910,12 @@ mod tests { | |||
911 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), | 910 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), |
912 | expect![[r#" | 911 | expect![[r#" |
913 | dep::fmt (t) | 912 | dep::fmt (t) |
914 | dep::Fmt (t) | 913 | dep::format (f) |
915 | dep::Fmt (v) | 914 | dep::Fmt (v) |
916 | dep::Fmt (m) | ||
917 | dep::fmt::Display (t) | 915 | dep::fmt::Display (t) |
916 | dep::Fmt (t) | ||
918 | dep::fmt::Display::fmt (a) | 917 | dep::fmt::Display::fmt (a) |
919 | dep::format (f) | 918 | dep::Fmt (m) |
920 | "#]], | 919 | "#]], |
921 | ); | 920 | ); |
922 | 921 | ||
@@ -926,10 +925,10 @@ mod tests { | |||
926 | Query::new("fmt".to_string()).search_mode(SearchMode::Equals), | 925 | Query::new("fmt".to_string()).search_mode(SearchMode::Equals), |
927 | expect![[r#" | 926 | expect![[r#" |
928 | dep::fmt (t) | 927 | dep::fmt (t) |
929 | dep::Fmt (t) | ||
930 | dep::Fmt (v) | 928 | dep::Fmt (v) |
931 | dep::Fmt (m) | 929 | dep::Fmt (t) |
932 | dep::fmt::Display::fmt (a) | 930 | dep::fmt::Display::fmt (a) |
931 | dep::Fmt (m) | ||
933 | "#]], | 932 | "#]], |
934 | ); | 933 | ); |
935 | 934 | ||
@@ -939,11 +938,11 @@ mod tests { | |||
939 | Query::new("fmt".to_string()).search_mode(SearchMode::Contains), | 938 | Query::new("fmt".to_string()).search_mode(SearchMode::Contains), |
940 | expect![[r#" | 939 | expect![[r#" |
941 | dep::fmt (t) | 940 | dep::fmt (t) |
942 | dep::Fmt (t) | ||
943 | dep::Fmt (v) | 941 | dep::Fmt (v) |
944 | dep::Fmt (m) | ||
945 | dep::fmt::Display (t) | 942 | dep::fmt::Display (t) |
943 | dep::Fmt (t) | ||
946 | dep::fmt::Display::fmt (a) | 944 | dep::fmt::Display::fmt (a) |
945 | dep::Fmt (m) | ||
947 | "#]], | 946 | "#]], |
948 | ); | 947 | ); |
949 | } | 948 | } |
@@ -980,11 +979,11 @@ mod tests { | |||
980 | Query::new("fmt".to_string()), | 979 | Query::new("fmt".to_string()), |
981 | expect![[r#" | 980 | expect![[r#" |
982 | dep::fmt (t) | 981 | dep::fmt (t) |
983 | dep::Fmt (t) | ||
984 | dep::Fmt (v) | 982 | dep::Fmt (v) |
985 | dep::Fmt (m) | ||
986 | dep::fmt::Display (t) | 983 | dep::fmt::Display (t) |
984 | dep::Fmt (t) | ||
987 | dep::fmt::Display::fmt (a) | 985 | dep::fmt::Display::fmt (a) |
986 | dep::Fmt (m) | ||
988 | "#]], | 987 | "#]], |
989 | ); | 988 | ); |
990 | 989 | ||
@@ -994,10 +993,10 @@ mod tests { | |||
994 | Query::new("fmt".to_string()).name_only(), | 993 | Query::new("fmt".to_string()).name_only(), |
995 | expect![[r#" | 994 | expect![[r#" |
996 | dep::fmt (t) | 995 | dep::fmt (t) |
997 | dep::Fmt (t) | ||
998 | dep::Fmt (v) | 996 | dep::Fmt (v) |
999 | dep::Fmt (m) | 997 | dep::Fmt (t) |
1000 | dep::fmt::Display::fmt (a) | 998 | dep::fmt::Display::fmt (a) |
999 | dep::Fmt (m) | ||
1001 | "#]], | 1000 | "#]], |
1002 | ); | 1001 | ); |
1003 | } | 1002 | } |
@@ -1018,9 +1017,9 @@ mod tests { | |||
1018 | Query::new("FMT".to_string()), | 1017 | Query::new("FMT".to_string()), |
1019 | expect![[r#" | 1018 | expect![[r#" |
1020 | dep::fmt (t) | 1019 | dep::fmt (t) |
1020 | dep::FMT (v) | ||
1021 | dep::fmt (v) | 1021 | dep::fmt (v) |
1022 | dep::FMT (t) | 1022 | dep::FMT (t) |
1023 | dep::FMT (v) | ||
1024 | "#]], | 1023 | "#]], |
1025 | ); | 1024 | ); |
1026 | 1025 | ||
@@ -1060,6 +1059,8 @@ mod tests { | |||
1060 | expect![[r#" | 1059 | expect![[r#" |
1061 | dep::fmt (t) | 1060 | dep::fmt (t) |
1062 | dep::Fmt (t) | 1061 | dep::Fmt (t) |
1062 | dep::Fmt (m) | ||
1063 | dep::Fmt (v) | ||
1063 | "#]], | 1064 | "#]], |
1064 | ); | 1065 | ); |
1065 | } | 1066 | } |
@@ -1080,9 +1081,9 @@ mod tests { | |||
1080 | Query::new("FMT".to_string()), | 1081 | Query::new("FMT".to_string()), |
1081 | expect![[r#" | 1082 | expect![[r#" |
1082 | dep::fmt (t) | 1083 | dep::fmt (t) |
1084 | dep::FMT (v) | ||
1083 | dep::fmt (v) | 1085 | dep::fmt (v) |
1084 | dep::FMT (t) | 1086 | dep::FMT (t) |
1085 | dep::FMT (v) | ||
1086 | "#]], | 1087 | "#]], |
1087 | ); | 1088 | ); |
1088 | 1089 | ||
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 4e5daa2ff..919933813 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -9,7 +9,6 @@ use hir_expand::MacroDefKind; | |||
9 | use once_cell::sync::Lazy; | 9 | use once_cell::sync::Lazy; |
10 | use rustc_hash::{FxHashMap, FxHashSet}; | 10 | use rustc_hash::{FxHashMap, FxHashSet}; |
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | use test_utils::mark; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, | 14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, |
@@ -237,7 +236,7 @@ impl ItemScope { | |||
237 | if $glob_imports.$field.contains(&$lookup) | 236 | if $glob_imports.$field.contains(&$lookup) |
238 | && matches!($def_import_type, ImportType::Named) => | 237 | && matches!($def_import_type, ImportType::Named) => |
239 | { | 238 | { |
240 | mark::hit!(import_shadowed); | 239 | cov_mark::hit!(import_shadowed); |
241 | $glob_imports.$field.remove(&$lookup); | 240 | $glob_imports.$field.remove(&$lookup); |
242 | if let Some(fld) = $def.$field { | 241 | if let Some(fld) = $def.$field { |
243 | entry.insert(fld); | 242 | entry.insert(fld); |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 3233b1957..6bb334573 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -25,7 +25,6 @@ use profile::Count; | |||
25 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
26 | use smallvec::SmallVec; | 26 | use smallvec::SmallVec; |
27 | use syntax::{ast, match_ast, SyntaxKind}; | 27 | use syntax::{ast, match_ast, SyntaxKind}; |
28 | use test_utils::mark; | ||
29 | 28 | ||
30 | use crate::{ | 29 | use crate::{ |
31 | attr::{Attrs, RawAttrs}, | 30 | attr::{Attrs, RawAttrs}, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 8f2f0b340..240fdacf9 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -466,7 +466,7 @@ impl Ctx { | |||
466 | .collect() | 466 | .collect() |
467 | }) | 467 | }) |
468 | .unwrap_or_else(|| { | 468 | .unwrap_or_else(|| { |
469 | mark::hit!(name_res_works_for_broken_modules); | 469 | cov_mark::hit!(name_res_works_for_broken_modules); |
470 | Box::new([]) as Box<[_]> | 470 | Box::new([]) as Box<[_]> |
471 | }), | 471 | }), |
472 | } | 472 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index e51d89b43..3bb69d935 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -18,7 +18,6 @@ use hir_expand::{ | |||
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use syntax::ast; | 20 | use syntax::ast; |
21 | use test_utils::mark; | ||
22 | use tt::{Leaf, TokenTree}; | 21 | use tt::{Leaf, TokenTree}; |
23 | 22 | ||
24 | use crate::{ | 23 | use crate::{ |
@@ -462,7 +461,7 @@ impl DefCollector<'_> { | |||
462 | let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); | 461 | let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); |
463 | 462 | ||
464 | if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { | 463 | if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { |
465 | mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); | 464 | cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); |
466 | self.import_all_macros_exported(current_module_id, m.krate); | 465 | self.import_all_macros_exported(current_module_id, m.krate); |
467 | } | 466 | } |
468 | } | 467 | } |
@@ -571,10 +570,10 @@ impl DefCollector<'_> { | |||
571 | match def.take_types() { | 570 | match def.take_types() { |
572 | Some(ModuleDefId::ModuleId(m)) => { | 571 | Some(ModuleDefId::ModuleId(m)) => { |
573 | if import.is_prelude { | 572 | if import.is_prelude { |
574 | mark::hit!(std_prelude); | 573 | cov_mark::hit!(std_prelude); |
575 | self.def_map.prelude = Some(m); | 574 | self.def_map.prelude = Some(m); |
576 | } else if m.krate != self.def_map.krate { | 575 | } else if m.krate != self.def_map.krate { |
577 | mark::hit!(glob_across_crates); | 576 | cov_mark::hit!(glob_across_crates); |
578 | // glob import from other crate => we can just import everything once | 577 | // glob import from other crate => we can just import everything once |
579 | let item_map = m.def_map(self.db); | 578 | let item_map = m.def_map(self.db); |
580 | let scope = &item_map[m.local_id].scope; | 579 | let scope = &item_map[m.local_id].scope; |
@@ -626,7 +625,7 @@ impl DefCollector<'_> { | |||
626 | } | 625 | } |
627 | } | 626 | } |
628 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 627 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
629 | mark::hit!(glob_enum); | 628 | cov_mark::hit!(glob_enum); |
630 | // glob import from enum => just import all the variants | 629 | // glob import from enum => just import all the variants |
631 | 630 | ||
632 | // XXX: urgh, so this works by accident! Here, we look at | 631 | // XXX: urgh, so this works by accident! Here, we look at |
@@ -675,7 +674,7 @@ impl DefCollector<'_> { | |||
675 | 674 | ||
676 | self.update(module_id, &[(name, def)], vis, ImportType::Named); | 675 | self.update(module_id, &[(name, def)], vis, ImportType::Named); |
677 | } | 676 | } |
678 | None => mark::hit!(bogus_paths), | 677 | None => cov_mark::hit!(bogus_paths), |
679 | } | 678 | } |
680 | } | 679 | } |
681 | } | 680 | } |
@@ -738,7 +737,7 @@ impl DefCollector<'_> { | |||
738 | if max_vis == old_vis { | 737 | if max_vis == old_vis { |
739 | false | 738 | false |
740 | } else { | 739 | } else { |
741 | mark::hit!(upgrade_underscore_visibility); | 740 | cov_mark::hit!(upgrade_underscore_visibility); |
742 | true | 741 | true |
743 | } | 742 | } |
744 | } | 743 | } |
@@ -866,7 +865,7 @@ impl DefCollector<'_> { | |||
866 | depth: usize, | 865 | depth: usize, |
867 | ) { | 866 | ) { |
868 | if depth > EXPANSION_DEPTH_LIMIT { | 867 | if depth > EXPANSION_DEPTH_LIMIT { |
869 | mark::hit!(macro_expansion_overflow); | 868 | cov_mark::hit!(macro_expansion_overflow); |
870 | log::warn!("macro expansion is too deep"); | 869 | log::warn!("macro expansion is too deep"); |
871 | return; | 870 | return; |
872 | } | 871 | } |
@@ -1009,7 +1008,7 @@ impl ModCollector<'_, '_> { | |||
1009 | // Prelude module is always considered to be `#[macro_use]`. | 1008 | // Prelude module is always considered to be `#[macro_use]`. |
1010 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 1009 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
1011 | if prelude_module.krate != self.def_collector.def_map.krate { | 1010 | if prelude_module.krate != self.def_collector.def_map.krate { |
1012 | mark::hit!(prelude_is_macro_use); | 1011 | cov_mark::hit!(prelude_is_macro_use); |
1013 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); | 1012 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); |
1014 | } | 1013 | } |
1015 | } | 1014 | } |
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index af3262439..d5de9899c 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | use base_db::{AnchoredPath, FileId}; | 2 | use base_db::{AnchoredPath, FileId}; |
3 | use hir_expand::name::Name; | 3 | use hir_expand::name::Name; |
4 | use syntax::SmolStr; | 4 | use syntax::SmolStr; |
5 | use test_utils::mark; | ||
6 | 5 | ||
7 | use crate::{db::DefDatabase, HirFileId}; | 6 | use crate::{db::DefDatabase, HirFileId}; |
8 | 7 | ||
@@ -28,7 +27,7 @@ impl ModDir { | |||
28 | let depth = self.depth + 1; | 27 | let depth = self.depth + 1; |
29 | if depth > MOD_DEPTH_LIMIT { | 28 | if depth > MOD_DEPTH_LIMIT { |
30 | log::error!("MOD_DEPTH_LIMIT exceeded"); | 29 | log::error!("MOD_DEPTH_LIMIT exceeded"); |
31 | mark::hit!(circular_mods); | 30 | cov_mark::hit!(circular_mods); |
32 | return None; | 31 | return None; |
33 | } | 32 | } |
34 | Some(ModDir { dir_path, root_non_dir_owner, depth }) | 33 | Some(ModDir { dir_path, root_non_dir_owner, depth }) |
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index dd1db0094..8258dcffb 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -13,7 +13,6 @@ | |||
13 | use base_db::Edition; | 13 | use base_db::Edition; |
14 | use hir_expand::name; | 14 | use hir_expand::name; |
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use test_utils::mark; | ||
17 | 16 | ||
18 | use crate::{ | 17 | use crate::{ |
19 | db::DefDatabase, | 18 | db::DefDatabase, |
@@ -63,7 +62,7 @@ impl ResolvePathResult { | |||
63 | impl DefMap { | 62 | impl DefMap { |
64 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | 63 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { |
65 | if name == &name!(self) { | 64 | if name == &name!(self) { |
66 | mark::hit!(extern_crate_self_as); | 65 | cov_mark::hit!(extern_crate_self_as); |
67 | return PerNs::types(self.module_id(self.root).into(), Visibility::Public); | 66 | return PerNs::types(self.module_id(self.root).into(), Visibility::Public); |
68 | } | 67 | } |
69 | self.extern_prelude | 68 | self.extern_prelude |
@@ -101,7 +100,7 @@ impl DefMap { | |||
101 | // DefMap they're written in, so we restrict them when that happens. | 100 | // DefMap they're written in, so we restrict them when that happens. |
102 | if let Visibility::Module(m) = vis { | 101 | if let Visibility::Module(m) = vis { |
103 | if self.block_id() != m.block { | 102 | if self.block_id() != m.block { |
104 | mark::hit!(adjust_vis_in_block_def_map); | 103 | cov_mark::hit!(adjust_vis_in_block_def_map); |
105 | vis = Visibility::Module(self.module_id(self.root())); | 104 | vis = Visibility::Module(self.module_id(self.root())); |
106 | log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); | 105 | log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); |
107 | } | 106 | } |
@@ -169,12 +168,12 @@ impl DefMap { | |||
169 | let mut curr_per_ns: PerNs = match path.kind { | 168 | let mut curr_per_ns: PerNs = match path.kind { |
170 | PathKind::DollarCrate(krate) => { | 169 | PathKind::DollarCrate(krate) => { |
171 | if krate == self.krate { | 170 | if krate == self.krate { |
172 | mark::hit!(macro_dollar_crate_self); | 171 | cov_mark::hit!(macro_dollar_crate_self); |
173 | PerNs::types(self.crate_root(db).into(), Visibility::Public) | 172 | PerNs::types(self.crate_root(db).into(), Visibility::Public) |
174 | } else { | 173 | } else { |
175 | let def_map = db.crate_def_map(krate); | 174 | let def_map = db.crate_def_map(krate); |
176 | let module = def_map.module_id(def_map.root); | 175 | let module = def_map.module_id(def_map.root); |
177 | mark::hit!(macro_dollar_crate_other); | 176 | cov_mark::hit!(macro_dollar_crate_other); |
178 | PerNs::types(module.into(), Visibility::Public) | 177 | PerNs::types(module.into(), Visibility::Public) |
179 | } | 178 | } |
180 | } | 179 | } |
@@ -310,7 +309,7 @@ impl DefMap { | |||
310 | } | 309 | } |
311 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 310 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
312 | // enum variant | 311 | // enum variant |
313 | mark::hit!(can_import_enum_variant); | 312 | cov_mark::hit!(can_import_enum_variant); |
314 | let enum_data = db.enum_data(e); | 313 | let enum_data = db.enum_data(e); |
315 | match enum_data.variant(&segment) { | 314 | match enum_data.variant(&segment) { |
316 | Some(local_id) => { | 315 | Some(local_id) => { |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index bd3e2701b..de3aa4f9a 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -9,7 +9,6 @@ use std::sync::Arc; | |||
9 | 9 | ||
10 | use base_db::{fixture::WithFixture, SourceDatabase}; | 10 | use base_db::{fixture::WithFixture, SourceDatabase}; |
11 | use expect_test::{expect, Expect}; | 11 | use expect_test::{expect, Expect}; |
12 | use test_utils::mark; | ||
13 | 12 | ||
14 | use crate::{db::DefDatabase, test_db::TestDB}; | 13 | use crate::{db::DefDatabase, test_db::TestDB}; |
15 | 14 | ||
@@ -136,7 +135,7 @@ mod m { | |||
136 | 135 | ||
137 | #[test] | 136 | #[test] |
138 | fn bogus_paths() { | 137 | fn bogus_paths() { |
139 | mark::check!(bogus_paths); | 138 | cov_mark::check!(bogus_paths); |
140 | check( | 139 | check( |
141 | r#" | 140 | r#" |
142 | //- /lib.rs | 141 | //- /lib.rs |
@@ -243,7 +242,7 @@ pub struct Baz; | |||
243 | 242 | ||
244 | #[test] | 243 | #[test] |
245 | fn std_prelude() { | 244 | fn std_prelude() { |
246 | mark::check!(std_prelude); | 245 | cov_mark::check!(std_prelude); |
247 | check( | 246 | check( |
248 | r#" | 247 | r#" |
249 | //- /main.rs crate:main deps:test_crate | 248 | //- /main.rs crate:main deps:test_crate |
@@ -267,7 +266,7 @@ pub enum Foo { Bar, Baz }; | |||
267 | 266 | ||
268 | #[test] | 267 | #[test] |
269 | fn can_import_enum_variant() { | 268 | fn can_import_enum_variant() { |
270 | mark::check!(can_import_enum_variant); | 269 | cov_mark::check!(can_import_enum_variant); |
271 | check( | 270 | check( |
272 | r#" | 271 | r#" |
273 | enum E { V } | 272 | enum E { V } |
@@ -628,7 +627,7 @@ use crate::reex::*; | |||
628 | 627 | ||
629 | #[test] | 628 | #[test] |
630 | fn underscore_pub_crate_reexport() { | 629 | fn underscore_pub_crate_reexport() { |
631 | mark::check!(upgrade_underscore_visibility); | 630 | cov_mark::check!(upgrade_underscore_visibility); |
632 | check( | 631 | check( |
633 | r#" | 632 | r#" |
634 | //- /main.rs crate:main deps:lib | 633 | //- /main.rs crate:main deps:lib |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index e8e72e5ef..d5ef8ceb5 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use base_db::fixture::WithFixture; | 1 | use base_db::fixture::WithFixture; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use crate::test_db::TestDB; | 3 | use crate::test_db::TestDB; |
5 | 4 | ||
@@ -63,7 +62,7 @@ fn unresolved_extern_crate() { | |||
63 | 62 | ||
64 | #[test] | 63 | #[test] |
65 | fn extern_crate_self_as() { | 64 | fn extern_crate_self_as() { |
66 | mark::check!(extern_crate_self_as); | 65 | cov_mark::check!(extern_crate_self_as); |
67 | check_diagnostics( | 66 | check_diagnostics( |
68 | r" | 67 | r" |
69 | //- /lib.rs | 68 | //- /lib.rs |
@@ -140,7 +139,7 @@ fn inactive_item() { | |||
140 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. | 139 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. |
141 | #[test] | 140 | #[test] |
142 | fn inactive_via_cfg_attr() { | 141 | fn inactive_via_cfg_attr() { |
143 | mark::check!(cfg_attr_active); | 142 | cov_mark::check!(cfg_attr_active); |
144 | check_diagnostics( | 143 | check_diagnostics( |
145 | r#" | 144 | r#" |
146 | //- /lib.rs | 145 | //- /lib.rs |
diff --git a/crates/hir_def/src/nameres/tests/globs.rs b/crates/hir_def/src/nameres/tests/globs.rs index 2ae836e3c..17426d54d 100644 --- a/crates/hir_def/src/nameres/tests/globs.rs +++ b/crates/hir_def/src/nameres/tests/globs.rs | |||
@@ -148,7 +148,7 @@ pub(crate) struct PubCrateStruct; | |||
148 | 148 | ||
149 | #[test] | 149 | #[test] |
150 | fn glob_across_crates() { | 150 | fn glob_across_crates() { |
151 | mark::check!(glob_across_crates); | 151 | cov_mark::check!(glob_across_crates); |
152 | check( | 152 | check( |
153 | r#" | 153 | r#" |
154 | //- /main.rs crate:main deps:test_crate | 154 | //- /main.rs crate:main deps:test_crate |
@@ -184,7 +184,7 @@ struct Foo; | |||
184 | 184 | ||
185 | #[test] | 185 | #[test] |
186 | fn glob_enum() { | 186 | fn glob_enum() { |
187 | mark::check!(glob_enum); | 187 | cov_mark::check!(glob_enum); |
188 | check( | 188 | check( |
189 | r#" | 189 | r#" |
190 | enum Foo { Bar, Baz } | 190 | enum Foo { Bar, Baz } |
@@ -201,7 +201,7 @@ use self::Foo::*; | |||
201 | 201 | ||
202 | #[test] | 202 | #[test] |
203 | fn glob_enum_group() { | 203 | fn glob_enum_group() { |
204 | mark::check!(glob_enum_group); | 204 | cov_mark::check!(glob_enum_group); |
205 | check( | 205 | check( |
206 | r#" | 206 | r#" |
207 | enum Foo { Bar, Baz } | 207 | enum Foo { Bar, Baz } |
@@ -218,7 +218,7 @@ use self::Foo::{*}; | |||
218 | 218 | ||
219 | #[test] | 219 | #[test] |
220 | fn glob_shadowed_def() { | 220 | fn glob_shadowed_def() { |
221 | mark::check!(import_shadowed); | 221 | cov_mark::check!(import_shadowed); |
222 | check( | 222 | check( |
223 | r#" | 223 | r#" |
224 | //- /lib.rs | 224 | //- /lib.rs |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 36ed5e8ce..f65a655bf 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -210,7 +210,7 @@ macro_rules! bar { | |||
210 | 210 | ||
211 | #[test] | 211 | #[test] |
212 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | 212 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { |
213 | mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); | 213 | cov_mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); |
214 | check( | 214 | check( |
215 | r#" | 215 | r#" |
216 | //- /main.rs crate:main deps:foo | 216 | //- /main.rs crate:main deps:foo |
@@ -260,7 +260,7 @@ mod priv_mod { | |||
260 | 260 | ||
261 | #[test] | 261 | #[test] |
262 | fn prelude_is_macro_use() { | 262 | fn prelude_is_macro_use() { |
263 | mark::check!(prelude_is_macro_use); | 263 | cov_mark::check!(prelude_is_macro_use); |
264 | check( | 264 | check( |
265 | r#" | 265 | r#" |
266 | //- /main.rs crate:main deps:foo | 266 | //- /main.rs crate:main deps:foo |
@@ -550,7 +550,7 @@ mod m { | |||
550 | 550 | ||
551 | #[test] | 551 | #[test] |
552 | fn macro_dollar_crate_is_correct_in_item() { | 552 | fn macro_dollar_crate_is_correct_in_item() { |
553 | mark::check!(macro_dollar_crate_self); | 553 | cov_mark::check!(macro_dollar_crate_self); |
554 | check( | 554 | check( |
555 | r#" | 555 | r#" |
556 | //- /main.rs crate:main deps:foo | 556 | //- /main.rs crate:main deps:foo |
@@ -608,7 +608,7 @@ struct Baz; | |||
608 | 608 | ||
609 | #[test] | 609 | #[test] |
610 | fn macro_dollar_crate_is_correct_in_indirect_deps() { | 610 | fn macro_dollar_crate_is_correct_in_indirect_deps() { |
611 | mark::check!(macro_dollar_crate_other); | 611 | cov_mark::check!(macro_dollar_crate_other); |
612 | // From std | 612 | // From std |
613 | check( | 613 | check( |
614 | r#" | 614 | r#" |
@@ -686,7 +686,7 @@ pub trait Clone {} | |||
686 | 686 | ||
687 | #[test] | 687 | #[test] |
688 | fn macro_expansion_overflow() { | 688 | fn macro_expansion_overflow() { |
689 | mark::check!(macro_expansion_overflow); | 689 | cov_mark::check!(macro_expansion_overflow); |
690 | check( | 690 | check( |
691 | r#" | 691 | r#" |
692 | macro_rules! a { | 692 | macro_rules! a { |
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs index e80b593aa..dfbbad1f9 100644 --- a/crates/hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -2,7 +2,7 @@ use super::*; | |||
2 | 2 | ||
3 | #[test] | 3 | #[test] |
4 | fn name_res_works_for_broken_modules() { | 4 | fn name_res_works_for_broken_modules() { |
5 | mark::check!(name_res_works_for_broken_modules); | 5 | cov_mark::check!(name_res_works_for_broken_modules); |
6 | check( | 6 | check( |
7 | r" | 7 | r" |
8 | //- /lib.rs | 8 | //- /lib.rs |
@@ -774,7 +774,7 @@ struct X; | |||
774 | 774 | ||
775 | #[test] | 775 | #[test] |
776 | fn circular_mods() { | 776 | fn circular_mods() { |
777 | mark::check!(circular_mods); | 777 | cov_mark::check!(circular_mods); |
778 | compute_crate_def_map( | 778 | compute_crate_def_map( |
779 | r#" | 779 | r#" |
780 | //- /lib.rs | 780 | //- /lib.rs |
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index d584b0b70..e2965b033 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs | |||
@@ -6,7 +6,6 @@ use std::iter; | |||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::{hygiene::Hygiene, name::AsName}; |
8 | use syntax::ast::{self, NameOwner}; | 8 | use syntax::ast::{self, NameOwner}; |
9 | use test_utils::mark; | ||
10 | 9 | ||
11 | use crate::path::{ImportAlias, ModPath, PathKind}; | 10 | use crate::path::{ImportAlias, ModPath, PathKind}; |
12 | 11 | ||
@@ -54,7 +53,7 @@ pub(crate) fn lower_use_tree( | |||
54 | // FIXME: report errors somewhere | 53 | // FIXME: report errors somewhere |
55 | // We get here if we do | 54 | // We get here if we do |
56 | } else if is_glob { | 55 | } else if is_glob { |
57 | mark::hit!(glob_enum_group); | 56 | cov_mark::hit!(glob_enum_group); |
58 | if let Some(prefix) = prefix { | 57 | if let Some(prefix) = prefix { |
59 | cb(prefix, &tree, is_glob, None) | 58 | cb(prefix, &tree, is_glob, None) |
60 | } | 59 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index d1302d749..6131ebee8 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -10,6 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = "1.1" | ||
13 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
14 | arrayvec = "0.5.1" | 15 | arrayvec = "0.5.1" |
15 | smallvec = "1.2.0" | 16 | smallvec = "1.2.0" |
@@ -17,9 +18,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 18 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 19 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 20 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.59", default-features = false } | 21 | chalk-solve = { version = "0.60", default-features = false } |
21 | chalk-ir = "0.59" | 22 | chalk-ir = "0.60" |
22 | chalk-recursive = "0.59" | 23 | chalk-recursive = "0.60" |
23 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
24 | 25 | ||
25 | stdx = { path = "../stdx", version = "0.0.0" } | 26 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 6773ddea3..e230f9765 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -28,7 +28,6 @@ use syntax::{ | |||
28 | ast::{self, NameOwner}, | 28 | ast::{self, NameOwner}, |
29 | AstNode, AstPtr, | 29 | AstNode, AstPtr, |
30 | }; | 30 | }; |
31 | use test_utils::mark; | ||
32 | 31 | ||
33 | use crate::{ | 32 | use crate::{ |
34 | db::HirDatabase, | 33 | db::HirDatabase, |
@@ -93,7 +92,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
93 | fn validate_func(&mut self, func: FunctionId) { | 92 | fn validate_func(&mut self, func: FunctionId) { |
94 | let data = self.db.function_data(func); | 93 | let data = self.db.function_data(func); |
95 | if data.is_extern { | 94 | if data.is_extern { |
96 | mark::hit!(extern_func_incorrect_case_ignored); | 95 | cov_mark::hit!(extern_func_incorrect_case_ignored); |
97 | return; | 96 | return; |
98 | } | 97 | } |
99 | 98 | ||
@@ -625,7 +624,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
625 | fn validate_static(&mut self, static_id: StaticId) { | 624 | fn validate_static(&mut self, static_id: StaticId) { |
626 | let data = self.db.static_data(static_id); | 625 | let data = self.db.static_data(static_id); |
627 | if data.is_extern { | 626 | if data.is_extern { |
628 | mark::hit!(extern_static_incorrect_case_ignored); | 627 | cov_mark::hit!(extern_static_incorrect_case_ignored); |
629 | return; | 628 | return; |
630 | } | 629 | } |
631 | 630 | ||
@@ -673,8 +672,6 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
673 | 672 | ||
674 | #[cfg(test)] | 673 | #[cfg(test)] |
675 | mod tests { | 674 | mod tests { |
676 | use test_utils::mark; | ||
677 | |||
678 | use crate::diagnostics::tests::check_diagnostics; | 675 | use crate::diagnostics::tests::check_diagnostics; |
679 | 676 | ||
680 | #[test] | 677 | #[test] |
@@ -889,8 +886,8 @@ fn main() { | |||
889 | 886 | ||
890 | #[test] | 887 | #[test] |
891 | fn ignores_extern_items() { | 888 | fn ignores_extern_items() { |
892 | mark::check!(extern_func_incorrect_case_ignored); | 889 | cov_mark::check!(extern_func_incorrect_case_ignored); |
893 | mark::check!(extern_static_incorrect_case_ignored); | 890 | cov_mark::check!(extern_static_incorrect_case_ignored); |
894 | check_diagnostics( | 891 | check_diagnostics( |
895 | r#" | 892 | r#" |
896 | extern { | 893 | extern { |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index cf0a3add4..7e8846f27 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -6,7 +6,6 @@ | |||
6 | 6 | ||
7 | use chalk_ir::{Mutability, TyVariableKind}; | 7 | use chalk_ir::{Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | use test_utils::mark; | ||
10 | 9 | ||
11 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty}; | 10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty}; |
12 | 11 | ||
@@ -35,7 +34,7 @@ impl<'a> InferenceContext<'a> { | |||
35 | ty1.clone() | 34 | ty1.clone() |
36 | } else { | 35 | } else { |
37 | if let (Ty::FnDef(..), Ty::FnDef(..)) = (ty1, ty2) { | 36 | if let (Ty::FnDef(..), Ty::FnDef(..)) = (ty1, ty2) { |
38 | mark::hit!(coerce_fn_reification); | 37 | cov_mark::hit!(coerce_fn_reification); |
39 | // Special case: two function types. Try to coerce both to | 38 | // Special case: two function types. Try to coerce both to |
40 | // pointers to have a chance at getting a match. See | 39 | // pointers to have a chance at getting a match. See |
41 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
@@ -45,7 +44,7 @@ impl<'a> InferenceContext<'a> { | |||
45 | let ptr_ty2 = Ty::fn_ptr(sig2); | 44 | let ptr_ty2 = Ty::fn_ptr(sig2); |
46 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | 45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) |
47 | } else { | 46 | } else { |
48 | mark::hit!(coerce_merge_fail_fallback); | 47 | cov_mark::hit!(coerce_merge_fail_fallback); |
49 | ty1.clone() | 48 | ty1.clone() |
50 | } | 49 | } |
51 | } | 50 | } |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index ec2c13154..262177ffb 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -12,7 +12,6 @@ use hir_def::{ | |||
12 | }; | 12 | }; |
13 | use hir_expand::name::{name, Name}; | 13 | use hir_expand::name::{name, Name}; |
14 | use syntax::ast::RangeOp; | 14 | use syntax::ast::RangeOp; |
15 | use test_utils::mark; | ||
16 | 15 | ||
17 | use crate::{ | 16 | use crate::{ |
18 | autoderef, | 17 | autoderef, |
@@ -565,7 +564,7 @@ impl<'a> InferenceContext<'a> { | |||
565 | let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); | 564 | let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); |
566 | 565 | ||
567 | if ret == Ty::Unknown { | 566 | if ret == Ty::Unknown { |
568 | mark::hit!(infer_expr_inner_binary_operator_overload); | 567 | cov_mark::hit!(infer_expr_inner_binary_operator_overload); |
569 | 568 | ||
570 | self.resolve_associated_type_with_params( | 569 | self.resolve_associated_type_with_params( |
571 | lhs_ty, | 570 | lhs_ty, |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 987793e2e..a0ac8d80f 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -10,7 +10,6 @@ use hir_def::{ | |||
10 | FieldId, | 10 | FieldId, |
11 | }; | 11 | }; |
12 | use hir_expand::name::Name; | 12 | use hir_expand::name::Name; |
13 | use test_utils::mark; | ||
14 | 13 | ||
15 | use super::{BindingMode, Expectation, InferenceContext}; | 14 | use super::{BindingMode, Expectation, InferenceContext}; |
16 | use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty}; | 15 | use crate::{lower::lower_to_chalk_mutability, utils::variant_data, Substs, Ty}; |
@@ -108,7 +107,7 @@ impl<'a> InferenceContext<'a> { | |||
108 | } | 107 | } |
109 | } | 108 | } |
110 | } else if let Pat::Ref { .. } = &body[pat] { | 109 | } else if let Pat::Ref { .. } = &body[pat] { |
111 | mark::hit!(match_ergonomics_ref); | 110 | cov_mark::hit!(match_ergonomics_ref); |
112 | // When you encounter a `&pat` pattern, reset to Move. | 111 | // When you encounter a `&pat` pattern, reset to Move. |
113 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` | 112 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` |
114 | default_bm = BindingMode::Move; | 113 | default_bm = BindingMode::Move; |
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index 99a89a7f3..54fcfed10 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -5,8 +5,6 @@ use std::borrow::Cow; | |||
5 | use chalk_ir::{FloatTy, IntTy, TyVariableKind}; | 5 | use chalk_ir::{FloatTy, IntTy, TyVariableKind}; |
6 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 6 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
7 | 7 | ||
8 | use test_utils::mark; | ||
9 | |||
10 | use super::{InferenceContext, Obligation}; | 8 | use super::{InferenceContext, Obligation}; |
11 | use crate::{ | 9 | use crate::{ |
12 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferenceVar, Scalar, | 10 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferenceVar, Scalar, |
@@ -387,7 +385,7 @@ impl InferenceTable { | |||
387 | // more than once | 385 | // more than once |
388 | for i in 0..3 { | 386 | for i in 0..3 { |
389 | if i > 0 { | 387 | if i > 0 { |
390 | mark::hit!(type_var_resolves_to_int_var); | 388 | cov_mark::hit!(type_var_resolves_to_int_var); |
391 | } | 389 | } |
392 | match &*ty { | 390 | match &*ty { |
393 | Ty::InferenceVar(tv, _) => { | 391 | Ty::InferenceVar(tv, _) => { |
@@ -416,7 +414,7 @@ impl InferenceTable { | |||
416 | Ty::InferenceVar(tv, kind) => { | 414 | Ty::InferenceVar(tv, kind) => { |
417 | let inner = tv.to_inner(); | 415 | let inner = tv.to_inner(); |
418 | if tv_stack.contains(&inner) { | 416 | if tv_stack.contains(&inner) { |
419 | mark::hit!(type_var_cycles_resolve_as_possible); | 417 | cov_mark::hit!(type_var_cycles_resolve_as_possible); |
420 | // recursive type | 418 | // recursive type |
421 | return self.type_variable_table.fallback_value(tv, kind); | 419 | return self.type_variable_table.fallback_value(tv, kind); |
422 | } | 420 | } |
@@ -443,7 +441,7 @@ impl InferenceTable { | |||
443 | Ty::InferenceVar(tv, kind) => { | 441 | Ty::InferenceVar(tv, kind) => { |
444 | let inner = tv.to_inner(); | 442 | let inner = tv.to_inner(); |
445 | if tv_stack.contains(&inner) { | 443 | if tv_stack.contains(&inner) { |
446 | mark::hit!(type_var_cycles_resolve_completely); | 444 | cov_mark::hit!(type_var_cycles_resolve_completely); |
447 | // recursive type | 445 | // recursive type |
448 | return self.type_variable_table.fallback_value(tv, kind); | 446 | return self.type_variable_table.fallback_value(tv, kind); |
449 | } | 447 | } |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 5fe5b8ad1..b90fdc382 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -24,7 +24,6 @@ use hir_expand::name::Name; | |||
24 | use la_arena::ArenaMap; | 24 | use la_arena::ArenaMap; |
25 | use smallvec::SmallVec; | 25 | use smallvec::SmallVec; |
26 | use stdx::impl_from; | 26 | use stdx::impl_from; |
27 | use test_utils::mark; | ||
28 | 27 | ||
29 | use crate::{ | 28 | use crate::{ |
30 | db::HirDatabase, | 29 | db::HirDatabase, |
@@ -760,7 +759,7 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
760 | 759 | ||
761 | impl ReturnTypeImplTrait { | 760 | impl ReturnTypeImplTrait { |
762 | fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { | 761 | fn from_hir(ctx: &TyLoweringContext, bounds: &[TypeBound]) -> Self { |
763 | mark::hit!(lower_rpit); | 762 | cov_mark::hit!(lower_rpit); |
764 | let self_ty = Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)); | 763 | let self_ty = Ty::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)); |
765 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 764 | let predicates = ctx.with_shifted_in(DebruijnIndex::ONE, |ctx| { |
766 | bounds | 765 | bounds |
@@ -935,7 +934,7 @@ impl TraitEnvironment { | |||
935 | // add `Self: Trait<T1, T2, ...>` to the environment in trait | 934 | // add `Self: Trait<T1, T2, ...>` to the environment in trait |
936 | // function default implementations (and hypothetical code | 935 | // function default implementations (and hypothetical code |
937 | // inside consts or type aliases) | 936 | // inside consts or type aliases) |
938 | test_utils::mark::hit!(trait_self_implements_self); | 937 | cov_mark::hit!(trait_self_implements_self); |
939 | let substs = Substs::type_params(db, trait_id); | 938 | let substs = Substs::type_params(db, trait_id); |
940 | let trait_ref = TraitRef { trait_: trait_id, substs }; | 939 | let trait_ref = TraitRef { trait_: trait_id, substs }; |
941 | let pred = GenericPredicate::Implemented(trait_ref); | 940 | let pred = GenericPredicate::Implemented(trait_ref); |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index dfcf346fb..24db33c49 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -588,7 +588,7 @@ fn iterate_inherent_methods( | |||
588 | // already happens in `is_valid_candidate` above; if not, we | 588 | // already happens in `is_valid_candidate` above; if not, we |
589 | // check it here | 589 | // check it here |
590 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { | 590 | if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { |
591 | test_utils::mark::hit!(impl_self_type_match_without_receiver); | 591 | cov_mark::hit!(impl_self_type_match_without_receiver); |
592 | continue; | 592 | continue; |
593 | } | 593 | } |
594 | if callback(&self_ty.value, item) { | 594 | if callback(&self_ty.value, item) { |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 7bc6c79f3..63d9d4e0b 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use super::{check_infer, check_infer_with_mismatches}; | 3 | use super::{check_infer, check_infer_with_mismatches}; |
5 | 4 | ||
@@ -381,7 +380,7 @@ fn infer_match_second_coerce() { | |||
381 | 380 | ||
382 | #[test] | 381 | #[test] |
383 | fn coerce_merge_one_by_one1() { | 382 | fn coerce_merge_one_by_one1() { |
384 | mark::check!(coerce_merge_fail_fallback); | 383 | cov_mark::check!(coerce_merge_fail_fallback); |
385 | 384 | ||
386 | check_infer( | 385 | check_infer( |
387 | r" | 386 | r" |
@@ -589,7 +588,7 @@ fn coerce_fn_item_to_fn_ptr() { | |||
589 | 588 | ||
590 | #[test] | 589 | #[test] |
591 | fn coerce_fn_items_in_match_arms() { | 590 | fn coerce_fn_items_in_match_arms() { |
592 | mark::check!(coerce_fn_reification); | 591 | cov_mark::check!(coerce_fn_reification); |
593 | 592 | ||
594 | check_infer_with_mismatches( | 593 | check_infer_with_mismatches( |
595 | r" | 594 | r" |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index a9901d7b8..4e3f9a9b6 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -913,7 +913,7 @@ fn test() { S2.into(); } | |||
913 | 913 | ||
914 | #[test] | 914 | #[test] |
915 | fn method_resolution_overloaded_method() { | 915 | fn method_resolution_overloaded_method() { |
916 | test_utils::mark::check!(impl_self_type_match_without_receiver); | 916 | cov_mark::check!(impl_self_type_match_without_receiver); |
917 | check_types( | 917 | check_types( |
918 | r#" | 918 | r#" |
919 | struct Wrapper<T>(T); | 919 | struct Wrapper<T>(T); |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 2053d8f56..5da19ba5f 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use super::{check_infer, check_infer_with_mismatches}; | 3 | use super::{check_infer, check_infer_with_mismatches}; |
5 | 4 | ||
@@ -197,7 +196,7 @@ fn infer_pattern_match_ergonomics() { | |||
197 | 196 | ||
198 | #[test] | 197 | #[test] |
199 | fn infer_pattern_match_ergonomics_ref() { | 198 | fn infer_pattern_match_ergonomics_ref() { |
200 | mark::check!(match_ergonomics_ref); | 199 | cov_mark::check!(match_ergonomics_ref); |
201 | check_infer( | 200 | check_infer( |
202 | r#" | 201 | r#" |
203 | fn test() { | 202 | fn test() { |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index cffe8630b..69314e245 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use super::{check_infer, check_types}; | 3 | use super::{check_infer, check_types}; |
5 | 4 | ||
@@ -87,8 +86,8 @@ fn bug_651() { | |||
87 | 86 | ||
88 | #[test] | 87 | #[test] |
89 | fn recursive_vars() { | 88 | fn recursive_vars() { |
90 | mark::check!(type_var_cycles_resolve_completely); | 89 | cov_mark::check!(type_var_cycles_resolve_completely); |
91 | mark::check!(type_var_cycles_resolve_as_possible); | 90 | cov_mark::check!(type_var_cycles_resolve_as_possible); |
92 | check_infer( | 91 | check_infer( |
93 | r#" | 92 | r#" |
94 | fn test() { | 93 | fn test() { |
@@ -166,7 +165,7 @@ fn infer_std_crash_1() { | |||
166 | 165 | ||
167 | #[test] | 166 | #[test] |
168 | fn infer_std_crash_2() { | 167 | fn infer_std_crash_2() { |
169 | mark::check!(type_var_resolves_to_int_var); | 168 | cov_mark::check!(type_var_resolves_to_int_var); |
170 | // caused "equating two type variables, ...", taken from std | 169 | // caused "equating two type variables, ...", taken from std |
171 | check_infer( | 170 | check_infer( |
172 | r#" | 171 | r#" |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 2947857a5..f5069eba5 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use super::{check_infer, check_types}; | 3 | use super::{check_infer, check_types}; |
5 | 4 | ||
@@ -2314,7 +2313,7 @@ fn generic_default_depending_on_other_type_arg_forward() { | |||
2314 | 2313 | ||
2315 | #[test] | 2314 | #[test] |
2316 | fn infer_operator_overload() { | 2315 | fn infer_operator_overload() { |
2317 | mark::check!(infer_expr_inner_binary_operator_overload); | 2316 | cov_mark::check!(infer_expr_inner_binary_operator_overload); |
2318 | 2317 | ||
2319 | check_infer( | 2318 | check_infer( |
2320 | r#" | 2319 | r#" |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 1298e5a88..528092082 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use expect_test::expect; | 1 | use expect_test::expect; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use super::{check_infer, check_infer_with_mismatches, check_types}; | 3 | use super::{check_infer, check_infer_with_mismatches, check_types}; |
5 | 4 | ||
@@ -319,7 +318,7 @@ fn infer_from_bound_2() { | |||
319 | 318 | ||
320 | #[test] | 319 | #[test] |
321 | fn trait_default_method_self_bound_implements_trait() { | 320 | fn trait_default_method_self_bound_implements_trait() { |
322 | mark::check!(trait_self_implements_self); | 321 | cov_mark::check!(trait_self_implements_self); |
323 | check_infer( | 322 | check_infer( |
324 | r#" | 323 | r#" |
325 | trait Trait { | 324 | trait Trait { |
@@ -1189,7 +1188,7 @@ fn impl_trait() { | |||
1189 | 1188 | ||
1190 | #[test] | 1189 | #[test] |
1191 | fn simple_return_pos_impl_trait() { | 1190 | fn simple_return_pos_impl_trait() { |
1192 | mark::check!(lower_rpit); | 1191 | cov_mark::check!(lower_rpit); |
1193 | check_infer( | 1192 | check_infer( |
1194 | r#" | 1193 | r#" |
1195 | trait Trait<T> { | 1194 | trait Trait<T> { |
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f6aaaeda4..f7c5efaf3 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -10,6 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = "1.1" | ||
13 | either = "1.5.3" | 14 | either = "1.5.3" |
14 | indexmap = "1.4.0" | 15 | indexmap = "1.4.0" |
15 | itertools = "0.10.0" | 16 | itertools = "0.10.0" |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index a9454cfa3..5d1cc2052 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -11,7 +11,6 @@ use ide_db::{ | |||
11 | use itertools::Itertools; | 11 | use itertools::Itertools; |
12 | use stdx::format_to; | 12 | use stdx::format_to; |
13 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 13 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
14 | use test_utils::mark; | ||
15 | 14 | ||
16 | use crate::{ | 15 | use crate::{ |
17 | display::{macro_label, ShortLabel, TryToNav}, | 16 | display::{macro_label, ShortLabel, TryToNav}, |
@@ -193,8 +192,8 @@ fn runnable_action( | |||
193 | ModuleDef::Function(func) => { | 192 | ModuleDef::Function(func) => { |
194 | let src = func.source(sema.db)?; | 193 | let src = func.source(sema.db)?; |
195 | if src.file_id != file_id.into() { | 194 | if src.file_id != file_id.into() { |
196 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 195 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
197 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 196 | cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
198 | return None; | 197 | return None; |
199 | } | 198 | } |
200 | 199 | ||
@@ -2101,7 +2100,7 @@ pub fn fo$0o() {} | |||
2101 | 2100 | ||
2102 | #[test] | 2101 | #[test] |
2103 | fn test_hover_macro_generated_struct_fn_doc_comment() { | 2102 | fn test_hover_macro_generated_struct_fn_doc_comment() { |
2104 | mark::check!(hover_macro_generated_struct_fn_doc_comment); | 2103 | cov_mark::check!(hover_macro_generated_struct_fn_doc_comment); |
2105 | 2104 | ||
2106 | check( | 2105 | check( |
2107 | r#" | 2106 | r#" |
@@ -2139,7 +2138,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); } | |||
2139 | 2138 | ||
2140 | #[test] | 2139 | #[test] |
2141 | fn test_hover_macro_generated_struct_fn_doc_attr() { | 2140 | fn test_hover_macro_generated_struct_fn_doc_attr() { |
2142 | mark::check!(hover_macro_generated_struct_fn_doc_attr); | 2141 | cov_mark::check!(hover_macro_generated_struct_fn_doc_attr); |
2143 | 2142 | ||
2144 | check( | 2143 | check( |
2145 | r#" | 2144 | r#" |
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 7fcae13e0..20a920ddb 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs | |||
@@ -7,7 +7,7 @@ use syntax::{ | |||
7 | SyntaxKind::{self, USE_TREE, WHITESPACE}, | 7 | SyntaxKind::{self, USE_TREE, WHITESPACE}, |
8 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, | 8 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
9 | }; | 9 | }; |
10 | use test_utils::mark; | 10 | |
11 | use text_edit::{TextEdit, TextEditBuilder}; | 11 | use text_edit::{TextEdit, TextEditBuilder}; |
12 | 12 | ||
13 | // Feature: Join Lines | 13 | // Feature: Join Lines |
@@ -60,7 +60,7 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS | |||
60 | let mut string_open_quote = false; | 60 | let mut string_open_quote = false; |
61 | if let Some(string) = ast::String::cast(token.clone()) { | 61 | if let Some(string) = ast::String::cast(token.clone()) { |
62 | if let Some(range) = string.open_quote_text_range() { | 62 | if let Some(range) = string.open_quote_text_range() { |
63 | mark::hit!(join_string_literal); | 63 | cov_mark::hit!(join_string_literal); |
64 | string_open_quote = range.end() == offset; | 64 | string_open_quote = range.end() == offset; |
65 | } | 65 | } |
66 | } | 66 | } |
@@ -206,7 +206,7 @@ fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str { | |||
206 | #[cfg(test)] | 206 | #[cfg(test)] |
207 | mod tests { | 207 | mod tests { |
208 | use syntax::SourceFile; | 208 | use syntax::SourceFile; |
209 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range, mark}; | 209 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
210 | 210 | ||
211 | use super::*; | 211 | use super::*; |
212 | 212 | ||
@@ -786,7 +786,7 @@ fn foo() { | |||
786 | 786 | ||
787 | #[test] | 787 | #[test] |
788 | fn join_string_literal() { | 788 | fn join_string_literal() { |
789 | mark::check!(join_string_literal); | 789 | cov_mark::check!(join_string_literal); |
790 | check_join_lines( | 790 | check_join_lines( |
791 | r#" | 791 | r#" |
792 | fn main() { | 792 | fn main() { |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b600178ee..f83ed65d5 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -478,7 +478,6 @@ impl Analysis { | |||
478 | position: FilePosition, | 478 | position: FilePosition, |
479 | full_import_path: &str, | 479 | full_import_path: &str, |
480 | imported_name: String, | 480 | imported_name: String, |
481 | import_for_trait_assoc_item: bool, | ||
482 | ) -> Cancelable<Vec<TextEdit>> { | 481 | ) -> Cancelable<Vec<TextEdit>> { |
483 | Ok(self | 482 | Ok(self |
484 | .with_db(|db| { | 483 | .with_db(|db| { |
@@ -488,7 +487,6 @@ impl Analysis { | |||
488 | position, | 487 | position, |
489 | full_import_path, | 488 | full_import_path, |
490 | imported_name, | 489 | imported_name, |
491 | import_for_trait_assoc_item, | ||
492 | ) | 490 | ) |
493 | })? | 491 | })? |
494 | .unwrap_or_default()) | 492 | .unwrap_or_default()) |
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index 1bfa1439d..000c412d9 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs | |||
@@ -2,7 +2,6 @@ use syntax::{ | |||
2 | ast::{self, AstNode}, | 2 | ast::{self, AstNode}, |
3 | SourceFile, SyntaxKind, TextSize, T, | 3 | SourceFile, SyntaxKind, TextSize, T, |
4 | }; | 4 | }; |
5 | use test_utils::mark; | ||
6 | 5 | ||
7 | // Feature: Matching Brace | 6 | // Feature: Matching Brace |
8 | // | 7 | // |
@@ -28,7 +27,7 @@ pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<Text | |||
28 | .next()?; | 27 | .next()?; |
29 | let parent = brace_token.parent(); | 28 | let parent = brace_token.parent(); |
30 | if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { | 29 | if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) { |
31 | mark::hit!(pipes_not_braces); | 30 | cov_mark::hit!(pipes_not_braces); |
32 | return None; | 31 | return None; |
33 | } | 32 | } |
34 | let matching_kind = BRACES[brace_idx ^ 1]; | 33 | let matching_kind = BRACES[brace_idx ^ 1]; |
@@ -63,7 +62,7 @@ mod tests { | |||
63 | do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); | 62 | do_check("fn main() { $0|x: i32| x * 2;}", "fn main() { |x: i32$0| x * 2;}"); |
64 | 63 | ||
65 | { | 64 | { |
66 | mark::check!(pipes_not_braces); | 65 | cov_mark::check!(pipes_not_braces); |
67 | do_check( | 66 | do_check( |
68 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", | 67 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
69 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", | 68 | "fn main() { match 92 { 1 | 2 |$0 3 => 92 } }", |
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index ddbaf22b7..03d71b380 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs | |||
@@ -5,7 +5,6 @@ use syntax::{ | |||
5 | algo::find_node_at_offset, | 5 | algo::find_node_at_offset, |
6 | ast::{self, AstNode}, | 6 | ast::{self, AstNode}, |
7 | }; | 7 | }; |
8 | use test_utils::mark; | ||
9 | 8 | ||
10 | use crate::NavigationTarget; | 9 | use crate::NavigationTarget; |
11 | 10 | ||
@@ -33,7 +32,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na | |||
33 | .item_list() | 32 | .item_list() |
34 | .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) | 33 | .map_or(false, |it| it.syntax().text_range().contains_inclusive(position.offset)) |
35 | { | 34 | { |
36 | mark::hit!(test_resolve_parent_module_on_module_decl); | 35 | cov_mark::hit!(test_resolve_parent_module_on_module_decl); |
37 | module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); | 36 | module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); |
38 | } | 37 | } |
39 | } | 38 | } |
@@ -64,7 +63,6 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { | |||
64 | #[cfg(test)] | 63 | #[cfg(test)] |
65 | mod tests { | 64 | mod tests { |
66 | use ide_db::base_db::FileRange; | 65 | use ide_db::base_db::FileRange; |
67 | use test_utils::mark; | ||
68 | 66 | ||
69 | use crate::fixture; | 67 | use crate::fixture; |
70 | 68 | ||
@@ -92,7 +90,7 @@ $0// empty | |||
92 | 90 | ||
93 | #[test] | 91 | #[test] |
94 | fn test_resolve_parent_module_on_module_decl() { | 92 | fn test_resolve_parent_module_on_module_decl() { |
95 | mark::check!(test_resolve_parent_module_on_module_decl); | 93 | cov_mark::check!(test_resolve_parent_module_on_module_decl); |
96 | check( | 94 | check( |
97 | r#" | 95 | r#" |
98 | //- /lib.rs | 96 | //- /lib.rs |
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 1919639a3..05c73de88 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -14,7 +14,7 @@ use syntax::{ | |||
14 | ast::{self, NameOwner}, | 14 | ast::{self, NameOwner}, |
15 | lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, | 15 | lex_single_syntax_kind, AstNode, SyntaxKind, SyntaxNode, T, |
16 | }; | 16 | }; |
17 | use test_utils::mark; | 17 | |
18 | use text_edit::TextEdit; | 18 | use text_edit::TextEdit; |
19 | 19 | ||
20 | use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; | 20 | use crate::{display::TryToNav, FilePosition, FileSystemEdit, RangeInfo, SourceChange, TextRange}; |
@@ -226,34 +226,36 @@ fn rename_reference( | |||
226 | | (IdentifierKind::Ident, _) | 226 | | (IdentifierKind::Ident, _) |
227 | if def_is_lbl_or_lt => | 227 | if def_is_lbl_or_lt => |
228 | { | 228 | { |
229 | mark::hit!(rename_not_a_lifetime_ident_ref); | 229 | cov_mark::hit!(rename_not_a_lifetime_ident_ref); |
230 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) | 230 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) |
231 | } | 231 | } |
232 | (IdentifierKind::Lifetime, _) if def_is_lbl_or_lt => mark::hit!(rename_lifetime), | 232 | (IdentifierKind::Lifetime, _) if def_is_lbl_or_lt => cov_mark::hit!(rename_lifetime), |
233 | (IdentifierKind::Lifetime, _) => { | 233 | (IdentifierKind::Lifetime, _) => { |
234 | mark::hit!(rename_not_an_ident_ref); | 234 | cov_mark::hit!(rename_not_an_ident_ref); |
235 | bail!("Invalid name `{}`: not an identifier", new_name) | 235 | bail!("Invalid name `{}`: not an identifier", new_name) |
236 | } | 236 | } |
237 | (IdentifierKind::ToSelf, Definition::Local(local)) if local.is_self(sema.db) => { | 237 | (IdentifierKind::ToSelf, Definition::Local(local)) if local.is_self(sema.db) => { |
238 | // no-op | 238 | // no-op |
239 | mark::hit!(rename_self_to_self); | 239 | cov_mark::hit!(rename_self_to_self); |
240 | return Ok(SourceChange::default()); | 240 | return Ok(SourceChange::default()); |
241 | } | 241 | } |
242 | (ident_kind, Definition::Local(local)) if local.is_self(sema.db) => { | 242 | (ident_kind, Definition::Local(local)) if local.is_self(sema.db) => { |
243 | mark::hit!(rename_self_to_param); | 243 | cov_mark::hit!(rename_self_to_param); |
244 | return rename_self_to_param(sema, local, new_name, ident_kind); | 244 | return rename_self_to_param(sema, local, new_name, ident_kind); |
245 | } | 245 | } |
246 | (IdentifierKind::ToSelf, Definition::Local(local)) => { | 246 | (IdentifierKind::ToSelf, Definition::Local(local)) => { |
247 | mark::hit!(rename_to_self); | 247 | cov_mark::hit!(rename_to_self); |
248 | return rename_to_self(sema, local); | 248 | return rename_to_self(sema, local); |
249 | } | 249 | } |
250 | (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name), | 250 | (IdentifierKind::ToSelf, _) => bail!("Invalid name `{}`: not an identifier", new_name), |
251 | (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), | 251 | (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => { |
252 | cov_mark::hit!(rename_ident) | ||
253 | } | ||
252 | } | 254 | } |
253 | 255 | ||
254 | let usages = def.usages(sema).all(); | 256 | let usages = def.usages(sema).all(); |
255 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { | 257 | if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { |
256 | mark::hit!(rename_underscore_multiple); | 258 | cov_mark::hit!(rename_underscore_multiple); |
257 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | 259 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); |
258 | } | 260 | } |
259 | let mut source_change = SourceChange::default(); | 261 | let mut source_change = SourceChange::default(); |
@@ -444,7 +446,7 @@ fn source_edit_from_name_ref( | |||
444 | (Some(field_name), Some(init)) => { | 446 | (Some(field_name), Some(init)) => { |
445 | if field_name == *name_ref { | 447 | if field_name == *name_ref { |
446 | if init.text() == new_name { | 448 | if init.text() == new_name { |
447 | mark::hit!(test_rename_field_put_init_shorthand); | 449 | cov_mark::hit!(test_rename_field_put_init_shorthand); |
448 | // same names, we can use a shorthand here instead. | 450 | // same names, we can use a shorthand here instead. |
449 | // we do not want to erase attributes hence this range start | 451 | // we do not want to erase attributes hence this range start |
450 | let s = field_name.syntax().text_range().start(); | 452 | let s = field_name.syntax().text_range().start(); |
@@ -453,7 +455,7 @@ fn source_edit_from_name_ref( | |||
453 | } | 455 | } |
454 | } else if init == *name_ref { | 456 | } else if init == *name_ref { |
455 | if field_name.text() == new_name { | 457 | if field_name.text() == new_name { |
456 | mark::hit!(test_rename_local_put_init_shorthand); | 458 | cov_mark::hit!(test_rename_local_put_init_shorthand); |
457 | // same names, we can use a shorthand here instead. | 459 | // same names, we can use a shorthand here instead. |
458 | // we do not want to erase attributes hence this range start | 460 | // we do not want to erase attributes hence this range start |
459 | let s = field_name.syntax().text_range().start(); | 461 | let s = field_name.syntax().text_range().start(); |
@@ -467,12 +469,12 @@ fn source_edit_from_name_ref( | |||
467 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the | 469 | // FIXME: instead of splitting the shorthand, recursively trigger a rename of the |
468 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 | 470 | // other name https://github.com/rust-analyzer/rust-analyzer/issues/6547 |
469 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { | 471 | (None, Some(_)) if matches!(def, Definition::Field(_)) => { |
470 | mark::hit!(test_rename_field_in_field_shorthand); | 472 | cov_mark::hit!(test_rename_field_in_field_shorthand); |
471 | let s = name_ref.syntax().text_range().start(); | 473 | let s = name_ref.syntax().text_range().start(); |
472 | Some((TextRange::empty(s), format!("{}: ", new_name))) | 474 | Some((TextRange::empty(s), format!("{}: ", new_name))) |
473 | } | 475 | } |
474 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { | 476 | (None, Some(_)) if matches!(def, Definition::Local(_)) => { |
475 | mark::hit!(test_rename_local_in_field_shorthand); | 477 | cov_mark::hit!(test_rename_local_in_field_shorthand); |
476 | let s = name_ref.syntax().text_range().end(); | 478 | let s = name_ref.syntax().text_range().end(); |
477 | Some((TextRange::empty(s), format!(": {}", new_name))) | 479 | Some((TextRange::empty(s), format!(": {}", new_name))) |
478 | } | 480 | } |
@@ -486,7 +488,7 @@ fn source_edit_from_name_ref( | |||
486 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { | 488 | (Some(field_name), Some(ast::Pat::IdentPat(pat))) if field_name == *name_ref => { |
487 | // field name is being renamed | 489 | // field name is being renamed |
488 | if pat.name().map_or(false, |it| it.text() == new_name) { | 490 | if pat.name().map_or(false, |it| it.text() == new_name) { |
489 | mark::hit!(test_rename_field_put_init_shorthand_pat); | 491 | cov_mark::hit!(test_rename_field_put_init_shorthand_pat); |
490 | // same names, we can use a shorthand here instead/ | 492 | // same names, we can use a shorthand here instead/ |
491 | // we do not want to erase attributes hence this range start | 493 | // we do not want to erase attributes hence this range start |
492 | let s = field_name.syntax().text_range().start(); | 494 | let s = field_name.syntax().text_range().start(); |
@@ -538,7 +540,7 @@ fn source_edit_from_def( | |||
538 | mod tests { | 540 | mod tests { |
539 | use expect_test::{expect, Expect}; | 541 | use expect_test::{expect, Expect}; |
540 | use stdx::trim_indent; | 542 | use stdx::trim_indent; |
541 | use test_utils::{assert_eq_text, mark}; | 543 | use test_utils::assert_eq_text; |
542 | use text_edit::TextEdit; | 544 | use text_edit::TextEdit; |
543 | 545 | ||
544 | use crate::{fixture, FileId}; | 546 | use crate::{fixture, FileId}; |
@@ -627,7 +629,7 @@ mod tests { | |||
627 | 629 | ||
628 | #[test] | 630 | #[test] |
629 | fn test_rename_to_invalid_identifier_lifetime() { | 631 | fn test_rename_to_invalid_identifier_lifetime() { |
630 | mark::check!(rename_not_an_ident_ref); | 632 | cov_mark::check!(rename_not_an_ident_ref); |
631 | check( | 633 | check( |
632 | "'foo", | 634 | "'foo", |
633 | r#"fn main() { let i$0 = 1; }"#, | 635 | r#"fn main() { let i$0 = 1; }"#, |
@@ -637,7 +639,7 @@ mod tests { | |||
637 | 639 | ||
638 | #[test] | 640 | #[test] |
639 | fn test_rename_to_invalid_identifier_lifetime2() { | 641 | fn test_rename_to_invalid_identifier_lifetime2() { |
640 | mark::check!(rename_not_a_lifetime_ident_ref); | 642 | cov_mark::check!(rename_not_a_lifetime_ident_ref); |
641 | check( | 643 | check( |
642 | "foo", | 644 | "foo", |
643 | r#"fn main<'a>(_: &'a$0 ()) {}"#, | 645 | r#"fn main<'a>(_: &'a$0 ()) {}"#, |
@@ -647,7 +649,7 @@ mod tests { | |||
647 | 649 | ||
648 | #[test] | 650 | #[test] |
649 | fn test_rename_to_underscore_invalid() { | 651 | fn test_rename_to_underscore_invalid() { |
650 | mark::check!(rename_underscore_multiple); | 652 | cov_mark::check!(rename_underscore_multiple); |
651 | check( | 653 | check( |
652 | "_", | 654 | "_", |
653 | r#"fn main(foo$0: ()) {foo;}"#, | 655 | r#"fn main(foo$0: ()) {foo;}"#, |
@@ -666,7 +668,7 @@ mod tests { | |||
666 | 668 | ||
667 | #[test] | 669 | #[test] |
668 | fn test_rename_for_local() { | 670 | fn test_rename_for_local() { |
669 | mark::check!(rename_ident); | 671 | cov_mark::check!(rename_ident); |
670 | check( | 672 | check( |
671 | "k", | 673 | "k", |
672 | r#" | 674 | r#" |
@@ -829,7 +831,7 @@ impl Foo { | |||
829 | 831 | ||
830 | #[test] | 832 | #[test] |
831 | fn test_rename_field_in_field_shorthand() { | 833 | fn test_rename_field_in_field_shorthand() { |
832 | mark::check!(test_rename_field_in_field_shorthand); | 834 | cov_mark::check!(test_rename_field_in_field_shorthand); |
833 | check( | 835 | check( |
834 | "j", | 836 | "j", |
835 | r#" | 837 | r#" |
@@ -855,7 +857,7 @@ impl Foo { | |||
855 | 857 | ||
856 | #[test] | 858 | #[test] |
857 | fn test_rename_local_in_field_shorthand() { | 859 | fn test_rename_local_in_field_shorthand() { |
858 | mark::check!(test_rename_local_in_field_shorthand); | 860 | cov_mark::check!(test_rename_local_in_field_shorthand); |
859 | check( | 861 | check( |
860 | "j", | 862 | "j", |
861 | r#" | 863 | r#" |
@@ -1261,7 +1263,7 @@ fn foo(f: foo::Foo) { | |||
1261 | 1263 | ||
1262 | #[test] | 1264 | #[test] |
1263 | fn test_parameter_to_self() { | 1265 | fn test_parameter_to_self() { |
1264 | mark::check!(rename_to_self); | 1266 | cov_mark::check!(rename_to_self); |
1265 | check( | 1267 | check( |
1266 | "self", | 1268 | "self", |
1267 | r#" | 1269 | r#" |
@@ -1401,7 +1403,7 @@ impl Foo { | |||
1401 | 1403 | ||
1402 | #[test] | 1404 | #[test] |
1403 | fn test_owned_self_to_parameter() { | 1405 | fn test_owned_self_to_parameter() { |
1404 | mark::check!(rename_self_to_param); | 1406 | cov_mark::check!(rename_self_to_param); |
1405 | check( | 1407 | check( |
1406 | "foo", | 1408 | "foo", |
1407 | r#" | 1409 | r#" |
@@ -1454,7 +1456,7 @@ impl Foo { | |||
1454 | 1456 | ||
1455 | #[test] | 1457 | #[test] |
1456 | fn test_rename_field_put_init_shorthand() { | 1458 | fn test_rename_field_put_init_shorthand() { |
1457 | mark::check!(test_rename_field_put_init_shorthand); | 1459 | cov_mark::check!(test_rename_field_put_init_shorthand); |
1458 | check( | 1460 | check( |
1459 | "bar", | 1461 | "bar", |
1460 | r#" | 1462 | r#" |
@@ -1476,7 +1478,7 @@ fn foo(bar: i32) -> Foo { | |||
1476 | 1478 | ||
1477 | #[test] | 1479 | #[test] |
1478 | fn test_rename_local_put_init_shorthand() { | 1480 | fn test_rename_local_put_init_shorthand() { |
1479 | mark::check!(test_rename_local_put_init_shorthand); | 1481 | cov_mark::check!(test_rename_local_put_init_shorthand); |
1480 | check( | 1482 | check( |
1481 | "i", | 1483 | "i", |
1482 | r#" | 1484 | r#" |
@@ -1498,7 +1500,7 @@ fn foo(i: i32) -> Foo { | |||
1498 | 1500 | ||
1499 | #[test] | 1501 | #[test] |
1500 | fn test_struct_field_pat_into_shorthand() { | 1502 | fn test_struct_field_pat_into_shorthand() { |
1501 | mark::check!(test_rename_field_put_init_shorthand_pat); | 1503 | cov_mark::check!(test_rename_field_put_init_shorthand_pat); |
1502 | check( | 1504 | check( |
1503 | "baz", | 1505 | "baz", |
1504 | r#" | 1506 | r#" |
@@ -1610,7 +1612,7 @@ fn foo(foo: Foo) { | |||
1610 | 1612 | ||
1611 | #[test] | 1613 | #[test] |
1612 | fn test_rename_lifetimes() { | 1614 | fn test_rename_lifetimes() { |
1613 | mark::check!(rename_lifetime); | 1615 | cov_mark::check!(rename_lifetime); |
1614 | check( | 1616 | check( |
1615 | "'yeeee", | 1617 | "'yeeee", |
1616 | r#" | 1618 | r#" |
@@ -1698,7 +1700,7 @@ fn foo<'a>() -> &'a () { | |||
1698 | 1700 | ||
1699 | #[test] | 1701 | #[test] |
1700 | fn test_self_to_self() { | 1702 | fn test_self_to_self() { |
1701 | mark::check!(rename_self_to_self); | 1703 | cov_mark::check!(rename_self_to_self); |
1702 | check( | 1704 | check( |
1703 | "self", | 1705 | "self", |
1704 | r#" | 1706 | r#" |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 65f60891e..280565563 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -9,7 +9,6 @@ use syntax::{ | |||
9 | ast::{self, AstNode, AttrsOwner}, | 9 | ast::{self, AstNode, AttrsOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | use test_utils::mark; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | display::{ToNav, TryToNav}, | 14 | display::{ToNav, TryToNav}, |
@@ -130,7 +129,9 @@ fn runnables_mod(sema: &Semantics<RootDatabase>, acc: &mut Vec<Runnable>, module | |||
130 | if let hir::ModuleDef::Module(submodule) = def { | 129 | if let hir::ModuleDef::Module(submodule) = def { |
131 | match submodule.definition_source(sema.db).value { | 130 | match submodule.definition_source(sema.db).value { |
132 | hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule), | 131 | hir::ModuleSource::Module(_) => runnables_mod(sema, acc, submodule), |
133 | hir::ModuleSource::SourceFile(_) => mark::hit!(dont_recurse_in_outline_submodules), | 132 | hir::ModuleSource::SourceFile(_) => { |
133 | cov_mark::hit!(dont_recurse_in_outline_submodules) | ||
134 | } | ||
134 | hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable | 135 | hir::ModuleSource::BlockExpr(_) => {} // inner items aren't runnable |
135 | } | 136 | } |
136 | } | 137 | } |
@@ -328,7 +329,6 @@ fn has_test_function_or_multiple_test_submodules( | |||
328 | #[cfg(test)] | 329 | #[cfg(test)] |
329 | mod tests { | 330 | mod tests { |
330 | use expect_test::{expect, Expect}; | 331 | use expect_test::{expect, Expect}; |
331 | use test_utils::mark; | ||
332 | 332 | ||
333 | use crate::fixture; | 333 | use crate::fixture; |
334 | 334 | ||
@@ -1056,7 +1056,7 @@ mod tests { | |||
1056 | 1056 | ||
1057 | #[test] | 1057 | #[test] |
1058 | fn dont_recurse_in_outline_submodules() { | 1058 | fn dont_recurse_in_outline_submodules() { |
1059 | mark::check!(dont_recurse_in_outline_submodules); | 1059 | cov_mark::check!(dont_recurse_in_outline_submodules); |
1060 | check( | 1060 | check( |
1061 | r#" | 1061 | r#" |
1062 | //- /lib.rs | 1062 | //- /lib.rs |
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index 63cd51b69..978c479de 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs | |||
@@ -9,7 +9,7 @@ use syntax::{ | |||
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, TextRange, TextSize, TokenAtOffset, | 10 | SyntaxToken, TextRange, TextSize, TokenAtOffset, |
11 | }; | 11 | }; |
12 | use test_utils::mark; | 12 | |
13 | use text_edit::TextEdit; | 13 | use text_edit::TextEdit; |
14 | 14 | ||
15 | // Feature: On Enter | 15 | // Feature: On Enter |
@@ -55,7 +55,7 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text | |||
55 | // Continuing single-line non-doc comments (like this one :) ) is annoying | 55 | // Continuing single-line non-doc comments (like this one :) ) is annoying |
56 | if prefix == "//" && comment_range.end() == position.offset { | 56 | if prefix == "//" && comment_range.end() == position.offset { |
57 | if comment.text().ends_with(' ') { | 57 | if comment.text().ends_with(' ') { |
58 | mark::hit!(continues_end_of_line_comment_with_space); | 58 | cov_mark::hit!(continues_end_of_line_comment_with_space); |
59 | remove_trailing_whitespace = true; | 59 | remove_trailing_whitespace = true; |
60 | } else if !followed_by_comment(&comment) { | 60 | } else if !followed_by_comment(&comment) { |
61 | return None; | 61 | return None; |
@@ -109,7 +109,7 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | |||
109 | #[cfg(test)] | 109 | #[cfg(test)] |
110 | mod tests { | 110 | mod tests { |
111 | use stdx::trim_indent; | 111 | use stdx::trim_indent; |
112 | use test_utils::{assert_eq_text, mark}; | 112 | use test_utils::assert_eq_text; |
113 | 113 | ||
114 | use crate::fixture; | 114 | use crate::fixture; |
115 | 115 | ||
@@ -238,7 +238,7 @@ fn main() { | |||
238 | 238 | ||
239 | #[test] | 239 | #[test] |
240 | fn continues_end_of_line_comment_with_space() { | 240 | fn continues_end_of_line_comment_with_space() { |
241 | mark::check!(continues_end_of_line_comment_with_space); | 241 | cov_mark::check!(continues_end_of_line_comment_with_space); |
242 | do_check( | 242 | do_check( |
243 | r#" | 243 | r#" |
244 | fn main() { | 244 | fn main() { |
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml index a34bdd6c3..3bf0099a9 100644 --- a/crates/ide_assists/Cargo.toml +++ b/crates/ide_assists/Cargo.toml | |||
@@ -10,6 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = "1.1" | ||
13 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
14 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
15 | either = "1.6.1" | 16 | either = "1.6.1" |
diff --git a/crates/ide_assists/src/handlers/add_turbo_fish.rs b/crates/ide_assists/src/handlers/add_turbo_fish.rs index a08b55ebb..3b6efbab4 100644 --- a/crates/ide_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ide_assists/src/handlers/add_turbo_fish.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use ide_db::defs::{Definition, NameRefClass}; | 1 | use ide_db::defs::{Definition, NameRefClass}; |
2 | use syntax::{ast, AstNode, SyntaxKind, T}; | 2 | use syntax::{ast, AstNode, SyntaxKind, T}; |
3 | use test_utils::mark; | ||
4 | 3 | ||
5 | use crate::{ | 4 | use crate::{ |
6 | assist_context::{AssistContext, Assists}, | 5 | assist_context::{AssistContext, Assists}, |
@@ -30,13 +29,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
30 | if arg_list.args().count() > 0 { | 29 | if arg_list.args().count() > 0 { |
31 | return None; | 30 | return None; |
32 | } | 31 | } |
33 | mark::hit!(add_turbo_fish_after_call); | 32 | cov_mark::hit!(add_turbo_fish_after_call); |
34 | mark::hit!(add_type_ascription_after_call); | 33 | cov_mark::hit!(add_type_ascription_after_call); |
35 | arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) | 34 | arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT) |
36 | })?; | 35 | })?; |
37 | let next_token = ident.next_token()?; | 36 | let next_token = ident.next_token()?; |
38 | if next_token.kind() == T![::] { | 37 | if next_token.kind() == T![::] { |
39 | mark::hit!(add_turbo_fish_one_fish_is_enough); | 38 | cov_mark::hit!(add_turbo_fish_one_fish_is_enough); |
40 | return None; | 39 | return None; |
41 | } | 40 | } |
42 | let name_ref = ast::NameRef::cast(ident.parent())?; | 41 | let name_ref = ast::NameRef::cast(ident.parent())?; |
@@ -50,7 +49,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
50 | }; | 49 | }; |
51 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | 50 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); |
52 | if generics.is_empty() { | 51 | if generics.is_empty() { |
53 | mark::hit!(add_turbo_fish_non_generic); | 52 | cov_mark::hit!(add_turbo_fish_non_generic); |
54 | return None; | 53 | return None; |
55 | } | 54 | } |
56 | 55 | ||
@@ -67,7 +66,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
67 | }, | 66 | }, |
68 | )? | 67 | )? |
69 | } else { | 68 | } else { |
70 | mark::hit!(add_type_ascription_already_typed); | 69 | cov_mark::hit!(add_type_ascription_already_typed); |
71 | } | 70 | } |
72 | } | 71 | } |
73 | 72 | ||
@@ -87,7 +86,6 @@ mod tests { | |||
87 | use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; | 86 | use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; |
88 | 87 | ||
89 | use super::*; | 88 | use super::*; |
90 | use test_utils::mark; | ||
91 | 89 | ||
92 | #[test] | 90 | #[test] |
93 | fn add_turbo_fish_function() { | 91 | fn add_turbo_fish_function() { |
@@ -110,7 +108,7 @@ fn main() { | |||
110 | 108 | ||
111 | #[test] | 109 | #[test] |
112 | fn add_turbo_fish_after_call() { | 110 | fn add_turbo_fish_after_call() { |
113 | mark::check!(add_turbo_fish_after_call); | 111 | cov_mark::check!(add_turbo_fish_after_call); |
114 | check_assist( | 112 | check_assist( |
115 | add_turbo_fish, | 113 | add_turbo_fish, |
116 | r#" | 114 | r#" |
@@ -155,7 +153,7 @@ fn main() { | |||
155 | 153 | ||
156 | #[test] | 154 | #[test] |
157 | fn add_turbo_fish_one_fish_is_enough() { | 155 | fn add_turbo_fish_one_fish_is_enough() { |
158 | mark::check!(add_turbo_fish_one_fish_is_enough); | 156 | cov_mark::check!(add_turbo_fish_one_fish_is_enough); |
159 | check_assist_not_applicable( | 157 | check_assist_not_applicable( |
160 | add_turbo_fish, | 158 | add_turbo_fish, |
161 | r#" | 159 | r#" |
@@ -169,7 +167,7 @@ fn main() { | |||
169 | 167 | ||
170 | #[test] | 168 | #[test] |
171 | fn add_turbo_fish_non_generic() { | 169 | fn add_turbo_fish_non_generic() { |
172 | mark::check!(add_turbo_fish_non_generic); | 170 | cov_mark::check!(add_turbo_fish_non_generic); |
173 | check_assist_not_applicable( | 171 | check_assist_not_applicable( |
174 | add_turbo_fish, | 172 | add_turbo_fish, |
175 | r#" | 173 | r#" |
@@ -203,7 +201,7 @@ fn main() { | |||
203 | 201 | ||
204 | #[test] | 202 | #[test] |
205 | fn add_type_ascription_after_call() { | 203 | fn add_type_ascription_after_call() { |
206 | mark::check!(add_type_ascription_after_call); | 204 | cov_mark::check!(add_type_ascription_after_call); |
207 | check_assist_by_label( | 205 | check_assist_by_label( |
208 | add_turbo_fish, | 206 | add_turbo_fish, |
209 | r#" | 207 | r#" |
@@ -250,7 +248,7 @@ fn main() { | |||
250 | 248 | ||
251 | #[test] | 249 | #[test] |
252 | fn add_type_ascription_already_typed() { | 250 | fn add_type_ascription_already_typed() { |
253 | mark::check!(add_type_ascription_already_typed); | 251 | cov_mark::check!(add_type_ascription_already_typed); |
254 | check_assist( | 252 | check_assist( |
255 | add_turbo_fish, | 253 | add_turbo_fish, |
256 | r#" | 254 | r#" |
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs index 128b1eb56..a1c339603 100644 --- a/crates/ide_assists/src/handlers/apply_demorgan.rs +++ b/crates/ide_assists/src/handlers/apply_demorgan.rs | |||
@@ -1,5 +1,4 @@ | |||
1 | use syntax::ast::{self, AstNode}; | 1 | use syntax::ast::{self, AstNode}; |
2 | use test_utils::mark; | ||
3 | 2 | ||
4 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; | 3 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; |
5 | 4 | ||
@@ -64,10 +63,10 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
64 | edit.replace(lhs_range, not_lhs.syntax().text()); | 63 | edit.replace(lhs_range, not_lhs.syntax().text()); |
65 | edit.replace(rhs_range, not_rhs.syntax().text()); | 64 | edit.replace(rhs_range, not_rhs.syntax().text()); |
66 | if let Some(neg_expr) = neg_expr { | 65 | if let Some(neg_expr) = neg_expr { |
67 | mark::hit!(demorgan_double_negation); | 66 | cov_mark::hit!(demorgan_double_negation); |
68 | edit.replace(neg_expr.op_token().unwrap().text_range(), ""); | 67 | edit.replace(neg_expr.op_token().unwrap().text_range(), ""); |
69 | } else { | 68 | } else { |
70 | mark::hit!(demorgan_double_parens); | 69 | cov_mark::hit!(demorgan_double_parens); |
71 | edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!("); | 70 | edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!("); |
72 | } | 71 | } |
73 | } else { | 72 | } else { |
@@ -90,7 +89,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | |||
90 | #[cfg(test)] | 89 | #[cfg(test)] |
91 | mod tests { | 90 | mod tests { |
92 | use ide_db::helpers::FamousDefs; | 91 | use ide_db::helpers::FamousDefs; |
93 | use test_utils::mark; | ||
94 | 92 | ||
95 | use super::*; | 93 | use super::*; |
96 | 94 | ||
@@ -188,13 +186,13 @@ fn f() { | |||
188 | 186 | ||
189 | #[test] | 187 | #[test] |
190 | fn demorgan_doesnt_double_negation() { | 188 | fn demorgan_doesnt_double_negation() { |
191 | mark::check!(demorgan_double_negation); | 189 | cov_mark::check!(demorgan_double_negation); |
192 | check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }") | 190 | check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }") |
193 | } | 191 | } |
194 | 192 | ||
195 | #[test] | 193 | #[test] |
196 | fn demorgan_doesnt_double_parens() { | 194 | fn demorgan_doesnt_double_parens() { |
197 | mark::check!(demorgan_double_parens); | 195 | cov_mark::check!(demorgan_double_parens); |
198 | check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }") | 196 | check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }") |
199 | } | 197 | } |
200 | } | 198 | } |
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index 1422224ac..7caee8df0 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ide_db::helpers::{ | 1 | use 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 | mod_path_to_ast, | 4 | item_name, mod_path_to_ast, |
5 | }; | 5 | }; |
6 | use syntax::{ast, AstNode, SyntaxNode}; | 6 | use syntax::{ast, AstNode, SyntaxNode}; |
7 | 7 | ||
@@ -92,14 +92,19 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
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 = import_group_message(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 | }; | ||
96 | acc.add_group( | 100 | acc.add_group( |
97 | &group, | 101 | &group, |
98 | AssistId("auto_import", AssistKind::QuickFix), | 102 | AssistId("auto_import", AssistKind::QuickFix), |
99 | format!("Import `{}`", &import), | 103 | format!("Import `{}`", name), |
100 | range, | 104 | range, |
101 | |builder| { | 105 | |builder| { |
102 | let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use); | 106 | let rewriter = |
107 | insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); | ||
103 | builder.rewrite(rewriter); | 108 | builder.rewrite(rewriter); |
104 | }, | 109 | }, |
105 | ); | 110 | ); |
@@ -125,10 +130,10 @@ fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | |||
125 | let name = match import_candidate { | 130 | let name = match import_candidate { |
126 | ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), | 131 | ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()), |
127 | ImportCandidate::TraitAssocItem(candidate) => { | 132 | ImportCandidate::TraitAssocItem(candidate) => { |
128 | format!("Import a trait for item {}", candidate.name.text()) | 133 | format!("Import a trait for item {}", candidate.assoc_item_name.text()) |
129 | } | 134 | } |
130 | ImportCandidate::TraitMethod(candidate) => { | 135 | ImportCandidate::TraitMethod(candidate) => { |
131 | format!("Import a trait for method {}", candidate.name.text()) | 136 | format!("Import a trait for method {}", candidate.assoc_item_name.text()) |
132 | } | 137 | } |
133 | }; | 138 | }; |
134 | GroupLabel(name) | 139 | GroupLabel(name) |
@@ -221,41 +226,6 @@ mod tests { | |||
221 | } | 226 | } |
222 | 227 | ||
223 | #[test] | 228 | #[test] |
224 | fn auto_imports_are_merged() { | ||
225 | check_assist( | ||
226 | auto_import, | ||
227 | r" | ||
228 | use PubMod::PubStruct1; | ||
229 | |||
230 | struct Test { | ||
231 | test: Pub$0Struct2<u8>, | ||
232 | } | ||
233 | |||
234 | pub mod PubMod { | ||
235 | pub struct PubStruct1; | ||
236 | pub struct PubStruct2<T> { | ||
237 | _t: T, | ||
238 | } | ||
239 | } | ||
240 | ", | ||
241 | r" | ||
242 | use PubMod::{PubStruct1, PubStruct2}; | ||
243 | |||
244 | struct Test { | ||
245 | test: PubStruct2<u8>, | ||
246 | } | ||
247 | |||
248 | pub mod PubMod { | ||
249 | pub struct PubStruct1; | ||
250 | pub struct PubStruct2<T> { | ||
251 | _t: T, | ||
252 | } | ||
253 | } | ||
254 | ", | ||
255 | ); | ||
256 | } | ||
257 | |||
258 | #[test] | ||
259 | fn applicable_when_found_multiple_imports() { | 229 | fn applicable_when_found_multiple_imports() { |
260 | check_assist( | 230 | check_assist( |
261 | auto_import, | 231 | auto_import, |
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs index ac8c44124..ec99a5505 100644 --- a/crates/ide_assists/src/handlers/change_visibility.rs +++ b/crates/ide_assists/src/handlers/change_visibility.rs | |||
@@ -4,7 +4,6 @@ use syntax::{ | |||
4 | SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, | 4 | SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, |
5 | T, | 5 | T, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | ||
8 | 7 | ||
9 | use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; | 8 | use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; |
10 | 9 | ||
@@ -56,7 +55,7 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
56 | } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { | 55 | } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() { |
57 | let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?; | 56 | let field = field_name.syntax().ancestors().find_map(ast::RecordField::cast)?; |
58 | if field.name()? != field_name { | 57 | if field.name()? != field_name { |
59 | mark::hit!(change_visibility_field_false_positive); | 58 | cov_mark::hit!(change_visibility_field_false_positive); |
60 | return None; | 59 | return None; |
61 | } | 60 | } |
62 | if field.visibility().is_some() { | 61 | if field.visibility().is_some() { |
@@ -110,8 +109,6 @@ fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> { | |||
110 | 109 | ||
111 | #[cfg(test)] | 110 | #[cfg(test)] |
112 | mod tests { | 111 | mod tests { |
113 | use test_utils::mark; | ||
114 | |||
115 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 112 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
116 | 113 | ||
117 | use super::*; | 114 | use super::*; |
@@ -139,7 +136,7 @@ mod tests { | |||
139 | 136 | ||
140 | #[test] | 137 | #[test] |
141 | fn change_visibility_field_false_positive() { | 138 | fn change_visibility_field_false_positive() { |
142 | mark::check!(change_visibility_field_false_positive); | 139 | cov_mark::check!(change_visibility_field_false_positive); |
143 | check_assist_not_applicable( | 140 | check_assist_not_applicable( |
144 | change_visibility, | 141 | change_visibility, |
145 | r"struct S { field: [(); { let $0x = ();}] }", | 142 | r"struct S { field: [(); { let $0x = ();}] }", |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 8779d8bd1..dd4501709 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -20,7 +20,6 @@ use syntax::{ | |||
20 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, | 20 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, |
21 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, | 21 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, |
22 | }; | 22 | }; |
23 | use test_utils::mark; | ||
24 | 23 | ||
25 | use crate::{ | 24 | use crate::{ |
26 | assist_context::{AssistContext, Assists}, | 25 | assist_context::{AssistContext, Assists}, |
@@ -59,7 +58,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
59 | 58 | ||
60 | let node = ctx.covering_element(); | 59 | let node = ctx.covering_element(); |
61 | if node.kind() == COMMENT { | 60 | if node.kind() == COMMENT { |
62 | mark::hit!(extract_function_in_comment_is_not_applicable); | 61 | cov_mark::hit!(extract_function_in_comment_is_not_applicable); |
63 | return None; | 62 | return None; |
64 | } | 63 | } |
65 | 64 | ||
@@ -197,14 +196,14 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con | |||
197 | if let Some(kind) = expr_err_kind(&expr, ctx) { | 196 | if let Some(kind) = expr_err_kind(&expr, ctx) { |
198 | Some(FlowKind::TryReturn { expr, kind }) | 197 | Some(FlowKind::TryReturn { expr, kind }) |
199 | } else { | 198 | } else { |
200 | mark::hit!(external_control_flow_try_and_return_non_err); | 199 | cov_mark::hit!(external_control_flow_try_and_return_non_err); |
201 | return None; | 200 | return None; |
202 | } | 201 | } |
203 | } | 202 | } |
204 | None => return None, | 203 | None => return None, |
205 | }, | 204 | }, |
206 | (Some(_), _, _, _) => { | 205 | (Some(_), _, _, _) => { |
207 | mark::hit!(external_control_flow_try_and_bc); | 206 | cov_mark::hit!(external_control_flow_try_and_bc); |
208 | return None; | 207 | return None; |
209 | } | 208 | } |
210 | (None, Some(r), None, None) => match r.expr() { | 209 | (None, Some(r), None, None) => match r.expr() { |
@@ -212,11 +211,11 @@ fn external_control_flow(ctx: &AssistContext, body: &FunctionBody) -> Option<Con | |||
212 | None => Some(FlowKind::Return), | 211 | None => Some(FlowKind::Return), |
213 | }, | 212 | }, |
214 | (None, Some(_), _, _) => { | 213 | (None, Some(_), _, _) => { |
215 | mark::hit!(external_control_flow_return_and_bc); | 214 | cov_mark::hit!(external_control_flow_return_and_bc); |
216 | return None; | 215 | return None; |
217 | } | 216 | } |
218 | (None, None, Some(_), Some(_)) => { | 217 | (None, None, Some(_), Some(_)) => { |
219 | mark::hit!(external_control_flow_break_and_continue); | 218 | cov_mark::hit!(external_control_flow_break_and_continue); |
220 | return None; | 219 | return None; |
221 | } | 220 | } |
222 | (None, None, Some(b), None) => match b.expr() { | 221 | (None, None, Some(b), None) => match b.expr() { |
@@ -1837,7 +1836,7 @@ fn $0fun_name(n: u32) -> u32 { | |||
1837 | 1836 | ||
1838 | #[test] | 1837 | #[test] |
1839 | fn in_comment_is_not_applicable() { | 1838 | fn in_comment_is_not_applicable() { |
1840 | mark::check!(extract_function_in_comment_is_not_applicable); | 1839 | cov_mark::check!(extract_function_in_comment_is_not_applicable); |
1841 | check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }"); | 1840 | check_assist_not_applicable(extract_function, r"fn main() { 1 + /* $0comment$0 */ 1; }"); |
1842 | } | 1841 | } |
1843 | 1842 | ||
@@ -2822,7 +2821,7 @@ fn $0fun_name(n: i32) -> Result<i32, i64> { | |||
2822 | 2821 | ||
2823 | #[test] | 2822 | #[test] |
2824 | fn break_and_continue() { | 2823 | fn break_and_continue() { |
2825 | mark::check!(external_control_flow_break_and_continue); | 2824 | cov_mark::check!(external_control_flow_break_and_continue); |
2826 | check_assist_not_applicable( | 2825 | check_assist_not_applicable( |
2827 | extract_function, | 2826 | extract_function, |
2828 | r##" | 2827 | r##" |
@@ -2842,7 +2841,7 @@ fn foo() { | |||
2842 | 2841 | ||
2843 | #[test] | 2842 | #[test] |
2844 | fn return_and_break() { | 2843 | fn return_and_break() { |
2845 | mark::check!(external_control_flow_return_and_bc); | 2844 | cov_mark::check!(external_control_flow_return_and_bc); |
2846 | check_assist_not_applicable( | 2845 | check_assist_not_applicable( |
2847 | extract_function, | 2846 | extract_function, |
2848 | r##" | 2847 | r##" |
@@ -3341,7 +3340,7 @@ fn $0fun_name() -> Result<i32, i64> { | |||
3341 | 3340 | ||
3342 | #[test] | 3341 | #[test] |
3343 | fn try_and_break() { | 3342 | fn try_and_break() { |
3344 | mark::check!(external_control_flow_try_and_bc); | 3343 | cov_mark::check!(external_control_flow_try_and_bc); |
3345 | check_assist_not_applicable( | 3344 | check_assist_not_applicable( |
3346 | extract_function, | 3345 | extract_function, |
3347 | r##" | 3346 | r##" |
@@ -3363,7 +3362,7 @@ fn foo() -> Option<()> { | |||
3363 | 3362 | ||
3364 | #[test] | 3363 | #[test] |
3365 | fn try_and_return_ok() { | 3364 | fn try_and_return_ok() { |
3366 | mark::check!(external_control_flow_try_and_return_non_err); | 3365 | cov_mark::check!(external_control_flow_try_and_return_non_err); |
3367 | check_assist_not_applicable( | 3366 | check_assist_not_applicable( |
3368 | extract_function, | 3367 | extract_function, |
3369 | r##" | 3368 | r##" |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index 4f0422e96..335e0ed95 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{AsName, Module, ModuleDef, Name, Variant}; | 4 | use hir::{Module, ModuleDef, Name, Variant}; |
5 | use ide_db::{ | 5 | use ide_db::{ |
6 | defs::Definition, | 6 | defs::Definition, |
7 | helpers::{ | 7 | helpers::{ |
@@ -133,7 +133,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va | |||
133 | ), | 133 | ), |
134 | _ => false, | 134 | _ => false, |
135 | }) | 135 | }) |
136 | .any(|(name, _)| name == variant_name.as_name()) | 136 | .any(|(name, _)| name.to_string() == variant_name.to_string()) |
137 | } | 137 | } |
138 | 138 | ||
139 | fn insert_import( | 139 | fn insert_import( |
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index 312ac7ac4..7a32483dc 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs | |||
@@ -6,7 +6,6 @@ use syntax::{ | |||
6 | }, | 6 | }, |
7 | SyntaxNode, | 7 | SyntaxNode, |
8 | }; | 8 | }; |
9 | use test_utils::mark; | ||
10 | 9 | ||
11 | use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; | 10 | use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; |
12 | 11 | ||
@@ -32,7 +31,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
32 | } | 31 | } |
33 | let node = ctx.covering_element(); | 32 | let node = ctx.covering_element(); |
34 | if node.kind() == COMMENT { | 33 | if node.kind() == COMMENT { |
35 | mark::hit!(extract_var_in_comment_is_not_applicable); | 34 | cov_mark::hit!(extract_var_in_comment_is_not_applicable); |
36 | return None; | 35 | return None; |
37 | } | 36 | } |
38 | let to_extract = node.ancestors().find_map(valid_target_expr)?; | 37 | let to_extract = node.ancestors().find_map(valid_target_expr)?; |
@@ -69,7 +68,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
69 | format_to!(buf, "{}", to_extract.syntax()); | 68 | format_to!(buf, "{}", to_extract.syntax()); |
70 | 69 | ||
71 | if let Anchor::Replace(stmt) = anchor { | 70 | if let Anchor::Replace(stmt) = anchor { |
72 | mark::hit!(test_extract_var_expr_stmt); | 71 | cov_mark::hit!(test_extract_var_expr_stmt); |
73 | if stmt.semicolon_token().is_none() { | 72 | if stmt.semicolon_token().is_none() { |
74 | buf.push_str(";"); | 73 | buf.push_str(";"); |
75 | } | 74 | } |
@@ -142,7 +141,7 @@ impl Anchor { | |||
142 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) | 141 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) |
143 | { | 142 | { |
144 | if expr.syntax() == &node { | 143 | if expr.syntax() == &node { |
145 | mark::hit!(test_extract_var_last_expr); | 144 | cov_mark::hit!(test_extract_var_last_expr); |
146 | return Some(Anchor::Before(node)); | 145 | return Some(Anchor::Before(node)); |
147 | } | 146 | } |
148 | } | 147 | } |
@@ -175,8 +174,6 @@ impl Anchor { | |||
175 | 174 | ||
176 | #[cfg(test)] | 175 | #[cfg(test)] |
177 | mod tests { | 176 | mod tests { |
178 | use test_utils::mark; | ||
179 | |||
180 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 177 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
181 | 178 | ||
182 | use super::*; | 179 | use super::*; |
@@ -199,13 +196,13 @@ fn foo() { | |||
199 | 196 | ||
200 | #[test] | 197 | #[test] |
201 | fn extract_var_in_comment_is_not_applicable() { | 198 | fn extract_var_in_comment_is_not_applicable() { |
202 | mark::check!(extract_var_in_comment_is_not_applicable); | 199 | cov_mark::check!(extract_var_in_comment_is_not_applicable); |
203 | check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }"); | 200 | check_assist_not_applicable(extract_variable, "fn main() { 1 + /* $0comment$0 */ 1; }"); |
204 | } | 201 | } |
205 | 202 | ||
206 | #[test] | 203 | #[test] |
207 | fn test_extract_var_expr_stmt() { | 204 | fn test_extract_var_expr_stmt() { |
208 | mark::check!(test_extract_var_expr_stmt); | 205 | cov_mark::check!(test_extract_var_expr_stmt); |
209 | check_assist( | 206 | check_assist( |
210 | extract_variable, | 207 | extract_variable, |
211 | r#" | 208 | r#" |
@@ -250,7 +247,7 @@ fn foo() { | |||
250 | 247 | ||
251 | #[test] | 248 | #[test] |
252 | fn test_extract_var_last_expr() { | 249 | fn test_extract_var_last_expr() { |
253 | mark::check!(test_extract_var_last_expr); | 250 | cov_mark::check!(test_extract_var_last_expr); |
254 | check_assist( | 251 | check_assist( |
255 | extract_variable, | 252 | extract_variable, |
256 | r#" | 253 | r#" |
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 7086e47d2..878b3a3fa 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -5,7 +5,6 @@ use ide_db::helpers::{mod_path_to_ast, FamousDefs}; | |||
5 | use ide_db::RootDatabase; | 5 | use ide_db::RootDatabase; |
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; | 7 | use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; |
8 | use test_utils::mark; | ||
9 | 8 | ||
10 | use crate::{ | 9 | use crate::{ |
11 | utils::{does_pat_match_variant, render_snippet, Cursor}, | 10 | utils::{does_pat_match_variant, render_snippet, Cursor}, |
@@ -62,7 +61,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
62 | .collect::<Vec<_>>(); | 61 | .collect::<Vec<_>>(); |
63 | if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { | 62 | if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { |
64 | // Match `Some` variant first. | 63 | // Match `Some` variant first. |
65 | mark::hit!(option_order); | 64 | cov_mark::hit!(option_order); |
66 | variants.reverse() | 65 | variants.reverse() |
67 | } | 66 | } |
68 | variants | 67 | variants |
@@ -195,7 +194,6 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio | |||
195 | #[cfg(test)] | 194 | #[cfg(test)] |
196 | mod tests { | 195 | mod tests { |
197 | use ide_db::helpers::FamousDefs; | 196 | use ide_db::helpers::FamousDefs; |
198 | use test_utils::mark; | ||
199 | 197 | ||
200 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 198 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
201 | 199 | ||
@@ -730,7 +728,7 @@ fn main() { | |||
730 | 728 | ||
731 | #[test] | 729 | #[test] |
732 | fn option_order() { | 730 | fn option_order() { |
733 | mark::check!(option_order); | 731 | cov_mark::check!(option_order); |
734 | let before = r#" | 732 | let before = r#" |
735 | fn foo(opt: Option<i32>) { | 733 | fn foo(opt: Option<i32>) { |
736 | match opt$0 { | 734 | match opt$0 { |
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs index 6a2ab9596..588ee1350 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use ide_db::helpers::FamousDefs; | 1 | use ide_db::helpers::FamousDefs; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | use test_utils::mark; | ||
5 | 4 | ||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
7 | 6 | ||
@@ -38,12 +37,12 @@ pub(crate) fn generate_default_from_enum_variant( | |||
38 | let variant_name = variant.name()?; | 37 | let variant_name = variant.name()?; |
39 | let enum_name = variant.parent_enum().name()?; | 38 | let enum_name = variant.parent_enum().name()?; |
40 | if !matches!(variant.kind(), ast::StructKind::Unit) { | 39 | if !matches!(variant.kind(), ast::StructKind::Unit) { |
41 | mark::hit!(test_gen_default_on_non_unit_variant_not_implemented); | 40 | cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented); |
42 | return None; | 41 | return None; |
43 | } | 42 | } |
44 | 43 | ||
45 | if existing_default_impl(&ctx.sema, &variant).is_some() { | 44 | if existing_default_impl(&ctx.sema, &variant).is_some() { |
46 | mark::hit!(test_gen_default_impl_already_exists); | 45 | cov_mark::hit!(test_gen_default_impl_already_exists); |
47 | return None; | 46 | return None; |
48 | } | 47 | } |
49 | 48 | ||
@@ -89,8 +88,6 @@ fn existing_default_impl( | |||
89 | 88 | ||
90 | #[cfg(test)] | 89 | #[cfg(test)] |
91 | mod tests { | 90 | mod tests { |
92 | use test_utils::mark; | ||
93 | |||
94 | use crate::tests::{check_assist, check_assist_not_applicable}; | 91 | use crate::tests::{check_assist, check_assist_not_applicable}; |
95 | 92 | ||
96 | use super::*; | 93 | use super::*; |
@@ -127,7 +124,7 @@ impl Default for Variant { | |||
127 | 124 | ||
128 | #[test] | 125 | #[test] |
129 | fn test_generate_default_already_implemented() { | 126 | fn test_generate_default_already_implemented() { |
130 | mark::check!(test_gen_default_impl_already_exists); | 127 | cov_mark::check!(test_gen_default_impl_already_exists); |
131 | check_not_applicable( | 128 | check_not_applicable( |
132 | r#" | 129 | r#" |
133 | enum Variant { | 130 | enum Variant { |
@@ -146,7 +143,7 @@ impl Default for Variant { | |||
146 | 143 | ||
147 | #[test] | 144 | #[test] |
148 | fn test_add_from_impl_no_element() { | 145 | fn test_add_from_impl_no_element() { |
149 | mark::check!(test_gen_default_on_non_unit_variant_not_implemented); | 146 | cov_mark::check!(test_gen_default_on_non_unit_variant_not_implemented); |
150 | check_not_applicable( | 147 | check_not_applicable( |
151 | r#" | 148 | r#" |
152 | enum Variant { | 149 | enum Variant { |
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index fa1254579..81c54ba3e 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs | |||
@@ -7,7 +7,6 @@ use syntax::{ | |||
7 | ast::{self, Impl, NameOwner}, | 7 | ast::{self, Impl, NameOwner}, |
8 | AstNode, | 8 | AstNode, |
9 | }; | 9 | }; |
10 | use test_utils::mark; | ||
11 | 10 | ||
12 | // Assist: generate_default_from_new | 11 | // Assist: generate_default_from_new |
13 | // | 12 | // |
@@ -43,19 +42,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) | |||
43 | let fn_name = fn_node.name()?; | 42 | let fn_name = fn_node.name()?; |
44 | 43 | ||
45 | if fn_name.text() != "new" { | 44 | if fn_name.text() != "new" { |
46 | mark::hit!(other_function_than_new); | 45 | cov_mark::hit!(other_function_than_new); |
47 | return None; | 46 | return None; |
48 | } | 47 | } |
49 | 48 | ||
50 | if fn_node.param_list()?.params().next().is_some() { | 49 | if fn_node.param_list()?.params().next().is_some() { |
51 | mark::hit!(new_function_with_parameters); | 50 | cov_mark::hit!(new_function_with_parameters); |
52 | return None; | 51 | return None; |
53 | } | 52 | } |
54 | 53 | ||
55 | let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; | 54 | let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; |
56 | if is_default_implemented(ctx, &impl_) { | 55 | if is_default_implemented(ctx, &impl_) { |
57 | mark::hit!(default_block_is_already_present); | 56 | cov_mark::hit!(default_block_is_already_present); |
58 | mark::hit!(struct_in_module_with_default); | 57 | cov_mark::hit!(struct_in_module_with_default); |
59 | return None; | 58 | return None; |
60 | } | 59 | } |
61 | 60 | ||
@@ -178,7 +177,7 @@ impl Default for Test { | |||
178 | 177 | ||
179 | #[test] | 178 | #[test] |
180 | fn new_function_with_parameters() { | 179 | fn new_function_with_parameters() { |
181 | mark::check!(new_function_with_parameters); | 180 | cov_mark::check!(new_function_with_parameters); |
182 | check_not_applicable( | 181 | check_not_applicable( |
183 | r#" | 182 | r#" |
184 | struct Example { _inner: () } | 183 | struct Example { _inner: () } |
@@ -194,7 +193,7 @@ impl Example { | |||
194 | 193 | ||
195 | #[test] | 194 | #[test] |
196 | fn other_function_than_new() { | 195 | fn other_function_than_new() { |
197 | mark::check!(other_function_than_new); | 196 | cov_mark::check!(other_function_than_new); |
198 | check_not_applicable( | 197 | check_not_applicable( |
199 | r#" | 198 | r#" |
200 | struct Example { _inner: () } | 199 | struct Example { _inner: () } |
@@ -211,7 +210,7 @@ impl Example { | |||
211 | 210 | ||
212 | #[test] | 211 | #[test] |
213 | fn default_block_is_already_present() { | 212 | fn default_block_is_already_present() { |
214 | mark::check!(default_block_is_already_present); | 213 | cov_mark::check!(default_block_is_already_present); |
215 | check_not_applicable( | 214 | check_not_applicable( |
216 | r#" | 215 | r#" |
217 | struct Example { _inner: () } | 216 | struct Example { _inner: () } |
@@ -340,7 +339,7 @@ impl Default for Example { | |||
340 | 339 | ||
341 | #[test] | 340 | #[test] |
342 | fn struct_in_module_with_default() { | 341 | fn struct_in_module_with_default() { |
343 | mark::check!(struct_in_module_with_default); | 342 | cov_mark::check!(struct_in_module_with_default); |
344 | check_not_applicable( | 343 | check_not_applicable( |
345 | r#" | 344 | r#" |
346 | mod test { | 345 | mod test { |
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs index d9388a737..c13c6eebe 100644 --- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use ide_db::helpers::FamousDefs; | 1 | use ide_db::helpers::FamousDefs; |
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::ast::{self, AstNode, NameOwner}; | 3 | use syntax::ast::{self, AstNode, NameOwner}; |
4 | use test_utils::mark; | ||
5 | 4 | ||
6 | use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; | 5 | use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; |
7 | 6 | ||
@@ -44,7 +43,7 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext | |||
44 | }; | 43 | }; |
45 | 44 | ||
46 | if existing_from_impl(&ctx.sema, &variant).is_some() { | 45 | if existing_from_impl(&ctx.sema, &variant).is_some() { |
47 | mark::hit!(test_add_from_impl_already_exists); | 46 | cov_mark::hit!(test_add_from_impl_already_exists); |
48 | return None; | 47 | return None; |
49 | } | 48 | } |
50 | 49 | ||
@@ -103,8 +102,6 @@ fn existing_from_impl( | |||
103 | 102 | ||
104 | #[cfg(test)] | 103 | #[cfg(test)] |
105 | mod tests { | 104 | mod tests { |
106 | use test_utils::mark; | ||
107 | |||
108 | use crate::tests::{check_assist, check_assist_not_applicable}; | 105 | use crate::tests::{check_assist, check_assist_not_applicable}; |
109 | 106 | ||
110 | use super::*; | 107 | use super::*; |
@@ -172,7 +169,7 @@ impl From<u32> for A { | |||
172 | 169 | ||
173 | #[test] | 170 | #[test] |
174 | fn test_add_from_impl_already_exists() { | 171 | fn test_add_from_impl_already_exists() { |
175 | mark::check!(test_add_from_impl_already_exists); | 172 | cov_mark::check!(test_add_from_impl_already_exists); |
176 | check_not_applicable( | 173 | check_not_applicable( |
177 | r#" | 174 | r#" |
178 | enum A { $0One(u32), } | 175 | enum A { $0One(u32), } |
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs index 3870b7e75..6f95b1a07 100644 --- a/crates/ide_assists/src/handlers/generate_function.rs +++ b/crates/ide_assists/src/handlers/generate_function.rs | |||
@@ -83,17 +83,18 @@ struct FunctionTemplate { | |||
83 | leading_ws: String, | 83 | leading_ws: String, |
84 | fn_def: ast::Fn, | 84 | fn_def: ast::Fn, |
85 | ret_type: ast::RetType, | 85 | ret_type: ast::RetType, |
86 | should_render_snippet: bool, | ||
86 | trailing_ws: String, | 87 | trailing_ws: String, |
87 | file: FileId, | 88 | file: FileId, |
88 | } | 89 | } |
89 | 90 | ||
90 | impl FunctionTemplate { | 91 | impl FunctionTemplate { |
91 | fn to_string(&self, cap: Option<SnippetCap>) -> String { | 92 | fn to_string(&self, cap: Option<SnippetCap>) -> String { |
92 | let f = match cap { | 93 | let f = match (cap, self.should_render_snippet) { |
93 | Some(cap) => { | 94 | (Some(cap), true) => { |
94 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) | 95 | render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax())) |
95 | } | 96 | } |
96 | None => self.fn_def.to_string(), | 97 | _ => self.fn_def.to_string(), |
97 | }; | 98 | }; |
98 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) | 99 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) |
99 | } | 100 | } |
@@ -104,6 +105,8 @@ struct FunctionBuilder { | |||
104 | fn_name: ast::Name, | 105 | fn_name: ast::Name, |
105 | type_params: Option<ast::GenericParamList>, | 106 | type_params: Option<ast::GenericParamList>, |
106 | params: ast::ParamList, | 107 | params: ast::ParamList, |
108 | ret_type: ast::RetType, | ||
109 | should_render_snippet: bool, | ||
107 | file: FileId, | 110 | file: FileId, |
108 | needs_pub: bool, | 111 | needs_pub: bool, |
109 | } | 112 | } |
@@ -132,7 +135,43 @@ impl FunctionBuilder { | |||
132 | let fn_name = fn_name(&path)?; | 135 | let fn_name = fn_name(&path)?; |
133 | let (type_params, params) = fn_args(ctx, target_module, &call)?; | 136 | let (type_params, params) = fn_args(ctx, target_module, &call)?; |
134 | 137 | ||
135 | Some(Self { target, fn_name, type_params, params, file, needs_pub }) | 138 | // should_render_snippet intends to express a rough level of confidence about |
139 | // the correctness of the return type. | ||
140 | // | ||
141 | // If we are able to infer some return type, and that return type is not unit, we | ||
142 | // don't want to render the snippet. The assumption here is in this situation the | ||
143 | // return type is just as likely to be correct as any other part of the generated | ||
144 | // function. | ||
145 | // | ||
146 | // In the case where the return type is inferred as unit it is likely that the | ||
147 | // user does in fact intend for this generated function to return some non unit | ||
148 | // type, but that the current state of their code doesn't allow that return type | ||
149 | // to be accurately inferred. | ||
150 | let (ret_ty, should_render_snippet) = { | ||
151 | match ctx.sema.type_of_expr(&ast::Expr::CallExpr(call.clone())) { | ||
152 | Some(ty) if ty.is_unknown() || ty.is_unit() => (make::ty_unit(), true), | ||
153 | Some(ty) => { | ||
154 | let rendered = ty.display_source_code(ctx.db(), target_module.into()); | ||
155 | match rendered { | ||
156 | Ok(rendered) => (make::ty(&rendered), false), | ||
157 | Err(_) => (make::ty_unit(), true), | ||
158 | } | ||
159 | } | ||
160 | None => (make::ty_unit(), true), | ||
161 | } | ||
162 | }; | ||
163 | let ret_type = make::ret_type(ret_ty); | ||
164 | |||
165 | Some(Self { | ||
166 | target, | ||
167 | fn_name, | ||
168 | type_params, | ||
169 | params, | ||
170 | ret_type, | ||
171 | should_render_snippet, | ||
172 | file, | ||
173 | needs_pub, | ||
174 | }) | ||
136 | } | 175 | } |
137 | 176 | ||
138 | fn render(self) -> FunctionTemplate { | 177 | fn render(self) -> FunctionTemplate { |
@@ -145,7 +184,7 @@ impl FunctionBuilder { | |||
145 | self.type_params, | 184 | self.type_params, |
146 | self.params, | 185 | self.params, |
147 | fn_body, | 186 | fn_body, |
148 | Some(make::ret_type(make::ty_unit())), | 187 | Some(self.ret_type), |
149 | ); | 188 | ); |
150 | let leading_ws; | 189 | let leading_ws; |
151 | let trailing_ws; | 190 | let trailing_ws; |
@@ -171,6 +210,7 @@ impl FunctionBuilder { | |||
171 | insert_offset, | 210 | insert_offset, |
172 | leading_ws, | 211 | leading_ws, |
173 | ret_type: fn_def.ret_type().unwrap(), | 212 | ret_type: fn_def.ret_type().unwrap(), |
213 | should_render_snippet: self.should_render_snippet, | ||
174 | fn_def, | 214 | fn_def, |
175 | trailing_ws, | 215 | trailing_ws, |
176 | file: self.file, | 216 | file: self.file, |
@@ -546,7 +586,7 @@ impl Baz { | |||
546 | } | 586 | } |
547 | } | 587 | } |
548 | 588 | ||
549 | fn bar(baz: Baz) ${0:-> ()} { | 589 | fn bar(baz: Baz) -> Baz { |
550 | todo!() | 590 | todo!() |
551 | } | 591 | } |
552 | ", | 592 | ", |
@@ -1060,6 +1100,27 @@ pub(crate) fn bar() ${0:-> ()} { | |||
1060 | } | 1100 | } |
1061 | 1101 | ||
1062 | #[test] | 1102 | #[test] |
1103 | fn add_function_with_return_type() { | ||
1104 | check_assist( | ||
1105 | generate_function, | ||
1106 | r" | ||
1107 | fn main() { | ||
1108 | let x: u32 = foo$0(); | ||
1109 | } | ||
1110 | ", | ||
1111 | r" | ||
1112 | fn main() { | ||
1113 | let x: u32 = foo(); | ||
1114 | } | ||
1115 | |||
1116 | fn foo() -> u32 { | ||
1117 | todo!() | ||
1118 | } | ||
1119 | ", | ||
1120 | ) | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1063 | fn add_function_not_applicable_if_function_already_exists() { | 1124 | fn add_function_not_applicable_if_function_already_exists() { |
1064 | check_assist_not_applicable( | 1125 | check_assist_not_applicable( |
1065 | generate_function, | 1126 |