Macros to use path instead of ident (#1474)

This commit is contained in:
Juan
2023-10-14 08:26:19 +02:00
committed by GitHub
parent 1f28cddd6f
commit 7c87d61f5a
26 changed files with 489 additions and 134 deletions
@@ -92,7 +92,7 @@ impl CompositeDef {
pub fn try_from(
attr_span: proc_macro2::Span,
index: usize,
scrate: &proc_macro2::Ident,
scrate: &syn::Path,
item: &mut syn::Item,
) -> syn::Result<Self> {
let item = if let syn::Item::Enum(item) = item {
@@ -16,7 +16,7 @@
// limitations under the License.
use super::helper;
use frame_support_procedural_tools::get_doc_literals;
use frame_support_procedural_tools::{get_doc_literals, is_using_frame_crate};
use quote::ToTokens;
use syn::{spanned::Spanned, token, Token};
@@ -165,24 +165,8 @@ pub struct PalletAttr {
typ: PalletAttrType,
}
pub struct ConfigBoundParse(syn::Ident);
impl syn::parse::Parse for ConfigBoundParse {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let ident = input.parse::<syn::Ident>()?;
input.parse::<syn::Token![::]>()?;
input.parse::<keyword::Config>()?;
if input.peek(syn::token::Lt) {
input.parse::<syn::AngleBracketedGenericArguments>()?;
}
Ok(Self(ident))
}
}
/// Parse for `IsType<<Sef as $ident::Config>::RuntimeEvent>` and retrieve `$ident`
pub struct IsTypeBoundEventParse(syn::Ident);
/// Parse for `IsType<<Self as $path>::RuntimeEvent>` and retrieve `$path`
pub struct IsTypeBoundEventParse(syn::Path);
impl syn::parse::Parse for IsTypeBoundEventParse {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
@@ -191,15 +175,13 @@ impl syn::parse::Parse for IsTypeBoundEventParse {
input.parse::<syn::Token![<]>()?;
input.parse::<syn::Token![Self]>()?;
input.parse::<syn::Token![as]>()?;
let ident = input.parse::<syn::Ident>()?;
input.parse::<syn::Token![::]>()?;
input.parse::<keyword::Config>()?;
let config_path = input.parse::<syn::Path>()?;
input.parse::<syn::Token![>]>()?;
input.parse::<syn::Token![::]>()?;
input.parse::<keyword::RuntimeEvent>()?;
input.parse::<syn::Token![>]>()?;
Ok(Self(ident))
Ok(Self(config_path))
}
}
@@ -237,7 +219,7 @@ impl syn::parse::Parse for FromEventParse {
/// Check if trait_item is `type RuntimeEvent`, if so checks its bounds are those expected.
/// (Event type is reserved type)
fn check_event_type(
frame_system: &syn::Ident,
frame_system: &syn::Path,
trait_item: &syn::TraitItem,
trait_has_instance: bool,
) -> syn::Result<bool> {
@@ -249,19 +231,16 @@ fn check_event_type(
no generics nor where_clause";
return Err(syn::Error::new(trait_item.span(), msg))
}
// Check bound contains IsType and From
// Check bound contains IsType and From
let has_is_type_bound = type_.bounds.iter().any(|s| {
syn::parse2::<IsTypeBoundEventParse>(s.to_token_stream())
.map_or(false, |b| b.0 == *frame_system)
.map_or(false, |b| has_expected_system_config(b.0, frame_system))
});
if !has_is_type_bound {
let msg = format!(
"Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `IsType<<Self as {}::Config>::RuntimeEvent>`",
frame_system,
);
let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \
bound: `IsType<<Self as frame_system::Config>::RuntimeEvent>`".to_string();
return Err(syn::Error::new(type_.span(), msg))
}
@@ -295,6 +274,43 @@ fn check_event_type(
}
}
/// Check that the path to `frame_system::Config` is valid, this is that the path is just
/// `frame_system::Config` or when using the `frame` crate it is `frame::xyz::frame_system::Config`.
fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool {
// Check if `frame_system` is actually 'frame_system'.
if path.segments.iter().all(|s| s.ident != "frame_system") {
return false
}
let mut expected_system_config =
match (is_using_frame_crate(&path), is_using_frame_crate(&frame_system)) {
(true, false) =>
// We can't use the path to `frame_system` from `frame` if `frame_system` is not being
// in scope through `frame`.
return false,
(false, true) =>
// We know that the only valid frame_system path is one that is `frame_system`, as
// `frame` re-exports it as such.
syn::parse2::<syn::Path>(quote::quote!(frame_system)).expect("is a valid path; qed"),
(_, _) =>
// They are either both `frame_system` or both `frame::xyz::frame_system`.
frame_system.clone(),
};
expected_system_config
.segments
.push(syn::PathSegment::from(syn::Ident::new("Config", path.span())));
// the parse path might be something like `frame_system::Config<...>`, so we
// only compare the idents along the path.
expected_system_config
.segments
.into_iter()
.map(|ps| ps.ident)
.collect::<Vec<_>>() ==
path.segments.into_iter().map(|ps| ps.ident).collect::<Vec<_>>()
}
/// Replace ident `Self` by `T`
pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
input
@@ -311,7 +327,7 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS
impl ConfigDef {
pub fn try_from(
frame_system: &syn::Ident,
frame_system: &syn::Path,
attr_span: proc_macro2::Span,
index: usize,
item: &mut syn::Item,
@@ -352,8 +368,8 @@ impl ConfigDef {
};
let has_frame_system_supertrait = item.supertraits.iter().any(|s| {
syn::parse2::<ConfigBoundParse>(s.to_token_stream())
.map_or(false, |b| b.0 == *frame_system)
syn::parse2::<syn::Path>(s.to_token_stream())
.map_or(false, |b| has_expected_system_config(b, frame_system))
});
let mut has_event_type = false;
@@ -461,7 +477,8 @@ impl ConfigDef {
(try `pub trait Config: frame_system::Config {{ ...` or \
`pub trait Config<I: 'static>: frame_system::Config {{ ...`). \
To disable this check, use `#[pallet::disable_frame_system_supertrait_check]`",
frame_system, found,
frame_system.to_token_stream(),
found,
);
return Err(syn::Error::new(item.span(), msg))
}
@@ -477,3 +494,97 @@ impl ConfigDef {
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn has_expected_system_config_works() {
let frame_system = syn::parse2::<syn::Path>(quote::quote!(frame_system)).unwrap();
let path = syn::parse2::<syn::Path>(quote::quote!(frame_system::Config)).unwrap();
assert!(has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_works_with_assoc_type() {
let frame_system = syn::parse2::<syn::Path>(quote::quote!(frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame_system::Config<RuntimeCall = Call>))
.unwrap();
assert!(has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_works_with_frame() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system)).unwrap();
let path = syn::parse2::<syn::Path>(quote::quote!(frame_system::Config)).unwrap();
assert!(has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_works_with_frame_full_path() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system::Config)).unwrap();
assert!(has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_works_with_other_frame_full_path() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(frame::xyz::frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame::xyz::frame_system::Config)).unwrap();
assert!(has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_does_not_works_with_mixed_frame_full_path() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(frame::xyz::frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system::Config)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_does_not_works_with_other_mixed_frame_full_path() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame::xyz::frame_system::Config)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_does_not_work_with_frame_full_path_if_not_frame_crate() {
let frame_system = syn::parse2::<syn::Path>(quote::quote!(frame_system)).unwrap();
let path =
syn::parse2::<syn::Path>(quote::quote!(frame::deps::frame_system::Config)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_unexpected_frame_system() {
let frame_system =
syn::parse2::<syn::Path>(quote::quote!(framez::deps::frame_system)).unwrap();
let path = syn::parse2::<syn::Path>(quote::quote!(frame_system::Config)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_unexpected_path() {
let frame_system = syn::parse2::<syn::Path>(quote::quote!(frame_system)).unwrap();
let path = syn::parse2::<syn::Path>(quote::quote!(frame_system::ConfigSystem)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
#[test]
fn has_expected_system_config_not_frame_system() {
let frame_system = syn::parse2::<syn::Path>(quote::quote!(something)).unwrap();
let path = syn::parse2::<syn::Path>(quote::quote!(something::Config)).unwrap();
assert!(!has_expected_system_config(path, &frame_system));
}
}
@@ -37,7 +37,7 @@ pub mod type_value;
pub mod validate_unsigned;
use composite::{keyword::CompositeKeyword, CompositeDef};
use frame_support_procedural_tools::generate_crate_access_2018;
use frame_support_procedural_tools::generate_access_from_frame_or_crate;
use syn::spanned::Spanned;
/// Parsed definition of a pallet.
@@ -60,15 +60,15 @@ pub struct Def {
pub extra_constants: Option<extra_constants::ExtraConstantsDef>,
pub composites: Vec<composite::CompositeDef>,
pub type_values: Vec<type_value::TypeValueDef>,
pub frame_system: syn::Ident,
pub frame_support: syn::Ident,
pub frame_system: syn::Path,
pub frame_support: syn::Path,
pub dev_mode: bool,
}
impl Def {
pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result<Self> {
let frame_system = generate_crate_access_2018("frame-system")?;
let frame_support = generate_crate_access_2018("frame-support")?;
let frame_system = generate_access_from_frame_or_crate("frame-system")?;
let frame_support = generate_access_from_frame_or_crate("frame-support")?;
let item_span = item.span();
let items = &mut item