leo_passes/static_analysis/
program.rs1use super::StaticAnalyzingVisitor;
18
19use leo_ast::{Type, *};
20use leo_errors::{StaticAnalyzerError, StaticAnalyzerWarning};
21
22impl ProgramVisitor for StaticAnalyzingVisitor<'_> {
23 fn visit_program_scope(&mut self, input: &ProgramScope) {
24 self.current_program = input.program_id.name.name;
26 input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
28 input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
29 input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));
30 input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
31 }
32
33 fn visit_function(&mut self, function: &Function) {
34 function.const_parameters.iter().for_each(|input| self.visit_type(&input.type_));
35 function.input.iter().for_each(|input| self.visit_type(&input.type_));
36 function.output.iter().for_each(|output| self.visit_type(&output.type_));
37 self.visit_type(&function.output_type);
38
39 self.variant = Some(function.variant);
41
42 self.non_async_external_call_seen = false;
44
45 if matches!(self.variant, Some(Variant::AsyncFunction) | Some(Variant::AsyncTransition)) {
46 super::future_checker::future_check_function(function, &self.state.type_table, &self.state.handler);
47 }
48
49 if self.variant == Some(Variant::AsyncFunction) {
51 self.await_checker.set_futures(
53 function
54 .input
55 .iter()
56 .filter_map(|input| {
57 if let Type::Future(_) = input.type_.clone() { Some(input.identifier.name) } else { None }
58 })
59 .collect(),
60 );
61 }
62
63 self.visit_block(&function.block);
64
65 if self.variant == Some(Variant::AsyncFunction) {
67 if !self.await_checker.static_to_await.is_empty() {
69 self.emit_err(StaticAnalyzerError::future_awaits_missing(
70 self.await_checker
71 .static_to_await
72 .clone()
73 .iter()
74 .map(|f| f.to_string())
75 .collect::<Vec<String>>()
76 .join(", "),
77 function.span(),
78 ));
79 } else if !self.await_checker.to_await.is_empty() {
80 let (num_paths_unawaited, num_paths_duplicate_awaited, num_perfect) =
82 self.await_checker.to_await.iter().fold((0, 0, 0), |(unawaited, duplicate, perfect), path| {
83 (
84 unawaited + if !path.elements.is_empty() { 1 } else { 0 },
85 duplicate + if path.counter > 0 { 1 } else { 0 },
86 perfect + if path.counter > 0 || !path.elements.is_empty() { 0 } else { 1 },
87 )
88 });
89
90 if num_perfect == 0 {
92 self.emit_err(StaticAnalyzerError::no_path_awaits_all_futures_exactly_once(
93 self.await_checker.to_await.len(),
94 function.span(),
95 ));
96 }
97
98 if num_paths_unawaited > 0 {
100 self.emit_warning(StaticAnalyzerWarning::some_paths_do_not_await_all_futures(
101 self.await_checker.to_await.len(),
102 num_paths_unawaited,
103 function.span(),
104 ));
105 }
106
107 if num_paths_duplicate_awaited > 0 {
109 self.emit_warning(StaticAnalyzerWarning::some_paths_contain_duplicate_future_awaits(
110 self.await_checker.to_await.len(),
111 num_paths_duplicate_awaited,
112 function.span(),
113 ));
114 }
115 }
116 }
117 }
118}