neo_solidity/solidity/validate/contract/
entry.rs

1pub fn validate_contract(metadata: &ContractMetadata) -> Vec<Diagnostic> {
2    let mut diagnostics = Vec::new();
3
4    let method_name_counts = build_method_name_counts(metadata);
5    let constructor_count = validate_methods(metadata, &mut diagnostics);
6
7    if constructor_count > 1 {
8        diagnostics.push(Diagnostic::error(format!("multiple constructors defined ({} total)", constructor_count)));
9    }
10
11    validate_state_variables(metadata, &method_name_counts, &mut diagnostics);
12    validate_events(metadata, &mut diagnostics);
13    validate_return_types(metadata, &mut diagnostics);
14    validate_erc_nep_patterns(metadata, &mut diagnostics);
15    validate_using_directives(metadata, &mut diagnostics);
16    validate_type_definitions(metadata, &mut diagnostics);
17    validate_library(metadata, &mut diagnostics);
18    validate_abstract_contract(metadata, &mut diagnostics);
19    validate_flatten_warnings(metadata, &mut diagnostics);
20
21    diagnostics
22}
23
24fn validate_using_directives(metadata: &ContractMetadata, diagnostics: &mut Vec<Diagnostic>) {
25    if metadata.has_using_for_star {
26        diagnostics.push(
27            Diagnostic::warning(
28                "'using X for *' is supported; all library functions are available \
29                 but type-specific filtering is not enforced at compile time"
30            )
31            .with_suggestion(
32                "this is functionally correct — library functions can be called \
33                 as member functions on any type"
34            ),
35        );
36    }
37
38    if metadata.has_using_function_list {
39        diagnostics.push(
40            Diagnostic::warning(
41                "'using { f, g } for Type' is supported; all library functions are \
42                 merged (selective filtering is not enforced at compile time)"
43            )
44            .with_suggestion(
45                "this is functionally correct — all library functions are available; \
46                 unused functions are excluded during bytecode optimization"
47            ),
48        );
49    }
50}
51
52fn validate_type_definitions(_metadata: &ContractMetadata, _diagnostics: &mut Vec<Diagnostic>) {
53    // User-defined value types (`type X is Y`) are now supported.
54    // They are treated as transparent type aliases; `wrap`/`unwrap` compile to no-ops.
55}
56
57fn validate_abstract_contract(metadata: &ContractMetadata, diagnostics: &mut Vec<Diagnostic>) {
58    let unimplemented: Vec<&str> = metadata
59        .methods
60        .iter()
61        .filter(|m| {
62            matches!(m.kind, FunctionKind::Regular)
63                && m.body.is_none()
64        })
65        .map(|m| m.name.as_str())
66        .collect();
67
68    if unimplemented.is_empty() {
69        return;
70    }
71
72    if metadata.is_abstract {
73        // Abstract contracts: informational warning listing unimplemented methods.
74        // This helps developers track what still needs implementation in derived contracts.
75        diagnostics.push(
76            Diagnostic::warning(format!(
77                "abstract contract '{}' has {} unimplemented function(s): [{}]",
78                metadata.name,
79                unimplemented.len(),
80                unimplemented.join(", "),
81            ))
82            .with_suggestion(
83                "derived contracts must implement these functions or also be declared abstract"
84            ),
85        );
86    } else {
87        // Non-abstract contracts must implement all declared functions.
88        diagnostics.push(
89            Diagnostic::error(format!(
90                "contract '{}' has {} unimplemented function(s) [{}] but is not declared abstract; \
91                 either provide implementations or declare the contract as 'abstract contract {}'",
92                metadata.name,
93                unimplemented.len(),
94                unimplemented.join(", "),
95                metadata.name,
96            ))
97            .with_suggestion(
98                "add 'abstract' before 'contract', or provide function bodies for all declared functions"
99            ),
100        );
101    }
102}
103
104fn validate_flatten_warnings(metadata: &ContractMetadata, diagnostics: &mut Vec<Diagnostic>) {
105    for warning in &metadata.flatten_warnings {
106        diagnostics.push(
107            Diagnostic::warning(warning.clone())
108                .with_code("W200")
109                .with_suggestion(
110                    "mark the base function 'virtual' and the overriding function 'override'",
111                ),
112        );
113    }
114}