Skip to main content

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