diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-06-24 16:07:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-24 16:07:37 +0100 |
commit | e9bdb05e9676e85bdd8fa5008e3ada3812b36fd9 (patch) | |
tree | a21d348fbfa2d06f1fba77622c5417383938e6fe /crates/ra_hir_def/src/item_tree/tests.rs | |
parent | 1a3b507a007d0373a83bde203d780b860ea55ce1 (diff) | |
parent | 2928600374a8356c2c2bffee080c47cb0f463fb9 (diff) |
Merge #4990
4990: Introduce an ItemTree layer to avoid reparsing files r=matklad a=jonas-schievink
This reduces the latency of "go to definition" in a simple benchmark on rust-analyzer by around 30%.
cc https://github.com/rust-analyzer/rust-analyzer/issues/1650
Closes https://github.com/rust-analyzer/rust-analyzer/issues/3485
Co-authored-by: Aleksey Kladov <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/ra_hir_def/src/item_tree/tests.rs')
-rw-r--r-- | crates/ra_hir_def/src/item_tree/tests.rs | 435 |
1 files changed, 435 insertions, 0 deletions
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); | ||
13 | let file_id = HirFileId::from(file_id); | ||
14 | let tree = db.item_tree(file_id); | ||
15 | let root = db.parse_or_expand(file_id).unwrap(); | ||
16 | let ast_id_map = db.ast_id_map(file_id); | ||
17 | |||
18 | // Traverse the item tree and collect all module/impl/trait-level items as AST nodes. | ||
19 | let mut outer_items = FxHashSet::default(); | ||
20 | let mut worklist = tree.top_level_items().to_vec(); | ||
21 | while let Some(item) = worklist.pop() { | ||
22 | let node: ast::ModuleItem = match item { | ||
23 | ModItem::Import(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
24 | ModItem::ExternCrate(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
25 | ModItem::Function(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
26 | ModItem::Struct(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
27 | ModItem::Union(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
28 | ModItem::Enum(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
29 | ModItem::Const(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
30 | ModItem::Static(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
31 | ModItem::TypeAlias(it) => tree.source(&db, InFile::new(file_id, it)).into(), | ||
32 | ModItem::Mod(it) => { | ||
33 | if let ModKind::Inline { items } = &tree[it].kind { | ||
34 | worklist.extend(&**items); | ||
35 | } | ||
36 | tree.source(&db, InFile::new(file_id, it)).into() | ||
37 | } | ||
38 | ModItem::Trait(it) => { | ||
39 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
40 | tree.source(&db, InFile::new(file_id, it)).into() | ||
41 | } | ||
42 | ModItem::Impl(it) => { | ||
43 | worklist.extend(tree[it].items.iter().map(|item| ModItem::from(*item))); | ||
44 | tree.source(&db, InFile::new(file_id, it)).into() | ||
45 | } | ||
46 | ModItem::MacroCall(_) => continue, | ||
47 | }; | ||
48 | |||
49 | outer_items.insert(node); | ||
50 | } | ||
51 | |||
52 | // Now descend the root node and check that all `ast::ModuleItem`s are either recorded above, or | ||
53 | // registered as inner items. | ||
54 | for item in root.descendants().skip(1).filter_map(ast::ModuleItem::cast) { | ||
55 | if outer_items.contains(&item) { | ||
56 | continue; | ||
57 | } | ||
58 | |||
59 | let ast_id = ast_id_map.ast_id(&item); | ||
60 | assert!(!tree.inner_items(ast_id).is_empty()); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | fn item_tree(ra_fixture: &str) -> Arc<ItemTree> { | ||
65 | let (db, file_id) = TestDB::with_single_file(ra_fixture); | ||
66 | db.item_tree(file_id.into()) | ||
67 | } | ||
68 | |||
69 | fn print_item_tree(ra_fixture: &str) -> String { | ||
70 | let tree = item_tree(ra_fixture); | ||
71 | let mut out = String::new(); | ||
72 | |||
73 | format_to!(out, "inner attrs: {:?}\n\n", tree.top_level_attrs()); | ||
74 | format_to!(out, "top-level items:\n"); | ||
75 | for item in tree.top_level_items() { | ||
76 | fmt_mod_item(&mut out, &tree, *item); | ||
77 | format_to!(out, "\n"); | ||
78 | } | ||
79 | |||
80 | if !tree.inner_items.is_empty() { | ||
81 | format_to!(out, "\ninner items:\n\n"); | ||
82 | for (ast_id, items) in &tree.inner_items { | ||
83 | format_to!(out, "for AST {:?}:\n", ast_id); | ||
84 | for inner in items { | ||
85 | fmt_mod_item(&mut out, &tree, *inner); | ||
86 | format_to!(out, "\n\n"); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | out | ||
92 | } | ||
93 | |||
94 | fn fmt_mod_item(out: &mut String, tree: &ItemTree, item: ModItem) { | ||
95 | let attrs = tree.attrs(item); | ||
96 | if !attrs.is_empty() { | ||
97 | format_to!(out, "#[{:?}]\n", attrs); | ||
98 | } | ||
99 | |||
100 | let mut children = String::new(); | ||
101 | match item { | ||
102 | ModItem::ExternCrate(it) => { | ||
103 | format_to!(out, "{:?}", tree[it]); | ||
104 | } | ||
105 | ModItem::Import(it) => { | ||
106 | format_to!(out, "{:?}", tree[it]); | ||
107 | } | ||
108 | ModItem::Function(it) => { | ||
109 | format_to!(out, "{:?}", tree[it]); | ||
110 | } | ||
111 | ModItem::Struct(it) => { | ||
112 | format_to!(out, "{:?}", tree[it]); | ||
113 | } | ||
114 | ModItem::Union(it) => { | ||
115 | format_to!(out, "{:?}", tree[it]); | ||
116 | } | ||
117 | ModItem::Enum(it) => { | ||
118 | format_to!(out, "{:?}", tree[it]); | ||
119 | } | ||
120 | ModItem::Const(it) => { | ||
121 | format_to!(out, "{:?}", tree[it]); | ||
122 | } | ||
123 | ModItem::Static(it) => { | ||
124 | format_to!(out, "{:?}", tree[it]); | ||
125 | } | ||
126 | ModItem::Trait(it) => { | ||
127 | format_to!(out, "{:?}", tree[it]); | ||
128 | for item in &*tree[it].items { | ||
129 | fmt_mod_item(&mut children, tree, ModItem::from(*item)); | ||
130 | format_to!(children, "\n"); | ||
131 | } | ||
132 | } | ||
133 | ModItem::Impl(it) => { | ||
134 | format_to!(out, "{:?}", tree[it]); | ||
135 | for item in &*tree[it].items { | ||
136 | fmt_mod_item(&mut children, tree, ModItem::from(*item)); | ||
137 | format_to!(children, "\n"); | ||
138 | } | ||
139 | } | ||
140 | ModItem::TypeAlias(it) => { | ||
141 | format_to!(out, "{:?}", tree[it]); | ||
142 | } | ||
143 | ModItem::Mod(it) => { | ||
144 | format_to!(out, "{:?}", tree[it]); | ||
145 | match &tree[it].kind { | ||
146 | ModKind::Inline { items } => { | ||
147 | for item in &**items { | ||
148 | fmt_mod_item(&mut children, tree, *item); | ||
149 | format_to!(children, "\n"); | ||
150 | } | ||
151 | } | ||
152 | ModKind::Outline {} => {} | ||
153 | } | ||
154 | } | ||
155 | ModItem::MacroCall(it) => { | ||
156 | format_to!(out, "{:?}", tree[it]); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | for line in children.lines() { | ||
161 | format_to!(out, "\n> {}", line); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn smoke() { | ||
167 | assert_snapshot!(print_item_tree(r" | ||
168 | #![attr] | ||
169 | |||
170 | #[attr_on_use] | ||
171 | use {a, b::*}; | ||
172 | |||
173 | #[ext_crate] | ||
174 | extern crate krate; | ||
175 | |||
176 | #[on_trait] | ||
177 | trait Tr<U> { | ||
178 | #[assoc_ty] | ||
179 | type AssocTy: Tr<()>; | ||
180 | |||
181 | #[assoc_const] | ||
182 | const CONST: u8; | ||
183 | |||
184 | #[assoc_method] | ||
185 | fn method(&self); | ||
186 | |||
187 | #[assoc_dfl_method] | ||
188 | fn dfl_method(&mut self) {} | ||
189 | } | ||
190 | |||
191 | #[struct0] | ||
192 | struct Struct0<T = ()>; | ||
193 | |||
194 | #[struct1] | ||
195 | struct Struct1<T>(#[struct1fld] u8); | ||
196 | |||
197 | #[struct2] | ||
198 | struct Struct2<T> { | ||
199 | #[struct2fld] | ||
200 | fld: (T, ), | ||
201 | } | ||
202 | |||
203 | #[en] | ||
204 | enum En { | ||
205 | #[enum_variant] | ||
206 | Variant { | ||
207 | #[enum_field] | ||
208 | field: u8, | ||
209 | }, | ||
210 | } | ||
211 | |||
212 | #[un] | ||
213 | union Un { | ||
214 | #[union_fld] | ||
215 | fld: u16, | ||
216 | } | ||
217 | "), @r###" | ||
218 | inner attrs: Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr"))] }, input: None }]) } | ||
219 | |||
220 | top-level items: | ||
221 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] | ||
222 | Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
223 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }] | ||
224 | Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UseItem>(0) } | ||
225 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }] | ||
226 | ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ExternCrateItem>(1) } | ||
227 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }] | ||
228 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(2) } | ||
229 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }] | ||
230 | > TypeAlias { name: Name(Text("AssocTy")), visibility: RawVisibilityId("pub(self)"), bounds: [Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Tr"))] }, generic_args: [Some(GenericArgs { args: [Type(Tuple([]))], has_self_type: false, bindings: [] })] })], generic_params: GenericParamsId(4294967295), type_ref: None, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TypeAliasDef>(8) } | ||
231 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_const"))] }, input: None }]) }] | ||
232 | > Const { name: Some(Name(Text("CONST"))), visibility: RawVisibilityId("pub(self)"), type_ref: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("u8"))] }, generic_args: [None] }), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ConstDef>(9) } | ||
233 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_method"))] }, input: None }]) }] | ||
234 | > Function { name: Name(Text("method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Shared)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(10) } | ||
235 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_dfl_method"))] }, input: None }]) }] | ||
236 | > Function { name: Name(Text("dfl_method")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: true, is_unsafe: false, params: [Reference(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Self"))] }, generic_args: [None] }), Mut)], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(11) } | ||
237 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct0"))] }, input: None }]) }] | ||
238 | Struct { name: Name(Text("Struct0")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), fields: Unit, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(3), kind: Unit } | ||
239 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct1"))] }, input: None }]) }] | ||
240 | Struct { name: Name(Text("Struct1")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(2), fields: Tuple(Idx::<Field>(0)..Idx::<Field>(1)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(4), kind: Tuple } | ||
241 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("struct2"))] }, input: None }]) }] | ||
242 | Struct { name: Name(Text("Struct2")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(3), fields: Record(Idx::<Field>(1)..Idx::<Field>(2)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::StructDef>(5), kind: Record } | ||
243 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("en"))] }, input: None }]) }] | ||
244 | Enum { name: Name(Text("En")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), variants: Idx::<Variant>(0)..Idx::<Variant>(1), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::EnumDef>(6) } | ||
245 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("un"))] }, input: None }]) }] | ||
246 | Union { name: Name(Text("Un")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), fields: Record(Idx::<Field>(3)..Idx::<Field>(4)), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::UnionDef>(7) } | ||
247 | "###); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn simple_inner_items() { | ||
252 | let tree = print_item_tree( | ||
253 | r" | ||
254 | impl<T:A> D for Response<T> { | ||
255 | fn foo() { | ||
256 | end(); | ||
257 | fn end<W: Write>() { | ||
258 | let _x: T = loop {}; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | ", | ||
263 | ); | ||
264 | |||
265 | assert_snapshot!(tree, @r###" | ||
266 | inner attrs: Attrs { entries: None } | ||
267 | |||
268 | top-level items: | ||
269 | Impl { generic_params: GenericParamsId(0), target_trait: Some(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("D"))] }, generic_args: [None] })), target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Response"))] }, generic_args: [Some(GenericArgs { args: [Type(Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("T"))] }, generic_args: [None] }))], has_self_type: false, bindings: [] })] }), is_negative: false, items: [Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
270 | > Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
271 | |||
272 | inner items: | ||
273 | |||
274 | for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(2): | ||
275 | Function { name: Name(Text("end")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(1), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
276 | |||
277 | "###); | ||
278 | } | ||
279 | |||
280 | #[test] | ||
281 | fn extern_attrs() { | ||
282 | let tree = print_item_tree( | ||
283 | r#" | ||
284 | #[block_attr] | ||
285 | extern "C" { | ||
286 | #[attr_a] | ||
287 | fn a() {} | ||
288 | #[attr_b] | ||
289 | fn b() {} | ||
290 | } | ||
291 | "#, | ||
292 | ); | ||
293 | |||
294 | assert_snapshot!(tree, @r###" | ||
295 | inner attrs: Attrs { entries: None } | ||
296 | |||
297 | top-level items: | ||
298 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] | ||
299 | Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
300 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }, Attr { path: ModPath { kind: Plain, segments: [Name(Text("block_attr"))] }, input: None }]) }] | ||
301 | Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
302 | "###); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn trait_attrs() { | ||
307 | let tree = print_item_tree( | ||
308 | r#" | ||
309 | #[trait_attr] | ||
310 | trait Tr { | ||
311 | #[attr_a] | ||
312 | fn a() {} | ||
313 | #[attr_b] | ||
314 | fn b() {} | ||
315 | } | ||
316 | "#, | ||
317 | ); | ||
318 | |||
319 | assert_snapshot!(tree, @r###" | ||
320 | inner attrs: Attrs { entries: None } | ||
321 | |||
322 | top-level items: | ||
323 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("trait_attr"))] }, input: None }]) }] | ||
324 | Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::TraitDef>(0) } | ||
325 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] | ||
326 | > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
327 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] | ||
328 | > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
329 | "###); | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn impl_attrs() { | ||
334 | let tree = print_item_tree( | ||
335 | r#" | ||
336 | #[impl_attr] | ||
337 | impl Ty { | ||
338 | #[attr_a] | ||
339 | fn a() {} | ||
340 | #[attr_b] | ||
341 | fn b() {} | ||
342 | } | ||
343 | "#, | ||
344 | ); | ||
345 | |||
346 | assert_snapshot!(tree, @r###" | ||
347 | inner attrs: Attrs { entries: None } | ||
348 | |||
349 | top-level items: | ||
350 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("impl_attr"))] }, input: None }]) }] | ||
351 | Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("Ty"))] }, generic_args: [None] }), is_negative: false, items: [Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
352 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_a"))] }, input: None }]) }] | ||
353 | > Function { name: Name(Text("a")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
354 | > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_b"))] }, input: None }]) }] | ||
355 | > Function { name: Name(Text("b")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(2) } | ||
356 | "###); | ||
357 | } | ||
358 | |||
359 | #[test] | ||
360 | fn cursed_inner_items() { | ||
361 | test_inner_items( | ||
362 | r" | ||
363 | struct S<T: Trait = [u8; { fn f() {} 0 }]>(T); | ||
364 | |||
365 | enum En { | ||
366 | Var1 { | ||
367 | t: [(); { trait Inner {} 0 }], | ||
368 | }, | ||
369 | |||
370 | Var2([u16; { enum Inner {} 0 }]), | ||
371 | } | ||
372 | |||
373 | type Ty = [En; { struct Inner; 0 }]; | ||
374 | |||
375 | impl En { | ||
376 | fn assoc() { | ||
377 | trait InnerTrait<T = [u8; { fn f() {} }]> {} | ||
378 | struct InnerStruct<T = [u8; { fn f() {} }]> {} | ||
379 | impl<T = [u8; { fn f() {} }]> InnerTrait for InnerStruct {} | ||
380 | } | ||
381 | } | ||
382 | |||
383 | trait Tr<T = [u8; { fn f() {} }]> { | ||
384 | type AssocTy = [u8; { fn f() {} }]; | ||
385 | |||
386 | const AssocConst: [u8; { fn f() {} }]; | ||
387 | } | ||
388 | ", | ||
389 | ); | ||
390 | } | ||
391 | |||
392 | #[test] | ||
393 | fn inner_item_attrs() { | ||
394 | let tree = print_item_tree( | ||
395 | r" | ||
396 | fn foo() { | ||
397 | #[on_inner] | ||
398 | fn inner() {} | ||
399 | } | ||
400 | ", | ||
401 | ); | ||
402 | |||
403 | assert_snapshot!(tree, @r###" | ||
404 | inner attrs: Attrs { entries: None } | ||
405 | |||
406 | top-level items: | ||
407 | Function { name: Name(Text("foo")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(0) } | ||
408 | |||
409 | inner items: | ||
410 | |||
411 | for AST FileAstId::<ra_syntax::ast::generated::nodes::ModuleItem>(1): | ||
412 | #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_inner"))] }, input: None }]) }] | ||
413 | Function { name: Name(Text("inner")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(4294967295), has_self_param: false, is_unsafe: false, params: [], ret_type: Tuple([]), ast_id: FileAstId::<ra_syntax::ast::generated::nodes::FnDef>(1) } | ||
414 | |||
415 | "###); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
419 | fn assoc_item_macros() { | ||
420 | let tree = print_item_tree( | ||
421 | r" | ||
422 | impl S { | ||
423 | items!(); | ||
424 | } | ||
425 | ", | ||
426 | ); | ||
427 | |||
428 | assert_snapshot!(tree, @r###" | ||
429 | inner attrs: Attrs { entries: None } | ||
430 | |||
431 | top-level items: | ||
432 | Impl { generic_params: GenericParamsId(4294967295), target_trait: None, target_type: Path(Path { type_anchor: None, mod_path: ModPath { kind: Plain, segments: [Name(Text("S"))] }, generic_args: [None] }), is_negative: false, items: [MacroCall(Idx::<MacroCall>(0))], ast_id: FileAstId::<ra_syntax::ast::generated::nodes::ImplDef>(0) } | ||
433 | > MacroCall { name: None, path: ModPath { kind: Plain, segments: [Name(Text("items"))] }, is_export: false, is_local_inner: false, is_builtin: false, ast_id: FileAstId::<ra_syntax::ast::generated::nodes::MacroCall>(1) } | ||
434 | "###); | ||
435 | } | ||