Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lang: allow the cfg attribute above the instructions #2339

Merged
merged 9 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The minor version will be incremented upon a breaking change and the patch versi

### Fixes

- lang: Allow the `cfg` attribute above the instructions ([#2339](https://github.com/coral-xyz/anchor/pull/2339)).
- ts: Packages no longer depend on `assert` ([#2535](https://github.com/coral-xyz/anchor/pull/2535)).
- lang: Support for `const` in the `InitSpace` macro ([#2555](https://github.com/coral-xyz/anchor/pull/2555)).
- cli: Support workspace inheritence ([#2570](https://github.com/coral-xyz/anchor/pull/2570)).
Expand Down
7 changes: 4 additions & 3 deletions lang/syn/src/codegen/program/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use heck::SnakeCase;
use quote::quote;

pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let mut accounts = std::collections::HashSet::new();
let mut accounts = std::collections::BTreeMap::new();
Aursen marked this conversation as resolved.
Show resolved Hide resolved

// Go through instruction accounts.
for ix in &program.ixs {
Expand All @@ -13,15 +13,16 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
"__client_accounts_{}",
anchor_ident.to_string().to_snake_case()
);
accounts.insert(macro_name);
accounts.insert(macro_name, ix.cfgs.as_slice());
}

// Build the tokens from all accounts
let account_structs: Vec<proc_macro2::TokenStream> = accounts
.iter()
.map(|macro_name: &String| {
.map(|(macro_name, cfgs)| {
let macro_name: proc_macro2::TokenStream = macro_name.parse().unwrap();
quote! {
#(#cfgs)*
pub use crate::#macro_name::*;
}
})
Expand Down
10 changes: 7 additions & 3 deletions lang/syn/src/codegen/program/cpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let method_name = &ix.ident;
let args: Vec<&syn::PatType> = ix.args.iter().map(|arg| &arg.raw_arg).collect();
let name = &ix.raw_method.sig.ident.to_string();
let ix_cfgs = &ix.cfgs;
let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, name);
let sighash_tts: proc_macro2::TokenStream =
format!("{sighash_arr:?}").parse().unwrap();
Expand All @@ -28,6 +29,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
};

quote! {
#(#ix_cfgs)*
pub fn #method_name<'a, 'b, 'c, 'info>(
ctx: anchor_lang::context::CpiContext<'a, 'b, 'c, 'info, #accounts_ident<'info>>,
#(#args),*
Expand Down Expand Up @@ -91,25 +93,27 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
}

pub fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
let mut accounts = std::collections::HashSet::new();
let mut accounts = std::collections::BTreeMap::new();

// Go through instruction accounts.
for ix in &program.ixs {
let anchor_ident = &ix.anchor_ident;
let cfgs = &ix.cfgs;
// TODO: move to fn and share with accounts.rs.
let macro_name = format!(
"__cpi_client_accounts_{}",
anchor_ident.to_string().to_snake_case()
);
accounts.insert(macro_name);
accounts.insert(macro_name, cfgs.as_slice());
}

// Build the tokens from all accounts
let account_structs: Vec<proc_macro2::TokenStream> = accounts
.iter()
.map(|macro_name: &String| {
.map(|(macro_name, cfgs)| {
let macro_name: proc_macro2::TokenStream = macro_name.parse().unwrap();
quote! {
#(#cfgs)*
pub use crate::#macro_name::*;
}
})
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/codegen/program/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
.iter()
.map(|ix| {
let ix_method_name = &ix.raw_method.sig.ident;
let ix_cfgs = &ix.cfgs;
let ix_name_camel: proc_macro2::TokenStream = ix_method_name
.to_string()
.as_str()
Expand All @@ -17,6 +18,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
.expect("Failed to parse ix method name in camel as `TokenStream`");

quote! {
#(#ix_cfgs)*
instruction::#ix_name_camel::DISCRIMINATOR => {
__private::__global::#ix_method_name(
program_id,
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/codegen/program/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let variant_arm = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
let ix_name_log = format!("Instruction: {ix_name}");
let ret_type = &ix.returns.ty.to_token_stream();
let cfgs = &ix.cfgs;
let maybe_set_return_data = match ret_type.to_string().as_str() {
"()" => quote! {},
_ => quote! {
anchor_lang::solana_program::program::set_return_data(&result.try_to_vec().unwrap());
},
};
quote! {
#(#cfgs)*
#[inline(never)]
pub fn #ix_method_name<'info>(
__program_id: &Pubkey,
Expand Down
6 changes: 6 additions & 0 deletions lang/syn/src/codegen/program/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
.iter()
.map(|ix| {
let name = &ix.raw_method.sig.ident.to_string();
let ix_cfgs = &ix.cfgs;
let ix_name_camel =
proc_macro2::Ident::new(&name.to_camel_case(), ix.raw_method.sig.ident.span());
let raw_args: Vec<proc_macro2::TokenStream> = ix
Expand All @@ -26,10 +27,13 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let sighash_tts: proc_macro2::TokenStream =
format!("{sighash_arr:?}").parse().unwrap();
quote! {
#(#ix_cfgs)*
impl anchor_lang::Discriminator for #ix_name_camel {
const DISCRIMINATOR: [u8; 8] = #sighash_tts;
}
#(#ix_cfgs)*
impl anchor_lang::InstructionData for #ix_name_camel {}
#(#ix_cfgs)*
impl anchor_lang::Owner for #ix_name_camel {
fn owner() -> Pubkey {
ID
Expand All @@ -40,6 +44,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
// If no args, output a "unit" variant instead of a struct variant.
if ix.args.is_empty() {
quote! {
#(#ix_cfgs)*
/// Instruction.
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct #ix_name_camel;
Expand All @@ -48,6 +53,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
}
} else {
quote! {
#(#ix_cfgs)*
/// Instruction.
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct #ix_name_camel {
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult}
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::Attribute;
use syn::{
Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, LitInt, PatType, Token, Type,
TypePath,
Expand Down Expand Up @@ -62,6 +63,7 @@ pub struct Ix {
pub raw_method: ItemFn,
pub ident: Ident,
pub docs: Option<Vec<String>>,
pub cfgs: Vec<Attribute>,
pub args: Vec<IxArg>,
pub returns: IxReturn,
// The ident for the struct deriving Accounts.
Expand Down
20 changes: 18 additions & 2 deletions lang/syn/src/parser/program/instructions.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::parser::docs;
use crate::parser::program::ctx_accounts_ident;
use crate::{FallbackFn, Ix, IxArg, IxReturn};
use syn::parse::{Error as ParseError, Result as ParseResult};
use syn::spanned::Spanned;
use syn::{
parse::{Error as ParseError, Result as ParseResult},
spanned::Spanned,
Attribute,
};

// Parse all non-state ix handlers from the program mod definition.
pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec<Ix>, Option<FallbackFn>)> {
Expand All @@ -25,12 +28,14 @@ pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec<Ix>, Option<Fallbac
.map(|method: &syn::ItemFn| {
let (ctx, args) = parse_args(method)?;
let docs = docs::parse(&method.attrs);
let cfgs = parse_cfg(method);
let returns = parse_return(method)?;
let anchor_ident = ctx_accounts_ident(&ctx.raw_arg)?;
Ok(Ix {
raw_method: method.clone(),
ident: method.sig.ident.clone(),
docs,
cfgs,
args,
anchor_ident,
returns,
Expand Down Expand Up @@ -129,3 +134,14 @@ pub fn parse_return(method: &syn::ItemFn) -> ParseResult<IxReturn> {
)),
}
}

fn parse_cfg(method: &syn::ItemFn) -> Vec<Attribute> {
method
.attrs
.iter()
.filter_map(|attr| match attr.path.is_ident("cfg") {
true => Some(attr.to_owned()),
false => None,
})
.collect()
}
1 change: 1 addition & 0 deletions tests/misc/programs/misc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ no-entrypoint = []
no-idl = []
cpi = ["no-entrypoint"]
default = []
my-feature = []

[dependencies]
anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
Expand Down
4 changes: 4 additions & 0 deletions tests/misc/programs/misc/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,3 +751,7 @@ pub struct TestUsedIdentifiers<'info> {
/// CHECK: ignore
pub test4: AccountInfo<'info>,
}

#[cfg(feature = "my-feature")]
#[derive(Accounts)]
pub struct Empty {}
5 changes: 5 additions & 0 deletions tests/misc/programs/misc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,9 @@ pub mod misc {
) -> Result<()> {
Ok(())
}

#[cfg(feature = "my-feature")]
pub fn only_my_feature(_ctx: Context<Empty>) -> Result<()> {
Ok(())
}
}
Loading