mirror of
https://github.com/slint-ui/slint.git
synced 2025-07-24 13:35:00 +00:00
109 lines
4.1 KiB
Rust
109 lines
4.1 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
|
|
|
use crate::diagnostics::BuildDiagnostics;
|
|
use crate::expression_tree::Expression;
|
|
|
|
/// Check that pure expression only call pure functions
|
|
pub fn purity_check(doc: &crate::object_tree::Document, diag: &mut BuildDiagnostics) {
|
|
for component in &doc.inner_components {
|
|
crate::object_tree::recurse_elem_including_sub_components_no_borrow(
|
|
component,
|
|
&(),
|
|
&mut |elem, &()| {
|
|
let level = match elem.borrow().is_legacy_syntax {
|
|
true => crate::diagnostics::DiagnosticLevel::Warning,
|
|
false => crate::diagnostics::DiagnosticLevel::Error,
|
|
};
|
|
crate::object_tree::visit_element_expressions(elem, |expr, name, _| {
|
|
if let Some(name) = name {
|
|
let lookup = elem.borrow().lookup_property(name);
|
|
if lookup.declared_pure.unwrap_or(false)
|
|
|| lookup.property_type.is_property_type()
|
|
{
|
|
ensure_pure(expr, Some(diag), level);
|
|
}
|
|
} else {
|
|
// model expression must be pure
|
|
ensure_pure(expr, Some(diag), level);
|
|
};
|
|
})
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
fn ensure_pure(
|
|
expr: &Expression,
|
|
mut diag: Option<&mut BuildDiagnostics>,
|
|
level: crate::diagnostics::DiagnosticLevel,
|
|
) -> bool {
|
|
let mut r = true;
|
|
expr.visit_recursive(&mut |e| match e {
|
|
Expression::CallbackReference(nr, node) => {
|
|
if !nr.element().borrow().lookup_property(nr.name()).declared_pure.unwrap_or(false) {
|
|
if let Some(diag) = diag.as_deref_mut() {
|
|
diag.push_diagnostic(
|
|
format!("Call of impure callback '{}'", nr.name()),
|
|
node,
|
|
level,
|
|
);
|
|
}
|
|
r = false;
|
|
}
|
|
}
|
|
Expression::FunctionReference(nr, node) => {
|
|
match nr.element().borrow().lookup_property(nr.name()).declared_pure {
|
|
Some(true) => return,
|
|
Some(false) => {
|
|
if let Some(diag) = diag.as_deref_mut() {
|
|
diag.push_diagnostic(
|
|
format!("Call of impure function '{}'", nr.name(),),
|
|
node,
|
|
level,
|
|
);
|
|
}
|
|
r = false;
|
|
}
|
|
None => {
|
|
if !ensure_pure(
|
|
&nr.element()
|
|
.borrow()
|
|
.bindings
|
|
.get(nr.name())
|
|
.expect("private function must be local and defined")
|
|
.borrow()
|
|
.expression,
|
|
None,
|
|
level,
|
|
) {
|
|
if let Some(diag) = diag.as_deref_mut() {
|
|
diag.push_diagnostic(
|
|
format!("Call of impure function '{}'", nr.name()),
|
|
node,
|
|
level,
|
|
);
|
|
}
|
|
r = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Expression::BuiltinFunctionReference(func, node) => {
|
|
if !func.is_pure() {
|
|
if let Some(diag) = diag.as_deref_mut() {
|
|
diag.push_diagnostic("Call of impure function".into(), node, level);
|
|
}
|
|
r = false;
|
|
}
|
|
}
|
|
Expression::SelfAssignment { node, .. } => {
|
|
if let Some(diag) = diag.as_deref_mut() {
|
|
diag.push_diagnostic("Assignment in a pure context".into(), node, level);
|
|
}
|
|
r = false;
|
|
}
|
|
_ => (),
|
|
});
|
|
r
|
|
}
|