i_slint_compiler/llr/optim_passes/
count_property_use.rs1use crate::llr::{
9 Animation, BindingExpression, CompilationUnit, EvaluationContext, Expression,
10 LocalMemberReference, MemberReference, ParentScope,
11};
12
13pub fn count_property_use(root: &CompilationUnit) {
14 for c in &root.public_components {
17 let root_ctx = EvaluationContext::new_sub_component(root, c.item_tree.root, (), None);
18 for p in c.public_properties.values() {
19 visit_property(&p.prop, &root_ctx);
21 }
22 }
23 for (idx, g) in root.globals.iter_enumerated().filter(|(_, g)| g.exported) {
24 let ctx = EvaluationContext::new_global(root, idx, ());
25 for p in g.public_properties.values() {
26 visit_property(&p.prop, &ctx);
27 }
28 }
29
30 root.for_each_sub_components(&mut |_, sc, ctx| {
31 for (_, expr) in &sc.property_init {
33 let c = expr.use_count.get();
34 expr.use_count.set(c + 1);
35 if c == 0 {
36 visit_binding_expression(expr, ctx)
37 }
38 }
39 for expr in sc.pre_init_code.iter().chain(&sc.init_code) {
41 expr.borrow().visit_property_references(ctx, &mut visit_property);
42 }
43 for (idx, r) in sc.repeated.iter_enumerated() {
45 r.model.borrow().visit_property_references(ctx, &mut visit_property);
46 if let Some(lv) = &r.listview {
47 visit_property(&lv.content_y, ctx);
48 if let Some(content_height) = &lv.content_height {
49 visit_property(content_height, ctx);
50 }
51 if let Some(content_width) = &lv.content_width {
52 visit_property(content_width, ctx);
53 }
54 visit_property(&lv.listview_width, ctx);
55 visit_property(&lv.listview_height, ctx);
56
57 let parent_ctx = ParentScope::new(ctx, Some(idx));
58 let rep_ctx = EvaluationContext::new_sub_component(
59 root,
60 r.sub_tree.root,
61 (),
62 Some(&parent_ctx),
63 );
64 visit_property(&lv.prop_y, &rep_ctx);
65 visit_property(&lv.prop_height, &rep_ctx);
66 }
67 for idx in r.data_prop.iter().chain(r.index_prop.iter()) {
68 let p = &root.sub_components[r.sub_tree.root].properties[*idx];
70 p.use_count.set(2);
71 }
72 if let Some(z_idx) = &r.dynamic_z {
73 let parent_ctx = ParentScope::new(ctx, Some(idx));
74 let rep_ctx = EvaluationContext::new_sub_component(
75 root,
76 r.sub_tree.root,
77 (),
78 Some(&parent_ctx),
79 );
80 visit_property(z_idx, &rep_ctx);
81 }
82 }
83
84 sc.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);
86 sc.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);
87 if let Some(e) = &sc.grid_layout_input_for_repeated {
88 e.borrow().visit_property_references(ctx, &mut visit_property);
89 }
90 if let Some(e) = &sc.flexbox_layout_item_info_for_repeated {
91 e.borrow().visit_property_references(ctx, &mut visit_property);
92 }
93 if let Some((_, e)) = &sc.cross_axis_self_alignment_for_repeated {
94 e.borrow().visit_property_references(ctx, &mut visit_property);
95 }
96 if let Some((_, e)) = &sc.layout_order_for_repeated {
97 e.borrow().visit_property_references(ctx, &mut visit_property);
98 }
99 if let Some(e) = &sc.layout_info_v_constrained_for_repeated {
100 e.borrow().visit_property_references(ctx, &mut visit_property);
101 }
102 if let Some(e) = &sc.layout_info_v_at_cross_width_for_repeated {
103 e.borrow().visit_property_references(ctx, &mut visit_property);
104 }
105 if let Some(e) = &sc.grid_row_child_cross_width {
106 e.borrow().visit_property_references(ctx, &mut visit_property);
107 }
108 for child in &sc.grid_layout_children {
109 child.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);
110 child.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);
111 }
112
113 for b in sc.accessible_prop.values() {
115 b.borrow().visit_property_references(ctx, &mut visit_property)
116 }
117 for i in sc.geometries.iter().filter_map(Option::as_ref) {
118 i.borrow().visit_property_references(ctx, &mut visit_property)
119 }
120
121 for twb in &sc.two_way_bindings {
123 visit_property(&twb.prop1.clone().into(), ctx);
124 visit_property(&twb.prop2, ctx);
125 if let &Some(p) = &twb.is_model {
126 let mut idx_prop = twb.prop2.clone();
127 let MemberReference::Relative { local_reference, .. } = &mut idx_prop else {
128 unreachable!()
129 };
130 local_reference.reference = p.into();
131 visit_property(&idx_prop, ctx);
132 }
133 }
134
135 for anim in sc.animations.values() {
138 anim.visit_property_references(ctx, &mut visit_property);
139 }
140
141 for (p, e) in &sc.change_callbacks {
146 visit_property(p, ctx);
147 e.borrow().visit_property_references(ctx, &mut visit_property);
148 }
149
150 for popup in &sc.popup_windows {
152 let parent_ctx = ParentScope::new(ctx, None);
153 let popup_ctx = EvaluationContext::new_sub_component(
154 root,
155 popup.item_tree.root,
156 (),
157 Some(&parent_ctx),
158 );
159 popup.position.borrow().visit_property_references(&popup_ctx, &mut visit_property)
160 }
161 for timer in &sc.timers {
163 timer.interval.borrow().visit_property_references(ctx, &mut visit_property);
164 timer.running.borrow().visit_property_references(ctx, &mut visit_property);
165 timer.triggered.borrow().visit_property_references(ctx, &mut visit_property);
166 }
167 });
168
169 for (idx, g) in root.globals.iter_enumerated() {
170 let ctx = EvaluationContext::new_global(root, idx, ());
171
172 for (p, e) in &g.change_callbacks {
173 visit_property(&LocalMemberReference::from(*p).into(), &ctx);
174 e.borrow().visit_property_references(&ctx, &mut visit_property);
175 }
176 }
177
178 if let Some(p) = &root.popup_menu {
179 let ctx = EvaluationContext::new_sub_component(root, p.item_tree.root, (), None);
180 visit_property(&p.entries, &ctx);
181 visit_property(&p.sub_menu, &ctx);
182 visit_property(&p.activated, &ctx);
183 }
184
185 root.for_each_z_order_expression(&mut |e, ctx| {
187 e.borrow().visit_property_references(ctx, &mut visit_property)
188 });
189
190 clean_unused_bindings(root);
191}
192
193fn visit_property(pr: &MemberReference, ctx: &EvaluationContext) {
194 let p_info = ctx.property_info(pr);
195 if let Some(use_count) = &p_info.use_count {
196 use_count.set(use_count.get() + 1);
197 }
198 if let Some((binding, map)) = &p_info.binding {
199 let c = binding.use_count.get();
200 binding.use_count.set(c + 1);
201 if c == 0 {
202 let ctx2 = map.map_context(ctx);
203 visit_binding_expression(binding, &ctx2);
204 }
205 }
206 if let Some((function, map)) = ctx.function_info(pr) {
209 let c = function.use_count.get();
210 function.use_count.set(c + 1);
211 if c == 0 {
212 let ctx2 = map.map_context(ctx);
213 function.code.borrow().visit_property_references(&ctx2, &mut visit_property);
214 }
215 }
216}
217
218fn visit_binding_expression(binding: &BindingExpression, ctx: &EvaluationContext) {
219 binding.expression.borrow().visit_property_references(ctx, &mut visit_property);
220 match &binding.animation {
221 Some(Animation::Static(e) | Animation::Transition(e)) => {
222 e.visit_property_references(ctx, &mut visit_property);
223 }
224 None => (),
225 }
226}
227
228fn clean_unused_bindings(root: &CompilationUnit) {
230 root.for_each_sub_components(&mut |_, sc, _| {
231 for (_, e) in &sc.property_init {
232 if e.use_count.get() == 0 {
233 e.expression.replace(Expression::CodeBlock(Vec::new()));
234 }
235 }
236 });
237 for g in &root.globals {
238 for e in g.init_values.values() {
239 if e.use_count.get() == 0 {
240 e.expression.replace(Expression::CodeBlock(Vec::new()));
241 }
242 }
243 }
244}