diff options
Diffstat (limited to 'crates/ra_ide_api/src/completion')
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_path.rs | 150 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_record_literal.rs | 28 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_item.rs | 17 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 68 |
4 files changed, 251 insertions, 12 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index a58fdc036..09ca40179 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -18,15 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
18 | match def { | 18 | match def { |
19 | hir::ModuleDef::Module(module) => { | 19 | hir::ModuleDef::Module(module) => { |
20 | let module_scope = module.scope(ctx.db); | 20 | let module_scope = module.scope(ctx.db); |
21 | for (name, res) in module_scope.entries() { | 21 | for (name, def, import) in module_scope { |
22 | if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() { | 22 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { |
23 | if ctx.use_item_syntax.is_some() { | 23 | if ctx.use_item_syntax.is_some() { |
24 | tested_by!(dont_complete_primitive_in_use); | 24 | tested_by!(dont_complete_primitive_in_use); |
25 | continue; | 25 | continue; |
26 | } | 26 | } |
27 | } | 27 | } |
28 | if Some(module) == ctx.module { | 28 | if Some(module) == ctx.module { |
29 | if let Some(import) = res.import { | 29 | if let Some(import) = import { |
30 | if let Either::A(use_tree) = module.import_source(ctx.db, import) { | 30 | if let Either::A(use_tree) = module.import_source(ctx.db, import) { |
31 | if use_tree.syntax().text_range().contains_inclusive(ctx.offset) { | 31 | if use_tree.syntax().text_range().contains_inclusive(ctx.offset) { |
32 | // for `use self::foo<|>`, don't suggest `foo` as a completion | 32 | // for `use self::foo<|>`, don't suggest `foo` as a completion |
@@ -36,7 +36,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
36 | } | 36 | } |
37 | } | 37 | } |
38 | } | 38 | } |
39 | acc.add_resolution(ctx, name.to_string(), &res.def.into()); | 39 | acc.add_resolution(ctx, name.to_string(), &def); |
40 | } | 40 | } |
41 | } | 41 | } |
42 | hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { | 42 | hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { |
@@ -50,23 +50,46 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
50 | hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), | 50 | hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), |
51 | _ => unreachable!(), | 51 | _ => unreachable!(), |
52 | }; | 52 | }; |
53 | ctx.analyzer.iterate_path_candidates(ctx.db, ty.clone(), None, |_ty, item| { | ||
54 | match item { | ||
55 | hir::AssocItem::Function(func) => { | ||
56 | let data = func.data(ctx.db); | ||
57 | if !data.has_self_param() { | ||
58 | acc.add_function(ctx, func); | ||
59 | } | ||
60 | } | ||
61 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
62 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
63 | } | ||
64 | None::<()> | ||
65 | }); | ||
66 | // Iterate assoc types separately | ||
67 | // FIXME: complete T::AssocType | ||
53 | let krate = ctx.module.map(|m| m.krate()); | 68 | let krate = ctx.module.map(|m| m.krate()); |
54 | if let Some(krate) = krate { | 69 | if let Some(krate) = krate { |
55 | ty.iterate_impl_items(ctx.db, krate, |item| { | 70 | ty.iterate_impl_items(ctx.db, krate, |item| { |
56 | match item { | 71 | match item { |
57 | hir::AssocItem::Function(func) => { | 72 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} |
58 | let data = func.data(ctx.db); | ||
59 | if !data.has_self_param() { | ||
60 | acc.add_function(ctx, func); | ||
61 | } | ||
62 | } | ||
63 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
64 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | 73 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), |
65 | } | 74 | } |
66 | None::<()> | 75 | None::<()> |
67 | }); | 76 | }); |
68 | } | 77 | } |
69 | } | 78 | } |
79 | hir::ModuleDef::Trait(t) => { | ||
80 | for item in t.items(ctx.db) { | ||
81 | match item { | ||
82 | hir::AssocItem::Function(func) => { | ||
83 | let data = func.data(ctx.db); | ||
84 | if !data.has_self_param() { | ||
85 | acc.add_function(ctx, func); | ||
86 | } | ||
87 | } | ||
88 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
89 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
90 | } | ||
91 | } | ||
92 | } | ||
70 | _ => {} | 93 | _ => {} |
71 | }; | 94 | }; |
72 | } | 95 | } |
@@ -559,6 +582,111 @@ mod tests { | |||
559 | } | 582 | } |
560 | 583 | ||
561 | #[test] | 584 | #[test] |
585 | fn completes_trait_associated_method_1() { | ||
586 | assert_debug_snapshot!( | ||
587 | do_reference_completion( | ||
588 | " | ||
589 | //- /lib.rs | ||
590 | trait Trait { | ||
591 | /// A trait method | ||
592 | fn m(); | ||
593 | } | ||
594 | |||
595 | fn foo() { let _ = Trait::<|> } | ||
596 | " | ||
597 | ), | ||
598 | @r###" | ||
599 | [ | ||
600 | CompletionItem { | ||
601 | label: "m()", | ||
602 | source_range: [73; 73), | ||
603 | delete: [73; 73), | ||
604 | insert: "m()$0", | ||
605 | kind: Function, | ||
606 | lookup: "m", | ||
607 | detail: "fn m()", | ||
608 | documentation: Documentation( | ||
609 | "A trait method", | ||
610 | ), | ||
611 | }, | ||
612 | ] | ||
613 | "### | ||
614 | ); | ||
615 | } | ||
616 | |||
617 | #[test] | ||
618 | fn completes_trait_associated_method_2() { | ||
619 | assert_debug_snapshot!( | ||
620 | do_reference_completion( | ||
621 | " | ||
622 | //- /lib.rs | ||
623 | trait Trait { | ||
624 | /// A trait method | ||
625 | fn m(); | ||
626 | } | ||
627 | |||
628 | struct S; | ||
629 | impl Trait for S {} | ||
630 | |||
631 | fn foo() { let _ = S::<|> } | ||
632 | " | ||
633 | ), | ||
634 | @r###" | ||
635 | [ | ||
636 | CompletionItem { | ||
637 | label: "m()", | ||
638 | source_range: [99; 99), | ||
639 | delete: [99; 99), | ||
640 | insert: "m()$0", | ||
641 | kind: Function, | ||
642 | lookup: "m", | ||
643 | detail: "fn m()", | ||
644 | documentation: Documentation( | ||
645 | "A trait method", | ||
646 | ), | ||
647 | }, | ||
648 | ] | ||
649 | "### | ||
650 | ); | ||
651 | } | ||
652 | |||
653 | #[test] | ||
654 | fn completes_trait_associated_method_3() { | ||
655 | assert_debug_snapshot!( | ||
656 | do_reference_completion( | ||
657 | " | ||
658 | //- /lib.rs | ||
659 | trait Trait { | ||
660 | /// A trait method | ||
661 | fn m(); | ||
662 | } | ||
663 | |||
664 | struct S; | ||
665 | impl Trait for S {} | ||
666 | |||
667 | fn foo() { let _ = <S as Trait>::<|> } | ||
668 | " | ||
669 | ), | ||
670 | @r###" | ||
671 | [ | ||
672 | CompletionItem { | ||
673 | label: "m()", | ||
674 | source_range: [110; 110), | ||
675 | delete: [110; 110), | ||
676 | insert: "m()$0", | ||
677 | kind: Function, | ||
678 | lookup: "m", | ||
679 | detail: "fn m()", | ||
680 | documentation: Documentation( | ||
681 | "A trait method", | ||
682 | ), | ||
683 | }, | ||
684 | ] | ||
685 | "### | ||
686 | ); | ||
687 | } | ||
688 | |||
689 | #[test] | ||
562 | fn completes_type_alias() { | 690 | fn completes_type_alias() { |
563 | assert_debug_snapshot!( | 691 | assert_debug_snapshot!( |
564 | do_reference_completion( | 692 | do_reference_completion( |
diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs index 4406695d5..0295b8101 100644 --- a/crates/ra_ide_api/src/completion/complete_record_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs | |||
@@ -32,6 +32,34 @@ mod tests { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | #[test] | 34 | #[test] |
35 | fn test_record_literal_deprecated_field() { | ||
36 | let completions = complete( | ||
37 | r" | ||
38 | struct A { | ||
39 | #[deprecated] | ||
40 | the_field: u32, | ||
41 | } | ||
42 | fn foo() { | ||
43 | A { the<|> } | ||
44 | } | ||
45 | ", | ||
46 | ); | ||
47 | assert_debug_snapshot!(completions, @r###" | ||
48 | â‹®[ | ||
49 | â‹® CompletionItem { | ||
50 | â‹® label: "the_field", | ||
51 | â‹® source_range: [142; 145), | ||
52 | â‹® delete: [142; 145), | ||
53 | â‹® insert: "the_field", | ||
54 | â‹® kind: Field, | ||
55 | â‹® detail: "u32", | ||
56 | â‹® deprecated: true, | ||
57 | â‹® }, | ||
58 | â‹®] | ||
59 | "###); | ||
60 | } | ||
61 | |||
62 | #[test] | ||
35 | fn test_record_literal_field() { | 63 | fn test_record_literal_field() { |
36 | let completions = complete( | 64 | let completions = complete( |
37 | r" | 65 | r" |
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 5c9c44704..93f336370 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs | |||
@@ -44,6 +44,9 @@ pub struct CompletionItem { | |||
44 | /// Additional info to show in the UI pop up. | 44 | /// Additional info to show in the UI pop up. |
45 | detail: Option<String>, | 45 | detail: Option<String>, |
46 | documentation: Option<Documentation>, | 46 | documentation: Option<Documentation>, |
47 | |||
48 | /// Whether this item is marked as deprecated | ||
49 | deprecated: bool, | ||
47 | } | 50 | } |
48 | 51 | ||
49 | // We use custom debug for CompletionItem to make `insta`'s diffs more readable. | 52 | // We use custom debug for CompletionItem to make `insta`'s diffs more readable. |
@@ -70,6 +73,9 @@ impl fmt::Debug for CompletionItem { | |||
70 | if let Some(documentation) = self.documentation() { | 73 | if let Some(documentation) = self.documentation() { |
71 | s.field("documentation", &documentation); | 74 | s.field("documentation", &documentation); |
72 | } | 75 | } |
76 | if self.deprecated { | ||
77 | s.field("deprecated", &true); | ||
78 | } | ||
73 | s.finish() | 79 | s.finish() |
74 | } | 80 | } |
75 | } | 81 | } |
@@ -132,6 +138,7 @@ impl CompletionItem { | |||
132 | lookup: None, | 138 | lookup: None, |
133 | kind: None, | 139 | kind: None, |
134 | text_edit: None, | 140 | text_edit: None, |
141 | deprecated: None, | ||
135 | } | 142 | } |
136 | } | 143 | } |
137 | /// What user sees in pop-up in the UI. | 144 | /// What user sees in pop-up in the UI. |
@@ -166,6 +173,10 @@ impl CompletionItem { | |||
166 | pub fn kind(&self) -> Option<CompletionItemKind> { | 173 | pub fn kind(&self) -> Option<CompletionItemKind> { |
167 | self.kind | 174 | self.kind |
168 | } | 175 | } |
176 | |||
177 | pub fn deprecated(&self) -> bool { | ||
178 | self.deprecated | ||
179 | } | ||
169 | } | 180 | } |
170 | 181 | ||
171 | /// A helper to make `CompletionItem`s. | 182 | /// A helper to make `CompletionItem`s. |
@@ -181,6 +192,7 @@ pub(crate) struct Builder { | |||
181 | lookup: Option<String>, | 192 | lookup: Option<String>, |
182 | kind: Option<CompletionItemKind>, | 193 | kind: Option<CompletionItemKind>, |
183 | text_edit: Option<TextEdit>, | 194 | text_edit: Option<TextEdit>, |
195 | deprecated: Option<bool>, | ||
184 | } | 196 | } |
185 | 197 | ||
186 | impl Builder { | 198 | impl Builder { |
@@ -208,6 +220,7 @@ impl Builder { | |||
208 | lookup: self.lookup, | 220 | lookup: self.lookup, |
209 | kind: self.kind, | 221 | kind: self.kind, |
210 | completion_kind: self.completion_kind, | 222 | completion_kind: self.completion_kind, |
223 | deprecated: self.deprecated.unwrap_or(false), | ||
211 | } | 224 | } |
212 | } | 225 | } |
213 | pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { | 226 | pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder { |
@@ -254,6 +267,10 @@ impl Builder { | |||
254 | self.documentation = docs.map(Into::into); | 267 | self.documentation = docs.map(Into::into); |
255 | self | 268 | self |
256 | } | 269 | } |
270 | pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder { | ||
271 | self.deprecated = Some(deprecated); | ||
272 | self | ||
273 | } | ||
257 | } | 274 | } |
258 | 275 | ||
259 | impl<'a> Into<CompletionItem> for Builder { | 276 | impl<'a> Into<CompletionItem> for Builder { |
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 65bb639ed..cb55d1875 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::{AttrsOwner, NameOwner}; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use crate::completion::{ | 8 | use crate::completion::{ |
@@ -18,6 +18,11 @@ impl Completions { | |||
18 | field: hir::StructField, | 18 | field: hir::StructField, |
19 | substs: &hir::Substs, | 19 | substs: &hir::Substs, |
20 | ) { | 20 | ) { |
21 | let ast_node = field.source(ctx.db).ast; | ||
22 | let is_deprecated = match ast_node { | ||
23 | hir::FieldSource::Named(m) => is_deprecated(m), | ||
24 | hir::FieldSource::Pos(m) => is_deprecated(m), | ||
25 | }; | ||
21 | CompletionItem::new( | 26 | CompletionItem::new( |
22 | CompletionKind::Reference, | 27 | CompletionKind::Reference, |
23 | ctx.source_range(), | 28 | ctx.source_range(), |
@@ -26,6 +31,7 @@ impl Completions { | |||
26 | .kind(CompletionItemKind::Field) | 31 | .kind(CompletionItemKind::Field) |
27 | .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) | 32 | .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) |
28 | .set_documentation(field.docs(ctx.db)) | 33 | .set_documentation(field.docs(ctx.db)) |
34 | .set_deprecated(is_deprecated) | ||
29 | .add_to(self); | 35 | .add_to(self); |
30 | } | 36 | } |
31 | 37 | ||
@@ -179,6 +185,7 @@ impl Completions { | |||
179 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) | 185 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) |
180 | .kind(CompletionItemKind::Macro) | 186 | .kind(CompletionItemKind::Macro) |
181 | .set_documentation(docs.clone()) | 187 | .set_documentation(docs.clone()) |
188 | .set_deprecated(is_deprecated(ast_node)) | ||
182 | .detail(detail); | 189 | .detail(detail); |
183 | 190 | ||
184 | builder = if ctx.use_item_syntax.is_some() { | 191 | builder = if ctx.use_item_syntax.is_some() { |
@@ -211,6 +218,7 @@ impl Completions { | |||
211 | CompletionItemKind::Function | 218 | CompletionItemKind::Function |
212 | }) | 219 | }) |
213 | .set_documentation(func.docs(ctx.db)) | 220 | .set_documentation(func.docs(ctx.db)) |
221 | .set_deprecated(is_deprecated(ast_node)) | ||
214 | .detail(detail); | 222 | .detail(detail); |
215 | 223 | ||
216 | // Add `<>` for generic types | 224 | // Add `<>` for generic types |
@@ -242,6 +250,7 @@ impl Completions { | |||
242 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 250 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
243 | .kind(CompletionItemKind::Const) | 251 | .kind(CompletionItemKind::Const) |
244 | .set_documentation(constant.docs(ctx.db)) | 252 | .set_documentation(constant.docs(ctx.db)) |
253 | .set_deprecated(is_deprecated(ast_node)) | ||
245 | .detail(detail) | 254 | .detail(detail) |
246 | .add_to(self); | 255 | .add_to(self); |
247 | } | 256 | } |
@@ -257,11 +266,13 @@ impl Completions { | |||
257 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | 266 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) |
258 | .kind(CompletionItemKind::TypeAlias) | 267 | .kind(CompletionItemKind::TypeAlias) |
259 | .set_documentation(type_alias.docs(ctx.db)) | 268 | .set_documentation(type_alias.docs(ctx.db)) |
269 | .set_deprecated(is_deprecated(type_def)) | ||
260 | .detail(detail) | 270 | .detail(detail) |
261 | .add_to(self); | 271 | .add_to(self); |
262 | } | 272 | } |
263 | 273 | ||
264 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | 274 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { |
275 | let is_deprecated = is_deprecated(variant.source(ctx.db).ast); | ||
265 | let name = match variant.name(ctx.db) { | 276 | let name = match variant.name(ctx.db) { |
266 | Some(it) => it, | 277 | Some(it) => it, |
267 | None => return, | 278 | None => return, |
@@ -274,11 +285,16 @@ impl Completions { | |||
274 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) | 285 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) |
275 | .kind(CompletionItemKind::EnumVariant) | 286 | .kind(CompletionItemKind::EnumVariant) |
276 | .set_documentation(variant.docs(ctx.db)) | 287 | .set_documentation(variant.docs(ctx.db)) |
288 | .set_deprecated(is_deprecated) | ||
277 | .detail(detail) | 289 | .detail(detail) |
278 | .add_to(self); | 290 | .add_to(self); |
279 | } | 291 | } |
280 | } | 292 | } |
281 | 293 | ||
294 | fn is_deprecated(node: impl AttrsOwner) -> bool { | ||
295 | node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") | ||
296 | } | ||
297 | |||
282 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { | 298 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { |
283 | let subst = db.generic_defaults(def); | 299 | let subst = db.generic_defaults(def); |
284 | subst.iter().any(|ty| ty == &Ty::Unknown) | 300 | subst.iter().any(|ty| ty == &Ty::Unknown) |
@@ -296,6 +312,56 @@ mod tests { | |||
296 | } | 312 | } |
297 | 313 | ||
298 | #[test] | 314 | #[test] |
315 | fn sets_deprecated_flag_in_completion_items() { | ||
316 | assert_debug_snapshot!( | ||
317 | do_reference_completion( | ||
318 | r#" | ||
319 | #[deprecated] | ||
320 | fn something_deprecated() {} | ||
321 | |||
322 | #[deprecated(since = "1.0.0")] | ||
323 | fn something_else_deprecated() {} | ||
324 | |||
325 | fn main() { som<|> } | ||
326 | "#, | ||
327 | ), | ||
328 | @r###" | ||
329 | [ | ||
330 | CompletionItem { | ||
331 | label: "main()", | ||
332 | source_range: [203; 206), | ||
333 | delete: [203; 206), | ||
334 | insert: "main()$0", | ||
335 | kind: Function, | ||
336 | lookup: "main", | ||
337 | detail: "fn main()", | ||
338 | }, | ||
339 | CompletionItem { | ||
340 | label: "something_deprecated()", | ||
341 | source_range: [203; 206), | ||
342 | delete: [203; 206), | ||
343 | insert: "something_deprecated()$0", | ||
344 | kind: Function, | ||
345 | lookup: "something_deprecated", | ||
346 | detail: "fn something_deprecated()", | ||
347 | deprecated: true, | ||
348 | }, | ||
349 | CompletionItem { | ||
350 | label: "something_else_deprecated()", | ||
351 | source_range: [203; 206), | ||
352 | delete: [203; 206), | ||
353 | insert: "something_else_deprecated()$0", | ||
354 | kind: Function, | ||
355 | lookup: "something_else_deprecated", | ||
356 | detail: "fn something_else_deprecated()", | ||
357 | deprecated: true, | ||
358 | }, | ||
359 | ] | ||
360 | "### | ||
361 | ); | ||
362 | } | ||
363 | |||
364 | #[test] | ||
299 | fn inserts_parens_for_function_calls() { | 365 | fn inserts_parens_for_function_calls() { |
300 | covers!(inserts_parens_for_function_calls); | 366 | covers!(inserts_parens_for_function_calls); |
301 | assert_debug_snapshot!( | 367 | assert_debug_snapshot!( |