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.clone().into(), ctx);
47 visit_property(&lv.viewport_width.clone().into(), ctx);
48 visit_property(&lv.viewport_height.clone().into(), ctx);
49 visit_property(&lv.listview_width.clone().into(), ctx);
50 visit_property(&lv.listview_height.clone().into(), 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 for child in &sc.grid_layout_children {
76 child.layout_info_h.borrow().visit_property_references(ctx, &mut visit_property);
77 child.layout_info_v.borrow().visit_property_references(ctx, &mut visit_property);
78 }
79
80 for b in sc.accessible_prop.values() {
82 b.borrow().visit_property_references(ctx, &mut visit_property)
83 }
84 for i in sc.geometries.iter().filter_map(Option::as_ref) {
85 i.borrow().visit_property_references(ctx, &mut visit_property)
86 }
87
88 for (a, b, _) in &sc.two_way_bindings {
90 visit_property(&a.clone(), ctx);
91 visit_property(&b.clone(), ctx);
92 }
93
94 for f in &sc.functions {
96 f.code.visit_property_references(ctx, &mut visit_property);
97 }
98
99 for (p, e) in &sc.change_callbacks {
101 visit_property(&p.clone(), ctx);
102 e.borrow().visit_property_references(ctx, &mut visit_property);
103 }
104
105 for popup in &sc.popup_windows {
107 let parent_ctx = ParentScope::new(ctx, None);
108 let popup_ctx = EvaluationContext::new_sub_component(
109 root,
110 popup.item_tree.root,
111 (),
112 Some(&parent_ctx),
113 );
114 popup.position.borrow().visit_property_references(&popup_ctx, &mut visit_property)
115 }
116 for timer in &sc.timers {
118 timer.interval.borrow().visit_property_references(ctx, &mut visit_property);
119 timer.running.borrow().visit_property_references(ctx, &mut visit_property);
120 timer.triggered.borrow().visit_property_references(ctx, &mut visit_property);
121 }
122 });
123
124 for (idx, g) in root.globals.iter_enumerated() {
125 let ctx = EvaluationContext::new_global(root, idx, ());
126 for f in &g.functions {
128 f.code.visit_property_references(&ctx, &mut visit_property);
129 }
130
131 for (p, e) in &g.change_callbacks {
132 visit_property(&LocalMemberReference::from(*p).into(), &ctx);
133 e.borrow().visit_property_references(&ctx, &mut visit_property);
134 }
135 }
136
137 if let Some(p) = &root.popup_menu {
138 let ctx = EvaluationContext::new_sub_component(root, p.item_tree.root, (), None);
139 visit_property(&p.entries, &ctx);
140 visit_property(&p.sub_menu, &ctx);
141 visit_property(&p.activated, &ctx);
142 }
143
144 clean_unused_bindings(root);
145}
146
147fn visit_property(pr: &MemberReference, ctx: &EvaluationContext) {
148 let p_info = ctx.property_info(pr);
149 if let Some(use_count) = &p_info.use_count {
150 use_count.set(use_count.get() + 1);
151 }
152 if let Some((binding, map)) = &p_info.binding {
153 let c = binding.use_count.get();
154 binding.use_count.set(c + 1);
155 if c == 0 {
156 let ctx2 = map.map_context(ctx);
157 visit_binding_expression(binding, &ctx2);
158 }
159 }
160}
161
162fn visit_binding_expression(binding: &BindingExpression, ctx: &EvaluationContext) {
163 binding.expression.borrow().visit_property_references(ctx, &mut visit_property);
164 match &binding.animation {
165 Some(Animation::Static(e) | Animation::Transition(e)) => {
166 e.visit_property_references(ctx, &mut visit_property);
167 }
168 None => (),
169 }
170}
171
172fn clean_unused_bindings(root: &CompilationUnit) {
174 root.for_each_sub_components(&mut |sc, _| {
175 for (_, e) in &sc.property_init {
176 if e.use_count.get() == 0 {
177 e.expression.replace(Expression::CodeBlock(Vec::new()));
178 }
179 }
180 });
181 for g in &root.globals {
182 for e in g.init_values.values() {
183 if e.use_count.get() == 0 {
184 e.expression.replace(Expression::CodeBlock(Vec::new()));
185 }
186 }
187 }
188}