mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 16:47:57 +00:00
Improve spans of pallet macro (#7830)
* fix spans * convert name to snake case
This commit is contained in:
committed by
GitHub
parent
d2ac8bd941
commit
66a9093fa3
@@ -24,9 +24,9 @@ use syn::spanned::Spanned;
|
||||
pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let frame_support = &def.frame_support;
|
||||
let frame_system = &def.frame_system;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_decl_bounded_gen = &def.type_decl_bounded_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(def.call.attr_span);
|
||||
let type_decl_bounded_gen = &def.type_decl_bounded_generics(def.call.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(def.call.attr_span);
|
||||
let call_ident = syn::Ident::new("Call", def.call.attr_span.clone());
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
let where_clause = &def.call.where_clause;
|
||||
@@ -61,7 +61,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
method.args.iter()
|
||||
.map(|(is_compact, _, type_)| {
|
||||
let final_type = if *is_compact {
|
||||
quote::quote!(Compact<#type_>)
|
||||
quote::quote_spanned!(type_.span() => Compact<#type_>)
|
||||
} else {
|
||||
quote::quote!(#type_)
|
||||
};
|
||||
|
||||
@@ -33,9 +33,9 @@ struct ConstDef {
|
||||
/// * Impl fn module_constant_metadata for pallet.
|
||||
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let frame_support = &def.frame_support;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_decl_gen = &def.type_decl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_decl_gen = &def.type_decl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// * impl various trait on Error
|
||||
/// * impl ModuleErrorMetadata for Error
|
||||
@@ -27,13 +26,11 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
return Default::default()
|
||||
};
|
||||
|
||||
let error_item_span =
|
||||
def.item.content.as_mut().expect("Checked by def parser").1[error.index].span();
|
||||
let error_ident = &error.error;
|
||||
let frame_support = &def.frame_support;
|
||||
let frame_system = &def.frame_system;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(error.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(error.attr_span);
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
let phantom_variant: syn::Variant = syn::parse_quote!(
|
||||
@@ -45,18 +42,20 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
);
|
||||
|
||||
let as_u8_matches = error.variants.iter().enumerate()
|
||||
.map(|(i, (variant, _))| quote::quote!(Self::#variant => #i as u8,));
|
||||
.map(|(i, (variant, _))| {
|
||||
quote::quote_spanned!(error.attr_span => Self::#variant => #i as u8,)
|
||||
});
|
||||
|
||||
let as_str_matches = error.variants.iter()
|
||||
.map(|(variant, _)| {
|
||||
let variant_str = format!("{}", variant);
|
||||
quote::quote!(Self::#variant => #variant_str,)
|
||||
quote::quote_spanned!(error.attr_span => Self::#variant => #variant_str,)
|
||||
});
|
||||
|
||||
let metadata = error.variants.iter()
|
||||
.map(|(variant, doc)| {
|
||||
let variant_str = format!("{}", variant);
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(error.attr_span =>
|
||||
#frame_support::error::ErrorMetadata {
|
||||
name: #frame_support::error::DecodeDifferent::Encode(#variant_str),
|
||||
documentation: #frame_support::error::DecodeDifferent::Encode(&[ #( #doc, )* ]),
|
||||
@@ -69,13 +68,13 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
if let syn::Item::Enum(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by event parser")
|
||||
unreachable!("Checked by error parser")
|
||||
}
|
||||
};
|
||||
|
||||
error_item.variants.insert(0, phantom_variant);
|
||||
|
||||
quote::quote_spanned!(error_item_span =>
|
||||
quote::quote_spanned!(error.attr_span =>
|
||||
impl<#type_impl_gen> #frame_support::sp_std::fmt::Debug for #error_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// * Add __Ignore variant on Event
|
||||
/// * Impl various trait on Event including metadata
|
||||
@@ -40,12 +39,12 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let event_ident = &event.event;
|
||||
let frame_system = &def.frame_system;
|
||||
let frame_support = &def.frame_support;
|
||||
let event_use_gen = &event.gen_kind.type_use_gen();
|
||||
let event_impl_gen= &event.gen_kind.type_impl_gen();
|
||||
let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
|
||||
let event_impl_gen= &event.gen_kind.type_impl_gen(event.attr_span);
|
||||
let metadata = event.metadata.iter()
|
||||
.map(|(ident, args, docs)| {
|
||||
let name = format!("{}", ident);
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(event.attr_span =>
|
||||
#frame_support::event::EventMetadata {
|
||||
name: #frame_support::event::DecodeDifferent::Encode(#name),
|
||||
arguments: #frame_support::event::DecodeDifferent::Encode(&[
|
||||
@@ -58,9 +57,6 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
)
|
||||
});
|
||||
|
||||
let event_item_span =
|
||||
def.item.content.as_mut().expect("Checked by def parser").1[event.index].span();
|
||||
|
||||
let event_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[event.index];
|
||||
if let syn::Item::Enum(item) = item {
|
||||
@@ -99,10 +95,10 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
|
||||
|
||||
let deposit_event = if let Some((fn_vis, fn_span)) = &event.deposit_event {
|
||||
let event_use_gen = &event.gen_kind.type_use_gen();
|
||||
let trait_use_gen = &def.trait_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
|
||||
let trait_use_gen = &def.trait_use_generics(event.attr_span);
|
||||
let type_impl_gen = &def.type_impl_generics(event.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(event.attr_span);
|
||||
|
||||
quote::quote_spanned!(*fn_span =>
|
||||
impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause {
|
||||
@@ -125,7 +121,7 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
quote::quote_spanned!(event_item_span =>
|
||||
quote::quote_spanned!(event.attr_span =>
|
||||
#deposit_event
|
||||
|
||||
impl<#event_impl_gen> From<#event_ident<#event_use_gen>> for () #event_where_clause {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// * implement the trait `sp_runtime::BuildModuleGenesisStorage`
|
||||
/// * add #[cfg(features = "std")] to GenesisBuild implementation.
|
||||
@@ -26,21 +25,21 @@ pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
} else {
|
||||
return Default::default()
|
||||
};
|
||||
let genesis_build = def.genesis_build.as_ref().expect("Checked by def parser");
|
||||
|
||||
let frame_support = &def.frame_support;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(genesis_build.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(genesis_build.attr_span);
|
||||
let trait_use_gen = if def.config.has_instance {
|
||||
quote::quote!(T, I)
|
||||
quote::quote_spanned!(genesis_build.attr_span => T, I)
|
||||
} else {
|
||||
// `__InherentHiddenInstance` used by construct_runtime here is alias for `()`
|
||||
quote::quote!(T, ())
|
||||
quote::quote_spanned!(genesis_build.attr_span => T, ())
|
||||
};
|
||||
let gen_cfg_ident = &genesis_config.genesis_config;
|
||||
|
||||
let gen_cfg_use_gen = genesis_config.gen_kind.type_use_gen();
|
||||
let gen_cfg_use_gen = genesis_config.gen_kind.type_use_gen(genesis_build.attr_span);
|
||||
|
||||
let genesis_build = def.genesis_build.as_ref().expect("Checked by def parser");
|
||||
let genesis_build_item = &mut def.item.content.as_mut()
|
||||
.expect("Checked by def parser").1[genesis_build.index];
|
||||
|
||||
@@ -53,7 +52,7 @@ pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
genesis_build_item_impl.attrs.push(syn::parse_quote!( #[cfg(feature = "std")] ));
|
||||
let where_clause = &genesis_build.where_clause;
|
||||
|
||||
quote::quote_spanned!(genesis_build_item.span() =>
|
||||
quote::quote_spanned!(genesis_build.attr_span =>
|
||||
#[cfg(feature = "std")]
|
||||
impl<#type_impl_gen> #frame_support::sp_runtime::BuildModuleGenesisStorage<#trait_use_gen>
|
||||
for #gen_cfg_ident<#gen_cfg_use_gen> #where_clause
|
||||
|
||||
@@ -16,21 +16,17 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// * implement the individual traits using the Hooks trait
|
||||
pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let frame_support = &def.frame_support;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(def.hooks.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(def.hooks.attr_span);
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
let where_clause = &def.hooks.where_clause;
|
||||
let frame_system = &def.frame_system;
|
||||
|
||||
let hooks_item_span = def.item.content.as_mut()
|
||||
.expect("Checked by def parser").1[def.hooks.index].span();
|
||||
|
||||
quote::quote_spanned!(hooks_item_span =>
|
||||
quote::quote_spanned!(def.hooks.attr_span =>
|
||||
impl<#type_impl_gen>
|
||||
#frame_support::traits::OnFinalize<<T as #frame_system::Config>::BlockNumber>
|
||||
for #pallet_ident<#type_use_gen> #where_clause
|
||||
|
||||
@@ -25,9 +25,9 @@ use crate::pallet::Def;
|
||||
pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let frame_support = &def.frame_support;
|
||||
let frame_system = &def.frame_system;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_decl_gen = &def.type_decl_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(def.pallet_struct.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(def.pallet_struct.attr_span);
|
||||
let type_decl_gen = &def.type_decl_generics(def.pallet_struct.attr_span);
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
|
||||
let module_error_metadata = if let Some(error_def) = &def.error {
|
||||
let error_ident = &error_def.error;
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(def.pallet_struct.attr_span =>
|
||||
impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
|
||||
for #pallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
@@ -65,7 +65,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
}
|
||||
)
|
||||
} else {
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(def.pallet_struct.attr_span =>
|
||||
impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
|
||||
for #pallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
@@ -77,7 +77,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
)
|
||||
};
|
||||
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(def.pallet_struct.attr_span =>
|
||||
#module_error_metadata
|
||||
|
||||
/// Type alias to `Pallet`, to be used by `construct_runtime`.
|
||||
|
||||
@@ -32,8 +32,6 @@ fn prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
|
||||
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let frame_support = &def.frame_support;
|
||||
let frame_system = &def.frame_system;
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
|
||||
// Replace first arg `_` by the generated prefix structure.
|
||||
@@ -63,6 +61,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
unreachable!("Checked by def");
|
||||
};
|
||||
|
||||
let type_use_gen = if def.config.has_instance {
|
||||
quote::quote_spanned!(storage_def.attr_span => T, I)
|
||||
} else {
|
||||
quote::quote_spanned!(storage_def.attr_span => T)
|
||||
};
|
||||
let prefix_ident = prefix_ident(&storage_def.ident);
|
||||
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
|
||||
}
|
||||
@@ -72,22 +75,25 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let docs = &storage.docs;
|
||||
|
||||
let ident = &storage.ident;
|
||||
let gen = &def.type_use_generics();
|
||||
let full_ident = quote::quote!( #ident<#gen> );
|
||||
let gen = &def.type_use_generics(storage.attr_span);
|
||||
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
|
||||
|
||||
let metadata_trait = match &storage.metadata {
|
||||
Metadata::Value { .. } =>
|
||||
quote::quote!(#frame_support::storage::types::StorageValueMetadata),
|
||||
Metadata::Map { .. } =>
|
||||
quote::quote!(#frame_support::storage::types::StorageMapMetadata),
|
||||
Metadata::DoubleMap { .. } =>
|
||||
quote::quote!(#frame_support::storage::types::StorageDoubleMapMetadata),
|
||||
Metadata::Value { .. } => quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::storage::types::StorageValueMetadata
|
||||
),
|
||||
Metadata::Map { .. } => quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::storage::types::StorageMapMetadata
|
||||
),
|
||||
Metadata::DoubleMap { .. } => quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::storage::types::StorageDoubleMapMetadata
|
||||
),
|
||||
};
|
||||
|
||||
let ty = match &storage.metadata {
|
||||
Metadata::Value { value } => {
|
||||
let value = clean_type_string("e::quote!(#value).to_string());
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::metadata::StorageEntryType::Plain(
|
||||
#frame_support::metadata::DecodeDifferent::Encode(#value)
|
||||
)
|
||||
@@ -96,7 +102,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
Metadata::Map { key, value } => {
|
||||
let value = clean_type_string("e::quote!(#value).to_string());
|
||||
let key = clean_type_string("e::quote!(#key).to_string());
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::metadata::StorageEntryType::Map {
|
||||
hasher: <#full_ident as #metadata_trait>::HASHER,
|
||||
key: #frame_support::metadata::DecodeDifferent::Encode(#key),
|
||||
@@ -109,7 +115,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let value = clean_type_string("e::quote!(#value).to_string());
|
||||
let key1 = clean_type_string("e::quote!(#key1).to_string());
|
||||
let key2 = clean_type_string("e::quote!(#key2).to_string());
|
||||
quote::quote!(
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::metadata::StorageEntryType::DoubleMap {
|
||||
hasher: <#full_ident as #metadata_trait>::HASHER1,
|
||||
key2_hasher: <#full_ident as #metadata_trait>::HASHER2,
|
||||
@@ -121,7 +127,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
}
|
||||
};
|
||||
|
||||
quote::quote_spanned!(storage.ident.span() =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#frame_support::metadata::StorageEntryMetadata {
|
||||
name: #frame_support::metadata::DecodeDifferent::Encode(
|
||||
<#full_ident as #metadata_trait>::NAME
|
||||
@@ -144,19 +150,24 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
&storage.where_clause,
|
||||
&def.config.where_clause,
|
||||
]);
|
||||
let docs = storage.docs.iter().map(|d| quote::quote!(#[doc = #d]));
|
||||
let docs = storage.docs.iter()
|
||||
.map(|d| quote::quote_spanned!(storage.attr_span => #[doc = #d]));
|
||||
|
||||
let ident = &storage.ident;
|
||||
let gen = &def.type_use_generics();
|
||||
let full_ident = quote::quote!( #ident<#gen> );
|
||||
let gen = &def.type_use_generics(storage.attr_span);
|
||||
let type_impl_gen = &def.type_impl_generics(storage.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(storage.attr_span);
|
||||
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
|
||||
|
||||
match &storage.metadata {
|
||||
Metadata::Value { value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote!(Option<#value>),
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(getter.span() =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#( #docs )*
|
||||
pub fn #getter() -> #query {
|
||||
@@ -169,10 +180,12 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
},
|
||||
Metadata::Map { key, value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote!(Option<#value>),
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(getter.span() =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#( #docs )*
|
||||
pub fn #getter<KArg>(k: KArg) -> #query where
|
||||
@@ -187,10 +200,12 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
},
|
||||
Metadata::DoubleMap { key1, key2, value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote!(Option<#value>),
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(getter.span() =>
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#( #docs )*
|
||||
pub fn #getter<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #query where
|
||||
@@ -211,12 +226,14 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
});
|
||||
|
||||
let prefix_structs = def.storages.iter().map(|storage_def| {
|
||||
let type_impl_gen = &def.type_impl_generics(storage_def.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(storage_def.attr_span);
|
||||
let prefix_struct_ident = prefix_ident(&storage_def.ident);
|
||||
let prefix_struct_vis = &storage_def.vis;
|
||||
let prefix_struct_const = storage_def.ident.to_string();
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
quote::quote_spanned!(storage_def.ident.span() =>
|
||||
quote::quote_spanned!(storage_def.attr_span =>
|
||||
#prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>(
|
||||
core::marker::PhantomData<(#type_use_gen,)>
|
||||
);
|
||||
@@ -239,6 +256,8 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
|
||||
let completed_where_clause = super::merge_where_clauses(&where_clauses);
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
|
||||
quote::quote!(
|
||||
impl<#type_impl_gen> #pallet_ident<#type_use_gen>
|
||||
|
||||
@@ -28,8 +28,8 @@ pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
return Default::default()
|
||||
};
|
||||
|
||||
let type_impl_gen = &def.type_impl_generics();
|
||||
let type_use_gen = &def.type_use_generics();
|
||||
let type_impl_gen = &def.type_impl_generics(trait_store.span());
|
||||
let type_use_gen = &def.type_use_generics(trait_store.span());
|
||||
let pallet_ident = &def.pallet_struct.pallet;
|
||||
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
|
||||
@@ -16,38 +16,56 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// * Generate the struct
|
||||
/// * implement the `Get<..>` on it
|
||||
/// * Rename the name of the function to internal name
|
||||
pub fn expand_type_values(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let mut expand = quote::quote!();
|
||||
let frame_support = &def.frame_support;
|
||||
|
||||
for type_value in &def.type_values {
|
||||
// Remove item from module content
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[type_value.index];
|
||||
let span = item.span();
|
||||
*item = syn::Item::Verbatim(Default::default());
|
||||
let fn_name_str = &type_value.ident.to_string();
|
||||
let fn_name_snakecase = inflector::cases::snakecase::to_snake_case(fn_name_str);
|
||||
let fn_ident_renamed = syn::Ident::new(
|
||||
&format!("__type_value_for_{}", fn_name_snakecase),
|
||||
type_value.ident.span(),
|
||||
);
|
||||
|
||||
let type_value_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[type_value.index];
|
||||
if let syn::Item::Fn(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by error parser")
|
||||
}
|
||||
};
|
||||
|
||||
// Rename the type_value function name
|
||||
type_value_item.sig.ident = fn_ident_renamed.clone();
|
||||
|
||||
let vis = &type_value.vis;
|
||||
let ident = &type_value.ident;
|
||||
let block = &type_value.block;
|
||||
let type_ = &type_value.type_;
|
||||
let where_clause = &type_value.where_clause;
|
||||
|
||||
let (struct_impl_gen, struct_use_gen) = if type_value.is_generic {
|
||||
(def.type_impl_generics(), def.type_use_generics())
|
||||
(
|
||||
def.type_impl_generics(type_value.attr_span),
|
||||
def.type_use_generics(type_value.attr_span),
|
||||
)
|
||||
} else {
|
||||
(Default::default(), Default::default())
|
||||
};
|
||||
|
||||
expand.extend(quote::quote_spanned!(span =>
|
||||
expand.extend(quote::quote_spanned!(type_value.attr_span =>
|
||||
#vis struct #ident<#struct_use_gen>(core::marker::PhantomData<((), #struct_use_gen)>);
|
||||
impl<#struct_impl_gen> #frame_support::traits::Get<#type_> for #ident<#struct_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn get() -> #type_ #block
|
||||
fn get() -> #type_ {
|
||||
#fn_ident_renamed::<#struct_use_gen>()
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct CallDef {
|
||||
pub index: usize,
|
||||
/// Information on methods (used for expansion).
|
||||
pub methods: Vec<CallVariantDef>,
|
||||
/// The span of the attribute.
|
||||
/// The span of the pallet::call attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ pub fn check_dispatchable_first_arg_type(ty: &syn::Type) -> syn::Result<()> {
|
||||
|
||||
impl CallDef {
|
||||
pub fn try_from(
|
||||
// Span needed for expansion
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item
|
||||
|
||||
@@ -48,7 +48,8 @@ pub struct ConfigDef {
|
||||
pub has_event_type: bool,
|
||||
/// The where clause on trait definition but modified so `Self` is `T`.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
|
||||
/// The span of the pallet::config attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
/// Input definition for a constant in pallet config.
|
||||
@@ -262,8 +263,9 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS
|
||||
impl ConfigDef {
|
||||
pub fn try_from(
|
||||
frame_system: &syn::Ident,
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Trait(item) = item {
|
||||
item
|
||||
@@ -379,6 +381,7 @@ impl ConfigDef {
|
||||
consts_metadata,
|
||||
has_event_type,
|
||||
where_clause,
|
||||
attr_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,17 @@ pub struct ErrorDef {
|
||||
/// A set of usage of instance, must be check for consistency with trait.
|
||||
pub instances: Vec<helper::InstanceUsage>,
|
||||
/// The keyword error used (contains span).
|
||||
pub error: keyword::Error
|
||||
pub error: keyword::Error,
|
||||
/// The span of the pallet::error attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
impl ErrorDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Enum(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -77,6 +83,7 @@ impl ErrorDef {
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(ErrorDef {
|
||||
attr_span,
|
||||
index,
|
||||
variants,
|
||||
instances,
|
||||
|
||||
@@ -45,6 +45,8 @@ pub struct EventDef {
|
||||
pub deposit_event: Option<(syn::Visibility, proc_macro2::Span)>,
|
||||
/// Where clause used in event definition.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::event attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
/// Attribute for Event: defines metadata name to use.
|
||||
@@ -150,7 +152,11 @@ impl PalletEventAttrInfo {
|
||||
}
|
||||
|
||||
impl EventDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Enum(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -208,6 +214,7 @@ impl EventDef {
|
||||
.collect();
|
||||
|
||||
Ok(EventDef {
|
||||
attr_span,
|
||||
index,
|
||||
metadata,
|
||||
instances,
|
||||
|
||||
@@ -26,10 +26,16 @@ pub struct GenesisBuildDef {
|
||||
pub instances: Vec<helper::InstanceUsage>,
|
||||
/// The where_clause used.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::genesis_build attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
impl GenesisBuildDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Impl(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -48,6 +54,7 @@ impl GenesisBuildDef {
|
||||
instances.push(helper::check_genesis_builder_usage(&item_trait)?);
|
||||
|
||||
Ok(Self {
|
||||
attr_span,
|
||||
index,
|
||||
instances,
|
||||
where_clause: item.generics.where_clause.clone(),
|
||||
|
||||
@@ -26,10 +26,16 @@ pub struct HooksDef {
|
||||
pub instances: Vec<helper::InstanceUsage>,
|
||||
/// The where_clause used.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::hooks attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
impl HooksDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Impl(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -61,6 +67,7 @@ impl HooksDef {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
attr_span,
|
||||
index,
|
||||
instances,
|
||||
where_clause: item.generics.where_clause.clone(),
|
||||
|
||||
@@ -92,38 +92,42 @@ impl Def {
|
||||
let pallet_attr: Option<PalletAttr> = helper::take_first_item_attr(item)?;
|
||||
|
||||
match pallet_attr {
|
||||
Some(PalletAttr::Config(_)) if config.is_none() =>
|
||||
config = Some(config::ConfigDef::try_from(&frame_system, index, item)?),
|
||||
Some(PalletAttr::Pallet(_)) if pallet_struct.is_none() =>
|
||||
pallet_struct = Some(pallet_struct::PalletStructDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Hooks(_)) if hooks.is_none() => {
|
||||
let m = hooks::HooksDef::try_from(index, item)?;
|
||||
Some(PalletAttr::Config(span)) if config.is_none() =>
|
||||
config = Some(config::ConfigDef::try_from(&frame_system, span, index, item)?),
|
||||
Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
|
||||
let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
|
||||
pallet_struct = Some(p);
|
||||
},
|
||||
Some(PalletAttr::Hooks(span)) if hooks.is_none() => {
|
||||
let m = hooks::HooksDef::try_from(span, index, item)?;
|
||||
hooks = Some(m);
|
||||
},
|
||||
Some(PalletAttr::Call(span)) if call.is_none() =>
|
||||
call = Some(call::CallDef::try_from(span, index, item)?),
|
||||
Some(PalletAttr::Error(_)) if error.is_none() =>
|
||||
error = Some(error::ErrorDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Event(_)) if event.is_none() =>
|
||||
event = Some(event::EventDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Error(span)) if error.is_none() =>
|
||||
error = Some(error::ErrorDef::try_from(span, index, item)?),
|
||||
Some(PalletAttr::Event(span)) if event.is_none() =>
|
||||
event = Some(event::EventDef::try_from(span, index, item)?),
|
||||
Some(PalletAttr::GenesisConfig(_)) if genesis_config.is_none() => {
|
||||
genesis_config =
|
||||
Some(genesis_config::GenesisConfigDef::try_from(index, item)?);
|
||||
let g = genesis_config::GenesisConfigDef::try_from(index, item)?;
|
||||
genesis_config = Some(g);
|
||||
},
|
||||
Some(PalletAttr::GenesisBuild(span)) if genesis_build.is_none() => {
|
||||
let g = genesis_build::GenesisBuildDef::try_from(span, index, item)?;
|
||||
genesis_build = Some(g);
|
||||
},
|
||||
Some(PalletAttr::GenesisBuild(_)) if genesis_build.is_none() =>
|
||||
genesis_build = Some(genesis_build::GenesisBuildDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Origin(_)) if origin.is_none() =>
|
||||
origin = Some(origin::OriginDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Inherent(_)) if inherent.is_none() =>
|
||||
inherent = Some(inherent::InherentDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Storage(_)) =>
|
||||
storages.push(storage::StorageDef::try_from(index, item)?),
|
||||
Some(PalletAttr::Storage(span)) =>
|
||||
storages.push(storage::StorageDef::try_from(span, index, item)?),
|
||||
Some(PalletAttr::ValidateUnsigned(_)) if validate_unsigned.is_none() => {
|
||||
let v = validate_unsigned::ValidateUnsignedDef::try_from(index, item)?;
|
||||
validate_unsigned = Some(v);
|
||||
},
|
||||
Some(PalletAttr::TypeValue(_)) =>
|
||||
type_values.push(type_value::TypeValueDef::try_from(index, item)?),
|
||||
Some(PalletAttr::TypeValue(span)) =>
|
||||
type_values.push(type_value::TypeValueDef::try_from(span, index, item)?),
|
||||
Some(PalletAttr::ExtraConstants(_)) => {
|
||||
extra_constants =
|
||||
Some(extra_constants::ExtraConstantsDef::try_from(index, item)?)
|
||||
@@ -255,33 +259,33 @@ impl Def {
|
||||
/// Depending on if pallet is instantiable:
|
||||
/// * either `T: Config`
|
||||
/// * or `T: Config<I>, I: 'static`
|
||||
pub fn type_impl_generics(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_impl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
if self.config.has_instance {
|
||||
quote::quote!(T: Config<I>, I: 'static)
|
||||
quote::quote_spanned!(span => T: Config<I>, I: 'static)
|
||||
} else {
|
||||
quote::quote!(T: Config)
|
||||
quote::quote_spanned!(span => T: Config)
|
||||
}
|
||||
}
|
||||
|
||||
/// Depending on if pallet is instantiable:
|
||||
/// * either `T: Config`
|
||||
/// * or `T: Config<I>, I: 'static = ()`
|
||||
pub fn type_decl_bounded_generics(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_decl_bounded_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
if self.config.has_instance {
|
||||
quote::quote!(T: Config<I>, I: 'static = ())
|
||||
quote::quote_spanned!(span => T: Config<I>, I: 'static = ())
|
||||
} else {
|
||||
quote::quote!(T: Config)
|
||||
quote::quote_spanned!(span => T: Config)
|
||||
}
|
||||
}
|
||||
|
||||
/// Depending on if pallet is instantiable:
|
||||
/// * either `T`
|
||||
/// * or `T, I = ()`
|
||||
pub fn type_decl_generics(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_decl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
if self.config.has_instance {
|
||||
quote::quote!(T, I = ())
|
||||
quote::quote_spanned!(span => T, I = ())
|
||||
} else {
|
||||
quote::quote!(T)
|
||||
quote::quote_spanned!(span => T)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,22 +293,22 @@ impl Def {
|
||||
/// * either ``
|
||||
/// * or `<I>`
|
||||
/// to be used when using pallet trait `Config`
|
||||
pub fn trait_use_generics(&self) -> proc_macro2::TokenStream {
|
||||
pub fn trait_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
if self.config.has_instance {
|
||||
quote::quote!(<I>)
|
||||
quote::quote_spanned!(span => <I>)
|
||||
} else {
|
||||
quote::quote!()
|
||||
quote::quote_spanned!(span => )
|
||||
}
|
||||
}
|
||||
|
||||
/// Depending on if pallet is instantiable:
|
||||
/// * either `T`
|
||||
/// * or `T, I`
|
||||
pub fn type_use_generics(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
if self.config.has_instance {
|
||||
quote::quote!(T, I)
|
||||
quote::quote_spanned!(span => T, I)
|
||||
} else {
|
||||
quote::quote!(T)
|
||||
quote::quote_spanned!(span => T)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,20 +335,20 @@ impl GenericKind {
|
||||
/// Return the generic to be used when using the type.
|
||||
///
|
||||
/// Depending on its definition it can be: ``, `T` or `T, I`
|
||||
pub fn type_use_gen(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_use_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
match self {
|
||||
GenericKind::None => quote::quote!(),
|
||||
GenericKind::Config => quote::quote!(T),
|
||||
GenericKind::ConfigAndInstance => quote::quote!(T, I),
|
||||
GenericKind::Config => quote::quote_spanned!(span => T),
|
||||
GenericKind::ConfigAndInstance => quote::quote_spanned!(span => T, I),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the generic to be used in `impl<..>` when implementing on the type.
|
||||
pub fn type_impl_gen(&self) -> proc_macro2::TokenStream {
|
||||
pub fn type_impl_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
|
||||
match self {
|
||||
GenericKind::None => quote::quote!(),
|
||||
GenericKind::Config => quote::quote!(T: Config),
|
||||
GenericKind::ConfigAndInstance => quote::quote!(T: Config<I>, I: 'static),
|
||||
GenericKind::Config => quote::quote_spanned!(span => T: Config),
|
||||
GenericKind::ConfigAndInstance => quote::quote_spanned!(span => T: Config<I>, I: 'static),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ pub struct PalletStructDef {
|
||||
/// The keyword Pallet used (contains span).
|
||||
pub pallet: keyword::Pallet,
|
||||
/// Whether the trait `Store` must be generated.
|
||||
pub store: Option<(syn::Visibility, keyword::Store)>
|
||||
pub store: Option<(syn::Visibility, keyword::Store)>,
|
||||
/// The span of the pallet::pallet attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
/// Parse for `#[pallet::generate_store($vis trait Store)]`
|
||||
@@ -64,7 +66,11 @@ impl syn::parse::Parse for PalletStructAttr {
|
||||
}
|
||||
|
||||
impl PalletStructDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Struct(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -94,6 +100,6 @@ impl PalletStructDef {
|
||||
let mut instances = vec![];
|
||||
instances.push(helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?);
|
||||
|
||||
Ok(Self { index, instances, pallet, store })
|
||||
Ok(Self { index, instances, pallet, store, attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ pub struct StorageDef {
|
||||
pub query_kind: Option<QueryKind>,
|
||||
/// Where clause of type definition.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::storage attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
/// In `Foo<A, B, C>` retrieve the argument at given position, i.e. A is argument at position 0.
|
||||
@@ -112,7 +114,11 @@ fn retrieve_arg(
|
||||
}
|
||||
|
||||
impl StorageDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Type(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -207,6 +213,7 @@ impl StorageDef {
|
||||
})?;
|
||||
|
||||
Ok(StorageDef {
|
||||
attr_span,
|
||||
index,
|
||||
vis: item.vis.clone(),
|
||||
ident: item.ident.clone(),
|
||||
|
||||
@@ -36,10 +36,16 @@ pub struct TypeValueDef {
|
||||
pub instances: Vec<helper::InstanceUsage>,
|
||||
/// The where clause of the function.
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::type_value attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
impl TypeValueDef {
|
||||
pub fn try_from(index: usize, item: &mut syn::Item) -> syn::Result<Self> {
|
||||
pub fn try_from(
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Fn(item) = item {
|
||||
item
|
||||
} else {
|
||||
@@ -88,6 +94,7 @@ impl TypeValueDef {
|
||||
let where_clause = item.sig.generics.where_clause.clone();
|
||||
|
||||
Ok(TypeValueDef {
|
||||
attr_span,
|
||||
index,
|
||||
is_generic,
|
||||
vis,
|
||||
|
||||
Reference in New Issue
Block a user