diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 955a31b..0153faf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,20 +15,20 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Cache cargo registry, git, bin, and target + - name: Cache cargo registry, git, bin, and target dirs uses: actions/cache@v4 with: path: | - ~/.cargo/bin ~/.cargo/registry ~/.cargo/git + ~/.cargo/bin target tests/target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install nightly + rustfmt run: rustup update nightly && rustup default nightly && rustup component add rustfmt clippy - name: Install dylint - run: cargo install --locked cargo-dylint@5.0.0 dylint-link@5.0.0 + run: cargo install --locked --force cargo-dylint@5.0.0 dylint-link@5.0.0 - name: Format run: cargo fmt --check - name: Build diff --git a/Cargo.lock b/Cargo.lock index a2f6de0..85b049d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -791,6 +791,16 @@ dependencies = [ "dylint_testing", ] +[[package]] +name = "missing_mut_constraint" +version = "0.1.0" +dependencies = [ + "anchor-lints-utils", + "clippy_utils", + "dylint_linting", + "dylint_testing", +] + [[package]] name = "missing_owner_check" version = "0.1.0" diff --git a/README.md b/README.md index cf616bc..fcfc7f3 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ cargo install cargo-dylint dylint-link | [`direct_lamport_cpi_dos`](lints/direct_lamport_cpi_dos) | | [`overconstrained_seed_account`](lints/overconstrained_seed_account) | | [`unsafe_pyth_price_account`](lints/unsafe_pyth_price_account) | +| [`missing_mut_constraint`](lints/missing_mut_constraint) | ## Usage @@ -68,4 +69,5 @@ cargo test ata_should_use_init_if_needed_tests cargo test direct_lamport_cpi_dos_tests cargo test overconstrained_seed_account_tests cargo test unsafe_pyth_price_account_tests +cargo test missing_mut_constraint_tests ``` diff --git a/anchor-lints-utils/src/mir_analyzer/account_extraction.rs b/anchor-lints-utils/src/mir_analyzer/account_extraction.rs index 43df17b..680f919 100644 --- a/anchor-lints-utils/src/mir_analyzer/account_extraction.rs +++ b/anchor-lints-utils/src/mir_analyzer/account_extraction.rs @@ -1,7 +1,7 @@ use clippy_utils::{source::HasSession, ty::is_type_diagnostic_item}; use rustc_middle::{ - mir::{HasLocalDecls, Local}, - ty::TyKind, + mir::{HasLocalDecls, Local, Place, Rvalue}, + ty::{Mutability, TyKind}, }; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -183,6 +183,43 @@ impl<'cx, 'tcx> MirAnalyzer<'cx, 'tcx> { ); account_name_and_locals.first().cloned() } + + /// Extracts the account name from a place or rvalue + pub fn account_name_from_place_or_rvalue( + &self, + place: &Place<'_>, + rvalue: &Rvalue<'_>, + ) -> Option { + let base_local = place.local; + let resolved = self.resolve_to_original_local(base_local, &mut HashSet::new()); + if let Some(acc) = self.extract_account_name_from_local(&resolved, true) { + let name = acc + .account_name + .split('.') + .next() + .unwrap_or(&acc.account_name) + .to_string(); + return Some(name); + } + + if let Rvalue::Ref(_, borrow_kind, ref_place) = rvalue + && borrow_kind.mutability() == Mutability::Mut + { + let base = ref_place.local; + let resolved = self.resolve_to_original_local(base, &mut HashSet::new()); + if let Some(acc) = self.extract_account_name_from_local(&resolved, true) { + let name = acc + .account_name + .split('.') + .next() + .unwrap_or(&acc.account_name) + .to_string(); + return Some(name); + } + } + + None + } } fn push_account_name_and_return( diff --git a/lints/arbitrary_cpi_call/tests/test_program/Cargo.toml b/lints/arbitrary_cpi_call/tests/test_program/Cargo.toml index 693b456..d226a32 100644 --- a/lints/arbitrary_cpi_call/tests/test_program/Cargo.toml +++ b/lints/arbitrary_cpi_call/tests/test_program/Cargo.toml @@ -9,5 +9,5 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/ata_should_use_init_if_needed/tests/test_program/Cargo.toml b/lints/ata_should_use_init_if_needed/tests/test_program/Cargo.toml index 0e6a5ea..5e99e5a 100644 --- a/lints/ata_should_use_init_if_needed/tests/test_program/Cargo.toml +++ b/lints/ata_should_use_init_if_needed/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843", features = ["init-if-needed"] } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true, features = ["init-if-needed"] } +anchor-spl = { workspace = true } diff --git a/lints/cpi_no_result/tests/test_program/Cargo.toml b/lints/cpi_no_result/tests/test_program/Cargo.toml index a10b8ea..717c1b7 100644 --- a/lints/cpi_no_result/tests/test_program/Cargo.toml +++ b/lints/cpi_no_result/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/direct_lamport_cpi_dos/tests/test_program/Cargo.toml b/lints/direct_lamport_cpi_dos/tests/test_program/Cargo.toml index 4624e15..bf2eed0 100644 --- a/lints/direct_lamport_cpi_dos/tests/test_program/Cargo.toml +++ b/lints/direct_lamport_cpi_dos/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/duplicate_mutable_accounts/tests/test_program/Cargo.toml b/lints/duplicate_mutable_accounts/tests/test_program/Cargo.toml index f91eacb..686a416 100644 --- a/lints/duplicate_mutable_accounts/tests/test_program/Cargo.toml +++ b/lints/duplicate_mutable_accounts/tests/test_program/Cargo.toml @@ -9,5 +9,5 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/missing_account_field_init/tests/test_program/Cargo.toml b/lints/missing_account_field_init/tests/test_program/Cargo.toml index f85cacc..e0cb761 100644 --- a/lints/missing_account_field_init/tests/test_program/Cargo.toml +++ b/lints/missing_account_field_init/tests/test_program/Cargo.toml @@ -9,7 +9,7 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/missing_account_reload/tests/test_program/Cargo.toml b/lints/missing_account_reload/tests/test_program/Cargo.toml index ad0bd3c..f6f1223 100644 --- a/lints/missing_account_reload/tests/test_program/Cargo.toml +++ b/lints/missing_account_reload/tests/test_program/Cargo.toml @@ -9,4 +9,4 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } diff --git a/lints/missing_mut_constraint/Cargo.toml b/lints/missing_mut_constraint/Cargo.toml new file mode 100644 index 0000000..c2c4d7e --- /dev/null +++ b/lints/missing_mut_constraint/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "missing_mut_constraint" +version.workspace = true +edition.workspace = true +publish = false +description = "Detects accounts that are mutated in the instruction but not declared with #[account(mut)]" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anchor-lints-utils.workspace = true +clippy_utils.workspace = true +dylint_linting.workspace = true + +[dev-dependencies] +dylint_testing.workspace = true + +[package.metadata.rust-analyzer] +rustc_private = true + +[lints] +workspace = true \ No newline at end of file diff --git a/lints/missing_mut_constraint/README.md b/lints/missing_mut_constraint/README.md new file mode 100644 index 0000000..2bf26f4 --- /dev/null +++ b/lints/missing_mut_constraint/README.md @@ -0,0 +1,36 @@ +# `missing_mut_constraint` + +### What it does +Detects when an account is mutated in the instruction body but not declared with `#[account(mut)]` in the Anchor accounts struct. + +### Why is this bad? +Mutating an account without the `mut` constraint can cause the runtime to reject the transaction or behave unexpectedly, because the account was not marked as writable. + +### Example + +**Bad:** account mutated without `#[account(mut)]` +```rust +#[derive(Accounts)] +pub struct Update<'info> { + pub vault: Account<'info, Vault>, // missing #[account(mut)] +} + +pub fn update(ctx: Context) -> Result<()> { + ctx.accounts.vault.amount += 1; // mutation + Ok(()) +} +``` + +**Good:** account has `#[account(mut)]` when mutated +```rust +#[derive(Accounts)] +pub struct Update<'info> { + #[account(mut)] + pub vault: Account<'info, Vault>, +} + +pub fn update(ctx: Context) -> Result<()> { + ctx.accounts.vault.amount += 1; + Ok(()) +} +``` \ No newline at end of file diff --git a/lints/missing_mut_constraint/src/lib.rs b/lints/missing_mut_constraint/src/lib.rs new file mode 100644 index 0000000..11be362 --- /dev/null +++ b/lints/missing_mut_constraint/src/lib.rs @@ -0,0 +1,163 @@ +#![feature(rustc_private)] +#![warn(unused_extern_crates)] +#![feature(box_patterns)] + +extern crate rustc_hir; +extern crate rustc_middle; +extern crate rustc_span; + +use anchor_lints_utils::{ + mir_analyzer::{AnchorContextInfo, MirAnalyzer}, + utils::{extract_account_constraints, should_skip_function}, +}; +use clippy_utils::diagnostics::span_lint; + +use rustc_hir::{Body as HirBody, FnDecl, def_id::LocalDefId, intravisit::FnKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::{mir::StatementKind, ty::TyKind}; +use rustc_span::Span; + +use std::collections::{HashMap, HashSet}; + +dylint_linting::impl_late_lint! { + /// ### What it does + /// Detects when an account is mutated in the instruction body but not declared + /// with `#[account(mut)]` in the Anchor accounts struct. + /// + /// ### Why is this bad? + /// Mutating an account without the `mut` constraint can cause the runtime to + /// reject the transaction or behave unexpectedly, as the account was not + /// marked as writable. + /// + /// ### Example + /// ```rust + /// #[derive(Accounts)] + /// pub struct Update<'info> { + /// pub vault: Account<'info, Vault>, // missing #[account(mut)] + /// } + /// pub fn update(ctx: Context) -> Result<()> { + /// ctx.accounts.vault.amount += 1; // mutation + /// Ok(()) + /// } + /// ``` + /// + /// ### Good + /// ```rust + /// #[derive(Accounts)] + /// pub struct Update<'info> { + /// #[account(mut)] + /// pub vault: Account<'info, Vault>, + /// } + /// ``` + pub MISSING_MUT_CONSTRAINT, + Warn, + "account is mutated but missing #[account(mut)]", + MissingMutConstraint +} + +#[derive(Default)] +pub struct MissingMutConstraint; + +struct AccountMutability { + span: Span, + mutable: bool, +} + +impl<'tcx> LateLintPass<'tcx> for MissingMutConstraint { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _kind: FnKind<'tcx>, + _: &FnDecl<'tcx>, + body: &HirBody<'tcx>, + main_fn_span: Span, + def_id: LocalDefId, + ) { + if should_skip_function(cx, main_fn_span, def_id) { + return; + } + + let mut mir_analyzer = MirAnalyzer::new(cx, body, def_id); + anchor_lints_utils::utils::ensure_anchor_context_initialized(&mut mir_analyzer, body); + + // Analyze functions that take Anchor context + let Some(anchor_context_info) = mir_analyzer.anchor_context_info.as_ref() else { + return; + }; + + analyze_missing_mut_constraint(cx, &mir_analyzer, anchor_context_info); + } +} + +fn analyze_missing_mut_constraint<'cx, 'tcx>( + cx: &'cx LateContext<'tcx>, + mir_analyzer: &MirAnalyzer<'cx, 'tcx>, + anchor_context_info: &AnchorContextInfo<'tcx>, +) { + let accounts_struct_ty = &anchor_context_info.anchor_context_account_type; + let TyKind::Adt(adt_def, _generics) = accounts_struct_ty.kind() else { + return; + }; + + if !adt_def.is_struct() && !adt_def.is_union() { + return; + } + + let variant = adt_def.non_enum_variant(); + let mut account_mutability: HashMap = HashMap::new(); + + for field in &variant.fields { + let account_name = field.ident(cx.tcx).to_string(); + let account_span = cx.tcx.def_span(field.did); + let constraints = extract_account_constraints(cx, field); + account_mutability.insert( + account_name, + AccountMutability { + span: account_span, + mutable: constraints.mutable, + }, + ); + } + + let mutated_accounts = collect_mutated_accounts(mir_analyzer); + let mut visited = HashSet::new(); + + for account_name in mutated_accounts { + if visited.contains(&account_name) { + continue; + } + visited.insert(account_name.clone()); + + if let Some(info) = account_mutability.get(&account_name) + && !info.mutable + { + span_lint( + cx, + MISSING_MUT_CONSTRAINT, + info.span, + format!( + "account `{}` is mutated in the instruction but is not declared with `#[account(mut)]`", + account_name + ), + ); + } + } +} + +/// Collects the accounts that are mutated in the instruction body +fn collect_mutated_accounts<'cx, 'tcx>(mir_analyzer: &MirAnalyzer<'cx, 'tcx>) -> HashSet { + let mut mutated = HashSet::new(); + + for (_bb, bbdata) in mir_analyzer.mir.basic_blocks.iter_enumerated() { + for stmt in &bbdata.statements { + if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind + && let Some(account_name) = + mir_analyzer.account_name_from_place_or_rvalue(place, rvalue) + { + mutated.insert(account_name); + } + } + } + + mutated +} diff --git a/lints/missing_mut_constraint/tests/test_program/Cargo.toml b/lints/missing_mut_constraint/tests/test_program/Cargo.toml new file mode 100644 index 0000000..6acb062 --- /dev/null +++ b/lints/missing_mut_constraint/tests/test_program/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "missing_mut_constraint_test_program" +version = "0.1.0" +edition = "2021" +workspace = "../../../../tests" + + +[lib] +crate-type = ["cdylib"] + +[dependencies] +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } \ No newline at end of file diff --git a/lints/missing_mut_constraint/tests/test_program/src/lib.rs b/lints/missing_mut_constraint/tests/test_program/src/lib.rs new file mode 100644 index 0000000..cfa144c --- /dev/null +++ b/lints/missing_mut_constraint/tests/test_program/src/lib.rs @@ -0,0 +1,76 @@ +use anchor_lang::prelude::*; + +declare_id!("11111111111111111111111111111111"); + +#[program] +pub mod missing_mut_constraint { + use super::*; + + // Bad: Account (vault) is mutated but not declared with #[account(mut)] + pub fn update_bad(ctx: Context) -> Result<()> { + ctx.accounts.vault.amount += 1; + Ok(()) + } + + // Good: Account (vault) has #[account(mut)] + pub fn update_good(ctx: Context) -> Result<()> { + ctx.accounts.vault.amount += 1; + Ok(()) + } + + // Good: Account (vault) is only read, no mut needed + pub fn read_only(ctx: Context) -> Result<()> { + let _ = ctx.accounts.vault.amount; + Ok(()) + } + + // Bad: Account (treasury) is mutated but not declared with #[account(mut)] (Account (vault) has mut) + pub fn transfer_bad(ctx: Context) -> Result<()> { + ctx.accounts.vault.amount -= 10; + ctx.accounts.treasury.amount += 10; + Ok(()) + } + + // Good: lamport mutation with #[account(mut)] on payer + pub fn pay_lamports(ctx: Context, amount: u64) -> Result<()> { + **ctx.accounts.payer.lamports.borrow_mut() -= amount; + **ctx.accounts.recipient.lamports.borrow_mut() += amount; + Ok(()) + } +} + +#[account] +pub struct Vault { + pub amount: u64, +} + +#[derive(Accounts)] +pub struct UpdateBad<'info> { + pub vault: Account<'info, Vault>, // [missing_mut_constraint] +} + +#[derive(Accounts)] +pub struct UpdateGood<'info> { + #[account(mut)] + pub vault: Account<'info, Vault>, +} + +#[derive(Accounts)] +pub struct ReadOnly<'info> { + pub vault: Account<'info, Vault>, +} + +#[derive(Accounts)] +pub struct TransferBad<'info> { + #[account(mut)] + pub vault: Account<'info, Vault>, + pub treasury: Account<'info, Vault>, // [missing_mut_constraint] +} + +#[derive(Accounts)] +pub struct PayLamports<'info> { + #[account(mut)] + pub payer: AccountInfo<'info>, + #[account(mut)] + pub recipient: AccountInfo<'info>, +} \ No newline at end of file diff --git a/lints/missing_owner_check/tests/test_program/Cargo.toml b/lints/missing_owner_check/tests/test_program/Cargo.toml index 73f7c99..99d8622 100644 --- a/lints/missing_owner_check/tests/test_program/Cargo.toml +++ b/lints/missing_owner_check/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } mpl-token-metadata = "5.1.2-alpha.1" diff --git a/lints/missing_signer_validation/tests/test_program/Cargo.toml b/lints/missing_signer_validation/tests/test_program/Cargo.toml index b8105b0..3a5353e 100644 --- a/lints/missing_signer_validation/tests/test_program/Cargo.toml +++ b/lints/missing_signer_validation/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor", rev = "939b843" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/overconstrained_seed_account/tests/test_program/Cargo.toml b/lints/overconstrained_seed_account/tests/test_program/Cargo.toml index 81837a8..1ad8461 100644 --- a/lints/overconstrained_seed_account/tests/test_program/Cargo.toml +++ b/lints/overconstrained_seed_account/tests/test_program/Cargo.toml @@ -9,6 +9,6 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/lints/pda_signer_account_overlap/tests/test_program/Cargo.toml b/lints/pda_signer_account_overlap/tests/test_program/Cargo.toml index f8a188a..8807277 100644 --- a/lints/pda_signer_account_overlap/tests/test_program/Cargo.toml +++ b/lints/pda_signer_account_overlap/tests/test_program/Cargo.toml @@ -9,5 +9,5 @@ workspace = "../../../../tests" crate-type = ["cdylib"] [dependencies] -anchor-lang = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } -anchor-spl = { git = "https://github.com/jamie-osec/anchor.git", branch = "anchor-lint" } +anchor-lang = { workspace = true } +anchor-spl = { workspace = true } diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 360dffb..d31c05a 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -71,20 +71,9 @@ dependencies = [ [[package]] name = "anchor-attribute-access-control" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-access-control" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "proc-macro2", "quote", "syn 1.0.109", @@ -106,20 +95,9 @@ dependencies = [ [[package]] name = "anchor-attribute-account" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-account" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "proc-macro2", "quote", "syn 1.0.109", @@ -139,19 +117,9 @@ dependencies = [ [[package]] name = "anchor-attribute-constant" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-constant" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "quote", "syn 1.0.109", ] @@ -170,19 +138,9 @@ dependencies = [ [[package]] name = "anchor-attribute-error" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-error" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "quote", "syn 1.0.109", ] @@ -202,20 +160,9 @@ dependencies = [ [[package]] name = "anchor-attribute-event" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-event" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "proc-macro2", "quote", "syn 1.0.109", @@ -241,25 +188,10 @@ dependencies = [ [[package]] name = "anchor-attribute-program" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-lang-idl 0.1.2 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anyhow", - "heck", - "proc-macro2", - "quote", - "serde_json", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-program" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-lang-idl 0.1.2 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang-idl 0.1.2 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "anyhow", "heck", "proc-macro2", @@ -282,19 +214,9 @@ dependencies = [ [[package]] name = "anchor-derive-accounts" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-accounts" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "quote", "syn 1.0.109", ] @@ -315,20 +237,9 @@ dependencies = [ [[package]] name = "anchor-derive-serde" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-serde" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-syn 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "proc-macro2", "quote", "syn 1.0.109", @@ -348,17 +259,7 @@ dependencies = [ [[package]] name = "anchor-derive-space" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-space" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ "proc-macro2", "quote", @@ -410,60 +311,17 @@ dependencies = [ [[package]] name = "anchor-lang" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-attribute-access-control 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-attribute-account 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-attribute-constant 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-attribute-error 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-attribute-event 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-attribute-program 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-derive-accounts 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-derive-serde 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-derive-space 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "base64 0.21.7", - "bincode", - "borsh 1.6.0", - "bytemuck", - "const-crypto", - "solana-account-info 3.1.0", - "solana-clock 3.0.0", - "solana-cpi 3.1.0", - "solana-define-syscall 3.0.0", - "solana-feature-gate-interface 3.1.0", - "solana-instruction 3.1.0", - "solana-instructions-sysvar 3.0.0", - "solana-invoke 0.5.0", - "solana-loader-v3-interface 6.1.0", - "solana-msg 3.0.0", - "solana-program-entrypoint 3.1.1", - "solana-program-error 3.0.0", - "solana-program-memory 3.1.0", - "solana-program-option 3.0.0", - "solana-program-pack 3.0.0", - "solana-pubkey 4.0.0", - "solana-sdk-ids 3.1.0", - "solana-stake-interface 2.0.2", - "solana-system-interface 2.0.0", - "solana-sysvar 3.0.0", - "solana-sysvar-id 3.1.0", - "thiserror 1.0.69", -] - -[[package]] -name = "anchor-lang" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-attribute-access-control 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-attribute-account 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-attribute-constant 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-attribute-error 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-attribute-event 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-attribute-program 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-derive-accounts 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-derive-serde 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-derive-space 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +dependencies = [ + "anchor-attribute-access-control 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-attribute-account 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-attribute-constant 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-attribute-error 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-attribute-event 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-attribute-program 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-derive-accounts 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-derive-serde 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-derive-space 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "base64 0.21.7", "bincode", "borsh 1.6.0", @@ -510,22 +368,9 @@ dependencies = [ [[package]] name = "anchor-lang-idl" version = "0.1.2" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-lang-idl-spec 0.1.0 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anyhow", - "heck", - "serde", - "serde_json", - "sha2 0.10.9", -] - -[[package]] -name = "anchor-lang-idl" -version = "0.1.2" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-lang-idl-spec 0.1.0 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang-idl-spec 0.1.0 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "anyhow", "heck", "serde", @@ -546,16 +391,7 @@ dependencies = [ [[package]] name = "anchor-lang-idl-spec" version = "0.1.0" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anyhow", - "serde", -] - -[[package]] -name = "anchor-lang-idl-spec" -version = "0.1.0" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ "anyhow", "serde", @@ -579,23 +415,9 @@ dependencies = [ [[package]] name = "anchor-spl" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "spl-associated-token-account-interface", - "spl-pod 0.7.1", - "spl-token-2022-interface", - "spl-token-group-interface 0.7.1", - "spl-token-interface", - "spl-token-metadata-interface 0.8.0", -] - -[[package]] -name = "anchor-spl" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "spl-associated-token-account-interface", "spl-pod 0.7.1", "spl-token-2022-interface", @@ -625,24 +447,7 @@ dependencies = [ [[package]] name = "anchor-syn" version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint#939b843af4c330d37be45b34e5971e0d1a10c07e" -dependencies = [ - "anyhow", - "bs58", - "heck", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2 0.10.9", - "syn 1.0.109", - "thiserror 1.0.69", -] - -[[package]] -name = "anchor-syn" -version = "0.32.1" -source = "git+https://github.com/jamie-osec/anchor?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" +source = "git+https://github.com/jamie-osec/anchor.git?rev=939b843#939b843af4c330d37be45b34e5971e0d1a10c07e" dependencies = [ "anyhow", "bs58", @@ -666,8 +471,8 @@ checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" name = "arbitrary_cpi_call_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -686,8 +491,8 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" name = "ata_should_use_init_if_needed_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -971,8 +776,8 @@ checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" name = "cpi_no_result_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -1127,16 +932,16 @@ dependencies = [ name = "direct_lamport_cpi_dos_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] name = "duplicate_mutable_accounts_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -1578,23 +1383,31 @@ dependencies = [ name = "missing_account_field_init_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] name = "missing_account_reload_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", +] + +[[package]] +name = "missing_mut_constraint_test_program" +version = "0.1.0" +dependencies = [ + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] name = "missing_owner_check_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", "mpl-token-metadata", ] @@ -1602,8 +1415,8 @@ dependencies = [ name = "missing_signer_validation_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor?rev=939b843)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -1754,8 +1567,8 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" name = "overconstrained_seed_account_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] @@ -1794,8 +1607,8 @@ dependencies = [ name = "pda_signer_account_overlap_test_program" version = "0.1.0" dependencies = [ - "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", - "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?branch=anchor-lint)", + "anchor-lang 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", + "anchor-spl 0.32.1 (git+https://github.com/jamie-osec/anchor.git?rev=939b843)", ] [[package]] diff --git a/tests/Cargo.toml b/tests/Cargo.toml index eb0a2d3..7b8312d 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -3,3 +3,7 @@ [workspace] members = ["../lints/*/tests/test_program"] resolver = "2" + +[workspace.dependencies] +anchor-lang = { git = "https://github.com/jamie-osec/anchor.git", rev = "939b843" } +anchor-spl = { git = "https://github.com/jamie-osec/anchor.git", rev = "939b843" } diff --git a/tests/lint_tests.rs b/tests/lint_tests.rs index 78db7a6..7bb334c 100644 --- a/tests/lint_tests.rs +++ b/tests/lint_tests.rs @@ -84,6 +84,11 @@ async fn unsafe_pyth_price_account_tests() -> Result<()> { run_unsafe_pyth_price_account_tests().await } +#[tokio::test] +async fn missing_mut_constraint_tests() -> Result<()> { + run_missing_mut_constraint_tests().await +} + async fn run_missing_account_reload_tests() -> Result<()> { let lint_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let test_program = lint_root.join("lints/missing_account_reload/tests/test_program"); @@ -425,6 +430,17 @@ async fn run_unsafe_pyth_price_account_tests() -> Result<()> { .await } +async fn run_missing_mut_constraint_tests() -> Result<()> { + run_standard_lint_test( + "missing_mut_constraint", + &["missing_mut_constraint"], + "warning: account", + Some("is mutated in the instruction but is not declared with `#[account(mut)]`"), + "missing_mut_constraint", + ) + .await +} + // Recursively find all .rs files fn find_rust_files(dir: &Path) -> std::io::Result> { let mut files = Vec::new();