neo_solidity/solidity/validate/contract/
state_variables.rs1fn 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}