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