use super::StaticAnalyzingVisitor;
use leo_ast::{Type, *};
use leo_errors::{StaticAnalyzerError, StaticAnalyzerWarning};
impl ProgramVisitor for StaticAnalyzingVisitor<'_> {
fn visit_program_scope(&mut self, input: &ProgramScope) {
self.current_program = input.program_id.name.name;
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));
input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
}
fn visit_function(&mut self, function: &Function) {
self.variant = Some(function.variant);
self.non_async_external_call_seen = false;
if matches!(self.variant, Some(Variant::AsyncFunction) | Some(Variant::AsyncTransition)) {
super::future_checker::future_check_function(function, &self.state.type_table, &self.state.handler);
}
if self.variant == Some(Variant::AsyncFunction) {
self.await_checker.set_futures(
function
.input
.iter()
.filter_map(|input| {
if let Type::Future(_) = input.type_.clone() { Some(input.identifier.name) } else { None }
})
.collect(),
);
}
self.visit_block(&function.block);
if self.variant == Some(Variant::AsyncFunction) {
if !self.await_checker.static_to_await.is_empty() {
self.emit_err(StaticAnalyzerError::future_awaits_missing(
self.await_checker
.static_to_await
.clone()
.iter()
.map(|f| f.to_string())
.collect::<Vec<String>>()
.join(", "),
function.span(),
));
} else if !self.await_checker.to_await.is_empty() {
let (num_paths_unawaited, num_paths_duplicate_awaited, num_perfect) =
self.await_checker.to_await.iter().fold((0, 0, 0), |(unawaited, duplicate, perfect), path| {
(
unawaited + if !path.elements.is_empty() { 1 } else { 0 },
duplicate + if path.counter > 0 { 1 } else { 0 },
perfect + if path.counter > 0 || !path.elements.is_empty() { 0 } else { 1 },
)
});
if num_perfect == 0 {
self.emit_err(StaticAnalyzerError::no_path_awaits_all_futures_exactly_once(
self.await_checker.to_await.len(),
function.span(),
));
}
if num_paths_unawaited > 0 {
self.emit_warning(StaticAnalyzerWarning::some_paths_do_not_await_all_futures(
self.await_checker.to_await.len(),
num_paths_unawaited,
function.span(),
));
}
if num_paths_duplicate_awaited > 0 {
self.emit_warning(StaticAnalyzerWarning::some_paths_contain_duplicate_future_awaits(
self.await_checker.to_await.len(),
num_paths_duplicate_awaited,
function.span(),
));
}
}
}
}
}