ide_assists/handlers/
generate_new.rs

1use ide_db::{
2    imports::import_assets::item_for_path_search, syntax_helpers::suggest_name::NameGenerator,
3    use_trivial_constructor::use_trivial_constructor,
4};
5use syntax::{
6    ast::{self, AstNode, HasName, HasVisibility, StructKind, edit_in_place::Indent, make},
7    syntax_editor::Position,
8};
9
10use crate::{
11    AssistContext, AssistId, Assists,
12    utils::{find_struct_impl, generate_impl_with_item},
13};
14
15// Assist: generate_new
16//
17// Adds a `fn new` for a type.
18//
19// ```
20// struct Ctx<T: Clone> {
21//      data: T,$0
22// }
23// ```
24// ->
25// ```
26// struct Ctx<T: Clone> {
27//      data: T,
28// }
29//
30// impl<T: Clone> Ctx<T> {
31//     fn $0new(data: T) -> Self {
32//         Self { data }
33//     }
34// }
35// ```
36pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
37    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
38
39    let field_list = match strukt.kind() {
40        StructKind::Record(named) => {
41            named.fields().filter_map(|f| Some((f.name()?, f.ty()?))).collect::<Vec<_>>()
42        }
43        StructKind::Tuple(tuple) => {
44            let mut name_generator = NameGenerator::default();
45            tuple
46                .fields()
47                .enumerate()
48                .filter_map(|(i, f)| {
49                    let ty = f.ty()?;
50                    let name = match name_generator.for_type(
51                        &ctx.sema.resolve_type(&ty)?,
52                        ctx.db(),
53                        ctx.edition(),
54                    ) {
55                        Some(name) => name,
56                        None => name_generator.suggest_name(&format!("_{i}")),
57                    };
58                    Some((make::name(name.as_str()), f.ty()?))
59                })
60                .collect::<Vec<_>>()
61        }
62        StructKind::Unit => return None,
63    };
64
65    // Return early if we've found an existing new fn
66    let impl_def =
67        find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[String::from("new")])?;
68
69    let current_module = ctx.sema.scope(strukt.syntax())?.module();
70
71    let target = strukt.syntax().text_range();
72    acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| {
73        let trivial_constructors = field_list
74            .iter()
75            .map(|(name, ty)| {
76                let ty = ctx.sema.resolve_type(ty)?;
77
78                let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
79
80                let cfg = ctx
81                    .config
82                    .find_path_config(ctx.sema.is_nightly(current_module.krate(ctx.sema.db)));
83                let type_path = current_module.find_path(
84                    ctx.sema.db,
85                    item_for_path_search(ctx.sema.db, item_in_ns)?,
86                    cfg,
87                )?;
88
89                let edition = current_module.krate(ctx.db()).edition(ctx.db());
90
91                let expr = use_trivial_constructor(
92                    ctx.sema.db,
93                    ide_db::helpers::mod_path_to_ast(&type_path, edition),
94                    &ty,
95                    edition,
96                )?;
97
98                Some((make::name_ref(&name.text()), Some(expr)))
99            })
100            .collect::<Vec<_>>();
101
102        let params = field_list.iter().enumerate().filter_map(|(i, (name, ty))| {
103            if trivial_constructors[i].is_none() {
104                Some(make::param(make::ident_pat(false, false, name.clone()).into(), ty.clone()))
105            } else {
106                None
107            }
108        });
109        let params = make::param_list(None, params);
110
111        let fields = field_list.iter().enumerate().map(|(i, (name, _))| {
112            if let Some(constructor) = trivial_constructors[i].clone() {
113                constructor
114            } else {
115                (make::name_ref(&name.text()), None)
116            }
117        });
118
119        let tail_expr: ast::Expr = match strukt.kind() {
120            StructKind::Record(_) => {
121                let fields = fields.map(|(name, expr)| make::record_expr_field(name, expr));
122                let fields = make::record_expr_field_list(fields);
123                make::record_expr(make::ext::ident_path("Self"), fields).into()
124            }
125            StructKind::Tuple(_) => {
126                let args = fields.map(|(arg, expr)| {
127                    let arg = || make::expr_path(make::path_unqualified(make::path_segment(arg)));
128                    expr.unwrap_or_else(arg)
129                });
130                let arg_list = make::arg_list(args);
131                make::expr_call(make::expr_path(make::ext::ident_path("Self")), arg_list).into()
132            }
133            StructKind::Unit => unreachable!(),
134        };
135        let body = make::block_expr(None, tail_expr.into());
136
137        let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
138
139        let fn_ = make::fn_(
140            None,
141            strukt.visibility(),
142            make::name("new"),
143            None,
144            None,
145            params,
146            body,
147            Some(ret_type),
148            false,
149            false,
150            false,
151            false,
152        )
153        .clone_for_update();
154        fn_.indent(1.into());
155
156        let mut editor = builder.make_editor(strukt.syntax());
157
158        // Get the node for set annotation
159        let contain_fn = if let Some(impl_def) = impl_def {
160            fn_.indent(impl_def.indent_level());
161
162            if let Some(l_curly) = impl_def.assoc_item_list().and_then(|list| list.l_curly_token())
163            {
164                editor.insert_all(
165                    Position::after(l_curly),
166                    vec![
167                        make::tokens::whitespace(&format!("\n{}", impl_def.indent_level() + 1))
168                            .into(),
169                        fn_.syntax().clone().into(),
170                        make::tokens::whitespace("\n").into(),
171                    ],
172                );
173                fn_.syntax().clone()
174            } else {
175                let items = vec![ast::AssocItem::Fn(fn_)];
176                let list = make::assoc_item_list(Some(items));
177                editor.insert(Position::after(impl_def.syntax()), list.syntax());
178                list.syntax().clone()
179            }
180        } else {
181            // Generate a new impl to add the method to
182            let indent_level = strukt.indent_level();
183            let body = vec![ast::AssocItem::Fn(fn_)];
184            let list = make::assoc_item_list(Some(body));
185            let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list));
186
187            impl_def.indent(strukt.indent_level());
188
189            // Insert it after the adt
190            editor.insert_all(
191                Position::after(strukt.syntax()),
192                vec![
193                    make::tokens::whitespace(&format!("\n\n{indent_level}")).into(),
194                    impl_def.syntax().clone().into(),
195                ],
196            );
197            impl_def.syntax().clone()
198        };
199
200        if let Some(fn_) = contain_fn.descendants().find_map(ast::Fn::cast)
201            && let Some(cap) = ctx.config.snippet_cap
202        {
203            match strukt.kind() {
204                StructKind::Tuple(_) => {
205                    let struct_args = fn_
206                        .body()
207                        .unwrap()
208                        .syntax()
209                        .descendants()
210                        .filter(|it| syntax::ast::ArgList::can_cast(it.kind()))
211                        .flat_map(|args| args.children())
212                        .filter(|it| syntax::ast::PathExpr::can_cast(it.kind()))
213                        .enumerate()
214                        .filter_map(|(i, node)| {
215                            if trivial_constructors[i].is_none() { Some(node) } else { None }
216                        });
217                    if let Some(fn_params) = fn_.param_list() {
218                        for (struct_arg, fn_param) in struct_args.zip(fn_params.params()) {
219                            if let Some(fn_pat) = fn_param.pat() {
220                                let fn_pat = fn_pat.syntax().clone();
221                                let placeholder = builder.make_placeholder_snippet(cap);
222                                editor.add_annotation_all(vec![struct_arg, fn_pat], placeholder)
223                            }
224                        }
225                    }
226                }
227                _ => {}
228            }
229
230            // Add a tabstop before the name
231            if let Some(name) = fn_.name() {
232                let tabstop_before = builder.make_tabstop_before(cap);
233                editor.add_annotation(name.syntax(), tabstop_before);
234            }
235        }
236
237        builder.add_file_edits(ctx.vfs_file_id(), editor);
238    })
239}
240
241#[cfg(test)]
242mod record_tests {
243    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
244
245    use super::*;
246
247    #[test]
248    fn test_generate_new_with_zst_fields() {
249        check_assist(
250            generate_new,
251            r#"
252struct Empty;
253
254struct Foo { empty: Empty $0}
255"#,
256            r#"
257struct Empty;
258
259struct Foo { empty: Empty }
260
261impl Foo {
262    fn $0new() -> Self {
263        Self { empty: Empty }
264    }
265}
266"#,
267        );
268        check_assist(
269            generate_new,
270            r#"
271struct Empty;
272
273struct Foo { baz: String, empty: Empty $0}
274"#,
275            r#"
276struct Empty;
277
278struct Foo { baz: String, empty: Empty }
279
280impl Foo {
281    fn $0new(baz: String) -> Self {
282        Self { baz, empty: Empty }
283    }
284}
285"#,
286        );
287        check_assist(
288            generate_new,
289            r#"
290enum Empty { Bar }
291
292struct Foo { empty: Empty $0}
293"#,
294            r#"
295enum Empty { Bar }
296
297struct Foo { empty: Empty }
298
299impl Foo {
300    fn $0new() -> Self {
301        Self { empty: Empty::Bar }
302    }
303}
304"#,
305        );
306
307        // make sure the assist only works on unit variants
308        check_assist(
309            generate_new,
310            r#"
311struct Empty {}
312
313struct Foo { empty: Empty $0}
314"#,
315            r#"
316struct Empty {}
317
318struct Foo { empty: Empty }
319
320impl Foo {
321    fn $0new(empty: Empty) -> Self {
322        Self { empty }
323    }
324}
325"#,
326        );
327        check_assist(
328            generate_new,
329            r#"
330enum Empty { Bar {} }
331
332struct Foo { empty: Empty $0}
333"#,
334            r#"
335enum Empty { Bar {} }
336
337struct Foo { empty: Empty }
338
339impl Foo {
340    fn $0new(empty: Empty) -> Self {
341        Self { empty }
342    }
343}
344"#,
345        );
346    }
347
348    #[test]
349    fn test_generate_new() {
350        check_assist(
351            generate_new,
352            r#"
353struct Foo {$0}
354"#,
355            r#"
356struct Foo {}
357
358impl Foo {
359    fn $0new() -> Self {
360        Self {  }
361    }
362}
363"#,
364        );
365        check_assist(
366            generate_new,
367            r#"
368struct Foo<T: Clone> {$0}
369"#,
370            r#"
371struct Foo<T: Clone> {}
372
373impl<T: Clone> Foo<T> {
374    fn $0new() -> Self {
375        Self {  }
376    }
377}
378"#,
379        );
380        check_assist(
381            generate_new,
382            r#"
383struct Foo<'a, T: Foo<'a>> {$0}
384"#,
385            r#"
386struct Foo<'a, T: Foo<'a>> {}
387
388impl<'a, T: Foo<'a>> Foo<'a, T> {
389    fn $0new() -> Self {
390        Self {  }
391    }
392}
393"#,
394        );
395        check_assist(
396            generate_new,
397            r#"
398struct Foo { baz: String $0}
399"#,
400            r#"
401struct Foo { baz: String }
402
403impl Foo {
404    fn $0new(baz: String) -> Self {
405        Self { baz }
406    }
407}
408"#,
409        );
410        check_assist(
411            generate_new,
412            r#"
413struct Foo { baz: String, qux: Vec<i32> $0}
414"#,
415            r#"
416struct Foo { baz: String, qux: Vec<i32> }
417
418impl Foo {
419    fn $0new(baz: String, qux: Vec<i32>) -> Self {
420        Self { baz, qux }
421    }
422}
423"#,
424        );
425    }
426
427    #[test]
428    fn check_that_visibility_modifiers_dont_get_brought_in() {
429        check_assist(
430            generate_new,
431            r#"
432struct Foo { pub baz: String, pub qux: Vec<i32> $0}
433"#,
434            r#"
435struct Foo { pub baz: String, pub qux: Vec<i32> }
436
437impl Foo {
438    fn $0new(baz: String, qux: Vec<i32>) -> Self {
439        Self { baz, qux }
440    }
441}
442"#,
443        );
444    }
445
446    #[test]
447    fn check_it_reuses_existing_impls() {
448        check_assist(
449            generate_new,
450            r#"
451struct Foo {$0}
452
453impl Foo {}
454"#,
455            r#"
456struct Foo {}
457
458impl Foo {
459    fn $0new() -> Self {
460        Self {  }
461    }
462}
463"#,
464        );
465        check_assist(
466            generate_new,
467            r#"
468struct Foo {$0}
469
470impl Foo {
471    fn qux(&self) {}
472}
473"#,
474            r#"
475struct Foo {}
476
477impl Foo {
478    fn $0new() -> Self {
479        Self {  }
480    }
481
482    fn qux(&self) {}
483}
484"#,
485        );
486
487        check_assist(
488            generate_new,
489            r#"
490struct Foo {$0}
491
492impl Foo {
493    fn qux(&self) {}
494    fn baz() -> i32 {
495        5
496    }
497}
498"#,
499            r#"
500struct Foo {}
501
502impl Foo {
503    fn $0new() -> Self {
504        Self {  }
505    }
506
507    fn qux(&self) {}
508    fn baz() -> i32 {
509        5
510    }
511}
512"#,
513        );
514    }
515
516    #[test]
517    fn non_zero_indent() {
518        check_assist(
519            generate_new,
520            r#"
521mod foo {
522    struct $0Foo {}
523}
524"#,
525            r#"
526mod foo {
527    struct Foo {}
528
529    impl Foo {
530        fn $0new() -> Self {
531            Self {  }
532        }
533    }
534}
535"#,
536        );
537        check_assist(
538            generate_new,
539            r#"
540mod foo {
541    mod bar {
542        struct $0Foo {}
543    }
544}
545"#,
546            r#"
547mod foo {
548    mod bar {
549        struct Foo {}
550
551        impl Foo {
552            fn $0new() -> Self {
553                Self {  }
554            }
555        }
556    }
557}
558"#,
559        );
560        check_assist(
561            generate_new,
562            r#"
563mod foo {
564    struct $0Foo {}
565
566    impl Foo {
567        fn some() {}
568    }
569}
570"#,
571            r#"
572mod foo {
573    struct Foo {}
574
575    impl Foo {
576        fn $0new() -> Self {
577            Self {  }
578        }
579
580        fn some() {}
581    }
582}
583"#,
584        );
585        check_assist(
586            generate_new,
587            r#"
588mod foo {
589    mod bar {
590        struct $0Foo {}
591
592        impl Foo {
593            fn some() {}
594        }
595    }
596}
597"#,
598            r#"
599mod foo {
600    mod bar {
601        struct Foo {}
602
603        impl Foo {
604            fn $0new() -> Self {
605                Self {  }
606            }
607
608            fn some() {}
609        }
610    }
611}
612"#,
613        );
614        check_assist(
615            generate_new,
616            r#"
617mod foo {
618    mod bar {
619struct $0Foo {}
620
621        impl Foo {
622            fn some() {}
623        }
624    }
625}
626"#,
627            r#"
628mod foo {
629    mod bar {
630struct Foo {}
631
632        impl Foo {
633            fn $0new() -> Self {
634                Self {  }
635            }
636
637            fn some() {}
638        }
639    }
640}
641"#,
642        );
643    }
644
645    #[test]
646    fn check_visibility_of_new_fn_based_on_struct() {
647        check_assist(
648            generate_new,
649            r#"
650pub struct Foo {$0}
651"#,
652            r#"
653pub struct Foo {}
654
655impl Foo {
656    pub fn $0new() -> Self {
657        Self {  }
658    }
659}
660"#,
661        );
662        check_assist(
663            generate_new,
664            r#"
665pub(crate) struct Foo {$0}
666"#,
667            r#"
668pub(crate) struct Foo {}
669
670impl Foo {
671    pub(crate) fn $0new() -> Self {
672        Self {  }
673    }
674}
675"#,
676        );
677    }
678
679    #[test]
680    fn generate_new_not_applicable_if_fn_exists() {
681        check_assist_not_applicable(
682            generate_new,
683            r#"
684struct Foo {$0}
685
686impl Foo {
687    fn new() -> Self {
688        Self
689    }
690}
691"#,
692        );
693
694        check_assist_not_applicable(
695            generate_new,
696            r#"
697struct Foo {$0}
698
699impl Foo {
700    fn New() -> Self {
701        Self
702    }
703}
704"#,
705        );
706    }
707
708    #[test]
709    fn generate_new_target() {
710        check_assist_target(
711            generate_new,
712            r#"
713struct SomeThingIrrelevant;
714/// Has a lifetime parameter
715struct Foo<'a, T: Foo<'a>> {$0}
716struct EvenMoreIrrelevant;
717"#,
718            "/// Has a lifetime parameter
719struct Foo<'a, T: Foo<'a>> {}",
720        );
721    }
722
723    #[test]
724    fn test_unrelated_new() {
725        check_assist(
726            generate_new,
727            r#"
728pub struct AstId<N: AstNode> {
729    file_id: HirFileId,
730    file_ast_id: FileAstId<N>,
731}
732
733impl<N: AstNode> AstId<N> {
734    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
735        AstId { file_id, file_ast_id }
736    }
737}
738
739pub struct Source<T> {
740    pub file_id: HirFileId,$0
741    pub ast: T,
742}
743
744impl<T> Source<T> {
745    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
746        Source { file_id: self.file_id, ast: f(self.ast) }
747    }
748}
749"#,
750            r#"
751pub struct AstId<N: AstNode> {
752    file_id: HirFileId,
753    file_ast_id: FileAstId<N>,
754}
755
756impl<N: AstNode> AstId<N> {
757    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
758        AstId { file_id, file_ast_id }
759    }
760}
761
762pub struct Source<T> {
763    pub file_id: HirFileId,
764    pub ast: T,
765}
766
767impl<T> Source<T> {
768    pub fn $0new(file_id: HirFileId, ast: T) -> Self {
769        Self { file_id, ast }
770    }
771
772    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
773        Source { file_id: self.file_id, ast: f(self.ast) }
774    }
775}
776"#,
777        );
778    }
779}
780
781#[cfg(test)]
782mod tuple_tests {
783    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
784
785    use super::*;
786
787    #[test]
788    fn test_generate_new_with_zst_fields() {
789        check_assist(
790            generate_new,
791            r#"
792struct Empty;
793
794struct Foo(Empty$0);
795"#,
796            r#"
797struct Empty;
798
799struct Foo(Empty);
800
801impl Foo {
802    fn $0new() -> Self {
803        Self(Empty)
804    }
805}
806"#,
807        );
808        check_assist(
809            generate_new,
810            r#"
811struct Empty;
812
813struct Foo(String, Empty$0);
814"#,
815            r#"
816struct Empty;
817
818struct Foo(String, Empty);
819
820impl Foo {
821    fn $0new(${1:_0}: String) -> Self {
822        Self(${1:_0}, Empty)
823    }
824}
825"#,
826        );
827        check_assist(
828            generate_new,
829            r#"
830enum Empty { Bar }
831
832struct Foo(Empty$0);
833"#,
834            r#"
835enum Empty { Bar }
836
837struct Foo(Empty);
838
839impl Foo {
840    fn $0new() -> Self {
841        Self(Empty::Bar)
842    }
843}
844"#,
845        );
846
847        // make sure the assist only works on unit variants
848        check_assist(
849            generate_new,
850            r#"
851struct Empty {}
852
853struct Foo(Empty$0);
854"#,
855            r#"
856struct Empty {}
857
858struct Foo(Empty);
859
860impl Foo {
861    fn $0new(${1:empty}: Empty) -> Self {
862        Self(${1:empty})
863    }
864}
865"#,
866        );
867        check_assist(
868            generate_new,
869            r#"
870enum Empty { Bar {} }
871
872struct Foo(Empty$0);
873"#,
874            r#"
875enum Empty { Bar {} }
876
877struct Foo(Empty);
878
879impl Foo {
880    fn $0new(${1:empty}: Empty) -> Self {
881        Self(${1:empty})
882    }
883}
884"#,
885        );
886    }
887
888    #[test]
889    fn test_generate_new() {
890        check_assist(
891            generate_new,
892            r#"
893struct Foo($0);
894"#,
895            r#"
896struct Foo();
897
898impl Foo {
899    fn $0new() -> Self {
900        Self()
901    }
902}
903"#,
904        );
905        check_assist(
906            generate_new,
907            r#"
908struct Foo<T: Clone>($0);
909"#,
910            r#"
911struct Foo<T: Clone>();
912
913impl<T: Clone> Foo<T> {
914    fn $0new() -> Self {
915        Self()
916    }
917}
918"#,
919        );
920        check_assist(
921            generate_new,
922            r#"
923struct Foo<'a, T: Foo<'a>>($0);
924"#,
925            r#"
926struct Foo<'a, T: Foo<'a>>();
927
928impl<'a, T: Foo<'a>> Foo<'a, T> {
929    fn $0new() -> Self {
930        Self()
931    }
932}
933"#,
934        );
935        check_assist(
936            generate_new,
937            r#"
938struct Foo(String$0);
939"#,
940            r#"
941struct Foo(String);
942
943impl Foo {
944    fn $0new(${1:_0}: String) -> Self {
945        Self(${1:_0})
946    }
947}
948"#,
949        );
950        check_assist(
951            generate_new,
952            r#"
953struct Vec<T> { };
954struct Foo(String, Vec<i32>$0);
955"#,
956            r#"
957struct Vec<T> { };
958struct Foo(String, Vec<i32>);
959
960impl Foo {
961    fn $0new(${1:_0}: String, ${2:items}: Vec<i32>) -> Self {
962        Self(${1:_0}, ${2:items})
963    }
964}
965"#,
966        );
967    }
968
969    #[test]
970    fn check_that_visibility_modifiers_dont_get_brought_in() {
971        check_assist(
972            generate_new,
973            r#"
974struct Vec<T> { };
975struct Foo(pub String, pub Vec<i32>$0);
976"#,
977            r#"
978struct Vec<T> { };
979struct Foo(pub String, pub Vec<i32>);
980
981impl Foo {
982    fn $0new(${1:_0}: String, ${2:items}: Vec<i32>) -> Self {
983        Self(${1:_0}, ${2:items})
984    }
985}
986"#,
987        );
988    }
989
990    #[test]
991    fn generate_new_not_applicable_if_fn_exists() {
992        check_assist_not_applicable(
993            generate_new,
994            r#"
995struct Foo($0);
996
997impl Foo {
998    fn new() -> Self {
999        Self
1000    }
1001}
1002"#,
1003        );
1004
1005        check_assist_not_applicable(
1006            generate_new,
1007            r#"
1008struct Foo($0);
1009
1010impl Foo {
1011    fn New() -> Self {
1012        Self
1013    }
1014}
1015"#,
1016        );
1017    }
1018
1019    #[test]
1020    fn generate_new_target() {
1021        check_assist_target(
1022            generate_new,
1023            r#"
1024struct SomeThingIrrelevant;
1025/// Has a lifetime parameter
1026struct Foo<'a, T: Foo<'a>>($0);
1027struct EvenMoreIrrelevant;
1028"#,
1029            "/// Has a lifetime parameter
1030struct Foo<'a, T: Foo<'a>>();",
1031        );
1032    }
1033
1034    #[test]
1035    fn test_unrelated_new() {
1036        check_assist(
1037            generate_new,
1038            r#"
1039pub struct AstId<N: AstNode> {
1040    file_id: HirFileId,
1041    file_ast_id: FileAstId<N>,
1042}
1043
1044impl<N: AstNode> AstId<N> {
1045    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
1046        AstId { file_id, file_ast_id }
1047    }
1048}
1049
1050pub struct Source<T>(pub HirFileId,$0 pub T);
1051
1052impl<T> Source<T> {
1053    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
1054        Source(self.file_id, f(self.ast))
1055    }
1056}
1057"#,
1058            r#"
1059pub struct AstId<N: AstNode> {
1060    file_id: HirFileId,
1061    file_ast_id: FileAstId<N>,
1062}
1063
1064impl<N: AstNode> AstId<N> {
1065    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
1066        AstId { file_id, file_ast_id }
1067    }
1068}
1069
1070pub struct Source<T>(pub HirFileId, pub T);
1071
1072impl<T> Source<T> {
1073    pub fn $0new(${1:_0}: HirFileId, ${2:_1}: T) -> Self {
1074        Self(${1:_0}, ${2:_1})
1075    }
1076
1077    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
1078        Source(self.file_id, f(self.ast))
1079    }
1080}
1081"#,
1082        );
1083    }
1084}