i_slint_compiler/passes/remove_unused_properties.rs
1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! Remove the properties which are not used
5
6use crate::expression_tree::TwoWayBinding;
7use crate::object_tree::{Component, Document};
8use std::collections::HashSet;
9
10pub fn remove_unused_properties(doc: &Document) {
11 fn recurse_remove_unused_properties(component: &Component) {
12 crate::object_tree::recurse_elem_including_sub_components_no_borrow(
13 component,
14 &(),
15 &mut |elem, _| {
16 let mut elem = elem.borrow_mut();
17 let mut to_remove = HashSet::new();
18 for (prop, decl) in &elem.property_declarations {
19 if !decl.expose_in_public_api
20 && !elem.named_references.is_referenced(prop)
21 && !elem.property_analysis.borrow().get(prop).is_some_and(|v| v.is_used())
22 && !elem.change_callbacks.contains_key(prop)
23 // Keep properties that carry model-data two-way bindings:
24 // these bridge repeater data to other properties (e.g. globals)
25 // and must survive for the interpreter to wire them up at runtime.
26 && !elem.bindings.get(prop).is_some_and(|b| {
27 b.borrow()
28 .two_way_bindings
29 .iter()
30 .any(|t| matches!(t, TwoWayBinding::ModelData { .. }))
31 })
32 {
33 to_remove.insert(prop.to_owned());
34 }
35 }
36 for x in &to_remove {
37 elem.property_declarations.remove(x);
38 elem.property_analysis.borrow_mut().remove(x);
39 elem.bindings.remove(x);
40 }
41 // Remove changed callbacks over properties that are not materialized as they are not used
42 let mut change_callbacks = std::mem::take(&mut elem.change_callbacks);
43 change_callbacks.retain(|prop, _| {
44 super::materialize_fake_properties::has_declared_property(&elem, prop)
45 });
46 elem.change_callbacks = change_callbacks;
47 },
48 );
49 }
50 doc.visit_all_used_components(|component| recurse_remove_unused_properties(component))
51}