i_slint_compiler/passes/
check_builtin_shadowing.rs1use crate::diagnostics::BuildDiagnostics;
13use crate::langtype::{ElementType, Type};
14use crate::object_tree::{Component, Document, recurse_elem};
15use crate::parser::SyntaxKind;
16use std::rc::Rc;
17
18pub fn check_builtin_shadowing(doc: &Document, diag: &mut BuildDiagnostics) {
19 for component in &doc.inner_components {
20 recurse_elem(&component.root_element, &(), &mut |elem, _| {
21 let elem = elem.borrow();
22 for (name, decl) in &elem.property_declarations {
23 if !decl.shadows_builtin {
24 continue;
25 }
26 let Some(node) = &decl.node else { continue };
27 let span =
28 node.child_node(SyntaxKind::DeclaredIdentifier).unwrap_or_else(|| node.clone());
29 let builtin_kind = member_kind(&elem.base_type.lookup_property(name).property_type);
30
31 let mut base = elem.base_type.clone();
33 let conflicting_base = loop {
34 let ElementType::Component(c) = base else { break None };
35 base = c.root_element.borrow().base_type.clone();
36 if uses_member_on_root(&c, name) {
37 break Some(c);
38 }
39 };
40
41 if let Some(c) = conflicting_base {
42 diag.push_error(
43 format!(
44 "Cannot shadow the builtin {builtin_kind} '{name}' because it is used by the base component '{}'",
45 c.id
46 ),
47 &span,
48 );
49 } else {
50 diag.push_warning(
51 format!("'{name}' shadows the builtin {builtin_kind} of the same name"),
52 &span,
53 );
54 }
55 }
56 });
57 }
58}
59
60fn uses_member_on_root(component: &Rc<Component>, name: &str) -> bool {
62 let root = component.root_element.borrow();
63 root.named_references.is_referenced(name)
66 || root.bindings.contains_key(name)
67 || root.change_callbacks.contains_key(name)
68}
69
70fn member_kind(ty: &Type) -> &'static str {
72 match ty {
73 Type::Callback { .. } => "callback",
74 Type::Function { .. } => "function",
75 _ => "property",
76 }
77}