//! > Test flat storage path check.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
#[starknet::storage_node]
struct HasA {
    a: felt252,
}

#[starknet::storage_node]
struct ComponentNewStorage {
    a: felt252,
    #[flat]
    has_a: HasA,
}

#[starknet::storage_node]
struct Storage {
    a: felt252,
    #[flat]
    pub has_a: HasA,
}

//! > diagnostics
warning: Plugin diagnostic: The path `has_a.a` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:10:5
    has_a: HasA,
    ^^^^^

warning: Plugin diagnostic: The path `has_a.a` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:17:9
    pub has_a: HasA,
        ^^^^^

//! > ==========================================================================

//! > Test contract flat path check.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
#[starknet::storage_node]
struct Struct1 {
    pub member1: felt252,
}

#[starknet::storage_node]
struct Struct0 {
    pub member0: Struct1,
}

#[starknet::storage_node]
struct IgnoredMemberStruct {
    #[flat]
    pub ignored_member: Struct0,
}

#[starknet::contract]
mod contract_with_and_without_ignored {
    use super::{IgnoredMemberStruct, Struct0};
    #[storage]
    pub struct Storage {
        #[flat]
        pub x: IgnoredMemberStruct,
        #[flat]
        pub y: Struct0,
    }
}

//! > diagnostics
warning: Plugin diagnostic: The path `y.member0` collides with existing path `x.ignored_member.member0`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:25:13
        pub y: Struct0,
            ^

//! > ==========================================================================

//! > Test component flat path check.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
#[starknet::storage_node]
struct HasA {
    a: felt252,
}

#[starknet::storage_node]
struct HasHasA {
    #[flat]
    has_a: HasA,
}

#[starknet::component]
mod component_with_and_without_ignored {
    use super::{HasA, HasHasA};
    #[storage]
    pub struct Storage {
        pub a: felt252,
        #[flat]
        pub has_a: HasA,
        #[flat]
        pub has_has_a: HasHasA,
    }
}

//! > diagnostics
warning: Plugin diagnostic: The path `has_a.a` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:19:13
        pub has_a: HasA,
            ^^^^^

warning: Plugin diagnostic: The path `has_has_a.has_a.a` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:21:13
        pub has_has_a: HasHasA,
            ^^^^^^^^^

//! > ==========================================================================

//! > Test contract and component flat path check.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
#[starknet::storage_node]
struct Struct1 {
    pub member1: felt252,
}

#[starknet::storage_node]
struct Struct0 {
    pub member0: Struct1,
}

#[starknet::storage_node]
struct IgnoredMemberStruct {
    #[flat]
    pub ignored_member: Struct0,
}

#[starknet::component]
mod component {
    use super::{IgnoredMemberStruct, Struct0};
    #[storage]
    pub struct Storage {
        #[flat]
        pub x: Struct0,
        #[flat]
        pub y: IgnoredMemberStruct,
    }
}

#[starknet::contract]
mod contract_with_component {
    use super::component;
    #[storage]
    struct Storage {
        #[substorage(v0)]
        member: component::Storage,
    }
}

//! > diagnostics
warning: Plugin diagnostic: The path `y.ignored_member.member0` collides with existing path `x.member0`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:25:13
        pub y: IgnoredMemberStruct,
            ^

warning: Plugin diagnostic: The path `member.y.ignored_member.member0` collides with existing path `member.x.member0`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:35:9
        member: component::Storage,
        ^^^^^^

//! > ==========================================================================

//! > Test ignored colliding paths check.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: false)

//! > cairo_code
#[starknet::storage_node]
struct SingleMember {
    pub value: felt252,
}

#[starknet::storage_node]
struct IgnoredCollision1 {
    #[flat]
    #[allow(starknet::colliding_storage_paths)]
    pub a: SingleMember,
    #[flat]
    pub b: SingleMember,
}

#[starknet::storage_node]
struct IgnoredCollision2 {
    #[flat]
    pub a: SingleMember,
    #[flat]
    #[allow(starknet::colliding_storage_paths)]
    pub b: SingleMember,
}

#[starknet::storage_node]
#[allow(starknet::colliding_storage_paths)]
struct IgnoredCollision3 {
    #[flat]
    pub a: SingleMember,
    #[flat]
    pub b: SingleMember,
}

//! > diagnostics

//! > ==========================================================================

//! > Test collision by renames.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
#[starknet::storage_node]
struct IgnoredCollision1 {
    pub a: felt252,
    #[rename("a")]
    pub b: felt252,
}

//! > diagnostics
warning: Plugin diagnostic: The path `b` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:5:9
    pub b: felt252,
        ^

//! > ==========================================================================

//! > Test that only structs implementing `ValidStorageTypeTrait` can be stored.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
use starknet::storage::{Map, Vec};
#[starknet::storage_node]
struct ValidStorageStruct {
    pub valid_field: felt252,
}

#[starknet::storage_node]
struct InvalidArrayStruct {
    pub valid: ValidStorageStruct,
    pub invalid_array: Array<felt252>,
}

struct InvalidStorageStruct {}
#[starknet::storage_node]
struct ValidVecStorage {
    pub valid_vec: Vec<felt252>,
}

#[starknet::storage_node]
struct InvalidVecStorage {
    pub invalid_vec: Vec<InvalidStorageStruct>,
}

#[starknet::storage_node]
struct ValidMapStorage {
    pub valid_map: Map<felt252, ValidStorageStruct>,
}

#[starknet::storage_node]
struct InvalidMapStorage {
    pub invalid_map: Map<felt252, InvalidStorageStruct>,
}

//! > diagnostics
warning: Plugin diagnostic: Missing `ValidStorageTypeTrait` for member type. Inference failed with: `Trait has no implementation in context: core::starknet::storage::ValidStorageTypeTrait::<core::array::Array::<core::felt252>>.`. Possible solutions: implement `Store`, mark type with `#[storage_node]`, or use valid args for `Vec` or `Map` library types. To suppress this warning, use `#[allow(starknet::invalid_storage_member_types)]`.
 --> lib.cairo:10:24
    pub invalid_array: Array<felt252>,
                       ^^^^^^^^^^^^^^

warning: Plugin diagnostic: Missing `ValidStorageTypeTrait` for member type. Inference failed with: `Trait has no implementation in context: core::starknet::storage::ValidStorageTypeTrait::<core::starknet::storage::vec::Vec::<test::InvalidStorageStruct>>.`. Possible solutions: implement `Store`, mark type with `#[storage_node]`, or use valid args for `Vec` or `Map` library types. To suppress this warning, use `#[allow(starknet::invalid_storage_member_types)]`.
 --> lib.cairo:21:22
    pub invalid_vec: Vec<InvalidStorageStruct>,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: Plugin diagnostic: Missing `ValidStorageTypeTrait` for member type. Inference failed with: `Trait has no implementation in context: core::starknet::storage::ValidStorageTypeTrait::<core::starknet::storage::map::Map::<core::felt252, test::InvalidStorageStruct>>.`. Possible solutions: implement `Store`, mark type with `#[storage_node]`, or use valid args for `Vec` or `Map` library types. To suppress this warning, use `#[allow(starknet::invalid_storage_member_types)]`.
 --> lib.cairo:31:22
    pub invalid_map: Map<felt252, InvalidStorageStruct>,
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//! > ==========================================================================

//! > Test allowing invalid storage members.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: false)

//! > cairo_code
use starknet::storage::{Map, Vec};
struct InvalidStorageStruct {}
#[starknet::storage_node]
#[allow(starknet::invalid_storage_member_types)]
struct FullyIgnoredStorage {
    pub ignored_array: Array<felt252>,
    pub ignored_vec: Vec<InvalidStorageStruct>,
    pub ignored_map: Map<felt252, InvalidStorageStruct>,
}

#[starknet::storage_node]
struct PartiallyIgnoredStorage {
    #[allow(starknet::invalid_storage_member_types)]
    pub invalid_array: Array<felt252>,
    #[allow(starknet::invalid_storage_member_types)]
    pub invalid_vec: Vec<InvalidStorageStruct>,
    #[allow(starknet::invalid_storage_member_types)]
    pub invalid_map: Map<felt252, InvalidStorageStruct>,
}

//! > diagnostics

//! > ==========================================================================

//! > Test mixing of allowing storage warnings.

//! > test_runner_name
test_plugin_diagnostics(expect_diagnostics: true)

//! > cairo_code
use starknet::storage::{Map, Vec};

struct InvalidStorageStruct {}

#[starknet::storage_node]
#[allow(starknet::invalid_storage_member_types)]
struct IgnoreInvalidStorageMemberTypes {
    pub a: InvalidStorageStruct,
    #[rename("a")]
    pub b: felt252,
}

#[starknet::storage_node]
#[allow(starknet::colliding_storage_paths)]
struct IgnoreCollidingPaths {
    pub a: InvalidStorageStruct,
    #[rename("a")]
    pub b: felt252,
}

//! > diagnostics
warning: Plugin diagnostic: The path `b` collides with existing path `a`. Fix or add `#[allow(starknet::colliding_storage_paths)]` if intentional.
 --> lib.cairo:10:9
    pub b: felt252,
        ^

warning: Plugin diagnostic: Missing `ValidStorageTypeTrait` for member type. Inference failed with: `Trait has no implementation in context: core::starknet::storage::ValidStorageTypeTrait::<test::InvalidStorageStruct>.`. Possible solutions: implement `Store`, mark type with `#[storage_node]`, or use valid args for `Vec` or `Map` library types. To suppress this warning, use `#[allow(starknet::invalid_storage_member_types)]`.
 --> lib.cairo:16:12
    pub a: InvalidStorageStruct,
           ^^^^^^^^^^^^^^^^^^^^
