neo_solidity/solidity/validate/contract/
state_variables.rs

1fn validate_state_variables(
2    metadata: &ContractMetadata,
3    method_name_counts: &std::collections::HashMap<String, usize>,
4    diagnostics: &mut Vec<Diagnostic>,
5) {
6    use std::collections::HashSet;
7
8    let mut state_names = HashSet::new();
9    for state in &metadata.state_variables {
10        match &state.name {
11            Some(name) => {
12                if !state_names.insert(name.clone()) {
13                    diagnostics.push(Diagnostic::error(format!("duplicate state variable '{}'", name)));
14                }
15            }
16            None => diagnostics.push(Diagnostic::error("state variable declared without a name")),
17        }
18
19        if state
20            .visibility
21            .as_deref()
22            .map(|v| v.eq_ignore_ascii_case("public"))
23            == Some(true)
24        {
25            if let Some(name) = state.name.as_deref() {
26                if method_name_counts.get(name).copied().unwrap_or(0) > 1 {
27                    diagnostics.push(Diagnostic::error(format!(
28                        "public state variable '{}' conflicts with a function of the same name",
29                        name
30                    )));
31                }
32            }
33        }
34
35        if state.neo_type.is_none() {
36            let lower_ty = state.ty.to_ascii_lowercase();
37            if lower_ty.starts_with("fixed") || lower_ty.starts_with("ufixed") {
38                diagnostics.push(
39                    Diagnostic::error(format!(
40                        "state variable '{}' uses fixed-point type '{}' which is not supported on NeoVM",
41                        state.name.as_deref().unwrap_or("<unnamed>"),
42                        state.ty
43                    ))
44                    .with_suggestion(
45                        "use scaled integer arithmetic instead (e.g., multiply by 10^18 for 18 decimal places)"
46                    ),
47                );
48            } else {
49                diagnostics.push(Diagnostic::error(format!(
50                    "state variable '{}' has unsupported type '{}'",
51                    state.name.as_deref().unwrap_or("<unnamed>"),
52                    state.ty
53                )));
54            }
55        }
56
57        if state.is_constant && !state.has_initializer {
58            diagnostics.push(Diagnostic::error(format!(
59                "constant state variable '{}' must have an initializer",
60                state.name.as_deref().unwrap_or("<unnamed>")
61            )));
62        }
63    }
64}