Skip to main content

ide_assists/handlers/
remove_unused_imports.rs

1use std::collections::hash_map::Entry;
2
3use hir::{
4    FileRange, InFile, InRealFile, Module, ModuleDef, ModuleSource, PathResolution,
5    PathResolutionPerNs,
6};
7use ide_db::text_edit::TextRange;
8use ide_db::{
9    FxHashMap, RootDatabase,
10    defs::Definition,
11    search::{FileReference, ReferenceCategory, SearchScope},
12};
13use syntax::{
14    AstNode,
15    ast::{self, Rename},
16};
17
18use crate::{AssistContext, AssistId, Assists};
19
20// Assist: remove_unused_imports
21//
22// Removes any use statements in the current selection that are unused.
23//
24// ```
25// struct X();
26// mod foo {
27//     use super::X$0;
28// }
29// ```
30// ->
31// ```
32// struct X();
33// mod foo {
34// }
35// ```
36pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
37    // First, grab the uses that intersect with the current selection.
38    let selected_el = match ctx.covering_element() {
39        syntax::NodeOrToken::Node(n) => n,
40        syntax::NodeOrToken::Token(t) => t.parent()?,
41    };
42
43    // This applies to all uses that are selected, or are ancestors of our selection.
44    let uses_up = selected_el.ancestors().skip(1).filter_map(ast::Use::cast);
45    let uses_down = selected_el
46        .descendants()
47        .filter(|x| x.text_range().intersect(ctx.selection_trimmed()).is_some())
48        .filter_map(ast::Use::cast);
49    let uses = uses_up.chain(uses_down).collect::<Vec<_>>();
50
51    // Maps use nodes to the scope that we should search through to find
52    let mut search_scopes = FxHashMap::<Module, Vec<SearchScope>>::default();
53
54    // iterator over all unused use trees
55    let mut unused = uses
56        .into_iter()
57        .flat_map(|u| u.syntax().descendants().filter_map(ast::UseTree::cast))
58        .filter(|u| u.use_tree_list().is_none())
59        .filter_map(|u| {
60            // Find any uses trees that are unused
61
62            let use_module = ctx.sema.scope(u.syntax()).map(|s| s.module())?;
63            let scope = match search_scopes.entry(use_module) {
64                Entry::Occupied(o) => o.into_mut(),
65                Entry::Vacant(v) => v.insert(module_search_scope(ctx.db(), use_module)),
66            };
67
68            // Gets the path associated with this use tree. If there isn't one, then ignore this use tree.
69            let path = if let Some(path) = u.path() {
70                path
71            } else if u.star_token().is_some() {
72                // This case maps to the situation where the * token is braced.
73                // In this case, the parent use tree's path is the one we should use to resolve the glob.
74                match u.syntax().ancestors().skip(1).find_map(ast::UseTree::cast) {
75                    Some(parent_u) if parent_u.path().is_some() => parent_u.path()?,
76                    _ => return None,
77                }
78            } else {
79                return None;
80            };
81
82            // Get the actual definition associated with this use item.
83            let res = match ctx.sema.resolve_path_per_ns(&path) {
84                Some(x) if x.any().is_some() => x,
85                Some(_) | None => {
86                    return None;
87                }
88            };
89
90            if u.star_token().is_some() {
91                // Check if any of the children of this module are used
92                let def_mod = match res.type_ns {
93                    Some(PathResolution::Def(ModuleDef::Module(module))) => module,
94                    _ => return None,
95                };
96
97                if !def_mod
98                    .scope(ctx.db(), Some(use_module))
99                    .iter()
100                    .filter_map(|(_, x)| match x {
101                        hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)),
102                        _ => None,
103                    })
104                    .any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
105                {
106                    Some(u)
107                } else {
108                    None
109                }
110            } else {
111                is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u)
112            }
113        })
114        .collect::<Vec<_>>();
115
116    // Terminate early unless an unused use is found. Only do the rest of the work if the user selects the assist.
117    if !unused.is_empty() {
118        acc.add(
119            AssistId::quick_fix("remove_unused_imports"),
120            "Remove all unused imports",
121            selected_el.text_range(),
122            |builder| {
123                let editor = builder.make_editor(&selected_el);
124                unused.sort_by_key(|use_tree| use_tree.syntax().text_range().start());
125                for node in &unused {
126                    editor.delete(node.syntax());
127                }
128                for node in unused.iter().cloned() {
129                    node.remove_recursive(&editor);
130                }
131                builder.add_file_edits(ctx.vfs_file_id(), editor);
132            },
133        )
134    } else {
135        None
136    }
137}
138
139fn is_path_per_ns_unused_in_scope(
140    ctx: &AssistContext<'_, '_>,
141    u: &ast::UseTree,
142    scope: &mut Vec<SearchScope>,
143    path: &PathResolutionPerNs,
144) -> bool {
145    if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns {
146        if is_trait_unused_in_scope(ctx, u, scope, t) {
147            let path = [path.value_ns, path.macro_ns];
148            is_path_unused_in_scope(ctx, u, scope, &path)
149        } else {
150            false
151        }
152    } else {
153        let path = [path.type_ns, path.value_ns, path.macro_ns];
154        is_path_unused_in_scope(ctx, u, scope, &path)
155    }
156}
157
158fn is_path_unused_in_scope(
159    ctx: &AssistContext<'_, '_>,
160    u: &ast::UseTree,
161    scope: &mut Vec<SearchScope>,
162    path: &[Option<PathResolution>],
163) -> bool {
164    !path
165        .iter()
166        .filter_map(|path| *path)
167        .filter_map(|res| match res {
168            PathResolution::Def(d) => Some(Definition::from(d)),
169            _ => None,
170        })
171        .any(|def| used_once_in_scope(ctx, def, u.rename(), scope))
172}
173
174fn is_trait_unused_in_scope(
175    ctx: &AssistContext<'_, '_>,
176    u: &ast::UseTree,
177    scope: &mut Vec<SearchScope>,
178    t: &hir::Trait,
179) -> bool {
180    !std::iter::once((Definition::Trait(*t), u.rename()))
181        .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
182        .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
183}
184
185fn used_once_in_scope(
186    ctx: &AssistContext<'_, '_>,
187    def: Definition,
188    rename: Option<Rename>,
189    scopes: &Vec<SearchScope>,
190) -> bool {
191    let mut found = false;
192
193    for scope in scopes {
194        let mut search_non_import = |_, r: FileReference| {
195            // The import itself is a use; we must skip that.
196            if !r.category.contains(ReferenceCategory::IMPORT) {
197                found = true;
198                true
199            } else {
200                false
201            }
202        };
203        def.usages(&ctx.sema)
204            .in_scope(scope)
205            .with_rename(rename.as_ref())
206            .search(&mut search_non_import);
207        if found {
208            break;
209        }
210    }
211
212    found
213}
214
215/// Build a search scope spanning the given module but none of its submodules.
216fn module_search_scope(db: &RootDatabase, module: hir::Module) -> Vec<SearchScope> {
217    let (file_id, range) = {
218        let InFile { file_id, value } = module.definition_source(db);
219        if let Some(InRealFile { file_id, value: call_source }) = file_id.original_call_node(db) {
220            (file_id, Some(call_source.text_range()))
221        } else {
222            (
223                file_id.original_file(db),
224                match value {
225                    ModuleSource::SourceFile(_) => None,
226                    ModuleSource::Module(it) => Some(it.syntax().text_range()),
227                    ModuleSource::BlockExpr(it) => Some(it.syntax().text_range()),
228                },
229            )
230        }
231    };
232
233    fn split_at_subrange(first: TextRange, second: TextRange) -> (TextRange, Option<TextRange>) {
234        let intersect = first.intersect(second);
235        if let Some(intersect) = intersect {
236            let start_range = TextRange::new(first.start(), intersect.start());
237
238            if intersect.end() < first.end() {
239                (start_range, Some(TextRange::new(intersect.end(), first.end())))
240            } else {
241                (start_range, None)
242            }
243        } else {
244            (first, None)
245        }
246    }
247
248    let mut scopes = Vec::new();
249    if let Some(range) = range {
250        let mut ranges = vec![range];
251
252        for child in module.children(db) {
253            let rng = match child.definition_source(db).value {
254                ModuleSource::SourceFile(_) => continue,
255                ModuleSource::Module(it) => it.syntax().text_range(),
256                ModuleSource::BlockExpr(_) => continue,
257            };
258            let mut new_ranges = Vec::new();
259            for old_range in ranges.iter_mut() {
260                let split = split_at_subrange(*old_range, rng);
261                *old_range = split.0;
262                new_ranges.extend(split.1);
263            }
264
265            ranges.append(&mut new_ranges);
266        }
267
268        for range in ranges {
269            scopes.push(SearchScope::file_range(FileRange { file_id, range }));
270        }
271    } else {
272        scopes.push(SearchScope::single_file(file_id));
273    }
274
275    scopes
276}
277
278#[cfg(test)]
279mod tests {
280    use crate::tests::{check_assist, check_assist_not_applicable};
281
282    use super::*;
283
284    #[test]
285    fn remove_unused() {
286        check_assist(
287            remove_unused_imports,
288            r#"
289struct X();
290struct Y();
291mod z {
292    $0use super::X;
293    use super::Y;$0
294}
295"#,
296            r#"
297struct X();
298struct Y();
299mod z {
300}
301"#,
302        );
303    }
304
305    #[test]
306    fn remove_unused_is_precise() {
307        check_assist(
308            remove_unused_imports,
309            r#"
310struct X();
311mod z {
312$0use super::X;$0
313
314fn w() {
315    struct X();
316    let x = X();
317}
318}
319"#,
320            r#"
321struct X();
322mod z {
323
324fn w() {
325    struct X();
326    let x = X();
327}
328}
329"#,
330        );
331    }
332
333    #[test]
334    fn trait_name_use_is_use() {
335        check_assist_not_applicable(
336            remove_unused_imports,
337            r#"
338struct X();
339trait Y {
340    fn f();
341}
342
343impl Y for X {
344    fn f() {}
345}
346mod z {
347$0use super::X;
348use super::Y;$0
349
350fn w() {
351    X::f();
352}
353}
354"#,
355        );
356    }
357
358    #[test]
359    fn trait_item_use_is_use() {
360        check_assist_not_applicable(
361            remove_unused_imports,
362            r#"
363struct X();
364trait Y {
365    fn f(self);
366}
367
368impl Y for X {
369    fn f(self) {}
370}
371mod z {
372$0use super::X;
373use super::Y;$0
374
375fn w() {
376    let x = X();
377    x.f();
378}
379}
380"#,
381        );
382    }
383
384    #[test]
385    fn renamed_trait_item_use_is_use() {
386        check_assist_not_applicable(
387            remove_unused_imports,
388            r#"
389struct X();
390trait Y {
391    fn f(self);
392}
393
394impl Y for X {
395    fn f(self) {}
396}
397mod z {
398$0use super::X;
399use super::Y as Z;$0
400
401fn w() {
402    let x = X();
403    x.f();
404}
405}
406"#,
407        );
408    }
409
410    #[test]
411    fn renamed_underscore_trait_item_use_is_use() {
412        check_assist_not_applicable(
413            remove_unused_imports,
414            r#"
415struct X();
416trait Y {
417    fn f(self);
418}
419
420impl Y for X {
421    fn f(self) {}
422}
423mod z {
424$0use super::X;
425use super::Y as _;$0
426
427fn w() {
428    let x = X();
429    x.f();
430}
431}
432"#,
433        );
434    }
435
436    #[test]
437    fn dont_remove_used() {
438        check_assist_not_applicable(
439            remove_unused_imports,
440            r#"
441struct X();
442struct Y();
443mod z {
444$0use super::X;
445use super::Y;$0
446
447fn w() {
448    let x = X();
449    let y = Y();
450}
451}
452"#,
453        );
454    }
455
456    #[test]
457    fn remove_unused_in_braces() {
458        check_assist(
459            remove_unused_imports,
460            r#"
461struct X();
462struct Y();
463mod z {
464    $0use super::{X, Y};$0
465
466    fn w() {
467        let x = X();
468    }
469}
470"#,
471            r#"
472struct X();
473struct Y();
474mod z {
475    use super::X;
476
477    fn w() {
478        let x = X();
479    }
480}
481"#,
482        );
483    }
484
485    #[test]
486    fn remove_unused_under_cursor() {
487        check_assist(
488            remove_unused_imports,
489            r#"
490struct X();
491mod z {
492    use super::X$0;
493}
494"#,
495            r#"
496struct X();
497mod z {
498}
499"#,
500        );
501    }
502
503    #[test]
504    fn remove_multi_use_block() {
505        check_assist(
506            remove_unused_imports,
507            r#"
508struct X();
509$0mod y {
510    use super::X;
511}
512mod z {
513    use super::X;
514}$0
515"#,
516            r#"
517struct X();
518mod y {
519}
520mod z {
521}
522"#,
523        );
524    }
525
526    #[test]
527    fn remove_nested() {
528        check_assist(
529            remove_unused_imports,
530            r#"
531struct X();
532mod y {
533    struct Y();
534    mod z {
535        use crate::{X, y::Y}$0;
536        fn f() {
537            let x = X();
538        }
539    }
540}
541"#,
542            r#"
543struct X();
544mod y {
545    struct Y();
546    mod z {
547        use crate::X;
548        fn f() {
549            let x = X();
550        }
551    }
552}
553"#,
554        );
555    }
556
557    #[test]
558    fn remove_nested_first_item() {
559        check_assist(
560            remove_unused_imports,
561            r#"
562struct X();
563mod y {
564    struct Y();
565    mod z {
566        use crate::{X, y::Y}$0;
567        fn f() {
568            let y = Y();
569        }
570    }
571}
572"#,
573            r#"
574struct X();
575mod y {
576    struct Y();
577    mod z {
578        use crate::y::Y;
579        fn f() {
580            let y = Y();
581        }
582    }
583}
584"#,
585        );
586    }
587
588    #[test]
589    fn remove_unused_auto_remove_brace_nested() {
590        check_assist(
591            remove_unused_imports,
592            r#"
593mod a {
594    pub struct A();
595}
596mod b {
597    struct F();
598    mod c {
599        $0use {{super::{{
600            {d::{{{{{{{S, U}}}}}}}},
601            {{{{e::{H, L, {{{R}}}}}}}},
602            F, super::a::A
603        }}}};$0
604        fn f() {
605            let f = F();
606            let l = L();
607            let a = A();
608            let s = S();
609            let h = H();
610        }
611    }
612
613    mod d {
614        pub struct S();
615        pub struct U();
616    }
617
618    mod e {
619        pub struct H();
620        pub struct L();
621        pub struct R();
622    }
623}
624"#,
625            r#"
626mod a {
627    pub struct A();
628}
629mod b {
630    struct F();
631    mod c {
632        use super::{
633            d::S,
634            e::{H, L},
635            F, super::a::A
636        };
637        fn f() {
638            let f = F();
639            let l = L();
640            let a = A();
641            let s = S();
642            let h = H();
643        }
644    }
645
646    mod d {
647        pub struct S();
648        pub struct U();
649    }
650
651    mod e {
652        pub struct H();
653        pub struct L();
654        pub struct R();
655    }
656}
657"#,
658        );
659    }
660
661    #[test]
662    fn remove_comma_after_auto_remove_brace() {
663        check_assist(
664            remove_unused_imports,
665            r#"
666mod m {
667    pub mod x {
668        pub struct A;
669        pub struct B;
670    }
671    pub mod y {
672        pub struct C;
673    }
674}
675
676$0use m::{
677    x::{A, B},
678    y::C,
679};$0
680
681fn main() {
682    B;
683}
684"#,
685            r#"
686mod m {
687    pub mod x {
688        pub struct A;
689        pub struct B;
690    }
691    pub mod y {
692        pub struct C;
693    }
694}
695
696use m::
697    x::B
698;
699
700fn main() {
701    B;
702}
703"#,
704        );
705        check_assist(
706            remove_unused_imports,
707            r#"
708mod m {
709    pub mod x {
710        pub struct A;
711        pub struct B;
712    }
713    pub mod y {
714        pub struct C;
715        pub struct D;
716    }
717    pub mod z {
718        pub struct E;
719        pub struct F;
720    }
721}
722
723$0use m::{
724    x::{A, B},
725    y::{C, D,},
726    z::{E, F},
727};$0
728
729fn main() {
730    B;
731    C;
732    F;
733}
734"#,
735            r#"
736mod m {
737    pub mod x {
738        pub struct A;
739        pub struct B;
740    }
741    pub mod y {
742        pub struct C;
743        pub struct D;
744    }
745    pub mod z {
746        pub struct E;
747        pub struct F;
748    }
749}
750
751use m::{
752    x::B,
753    y::C,
754    z::F,
755};
756
757fn main() {
758    B;
759    C;
760    F;
761}
762"#,
763        );
764    }
765
766    #[test]
767    fn remove_nested_all_unused() {
768        check_assist(
769            remove_unused_imports,
770            r#"
771struct X();
772mod y {
773    struct Y();
774    mod z {
775        use crate::{X, y::Y}$0;
776    }
777}
778"#,
779            r#"
780struct X();
781mod y {
782    struct Y();
783    mod z {
784    }
785}
786"#,
787        );
788    }
789
790    #[test]
791    fn remove_unused_glob() {
792        check_assist(
793            remove_unused_imports,
794            r#"
795struct X();
796struct Y();
797mod z {
798    use super::*$0;
799}
800"#,
801            r#"
802struct X();
803struct Y();
804mod z {
805}
806"#,
807        );
808    }
809
810    #[test]
811    fn remove_unused_braced_glob() {
812        check_assist(
813            remove_unused_imports,
814            r#"
815struct X();
816struct Y();
817mod z {
818    use super::{*}$0;
819}
820"#,
821            r#"
822struct X();
823struct Y();
824mod z {
825}
826"#,
827        );
828    }
829
830    #[test]
831    fn remove_unused_fixes_nested_self() {
832        check_assist(
833            remove_unused_imports,
834            r#"
835mod inner {
836    pub struct X();
837    pub struct Y();
838}
839
840mod z {
841    use super::inner::{self, X}$0;
842
843    fn f() {
844        let y = inner::Y();
845    }
846}
847"#,
848            r#"mod inner {
849    pub struct X();
850    pub struct Y();
851}
852
853mod z {
854    use super::inner::{self};
855
856    fn f() {
857        let y = inner::Y();
858    }
859}
860"#,
861        );
862    }
863
864    #[test]
865    fn dont_remove_used_glob() {
866        check_assist_not_applicable(
867            remove_unused_imports,
868            r#"
869struct X();
870struct Y();
871mod z {
872    use super::*$0;
873
874    fn f() {
875        let x = X();
876    }
877}
878"#,
879        );
880    }
881
882    #[test]
883    fn only_remove_from_selection() {
884        check_assist(
885            remove_unused_imports,
886            r#"
887struct X();
888struct Y();
889mod z {
890    $0use super::X;$0
891    use super::Y;
892}
893mod w {
894    use super::Y;
895}
896"#,
897            r#"
898struct X();
899struct Y();
900mod z {
901    use super::Y;
902}
903mod w {
904    use super::Y;
905}
906"#,
907        );
908    }
909
910    #[test]
911    fn test_several_files() {
912        check_assist(
913            remove_unused_imports,
914            r#"
915//- /foo.rs
916pub struct X();
917pub struct Y();
918
919//- /main.rs
920$0use foo::X;
921use foo::Y;
922$0
923mod foo;
924mod z {
925    use crate::foo::X;
926}
927"#,
928            r#"
929
930mod foo;
931mod z {
932    use crate::foo::X;
933}
934"#,
935        );
936    }
937
938    #[test]
939    fn use_in_submodule_doesnt_count() {
940        check_assist(
941            remove_unused_imports,
942            r#"
943struct X();
944mod z {
945    use super::X$0;
946
947    mod w {
948        use crate::X;
949
950        fn f() {
951            let x = X();
952        }
953    }
954}
955"#,
956            r#"
957struct X();
958mod z {
959
960    mod w {
961        use crate::X;
962
963        fn f() {
964            let x = X();
965        }
966    }
967}
968"#,
969        );
970    }
971
972    #[test]
973    fn use_in_submodule_file_doesnt_count() {
974        check_assist(
975            remove_unused_imports,
976            r#"
977//- /z/foo.rs
978use crate::X;
979fn f() {
980    let x = X();
981}
982
983//- /main.rs
984pub struct X();
985
986mod z {
987    use crate::X$0;
988    mod foo;
989}
990"#,
991            r#"
992pub struct X();
993
994mod z {
995    mod foo;
996}
997"#,
998        );
999    }
1000
1001    #[test]
1002    fn use_as_alias() {
1003        check_assist_not_applicable(
1004            remove_unused_imports,
1005            r#"
1006mod foo {
1007    pub struct Foo {}
1008}
1009
1010use foo::Foo as Bar$0;
1011
1012fn test(_: Bar) {}
1013"#,
1014        );
1015
1016        check_assist(
1017            remove_unused_imports,
1018            r#"
1019mod foo {
1020    pub struct Foo {}
1021    pub struct Bar {}
1022    pub struct Qux {}
1023    pub trait Quux {
1024        fn quxx(&self) {}
1025    }
1026    impl<T> Quxx for T {}
1027}
1028
1029use foo::{Foo as Bar, Bar as Baz, Qux as _, Quxx as _}$0;
1030
1031fn test(_: Bar) {
1032    let a = ();
1033    a.quxx();
1034}
1035"#,
1036            r#"
1037mod foo {
1038    pub struct Foo {}
1039    pub struct Bar {}
1040    pub struct Qux {}
1041    pub trait Quux {
1042        fn quxx(&self) {}
1043    }
1044    impl<T> Quxx for T {}
1045}
1046
1047use foo::{Foo as Bar, Quxx as _};
1048
1049fn test(_: Bar) {
1050    let a = ();
1051    a.quxx();
1052}
1053"#,
1054        );
1055    }
1056
1057    #[test]
1058    fn test_unused_macro() {
1059        check_assist(
1060            remove_unused_imports,
1061            r#"
1062//- /foo.rs crate:foo
1063#[macro_export]
1064macro_rules! m { () => {} }
1065
1066//- /main.rs crate:main deps:foo
1067use foo::m;$0
1068fn main() {}
1069"#,
1070            r#"
1071fn main() {}
1072"#,
1073        );
1074
1075        check_assist_not_applicable(
1076            remove_unused_imports,
1077            r#"
1078//- /foo.rs crate:foo
1079#[macro_export]
1080macro_rules! m { () => {} }
1081
1082//- /main.rs crate:main deps:foo
1083use foo::m;$0
1084fn main() {
1085    m!();
1086}
1087"#,
1088        );
1089
1090        check_assist_not_applicable(
1091            remove_unused_imports,
1092            r#"
1093//- /foo.rs crate:foo
1094#[macro_export]
1095macro_rules! m { () => {} }
1096
1097//- /bar.rs crate:bar deps:foo
1098pub use foo::m;
1099fn m() {}
1100
1101
1102//- /main.rs crate:main deps:bar
1103use bar::m;$0
1104fn main() {
1105    m!();
1106}
1107"#,
1108        );
1109    }
1110
1111    #[test]
1112    fn test_conflict_derive_macro() {
1113        check_assist_not_applicable(
1114            remove_unused_imports,
1115            r#"
1116//- proc_macros: derive_identity
1117//- minicore: derive
1118//- /bar.rs crate:bar
1119pub use proc_macros::DeriveIdentity;
1120pub trait DeriveIdentity {}
1121
1122//- /main.rs crate:main deps:bar
1123$0use bar::DeriveIdentity;$0
1124#[derive(DeriveIdentity)]
1125struct S;
1126"#,
1127        );
1128
1129        check_assist_not_applicable(
1130            remove_unused_imports,
1131            r#"
1132//- proc_macros: derive_identity
1133//- minicore: derive
1134//- /bar.rs crate:bar
1135pub use proc_macros::DeriveIdentity;
1136pub fn DeriveIdentity() {}
1137
1138//- /main.rs crate:main deps:bar
1139$0use bar::DeriveIdentity;$0
1140#[derive(DeriveIdentity)]
1141struct S;
1142"#,
1143        );
1144
1145        check_assist_not_applicable(
1146            remove_unused_imports,
1147            r#"
1148//- proc_macros: derive_identity
1149//- minicore: derive
1150//- /bar.rs crate:bar
1151pub use proc_macros::DeriveIdentity;
1152pub fn DeriveIdentity() {}
1153
1154//- /main.rs crate:main deps:bar
1155$0use bar::DeriveIdentity;$0
1156fn main() {
1157    DeriveIdentity();
1158}
1159"#,
1160        );
1161    }
1162}