diff options
Diffstat (limited to 'crates')
196 files changed, 13911 insertions, 8649 deletions
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index c7ce0c42f..1b259682d 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs | |||
@@ -28,6 +28,12 @@ impl AsRef<Path> for AbsPathBuf { | |||
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | impl AsRef<AbsPath> for AbsPathBuf { | ||
32 | fn as_ref(&self) -> &AbsPath { | ||
33 | self.as_path() | ||
34 | } | ||
35 | } | ||
36 | |||
31 | impl TryFrom<PathBuf> for AbsPathBuf { | 37 | impl TryFrom<PathBuf> for AbsPathBuf { |
32 | type Error = PathBuf; | 38 | type Error = PathBuf; |
33 | fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { | 39 | fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { |
@@ -45,9 +51,19 @@ impl TryFrom<&str> for AbsPathBuf { | |||
45 | } | 51 | } |
46 | } | 52 | } |
47 | 53 | ||
54 | impl PartialEq<AbsPath> for AbsPathBuf { | ||
55 | fn eq(&self, other: &AbsPath) -> bool { | ||
56 | self.as_path() == other | ||
57 | } | ||
58 | } | ||
59 | |||
48 | impl AbsPathBuf { | 60 | impl AbsPathBuf { |
61 | pub fn assert(path: PathBuf) -> AbsPathBuf { | ||
62 | AbsPathBuf::try_from(path) | ||
63 | .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display())) | ||
64 | } | ||
49 | pub fn as_path(&self) -> &AbsPath { | 65 | pub fn as_path(&self) -> &AbsPath { |
50 | AbsPath::new_unchecked(self.0.as_path()) | 66 | AbsPath::assert(self.0.as_path()) |
51 | } | 67 | } |
52 | pub fn pop(&mut self) -> bool { | 68 | pub fn pop(&mut self) -> bool { |
53 | self.0.pop() | 69 | self.0.pop() |
@@ -77,21 +93,99 @@ impl<'a> TryFrom<&'a Path> for &'a AbsPath { | |||
77 | if !path.is_absolute() { | 93 | if !path.is_absolute() { |
78 | return Err(path); | 94 | return Err(path); |
79 | } | 95 | } |
80 | Ok(AbsPath::new_unchecked(path)) | 96 | Ok(AbsPath::assert(path)) |
81 | } | 97 | } |
82 | } | 98 | } |
83 | 99 | ||
84 | impl AbsPath { | 100 | impl AbsPath { |
85 | fn new_unchecked(path: &Path) -> &AbsPath { | 101 | pub fn assert(path: &Path) -> &AbsPath { |
102 | assert!(path.is_absolute()); | ||
86 | unsafe { &*(path as *const Path as *const AbsPath) } | 103 | unsafe { &*(path as *const Path as *const AbsPath) } |
87 | } | 104 | } |
88 | 105 | ||
106 | pub fn parent(&self) -> Option<&AbsPath> { | ||
107 | self.0.parent().map(AbsPath::assert) | ||
108 | } | ||
89 | pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { | 109 | pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { |
90 | self.as_ref().join(path).try_into().unwrap() | 110 | self.as_ref().join(path).try_into().unwrap() |
91 | } | 111 | } |
92 | pub fn normalize(&self) -> AbsPathBuf { | 112 | pub fn normalize(&self) -> AbsPathBuf { |
93 | AbsPathBuf(normalize_path(&self.0)) | 113 | AbsPathBuf(normalize_path(&self.0)) |
94 | } | 114 | } |
115 | pub fn to_path_buf(&self) -> AbsPathBuf { | ||
116 | AbsPathBuf::try_from(self.0.to_path_buf()).unwrap() | ||
117 | } | ||
118 | pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> { | ||
119 | self.0.strip_prefix(base).ok().map(RelPath::new_unchecked) | ||
120 | } | ||
121 | } | ||
122 | |||
123 | #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] | ||
124 | pub struct RelPathBuf(PathBuf); | ||
125 | |||
126 | impl From<RelPathBuf> for PathBuf { | ||
127 | fn from(RelPathBuf(path_buf): RelPathBuf) -> PathBuf { | ||
128 | path_buf | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl ops::Deref for RelPathBuf { | ||
133 | type Target = RelPath; | ||
134 | fn deref(&self) -> &RelPath { | ||
135 | self.as_path() | ||
136 | } | ||
137 | } | ||
138 | |||
139 | impl AsRef<Path> for RelPathBuf { | ||
140 | fn as_ref(&self) -> &Path { | ||
141 | self.0.as_path() | ||
142 | } | ||
143 | } | ||
144 | |||
145 | impl TryFrom<PathBuf> for RelPathBuf { | ||
146 | type Error = PathBuf; | ||
147 | fn try_from(path_buf: PathBuf) -> Result<RelPathBuf, PathBuf> { | ||
148 | if !path_buf.is_relative() { | ||
149 | return Err(path_buf); | ||
150 | } | ||
151 | Ok(RelPathBuf(path_buf)) | ||
152 | } | ||
153 | } | ||
154 | |||
155 | impl TryFrom<&str> for RelPathBuf { | ||
156 | type Error = PathBuf; | ||
157 | fn try_from(path: &str) -> Result<RelPathBuf, PathBuf> { | ||
158 | RelPathBuf::try_from(PathBuf::from(path)) | ||
159 | } | ||
160 | } | ||
161 | |||
162 | impl RelPathBuf { | ||
163 | pub fn as_path(&self) -> &RelPath { | ||
164 | RelPath::new_unchecked(self.0.as_path()) | ||
165 | } | ||
166 | } | ||
167 | |||
168 | #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] | ||
169 | #[repr(transparent)] | ||
170 | pub struct RelPath(Path); | ||
171 | |||
172 | impl ops::Deref for RelPath { | ||
173 | type Target = Path; | ||
174 | fn deref(&self) -> &Path { | ||
175 | &self.0 | ||
176 | } | ||
177 | } | ||
178 | |||
179 | impl AsRef<Path> for RelPath { | ||
180 | fn as_ref(&self) -> &Path { | ||
181 | &self.0 | ||
182 | } | ||
183 | } | ||
184 | |||
185 | impl RelPath { | ||
186 | pub fn new_unchecked(path: &Path) -> &RelPath { | ||
187 | unsafe { &*(path as *const Path as *const RelPath) } | ||
188 | } | ||
95 | } | 189 | } |
96 | 190 | ||
97 | // https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85 | 191 | // https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85 |
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs index 441fbb3cb..3169aa5b8 100644 --- a/crates/ra_arena/src/lib.rs +++ b/crates/ra_arena/src/lib.rs | |||
@@ -116,6 +116,9 @@ impl<T> Arena<T> { | |||
116 | ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { | 116 | ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { |
117 | self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) | 117 | self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) |
118 | } | 118 | } |
119 | pub fn shrink_to_fit(&mut self) { | ||
120 | self.data.shrink_to_fit(); | ||
121 | } | ||
119 | } | 122 | } |
120 | 123 | ||
121 | impl<T> Default for Arena<T> { | 124 | impl<T> Default for Arena<T> { |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 776bddf91..b0e56e1b5 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -128,7 +128,7 @@ impl From<foo::bar::baz::Boo> for A { | |||
128 | 128 | ||
129 | fn check_not_applicable(ra_fixture: &str) { | 129 | fn check_not_applicable(ra_fixture: &str) { |
130 | let fixture = | 130 | let fixture = |
131 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | 131 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); |
132 | check_assist_not_applicable(add_from_impl_for_enum, &fixture) | 132 | check_assist_not_applicable(add_from_impl_for_enum, &fixture) |
133 | } | 133 | } |
134 | 134 | ||
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 5092bf336..d1cafa7d9 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -488,16 +488,17 @@ mod tests { | |||
488 | check_assist( | 488 | check_assist( |
489 | auto_import, | 489 | auto_import, |
490 | r" | 490 | r" |
491 | //- /lib.rs crate:crate_with_macro | 491 | //- /lib.rs crate:crate_with_macro |
492 | #[macro_export] | 492 | #[macro_export] |
493 | macro_rules! foo { | 493 | macro_rules! foo { |
494 | () => () | 494 | () => () |
495 | } | 495 | } |
496 | 496 | ||
497 | //- /main.rs crate:main deps:crate_with_macro | 497 | //- /main.rs crate:main deps:crate_with_macro |
498 | fn main() { | 498 | fn main() { |
499 | foo<|> | 499 | foo<|> |
500 | }", | 500 | } |
501 | ", | ||
501 | r"use crate_with_macro::foo; | 502 | r"use crate_with_macro::foo; |
502 | 503 | ||
503 | fn main() { | 504 | fn main() { |
@@ -847,13 +848,14 @@ fn main() { | |||
847 | check_assist( | 848 | check_assist( |
848 | auto_import, | 849 | auto_import, |
849 | r" | 850 | r" |
850 | //- /lib.rs crate:dep | 851 | //- /lib.rs crate:dep |
851 | pub struct Struct; | 852 | pub struct Struct; |
852 | 853 | ||
853 | //- /main.rs crate:main deps:dep | 854 | //- /main.rs crate:main deps:dep |
854 | fn main() { | 855 | fn main() { |
855 | Struct<|> | 856 | Struct<|> |
856 | }", | 857 | } |
858 | ", | ||
857 | r"use dep::Struct; | 859 | r"use dep::Struct; |
858 | 860 | ||
859 | fn main() { | 861 | fn main() { |
@@ -869,20 +871,22 @@ fn main() { | |||
869 | check_assist( | 871 | check_assist( |
870 | auto_import, | 872 | auto_import, |
871 | r" | 873 | r" |
872 | //- /lib.rs crate:dep | 874 | //- /lib.rs crate:dep |
873 | pub mod fmt { | 875 | pub mod fmt { |
874 | pub trait Display {} | 876 | pub trait Display {} |
875 | } | 877 | } |
876 | 878 | ||
877 | pub fn panic_fmt() {} | 879 | pub fn panic_fmt() {} |
878 | 880 | ||
879 | //- /main.rs crate:main deps:dep | 881 | //- /main.rs crate:main deps:dep |
880 | struct S; | 882 | struct S; |
881 | 883 | ||
882 | impl f<|>mt::Display for S {}", | 884 | impl f<|>mt::Display for S {} |
885 | ", | ||
883 | r"use dep::fmt; | 886 | r"use dep::fmt; |
884 | 887 | ||
885 | struct S; | 888 | struct S; |
889 | |||
886 | impl fmt::Display for S {} | 890 | impl fmt::Display for S {} |
887 | ", | 891 | ", |
888 | ); | 892 | ); |
@@ -894,21 +898,20 @@ impl fmt::Display for S {} | |||
894 | check_assist( | 898 | check_assist( |
895 | auto_import, | 899 | auto_import, |
896 | r" | 900 | r" |
897 | //- /lib.rs crate:dep | 901 | //- /lib.rs crate:dep |
898 | 902 | macro_rules! mac { | |
899 | macro_rules! mac { | 903 | () => { |
900 | () => { | 904 | pub struct Cheese; |
901 | pub struct Cheese; | 905 | }; |
902 | }; | 906 | } |
903 | } | ||
904 | |||
905 | mac!(); | ||
906 | 907 | ||
907 | //- /main.rs crate:main deps:dep | 908 | mac!(); |
908 | 909 | ||
909 | fn main() { | 910 | //- /main.rs crate:main deps:dep |
910 | Cheese<|>; | 911 | fn main() { |
911 | }", | 912 | Cheese<|>; |
913 | } | ||
914 | ", | ||
912 | r"use dep::Cheese; | 915 | r"use dep::Cheese; |
913 | 916 | ||
914 | fn main() { | 917 | fn main() { |
@@ -924,16 +927,15 @@ fn main() { | |||
924 | check_assist( | 927 | check_assist( |
925 | auto_import, | 928 | auto_import, |
926 | r" | 929 | r" |
927 | //- /lib.rs crate:dep | 930 | //- /lib.rs crate:dep |
928 | 931 | pub struct FMT; | |
929 | pub struct FMT; | 932 | pub struct fmt; |
930 | pub struct fmt; | ||
931 | |||
932 | //- /main.rs crate:main deps:dep | ||
933 | 933 | ||
934 | fn main() { | 934 | //- /main.rs crate:main deps:dep |
935 | FMT<|>; | 935 | fn main() { |
936 | }", | 936 | FMT<|>; |
937 | } | ||
938 | ", | ||
937 | r"use dep::FMT; | 939 | r"use dep::FMT; |
938 | 940 | ||
939 | fn main() { | 941 | fn main() { |
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs index 44db7917a..43b4584b4 100644 --- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -301,7 +301,7 @@ fn another_fn() { | |||
301 | 301 | ||
302 | fn check_not_applicable(ra_fixture: &str) { | 302 | fn check_not_applicable(ra_fixture: &str) { |
303 | let fixture = | 303 | let fixture = |
304 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | 304 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); |
305 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) | 305 | check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) |
306 | } | 306 | } |
307 | 307 | ||
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 569efb768..64270c86f 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -763,9 +763,9 @@ mod tests { | |||
763 | fn foo(opt: Option<i32>) { | 763 | fn foo(opt: Option<i32>) { |
764 | match opt<|> { | 764 | match opt<|> { |
765 | } | 765 | } |
766 | }"#; | 766 | } |
767 | let before = | 767 | "#; |
768 | &format!("//- main.rs crate:main deps:core\n{}{}", before, FamousDefs::FIXTURE); | 768 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); |
769 | 769 | ||
770 | check_assist( | 770 | check_assist( |
771 | fill_match_arms, | 771 | fill_match_arms, |
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index 531b3560f..54601d1f3 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs | |||
@@ -255,15 +255,14 @@ mod tests { | |||
255 | check_assist( | 255 | check_assist( |
256 | fix_visibility, | 256 | fix_visibility, |
257 | r" | 257 | r" |
258 | //- /main.rs | 258 | //- /main.rs |
259 | mod foo; | 259 | mod foo; |
260 | fn main() { foo::Foo<|> } | 260 | fn main() { foo::Foo<|> } |
261 | 261 | ||
262 | //- /foo.rs | 262 | //- /foo.rs |
263 | struct Foo; | 263 | struct Foo; |
264 | ", | 264 | ", |
265 | r"$0pub(crate) struct Foo; | 265 | r"$0pub(crate) struct Foo; |
266 | |||
267 | ", | 266 | ", |
268 | ); | 267 | ); |
269 | } | 268 | } |
@@ -279,14 +278,14 @@ mod tests { | |||
279 | ); | 278 | ); |
280 | check_assist( | 279 | check_assist( |
281 | fix_visibility, | 280 | fix_visibility, |
282 | r"//- /lib.rs | 281 | r" |
283 | mod foo; | 282 | //- /lib.rs |
284 | fn main() { foo::Foo { <|>bar: () }; } | 283 | mod foo; |
285 | //- /foo.rs | 284 | fn main() { foo::Foo { <|>bar: () }; } |
286 | pub struct Foo { bar: () } | 285 | //- /foo.rs |
287 | ", | 286 | pub struct Foo { bar: () } |
287 | ", | ||
288 | r"pub struct Foo { $0pub(crate) bar: () } | 288 | r"pub struct Foo { $0pub(crate) bar: () } |
289 | |||
290 | ", | 289 | ", |
291 | ); | 290 | ); |
292 | check_assist_not_applicable( | 291 | check_assist_not_applicable( |
@@ -296,12 +295,13 @@ mod tests { | |||
296 | ); | 295 | ); |
297 | check_assist_not_applicable( | 296 | check_assist_not_applicable( |
298 | fix_visibility, | 297 | fix_visibility, |
299 | r"//- /lib.rs | 298 | r" |
300 | mod foo; | 299 | //- /lib.rs |
301 | fn main() { foo::Foo { <|>bar: () }; } | 300 | mod foo; |
302 | //- /foo.rs | 301 | fn main() { foo::Foo { <|>bar: () }; } |
303 | pub struct Foo { pub bar: () } | 302 | //- /foo.rs |
304 | ", | 303 | pub struct Foo { pub bar: () } |
304 | ", | ||
305 | ); | 305 | ); |
306 | } | 306 | } |
307 | 307 | ||
@@ -316,14 +316,14 @@ mod tests { | |||
316 | ); | 316 | ); |
317 | check_assist( | 317 | check_assist( |
318 | fix_visibility, | 318 | fix_visibility, |
319 | r"//- /lib.rs | 319 | r" |
320 | mod foo; | 320 | //- /lib.rs |
321 | fn main() { foo::Foo::Bar { <|>bar: () }; } | 321 | mod foo; |
322 | //- /foo.rs | 322 | fn main() { foo::Foo::Bar { <|>bar: () }; } |
323 | pub enum Foo { Bar { bar: () } } | 323 | //- /foo.rs |
324 | ", | 324 | pub enum Foo { Bar { bar: () } } |
325 | ", | ||
325 | r"pub enum Foo { Bar { $0pub(crate) bar: () } } | 326 | r"pub enum Foo { Bar { $0pub(crate) bar: () } } |
326 | |||
327 | ", | 327 | ", |
328 | ); | 328 | ); |
329 | check_assist_not_applicable( | 329 | check_assist_not_applicable( |
@@ -333,12 +333,13 @@ mod tests { | |||
333 | ); | 333 | ); |
334 | check_assist_not_applicable( | 334 | check_assist_not_applicable( |
335 | fix_visibility, | 335 | fix_visibility, |
336 | r"//- /lib.rs | 336 | r" |
337 | mod foo; | 337 | //- /lib.rs |
338 | fn main() { foo::Foo { <|>bar: () }; } | 338 | mod foo; |
339 | //- /foo.rs | 339 | fn main() { foo::Foo { <|>bar: () }; } |
340 | pub struct Foo { pub bar: () } | 340 | //- /foo.rs |
341 | ", | 341 | pub struct Foo { pub bar: () } |
342 | ", | ||
342 | ); | 343 | ); |
343 | } | 344 | } |
344 | 345 | ||
@@ -355,14 +356,14 @@ mod tests { | |||
355 | ); | 356 | ); |
356 | check_assist( | 357 | check_assist( |
357 | fix_visibility, | 358 | fix_visibility, |
358 | r"//- /lib.rs | 359 | r" |
359 | mod foo; | 360 | //- /lib.rs |
360 | fn main() { foo::Foo { <|>bar: () }; } | 361 | mod foo; |
361 | //- /foo.rs | 362 | fn main() { foo::Foo { <|>bar: () }; } |
362 | pub union Foo { bar: () } | 363 | //- /foo.rs |
363 | ", | 364 | pub union Foo { bar: () } |
365 | ", | ||
364 | r"pub union Foo { $0pub(crate) bar: () } | 366 | r"pub union Foo { $0pub(crate) bar: () } |
365 | |||
366 | ", | 367 | ", |
367 | ); | 368 | ); |
368 | check_assist_not_applicable( | 369 | check_assist_not_applicable( |
@@ -372,12 +373,13 @@ mod tests { | |||
372 | ); | 373 | ); |
373 | check_assist_not_applicable( | 374 | check_assist_not_applicable( |
374 | fix_visibility, | 375 | fix_visibility, |
375 | r"//- /lib.rs | 376 | r" |
376 | mod foo; | 377 | //- /lib.rs |
377 | fn main() { foo::Foo { <|>bar: () }; } | 378 | mod foo; |
378 | //- /foo.rs | 379 | fn main() { foo::Foo { <|>bar: () }; } |
379 | pub union Foo { pub bar: () } | 380 | //- /foo.rs |
380 | ", | 381 | pub union Foo { pub bar: () } |
382 | ", | ||
381 | ); | 383 | ); |
382 | } | 384 | } |
383 | 385 | ||
@@ -458,19 +460,18 @@ mod tests { | |||
458 | check_assist( | 460 | check_assist( |
459 | fix_visibility, | 461 | fix_visibility, |
460 | r" | 462 | r" |
461 | //- /main.rs | 463 | //- /main.rs |
462 | mod foo; | 464 | mod foo; |
463 | fn main() { foo::bar<|>::baz(); } | 465 | fn main() { foo::bar<|>::baz(); } |
464 | 466 | ||
465 | //- /foo.rs | 467 | //- /foo.rs |
466 | mod bar { | 468 | mod bar { |
467 | pub fn baz() {} | 469 | pub fn baz() {} |
468 | } | 470 | } |
469 | ", | 471 | ", |
470 | r"$0pub(crate) mod bar { | 472 | r"$0pub(crate) mod bar { |
471 | pub fn baz() {} | 473 | pub fn baz() {} |
472 | } | 474 | } |
473 | |||
474 | ", | 475 | ", |
475 | ); | 476 | ); |
476 | 477 | ||
@@ -486,17 +487,15 @@ mod tests { | |||
486 | check_assist( | 487 | check_assist( |
487 | fix_visibility, | 488 | fix_visibility, |
488 | r" | 489 | r" |
489 | //- /main.rs | 490 | //- /main.rs |
490 | mod foo; | 491 | mod foo; |
491 | fn main() { foo::bar<|>::baz(); } | 492 | fn main() { foo::bar<|>::baz(); } |
492 | 493 | ||
493 | //- /foo.rs | 494 | //- /foo.rs |
494 | mod bar; | 495 | mod bar; |
495 | 496 | //- /foo/bar.rs | |
496 | //- /foo/bar.rs | 497 | pub fn baz() {} |
497 | pub fn baz() {} | 498 | ", |
498 | } | ||
499 | ", | ||
500 | r"$0pub(crate) mod bar; | 499 | r"$0pub(crate) mod bar; |
501 | ", | 500 | ", |
502 | ); | 501 | ); |
@@ -506,14 +505,16 @@ mod tests { | |||
506 | fn fix_visibility_of_module_declaration_in_other_file() { | 505 | fn fix_visibility_of_module_declaration_in_other_file() { |
507 | check_assist( | 506 | check_assist( |
508 | fix_visibility, | 507 | fix_visibility, |
509 | r"//- /main.rs | 508 | r" |
510 | mod foo; | 509 | //- /main.rs |
511 | fn main() { foo::bar<|>>::baz(); } | 510 | mod foo; |
511 | fn main() { foo::bar<|>>::baz(); } | ||
512 | 512 | ||
513 | //- /foo.rs | 513 | //- /foo.rs |
514 | mod bar { | 514 | mod bar { |
515 | pub fn baz() {} | 515 | pub fn baz() {} |
516 | }", | 516 | } |
517 | ", | ||
517 | r"$0pub(crate) mod bar { | 518 | r"$0pub(crate) mod bar { |
518 | pub fn baz() {} | 519 | pub fn baz() {} |
519 | } | 520 | } |
@@ -525,10 +526,12 @@ mod tests { | |||
525 | fn adds_pub_when_target_is_in_another_crate() { | 526 | fn adds_pub_when_target_is_in_another_crate() { |
526 | check_assist( | 527 | check_assist( |
527 | fix_visibility, | 528 | fix_visibility, |
528 | r"//- /main.rs crate:a deps:foo | 529 | r" |
529 | foo::Bar<|> | 530 | //- /main.rs crate:a deps:foo |
530 | //- /lib.rs crate:foo | 531 | foo::Bar<|> |
531 | struct Bar;", | 532 | //- /lib.rs crate:foo |
533 | struct Bar; | ||
534 | ", | ||
532 | r"$0pub struct Bar; | 535 | r"$0pub struct Bar; |
533 | ", | 536 | ", |
534 | ) | 537 | ) |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 31d6539f7..88b62278f 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -226,27 +226,31 @@ fn foo() { | |||
226 | mark::check!(test_introduce_var_last_expr); | 226 | mark::check!(test_introduce_var_last_expr); |
227 | check_assist( | 227 | check_assist( |
228 | introduce_variable, | 228 | introduce_variable, |
229 | " | 229 | r#" |
230 | fn foo() { | 230 | fn foo() { |
231 | bar(<|>1 + 1<|>) | 231 | bar(<|>1 + 1<|>) |
232 | }", | 232 | } |
233 | " | 233 | "#, |
234 | r#" | ||
234 | fn foo() { | 235 | fn foo() { |
235 | let $0var_name = 1 + 1; | 236 | let $0var_name = 1 + 1; |
236 | bar(var_name) | 237 | bar(var_name) |
237 | }", | 238 | } |
239 | "#, | ||
238 | ); | 240 | ); |
239 | check_assist( | 241 | check_assist( |
240 | introduce_variable, | 242 | introduce_variable, |
241 | " | 243 | r#" |
242 | fn foo() { | 244 | fn foo() { |
243 | <|>bar(1 + 1)<|> | 245 | <|>bar(1 + 1)<|> |
244 | }", | 246 | } |
245 | " | 247 | "#, |
248 | r#" | ||
246 | fn foo() { | 249 | fn foo() { |
247 | let $0var_name = bar(1 + 1); | 250 | let $0var_name = bar(1 + 1); |
248 | var_name | 251 | var_name |
249 | }", | 252 | } |
253 | "#, | ||
250 | ) | 254 | ) |
251 | } | 255 | } |
252 | 256 | ||
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 972d16241..ac0b3035c 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -127,7 +127,7 @@ fn first_path(path: &ast::Path) -> ast::Path { | |||
127 | 127 | ||
128 | #[cfg(test)] | 128 | #[cfg(test)] |
129 | mod tests { | 129 | mod tests { |
130 | use crate::tests::check_assist; | 130 | use crate::tests::{check_assist, check_assist_not_applicable}; |
131 | 131 | ||
132 | use super::*; | 132 | use super::*; |
133 | 133 | ||
@@ -276,4 +276,14 @@ bar::baz}; | |||
276 | ", | 276 | ", |
277 | ) | 277 | ) |
278 | } | 278 | } |
279 | |||
280 | #[test] | ||
281 | fn test_empty_use() { | ||
282 | check_assist_not_applicable( | ||
283 | merge_imports, | ||
284 | r" | ||
285 | use std::<|> | ||
286 | fn main() {}", | ||
287 | ); | ||
288 | } | ||
279 | } | 289 | } |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 16002d2ac..d22d0aa55 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -158,16 +158,16 @@ mod test { | |||
158 | check_assist( | 158 | check_assist( |
159 | make_raw_string, | 159 | make_raw_string, |
160 | r#" | 160 | r#" |
161 | fn f() { | 161 | fn f() { |
162 | let s = <|>"random\nstring"; | 162 | let s = <|>"random\nstring"; |
163 | } | 163 | } |
164 | "#, | 164 | "#, |
165 | r##" | 165 | r##" |
166 | fn f() { | 166 | fn f() { |
167 | let s = r#"random | 167 | let s = r#"random |
168 | string"#; | 168 | string"#; |
169 | } | 169 | } |
170 | "##, | 170 | "##, |
171 | ) | 171 | ) |
172 | } | 172 | } |
173 | 173 | ||
@@ -193,16 +193,16 @@ string"#; | |||
193 | check_assist( | 193 | check_assist( |
194 | make_raw_string, | 194 | make_raw_string, |
195 | r###" | 195 | r###" |
196 | fn f() { | 196 | fn f() { |
197 | let s = <|>"#random##\nstring"; | 197 | let s = <|>"#random##\nstring"; |
198 | } | 198 | } |
199 | "###, | 199 | "###, |
200 | r####" | 200 | r####" |
201 | fn f() { | 201 | fn f() { |
202 | let s = r#"#random## | 202 | let s = r#"#random## |
203 | string"#; | 203 | string"#; |
204 | } | 204 | } |
205 | "####, | 205 | "####, |
206 | ) | 206 | ) |
207 | } | 207 | } |
208 | 208 | ||
@@ -211,16 +211,16 @@ string"#; | |||
211 | check_assist( | 211 | check_assist( |
212 | make_raw_string, | 212 | make_raw_string, |
213 | r###" | 213 | r###" |
214 | fn f() { | 214 | fn f() { |
215 | let s = <|>"#random\"##\nstring"; | 215 | let s = <|>"#random\"##\nstring"; |
216 | } | 216 | } |
217 | "###, | 217 | "###, |
218 | r####" | 218 | r####" |
219 | fn f() { | 219 | fn f() { |
220 | let s = r###"#random"## | 220 | let s = r###"#random"## |
221 | string"###; | 221 | string"###; |
222 | } | 222 | } |
223 | "####, | 223 | "####, |
224 | ) | 224 | ) |
225 | } | 225 | } |
226 | 226 | ||
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index c7a874480..38aa199a0 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -66,4 +66,14 @@ mod tests { | |||
66 | fn issue4044() { | 66 | fn issue4044() { |
67 | check_assist_not_applicable(split_import, "use crate::<|>:::self;") | 67 | check_assist_not_applicable(split_import, "use crate::<|>:::self;") |
68 | } | 68 | } |
69 | |||
70 | #[test] | ||
71 | fn test_empty_use() { | ||
72 | check_assist_not_applicable( | ||
73 | split_import, | ||
74 | r" | ||
75 | use std::<|> | ||
76 | fn main() {}", | ||
77 | ); | ||
78 | } | ||
69 | } | 79 | } |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 62dd3547f..858f5ca80 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -1,27 +1,21 @@ | |||
1 | mod generated; | 1 | mod generated; |
2 | 2 | ||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir::Semantics; | 3 | use hir::Semantics; |
6 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 4 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
7 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 5 | use ra_ide_db::RootDatabase; |
8 | use ra_syntax::TextRange; | 6 | use ra_syntax::TextRange; |
9 | use test_utils::{ | 7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
10 | assert_eq_text, extract_offset, extract_range, extract_range_or_offset, RangeOrOffset, | ||
11 | }; | ||
12 | 8 | ||
13 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; | 9 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; |
10 | use stdx::trim_indent; | ||
14 | 11 | ||
15 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 12 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
16 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 13 | RootDatabase::with_single_file(text) |
17 | // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`, | ||
18 | // but it looks like this might need specialization? :( | ||
19 | db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)])); | ||
20 | (db, file_id) | ||
21 | } | 14 | } |
22 | 15 | ||
23 | pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { | 16 | pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { |
24 | check(assist, ra_fixture_before, ExpectedResult::After(ra_fixture_after)); | 17 | let ra_fixture_after = trim_indent(ra_fixture_after); |
18 | check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after)); | ||
25 | } | 19 | } |
26 | 20 | ||
27 | // FIXME: instead of having a separate function here, maybe use | 21 | // FIXME: instead of having a separate function here, maybe use |
@@ -36,8 +30,9 @@ pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) { | |||
36 | } | 30 | } |
37 | 31 | ||
38 | fn check_doc_test(assist_id: &str, before: &str, after: &str) { | 32 | fn check_doc_test(assist_id: &str, before: &str, after: &str) { |
39 | let (selection, before) = extract_range_or_offset(before); | 33 | let after = trim_indent(after); |
40 | let (db, file_id) = crate::tests::with_single_file(&before); | 34 | let (db, file_id, selection) = RootDatabase::with_range_or_offset(&before); |
35 | let before = db.file_text(file_id).to_string(); | ||
41 | let frange = FileRange { file_id, range: selection.into() }; | 36 | let frange = FileRange { file_id, range: selection.into() }; |
42 | 37 | ||
43 | let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) | 38 | let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) |
@@ -57,11 +52,11 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
57 | 52 | ||
58 | let actual = { | 53 | let actual = { |
59 | let change = assist.source_change.source_file_edits.pop().unwrap(); | 54 | let change = assist.source_change.source_file_edits.pop().unwrap(); |
60 | let mut actual = before.clone(); | 55 | let mut actual = before; |
61 | change.edit.apply(&mut actual); | 56 | change.edit.apply(&mut actual); |
62 | actual | 57 | actual |
63 | }; | 58 | }; |
64 | assert_eq_text!(after, &actual); | 59 | assert_eq_text!(&after, &actual); |
65 | } | 60 | } |
66 | 61 | ||
67 | enum ExpectedResult<'a> { | 62 | enum ExpectedResult<'a> { |
@@ -71,20 +66,8 @@ enum ExpectedResult<'a> { | |||
71 | } | 66 | } |
72 | 67 | ||
73 | fn check(handler: Handler, before: &str, expected: ExpectedResult) { | 68 | fn check(handler: Handler, before: &str, expected: ExpectedResult) { |
74 | let (text_without_caret, file_with_caret_id, range_or_offset, db) = if before.contains("//-") { | 69 | let (db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before); |
75 | let (mut db, position) = RootDatabase::with_position(before); | 70 | let text_without_caret = db.file_text(file_with_caret_id).to_string(); |
76 | db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)])); | ||
77 | ( | ||
78 | db.file_text(position.file_id).as_ref().to_owned(), | ||
79 | position.file_id, | ||
80 | RangeOrOffset::Offset(position.offset), | ||
81 | db, | ||
82 | ) | ||
83 | } else { | ||
84 | let (range_or_offset, text_without_caret) = extract_range_or_offset(before); | ||
85 | let (db, file_id) = with_single_file(&text_without_caret); | ||
86 | (text_without_caret, file_id, range_or_offset, db) | ||
87 | }; | ||
88 | 71 | ||
89 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; | 72 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; |
90 | 73 | ||
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index c1ff0de7b..b7c45a619 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -198,8 +198,7 @@ pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, | |||
198 | #[allow(non_snake_case)] | 198 | #[allow(non_snake_case)] |
199 | impl FamousDefs<'_, '_> { | 199 | impl FamousDefs<'_, '_> { |
200 | #[cfg(test)] | 200 | #[cfg(test)] |
201 | pub(crate) const FIXTURE: &'static str = r#" | 201 | pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core |
202 | //- /libcore.rs crate:core | ||
203 | pub mod convert { | 202 | pub mod convert { |
204 | pub trait From<T> { | 203 | pub trait From<T> { |
205 | fn from(T) -> Self; | 204 | fn from(T) -> Self; |
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 8ab409158..372fb242b 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml | |||
@@ -17,3 +17,5 @@ ra_cfg = { path = "../ra_cfg" } | |||
17 | ra_prof = { path = "../ra_prof" } | 17 | ra_prof = { path = "../ra_prof" } |
18 | ra_tt = { path = "../ra_tt" } | 18 | ra_tt = { path = "../ra_tt" } |
19 | test_utils = { path = "../test_utils" } | 19 | test_utils = { path = "../test_utils" } |
20 | vfs = { path = "../vfs" } | ||
21 | stdx = { path = "../stdx" } | ||
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 482a2f3e6..4f4fb4494 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -57,17 +57,16 @@ | |||
57 | //! fn insert_source_code_here() {} | 57 | //! fn insert_source_code_here() {} |
58 | //! " | 58 | //! " |
59 | //! ``` | 59 | //! ``` |
60 | 60 | use std::{str::FromStr, sync::Arc}; | |
61 | use std::str::FromStr; | ||
62 | use std::sync::Arc; | ||
63 | 61 | ||
64 | use ra_cfg::CfgOptions; | 62 | use ra_cfg::CfgOptions; |
65 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; | 64 | use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; |
65 | use vfs::{file_set::FileSet, VfsPath}; | ||
67 | 66 | ||
68 | use crate::{ | 67 | use crate::{ |
69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 68 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt, |
70 | SourceDatabaseExt, SourceRoot, SourceRootId, | 69 | SourceRoot, SourceRootId, |
71 | }; | 70 | }; |
72 | 71 | ||
73 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 72 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
@@ -75,21 +74,32 @@ pub const WORKSPACE: SourceRootId = SourceRootId(0); | |||
75 | pub trait WithFixture: Default + SourceDatabaseExt + 'static { | 74 | pub trait WithFixture: Default + SourceDatabaseExt + 'static { |
76 | fn with_single_file(text: &str) -> (Self, FileId) { | 75 | fn with_single_file(text: &str) -> (Self, FileId) { |
77 | let mut db = Self::default(); | 76 | let mut db = Self::default(); |
78 | let file_id = with_single_file(&mut db, text); | 77 | let (_, files) = with_files(&mut db, text); |
79 | (db, file_id) | 78 | assert_eq!(files.len(), 1); |
79 | (db, files[0]) | ||
80 | } | 80 | } |
81 | 81 | ||
82 | fn with_files(ra_fixture: &str) -> Self { | 82 | fn with_files(ra_fixture: &str) -> Self { |
83 | let mut db = Self::default(); | 83 | let mut db = Self::default(); |
84 | let pos = with_files(&mut db, ra_fixture); | 84 | let (pos, _) = with_files(&mut db, ra_fixture); |
85 | assert!(pos.is_none()); | 85 | assert!(pos.is_none()); |
86 | db | 86 | db |
87 | } | 87 | } |
88 | 88 | ||
89 | fn with_position(ra_fixture: &str) -> (Self, FilePosition) { | 89 | fn with_position(ra_fixture: &str) -> (Self, FilePosition) { |
90 | let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); | ||
91 | let offset = match range_or_offset { | ||
92 | RangeOrOffset::Range(_) => panic!(), | ||
93 | RangeOrOffset::Offset(it) => it, | ||
94 | }; | ||
95 | (db, FilePosition { file_id, offset }) | ||
96 | } | ||
97 | |||
98 | fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) { | ||
90 | let mut db = Self::default(); | 99 | let mut db = Self::default(); |
91 | let pos = with_files(&mut db, ra_fixture); | 100 | let (pos, _) = with_files(&mut db, ra_fixture); |
92 | (db, pos.unwrap()) | 101 | let (file_id, range_or_offset) = pos.unwrap(); |
102 | (db, file_id, range_or_offset) | ||
93 | } | 103 | } |
94 | 104 | ||
95 | fn test_crate(&self) -> CrateId { | 105 | fn test_crate(&self) -> CrateId { |
@@ -103,83 +113,36 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
103 | 113 | ||
104 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | 114 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} |
105 | 115 | ||
106 | fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId { | 116 | fn with_files( |
107 | let file_id = FileId(0); | 117 | db: &mut dyn SourceDatabaseExt, |
108 | let rel_path: RelativePathBuf = "/main.rs".into(); | 118 | fixture: &str, |
109 | 119 | ) -> (Option<(FileId, RangeOrOffset)>, Vec<FileId>) { | |
110 | let mut source_root = SourceRoot::new_local(); | 120 | let fixture = Fixture::parse(fixture); |
111 | source_root.insert_file(rel_path.clone(), file_id); | ||
112 | |||
113 | let fixture = parse_single_fixture(ra_fixture); | ||
114 | |||
115 | let crate_graph = if let Some(entry) = fixture { | ||
116 | let meta = match ParsedMeta::from(&entry.meta) { | ||
117 | ParsedMeta::File(it) => it, | ||
118 | _ => panic!("with_single_file only support file meta"), | ||
119 | }; | ||
120 | |||
121 | let mut crate_graph = CrateGraph::default(); | ||
122 | crate_graph.add_crate_root( | ||
123 | file_id, | ||
124 | meta.edition, | ||
125 | meta.krate.map(|name| { | ||
126 | CrateName::new(&name).expect("Fixture crate name should not contain dashes") | ||
127 | }), | ||
128 | meta.cfg, | ||
129 | meta.env, | ||
130 | Default::default(), | ||
131 | Default::default(), | ||
132 | ); | ||
133 | crate_graph | ||
134 | } else { | ||
135 | let mut crate_graph = CrateGraph::default(); | ||
136 | crate_graph.add_crate_root( | ||
137 | file_id, | ||
138 | Edition::Edition2018, | ||
139 | None, | ||
140 | CfgOptions::default(), | ||
141 | Env::default(), | ||
142 | Default::default(), | ||
143 | Default::default(), | ||
144 | ); | ||
145 | crate_graph | ||
146 | }; | ||
147 | |||
148 | db.set_file_text(file_id, Arc::new(ra_fixture.to_string())); | ||
149 | db.set_file_relative_path(file_id, rel_path); | ||
150 | db.set_file_source_root(file_id, WORKSPACE); | ||
151 | db.set_source_root(WORKSPACE, Arc::new(source_root)); | ||
152 | db.set_crate_graph(Arc::new(crate_graph)); | ||
153 | |||
154 | file_id | ||
155 | } | ||
156 | |||
157 | fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosition> { | ||
158 | let fixture = parse_fixture(fixture); | ||
159 | 121 | ||
122 | let mut files = Vec::new(); | ||
160 | let mut crate_graph = CrateGraph::default(); | 123 | let mut crate_graph = CrateGraph::default(); |
161 | let mut crates = FxHashMap::default(); | 124 | let mut crates = FxHashMap::default(); |
162 | let mut crate_deps = Vec::new(); | 125 | let mut crate_deps = Vec::new(); |
163 | let mut default_crate_root: Option<FileId> = None; | 126 | let mut default_crate_root: Option<FileId> = None; |
164 | 127 | ||
165 | let mut source_root = SourceRoot::new_local(); | 128 | let mut file_set = FileSet::default(); |
166 | let mut source_root_id = WORKSPACE; | 129 | let source_root_id = WORKSPACE; |
167 | let mut source_root_prefix: RelativePathBuf = "/".into(); | 130 | let source_root_prefix = "/".to_string(); |
168 | let mut file_id = FileId(0); | 131 | let mut file_id = FileId(0); |
169 | 132 | ||
170 | let mut file_position = None; | 133 | let mut file_position = None; |
171 | 134 | ||
172 | for entry in fixture.iter() { | 135 | for entry in fixture { |
173 | let meta = match ParsedMeta::from(&entry.meta) { | 136 | let text = if entry.text.contains(CURSOR_MARKER) { |
174 | ParsedMeta::Root { path } => { | 137 | let (range_or_offset, text) = extract_range_or_offset(&entry.text); |
175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); | 138 | assert!(file_position.is_none()); |
176 | db.set_source_root(source_root_id, Arc::new(source_root)); | 139 | file_position = Some((file_id, range_or_offset)); |
177 | source_root_id.0 += 1; | 140 | text.to_string() |
178 | source_root_prefix = path; | 141 | } else { |
179 | continue; | 142 | entry.text.clone() |
180 | } | ||
181 | ParsedMeta::File(it) => it, | ||
182 | }; | 143 | }; |
144 | |||
145 | let meta = FileMeta::from(entry); | ||
183 | assert!(meta.path.starts_with(&source_root_prefix)); | 146 | assert!(meta.path.starts_with(&source_root_prefix)); |
184 | 147 | ||
185 | if let Some(krate) = meta.krate { | 148 | if let Some(krate) = meta.krate { |
@@ -190,7 +153,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
190 | meta.cfg, | 153 | meta.cfg, |
191 | meta.env, | 154 | meta.env, |
192 | Default::default(), | 155 | Default::default(), |
193 | Default::default(), | ||
194 | ); | 156 | ); |
195 | let prev = crates.insert(krate.clone(), crate_id); | 157 | let prev = crates.insert(krate.clone(), crate_id); |
196 | assert!(prev.is_none()); | 158 | assert!(prev.is_none()); |
@@ -202,20 +164,11 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
202 | default_crate_root = Some(file_id); | 164 | default_crate_root = Some(file_id); |
203 | } | 165 | } |
204 | 166 | ||
205 | let text = if entry.text.contains(CURSOR_MARKER) { | ||
206 | let (offset, text) = extract_offset(&entry.text); | ||
207 | assert!(file_position.is_none()); | ||
208 | file_position = Some(FilePosition { file_id, offset }); | ||
209 | text.to_string() | ||
210 | } else { | ||
211 | entry.text.to_string() | ||
212 | }; | ||
213 | |||
214 | db.set_file_text(file_id, Arc::new(text)); | 167 | db.set_file_text(file_id, Arc::new(text)); |
215 | db.set_file_relative_path(file_id, meta.path.clone()); | ||
216 | db.set_file_source_root(file_id, source_root_id); | 168 | db.set_file_source_root(file_id, source_root_id); |
217 | source_root.insert_file(meta.path, file_id); | 169 | let path = VfsPath::new_virtual_path(meta.path); |
218 | 170 | file_set.insert(file_id, path.into()); | |
171 | files.push(file_id); | ||
219 | file_id.0 += 1; | 172 | file_id.0 += 1; |
220 | } | 173 | } |
221 | 174 | ||
@@ -228,7 +181,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
228 | CfgOptions::default(), | 181 | CfgOptions::default(), |
229 | Env::default(), | 182 | Env::default(), |
230 | Default::default(), | 183 | Default::default(), |
231 | Default::default(), | ||
232 | ); | 184 | ); |
233 | } else { | 185 | } else { |
234 | for (from, to) in crate_deps { | 186 | for (from, to) in crate_deps { |
@@ -238,19 +190,14 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
238 | } | 190 | } |
239 | } | 191 | } |
240 | 192 | ||
241 | db.set_source_root(source_root_id, Arc::new(source_root)); | 193 | db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set))); |
242 | db.set_crate_graph(Arc::new(crate_graph)); | 194 | db.set_crate_graph(Arc::new(crate_graph)); |
243 | 195 | ||
244 | file_position | 196 | (file_position, files) |
245 | } | ||
246 | |||
247 | enum ParsedMeta { | ||
248 | Root { path: RelativePathBuf }, | ||
249 | File(FileMeta), | ||
250 | } | 197 | } |
251 | 198 | ||
252 | struct FileMeta { | 199 | struct FileMeta { |
253 | path: RelativePathBuf, | 200 | path: String, |
254 | krate: Option<String>, | 201 | krate: Option<String>, |
255 | deps: Vec<String>, | 202 | deps: Vec<String>, |
256 | cfg: CfgOptions, | 203 | cfg: CfgOptions, |
@@ -258,25 +205,22 @@ struct FileMeta { | |||
258 | env: Env, | 205 | env: Env, |
259 | } | 206 | } |
260 | 207 | ||
261 | impl From<&FixtureMeta> for ParsedMeta { | 208 | impl From<Fixture> for FileMeta { |
262 | fn from(meta: &FixtureMeta) -> Self { | 209 | fn from(f: Fixture) -> FileMeta { |
263 | match meta { | 210 | let mut cfg = CfgOptions::default(); |
264 | FixtureMeta::Root { path } => { | 211 | f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into())); |
265 | // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' | 212 | f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into())); |
266 | // see https://github.com/rust-lang/rust/issues/69018 | 213 | |
267 | ParsedMeta::Root { path: path.to_owned() } | 214 | FileMeta { |
268 | } | 215 | path: f.path, |
269 | FixtureMeta::File(f) => Self::File(FileMeta { | 216 | krate: f.krate, |
270 | path: f.path.to_owned(), | 217 | deps: f.deps, |
271 | krate: f.crate_name.to_owned(), | 218 | cfg, |
272 | deps: f.deps.to_owned(), | 219 | edition: f |
273 | cfg: f.cfg.to_owned(), | 220 | .edition |
274 | edition: f | 221 | .as_ref() |
275 | .edition | 222 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), |
276 | .as_ref() | 223 | env: Env::from(f.env.iter()), |
277 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | ||
278 | env: Env::from(f.env.iter()), | ||
279 | }), | ||
280 | } | 224 | } |
281 | } | 225 | } |
282 | } | 226 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index bf26048f2..7f3660118 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -6,27 +6,15 @@ | |||
6 | //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how | 6 | //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how |
7 | //! actual IO is done and lowered to input. | 7 | //! actual IO is done and lowered to input. |
8 | 8 | ||
9 | use std::{ | 9 | use std::{fmt, ops, str::FromStr, sync::Arc}; |
10 | fmt, ops, | ||
11 | path::{Path, PathBuf}, | ||
12 | str::FromStr, | ||
13 | sync::Arc, | ||
14 | }; | ||
15 | 10 | ||
16 | use ra_cfg::CfgOptions; | 11 | use ra_cfg::CfgOptions; |
17 | use ra_syntax::SmolStr; | 12 | use ra_syntax::SmolStr; |
18 | use ra_tt::TokenExpander; | 13 | use ra_tt::TokenExpander; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 14 | use rustc_hash::{FxHashMap, FxHashSet}; |
15 | use vfs::file_set::FileSet; | ||
20 | 16 | ||
21 | use crate::{RelativePath, RelativePathBuf}; | 17 | pub use vfs::FileId; |
22 | |||
23 | /// `FileId` is an integer which uniquely identifies a file. File paths are | ||
24 | /// messy and system-dependent, so most of the code should work directly with | ||
25 | /// `FileId`, without inspecting the path. The mapping between `FileId` and path | ||
26 | /// and `SourceRoot` is constant. A file rename is represented as a pair of | ||
27 | /// deletion/creation. | ||
28 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
29 | pub struct FileId(pub u32); | ||
30 | 18 | ||
31 | /// Files are grouped into source roots. A source root is a directory on the | 19 | /// Files are grouped into source roots. A source root is a directory on the |
32 | /// file systems which is watched for changes. Typically it corresponds to a | 20 | /// file systems which is watched for changes. Typically it corresponds to a |
@@ -45,27 +33,18 @@ pub struct SourceRoot { | |||
45 | /// Libraries are considered mostly immutable, this assumption is used to | 33 | /// Libraries are considered mostly immutable, this assumption is used to |
46 | /// optimize salsa's query structure | 34 | /// optimize salsa's query structure |
47 | pub is_library: bool, | 35 | pub is_library: bool, |
48 | files: FxHashMap<RelativePathBuf, FileId>, | 36 | pub(crate) file_set: FileSet, |
49 | } | 37 | } |
50 | 38 | ||
51 | impl SourceRoot { | 39 | impl SourceRoot { |
52 | pub fn new_local() -> SourceRoot { | 40 | pub fn new_local(file_set: FileSet) -> SourceRoot { |
53 | SourceRoot { is_library: false, files: Default::default() } | 41 | SourceRoot { is_library: false, file_set } |
54 | } | ||
55 | pub fn new_library() -> SourceRoot { | ||
56 | SourceRoot { is_library: true, files: Default::default() } | ||
57 | } | ||
58 | pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) { | ||
59 | self.files.insert(path, file_id); | ||
60 | } | 42 | } |
61 | pub fn remove_file(&mut self, path: &RelativePath) { | 43 | pub fn new_library(file_set: FileSet) -> SourceRoot { |
62 | self.files.remove(path); | 44 | SourceRoot { is_library: true, file_set } |
63 | } | 45 | } |
64 | pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ { | 46 | pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ { |
65 | self.files.values().copied() | 47 | self.file_set.iter() |
66 | } | ||
67 | pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> { | ||
68 | self.files.get(path).copied() | ||
69 | } | 48 | } |
70 | } | 49 | } |
71 | 50 | ||
@@ -141,7 +120,6 @@ pub struct CrateData { | |||
141 | pub display_name: Option<CrateName>, | 120 | pub display_name: Option<CrateName>, |
142 | pub cfg_options: CfgOptions, | 121 | pub cfg_options: CfgOptions, |
143 | pub env: Env, | 122 | pub env: Env, |
144 | pub extern_source: ExternSource, | ||
145 | pub dependencies: Vec<Dependency>, | 123 | pub dependencies: Vec<Dependency>, |
146 | pub proc_macro: Vec<ProcMacro>, | 124 | pub proc_macro: Vec<ProcMacro>, |
147 | } | 125 | } |
@@ -152,22 +130,11 @@ pub enum Edition { | |||
152 | Edition2015, | 130 | Edition2015, |
153 | } | 131 | } |
154 | 132 | ||
155 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
156 | pub struct ExternSourceId(pub u32); | ||
157 | |||
158 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 133 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
159 | pub struct Env { | 134 | pub struct Env { |
160 | entries: FxHashMap<String, String>, | 135 | entries: FxHashMap<String, String>, |
161 | } | 136 | } |
162 | 137 | ||
163 | // FIXME: Redesign vfs for solve the following limitation ? | ||
164 | // Note: Some env variables (e.g. OUT_DIR) are located outside of the | ||
165 | // crate. We store a map to allow remap it to ExternSourceId | ||
166 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
167 | pub struct ExternSource { | ||
168 | extern_paths: FxHashMap<PathBuf, ExternSourceId>, | ||
169 | } | ||
170 | |||
171 | #[derive(Debug, Clone, PartialEq, Eq)] | 138 | #[derive(Debug, Clone, PartialEq, Eq)] |
172 | pub struct Dependency { | 139 | pub struct Dependency { |
173 | pub crate_id: CrateId, | 140 | pub crate_id: CrateId, |
@@ -182,7 +149,6 @@ impl CrateGraph { | |||
182 | display_name: Option<CrateName>, | 149 | display_name: Option<CrateName>, |
183 | cfg_options: CfgOptions, | 150 | cfg_options: CfgOptions, |
184 | env: Env, | 151 | env: Env, |
185 | extern_source: ExternSource, | ||
186 | proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, | 152 | proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, |
187 | ) -> CrateId { | 153 | ) -> CrateId { |
188 | let proc_macro = | 154 | let proc_macro = |
@@ -194,7 +160,6 @@ impl CrateGraph { | |||
194 | display_name, | 160 | display_name, |
195 | cfg_options, | 161 | cfg_options, |
196 | env, | 162 | env, |
197 | extern_source, | ||
198 | proc_macro, | 163 | proc_macro, |
199 | dependencies: Vec::new(), | 164 | dependencies: Vec::new(), |
200 | }; | 165 | }; |
@@ -254,12 +219,12 @@ impl CrateGraph { | |||
254 | return false; | 219 | return false; |
255 | } | 220 | } |
256 | 221 | ||
222 | if target == from { | ||
223 | return true; | ||
224 | } | ||
225 | |||
257 | for dep in &self[from].dependencies { | 226 | for dep in &self[from].dependencies { |
258 | let crate_id = dep.crate_id; | 227 | let crate_id = dep.crate_id; |
259 | if crate_id == target { | ||
260 | return true; | ||
261 | } | ||
262 | |||
263 | if self.dfs_find(target, crate_id, visited) { | 228 | if self.dfs_find(target, crate_id, visited) { |
264 | return true; | 229 | return true; |
265 | } | 230 | } |
@@ -334,20 +299,6 @@ impl Env { | |||
334 | } | 299 | } |
335 | } | 300 | } |
336 | 301 | ||
337 | impl ExternSource { | ||
338 | pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> { | ||
339 | self.extern_paths.iter().find_map(|(root_path, id)| { | ||
340 | let rel_path = path.strip_prefix(root_path).ok()?; | ||
341 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
342 | Some((*id, rel_path)) | ||
343 | }) | ||
344 | } | ||
345 | |||
346 | pub fn set_extern_path(&mut self, root_path: &Path, root: ExternSourceId) { | ||
347 | self.extern_paths.insert(root_path.to_path_buf(), root); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | #[derive(Debug)] | 302 | #[derive(Debug)] |
352 | pub struct ParseEditionError { | 303 | pub struct ParseEditionError { |
353 | invalid_input: String, | 304 | invalid_input: String, |
@@ -369,7 +320,7 @@ mod tests { | |||
369 | use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; | 320 | use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; |
370 | 321 | ||
371 | #[test] | 322 | #[test] |
372 | fn it_should_panic_because_of_cycle_dependencies() { | 323 | fn detect_cyclic_dependency_indirect() { |
373 | let mut graph = CrateGraph::default(); | 324 | let mut graph = CrateGraph::default(); |
374 | let crate1 = graph.add_crate_root( | 325 | let crate1 = graph.add_crate_root( |
375 | FileId(1u32), | 326 | FileId(1u32), |
@@ -378,7 +329,6 @@ mod tests { | |||
378 | CfgOptions::default(), | 329 | CfgOptions::default(), |
379 | Env::default(), | 330 | Env::default(), |
380 | Default::default(), | 331 | Default::default(), |
381 | Default::default(), | ||
382 | ); | 332 | ); |
383 | let crate2 = graph.add_crate_root( | 333 | let crate2 = graph.add_crate_root( |
384 | FileId(2u32), | 334 | FileId(2u32), |
@@ -387,7 +337,6 @@ mod tests { | |||
387 | CfgOptions::default(), | 337 | CfgOptions::default(), |
388 | Env::default(), | 338 | Env::default(), |
389 | Default::default(), | 339 | Default::default(), |
390 | Default::default(), | ||
391 | ); | 340 | ); |
392 | let crate3 = graph.add_crate_root( | 341 | let crate3 = graph.add_crate_root( |
393 | FileId(3u32), | 342 | FileId(3u32), |
@@ -396,7 +345,6 @@ mod tests { | |||
396 | CfgOptions::default(), | 345 | CfgOptions::default(), |
397 | Env::default(), | 346 | Env::default(), |
398 | Default::default(), | 347 | Default::default(), |
399 | Default::default(), | ||
400 | ); | 348 | ); |
401 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 349 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
402 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 350 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -404,7 +352,7 @@ mod tests { | |||
404 | } | 352 | } |
405 | 353 | ||
406 | #[test] | 354 | #[test] |
407 | fn it_works() { | 355 | fn detect_cyclic_dependency_direct() { |
408 | let mut graph = CrateGraph::default(); | 356 | let mut graph = CrateGraph::default(); |
409 | let crate1 = graph.add_crate_root( | 357 | let crate1 = graph.add_crate_root( |
410 | FileId(1u32), | 358 | FileId(1u32), |
@@ -413,7 +361,6 @@ mod tests { | |||
413 | CfgOptions::default(), | 361 | CfgOptions::default(), |
414 | Env::default(), | 362 | Env::default(), |
415 | Default::default(), | 363 | Default::default(), |
416 | Default::default(), | ||
417 | ); | 364 | ); |
418 | let crate2 = graph.add_crate_root( | 365 | let crate2 = graph.add_crate_root( |
419 | FileId(2u32), | 366 | FileId(2u32), |
@@ -422,6 +369,28 @@ mod tests { | |||
422 | CfgOptions::default(), | 369 | CfgOptions::default(), |
423 | Env::default(), | 370 | Env::default(), |
424 | Default::default(), | 371 | Default::default(), |
372 | ); | ||
373 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | ||
374 | assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err()); | ||
375 | } | ||
376 | |||
377 | #[test] | ||
378 | fn it_works() { | ||
379 | let mut graph = CrateGraph::default(); | ||
380 | let crate1 = graph.add_crate_root( | ||
381 | FileId(1u32), | ||
382 | Edition2018, | ||
383 | None, | ||
384 | CfgOptions::default(), | ||
385 | Env::default(), | ||
386 | Default::default(), | ||
387 | ); | ||
388 | let crate2 = graph.add_crate_root( | ||
389 | FileId(2u32), | ||
390 | Edition2018, | ||
391 | None, | ||
392 | CfgOptions::default(), | ||
393 | Env::default(), | ||
425 | Default::default(), | 394 | Default::default(), |
426 | ); | 395 | ); |
427 | let crate3 = graph.add_crate_root( | 396 | let crate3 = graph.add_crate_root( |
@@ -431,7 +400,6 @@ mod tests { | |||
431 | CfgOptions::default(), | 400 | CfgOptions::default(), |
432 | Env::default(), | 401 | Env::default(), |
433 | Default::default(), | 402 | Default::default(), |
434 | Default::default(), | ||
435 | ); | 403 | ); |
436 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 404 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
437 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 405 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -447,7 +415,6 @@ mod tests { | |||
447 | CfgOptions::default(), | 415 | CfgOptions::default(), |
448 | Env::default(), | 416 | Env::default(), |
449 | Default::default(), | 417 | Default::default(), |
450 | Default::default(), | ||
451 | ); | 418 | ); |
452 | let crate2 = graph.add_crate_root( | 419 | let crate2 = graph.add_crate_root( |
453 | FileId(2u32), | 420 | FileId(2u32), |
@@ -456,7 +423,6 @@ mod tests { | |||
456 | CfgOptions::default(), | 423 | CfgOptions::default(), |
457 | Env::default(), | 424 | Env::default(), |
458 | Default::default(), | 425 | Default::default(), |
459 | Default::default(), | ||
460 | ); | 426 | ); |
461 | assert!(graph | 427 | assert!(graph |
462 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) | 428 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 80ddb6058..4a3ba57da 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -12,12 +12,13 @@ use rustc_hash::FxHashSet; | |||
12 | pub use crate::{ | 12 | pub use crate::{ |
13 | cancellation::Canceled, | 13 | cancellation::Canceled, |
14 | input::{ | 14 | input::{ |
15 | CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, | 15 | CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId, |
16 | ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId, | 16 | SourceRoot, SourceRootId, |
17 | }, | 17 | }, |
18 | }; | 18 | }; |
19 | pub use relative_path::{RelativePath, RelativePathBuf}; | 19 | pub use relative_path::{RelativePath, RelativePathBuf}; |
20 | pub use salsa; | 20 | pub use salsa; |
21 | pub use vfs::{file_set::FileSet, AbsPathBuf, VfsPath}; | ||
21 | 22 | ||
22 | #[macro_export] | 23 | #[macro_export] |
23 | macro_rules! impl_intern_key { | 24 | macro_rules! impl_intern_key { |
@@ -113,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { | |||
113 | } | 114 | } |
114 | 115 | ||
115 | fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { | 116 | fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { |
116 | let _p = profile("parse_query"); | 117 | let _p = profile("parse_query").detail(|| format!("{:?}", file_id)); |
117 | let text = db.file_text(file_id); | 118 | let text = db.file_text(file_id); |
118 | SourceFile::parse(&*text) | 119 | SourceFile::parse(&*text) |
119 | } | 120 | } |
@@ -125,8 +126,6 @@ pub trait SourceDatabaseExt: SourceDatabase { | |||
125 | #[salsa::input] | 126 | #[salsa::input] |
126 | fn file_text(&self, file_id: FileId) -> Arc<String>; | 127 | fn file_text(&self, file_id: FileId) -> Arc<String>; |
127 | /// Path to a file, relative to the root of its source root. | 128 | /// Path to a file, relative to the root of its source root. |
128 | #[salsa::input] | ||
129 | fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf; | ||
130 | /// Source root of the file. | 129 | /// Source root of the file. |
131 | #[salsa::input] | 130 | #[salsa::input] |
132 | fn file_source_root(&self, file_id: FileId) -> SourceRootId; | 131 | fn file_source_root(&self, file_id: FileId) -> SourceRootId; |
@@ -161,24 +160,9 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
161 | } | 160 | } |
162 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 161 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
163 | // FIXME: this *somehow* should be platform agnostic... | 162 | // FIXME: this *somehow* should be platform agnostic... |
164 | if std::path::Path::new(path).is_absolute() { | 163 | let source_root = self.0.file_source_root(anchor); |
165 | let krate = *self.relevant_crates(anchor).iter().next()?; | 164 | let source_root = self.0.source_root(source_root); |
166 | let (extern_source_id, relative_file) = | 165 | source_root.file_set.resolve_path(anchor, path) |
167 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; | ||
168 | |||
169 | let source_root = self.0.source_root(SourceRootId(extern_source_id.0)); | ||
170 | source_root.file_by_relative_path(&relative_file) | ||
171 | } else { | ||
172 | let rel_path = { | ||
173 | let mut rel_path = self.0.file_relative_path(anchor); | ||
174 | assert!(rel_path.pop()); | ||
175 | rel_path.push(path); | ||
176 | rel_path.normalize() | ||
177 | }; | ||
178 | let source_root = self.0.file_source_root(anchor); | ||
179 | let source_root = self.0.source_root(source_root); | ||
180 | source_root.file_by_relative_path(&rel_path) | ||
181 | } | ||
182 | } | 166 | } |
183 | 167 | ||
184 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 168 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 1a9f6cc76..a379b9f49 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -26,15 +26,12 @@ use hir_ty::{ | |||
26 | autoderef, | 26 | autoderef, |
27 | display::{HirDisplayError, HirFormatter}, | 27 | display::{HirDisplayError, HirFormatter}, |
28 | expr::ExprValidator, | 28 | expr::ExprValidator, |
29 | method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, Ty, | 29 | method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, |
30 | TyDefId, TypeCtor, | 30 | TraitEnvironment, Ty, TyDefId, TypeCtor, |
31 | }; | 31 | }; |
32 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 32 | use ra_db::{CrateId, CrateName, Edition, FileId}; |
33 | use ra_prof::profile; | 33 | use ra_prof::profile; |
34 | use ra_syntax::{ | 34 | use ra_syntax::ast::{self, AttrsOwner, NameOwner}; |
35 | ast::{self, AttrsOwner, NameOwner}, | ||
36 | AstNode, | ||
37 | }; | ||
38 | use rustc_hash::FxHashSet; | 35 | use rustc_hash::FxHashSet; |
39 | 36 | ||
40 | use crate::{ | 37 | use crate::{ |
@@ -186,10 +183,27 @@ impl ModuleDef { | |||
186 | 183 | ||
187 | module.visibility_of(db, self) | 184 | module.visibility_of(db, self) |
188 | } | 185 | } |
186 | |||
187 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | ||
188 | match self { | ||
189 | ModuleDef::Adt(it) => Some(it.name(db)), | ||
190 | ModuleDef::Trait(it) => Some(it.name(db)), | ||
191 | ModuleDef::Function(it) => Some(it.name(db)), | ||
192 | ModuleDef::EnumVariant(it) => Some(it.name(db)), | ||
193 | ModuleDef::TypeAlias(it) => Some(it.name(db)), | ||
194 | |||
195 | ModuleDef::Module(it) => it.name(db), | ||
196 | ModuleDef::Const(it) => it.name(db), | ||
197 | ModuleDef::Static(it) => it.name(db), | ||
198 | |||
199 | ModuleDef::BuiltinType(it) => Some(it.as_name()), | ||
200 | } | ||
201 | } | ||
189 | } | 202 | } |
190 | 203 | ||
191 | pub use hir_def::{ | 204 | pub use hir_def::{ |
192 | attr::Attrs, item_scope::ItemInNs, visibility::Visibility, AssocItemId, AssocItemLoc, | 205 | attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility, |
206 | AssocItemId, AssocItemLoc, | ||
193 | }; | 207 | }; |
194 | 208 | ||
195 | impl Module { | 209 | impl Module { |
@@ -856,7 +870,7 @@ where | |||
856 | ID: Lookup<Data = AssocItemLoc<AST>>, | 870 | ID: Lookup<Data = AssocItemLoc<AST>>, |
857 | DEF: From<ID>, | 871 | DEF: From<ID>, |
858 | CTOR: FnOnce(DEF) -> AssocItem, | 872 | CTOR: FnOnce(DEF) -> AssocItem, |
859 | AST: AstNode, | 873 | AST: ItemTreeNode, |
860 | { | 874 | { |
861 | match id.lookup(db.upcast()).container { | 875 | match id.lookup(db.upcast()).container { |
862 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), | 876 | AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), |
@@ -1359,6 +1373,27 @@ impl Type { | |||
1359 | Some(adt.into()) | 1373 | Some(adt.into()) |
1360 | } | 1374 | } |
1361 | 1375 | ||
1376 | pub fn as_dyn_trait(&self) -> Option<Trait> { | ||
1377 | self.ty.value.dyn_trait().map(Into::into) | ||
1378 | } | ||
1379 | |||
1380 | pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { | ||
1381 | self.ty.value.impl_trait_bounds(db).map(|it| { | ||
1382 | it.into_iter() | ||
1383 | .filter_map(|pred| match pred { | ||
1384 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1385 | Some(Trait::from(trait_ref.trait_)) | ||
1386 | } | ||
1387 | _ => None, | ||
1388 | }) | ||
1389 | .collect() | ||
1390 | }) | ||
1391 | } | ||
1392 | |||
1393 | pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1394 | self.ty.value.associated_type_parent_trait(db).map(Into::into) | ||
1395 | } | ||
1396 | |||
1362 | // FIXME: provide required accessors such that it becomes implementable from outside. | 1397 | // FIXME: provide required accessors such that it becomes implementable from outside. |
1363 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { | 1398 | pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { |
1364 | match (&self.ty.value, &other.ty.value) { | 1399 | match (&self.ty.value, &other.ty.value) { |
@@ -1380,6 +1415,80 @@ impl Type { | |||
1380 | ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, | 1415 | ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, |
1381 | } | 1416 | } |
1382 | } | 1417 | } |
1418 | |||
1419 | pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { | ||
1420 | // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself. | ||
1421 | // We need a different order here. | ||
1422 | |||
1423 | fn walk_substs( | ||
1424 | db: &dyn HirDatabase, | ||
1425 | type_: &Type, | ||
1426 | substs: &Substs, | ||
1427 | cb: &mut impl FnMut(Type), | ||
1428 | ) { | ||
1429 | for ty in substs.iter() { | ||
1430 | walk_type(db, &type_.derived(ty.clone()), cb); | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | fn walk_bounds( | ||
1435 | db: &dyn HirDatabase, | ||
1436 | type_: &Type, | ||
1437 | bounds: &[GenericPredicate], | ||
1438 | cb: &mut impl FnMut(Type), | ||
1439 | ) { | ||
1440 | for pred in bounds { | ||
1441 | match pred { | ||
1442 | GenericPredicate::Implemented(trait_ref) => { | ||
1443 | cb(type_.clone()); | ||
1444 | walk_substs(db, type_, &trait_ref.substs, cb); | ||
1445 | } | ||
1446 | _ => (), | ||
1447 | } | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { | ||
1452 | let ty = type_.ty.value.strip_references(); | ||
1453 | match ty { | ||
1454 | Ty::Apply(ApplicationTy { ctor, parameters }) => { | ||
1455 | match ctor { | ||
1456 | TypeCtor::Adt(_) => { | ||
1457 | cb(type_.derived(ty.clone())); | ||
1458 | } | ||
1459 | TypeCtor::AssociatedType(_) => { | ||
1460 | if let Some(_) = ty.associated_type_parent_trait(db) { | ||
1461 | cb(type_.derived(ty.clone())); | ||
1462 | } | ||
1463 | } | ||
1464 | _ => (), | ||
1465 | } | ||
1466 | |||
1467 | // adt params, tuples, etc... | ||
1468 | walk_substs(db, type_, parameters, cb); | ||
1469 | } | ||
1470 | Ty::Opaque(opaque_ty) => { | ||
1471 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1472 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1473 | } | ||
1474 | |||
1475 | walk_substs(db, type_, &opaque_ty.parameters, cb); | ||
1476 | } | ||
1477 | Ty::Placeholder(_) => { | ||
1478 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1479 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1480 | } | ||
1481 | } | ||
1482 | Ty::Dyn(bounds) => { | ||
1483 | walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); | ||
1484 | } | ||
1485 | |||
1486 | _ => (), | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | walk_type(db, self, &mut cb); | ||
1491 | } | ||
1383 | } | 1492 | } |
1384 | 1493 | ||
1385 | impl HirDisplay for Type { | 1494 | impl HirDisplay for Type { |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index b6b665de1..bb67952de 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -6,7 +6,7 @@ pub use hir_def::db::{ | |||
6 | ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, | 6 | ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, |
7 | InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, | 7 | InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, |
8 | InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, | 8 | InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, |
9 | InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, | 9 | InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery, |
10 | StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, | 10 | StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, |
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
@@ -16,7 +16,7 @@ pub use hir_expand::db::{ | |||
16 | pub use hir_ty::db::{ | 16 | pub use hir_ty::db::{ |
17 | AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, | 17 | AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, |
18 | GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, | 18 | GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, |
19 | HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, | 19 | HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery, |
20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, | 20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, |
21 | InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, | 21 | InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, |
22 | TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, | 22 | TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, |
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs index 63b8fd369..76c32fc17 100644 --- a/crates/ra_hir/src/has_source.rs +++ b/crates/ra_hir/src/has_source.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir_def::{ | 4 | use hir_def::{ |
5 | nameres::ModuleSource, | 5 | nameres::{ModuleOrigin, ModuleSource}, |
6 | src::{HasChildSource, HasSource as _}, | 6 | src::{HasChildSource, HasSource as _}, |
7 | Lookup, VariantId, | 7 | Lookup, VariantId, |
8 | }; | 8 | }; |
@@ -29,6 +29,14 @@ impl Module { | |||
29 | def_map[self.id.local_id].definition_source(db.upcast()) | 29 | def_map[self.id.local_id].definition_source(db.upcast()) |
30 | } | 30 | } |
31 | 31 | ||
32 | pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { | ||
33 | let def_map = db.crate_def_map(self.id.krate); | ||
34 | match def_map[self.id.local_id].origin { | ||
35 | ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs, | ||
36 | _ => false, | ||
37 | } | ||
38 | } | ||
39 | |||
32 | /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. | 40 | /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. |
33 | /// `None` for the crate root. | 41 | /// `None` for the crate root. |
34 | pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { | 42 | pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index a232a5856..6a49c424a 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -6,9 +6,9 @@ use std::{cell::RefCell, fmt, iter::successors}; | |||
6 | 6 | ||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, | 9 | AsMacroCall, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
@@ -104,6 +104,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
104 | tree | 104 | tree |
105 | } | 105 | } |
106 | 106 | ||
107 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | ||
108 | let file_id = d.source().file_id; | ||
109 | let root = self.db.parse_or_expand(file_id).unwrap(); | ||
110 | self.cache(root, file_id); | ||
111 | d.ast(self.db) | ||
112 | } | ||
113 | |||
107 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 114 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
108 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); | 115 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); |
109 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 116 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
@@ -247,6 +254,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
247 | self.analyze(path.syntax()).resolve_path(self.db, path) | 254 | self.analyze(path.syntax()).resolve_path(self.db, path) |
248 | } | 255 | } |
249 | 256 | ||
257 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { | ||
258 | self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) | ||
259 | } | ||
260 | |||
250 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | 261 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { |
251 | let src = self.find_file(path.syntax().clone()); | 262 | let src = self.find_file(path.syntax().clone()); |
252 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) | 263 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 7c6bbea13..1d6c47103 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -216,13 +216,43 @@ impl SourceAnalyzer { | |||
216 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 216 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { |
217 | return Some(PathResolution::AssocItem(assoc.into())); | 217 | return Some(PathResolution::AssocItem(assoc.into())); |
218 | } | 218 | } |
219 | if let Some(VariantId::EnumVariantId(variant)) = | ||
220 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) | ||
221 | { | ||
222 | return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into()))); | ||
223 | } | ||
219 | } | 224 | } |
225 | |||
220 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | 226 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { |
221 | let pat_id = self.pat_id(&path_pat.into())?; | 227 | let pat_id = self.pat_id(&path_pat.into())?; |
222 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | 228 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { |
223 | return Some(PathResolution::AssocItem(assoc.into())); | 229 | return Some(PathResolution::AssocItem(assoc.into())); |
224 | } | 230 | } |
231 | if let Some(VariantId::EnumVariantId(variant)) = | ||
232 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) | ||
233 | { | ||
234 | return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into()))); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordLit::cast) { | ||
239 | let expr_id = self.expr_id(db, &rec_lit.into())?; | ||
240 | if let Some(VariantId::EnumVariantId(variant)) = | ||
241 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) | ||
242 | { | ||
243 | return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into()))); | ||
244 | } | ||
225 | } | 245 | } |
246 | |||
247 | if let Some(rec_pat) = path.syntax().parent().and_then(ast::RecordPat::cast) { | ||
248 | let pat_id = self.pat_id(&rec_pat.into())?; | ||
249 | if let Some(VariantId::EnumVariantId(variant)) = | ||
250 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) | ||
251 | { | ||
252 | return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into()))); | ||
253 | } | ||
254 | } | ||
255 | |||
226 | // This must be a normal source file rather than macro file. | 256 | // This must be a normal source file rather than macro file. |
227 | let hir_path = | 257 | let hir_path = |
228 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | 258 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; |
@@ -313,6 +343,16 @@ impl SourceAnalyzer { | |||
313 | })?; | 343 | })?; |
314 | Some(macro_call_id.as_file()) | 344 | Some(macro_call_id.as_file()) |
315 | } | 345 | } |
346 | |||
347 | pub(crate) fn resolve_variant( | ||
348 | &self, | ||
349 | db: &dyn HirDatabase, | ||
350 | record_lit: ast::RecordLit, | ||
351 | ) -> Option<VariantId> { | ||
352 | let infer = self.infer.as_ref()?; | ||
353 | let expr_id = self.expr_id(db, &record_lit.into())?; | ||
354 | infer.variant_resolution_for_expr(expr_id) | ||
355 | } | ||
316 | } | 356 | } |
317 | 357 | ||
318 | fn scope_for( | 358 | fn scope_for( |
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index ef1f65ee0..6d43924e3 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml | |||
@@ -17,6 +17,7 @@ drop_bomb = "0.1.4" | |||
17 | fst = { version = "0.4", default-features = false } | 17 | fst = { version = "0.4", default-features = false } |
18 | itertools = "0.9.0" | 18 | itertools = "0.9.0" |
19 | indexmap = "1.4.0" | 19 | indexmap = "1.4.0" |
20 | smallvec = "1.4.0" | ||
20 | 21 | ||
21 | stdx = { path = "../stdx" } | 22 | stdx = { path = "../stdx" } |
22 | 23 | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 2eeba0572..197737ffc 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -13,7 +13,11 @@ use ra_syntax::{ | |||
13 | use tt::Subtree; | 13 | use tt::Subtree; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, | 16 | db::DefDatabase, |
17 | item_tree::{ItemTreeId, ItemTreeNode}, | ||
18 | nameres::ModuleSource, | ||
19 | path::ModPath, | ||
20 | src::HasChildSource, | ||
17 | AdtId, AttrDefId, Lookup, | 21 | AdtId, AttrDefId, Lookup, |
18 | }; | 22 | }; |
19 | 23 | ||
@@ -34,6 +38,8 @@ impl ops::Deref for Attrs { | |||
34 | } | 38 | } |
35 | 39 | ||
36 | impl Attrs { | 40 | impl Attrs { |
41 | pub const EMPTY: Attrs = Attrs { entries: None }; | ||
42 | |||
37 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | 43 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { |
38 | match def { | 44 | match def { |
39 | AttrDefId::ModuleId(module) => { | 45 | AttrDefId::ModuleId(module) => { |
@@ -65,19 +71,19 @@ impl Attrs { | |||
65 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | 71 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) |
66 | } | 72 | } |
67 | AttrDefId::AdtId(it) => match it { | 73 | AttrDefId::AdtId(it) => match it { |
68 | AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), | 74 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
69 | AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), | 75 | AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
70 | AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), | 76 | AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
71 | }, | 77 | }, |
72 | AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), | 78 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
73 | AttrDefId::MacroDefId(it) => { | 79 | AttrDefId::MacroDefId(it) => { |
74 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | 80 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) |
75 | } | 81 | } |
76 | AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), | 82 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
77 | AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), | 83 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
78 | AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), | 84 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
79 | AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), | 85 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
80 | AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), | 86 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
81 | } | 87 | } |
82 | } | 88 | } |
83 | 89 | ||
@@ -103,6 +109,18 @@ impl Attrs { | |||
103 | Attrs { entries } | 109 | Attrs { entries } |
104 | } | 110 | } |
105 | 111 | ||
112 | pub fn merge(&self, other: Attrs) -> Attrs { | ||
113 | match (&self.entries, &other.entries) { | ||
114 | (None, None) => Attrs { entries: None }, | ||
115 | (Some(entries), None) | (None, Some(entries)) => { | ||
116 | Attrs { entries: Some(entries.clone()) } | ||
117 | } | ||
118 | (Some(a), Some(b)) => { | ||
119 | Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
106 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 124 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
107 | AttrQuery { attrs: self, key } | 125 | AttrQuery { attrs: self, key } |
108 | } | 126 | } |
@@ -187,11 +205,8 @@ where | |||
187 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | 205 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) |
188 | } | 206 | } |
189 | 207 | ||
190 | fn attrs_from_loc<T>(node: T, db: &dyn DefDatabase) -> Attrs | 208 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { |
191 | where | 209 | let tree = db.item_tree(id.file_id); |
192 | T: HasSource, | 210 | let mod_item = N::id_to_mod_item(id.value); |
193 | T::Value: ast::AttrsOwner, | 211 | tree.attrs(mod_item).clone() |
194 | { | ||
195 | let src = node.source(db); | ||
196 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
197 | } | 212 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f159f80af..3ced648e5 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -5,7 +5,7 @@ use either::Either; | |||
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | hygiene::Hygiene, | 6 | hygiene::Hygiene, |
7 | name::{name, AsName, Name}, | 7 | name::{name, AsName, Name}, |
8 | HirFileId, MacroDefId, MacroDefKind, | 8 | AstId, HirFileId, MacroDefId, MacroDefKind, |
9 | }; | 9 | }; |
10 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
11 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -27,6 +27,7 @@ use crate::{ | |||
27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
28 | }, | 28 | }, |
29 | item_scope::BuiltinShadowMode, | 29 | item_scope::BuiltinShadowMode, |
30 | item_tree::{FileItemTreeId, ItemTree, ItemTreeNode}, | ||
30 | path::{GenericArgs, Path}, | 31 | path::{GenericArgs, Path}, |
31 | type_ref::{Mutability, Rawness, TypeRef}, | 32 | type_ref::{Mutability, Rawness, TypeRef}, |
32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 33 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
@@ -35,6 +36,8 @@ use crate::{ | |||
35 | 36 | ||
36 | use super::{ExprSource, PatSource}; | 37 | use super::{ExprSource, PatSource}; |
37 | use ast::AstChildren; | 38 | use ast::AstChildren; |
39 | use rustc_hash::FxHashMap; | ||
40 | use std::sync::Arc; | ||
38 | 41 | ||
39 | pub(crate) struct LowerCtx { | 42 | pub(crate) struct LowerCtx { |
40 | hygiene: Hygiene, | 43 | hygiene: Hygiene, |
@@ -60,10 +63,10 @@ pub(super) fn lower( | |||
60 | params: Option<ast::ParamList>, | 63 | params: Option<ast::ParamList>, |
61 | body: Option<ast::Expr>, | 64 | body: Option<ast::Expr>, |
62 | ) -> (Body, BodySourceMap) { | 65 | ) -> (Body, BodySourceMap) { |
66 | let item_tree = db.item_tree(expander.current_file_id); | ||
63 | ExprCollector { | 67 | ExprCollector { |
64 | db, | 68 | db, |
65 | def, | 69 | def, |
66 | expander, | ||
67 | source_map: BodySourceMap::default(), | 70 | source_map: BodySourceMap::default(), |
68 | body: Body { | 71 | body: Body { |
69 | exprs: Arena::default(), | 72 | exprs: Arena::default(), |
@@ -72,6 +75,12 @@ pub(super) fn lower( | |||
72 | body_expr: dummy_expr_id(), | 75 | body_expr: dummy_expr_id(), |
73 | item_scope: Default::default(), | 76 | item_scope: Default::default(), |
74 | }, | 77 | }, |
78 | item_trees: { | ||
79 | let mut map = FxHashMap::default(); | ||
80 | map.insert(expander.current_file_id, item_tree); | ||
81 | map | ||
82 | }, | ||
83 | expander, | ||
75 | } | 84 | } |
76 | .collect(params, body) | 85 | .collect(params, body) |
77 | } | 86 | } |
@@ -82,6 +91,8 @@ struct ExprCollector<'a> { | |||
82 | expander: Expander, | 91 | expander: Expander, |
83 | body: Body, | 92 | body: Body, |
84 | source_map: BodySourceMap, | 93 | source_map: BodySourceMap, |
94 | |||
95 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, | ||
85 | } | 96 | } |
86 | 97 | ||
87 | impl ExprCollector<'_> { | 98 | impl ExprCollector<'_> { |
@@ -533,6 +544,9 @@ impl ExprCollector<'_> { | |||
533 | self.source_map | 544 | self.source_map |
534 | .expansions | 545 | .expansions |
535 | .insert(macro_call, self.expander.current_file_id); | 546 | .insert(macro_call, self.expander.current_file_id); |
547 | |||
548 | let item_tree = self.db.item_tree(self.expander.current_file_id); | ||
549 | self.item_trees.insert(self.expander.current_file_id, item_tree); | ||
536 | let id = self.collect_expr(expansion); | 550 | let id = self.collect_expr(expansion); |
537 | self.expander.exit(self.db, mark); | 551 | self.expander.exit(self.db, mark); |
538 | id | 552 | id |
@@ -547,6 +561,19 @@ impl ExprCollector<'_> { | |||
547 | } | 561 | } |
548 | } | 562 | } |
549 | 563 | ||
564 | fn find_inner_item<S: ItemTreeNode>(&self, id: AstId<ast::ModuleItem>) -> FileItemTreeId<S> { | ||
565 | let tree = &self.item_trees[&id.file_id]; | ||
566 | |||
567 | // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes | ||
568 | |||
569 | // Root file (non-macro). | ||
570 | tree.all_inner_items() | ||
571 | .chain(tree.top_level_items().iter().copied()) | ||
572 | .filter_map(|mod_item| mod_item.downcast::<S>()) | ||
573 | .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value) | ||
574 | .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id)) | ||
575 | } | ||
576 | |||
550 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | 577 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { |
551 | if let Some(expr) = expr { | 578 | if let Some(expr) = expr { |
552 | self.collect_expr(expr) | 579 | self.collect_expr(expr) |
@@ -578,56 +605,102 @@ impl ExprCollector<'_> { | |||
578 | 605 | ||
579 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | 606 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
580 | let container = ContainerId::DefWithBodyId(self.def); | 607 | let container = ContainerId::DefWithBodyId(self.def); |
581 | for item in block.items() { | 608 | |
582 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | 609 | let items = block |
583 | ast::ModuleItem::FnDef(def) => { | 610 | .items() |
584 | let ast_id = self.expander.ast_id(&def); | 611 | .filter_map(|item| { |
585 | ( | 612 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { |
586 | FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), | 613 | ast::ModuleItem::FnDef(def) => { |
587 | def.name(), | 614 | let ast_id = self.expander.ast_id(&def); |
588 | ) | 615 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
589 | } | 616 | ( |
590 | ast::ModuleItem::TypeAliasDef(def) => { | 617 | FunctionLoc { container: container.into(), id: ast_id.with_value(id) } |
591 | let ast_id = self.expander.ast_id(&def); | 618 | .intern(self.db) |
592 | ( | 619 | .into(), |
593 | TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), | 620 | def.name(), |
594 | def.name(), | 621 | ) |
595 | ) | 622 | } |
596 | } | 623 | ast::ModuleItem::TypeAliasDef(def) => { |
597 | ast::ModuleItem::ConstDef(def) => { | 624 | let ast_id = self.expander.ast_id(&def); |
598 | let ast_id = self.expander.ast_id(&def); | 625 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
599 | ( | 626 | ( |
600 | ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), | 627 | TypeAliasLoc { container: container.into(), id: ast_id.with_value(id) } |
601 | def.name(), | 628 | .intern(self.db) |
602 | ) | 629 | .into(), |
603 | } | 630 | def.name(), |
604 | ast::ModuleItem::StaticDef(def) => { | 631 | ) |
605 | let ast_id = self.expander.ast_id(&def); | 632 | } |
606 | (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) | 633 | ast::ModuleItem::ConstDef(def) => { |
607 | } | 634 | let ast_id = self.expander.ast_id(&def); |
608 | ast::ModuleItem::StructDef(def) => { | 635 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
609 | let ast_id = self.expander.ast_id(&def); | 636 | ( |
610 | (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) | 637 | ConstLoc { container: container.into(), id: ast_id.with_value(id) } |
611 | } | 638 | .intern(self.db) |
612 | ast::ModuleItem::EnumDef(def) => { | 639 | .into(), |
613 | let ast_id = self.expander.ast_id(&def); | 640 | def.name(), |
614 | (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) | 641 | ) |
615 | } | 642 | } |
616 | ast::ModuleItem::UnionDef(def) => { | 643 | ast::ModuleItem::StaticDef(def) => { |
617 | let ast_id = self.expander.ast_id(&def); | 644 | let ast_id = self.expander.ast_id(&def); |
618 | (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) | 645 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
619 | } | 646 | ( |
620 | ast::ModuleItem::TraitDef(def) => { | 647 | StaticLoc { container, id: ast_id.with_value(id) } |
621 | let ast_id = self.expander.ast_id(&def); | 648 | .intern(self.db) |
622 | (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) | 649 | .into(), |
623 | } | 650 | def.name(), |
624 | ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks | 651 | ) |
625 | ast::ModuleItem::ImplDef(_) | 652 | } |
626 | | ast::ModuleItem::UseItem(_) | 653 | ast::ModuleItem::StructDef(def) => { |
627 | | ast::ModuleItem::ExternCrateItem(_) | 654 | let ast_id = self.expander.ast_id(&def); |
628 | | ast::ModuleItem::Module(_) | 655 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); |
629 | | ast::ModuleItem::MacroCall(_) => continue, | 656 | ( |
630 | }; | 657 | StructLoc { container, id: ast_id.with_value(id) } |
658 | .intern(self.db) | ||
659 | .into(), | ||
660 | def.name(), | ||
661 | ) | ||
662 | } | ||
663 | ast::ModuleItem::EnumDef(def) => { | ||
664 | let ast_id = self.expander.ast_id(&def); | ||
665 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
666 | ( | ||
667 | EnumLoc { container, id: ast_id.with_value(id) }.intern(self.db).into(), | ||
668 | def.name(), | ||
669 | ) | ||
670 | } | ||
671 | ast::ModuleItem::UnionDef(def) => { | ||
672 | let ast_id = self.expander.ast_id(&def); | ||
673 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
674 | ( | ||
675 | UnionLoc { container, id: ast_id.with_value(id) } | ||
676 | .intern(self.db) | ||
677 | .into(), | ||
678 | def.name(), | ||
679 | ) | ||
680 | } | ||
681 | ast::ModuleItem::TraitDef(def) => { | ||
682 | let ast_id = self.expander.ast_id(&def); | ||
683 | let id = self.find_inner_item(ast_id.map(|id| id.upcast())); | ||
684 | ( | ||
685 | TraitLoc { container, id: ast_id.with_value(id) } | ||
686 | .intern(self.db) | ||
687 | .into(), | ||
688 | def.name(), | ||
689 | ) | ||
690 | } | ||
691 | ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks | ||
692 | ast::ModuleItem::ImplDef(_) | ||
693 | | ast::ModuleItem::UseItem(_) | ||
694 | | ast::ModuleItem::ExternCrateItem(_) | ||
695 | | ast::ModuleItem::Module(_) | ||
696 | | ast::ModuleItem::MacroCall(_) => return None, | ||
697 | }; | ||
698 | |||
699 | Some((def, name)) | ||
700 | }) | ||
701 | .collect::<Vec<_>>(); | ||
702 | |||
703 | for (def, name) in items { | ||
631 | self.body.item_scope.define_def(def); | 704 | self.body.item_scope.define_def(def); |
632 | if let Some(name) = name { | 705 | if let Some(name) = name { |
633 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly | 706 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index e48ff38f9..81397b063 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -87,15 +87,13 @@ impl ExprScopes { | |||
87 | } | 87 | } |
88 | 88 | ||
89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | 89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { |
90 | match &body[pat] { | 90 | let pattern = &body[pat]; |
91 | Pat::Bind { name, .. } => { | 91 | if let Pat::Bind { name, .. } = pattern { |
92 | // bind can have a sub pattern, but it's actually not allowed | 92 | let entry = ScopeEntry { name: name.clone(), pat }; |
93 | // to bind to things in there | 93 | self.scopes[scope].entries.push(entry); |
94 | let entry = ScopeEntry { name: name.clone(), pat }; | ||
95 | self.scopes[scope].entries.push(entry) | ||
96 | } | ||
97 | p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), | ||
98 | } | 94 | } |
95 | |||
96 | pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat)); | ||
99 | } | 97 | } |
100 | 98 | ||
101 | fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { | 99 | fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { |
@@ -190,21 +188,23 @@ mod tests { | |||
190 | } | 188 | } |
191 | } | 189 | } |
192 | 190 | ||
193 | fn do_check(code: &str, expected: &[&str]) { | 191 | fn do_check(ra_fixture: &str, expected: &[&str]) { |
194 | let (off, code) = extract_offset(code); | 192 | let (offset, code) = extract_offset(ra_fixture); |
195 | let code = { | 193 | let code = { |
196 | let mut buf = String::new(); | 194 | let mut buf = String::new(); |
197 | let off: usize = off.into(); | 195 | let off: usize = offset.into(); |
198 | buf.push_str(&code[..off]); | 196 | buf.push_str(&code[..off]); |
199 | buf.push_str("marker"); | 197 | buf.push_str("<|>marker"); |
200 | buf.push_str(&code[off..]); | 198 | buf.push_str(&code[off..]); |
201 | buf | 199 | buf |
202 | }; | 200 | }; |
203 | 201 | ||
204 | let (db, file_id) = TestDB::with_single_file(&code); | 202 | let (db, position) = TestDB::with_position(&code); |
203 | let file_id = position.file_id; | ||
204 | let offset = position.offset; | ||
205 | 205 | ||
206 | let file_syntax = db.parse(file_id).syntax_node(); | 206 | let file_syntax = db.parse(file_id).syntax_node(); |
207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); | 207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); |
208 | let function = find_function(&db, file_id); | 208 | let function = find_function(&db, file_id); |
209 | 209 | ||
210 | let scopes = db.expr_scopes(function.into()); | 210 | let scopes = db.expr_scopes(function.into()); |
@@ -300,15 +300,52 @@ mod tests { | |||
300 | ); | 300 | ); |
301 | } | 301 | } |
302 | 302 | ||
303 | fn do_check_local_name(code: &str, expected_offset: u32) { | 303 | #[test] |
304 | let (off, code) = extract_offset(code); | 304 | fn test_bindings_after_at() { |
305 | do_check( | ||
306 | r" | ||
307 | fn foo() { | ||
308 | match Some(()) { | ||
309 | opt @ Some(unit) => { | ||
310 | <|> | ||
311 | } | ||
312 | _ => {} | ||
313 | } | ||
314 | } | ||
315 | ", | ||
316 | &["opt", "unit"], | ||
317 | ); | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn macro_inner_item() { | ||
322 | do_check( | ||
323 | r" | ||
324 | macro_rules! mac { | ||
325 | () => {{ | ||
326 | fn inner() {} | ||
327 | inner(); | ||
328 | }}; | ||
329 | } | ||
330 | |||
331 | fn foo() { | ||
332 | mac!(); | ||
333 | <|> | ||
334 | } | ||
335 | ", | ||
336 | &[], | ||
337 | ); | ||
338 | } | ||
305 | 339 | ||
306 | let (db, file_id) = TestDB::with_single_file(&code); | 340 | fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { |
341 | let (db, position) = TestDB::with_position(ra_fixture); | ||
342 | let file_id = position.file_id; | ||
343 | let offset = position.offset; | ||
307 | 344 | ||
308 | let file = db.parse(file_id).ok().unwrap(); | 345 | let file = db.parse(file_id).ok().unwrap(); |
309 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 346 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) |
310 | .expect("failed to find a name at the target offset"); | 347 | .expect("failed to find a name at the target offset"); |
311 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 348 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap(); |
312 | 349 | ||
313 | let function = find_function(&db, file_id); | 350 | let function = find_function(&db, file_id); |
314 | 351 | ||
@@ -336,15 +373,16 @@ mod tests { | |||
336 | fn test_resolve_local_name() { | 373 | fn test_resolve_local_name() { |
337 | do_check_local_name( | 374 | do_check_local_name( |
338 | r#" | 375 | r#" |
339 | fn foo(x: i32, y: u32) { | 376 | fn foo(x: i32, y: u32) { |
340 | { | 377 | { |
341 | let z = x * 2; | 378 | let z = x * 2; |
342 | } | 379 | } |
343 | { | 380 | { |
344 | let t = x<|> * 3; | 381 | let t = x<|> * 3; |
345 | } | 382 | } |
346 | }"#, | 383 | } |
347 | 21, | 384 | "#, |
385 | 7, | ||
348 | ); | 386 | ); |
349 | } | 387 | } |
350 | 388 | ||
@@ -352,10 +390,11 @@ mod tests { | |||
352 | fn test_resolve_local_name_declaration() { | 390 | fn test_resolve_local_name_declaration() { |
353 | do_check_local_name( | 391 | do_check_local_name( |
354 | r#" | 392 | r#" |
355 | fn foo(x: String) { | 393 | fn foo(x: String) { |
356 | let x : &str = &x<|>; | 394 | let x : &str = &x<|>; |
357 | }"#, | 395 | } |
358 | 21, | 396 | "#, |
397 | 7, | ||
359 | ); | 398 | ); |
360 | } | 399 | } |
361 | 400 | ||
@@ -363,12 +402,12 @@ mod tests { | |||
363 | fn test_resolve_local_name_shadow() { | 402 | fn test_resolve_local_name_shadow() { |
364 | do_check_local_name( | 403 | do_check_local_name( |
365 | r" | 404 | r" |
366 | fn foo(x: String) { | 405 | fn foo(x: String) { |
367 | let x : &str = &x; | 406 | let x : &str = &x; |
368 | x<|> | 407 | x<|> |
369 | } | 408 | } |
370 | ", | 409 | ", |
371 | 53, | 410 | 28, |
372 | ); | 411 | ); |
373 | } | 412 | } |
374 | 413 | ||
@@ -376,13 +415,13 @@ mod tests { | |||
376 | fn ref_patterns_contribute_bindings() { | 415 | fn ref_patterns_contribute_bindings() { |
377 | do_check_local_name( | 416 | do_check_local_name( |
378 | r" | 417 | r" |
379 | fn foo() { | 418 | fn foo() { |
380 | if let Some(&from) = bar() { | 419 | if let Some(&from) = bar() { |
381 | from<|>; | 420 | from<|>; |
382 | } | 421 | } |
383 | } | 422 | } |
384 | ", | 423 | ", |
385 | 53, | 424 | 28, |
386 | ); | 425 | ); |
387 | } | 426 | } |
388 | 427 | ||
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 53599e74a..f9e5701db 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -2,27 +2,19 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::{ | 5 | use hir_expand::{name::Name, InFile}; |
6 | hygiene::Hygiene, | ||
7 | name::{name, AsName, Name}, | ||
8 | AstId, InFile, | ||
9 | }; | ||
10 | use ra_prof::profile; | 6 | use ra_prof::profile; |
11 | use ra_syntax::ast::{ | 7 | use ra_syntax::ast; |
12 | self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, | ||
13 | VisibilityOwner, | ||
14 | }; | ||
15 | 8 | ||
16 | use crate::{ | 9 | use crate::{ |
17 | attr::Attrs, | 10 | attr::Attrs, |
18 | body::LowerCtx, | 11 | body::Expander, |
19 | db::DefDatabase, | 12 | db::DefDatabase, |
20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 13 | item_tree::{AssocItem, ItemTreeId, ModItem}, |
21 | src::HasSource, | 14 | type_ref::{TypeBound, TypeRef}, |
22 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
23 | visibility::RawVisibility, | 15 | visibility::RawVisibility, |
24 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
25 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
26 | }; | 18 | }; |
27 | 19 | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -41,82 +33,27 @@ pub struct FunctionData { | |||
41 | impl FunctionData { | 33 | impl FunctionData { |
42 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 34 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
43 | let loc = func.lookup(db); | 35 | let loc = func.lookup(db); |
44 | let src = loc.source(db); | 36 | let item_tree = db.item_tree(loc.id.file_id); |
45 | let ctx = LowerCtx::new(db, src.file_id); | 37 | let func = &item_tree[loc.id.value]; |
46 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 38 | |
47 | let mut params = Vec::new(); | 39 | Arc::new(FunctionData { |
48 | let mut has_self_param = false; | 40 | name: func.name.clone(), |
49 | if let Some(param_list) = src.value.param_list() { | 41 | params: func.params.to_vec(), |
50 | if let Some(self_param) = param_list.self_param() { | 42 | ret_type: func.ret_type.clone(), |
51 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 43 | attrs: item_tree.attrs(loc.id.value.into()).clone(), |
52 | TypeRef::from_ast(&ctx, type_ref) | 44 | has_self_param: func.has_self_param, |
53 | } else { | 45 | is_unsafe: func.is_unsafe, |
54 | let self_type = TypeRef::Path(name![Self].into()); | 46 | visibility: item_tree[func.visibility].clone(), |
55 | match self_param.kind() { | 47 | }) |
56 | ast::SelfParamKind::Owned => self_type, | ||
57 | ast::SelfParamKind::Ref => { | ||
58 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
59 | } | ||
60 | ast::SelfParamKind::MutRef => { | ||
61 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
62 | } | ||
63 | } | ||
64 | }; | ||
65 | params.push(self_type); | ||
66 | has_self_param = true; | ||
67 | } | ||
68 | for param in param_list.params() { | ||
69 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); | ||
70 | params.push(type_ref); | ||
71 | } | ||
72 | } | ||
73 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); | ||
74 | |||
75 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | ||
76 | TypeRef::from_ast(&ctx, type_ref) | ||
77 | } else { | ||
78 | TypeRef::unit() | ||
79 | }; | ||
80 | |||
81 | let ret_type = if src.value.async_token().is_some() { | ||
82 | let future_impl = desugar_future_path(ret_type); | ||
83 | let ty_bound = TypeBound::Path(future_impl); | ||
84 | TypeRef::ImplTrait(vec![ty_bound]) | ||
85 | } else { | ||
86 | ret_type | ||
87 | }; | ||
88 | |||
89 | let is_unsafe = src.value.unsafe_token().is_some(); | ||
90 | |||
91 | let vis_default = RawVisibility::default_for_container(loc.container); | ||
92 | let visibility = | ||
93 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | ||
94 | |||
95 | let sig = | ||
96 | FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; | ||
97 | Arc::new(sig) | ||
98 | } | 48 | } |
99 | } | 49 | } |
100 | 50 | ||
101 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
102 | let path = path![core::future::Future]; | ||
103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
104 | let mut last = GenericArgs::empty(); | ||
105 | last.bindings.push(AssociatedTypeBinding { | ||
106 | name: name![Output], | ||
107 | type_ref: Some(orig), | ||
108 | bounds: Vec::new(), | ||
109 | }); | ||
110 | generic_args.push(Some(Arc::new(last))); | ||
111 | |||
112 | Path::from_known_path(path, generic_args) | ||
113 | } | ||
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | 51 | #[derive(Debug, Clone, PartialEq, Eq)] |
116 | pub struct TypeAliasData { | 52 | pub struct TypeAliasData { |
117 | pub name: Name, | 53 | pub name: Name, |
118 | pub type_ref: Option<TypeRef>, | 54 | pub type_ref: Option<TypeRef>, |
119 | pub visibility: RawVisibility, | 55 | pub visibility: RawVisibility, |
56 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
120 | pub bounds: Vec<TypeBound>, | 57 | pub bounds: Vec<TypeBound>, |
121 | } | 58 | } |
122 | 59 | ||
@@ -126,22 +63,15 @@ impl TypeAliasData { | |||
126 | typ: TypeAliasId, | 63 | typ: TypeAliasId, |
127 | ) -> Arc<TypeAliasData> { | 64 | ) -> Arc<TypeAliasData> { |
128 | let loc = typ.lookup(db); | 65 | let loc = typ.lookup(db); |
129 | let node = loc.source(db); | 66 | let item_tree = db.item_tree(loc.id.file_id); |
130 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 67 | let typ = &item_tree[loc.id.value]; |
131 | let lower_ctx = LowerCtx::new(db, node.file_id); | 68 | |
132 | let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 69 | Arc::new(TypeAliasData { |
133 | let vis_default = RawVisibility::default_for_container(loc.container); | 70 | name: typ.name.clone(), |
134 | let visibility = RawVisibility::from_ast_with_default( | 71 | type_ref: typ.type_ref.clone(), |
135 | db, | 72 | visibility: item_tree[typ.visibility].clone(), |
136 | vis_default, | 73 | bounds: typ.bounds.to_vec(), |
137 | node.as_ref().map(|n| n.visibility()), | 74 | }) |
138 | ); | ||
139 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { | ||
140 | bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() | ||
141 | } else { | ||
142 | Vec::new() | ||
143 | }; | ||
144 | Arc::new(TypeAliasData { name, type_ref, visibility, bounds }) | ||
145 | } | 75 | } |
146 | } | 76 | } |
147 | 77 | ||
@@ -155,30 +85,24 @@ pub struct TraitData { | |||
155 | impl TraitData { | 85 | impl TraitData { |
156 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 86 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
157 | let tr_loc = tr.lookup(db); | 87 | let tr_loc = tr.lookup(db); |
158 | let src = tr_loc.source(db); | 88 | let item_tree = db.item_tree(tr_loc.id.file_id); |
159 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 89 | let tr_def = &item_tree[tr_loc.id.value]; |
160 | let auto = src.value.auto_token().is_some(); | 90 | let name = tr_def.name.clone(); |
91 | let auto = tr_def.auto; | ||
161 | let module_id = tr_loc.container.module(db); | 92 | let module_id = tr_loc.container.module(db); |
162 | |||
163 | let container = AssocContainerId::TraitId(tr); | 93 | let container = AssocContainerId::TraitId(tr); |
164 | let mut items = Vec::new(); | 94 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); |
165 | 95 | ||
166 | if let Some(item_list) = src.value.item_list() { | 96 | let items = collect_items( |
167 | let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); | 97 | db, |
168 | items.extend(collect_items( | 98 | module_id, |
169 | db, | 99 | &mut expander, |
170 | &mut expander, | 100 | tr_def.items.iter().copied(), |
171 | item_list.assoc_items(), | 101 | tr_loc.id.file_id, |
172 | src.file_id, | 102 | container, |
173 | container, | 103 | 100, |
174 | )); | 104 | ); |
175 | items.extend(collect_items_in_macros( | 105 | |
176 | db, | ||
177 | &mut expander, | ||
178 | &src.with_value(item_list), | ||
179 | container, | ||
180 | )); | ||
181 | } | ||
182 | Arc::new(TraitData { name, items, auto }) | 106 | Arc::new(TraitData { name, items, auto }) |
183 | } | 107 | } |
184 | 108 | ||
@@ -209,33 +133,28 @@ impl ImplData { | |||
209 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | 133 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { |
210 | let _p = profile("impl_data_query"); | 134 | let _p = profile("impl_data_query"); |
211 | let impl_loc = id.lookup(db); | 135 | let impl_loc = id.lookup(db); |
212 | let src = impl_loc.source(db); | ||
213 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
214 | 136 | ||
215 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 137 | let item_tree = db.item_tree(impl_loc.id.file_id); |
216 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); | 138 | let impl_def = &item_tree[impl_loc.id.value]; |
217 | let is_negative = src.value.excl_token().is_some(); | 139 | let target_trait = impl_def.target_trait.clone(); |
140 | let target_type = impl_def.target_type.clone(); | ||
141 | let is_negative = impl_def.is_negative; | ||
218 | let module_id = impl_loc.container.module(db); | 142 | let module_id = impl_loc.container.module(db); |
219 | let container = AssocContainerId::ImplId(id); | 143 | let container = AssocContainerId::ImplId(id); |
144 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
220 | 145 | ||
221 | let mut items: Vec<AssocItemId> = Vec::new(); | 146 | let items = collect_items( |
222 | 147 | db, | |
223 | if let Some(item_list) = src.value.item_list() { | 148 | module_id, |
224 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); | 149 | &mut expander, |
225 | items.extend( | 150 | impl_def.items.iter().copied(), |
226 | collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) | 151 | impl_loc.id.file_id, |
227 | .into_iter() | 152 | container, |
228 | .map(|(_, item)| item), | 153 | 100, |
229 | ); | 154 | ); |
230 | items.extend( | 155 | let items = items.into_iter().map(|(_, item)| item).collect(); |
231 | collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) | ||
232 | .into_iter() | ||
233 | .map(|(_, item)| item), | ||
234 | ); | ||
235 | } | ||
236 | 156 | ||
237 | let res = ImplData { target_trait, target_type, items, is_negative }; | 157 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) |
238 | Arc::new(res) | ||
239 | } | 158 | } |
240 | } | 159 | } |
241 | 160 | ||
@@ -250,22 +169,14 @@ pub struct ConstData { | |||
250 | impl ConstData { | 169 | impl ConstData { |
251 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | 170 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { |
252 | let loc = konst.lookup(db); | 171 | let loc = konst.lookup(db); |
253 | let node = loc.source(db); | 172 | let item_tree = db.item_tree(loc.id.file_id); |
254 | let vis_default = RawVisibility::default_for_container(loc.container); | 173 | let konst = &item_tree[loc.id.value]; |
255 | Arc::new(ConstData::new(db, vis_default, node)) | ||
256 | } | ||
257 | 174 | ||
258 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( | 175 | Arc::new(ConstData { |
259 | db: &dyn DefDatabase, | 176 | name: konst.name.clone(), |
260 | vis_default: RawVisibility, | 177 | type_ref: konst.type_ref.clone(), |
261 | node: InFile<N>, | 178 | visibility: item_tree[konst.visibility].clone(), |
262 | ) -> ConstData { | 179 | }) |
263 | let ctx = LowerCtx::new(db, node.file_id); | ||
264 | let name = node.value.name().map(|n| n.as_name()); | ||
265 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | ||
266 | let visibility = | ||
267 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
268 | ConstData { name, type_ref, visibility } | ||
269 | } | 180 | } |
270 | } | 181 | } |
271 | 182 | ||
@@ -279,44 +190,25 @@ pub struct StaticData { | |||
279 | 190 | ||
280 | impl StaticData { | 191 | impl StaticData { |
281 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | 192 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { |
282 | let node = konst.lookup(db).source(db); | 193 | let node = konst.lookup(db); |
283 | let ctx = LowerCtx::new(db, node.file_id); | 194 | let item_tree = db.item_tree(node.id.file_id); |
284 | 195 | let statik = &item_tree[node.id.value]; | |
285 | let name = node.value.name().map(|n| n.as_name()); | 196 | |
286 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | 197 | Arc::new(StaticData { |
287 | let mutable = node.value.mut_token().is_some(); | 198 | name: Some(statik.name.clone()), |
288 | let visibility = RawVisibility::from_ast_with_default( | 199 | type_ref: statik.type_ref.clone(), |
289 | db, | 200 | visibility: item_tree[statik.visibility].clone(), |
290 | RawVisibility::private(), | 201 | mutable: statik.mutable, |
291 | node.map(|n| n.visibility()), | 202 | }) |
292 | ); | ||
293 | |||
294 | Arc::new(StaticData { name, type_ref, visibility, mutable }) | ||
295 | } | ||
296 | } | ||
297 | |||
298 | fn collect_items_in_macros( | ||
299 | db: &dyn DefDatabase, | ||
300 | expander: &mut Expander, | ||
301 | impl_def: &InFile<ast::ItemList>, | ||
302 | container: AssocContainerId, | ||
303 | ) -> Vec<(Name, AssocItemId)> { | ||
304 | let mut res = Vec::new(); | ||
305 | |||
306 | // We set a limit to protect against infinite recursion | ||
307 | let limit = 100; | ||
308 | |||
309 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
310 | res.extend(collect_items_in_macro(db, expander, m, container, limit)) | ||
311 | } | 203 | } |
312 | |||
313 | res | ||
314 | } | 204 | } |
315 | 205 | ||
316 | fn collect_items_in_macro( | 206 | fn collect_items( |
317 | db: &dyn DefDatabase, | 207 | db: &dyn DefDatabase, |
208 | module: ModuleId, | ||
318 | expander: &mut Expander, | 209 | expander: &mut Expander, |
319 | m: ast::MacroCall, | 210 | assoc_items: impl Iterator<Item = AssocItem>, |
211 | file_id: crate::HirFileId, | ||
320 | container: AssocContainerId, | 212 | container: AssocContainerId, |
321 | limit: usize, | 213 | limit: usize, |
322 | ) -> Vec<(Name, AssocItemId)> { | 214 | ) -> Vec<(Name, AssocItemId)> { |
@@ -324,62 +216,62 @@ fn collect_items_in_macro( | |||
324 | return Vec::new(); | 216 | return Vec::new(); |
325 | } | 217 | } |
326 | 218 | ||
327 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { | 219 | let item_tree = db.item_tree(file_id); |
328 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 220 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); |
329 | let mut res = collect_items( | 221 | |
330 | db, | 222 | let mut items = Vec::new(); |
331 | expander, | 223 | for item in assoc_items { |
332 | items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), | 224 | match item { |
333 | items.file_id, | 225 | AssocItem::Function(id) => { |
334 | container, | 226 | let item = &item_tree[id]; |
335 | ); | 227 | let attrs = item_tree.attrs(id.into()); |
336 | 228 | if !attrs.is_cfg_enabled(&cfg_options) { | |
337 | // Recursive collect macros | 229 | continue; |
338 | // Note that ast::ModuleItem do not include ast::MacroCall | ||
339 | // We cannot use ModuleItemOwner::items here | ||
340 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
341 | res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) | ||
342 | } | ||
343 | expander.exit(db, mark); | ||
344 | res | ||
345 | } else { | ||
346 | Vec::new() | ||
347 | } | ||
348 | } | ||
349 | |||
350 | fn collect_items( | ||
351 | db: &dyn DefDatabase, | ||
352 | expander: &mut Expander, | ||
353 | assoc_items: impl Iterator<Item = AssocItem>, | ||
354 | file_id: crate::HirFileId, | ||
355 | container: AssocContainerId, | ||
356 | ) -> Vec<(Name, AssocItemId)> { | ||
357 | let items = db.ast_id_map(file_id); | ||
358 | |||
359 | assoc_items | ||
360 | .filter_map(|item_node| match item_node { | ||
361 | ast::AssocItem::FnDef(it) => { | ||
362 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
363 | if !expander.is_cfg_enabled(&it) { | ||
364 | return None; | ||
365 | } | 230 | } |
366 | let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 231 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
367 | .intern(db); | 232 | items.push((item.name.clone(), def.into())); |
368 | Some((name, def.into())) | ||
369 | } | 233 | } |
370 | ast::AssocItem::ConstDef(it) => { | 234 | // FIXME: cfg? |
371 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 235 | AssocItem::Const(id) => { |
372 | let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 236 | let item = &item_tree[id]; |
373 | .intern(db); | 237 | let name = match item.name.clone() { |
374 | Some((name, def.into())) | 238 | Some(name) => name, |
239 | None => continue, | ||
240 | }; | ||
241 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
242 | items.push((name, def.into())); | ||
375 | } | 243 | } |
376 | ast::AssocItem::TypeAliasDef(it) => { | 244 | AssocItem::TypeAlias(id) => { |
377 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 245 | let item = &item_tree[id]; |
378 | let def = | 246 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
379 | TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 247 | items.push((item.name.clone(), def.into())); |
380 | .intern(db); | ||
381 | Some((name, def.into())) | ||
382 | } | 248 | } |
383 | }) | 249 | AssocItem::MacroCall(call) => { |
384 | .collect() | 250 | let call = &item_tree[call]; |
251 | let ast_id_map = db.ast_id_map(file_id); | ||
252 | let root = db.parse_or_expand(file_id).unwrap(); | ||
253 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
254 | |||
255 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
256 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
257 | let item_tree = db.item_tree(src.file_id); | ||
258 | let iter = | ||
259 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
260 | items.extend(collect_items( | ||
261 | db, | ||
262 | module, | ||
263 | expander, | ||
264 | iter, | ||
265 | src.file_id, | ||
266 | container, | ||
267 | limit - 1, | ||
268 | )); | ||
269 | |||
270 | expander.exit(db, mark); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | items | ||
385 | } | 277 | } |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 10cc26480..9c3ede2d7 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -14,8 +14,9 @@ use crate::{ | |||
14 | docs::Documentation, | 14 | docs::Documentation, |
15 | generics::GenericParams, | 15 | generics::GenericParams, |
16 | import_map::ImportMap, | 16 | import_map::ImportMap, |
17 | item_tree::ItemTree, | ||
17 | lang_item::{LangItemTarget, LangItems}, | 18 | lang_item::{LangItemTarget, LangItems}, |
18 | nameres::{raw::RawItems, CrateDefMap}, | 19 | nameres::CrateDefMap, |
19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 20 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
20 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | 21 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, |
21 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 22 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, |
@@ -45,8 +46,8 @@ pub trait InternDatabase: SourceDatabase { | |||
45 | 46 | ||
46 | #[salsa::query_group(DefDatabaseStorage)] | 47 | #[salsa::query_group(DefDatabaseStorage)] |
47 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | 48 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { |
48 | #[salsa::invoke(RawItems::raw_items_query)] | 49 | #[salsa::invoke(ItemTree::item_tree_query)] |
49 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; | 50 | fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; |
50 | 51 | ||
51 | #[salsa::invoke(crate_def_map_wait)] | 52 | #[salsa::invoke(crate_def_map_wait)] |
52 | #[salsa::transparent] | 53 | #[salsa::transparent] |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index 09a5241f7..6a0f493a7 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -42,7 +42,7 @@ pub enum TypeParamProvenance { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | /// Data about the generic parameters of a function, struct, impl, etc. | 44 | /// Data about the generic parameters of a function, struct, impl, etc. |
45 | #[derive(Clone, PartialEq, Eq, Debug)] | 45 | #[derive(Clone, PartialEq, Eq, Debug, Default)] |
46 | pub struct GenericParams { | 46 | pub struct GenericParams { |
47 | pub types: Arena<TypeParamData>, | 47 | pub types: Arena<TypeParamData>, |
48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, | 48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, |
@@ -74,8 +74,53 @@ impl GenericParams { | |||
74 | def: GenericDefId, | 74 | def: GenericDefId, |
75 | ) -> Arc<GenericParams> { | 75 | ) -> Arc<GenericParams> { |
76 | let _p = profile("generic_params_query"); | 76 | let _p = profile("generic_params_query"); |
77 | let (params, _source_map) = GenericParams::new(db, def); | 77 | |
78 | Arc::new(params) | 78 | let generics = match def { |
79 | GenericDefId::FunctionId(id) => { | ||
80 | let id = id.lookup(db).id; | ||
81 | let tree = db.item_tree(id.file_id); | ||
82 | let item = &tree[id.value]; | ||
83 | tree[item.generic_params].clone() | ||
84 | } | ||
85 | GenericDefId::AdtId(AdtId::StructId(id)) => { | ||
86 | let id = id.lookup(db).id; | ||
87 | let tree = db.item_tree(id.file_id); | ||
88 | let item = &tree[id.value]; | ||
89 | tree[item.generic_params].clone() | ||
90 | } | ||
91 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | ||
92 | let id = id.lookup(db).id; | ||
93 | let tree = db.item_tree(id.file_id); | ||
94 | let item = &tree[id.value]; | ||
95 | tree[item.generic_params].clone() | ||
96 | } | ||
97 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | ||
98 | let id = id.lookup(db).id; | ||
99 | let tree = db.item_tree(id.file_id); | ||
100 | let item = &tree[id.value]; | ||
101 | tree[item.generic_params].clone() | ||
102 | } | ||
103 | GenericDefId::TraitId(id) => { | ||
104 | let id = id.lookup(db).id; | ||
105 | let tree = db.item_tree(id.file_id); | ||
106 | let item = &tree[id.value]; | ||
107 | tree[item.generic_params].clone() | ||
108 | } | ||
109 | GenericDefId::TypeAliasId(id) => { | ||
110 | let id = id.lookup(db).id; | ||
111 | let tree = db.item_tree(id.file_id); | ||
112 | let item = &tree[id.value]; | ||
113 | tree[item.generic_params].clone() | ||
114 | } | ||
115 | GenericDefId::ImplId(id) => { | ||
116 | let id = id.lookup(db).id; | ||
117 | let tree = db.item_tree(id.file_id); | ||
118 | let item = &tree[id.value]; | ||
119 | tree[item.generic_params].clone() | ||
120 | } | ||
121 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
122 | }; | ||
123 | Arc::new(generics) | ||
79 | } | 124 | } |
80 | 125 | ||
81 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 126 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
@@ -156,7 +201,12 @@ impl GenericParams { | |||
156 | (generics, InFile::new(file_id, sm)) | 201 | (generics, InFile::new(file_id, sm)) |
157 | } | 202 | } |
158 | 203 | ||
159 | fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { | 204 | pub(crate) fn fill( |
205 | &mut self, | ||
206 | lower_ctx: &LowerCtx, | ||
207 | sm: &mut SourceMap, | ||
208 | node: &dyn TypeParamsOwner, | ||
209 | ) { | ||
160 | if let Some(params) = node.type_param_list() { | 210 | if let Some(params) = node.type_param_list() { |
161 | self.fill_params(lower_ctx, sm, params) | 211 | self.fill_params(lower_ctx, sm, params) |
162 | } | 212 | } |
@@ -165,7 +215,7 @@ impl GenericParams { | |||
165 | } | 215 | } |
166 | } | 216 | } |
167 | 217 | ||
168 | fn fill_bounds( | 218 | pub(crate) fn fill_bounds( |
169 | &mut self, | 219 | &mut self, |
170 | lower_ctx: &LowerCtx, | 220 | lower_ctx: &LowerCtx, |
171 | node: &dyn ast::TypeBoundsOwner, | 221 | node: &dyn ast::TypeBoundsOwner, |
@@ -229,7 +279,7 @@ impl GenericParams { | |||
229 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | 279 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); |
230 | } | 280 | } |
231 | 281 | ||
232 | fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { | 282 | pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { |
233 | type_ref.walk(&mut |type_ref| { | 283 | type_ref.walk(&mut |type_ref| { |
234 | if let TypeRef::ImplTrait(bounds) = type_ref { | 284 | if let TypeRef::ImplTrait(bounds) = type_ref { |
235 | let param = TypeParamData { | 285 | let param = TypeParamData { |
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index b03ba939a..c81b966c3 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -5,6 +5,7 @@ use hir_expand::name::Name; | |||
5 | use once_cell::sync::Lazy; | 5 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 6 | use ra_db::CrateId; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use test_utils::mark; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 11 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
@@ -126,19 +127,27 @@ impl ItemScope { | |||
126 | let mut changed = false; | 127 | let mut changed = false; |
127 | let existing = self.visible.entry(name).or_default(); | 128 | let existing = self.visible.entry(name).or_default(); |
128 | 129 | ||
129 | if existing.types.is_none() && def.types.is_some() { | 130 | macro_rules! check_changed { |
130 | existing.types = def.types; | 131 | ($changed:ident, $existing:expr, $def:expr) => { |
131 | changed = true; | 132 | match ($existing, $def) { |
132 | } | 133 | (None, Some(_)) => { |
133 | if existing.values.is_none() && def.values.is_some() { | 134 | $existing = $def; |
134 | existing.values = def.values; | 135 | $changed = true; |
135 | changed = true; | 136 | } |
136 | } | 137 | (Some(e), Some(d)) if e.0 != d.0 => { |
137 | if existing.macros.is_none() && def.macros.is_some() { | 138 | mark::hit!(import_shadowed); |
138 | existing.macros = def.macros; | 139 | $existing = $def; |
139 | changed = true; | 140 | $changed = true; |
141 | } | ||
142 | _ => {} | ||
143 | } | ||
144 | }; | ||
140 | } | 145 | } |
141 | 146 | ||
147 | check_changed!(changed, existing.types, def.types); | ||
148 | check_changed!(changed, existing.values, def.values); | ||
149 | check_changed!(changed, existing.macros, def.macros); | ||
150 | |||
142 | changed | 151 | changed |
143 | } | 152 | } |
144 | 153 | ||
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs new file mode 100644 index 000000000..d7bc64e6c --- /dev/null +++ b/crates/ra_hir_def/src/item_tree.rs | |||
@@ -0,0 +1,697 @@ | |||
1 | //! A simplified AST that only contains items. | ||
2 | |||
3 | mod lower; | ||
4 | #[cfg(test)] | ||
5 | mod tests; | ||
6 | |||
7 | use std::{ | ||
8 | fmt::{self, Debug}, | ||
9 | hash::{Hash, Hasher}, | ||
10 | marker::PhantomData, | ||
11 | ops::{Index, Range}, | ||
12 | sync::Arc, | ||
13 | }; | ||
14 | |||
15 | use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner}; | ||
16 | use either::Either; | ||
17 | use hir_expand::{ | ||
18 | ast_id_map::FileAstId, | ||
19 | hygiene::Hygiene, | ||
20 | name::{name, AsName, Name}, | ||
21 | HirFileId, InFile, | ||
22 | }; | ||
23 | use ra_arena::{Arena, Idx, RawId}; | ||
24 | use ra_syntax::{ast, match_ast}; | ||
25 | use rustc_hash::FxHashMap; | ||
26 | use smallvec::SmallVec; | ||
27 | use test_utils::mark; | ||
28 | |||
29 | use crate::{ | ||
30 | attr::Attrs, | ||
31 | db::DefDatabase, | ||
32 | generics::GenericParams, | ||
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | ||
34 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
35 | visibility::RawVisibility, | ||
36 | }; | ||
37 | |||
38 | #[derive(Copy, Clone, Eq, PartialEq)] | ||
39 | pub struct RawVisibilityId(u32); | ||
40 | |||
41 | impl RawVisibilityId { | ||
42 | pub const PUB: Self = RawVisibilityId(u32::max_value()); | ||
43 | pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); | ||
44 | pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); | ||
45 | } | ||
46 | |||
47 | impl fmt::Debug for RawVisibilityId { | ||
48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
49 | let mut f = f.debug_tuple("RawVisibilityId"); | ||
50 | match *self { | ||
51 | Self::PUB => f.field(&"pub"), | ||
52 | Self::PRIV => f.field(&"pub(self)"), | ||
53 | Self::PUB_CRATE => f.field(&"pub(crate)"), | ||
54 | _ => f.field(&self.0), | ||
55 | }; | ||
56 | f.finish() | ||
57 | } | ||
58 | } | ||
59 | |||
60 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
61 | pub struct GenericParamsId(u32); | ||
62 | |||
63 | impl GenericParamsId { | ||
64 | pub const EMPTY: Self = GenericParamsId(u32::max_value()); | ||
65 | } | ||
66 | |||
67 | /// The item tree of a source file. | ||
68 | #[derive(Debug, Eq, PartialEq)] | ||
69 | pub struct ItemTree { | ||
70 | top_level: SmallVec<[ModItem; 1]>, | ||
71 | attrs: FxHashMap<AttrOwner, Attrs>, | ||
72 | inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>, | ||
73 | |||
74 | data: Option<Box<ItemTreeData>>, | ||
75 | } | ||
76 | |||
77 | impl ItemTree { | ||
78 | pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { | ||
79 | let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); | ||
80 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { | ||
81 | node | ||
82 | } else { | ||
83 | return Arc::new(Self::empty()); | ||
84 | }; | ||
85 | |||
86 | let hygiene = Hygiene::new(db.upcast(), file_id); | ||
87 | let ctx = lower::Ctx::new(db, hygiene.clone(), file_id); | ||
88 | let mut top_attrs = None; | ||
89 | let mut item_tree = match_ast! { | ||
90 | match syntax { | ||
91 | ast::SourceFile(file) => { | ||
92 | top_attrs = Some(Attrs::new(&file, &hygiene)); | ||
93 | ctx.lower_module_items(&file) | ||
94 | }, | ||
95 | ast::MacroItems(items) => { | ||
96 | ctx.lower_module_items(&items) | ||
97 | }, | ||
98 | // Macros can expand to expressions. We return an empty item tree in this case, but | ||
99 | // still need to collect inner items. | ||
100 | ast::Expr(e) => { | ||
101 | ctx.lower_inner_items(e.syntax()) | ||
102 | }, | ||
103 | _ => { | ||
104 | panic!("cannot create item tree from {:?}", syntax); | ||
105 | }, | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | if let Some(attrs) = top_attrs { | ||
110 | item_tree.attrs.insert(AttrOwner::TopLevel, attrs); | ||
111 | } | ||
112 | item_tree.shrink_to_fit(); | ||
113 | Arc::new(item_tree) | ||
114 | } | ||
115 | |||
116 | fn empty() -> Self { | ||
117 | Self { | ||
118 | top_level: Default::default(), | ||
119 | attrs: Default::default(), | ||
120 | inner_items: Default::default(), | ||
121 | data: Default::default(), | ||
122 | } | ||
123 | } | ||
124 | |||
125 | fn shrink_to_fit(&mut self) { | ||
126 | if let Some(data) = &mut self.data { | ||
127 | let ItemTreeData { | ||
128 | imports, | ||
129 | extern_crates, | ||
130 | functions, | ||
131 | structs, | ||
132 | fields, | ||
133 | unions, | ||
134 | enums, | ||
135 | variants, | ||
136 | consts, | ||
137 | statics, | ||
138 | traits, | ||
139 | impls, | ||
140 | type_aliases, | ||
141 | mods, | ||
142 | macro_calls, | ||
143 | exprs, | ||
144 | vis, | ||
145 | generics, | ||
146 | } = &mut **data; | ||
147 | |||
148 | imports.shrink_to_fit(); | ||
149 | extern_crates.shrink_to_fit(); | ||
150 | functions.shrink_to_fit(); | ||
151 | structs.shrink_to_fit(); | ||
152 | fields.shrink_to_fit(); | ||
153 | unions.shrink_to_fit(); | ||
154 | enums.shrink_to_fit(); | ||
155 | variants.shrink_to_fit(); | ||
156 | consts.shrink_to_fit(); | ||
157 | statics.shrink_to_fit(); | ||
158 | traits.shrink_to_fit(); | ||
159 | impls.shrink_to_fit(); | ||
160 | type_aliases.shrink_to_fit(); | ||
161 | mods.shrink_to_fit(); | ||
162 | macro_calls.shrink_to_fit(); | ||
163 | exprs.shrink_to_fit(); | ||
164 | |||
165 | vis.arena.shrink_to_fit(); | ||
166 | generics.arena.shrink_to_fit(); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /// Returns an iterator over all items located at the top level of the `HirFileId` this | ||
171 | /// `ItemTree` was created from. | ||
172 | pub fn top_level_items(&self) -> &[ModItem] { | ||
173 | &self.top_level | ||
174 | } | ||
175 | |||
176 | /// Returns the inner attributes of the source file. | ||
177 | pub fn top_level_attrs(&self) -> &Attrs { | ||
178 | self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) | ||
179 | } | ||
180 | |||
181 | pub fn attrs(&self, of: ModItem) -> &Attrs { | ||
182 | self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY) | ||
183 | } | ||
184 | |||
185 | /// Returns the lowered inner items that `ast` corresponds to. | ||
186 | /// | ||
187 | /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered | ||
188 | /// to multiple items in the `ItemTree`. | ||
189 | pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] { | ||
190 | &self.inner_items[&ast] | ||
191 | } | ||
192 | |||
193 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { | ||
194 | self.inner_items.values().flatten().copied() | ||
195 | } | ||
196 | |||
197 | pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { | ||
198 | // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty | ||
199 | // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). | ||
200 | let root = | ||
201 | db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree"); | ||
202 | |||
203 | let id = self[of.value].ast_id(); | ||
204 | let map = db.ast_id_map(of.file_id); | ||
205 | let ptr = map.get(id); | ||
206 | ptr.to_node(&root) | ||
207 | } | ||
208 | |||
209 | fn data(&self) -> &ItemTreeData { | ||
210 | self.data.as_ref().expect("attempted to access data of empty ItemTree") | ||
211 | } | ||
212 | |||
213 | fn data_mut(&mut self) -> &mut ItemTreeData { | ||
214 | self.data.get_or_insert_with(Box::default) | ||
215 | } | ||
216 | } | ||
217 | |||
218 | #[derive(Default, Debug, Eq, PartialEq)] | ||
219 | struct ItemVisibilities { | ||
220 | arena: Arena<RawVisibility>, | ||
221 | } | ||
222 | |||
223 | impl ItemVisibilities { | ||
224 | fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { | ||
225 | match &vis { | ||
226 | RawVisibility::Public => RawVisibilityId::PUB, | ||
227 | RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { | ||
228 | PathKind::Super(0) => RawVisibilityId::PRIV, | ||
229 | PathKind::Crate => RawVisibilityId::PUB_CRATE, | ||
230 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
231 | }, | ||
232 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | static VIS_PUB: RawVisibility = RawVisibility::Public; | ||
238 | static VIS_PRIV: RawVisibility = | ||
239 | RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); | ||
240 | static VIS_PUB_CRATE: RawVisibility = | ||
241 | RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); | ||
242 | |||
243 | #[derive(Default, Debug, Eq, PartialEq)] | ||
244 | struct GenericParamsStorage { | ||
245 | arena: Arena<GenericParams>, | ||
246 | } | ||
247 | |||
248 | impl GenericParamsStorage { | ||
249 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | ||
250 | if params.types.is_empty() && params.where_predicates.is_empty() { | ||
251 | return GenericParamsId::EMPTY; | ||
252 | } | ||
253 | |||
254 | GenericParamsId(self.arena.alloc(params).into_raw().into()) | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static EMPTY_GENERICS: GenericParams = | ||
259 | GenericParams { types: Arena::new(), where_predicates: Vec::new() }; | ||
260 | |||
261 | #[derive(Default, Debug, Eq, PartialEq)] | ||
262 | struct ItemTreeData { | ||
263 | imports: Arena<Import>, | ||
264 | extern_crates: Arena<ExternCrate>, | ||
265 | functions: Arena<Function>, | ||
266 | structs: Arena<Struct>, | ||
267 | fields: Arena<Field>, | ||
268 | unions: Arena<Union>, | ||
269 | enums: Arena<Enum>, | ||
270 | variants: Arena<Variant>, | ||
271 | consts: Arena<Const>, | ||
272 | statics: Arena<Static>, | ||
273 | traits: Arena<Trait>, | ||
274 | impls: Arena<Impl>, | ||
275 | type_aliases: Arena<TypeAlias>, | ||
276 | mods: Arena<Mod>, | ||
277 | macro_calls: Arena<MacroCall>, | ||
278 | exprs: Arena<Expr>, | ||
279 | |||
280 | vis: ItemVisibilities, | ||
281 | generics: GenericParamsStorage, | ||
282 | } | ||
283 | |||
284 | #[derive(Debug, Eq, PartialEq, Hash)] | ||
285 | enum AttrOwner { | ||
286 | /// Attributes on an item. | ||
287 | ModItem(ModItem), | ||
288 | /// Inner attributes of the source file. | ||
289 | TopLevel, | ||
290 | // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. | ||
291 | } | ||
292 | |||
293 | /// Trait implemented by all nodes in the item tree. | ||
294 | pub trait ItemTreeNode: Clone { | ||
295 | type Source: AstNode + Into<ast::ModuleItem>; | ||
296 | |||
297 | fn ast_id(&self) -> FileAstId<Self::Source>; | ||
298 | |||
299 | /// Looks up an instance of `Self` in an item tree. | ||
300 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; | ||
301 | |||
302 | /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. | ||
303 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>; | ||
304 | |||
305 | /// Upcasts a `FileItemTreeId` to a generic `ModItem`. | ||
306 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem; | ||
307 | } | ||
308 | |||
309 | pub struct FileItemTreeId<N: ItemTreeNode> { | ||
310 | index: Idx<N>, | ||
311 | _p: PhantomData<N>, | ||
312 | } | ||
313 | |||
314 | impl<N: ItemTreeNode> Clone for FileItemTreeId<N> { | ||
315 | fn clone(&self) -> Self { | ||
316 | Self { index: self.index, _p: PhantomData } | ||
317 | } | ||
318 | } | ||
319 | impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {} | ||
320 | |||
321 | impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> { | ||
322 | fn eq(&self, other: &FileItemTreeId<N>) -> bool { | ||
323 | self.index == other.index | ||
324 | } | ||
325 | } | ||
326 | impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {} | ||
327 | |||
328 | impl<N: ItemTreeNode> Hash for FileItemTreeId<N> { | ||
329 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
330 | self.index.hash(state) | ||
331 | } | ||
332 | } | ||
333 | |||
334 | impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> { | ||
335 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
336 | self.index.fmt(f) | ||
337 | } | ||
338 | } | ||
339 | |||
340 | pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>; | ||
341 | |||
342 | macro_rules! mod_items { | ||
343 | ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { | ||
344 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
345 | pub enum ModItem { | ||
346 | $( | ||
347 | $typ(FileItemTreeId<$typ>), | ||
348 | )+ | ||
349 | } | ||
350 | |||
351 | $( | ||
352 | impl From<FileItemTreeId<$typ>> for ModItem { | ||
353 | fn from(id: FileItemTreeId<$typ>) -> ModItem { | ||
354 | ModItem::$typ(id) | ||
355 | } | ||
356 | } | ||
357 | )+ | ||
358 | |||
359 | $( | ||
360 | impl ItemTreeNode for $typ { | ||
361 | type Source = $ast; | ||
362 | |||
363 | fn ast_id(&self) -> FileAstId<Self::Source> { | ||
364 | self.ast_id | ||
365 | } | ||
366 | |||
367 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { | ||
368 | &tree.data().$fld[index] | ||
369 | } | ||
370 | |||
371 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { | ||
372 | if let ModItem::$typ(id) = mod_item { | ||
373 | Some(id) | ||
374 | } else { | ||
375 | None | ||
376 | } | ||
377 | } | ||
378 | |||
379 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem { | ||
380 | ModItem::$typ(id) | ||
381 | } | ||
382 | } | ||
383 | |||
384 | impl Index<Idx<$typ>> for ItemTree { | ||
385 | type Output = $typ; | ||
386 | |||
387 | fn index(&self, index: Idx<$typ>) -> &Self::Output { | ||
388 | &self.data().$fld[index] | ||
389 | } | ||
390 | } | ||
391 | )+ | ||
392 | }; | ||
393 | } | ||
394 | |||
395 | mod_items! { | ||
396 | Import in imports -> ast::UseItem, | ||
397 | ExternCrate in extern_crates -> ast::ExternCrateItem, | ||
398 | Function in functions -> ast::FnDef, | ||
399 | Struct in structs -> ast::StructDef, | ||
400 | Union in unions -> ast::UnionDef, | ||
401 | Enum in enums -> ast::EnumDef, | ||
402 | Const in consts -> ast::ConstDef, | ||
403 | Static in statics -> ast::StaticDef, | ||
404 | Trait in traits -> ast::TraitDef, | ||
405 | Impl in impls -> ast::ImplDef, | ||
406 | TypeAlias in type_aliases -> ast::TypeAliasDef, | ||
407 | Mod in mods -> ast::Module, | ||
408 | MacroCall in macro_calls -> ast::MacroCall, | ||
409 | } | ||
410 | |||
411 | macro_rules! impl_index { | ||
412 | ( $($fld:ident: $t:ty),+ $(,)? ) => { | ||
413 | $( | ||
414 | impl Index<Idx<$t>> for ItemTree { | ||
415 | type Output = $t; | ||
416 | |||
417 | fn index(&self, index: Idx<$t>) -> &Self::Output { | ||
418 | &self.data().$fld[index] | ||
419 | } | ||
420 | } | ||
421 | )+ | ||
422 | }; | ||
423 | } | ||
424 | |||
425 | impl_index!(fields: Field, variants: Variant, exprs: Expr); | ||
426 | |||
427 | impl Index<RawVisibilityId> for ItemTree { | ||
428 | type Output = RawVisibility; | ||
429 | fn index(&self, index: RawVisibilityId) -> &Self::Output { | ||
430 | match index { | ||
431 | RawVisibilityId::PRIV => &VIS_PRIV, | ||
432 | RawVisibilityId::PUB => &VIS_PUB, | ||
433 | RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, | ||
434 | _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | impl Index<GenericParamsId> for ItemTree { | ||
440 | type Output = GenericParams; | ||
441 | |||
442 | fn index(&self, index: GenericParamsId) -> &Self::Output { | ||
443 | match index { | ||
444 | GenericParamsId::EMPTY => &EMPTY_GENERICS, | ||
445 | _ => &self.data().generics.arena[Idx::from_raw(index.0.into())], | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | |||
450 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | ||
451 | type Output = N; | ||
452 | fn index(&self, id: FileItemTreeId<N>) -> &N { | ||
453 | N::lookup(self, id.index) | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /// A desugared `use` import. | ||
458 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
459 | pub struct Import { | ||
460 | pub path: ModPath, | ||
461 | pub alias: Option<ImportAlias>, | ||
462 | pub visibility: RawVisibilityId, | ||
463 | pub is_glob: bool, | ||
464 | pub is_prelude: bool, | ||
465 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many | ||
466 | /// `Import`s can map to the same `use` item. | ||
467 | pub ast_id: FileAstId<ast::UseItem>, | ||
468 | } | ||
469 | |||
470 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
471 | pub struct ExternCrate { | ||
472 | pub path: ModPath, | ||
473 | pub alias: Option<ImportAlias>, | ||
474 | pub visibility: RawVisibilityId, | ||
475 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
476 | pub is_macro_use: bool, | ||
477 | pub ast_id: FileAstId<ast::ExternCrateItem>, | ||
478 | } | ||
479 | |||
480 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
481 | pub struct Function { | ||
482 | pub name: Name, | ||
483 | pub visibility: RawVisibilityId, | ||
484 | pub generic_params: GenericParamsId, | ||
485 | pub has_self_param: bool, | ||
486 | pub is_unsafe: bool, | ||
487 | pub params: Box<[TypeRef]>, | ||
488 | pub ret_type: TypeRef, | ||
489 | pub ast_id: FileAstId<ast::FnDef>, | ||
490 | } | ||
491 | |||
492 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
493 | pub struct Struct { | ||
494 | pub name: Name, | ||
495 | pub visibility: RawVisibilityId, | ||
496 | pub generic_params: GenericParamsId, | ||
497 | pub fields: Fields, | ||
498 | pub ast_id: FileAstId<ast::StructDef>, | ||
499 | pub kind: StructDefKind, | ||
500 | } | ||
501 | |||
502 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
503 | pub enum StructDefKind { | ||
504 | /// `struct S { ... }` - type namespace only. | ||
505 | Record, | ||
506 | /// `struct S(...);` | ||
507 | Tuple, | ||
508 | /// `struct S;` | ||
509 | Unit, | ||
510 | } | ||
511 | |||
512 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
513 | pub struct Union { | ||
514 | pub name: Name, | ||
515 | pub visibility: RawVisibilityId, | ||
516 | pub generic_params: GenericParamsId, | ||
517 | pub fields: Fields, | ||
518 | pub ast_id: FileAstId<ast::UnionDef>, | ||
519 | } | ||
520 | |||
521 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
522 | pub struct Enum { | ||
523 | pub name: Name, | ||
524 | pub visibility: RawVisibilityId, | ||
525 | pub generic_params: GenericParamsId, | ||
526 | pub variants: Range<Idx<Variant>>, | ||
527 | pub ast_id: FileAstId<ast::EnumDef>, | ||
528 | } | ||
529 | |||
530 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
531 | pub struct Const { | ||
532 | /// const _: () = (); | ||
533 | pub name: Option<Name>, | ||
534 | pub visibility: RawVisibilityId, | ||
535 | pub type_ref: TypeRef, | ||
536 | pub ast_id: FileAstId<ast::ConstDef>, | ||
537 | } | ||
538 | |||
539 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
540 | pub struct Static { | ||
541 | pub name: Name, | ||
542 | pub visibility: RawVisibilityId, | ||
543 | pub mutable: bool, | ||
544 | pub type_ref: TypeRef, | ||
545 | pub ast_id: FileAstId<ast::StaticDef>, | ||
546 | } | ||
547 | |||
548 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
549 | pub struct Trait { | ||
550 | pub name: Name, | ||
551 | pub visibility: RawVisibilityId, | ||
552 | pub generic_params: GenericParamsId, | ||
553 | pub auto: bool, | ||
554 | pub items: Box<[AssocItem]>, | ||
555 | pub ast_id: FileAstId<ast::TraitDef>, | ||
556 | } | ||
557 | |||
558 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
559 | pub struct Impl { | ||
560 | pub generic_params: GenericParamsId, | ||
561 | pub target_trait: Option<TypeRef>, | ||
562 | pub target_type: TypeRef, | ||
563 | pub is_negative: bool, | ||
564 | pub items: Box<[AssocItem]>, | ||
565 | pub ast_id: FileAstId<ast::ImplDef>, | ||
566 | } | ||
567 | |||
568 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
569 | pub struct TypeAlias { | ||
570 | pub name: Name, | ||
571 | pub visibility: RawVisibilityId, | ||
572 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | ||
573 | pub bounds: Box<[TypeBound]>, | ||
574 | pub generic_params: GenericParamsId, | ||
575 | pub type_ref: Option<TypeRef>, | ||
576 | pub ast_id: FileAstId<ast::TypeAliasDef>, | ||
577 | } | ||
578 | |||
579 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
580 | pub struct Mod { | ||
581 | pub name: Name, | ||
582 | pub visibility: RawVisibilityId, | ||
583 | pub kind: ModKind, | ||
584 | pub ast_id: FileAstId<ast::Module>, | ||
585 | } | ||
586 | |||
587 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
588 | pub enum ModKind { | ||
589 | /// `mod m { ... }` | ||
590 | Inline { items: Box<[ModItem]> }, | ||
591 | |||
592 | /// `mod m;` | ||
593 | Outline {}, | ||
594 | } | ||
595 | |||
596 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
597 | pub struct MacroCall { | ||
598 | /// For `macro_rules!` declarations, this is the name of the declared macro. | ||
599 | pub name: Option<Name>, | ||
600 | /// Path to the called macro. | ||
601 | pub path: ModPath, | ||
602 | /// Has `#[macro_export]`. | ||
603 | pub is_export: bool, | ||
604 | /// Has `#[macro_export(local_inner_macros)]`. | ||
605 | pub is_local_inner: bool, | ||
606 | /// Has `#[rustc_builtin_macro]`. | ||
607 | pub is_builtin: bool, | ||
608 | pub ast_id: FileAstId<ast::MacroCall>, | ||
609 | } | ||
610 | |||
611 | // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array | ||
612 | // lengths, but we don't do much with them yet. | ||
613 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
614 | pub struct Expr; | ||
615 | |||
616 | macro_rules! impl_froms { | ||
617 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | ||
618 | $( | ||
619 | impl From<$t> for $e { | ||
620 | fn from(it: $t) -> $e { | ||
621 | $e::$v(it) | ||
622 | } | ||
623 | } | ||
624 | )* | ||
625 | } | ||
626 | } | ||
627 | |||
628 | impl ModItem { | ||
629 | pub fn as_assoc_item(&self) -> Option<AssocItem> { | ||
630 | match self { | ||
631 | ModItem::Import(_) | ||
632 | | ModItem::ExternCrate(_) | ||
633 | | ModItem::Struct(_) | ||
634 | | ModItem::Union(_) | ||
635 | | ModItem::Enum(_) | ||
636 | | ModItem::Static(_) | ||
637 | | ModItem::Trait(_) | ||
638 | | ModItem::Impl(_) | ||
639 | | ModItem::Mod(_) => None, | ||
640 | ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), | ||
641 | ModItem::Const(konst) => Some(AssocItem::Const(*konst)), | ||
642 | ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), | ||
643 | ModItem::Function(func) => Some(AssocItem::Function(*func)), | ||
644 | } | ||
645 | } | ||
646 | |||
647 | pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { | ||
648 | N::id_from_mod_item(self) | ||
649 | } | ||
650 | } | ||
651 | |||
652 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
653 | pub enum AssocItem { | ||
654 | Function(FileItemTreeId<Function>), | ||
655 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
656 | Const(FileItemTreeId<Const>), | ||
657 | MacroCall(FileItemTreeId<MacroCall>), | ||
658 | } | ||
659 | |||
660 | impl_froms!(AssocItem { | ||
661 | Function(FileItemTreeId<Function>), | ||
662 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
663 | Const(FileItemTreeId<Const>), | ||
664 | MacroCall(FileItemTreeId<MacroCall>), | ||
665 | }); | ||
666 | |||
667 | impl From<AssocItem> for ModItem { | ||
668 | fn from(item: AssocItem) -> Self { | ||
669 | match item { | ||
670 | AssocItem::Function(it) => it.into(), | ||
671 | AssocItem::TypeAlias(it) => it.into(), | ||
672 | AssocItem::Const(it) => it.into(), | ||
673 | AssocItem::MacroCall(it) => it.into(), | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | |||
678 | #[derive(Debug, Eq, PartialEq)] | ||
679 | pub struct Variant { | ||
680 | pub name: Name, | ||
681 | pub fields: Fields, | ||
682 | } | ||
683 | |||
684 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
685 | pub enum Fields { | ||
686 | Record(Range<Idx<Field>>), | ||
687 | Tuple(Range<Idx<Field>>), | ||
688 | Unit, | ||
689 | } | ||
690 | |||
691 | /// A single field of an enum variant or struct | ||
692 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
693 | pub struct Field { | ||
694 | pub name: Name, | ||
695 | pub type_ref: TypeRef, | ||
696 | pub visibility: RawVisibilityId, | ||
697 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs new file mode 100644 index 000000000..f10ad25f7 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/lower.rs | |||
@@ -0,0 +1,695 @@ | |||
1 | //! AST -> `ItemTree` lowering code. | ||
2 | |||
3 | use super::*; | ||
4 | use crate::{ | ||
5 | attr::Attrs, | ||
6 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | ||
7 | }; | ||
8 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; | ||
9 | use ra_arena::map::ArenaMap; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, ModuleItemOwner}, | ||
12 | SyntaxNode, | ||
13 | }; | ||
14 | use smallvec::SmallVec; | ||
15 | use std::{collections::hash_map::Entry, mem, sync::Arc}; | ||
16 | |||
17 | fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { | ||
18 | FileItemTreeId { index, _p: PhantomData } | ||
19 | } | ||
20 | |||
21 | struct ModItems(SmallVec<[ModItem; 1]>); | ||
22 | |||
23 | impl<T> From<T> for ModItems | ||
24 | where | ||
25 | T: Into<ModItem>, | ||
26 | { | ||
27 | fn from(t: T) -> Self { | ||
28 | ModItems(SmallVec::from_buf([t.into(); 1])) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub(super) struct Ctx { | ||
33 | tree: ItemTree, | ||
34 | hygiene: Hygiene, | ||
35 | file: HirFileId, | ||
36 | source_ast_id_map: Arc<AstIdMap>, | ||
37 | body_ctx: crate::body::LowerCtx, | ||
38 | inner_items: Vec<ModItem>, | ||
39 | forced_visibility: Option<RawVisibilityId>, | ||
40 | } | ||
41 | |||
42 | impl Ctx { | ||
43 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | ||
44 | Self { | ||
45 | tree: ItemTree::empty(), | ||
46 | hygiene, | ||
47 | file, | ||
48 | source_ast_id_map: db.ast_id_map(file), | ||
49 | body_ctx: crate::body::LowerCtx::new(db, file), | ||
50 | inner_items: Vec::new(), | ||
51 | forced_visibility: None, | ||
52 | } | ||
53 | } | ||
54 | |||
55 | pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { | ||
56 | self.tree.top_level = item_owner | ||
57 | .items() | ||
58 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
59 | .flat_map(|items| items.0) | ||
60 | .collect(); | ||
61 | self.tree | ||
62 | } | ||
63 | |||
64 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | ||
65 | self.collect_inner_items(within); | ||
66 | self.tree | ||
67 | } | ||
68 | |||
69 | fn data(&mut self) -> &mut ItemTreeData { | ||
70 | self.tree.data_mut() | ||
71 | } | ||
72 | |||
73 | fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> { | ||
74 | assert!(inner || self.inner_items.is_empty()); | ||
75 | |||
76 | // Collect inner items for 1-to-1-lowered items. | ||
77 | match item { | ||
78 | ast::ModuleItem::StructDef(_) | ||
79 | | ast::ModuleItem::UnionDef(_) | ||
80 | | ast::ModuleItem::EnumDef(_) | ||
81 | | ast::ModuleItem::FnDef(_) | ||
82 | | ast::ModuleItem::TypeAliasDef(_) | ||
83 | | ast::ModuleItem::ConstDef(_) | ||
84 | | ast::ModuleItem::StaticDef(_) | ||
85 | | ast::ModuleItem::MacroCall(_) => { | ||
86 | // Skip this if we're already collecting inner items. We'll descend into all nodes | ||
87 | // already. | ||
88 | if !inner { | ||
89 | self.collect_inner_items(item.syntax()); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // These are handled in their respective `lower_X` method (since we can't just blindly | ||
94 | // walk them). | ||
95 | ast::ModuleItem::TraitDef(_) | ||
96 | | ast::ModuleItem::ImplDef(_) | ||
97 | | ast::ModuleItem::ExternBlock(_) => {} | ||
98 | |||
99 | // These don't have inner items. | ||
100 | ast::ModuleItem::Module(_) | ||
101 | | ast::ModuleItem::ExternCrateItem(_) | ||
102 | | ast::ModuleItem::UseItem(_) => {} | ||
103 | }; | ||
104 | |||
105 | let attrs = Attrs::new(item, &self.hygiene); | ||
106 | let items = match item { | ||
107 | ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into), | ||
108 | ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into), | ||
109 | ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into), | ||
110 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), | ||
111 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), | ||
112 | ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into), | ||
113 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), | ||
114 | ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into), | ||
115 | ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into), | ||
116 | ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into), | ||
117 | ast::ModuleItem::UseItem(ast) => Some(ModItems( | ||
118 | self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), | ||
119 | )), | ||
120 | ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into), | ||
121 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
122 | ast::ModuleItem::ExternBlock(ast) => { | ||
123 | Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) | ||
124 | } | ||
125 | }; | ||
126 | |||
127 | if !attrs.is_empty() { | ||
128 | for item in items.iter().flat_map(|items| &items.0) { | ||
129 | self.add_attrs(*item, attrs.clone()); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | items | ||
134 | } | ||
135 | |||
136 | fn add_attrs(&mut self, item: ModItem, attrs: Attrs) { | ||
137 | match self.tree.attrs.entry(AttrOwner::ModItem(item)) { | ||
138 | Entry::Occupied(mut entry) => { | ||
139 | *entry.get_mut() = entry.get().merge(attrs); | ||
140 | } | ||
141 | Entry::Vacant(entry) => { | ||
142 | entry.insert(attrs); | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | fn collect_inner_items(&mut self, container: &SyntaxNode) { | ||
148 | let forced_vis = self.forced_visibility.take(); | ||
149 | let mut inner_items = mem::take(&mut self.tree.inner_items); | ||
150 | inner_items.extend( | ||
151 | container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| { | ||
152 | let ast_id = self.source_ast_id_map.ast_id(&item); | ||
153 | Some((ast_id, self.lower_mod_item(&item, true)?.0)) | ||
154 | }), | ||
155 | ); | ||
156 | self.tree.inner_items = inner_items; | ||
157 | self.forced_visibility = forced_vis; | ||
158 | } | ||
159 | |||
160 | fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> { | ||
161 | match item { | ||
162 | ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into), | ||
163 | ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into), | ||
164 | ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()), | ||
165 | ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
166 | _ => None, | ||
167 | } | ||
168 | } | ||
169 | |||
170 | fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> { | ||
171 | let visibility = self.lower_visibility(strukt); | ||
172 | let name = strukt.name()?.as_name(); | ||
173 | let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); | ||
174 | let fields = self.lower_fields(&strukt.kind()); | ||
175 | let ast_id = self.source_ast_id_map.ast_id(strukt); | ||
176 | let kind = match strukt.kind() { | ||
177 | ast::StructKind::Record(_) => StructDefKind::Record, | ||
178 | ast::StructKind::Tuple(_) => StructDefKind::Tuple, | ||
179 | ast::StructKind::Unit => StructDefKind::Unit, | ||
180 | }; | ||
181 | let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; | ||
182 | Some(id(self.data().structs.alloc(res))) | ||
183 | } | ||
184 | |||
185 | fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { | ||
186 | match strukt_kind { | ||
187 | ast::StructKind::Record(it) => { | ||
188 | let range = self.lower_record_fields(it); | ||
189 | Fields::Record(range) | ||
190 | } | ||
191 | ast::StructKind::Tuple(it) => { | ||
192 | let range = self.lower_tuple_fields(it); | ||
193 | Fields::Tuple(range) | ||
194 | } | ||
195 | ast::StructKind::Unit => Fields::Unit, | ||
196 | } | ||
197 | } | ||
198 | |||
199 | fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range<Idx<Field>> { | ||
200 | let start = self.next_field_idx(); | ||
201 | for field in fields.fields() { | ||
202 | if let Some(data) = self.lower_record_field(&field) { | ||
203 | self.data().fields.alloc(data); | ||
204 | } | ||
205 | } | ||
206 | let end = self.next_field_idx(); | ||
207 | start..end | ||
208 | } | ||
209 | |||
210 | fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> { | ||
211 | let name = field.name()?.as_name(); | ||
212 | let visibility = self.lower_visibility(field); | ||
213 | let type_ref = self.lower_type_ref(&field.ascribed_type()?); | ||
214 | let res = Field { name, type_ref, visibility }; | ||
215 | Some(res) | ||
216 | } | ||
217 | |||
218 | fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range<Idx<Field>> { | ||
219 | let start = self.next_field_idx(); | ||
220 | for (i, field) in fields.fields().enumerate() { | ||
221 | if let Some(data) = self.lower_tuple_field(i, &field) { | ||
222 | self.data().fields.alloc(data); | ||
223 | } | ||
224 | } | ||
225 | let end = self.next_field_idx(); | ||
226 | start..end | ||
227 | } | ||
228 | |||
229 | fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> { | ||
230 | let name = Name::new_tuple_field(idx); | ||
231 | let visibility = self.lower_visibility(field); | ||
232 | let type_ref = self.lower_type_ref(&field.type_ref()?); | ||
233 | let res = Field { name, type_ref, visibility }; | ||
234 | Some(res) | ||
235 | } | ||
236 | |||
237 | fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> { | ||
238 | let visibility = self.lower_visibility(union); | ||
239 | let name = union.name()?.as_name(); | ||
240 | let generic_params = self.lower_generic_params(GenericsOwner::Union, union); | ||
241 | let fields = match union.record_field_def_list() { | ||
242 | Some(record_field_def_list) => { | ||
243 | self.lower_fields(&StructKind::Record(record_field_def_list)) | ||
244 | } | ||
245 | None => Fields::Record(self.next_field_idx()..self.next_field_idx()), | ||
246 | }; | ||
247 | let ast_id = self.source_ast_id_map.ast_id(union); | ||
248 | let res = Union { name, visibility, generic_params, fields, ast_id }; | ||
249 | Some(id(self.data().unions.alloc(res))) | ||
250 | } | ||
251 | |||
252 | fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> { | ||
253 | let visibility = self.lower_visibility(enum_); | ||
254 | let name = enum_.name()?.as_name(); | ||
255 | let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); | ||
256 | let variants = match &enum_.variant_list() { | ||
257 | Some(variant_list) => self.lower_variants(variant_list), | ||
258 | None => self.next_variant_idx()..self.next_variant_idx(), | ||
259 | }; | ||
260 | let ast_id = self.source_ast_id_map.ast_id(enum_); | ||
261 | let res = Enum { name, visibility, generic_params, variants, ast_id }; | ||
262 | Some(id(self.data().enums.alloc(res))) | ||
263 | } | ||
264 | |||
265 | fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> { | ||
266 | let start = self.next_variant_idx(); | ||
267 | for variant in variants.variants() { | ||
268 | if let Some(data) = self.lower_variant(&variant) { | ||
269 | self.data().variants.alloc(data); | ||
270 | } | ||
271 | } | ||
272 | let end = self.next_variant_idx(); | ||
273 | start..end | ||
274 | } | ||
275 | |||
276 | fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> { | ||
277 | let name = variant.name()?.as_name(); | ||
278 | let fields = self.lower_fields(&variant.kind()); | ||
279 | let res = Variant { name, fields }; | ||
280 | Some(res) | ||
281 | } | ||
282 | |||
283 | fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> { | ||
284 | let visibility = self.lower_visibility(func); | ||
285 | let name = func.name()?.as_name(); | ||
286 | |||
287 | let mut params = Vec::new(); | ||
288 | let mut has_self_param = false; | ||
289 | if let Some(param_list) = func.param_list() { | ||
290 | if let Some(self_param) = param_list.self_param() { | ||
291 | let self_type = match self_param.ascribed_type() { | ||
292 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
293 | None => { | ||
294 | let self_type = TypeRef::Path(name![Self].into()); | ||
295 | match self_param.kind() { | ||
296 | ast::SelfParamKind::Owned => self_type, | ||
297 | ast::SelfParamKind::Ref => { | ||
298 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
299 | } | ||
300 | ast::SelfParamKind::MutRef => { | ||
301 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | }; | ||
306 | params.push(self_type); | ||
307 | has_self_param = true; | ||
308 | } | ||
309 | for param in param_list.params() { | ||
310 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type()); | ||
311 | params.push(type_ref); | ||
312 | } | ||
313 | } | ||
314 | let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { | ||
315 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
316 | _ => TypeRef::unit(), | ||
317 | }; | ||
318 | |||
319 | let ret_type = if func.async_token().is_some() { | ||
320 | let future_impl = desugar_future_path(ret_type); | ||
321 | let ty_bound = TypeBound::Path(future_impl); | ||
322 | TypeRef::ImplTrait(vec![ty_bound]) | ||
323 | } else { | ||
324 | ret_type | ||
325 | }; | ||
326 | |||
327 | let ast_id = self.source_ast_id_map.ast_id(func); | ||
328 | let mut res = Function { | ||
329 | name, | ||
330 | visibility, | ||
331 | generic_params: GenericParamsId::EMPTY, | ||
332 | has_self_param, | ||
333 | is_unsafe: func.unsafe_token().is_some(), | ||
334 | params: params.into_boxed_slice(), | ||
335 | ret_type, | ||
336 | ast_id, | ||
337 | }; | ||
338 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | ||
339 | |||
340 | Some(id(self.data().functions.alloc(res))) | ||
341 | } | ||
342 | |||
343 | fn lower_type_alias( | ||
344 | &mut self, | ||
345 | type_alias: &ast::TypeAliasDef, | ||
346 | ) -> Option<FileItemTreeId<TypeAlias>> { | ||
347 | let name = type_alias.name()?.as_name(); | ||
348 | let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it)); | ||
349 | let visibility = self.lower_visibility(type_alias); | ||
350 | let bounds = self.lower_type_bounds(type_alias); | ||
351 | let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); | ||
352 | let ast_id = self.source_ast_id_map.ast_id(type_alias); | ||
353 | let res = TypeAlias { | ||
354 | name, | ||
355 | visibility, | ||
356 | bounds: bounds.into_boxed_slice(), | ||
357 | generic_params, | ||
358 | type_ref, | ||
359 | ast_id, | ||
360 | }; | ||
361 | Some(id(self.data().type_aliases.alloc(res))) | ||
362 | } | ||
363 | |||
364 | fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> { | ||
365 | let name = static_.name()?.as_name(); | ||
366 | let type_ref = self.lower_type_ref_opt(static_.ascribed_type()); | ||
367 | let visibility = self.lower_visibility(static_); | ||
368 | let mutable = static_.mut_token().is_some(); | ||
369 | let ast_id = self.source_ast_id_map.ast_id(static_); | ||
370 | let res = Static { name, visibility, mutable, type_ref, ast_id }; | ||
371 | Some(id(self.data().statics.alloc(res))) | ||
372 | } | ||
373 | |||
374 | fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> { | ||
375 | let name = konst.name().map(|it| it.as_name()); | ||
376 | let type_ref = self.lower_type_ref_opt(konst.ascribed_type()); | ||
377 | let visibility = self.lower_visibility(konst); | ||
378 | let ast_id = self.source_ast_id_map.ast_id(konst); | ||
379 | let res = Const { name, visibility, type_ref, ast_id }; | ||
380 | id(self.data().consts.alloc(res)) | ||
381 | } | ||
382 | |||
383 | fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { | ||
384 | let name = module.name()?.as_name(); | ||
385 | let visibility = self.lower_visibility(module); | ||
386 | let kind = if module.semicolon_token().is_some() { | ||
387 | ModKind::Outline {} | ||
388 | } else { | ||
389 | ModKind::Inline { | ||
390 | items: module | ||
391 | .item_list() | ||
392 | .map(|list| { | ||
393 | list.items() | ||
394 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
395 | .flat_map(|items| items.0) | ||
396 | .collect() | ||
397 | }) | ||
398 | .unwrap_or_else(|| { | ||
399 | mark::hit!(name_res_works_for_broken_modules); | ||
400 | Box::new([]) as Box<[_]> | ||
401 | }), | ||
402 | } | ||
403 | }; | ||
404 | let ast_id = self.source_ast_id_map.ast_id(module); | ||
405 | let res = Mod { name, visibility, kind, ast_id }; | ||
406 | Some(id(self.data().mods.alloc(res))) | ||
407 | } | ||
408 | |||
409 | fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> { | ||
410 | let name = trait_def.name()?.as_name(); | ||
411 | let visibility = self.lower_visibility(trait_def); | ||
412 | let generic_params = | ||
413 | self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); | ||
414 | let auto = trait_def.auto_token().is_some(); | ||
415 | let items = trait_def.item_list().map(|list| { | ||
416 | self.with_inherited_visibility(visibility, |this| { | ||
417 | list.items() | ||
418 | .filter_map(|item| { | ||
419 | let attrs = Attrs::new(&item, &this.hygiene); | ||
420 | this.collect_inner_items(item.syntax()); | ||
421 | this.lower_assoc_item(&item).map(|item| { | ||
422 | this.add_attrs(item.into(), attrs); | ||
423 | item | ||
424 | }) | ||
425 | }) | ||
426 | .collect() | ||
427 | }) | ||
428 | }); | ||
429 | let ast_id = self.source_ast_id_map.ast_id(trait_def); | ||
430 | let res = Trait { | ||
431 | name, | ||
432 | visibility, | ||
433 | generic_params, | ||
434 | auto, | ||
435 | items: items.unwrap_or_default(), | ||
436 | ast_id, | ||
437 | }; | ||
438 | Some(id(self.data().traits.alloc(res))) | ||
439 | } | ||
440 | |||
441 | fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> { | ||
442 | let generic_params = | ||
443 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | ||
444 | let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); | ||
445 | let target_type = self.lower_type_ref(&impl_def.target_type()?); | ||
446 | let is_negative = impl_def.excl_token().is_some(); | ||
447 | |||
448 | // We cannot use `assoc_items()` here as that does not include macro calls. | ||
449 | let items = impl_def | ||
450 | .item_list()? | ||
451 | .items() | ||
452 | .filter_map(|item| { | ||
453 | self.collect_inner_items(item.syntax()); | ||
454 | let assoc = self.lower_assoc_item(&item)?; | ||
455 | let attrs = Attrs::new(&item, &self.hygiene); | ||
456 | self.add_attrs(assoc.into(), attrs); | ||
457 | Some(assoc) | ||
458 | }) | ||
459 | .collect(); | ||
460 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | ||
461 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; | ||
462 | Some(id(self.data().impls.alloc(res))) | ||
463 | } | ||
464 | |||
465 | fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> { | ||
466 | // FIXME: cfg_attr | ||
467 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
468 | let visibility = self.lower_visibility(use_item); | ||
469 | let ast_id = self.source_ast_id_map.ast_id(use_item); | ||
470 | |||
471 | // Every use item can expand to many `Import`s. | ||
472 | let mut imports = Vec::new(); | ||
473 | let tree = self.tree.data_mut(); | ||
474 | ModPath::expand_use_item( | ||
475 | InFile::new(self.file, use_item.clone()), | ||
476 | &self.hygiene, | ||
477 | |path, _tree, is_glob, alias| { | ||
478 | imports.push(id(tree.imports.alloc(Import { | ||
479 | path, | ||
480 | alias, | ||
481 | visibility, | ||
482 | is_glob, | ||
483 | is_prelude, | ||
484 | ast_id, | ||
485 | }))); | ||
486 | }, | ||
487 | ); | ||
488 | |||
489 | imports | ||
490 | } | ||
491 | |||
492 | fn lower_extern_crate( | ||
493 | &mut self, | ||
494 | extern_crate: &ast::ExternCrateItem, | ||
495 | ) -> Option<FileItemTreeId<ExternCrate>> { | ||
496 | let path = ModPath::from_name_ref(&extern_crate.name_ref()?); | ||
497 | let alias = extern_crate.alias().map(|a| { | ||
498 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
499 | }); | ||
500 | let visibility = self.lower_visibility(extern_crate); | ||
501 | let ast_id = self.source_ast_id_map.ast_id(extern_crate); | ||
502 | // FIXME: cfg_attr | ||
503 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
504 | |||
505 | let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id }; | ||
506 | Some(id(self.data().extern_crates.alloc(res))) | ||
507 | } | ||
508 | |||
509 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | ||
510 | let name = m.name().map(|it| it.as_name()); | ||
511 | let attrs = Attrs::new(m, &self.hygiene); | ||
512 | let path = ModPath::from_src(m.path()?, &self.hygiene)?; | ||
513 | |||
514 | let ast_id = self.source_ast_id_map.ast_id(m); | ||
515 | |||
516 | // FIXME: cfg_attr | ||
517 | let export_attr = attrs.by_key("macro_export"); | ||
518 | |||
519 | let is_export = export_attr.exists(); | ||
520 | let is_local_inner = if is_export { | ||
521 | export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { | ||
522 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { | ||
523 | ident.text.contains("local_inner_macros") | ||
524 | } | ||
525 | _ => false, | ||
526 | }) | ||
527 | } else { | ||
528 | false | ||
529 | }; | ||
530 | |||
531 | let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); | ||
532 | let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id }; | ||
533 | Some(id(self.data().macro_calls.alloc(res))) | ||
534 | } | ||
535 | |||
536 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { | ||
537 | block.extern_item_list().map_or(Vec::new(), |list| { | ||
538 | list.extern_items() | ||
539 | .filter_map(|item| { | ||
540 | self.collect_inner_items(item.syntax()); | ||
541 | let attrs = Attrs::new(&item, &self.hygiene); | ||
542 | let id = match item { | ||
543 | ast::ExternItem::FnDef(ast) => { | ||
544 | let func = self.lower_function(&ast)?; | ||
545 | func.into() | ||
546 | } | ||
547 | ast::ExternItem::StaticDef(ast) => { | ||
548 | let statik = self.lower_static(&ast)?; | ||
549 | statik.into() | ||
550 | } | ||
551 | }; | ||
552 | self.add_attrs(id, attrs); | ||
553 | Some(id) | ||
554 | }) | ||
555 | .collect() | ||
556 | }) | ||
557 | } | ||
558 | |||
559 | /// Lowers generics defined on `node` and collects inner items defined within. | ||
560 | fn lower_generic_params_and_inner_items( | ||
561 | &mut self, | ||
562 | owner: GenericsOwner<'_>, | ||
563 | node: &impl ast::TypeParamsOwner, | ||
564 | ) -> GenericParamsId { | ||
565 | // Generics are part of item headers and may contain inner items we need to collect. | ||
566 | if let Some(params) = node.type_param_list() { | ||
567 | self.collect_inner_items(params.syntax()); | ||
568 | } | ||
569 | if let Some(clause) = node.where_clause() { | ||
570 | self.collect_inner_items(clause.syntax()); | ||
571 | } | ||
572 | |||
573 | self.lower_generic_params(owner, node) | ||
574 | } | ||
575 | |||
576 | fn lower_generic_params( | ||
577 | &mut self, | ||
578 | owner: GenericsOwner<'_>, | ||
579 | node: &impl ast::TypeParamsOwner, | ||
580 | ) -> GenericParamsId { | ||
581 | let mut sm = &mut ArenaMap::default(); | ||
582 | let mut generics = GenericParams::default(); | ||
583 | match owner { | ||
584 | GenericsOwner::Function(func) => { | ||
585 | generics.fill(&self.body_ctx, sm, node); | ||
586 | // lower `impl Trait` in arguments | ||
587 | for param in &*func.params { | ||
588 | generics.fill_implicit_impl_trait_args(param); | ||
589 | } | ||
590 | } | ||
591 | GenericsOwner::Struct | ||
592 | | GenericsOwner::Enum | ||
593 | | GenericsOwner::Union | ||
594 | | GenericsOwner::TypeAlias => { | ||
595 | generics.fill(&self.body_ctx, sm, node); | ||
596 | } | ||
597 | GenericsOwner::Trait(trait_def) => { | ||
598 | // traits get the Self type as an implicit first type parameter | ||
599 | let self_param_id = generics.types.alloc(TypeParamData { | ||
600 | name: Some(name![Self]), | ||
601 | default: None, | ||
602 | provenance: TypeParamProvenance::TraitSelf, | ||
603 | }); | ||
604 | sm.insert(self_param_id, Either::Left(trait_def.clone())); | ||
605 | // add super traits as bounds on Self | ||
606 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | ||
607 | let self_param = TypeRef::Path(name![Self].into()); | ||
608 | generics.fill_bounds(&self.body_ctx, trait_def, self_param); | ||
609 | |||
610 | generics.fill(&self.body_ctx, &mut sm, node); | ||
611 | } | ||
612 | GenericsOwner::Impl => { | ||
613 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | ||
614 | // type-parameter, but rather is a type-alias for impl's target | ||
615 | // type, so this is handled by the resolver. | ||
616 | generics.fill(&self.body_ctx, &mut sm, node); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | self.data().generics.alloc(generics) | ||
621 | } | ||
622 | |||
623 | fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { | ||
624 | match node.type_bound_list() { | ||
625 | Some(bound_list) => { | ||
626 | bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() | ||
627 | } | ||
628 | None => Vec::new(), | ||
629 | } | ||
630 | } | ||
631 | |||
632 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { | ||
633 | let vis = match self.forced_visibility { | ||
634 | Some(vis) => return vis, | ||
635 | None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), | ||
636 | }; | ||
637 | |||
638 | self.data().vis.alloc(vis) | ||
639 | } | ||
640 | |||
641 | fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef { | ||
642 | TypeRef::from_ast(&self.body_ctx, type_ref.clone()) | ||
643 | } | ||
644 | fn lower_type_ref_opt(&self, type_ref: Option<ast::TypeRef>) -> TypeRef { | ||
645 | type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) | ||
646 | } | ||
647 | |||
648 | /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. | ||
649 | fn with_inherited_visibility<R>( | ||
650 | &mut self, | ||
651 | vis: RawVisibilityId, | ||
652 | f: impl FnOnce(&mut Self) -> R, | ||
653 | ) -> R { | ||
654 | let old = mem::replace(&mut self.forced_visibility, Some(vis)); | ||
655 | let res = f(self); | ||
656 | self.forced_visibility = old; | ||
657 | res | ||
658 | } | ||
659 | |||
660 | fn next_field_idx(&self) -> Idx<Field> { | ||
661 | Idx::from_raw(RawId::from( | ||
662 | self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32), | ||
663 | )) | ||
664 | } | ||
665 | fn next_variant_idx(&self) -> Idx<Variant> { | ||
666 | Idx::from_raw(RawId::from( | ||
667 | self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), | ||
668 | )) | ||
669 | } | ||
670 | } | ||
671 | |||
672 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
673 | let path = path![core::future::Future]; | ||
674 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
675 | let mut last = GenericArgs::empty(); | ||
676 | let binding = | ||
677 | AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; | ||
678 | last.bindings.push(binding); | ||
679 | generic_args.push(Some(Arc::new(last))); | ||
680 | |||
681 | Path::from_known_path(path, generic_args) | ||
682 | } | ||
683 | |||
684 | enum GenericsOwner<'a> { | ||
685 | /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument | ||
686 | /// position. | ||
687 | Function(&'a Function), | ||
688 | Struct, | ||
689 | Enum, | ||
690 | Union, | ||
691 | /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. | ||
692 | Trait(&'a ast::TraitDef), | ||
693 | TypeAlias, | ||
694 | Impl, | ||
695 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs new file mode 100644 index 000000000..dc035d809 --- /dev/null +++ b/crates/ra_hir_def/src/item_tree/tests.rs | |||
@@ -0,0 +1,435 @@ | |||
1 | use super::{ItemTree, ModItem, ModKind}; | ||
2 | use crate::{db::DefDatabase, test_db::TestDB}; | ||
3 | use hir_expand::{db::AstDatabase, HirFileId, InFile}; | ||
4 | use insta::assert_snapshot; | ||
5 | use ra_db::fixture::WithFixture; | ||
6 | use ra_syntax::{ast, AstNode}; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use std::sync::Arc; | ||
9 | use stdx::format_to; | ||
10 | |||
11 | fn test_inner_items(ra_fixture: &str) { | ||
12 | let (db, file_id) = TestDB::with_single_file(ra_fixture |