diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 3a3d068676..282d5e5add 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -2501,6 +2501,22 @@ fn generate_idl_build(no_docs: bool) -> Result> { }) .collect::>(); + // Verify IDLs are valid + for idl in &idls { + let full_path_account = idl + .accounts + .iter() + .find(|account| account.name.contains("::")); + + if let Some(account) = full_path_account { + return Err(anyhow!( + "Conflicting accounts names are not allowed.\nProgram: {}\nAccount: {}", + idl.name, + account.name + )); + } + } + Ok(idls) } diff --git a/tests/idl/Anchor.toml b/tests/idl/Anchor.toml index ef47c81a96..eed2cd3684 100644 --- a/tests/idl/Anchor.toml +++ b/tests/idl/Anchor.toml @@ -7,6 +7,7 @@ docs = "Docs111111111111111111111111111111111111111" external = "Externa1111111111111111111111111111111111111" generics = "Generics111111111111111111111111111111111111" idl = "id11111111111111111111111111111111111111111" +idl_build_features = "id1Bui1dFeatures111111111111111111111111111" relations_derivation = "Re1ationsDerivation111111111111111111111111" non_existent = { address = "NonExistent11111111111111111111111111111111", idl = "non-existent.json" } numbers_123 = { address = "Numbers111111111111111111111111111111111111", idl = "idls/relations_build.json" } diff --git a/tests/idl/programs/idl-build-features/Cargo.toml b/tests/idl/programs/idl-build-features/Cargo.toml new file mode 100644 index 0000000000..a8577df4cd --- /dev/null +++ b/tests/idl/programs/idl-build-features/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "idl-build-features" +version = "0.1.0" +description = "Created with Anchor" +rust-version = "1.60" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "idl_build_features" + +[features] +no-entrypoint = [] +no-idl = [] +cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] +default = [] + +[dependencies] +anchor-lang = { path = "../../../../lang" } diff --git a/tests/idl/programs/idl-build-features/Xargo.toml b/tests/idl/programs/idl-build-features/Xargo.toml new file mode 100644 index 0000000000..1744f098ae --- /dev/null +++ b/tests/idl/programs/idl-build-features/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/tests/idl/programs/idl-build-features/src/lib.rs b/tests/idl/programs/idl-build-features/src/lib.rs new file mode 100644 index 0000000000..939df83eb8 --- /dev/null +++ b/tests/idl/programs/idl-build-features/src/lib.rs @@ -0,0 +1,47 @@ +use anchor_lang::prelude::*; + +declare_id!("id1Bui1dFeatures111111111111111111111111111"); + +#[program] +pub mod idl_build_features { + use super::*; + + pub fn full_path( + ctx: Context, + my_struct: MyStruct, + some_module_my_struct: some_module::MyStruct, + ) -> Result<()> { + ctx.accounts.account.my_struct = my_struct; + ctx.accounts.account.some_module_my_struct = some_module_my_struct; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct FullPath<'info> { + #[account(zero)] + pub account: Account<'info, FullPathAccount>, +} + +#[account] +pub struct FullPathAccount { + pub my_struct: MyStruct, + pub some_module_my_struct: some_module::MyStruct, +} + +mod some_module { + use super::*; + + #[derive(AnchorSerialize, AnchorDeserialize, Clone)] + pub struct MyStruct { + pub data: u8, + } +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct MyStruct { + pub u8: u8, + pub u16: u16, + pub u32: u32, + pub u64: u64, +} diff --git a/tests/idl/tests/idl-build-features.ts b/tests/idl/tests/idl-build-features.ts new file mode 100644 index 0000000000..4abdb13d34 --- /dev/null +++ b/tests/idl/tests/idl-build-features.ts @@ -0,0 +1,35 @@ +import * as anchor from "@coral-xyz/anchor"; +import { assert } from "chai"; + +import { IdlBuildFeatures } from "../target/types/idl_build_features"; + +describe("idl-build features", () => { + anchor.setProvider(anchor.AnchorProvider.env()); + const program = anchor.workspace + .idlBuildFeatures as anchor.Program; + + it("Can use full module path types", async () => { + const kp = anchor.web3.Keypair.generate(); + + const outerMyStructArg = { u8: 1, u16: 2, u32: 3, u64: new anchor.BN(4) }; + const someModuleMyStructArg = { data: 5 }; + + await program.methods + .fullPath(outerMyStructArg, someModuleMyStructArg) + .accounts({ account: kp.publicKey }) + .preInstructions([ + await program.account.fullPathAccount.createInstruction(kp), + ]) + .signers([kp]) + .rpc(); + + const fullPathAccount = await program.account.fullPathAccount.fetch( + kp.publicKey + ); + assert.strictEqual(fullPathAccount.myStruct.u8, outerMyStructArg.u8); + assert.strictEqual(fullPathAccount.myStruct.u16, outerMyStructArg.u16); + assert.strictEqual(fullPathAccount.myStruct.u32, outerMyStructArg.u32); + assert(fullPathAccount.myStruct.u64.eq(outerMyStructArg.u64)); + assert.deepEqual(fullPathAccount.someModuleMyStruct, someModuleMyStructArg); + }); +});