neo-devpack-solidity 0.22.0

Production-focused Solidity-to-NeoVM compilation system
Documentation
fn contract_with_state_variables(state_variables: Vec<StateVariableMetadata>) -> ContractMetadata {
    ContractMetadata {
        name: "StateVariableDiagnostics".to_string(),
        is_abstract: false,
            is_interface: false,
        is_library: false,
        methods: vec![],
        events: vec![],
        errors: vec![],
        uses_storage: state_variables.iter().any(|state| !state.is_constant),
        state_variables,
        structs: vec![],
        enums: vec![],
        contract_types: vec![],
        selector_registry: std::sync::Arc::new(SelectorRegistry::default()),
        documentation: NatspecDoc::default(),
        has_using_for_star: false,
        has_using_function_list: false,
        using_for_libraries: vec![],
        using_directives: vec![],
        has_type_definitions: false,
        type_aliases: std::collections::HashMap::new(),
        flatten_warnings: Vec::new(),
        super_method_map: std::collections::HashMap::new(),
    }
}

fn constant_address_state(name: &str) -> StateVariableMetadata {
    StateVariableMetadata {
        name: Some(name.to_string()),
        ty: "address".to_string(),
        is_constant: true,
        is_immutable: false,
        visibility: Some("internal".to_string()),
        neo_type: Some(NeoType::Address),
        has_initializer: true,
        initializer: None,
    }
}

fn constant_uint_state(name: &str) -> StateVariableMetadata {
    StateVariableMetadata {
        name: Some(name.to_string()),
        ty: "uint256".to_string(),
        is_constant: true,
        is_immutable: false,
        visibility: Some("internal".to_string()),
        neo_type: Some(NeoType::Integer {
            signed: false,
            bits: 256,
        }),
        has_initializer: true,
        initializer: None,
    }
}

fn storage_uint_state(name: &str) -> StateVariableMetadata {
    StateVariableMetadata {
        name: Some(name.to_string()),
        ty: "uint256".to_string(),
        is_constant: false,
        is_immutable: false,
        visibility: Some("internal".to_string()),
        neo_type: Some(NeoType::Integer {
            signed: false,
            bits: 256,
        }),
        has_initializer: false,
        initializer: None,
    }
}

#[test]
fn identical_duplicate_constant_state_variables_are_silent() {
    let metadata = contract_with_state_variables(vec![
        constant_address_state("NEO_CONTRACT"),
        constant_address_state("NEO_CONTRACT"),
    ]);

    let diagnostics = validate_contract(&metadata);
    assert!(
        diagnostics
            .iter()
            .all(|diagnostic| diagnostic.code.as_deref() != Some("W121")),
        "identical constant duplicates should not emit W121, got: {diagnostics:?}",
    );
}

#[test]
fn conflicting_duplicate_constant_state_variables_emit_single_warning() {
    let metadata = contract_with_state_variables(vec![
        constant_address_state("NEO_CONTRACT"),
        constant_uint_state("NEO_CONTRACT"),
        constant_uint_state("NEO_CONTRACT"),
    ]);

    let diagnostics = validate_contract(&metadata);
    let warnings: Vec<&Diagnostic> = diagnostics
        .iter()
        .filter(|diagnostic| diagnostic.code.as_deref() == Some("W121"))
        .collect();
    assert_eq!(
        warnings.len(),
        1,
        "conflicting constant duplicates should emit exactly one W121, got: {diagnostics:?}",
    );
    assert!(
        warnings[0]
            .message
            .contains("conflicting duplicate constant state variable 'NEO_CONTRACT'"),
        "W121 message should explain conflict semantics, got: {:?}",
        warnings[0].message,
    );
}

#[test]
fn non_constant_duplicate_state_variables_still_emit_w122() {
    let metadata = contract_with_state_variables(vec![
        constant_uint_state("totalSupply"),
        storage_uint_state("totalSupply"),
        storage_uint_state("totalSupply"),
    ]);

    let diagnostics = validate_contract(&metadata);
    let non_constant_warnings: Vec<&Diagnostic> = diagnostics
        .iter()
        .filter(|diagnostic| diagnostic.code.as_deref() == Some("W122"))
        .collect();
    assert_eq!(
        non_constant_warnings.len(),
        1,
        "non-constant duplicates should emit exactly one W122, got: {diagnostics:?}",
    );

    let constant_conflict_warnings: Vec<&Diagnostic> = diagnostics
        .iter()
        .filter(|diagnostic| diagnostic.code.as_deref() == Some("W121"))
        .collect();
    assert_eq!(
        constant_conflict_warnings.len(),
        0,
        "non-constant duplicates should not emit W121, got: {diagnostics:?}",
    );
}