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.consts.iter().for_each(|(_, c)| self.visit_const(c));
28 input.structs.iter().for_each(|(_, c)| self.visit_struct(c));
29 input.mappings.iter().for_each(|(_, c)| self.visit_mapping(c));
30 input.storage_variables.iter().for_each(|(_, c)| self.visit_storage_variable(c));
31 input.functions.iter().for_each(|(_, c)| self.visit_function(c));
32 if let Some(c) = input.constructor.as_ref() {
33 self.visit_constructor(c);
34 }
35 }
36
37 fn visit_function(&mut self, function: &Function) {
38 function.const_parameters.iter().for_each(|input| self.visit_type(&input.type_));
39 function.input.iter().for_each(|input| self.visit_type(&input.type_));
40 function.output.iter().for_each(|output| self.visit_type(&output.type_));
41 self.visit_type(&function.output_type);
42
43 self.variant = Some(function.variant);
45
46 self.non_async_external_call_seen = false;
48
49 if matches!(self.variant, Some(Variant::AsyncFunction) | Some(Variant::AsyncTransition)) {
50 super::future_checker::future_check_function(function, &self.state.type_table, &self.state.handler);
51 }
52
53 if self.variant == Some(Variant::AsyncFunction) {
55 self.await_checker.set_futures(
57 function
58 .input
59 .iter()
60 .filter_map(|input| {
61 if let Type::Future(_) = input.type_.clone() { Some(input.identifier.name) } else { None }
62 })
63 .collect(),
64 );
65 }
66
67 self.visit_block(&function.block);
68
69 if self.variant == Some(Variant::AsyncFunction) {
71 if !self.await_checker.static_to_await.is_empty() {
73 self.emit_err(StaticAnalyzerError::future_awaits_missing(
74 self.await_checker
75 .static_to_await
76 .clone()
77 .iter()
78 .map(|f| f.to_string())
79 .collect::<Vec<String>>()
80 .join(", "),
81 function.span(),
82 ));
83 } else if !self.await_checker.to_await.is_empty() {
84 let (num_paths_unawaited, num_paths_duplicate_awaited, num_perfect) =
86 self.await_checker.to_await.iter().fold((0, 0, 0), |(unawaited, duplicate, perfect), path| {
87 (
88 unawaited + if !path.elements.is_empty() { 1 } else { 0 },
89 duplicate + if path.counter > 0 { 1 } else { 0 },
90 perfect + if path.counter > 0 || !path.elements.is_empty() { 0 } else { 1 },
91 )
92 });
93
94 if num_perfect == 0 {
96 self.emit_err(StaticAnalyzerError::no_path_awaits_all_futures_exactly_once(
97 self.await_checker.to_await.len(),
98 function.span(),
99 ));
100 }
101
102 if num_paths_unawaited > 0 {
104 self.emit_warning(StaticAnalyzerWarning::some_paths_do_not_await_all_futures(
105 self.await_checker.to_await.len(),
106 num_paths_unawaited,
107 function.span(),
108 ));
109 }
110
111 if num_paths_duplicate_awaited > 0 {
113 self.emit_warning(StaticAnalyzerWarning::some_paths_contain_duplicate_future_awaits(
114 self.await_checker.to_await.len(),
115 num_paths_duplicate_awaited,
116 function.span(),
117 ));
118 }
119 }
120 }
121 }
122
123 fn visit_constructor(&mut self, _: &Constructor) {
124 }
126}