1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
use crate::semantics::*; use crate::syntax::*; use crate::*; pub struct VariableInitialization; impl VariableInitialization { fn check_class( &self, class: &Node, analysis: &mut Analysis, diagnostics: &mut Vec<Diagnostic>, ) { if let Some((class_name, _)) = analysis.navigator.symbol_of(class) { let variables = analysis.navigator.variables_of_class(class); let variable_names = variables .iter() .filter_map(|v| analysis.navigator.symbol_of(v)) .map(|(name, _)| name) .collect::<Vec<_>>(); let default_initialized_names = variables .iter() .filter(|v| analysis.navigator.variable_has_const_initializer(v)) .filter_map(|v| analysis.navigator.symbol_of(v)) .map(|(name, _)| name) .collect::<Vec<_>>(); for initializer in analysis.navigator.initializers_of(class) { self.check_initializer( &class_name, &initializer, &variable_names, &default_initialized_names, analysis, diagnostics, ) .unwrap_or(()); } } } fn check_initializer( &self, class_name: &String, initializer: &Node, variable_names: &Vec<String>, default_initialized_names: &Vec<String>, analysis: &mut Analysis, diagnostics: &mut Vec<Diagnostic>, ) -> Option<()> { if let Initializer { ref keyword_pairs, message_pattern, .. } = initializer.kind { let mut uninitialized_names = variable_names.iter().cloned().collect::<HashSet<_>>(); let mut extraneous_names = vec![]; analysis .navigator .keyword_pairs(initializer, keyword_pairs) .into_iter() .filter_map(|(keyword, _)| analysis.navigator.symbol_of(&keyword)) .for_each(|(initialized_name, symbol)| { if variable_names.contains(&initialized_name) { uninitialized_names.remove(&initialized_name); } else { extraneous_names.push((initialized_name, symbol)); } }); for default_init in default_initialized_names.iter() { uninitialized_names.remove(default_init); } if !uninitialized_names.is_empty() { let message_pattern = analysis .navigator .find_child(initializer, message_pattern)?; let selector = analysis .navigator .message_pattern_selector(&message_pattern)?; let mut uninitialized_names = uninitialized_names.into_iter().collect::<Vec<_>>(); uninitialized_names.sort(); diagnostics.push(Diagnostic::IncompleteInitializer( message_pattern.span, selector, uninitialized_names, )); } for (extraneous_name, symbol) in extraneous_names { diagnostics.push(Diagnostic::UndefinedInitializedVariable( symbol.span, extraneous_name, class_name.clone(), )); } } None } } impl Checker for VariableInitialization { fn check(&self, analysis: &mut Analysis, diagnostics: &mut Vec<Diagnostic>) { for class in analysis.navigator.all_classes() { self.check_class(&class, analysis, diagnostics); } } }