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.pre_init_code.iter().chain(&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 twb in &sc.two_way_bindings {
93 visit_property(&twb.prop1.clone().into(), ctx);
94 visit_property(&twb.prop2, ctx);
95 if let &Some(p) = &twb.is_model {
96 let mut idx_prop = twb.prop2.clone();
97 let MemberReference::Relative { local_reference, .. } = &mut idx_prop else {
98 unreachable!()
99 };
100 local_reference.reference = p.into();
101 visit_property(&idx_prop, ctx);
102 }
103 }
104
105 for f in &sc.functions {
107 f.code.visit_property_references(ctx, &mut visit_property);
108 }
109
110 for (p, e) in &sc.change_callbacks {
112 visit_property(p, ctx);
113 e.borrow().visit_property_references(ctx, &mut visit_property);
114 }
115
116 for popup in &sc.popup_windows {
118 let parent_ctx = ParentScope::new(ctx, None);
119 let popup_ctx = EvaluationContext::new_sub_component(
120 root,
121 popup.item_tree.root,
122 (),
123 Some(&parent_ctx),
124 );
125 popup.position.borrow().visit_property_references(&popup_ctx, &mut visit_property)
126 }
127 for timer in &sc.timers {
129 timer.interval.borrow().visit_property_references(ctx, &mut visit_property);
130 timer.running.borrow().visit_property_references(ctx, &mut visit_property);
131 timer.triggered.borrow().visit_property_references(ctx, &mut visit_property);
132 }
133 });
134
135 for (idx, g) in root.globals.iter_enumerated() {
136 let ctx = EvaluationContext::new_global(root, idx, ());
137 for f in &g.functions {
139 f.code.visit_property_references(&ctx, &mut visit_property);
140 }
141
142 for (p, e) in &g.change_callbacks {
143 visit_property(&LocalMemberReference::from(*p).into(), &ctx);
144 e.borrow().visit_property_references(&ctx, &mut visit_property);
145 }
146 }
147
148 if let Some(p) = &root.popup_menu {
149 let ctx = EvaluationContext::new_sub_component(root, p.item_tree.root, (), None);
150 visit_property(&p.entries, &ctx);
151 visit_property(&p.sub_menu, &ctx);
152 visit_property(&p.activated, &ctx);
153 }
154
155 clean_unused_bindings(root);
156}
157
158fn visit_property(pr: &MemberReference, ctx: &EvaluationContext) {
159 let p_info = ctx.property_info(pr);
160 if let Some(use_count) = &p_info.use_count {
161 use_count.set(use_count.get() + 1);
162 }
163 if let Some((binding, map)) = &p_info.binding {
164 let c = binding.use_count.get();
165 binding.use_count.set(c + 1);
166 if c == 0 {
167 let ctx2 = map.map_context(ctx);
168 visit_binding_expression(binding, &ctx2);
169 }
170 }
171}
172
173fn visit_binding_expression(binding: &BindingExpression, ctx: &EvaluationContext) {
174 binding.expression.borrow().visit_property_references(ctx, &mut visit_property);
175 match &binding.animation {
176 Some(Animation::Static(e) | Animation::Transition(e)) => {
177 e.visit_property_references(ctx, &mut visit_property);
178 }
179 None => (),
180 }
181}
182
183fn clean_unused_bindings(root: &CompilationUnit) {
185 root.for_each_sub_components(&mut |sc, _| {
186 for (_, e) in &sc.property_init {
187 if e.use_count.get() == 0 {
188 e.expression.replace(Expression::CodeBlock(Vec::new()));
189 }
190 }
191 });
192 for g in &root.globals {
193 for e in g.init_values.values() {
194 if e.use_count.get() == 0 {
195 e.expression.replace(Expression::CodeBlock(Vec::new()));
196 }
197 }
198 }
199}