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.iter().filter(|p| !p.prop.is_function()) {
19 visit_property(&p.prop, &root_ctx);
20 }
21 }
22 for (idx, g) in root.globals.iter_enumerated().filter(|(_, g)| g.exported) {
23 let ctx = EvaluationContext::new_global(root, idx, ());
24 for p in g.public_properties.iter().filter(|p| !p.prop.is_function()) {
25 visit_property(&p.prop, &ctx);
26 }
27 }
28
29 root.for_each_sub_components(&mut |sc, ctx| {
30 for (_, expr) in &sc.property_init {
32 let c = expr.use_count.get();
33 expr.use_count.set(c + 1);
34 if c == 0 {
35 visit_binding_expression(expr, ctx)
36 }
37 }
38 for expr in &sc.init_code {
40 expr.borrow().visit_property_references(ctx, &mut visit_property);
41 }
42 for (idx, r) in sc.repeated.iter_enumerated() {
44 r.model.borrow().visit_property_references(ctx, &mut visit_property);
45 if let Some(lv) = &r.listview {
46 visit_property(&lv.viewport_y, ctx);
47 visit_property(&lv.viewport_width, ctx);
48 visit_property(&lv.viewport_height, ctx);
49 visit_property(&lv.listview_width, ctx);
50 visit_property(&lv.listview_height, ctx);
51
52 let parent_ctx = ParentScope::new(ctx, Some(idx));
53 let rep_ctx = EvaluationContext::new_sub_component(
54 root,
55 r.sub_tree.root,
56 (),
57 Some(&parent_ctx),
58 );
59 visit_property(&lv.prop_y, &rep_ctx);
60 visit_property(&lv.prop_height, &rep_ctx);
61 }
62 for idx in r.data_prop.iter().chain(r.index_prop.iter()) {
63 let p = &root.sub_components[r.sub_tree.root].properties[*idx];
65 p.use_count.set(2);
66 }
67 }
68
69 sc.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);
71 sc.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);
72 if let Some(e) = &sc.grid_layout_input_for_repeated {
73 e.borrow().visit_property_references(ctx, &mut visit_property);
74 }
75 if let Some(e) = &sc.flexbox_layout_item_info_for_repeated {
76 e.borrow().visit_property_references(ctx, &mut visit_property);
77 }
78 for child in &sc.grid_layout_children {
79 child.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);
80 child.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);
81 }
82
83 for b in sc.accessible_prop.values() {
85 b.borrow().visit_property_references(ctx, &mut visit_property)
86 }
87 for i in sc.geometries.iter().filter_map(Option::as_ref) {
88 i.borrow().visit_property_references(ctx, &mut visit_property)
89 }
90
91 for (a, b, _) in &sc.two_way_bindings {
93 visit_property(&a.clone(), ctx);
94 visit_property(&b.clone(), ctx);
95 }
96
97 for f in &sc.functions {
99 f.code.visit_property_references(ctx, &mut visit_property);
100 }
101
102 for (p, e) in &sc.change_callbacks {
104 visit_property(&p.clone(), ctx);
105 e.borrow().visit_property_references(ctx, &mut visit_property);
106 }
107
108 for popup in &sc.popup_windows {
110 let parent_ctx = ParentScope::new(ctx, None);
111 let popup_ctx = EvaluationContext::new_sub_component(
112 root,
113 popup.item_tree.root,
114 (),
115 Some(&parent_ctx),
116 );
117 popup.position.borrow().visit_property_references(&popup_ctx, &mut visit_property)
118 }
119 for timer in &sc.timers {
121 timer.interval.borrow().visit_property_references(ctx, &mut visit_property);
122 timer.running.borrow().visit_property_references(ctx, &mut visit_property);
123 timer.triggered.borrow().visit_property_references(ctx, &mut visit_property);
124 }
125 });
126
127 for (idx, g) in root.globals.iter_enumerated() {
128 let ctx = EvaluationContext::new_global(root, idx, ());
129 for f in &g.functions {
131 f.code.visit_property_references(&ctx, &mut visit_property);
132 }
133
134 for (p, e) in &g.change_callbacks {
135 visit_property(&LocalMemberReference::from(*p).into(), &ctx);
136 e.borrow().visit_property_references(&ctx, &mut visit_property);
137 }
138 }
139
140 if let Some(p) = &root.popup_menu {
141 let ctx = EvaluationContext::new_sub_component(root, p.item_tree.root, (), None);
142 visit_property(&p.entries, &ctx);
143 visit_property(&p.sub_menu, &ctx);
144 visit_property(&p.activated, &ctx);
145 }
146
147 clean_unused_bindings(root);
148}
149
150fn visit_property(pr: &MemberReference, ctx: &EvaluationContext) {
151 let p_info = ctx.property_info(pr);
152 if let Some(use_count) = &p_info.use_count {
153 use_count.set(use_count.get() + 1);
154 }
155 if let Some((binding, map)) = &p_info.binding {
156 let c = binding.use_count.get();
157 binding.use_count.set(c + 1);
158 if c == 0 {
159 let ctx2 = map.map_context(ctx);
160 visit_binding_expression(binding, &ctx2);
161 }
162 }
163}
164
165fn visit_binding_expression(binding: &BindingExpression, ctx: &EvaluationContext) {
166 binding.expression.borrow().visit_property_references(ctx, &mut visit_property);
167 match &binding.animation {
168 Some(Animation::Static(e) | Animation::Transition(e)) => {
169 e.visit_property_references(ctx, &mut visit_property);
170 }
171 None => (),
172 }
173}
174
175fn clean_unused_bindings(root: &CompilationUnit) {
177 root.for_each_sub_components(&mut |sc, _| {
178 for (_, e) in &sc.property_init {
179 if e.use_count.get() == 0 {
180 e.expression.replace(Expression::CodeBlock(Vec::new()));
181 }
182 }
183 });
184 for g in &root.globals {
185 for e in g.init_values.values() {
186 if e.use_count.get() == 0 {
187 e.expression.replace(Expression::CodeBlock(Vec::new()));
188 }
189 }
190 }
191}