Allow renaming storage item prefixes (#9016)

* Implement parsing for #[pallet::storage_name] on storage items

* Rename storage prefix when a #[pallet::storage_name] is supplied

* Fix test_storage_info

* Rename storage_name to storage_prefix

* Check for duplicates when renaming storage prefixes

* Allow only string literals for storage_prefix renames

* Use proper spans for attribute errors

* Check for valid identifiers when parsing storage prefix renames
This commit is contained in:
Keith Yeung
2021-06-14 03:07:09 -07:00
committed by GitHub
parent 0975a92818
commit c2f13a03a8
13 changed files with 288 additions and 20 deletions
@@ -15,22 +15,48 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use crate::pallet::{Def, parse::storage::StorageDef};
use crate::pallet::parse::storage::{Metadata, QueryKind, StorageGenerics};
use frame_support_procedural_tools::clean_type_string;
use std::collections::HashSet;
/// Generate the prefix_ident related the the storage.
/// prefix_ident is used for the prefix struct to be given to storage as first generic param.
fn prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
fn prefix_ident(storage: &StorageDef) -> syn::Ident {
let storage_ident = &storage.ident;
syn::Ident::new(&format!("_GeneratedPrefixForStorage{}", storage_ident), storage_ident.span())
}
/// Check for duplicated storage prefixes. This step is necessary since users can specify an
/// alternative storage prefix using the #[pallet::storage_prefix] syntax, and we need to ensure
/// that the prefix specified by the user is not a duplicate of an existing one.
fn check_prefix_duplicates(
storage_def: &StorageDef,
set: &mut HashSet<String>,
) -> syn::Result<()> {
let prefix = storage_def.prefix();
if !set.insert(prefix.clone()) {
let err = syn::Error::new(
storage_def.prefix_span(),
format!("Duplicate storage prefixes found for `{}`", prefix),
);
return Err(err);
}
Ok(())
}
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
/// * Add `#[allow(type_alias_bounds)]`
pub fn process_generics(def: &mut Def) {
pub fn process_generics(def: &mut Def) -> syn::Result<()> {
let frame_support = &def.frame_support;
let mut prefix_set = HashSet::new();
for storage_def in def.storages.iter_mut() {
check_prefix_duplicates(storage_def, &mut prefix_set)?;
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index];
let typ_item = match item {
@@ -50,7 +76,7 @@ pub fn process_generics(def: &mut Def) {
_ => unreachable!("Checked by def"),
};
let prefix_ident = prefix_ident(&storage_def.ident);
let prefix_ident = prefix_ident(&storage_def);
let type_use_gen = if def.config.has_instance {
quote::quote_spanned!(storage_def.attr_span => T, I)
} else {
@@ -116,6 +142,8 @@ pub fn process_generics(def: &mut Def) {
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
}
}
Ok(())
}
/// * generate StoragePrefix structs (e.g. for a storage `MyStorage` a struct with the name
@@ -125,7 +153,9 @@ pub fn process_generics(def: &mut Def) {
/// * Add `#[allow(type_alias_bounds)]` on storages type alias
/// * generate metadatas
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
process_generics(def);
if let Err(e) = process_generics(def) {
return e.into_compile_error().into();
}
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
@@ -344,9 +374,9 @@ 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_ident = prefix_ident(&storage_def);
let prefix_struct_vis = &storage_def.vis;
let prefix_struct_const = storage_def.ident.to_string();
let prefix_struct_const = storage_def.prefix();
let config_where_clause = &def.config.where_clause;
let cfg_attrs = &storage_def.cfg_attrs;