1mod apply;
9mod items;
10mod module_graph;
11mod reachability;
12mod references;
13mod struct_utils;
14
15use crate::module::Module;
16
17use self::{apply::prune_module, module_graph::ModuleGraph, reachability::compute_reachability};
18
19pub fn prune_modules(modules: &mut [Module]) {
24 if modules.is_empty() {
25 return;
26 }
27
28 let graph = ModuleGraph::new(modules);
29 let reachability = compute_reachability(&graph);
30
31 for module in modules {
32 if let Some(reach) = reachability.get(&module.name) {
33 prune_module(module, reach);
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use crate::{
41 block::Block,
42 function::Function,
43 module::{Module, Symbol},
44 scope::Scope,
45 stage::Stage,
46 statement::Statement,
47 };
48
49 use super::prune_modules;
50
51 #[test]
52 fn prunes_unreachable_private_functions() {
53 let mut modules = vec![Module {
54 name: "control".to_string(),
55 stage: Stage::Control,
56 body: Block {
57 statements: vec![Statement::FunctionDecl(Function {
58 name: "add".to_string(),
59 params: vec![],
60 body: Block { statements: vec![] },
61 doc: None,
62 debug: None,
63 event: None,
64 event_filter: None,
65 })],
66 },
67 imports: vec![],
68 submodules: vec![],
69 locales: vec![],
70 symbols: vec![Symbol {
71 scope: Scope::Public,
72 statement: Statement::FunctionDecl(Function {
73 name: "on_init".to_string(),
74 params: vec![],
75 body: Block { statements: vec![] },
76 doc: None,
77 debug: None,
78 event: Some("on_init".to_string()),
79 event_filter: None,
80 }),
81 }],
82 }];
83
84 prune_modules(&mut modules);
85
86 assert!(modules[0].body.statements.is_empty());
87 assert_eq!(modules[0].symbols.len(), 1);
88 assert_eq!(
89 match &modules[0].symbols[0].statement {
90 Statement::FunctionDecl(function) => function.name.as_str(),
91 _ => panic!("expected function"),
92 },
93 "on_init"
94 );
95 }
96
97 #[test]
98 fn prunes_unused_public_exports() {
99 let mut modules = vec![Module {
100 name: "control".to_string(),
101 stage: Stage::Control,
102 body: Block { statements: vec![] },
103 imports: vec![],
104 submodules: vec![],
105 locales: vec![],
106 symbols: vec![
107 Symbol {
108 scope: Scope::Public,
109 statement: Statement::FunctionDecl(Function {
110 name: "unused".to_string(),
111 params: vec![],
112 body: Block { statements: vec![] },
113 doc: None,
114 debug: None,
115 event: None,
116 event_filter: None,
117 }),
118 },
119 Symbol {
120 scope: Scope::Public,
121 statement: Statement::FunctionDecl(Function {
122 name: "on_init".to_string(),
123 params: vec![],
124 body: Block { statements: vec![] },
125 doc: None,
126 debug: None,
127 event: Some("on_init".to_string()),
128 event_filter: None,
129 }),
130 },
131 ],
132 }];
133
134 prune_modules(&mut modules);
135
136 assert_eq!(modules[0].symbols.len(), 1);
137 }
138}