From ec9a734f9a1f9aad839f0fd1d549179d7b1354a4 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko <45178695+pkhry@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:56:52 +0200 Subject: [PATCH] Deprecation info support in RuntimeMetadataIR (#4851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description: * Adds `DeprecationStatusIR` enum to sp_metadata_ir. Deprecation info for simple items. * Adds `DeprecationInfoIR` enum to sp_metadata_ir. It is a deprecation info for an enums/errors/calls. Contains `DeprecationStatusIR`. Denotes full/partial deprecation of the type or its variants/calls * Adds `deprecation_info` field to - `RuntimeApiMetadataIR` - `RuntimeApiMethodMetadataIR` - `StorageEntryMetadataIR` - `PalletConstantMetadataIR` - `PalletCallMetadataIR` - `PalletMetadataIR` - `PalletEventMetadataIR` - `PalletErrorMetadataIR` ### Testing done: - Unit tests to check whether or not correct `note`/`since` texts are getting propagated to the metadata structs. - UI test to check for error message in case of incorrect attribute usage. There's also some test updates to make sure that deprecation attributes are getting propagated to the relevant structs. see: #4098, Solution: A ### Examples of produced deprecation info metadata They can be found in: - Tests for `frame-support` - hackmd link https://hackmd.io/@Zett98/Bys0YgbcR --------- Co-authored-by: GitHub Action Co-authored-by: command-bot <> Co-authored-by: Bastian Köcher --- prdoc/pr_4851.prdoc | 40 ++++ .../examples/proc_main/inject_runtime_type.rs | 1 + .../procedural/examples/proc_main/runtime.rs | 2 + .../src/construct_runtime/expand/metadata.rs | 17 +- .../procedural/src/construct_runtime/parse.rs | 35 ++-- .../support/procedural/src/deprecation.rs | 181 ++++++++++++++++++ substrate/frame/support/procedural/src/lib.rs | 5 +- .../procedural/src/pallet/expand/call.rs | 14 +- .../procedural/src/pallet/expand/constants.rs | 44 +++-- .../procedural/src/pallet/expand/error.rs | 24 +++ .../procedural/src/pallet/expand/event.rs | 25 ++- .../src/pallet/expand/pallet_struct.rs | 19 +- .../procedural/src/pallet/expand/storage.rs | 29 +-- .../procedural/src/pallet/parse/call.rs | 48 ++--- .../procedural/src/pallet/parse/config.rs | 40 ++-- .../procedural/src/pallet/parse/error.rs | 4 +- .../procedural/src/pallet/parse/event.rs | 15 +- .../src/pallet/parse/extra_constants.rs | 19 +- .../procedural/src/pallet/parse/mod.rs | 15 +- .../procedural/src/pallet/parse/storage.rs | 33 ++-- .../procedural/src/runtime/parse/mod.rs | 12 +- .../procedural/src/runtime/parse/pallet.rs | 3 +- substrate/frame/support/src/lib.rs | 42 ++++ .../support/src/storage/generator/map.rs | 6 +- .../support/src/storage/types/counted_map.rs | 13 +- .../support/src/storage/types/counted_nmap.rs | 57 +++++- .../support/src/storage/types/double_map.rs | 21 +- .../frame/support/src/storage/types/map.rs | 21 +- .../frame/support/src/storage/types/mod.rs | 6 +- .../frame/support/src/storage/types/nmap.rs | 49 ++++- .../frame/support/src/storage/types/value.rs | 21 +- substrate/frame/support/src/tests/mod.rs | 52 ++++- .../undefined_event_part.stderr | 20 ++ .../support/test/tests/enum_deprecation.rs | 173 +++++++++++++++++ .../frame/support/test/tests/instance.rs | 3 + substrate/frame/support/test/tests/pallet.rs | 62 +++++- .../support/test/tests/runtime_metadata.rs | 31 ++- .../api/proc-macro/src/impl_runtime_apis.rs | 8 +- .../api/proc-macro/src/runtime_metadata.rs | 14 +- .../primitives/api/proc-macro/src/utils.rs | 125 +++++++++++- substrate/primitives/api/src/lib.rs | 5 + .../api/test/tests/ui/deprecation_info.rs | 29 +++ .../api/test/tests/ui/deprecation_info.stderr | 25 +++ substrate/primitives/metadata-ir/src/types.rs | 118 +++++++++--- 44 files changed, 1319 insertions(+), 207 deletions(-) create mode 100644 prdoc/pr_4851.prdoc create mode 100644 substrate/frame/support/procedural/src/deprecation.rs create mode 100644 substrate/frame/support/test/tests/enum_deprecation.rs create mode 100644 substrate/primitives/api/test/tests/ui/deprecation_info.rs create mode 100644 substrate/primitives/api/test/tests/ui/deprecation_info.stderr diff --git a/prdoc/pr_4851.prdoc b/prdoc/pr_4851.prdoc new file mode 100644 index 000000000000..923ca4bfff5d --- /dev/null +++ b/prdoc/pr_4851.prdoc @@ -0,0 +1,40 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Add support for deprecation metadata in `RuntimeMetadataIr` entries. + +doc: + - audience: + - Runtime dev + - Runtime user + description: | + Changes introduced are listed below. + Adds `DeprecationStatusIR` enum to sp_metadata_ir. + - Is a deprecation info for simple items. + Adds `DeprecationInfoIR` enum to sp_metadata_ir. + - It is a deprecation info for an enums/errors/calls. Contains `DeprecationStatusIR`. + Also denotes full/partial deprecation of the type or its variants/calls. + Adds `deprecation_info` field to + - `RuntimeApiMetadataIR` + - `RuntimeApiMethodMetadataIR` + - `StorageEntryMetadataIR` + - `PalletConstantMetadataIR` + - `PalletCallMetadataIR` + - `PalletMetadataIR` + - `PalletEventMetadataIR` + - `PalletErrorMetadataIR` + Examples of the deprecation info produced can be seen inside + - Tests for `frame-support` + - hackmd link https://hackmd.io/@Zett98/Bys0YgbcR + +crates: + - name: frame-support-procedural + bump: patch + - name: frame-support + bump: major + - name: sp-api-proc-macro + bump: patch + - name: sp-api + bump: patch + - name: sp-metadata-ir + bump: major diff --git a/substrate/frame/support/procedural/examples/proc_main/inject_runtime_type.rs b/substrate/frame/support/procedural/examples/proc_main/inject_runtime_type.rs index cd5660f2bda7..d0725ba2049f 100644 --- a/substrate/frame/support/procedural/examples/proc_main/inject_runtime_type.rs +++ b/substrate/frame/support/procedural/examples/proc_main/inject_runtime_type.rs @@ -43,6 +43,7 @@ fn derive_impl_works_with_no_aggregated_types() { type Block = super::Block; type AccountId = super::AccountId; type PalletInfo = super::PalletInfo; + type ExampleConstant = (); } assert_type_eq_all!(::RuntimeOrigin, ()); diff --git a/substrate/frame/support/procedural/examples/proc_main/runtime.rs b/substrate/frame/support/procedural/examples/proc_main/runtime.rs index a9d9281f50da..109ca4f6dc48 100644 --- a/substrate/frame/support/procedural/examples/proc_main/runtime.rs +++ b/substrate/frame/support/procedural/examples/proc_main/runtime.rs @@ -14,6 +14,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(deprecated, clippy::deprecated_semver)] use super::{frame_system, Block}; use crate::derive_impl; @@ -121,6 +122,7 @@ mod runtime { // Ensure that the runtime does not export the calls from the pallet #[runtime::pallet_index(4)] #[runtime::disable_call] + #[deprecated = "example"] pub type PalletWithDisabledCall = pallet_with_disabled_call::Pallet; // Ensure that the runtime does not export the unsigned calls from the pallet diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs index daef1b171617..f3724f4ccb69 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -46,7 +46,7 @@ pub fn expand_runtime_metadata( let index = &decl.index; let storage = expand_pallet_metadata_storage(&filtered_names, runtime, decl); let calls = expand_pallet_metadata_calls(&filtered_names, runtime, decl); - let event = expand_pallet_metadata_events(&filtered_names, runtime, scrate, decl); + let event = expand_pallet_metadata_events(&filtered_names, runtime, decl); let constants = expand_pallet_metadata_constants(runtime, decl); let errors = expand_pallet_metadata_errors(runtime, decl); let docs = expand_pallet_metadata_docs(runtime, decl); @@ -58,7 +58,7 @@ pub fn expand_runtime_metadata( #attr } }); - + let deprecation_info = expand_pallet_metadata_deprecation(runtime, decl); quote! { #attr #scrate::__private::metadata_ir::PalletMetadataIR { @@ -70,6 +70,7 @@ pub fn expand_runtime_metadata( constants: #constants, error: #errors, docs: #docs, + deprecation_info: #deprecation_info, } } }) @@ -200,7 +201,6 @@ fn expand_pallet_metadata_calls( fn expand_pallet_metadata_events( filtered_names: &[&'static str], runtime: &Ident, - scrate: &TokenStream, decl: &Pallet, ) -> TokenStream { if filtered_names.contains(&"Event") { @@ -220,9 +220,7 @@ fn expand_pallet_metadata_events( quote! { Some( - #scrate::__private::metadata_ir::PalletEventMetadataIR { - ty: #scrate::__private::scale_info::meta_type::<#pallet_event>() - } + #pallet_event::event_metadata::<#pallet_event>() ) } } else { @@ -230,6 +228,13 @@ fn expand_pallet_metadata_events( } } +fn expand_pallet_metadata_deprecation(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { #path::Pallet::<#runtime #(, #path::#instance)*>::deprecation_info() } +} + fn expand_pallet_metadata_constants(runtime: &Ident, decl: &Pallet) -> TokenStream { let path = &decl.path; let instance = decl.instance.as_ref().into_iter(); diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index 532e032d0cb7..3e38adcc3c59 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -130,9 +130,9 @@ impl Parse for WhereSection { definitions.push(definition); if !input.peek(Token![,]) { if !input.peek(token::Brace) { - return Err(input.error("Expected `,` or `{`")) + return Err(input.error("Expected `,` or `{`")); } - break + break; } input.parse::()?; } @@ -144,7 +144,7 @@ impl Parse for WhereSection { "`{:?}` was declared above. Please use exactly one declaration for `{:?}`.", kind, kind ); - return Err(Error::new(*kind_span, msg)) + return Err(Error::new(*kind_span, msg)); } Ok(Self { span: input.span() }) } @@ -173,7 +173,7 @@ impl Parse for WhereDefinition { } else if lookahead.peek(keyword::UncheckedExtrinsic) { (input.parse::()?.span(), WhereKind::UncheckedExtrinsic) } else { - return Err(lookahead.error()) + return Err(lookahead.error()); }; let _: Token![=] = input.parse()?; @@ -270,7 +270,7 @@ impl Parse for PalletDeclaration { { return Err(input.error( "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", - )) + )); } else { is_expanded.then_some(extra_parts) }; @@ -283,7 +283,7 @@ impl Parse for PalletDeclaration { let _: keyword::use_parts = input.parse()?; SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { - return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")) + return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")); } else { SpecifiedParts::All }; @@ -295,7 +295,7 @@ impl Parse for PalletDeclaration { let index = index.base10_parse::()?; Some(index) } else if !input.peek(Token![,]) && !input.is_empty() { - return Err(input.error("Unexpected tokens, expected one of `=`, `,`")) + return Err(input.error("Unexpected tokens, expected one of `=`, `,`")); } else { None }; @@ -339,7 +339,7 @@ impl Parse for PalletPath { let ident = input.call(Ident::parse_any)?; res.inner.segments.push(ident.into()); } else { - return Err(lookahead.error()) + return Err(lookahead.error()); } while input.peek(Token![::]) && input.peek3(Ident) { @@ -370,7 +370,7 @@ fn parse_pallet_parts(input: ParseStream) -> Result> { "`{}` was already declared before. Please remove the duplicate declaration", part.name(), ); - return Err(Error::new(part.keyword.span(), msg)) + return Err(Error::new(part.keyword.span(), msg)); } } @@ -505,7 +505,7 @@ impl Parse for PalletPart { keyword.name(), valid_generics, ); - return Err(syn::Error::new(keyword.span(), msg)) + return Err(syn::Error::new(keyword.span(), msg)); } Ok(Self { keyword, generics }) @@ -566,7 +566,7 @@ fn parse_pallet_parts_no_generic(input: ParseStream) -> Result, /// The doc literals pub docs: Vec, + /// attributes + pub attrs: Vec, } impl Pallet { @@ -650,7 +652,7 @@ enum PalletsConversion { /// incrementally from last explicit or 0. fn convert_pallets(pallets: Vec) -> syn::Result { if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { - return Ok(PalletsConversion::Implicit(pallets)) + return Ok(PalletsConversion::Implicit(pallets)); } let mut indices = HashMap::new(); @@ -678,7 +680,7 @@ fn convert_pallets(pallets: Vec) -> syn::Result) -> syn::Result) -> syn::Result (), @@ -738,7 +740,7 @@ fn convert_pallets(pallets: Vec) -> syn::Result) -> syn::Result>>()?; diff --git a/substrate/frame/support/procedural/src/deprecation.rs b/substrate/frame/support/procedural/src/deprecation.rs new file mode 100644 index 000000000000..bdf996d21229 --- /dev/null +++ b/substrate/frame/support/procedural/src/deprecation.rs @@ -0,0 +1,181 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + punctuated::Punctuated, spanned::Spanned, Error, Expr, ExprLit, Lit, Meta, MetaNameValue, + Result, Token, Variant, +}; + +fn deprecation_msg_formatter(msg: &str) -> String { + format!( + r#"{msg} + help: the following are the possible correct uses +| +| #[deprecated = "reason"] +| +| #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] +| +| #[deprecated] +|"# + ) +} + +fn parse_deprecated_meta(crate_: &TokenStream, attr: &syn::Attribute) -> Result { + match &attr.meta { + Meta::List(meta_list) => { + let parsed = meta_list + .parse_args_with(Punctuated::::parse_terminated) + .map_err(|e| Error::new(attr.span(), e.to_string()))?; + let (note, since) = parsed.iter().try_fold((None, None), |mut acc, item| { + let value = match &item.value { + Expr::Lit(ExprLit { lit: lit @ Lit::Str(_), .. }) => Ok(lit), + _ => Err(Error::new( + attr.span(), + deprecation_msg_formatter( + "Invalid deprecation attribute: expected string literal", + ), + )), + }?; + if item.path.is_ident("note") { + acc.0.replace(value); + } else if item.path.is_ident("since") { + acc.1.replace(value); + } + Ok::<(Option<&syn::Lit>, Option<&syn::Lit>), Error>(acc) + })?; + note.map_or_else( + || Err(Error::new(attr.span(), deprecation_msg_formatter("Invalid deprecation attribute: missing `note`"))), + |note| { + let since = if let Some(str) = since { + quote! { Some(#str) } + } else { + quote! { None } + }; + let doc = quote! { #crate_::__private::metadata_ir::DeprecationStatusIR::Deprecated { note: #note, since: #since }}; + Ok(doc) + }, + ) + }, + Meta::NameValue(MetaNameValue { + value: Expr::Lit(ExprLit { lit: lit @ Lit::Str(_), .. }), + .. + }) => { + // #[deprecated = "lit"] + let doc = quote! { #crate_::__private::metadata_ir::DeprecationStatusIR::Deprecated { note: #lit, since: None } }; + Ok(doc) + }, + Meta::Path(_) => { + // #[deprecated] + Ok( + quote! { #crate_::__private::metadata_ir::DeprecationStatusIR::DeprecatedWithoutNote }, + ) + }, + _ => Err(Error::new( + attr.span(), + deprecation_msg_formatter("Invalid deprecation attribute: expected string literal"), + )), + } +} + +/// collects deprecation attribute if its present. +pub fn get_deprecation(path: &TokenStream, attrs: &[syn::Attribute]) -> Result { + parse_deprecation(path, attrs).map(|item| { + item.unwrap_or_else(|| { + quote! {#path::__private::metadata_ir::DeprecationStatusIR::NotDeprecated} + }) + }) +} + +fn parse_deprecation(path: &TokenStream, attrs: &[syn::Attribute]) -> Result> { + attrs + .iter() + .find(|a| a.path().is_ident("deprecated")) + .map(|a| parse_deprecated_meta(path, a)) + .transpose() +} + +/// collects deprecation attribute if its present for enum-like types +pub fn get_deprecation_enum<'a>( + path: &TokenStream, + parent_attrs: &[syn::Attribute], + children_attrs: impl Iterator, +) -> Result { + let parent_deprecation = parse_deprecation(path, parent_attrs)?; + + let children = children_attrs + .filter_map(|(key, attributes)| { + let key = quote::quote! { #path::__private::codec::Compact(#key as u8) }; + let deprecation_status = parse_deprecation(path, attributes).transpose(); + deprecation_status.map(|item| item.map(|item| quote::quote! { (#key, #item) })) + }) + .collect::>>()?; + match (parent_deprecation, children.as_slice()) { + (None, []) => + Ok(quote::quote! { #path::__private::metadata_ir::DeprecationInfoIR::NotDeprecated }), + (None, _) => { + let children = quote::quote! { #path::__private::scale_info::prelude::collections::BTreeMap::from([#( #children),*]) }; + Ok( + quote::quote! { #path::__private::metadata_ir::DeprecationInfoIR::VariantsDeprecated(#children) }, + ) + }, + (Some(depr), _) => Ok( + quote::quote! { #path::__private::metadata_ir::DeprecationInfoIR::ItemDeprecated(#depr) }, + ), + } +} + +/// Gets the index for the variant inside `Error` or `Event` declaration. +/// priority is as follows: +/// Manual `#[codec(index = N)]` +/// Explicit discriminant `Variant = N` +/// Variant's definition index +pub fn variant_index_for_deprecation(index: u8, item: &Variant) -> u8 { + let index: u8 = + if let Some((_, Expr::Lit(ExprLit { lit: Lit::Int(num_lit), .. }))) = &item.discriminant { + num_lit.base10_parse::().unwrap_or(index as u8) + } else { + index as u8 + }; + + item.attrs + .iter() + .find(|attr| attr.path().is_ident("codec")) + .and_then(|attr| { + if let Meta::List(meta_list) = &attr.meta { + meta_list + .parse_args_with(Punctuated::::parse_terminated) + .ok() + } else { + None + } + }) + .and_then(|parsed| { + parsed.iter().fold(None, |mut acc, item| { + if let Expr::Lit(ExprLit { lit: Lit::Int(num_lit), .. }) = &item.value { + num_lit.base10_parse::().iter().for_each(|val| { + if item.path.is_ident("index") { + acc.replace(*val); + } + }) + }; + acc + }) + }) + .unwrap_or(index) +} diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index ef99faee86ae..8554a5b830de 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -23,6 +23,7 @@ mod benchmark; mod construct_runtime; mod crate_version; +mod deprecation; mod derive_impl; mod dummy_part_checker; mod dynamic_params; @@ -812,7 +813,7 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { `RuntimeTask`, `RuntimeOrigin`, `RuntimeParameters` or `PalletInfo`", ) .to_compile_error() - .into() + .into(); } tokens } @@ -1221,7 +1222,7 @@ pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { "`#[import_section]` can only be applied to a valid pallet module", ) .to_compile_error() - .into() + .into(); } if let Some(ref mut content) = internal_mod.content { diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index 5dc8dc3146cf..8b333d19087d 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -263,6 +263,15 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } }); + let deprecation = match crate::deprecation::get_deprecation_enum( + "e::quote! {#frame_support}, + def.call.as_ref().map(|call| call.attrs.as_ref()).unwrap_or(&[]), + methods.iter().map(|item| (item.call_index as u8, item.attrs.as_ref())), + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + quote::quote_spanned!(span => #[doc(hidden)] mod warnings { @@ -463,7 +472,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #[allow(dead_code)] #[doc(hidden)] pub fn call_functions() -> #frame_support::__private::metadata_ir::PalletCallMetadataIR { - #frame_support::__private::scale_info::meta_type::<#call_ident<#type_use_gen>>().into() + #frame_support::__private::metadata_ir::PalletCallMetadataIR { + ty: #frame_support::__private::scale_info::meta_type::<#call_ident<#type_use_gen>>(), + deprecation_info: #deprecation, + } } } ) diff --git a/substrate/frame/support/procedural/src/pallet/expand/constants.rs b/substrate/frame/support/procedural/src/pallet/expand/constants.rs index a36df790bd29..ca34631e7494 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/constants.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/constants.rs @@ -28,6 +28,8 @@ struct ConstDef { pub default_byte_impl: proc_macro2::TokenStream, /// Constant name for Metadata (optional) pub metadata_name: Option, + /// Deprecation_info: + pub deprecation_info: proc_macro2::TokenStream, } /// Implement the `pallet_constants_metadata` function for the pallet. @@ -42,11 +44,18 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause)); let completed_where_clause = super::merge_where_clauses(&where_clauses); - let config_consts = def.config.consts_metadata.iter().map(|const_| { + let mut config_consts = vec![]; + for const_ in def.config.consts_metadata.iter() { let ident = &const_.ident; let const_type = &const_.type_; - - ConstDef { + let deprecation_info = match crate::deprecation::get_deprecation( + "e::quote! { #frame_support }, + &const_.attrs, + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + config_consts.push(ConstDef { ident: const_.ident.clone(), type_: const_.type_.clone(), doc: const_.doc.clone(), @@ -56,13 +65,22 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::codec::Encode::encode(&value) ), metadata_name: None, - } - }); + deprecation_info, + }) + } - let extra_consts = def.extra_constants.iter().flat_map(|d| &d.extra_constants).map(|const_| { + let mut extra_consts = vec![]; + for const_ in def.extra_constants.iter().flat_map(|d| &d.extra_constants) { let ident = &const_.ident; - - ConstDef { + let deprecation_info = match crate::deprecation::get_deprecation( + "e::quote! { #frame_support }, + &const_.attrs, + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + + extra_consts.push(ConstDef { ident: const_.ident.clone(), type_: const_.type_.clone(), doc: const_.doc.clone(), @@ -71,10 +89,11 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::__private::codec::Encode::encode(&value) ), metadata_name: const_.metadata_name.clone(), - } - }); + deprecation_info, + }) + } - let consts = config_consts.chain(extra_consts).map(|const_| { + let consts = config_consts.into_iter().chain(extra_consts.into_iter()).map(|const_| { let const_type = &const_.type_; let ident_str = format!("{}", const_.metadata_name.unwrap_or(const_.ident)); @@ -82,13 +101,14 @@ pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream { let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &const_.doc }; let default_byte_impl = &const_.default_byte_impl; - + let deprecation_info = &const_.deprecation_info; quote::quote!({ #frame_support::__private::metadata_ir::PalletConstantMetadataIR { name: #ident_str, ty: #frame_support::__private::scale_info::meta_type::<#const_type>(), value: { #default_byte_impl }, docs: #frame_support::__private::vec![ #( #doc ),* ], + deprecation_info: #deprecation_info } }) }); diff --git a/substrate/frame/support/procedural/src/pallet/expand/error.rs b/substrate/frame/support/procedural/src/pallet/expand/error.rs index 05478ee39084..646655cfe14e 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/error.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/error.rs @@ -104,6 +104,19 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" }; + let deprecation = match crate::deprecation::get_deprecation_enum( + "e::quote! {#frame_support}, + &error.attrs, + error_item.variants.iter().enumerate().map(|(index, item)| { + let index = crate::deprecation::variant_index_for_deprecation(index as u8, item); + + (index, item.attrs.as_ref()) + }), + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + // derive TypeInfo for error metadata error_item.attrs.push(syn::parse_quote! { #[derive( @@ -189,5 +202,16 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { } pub use #error_token_unique_id as tt_error_token; + + impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause { + #[allow(dead_code)] + #[doc(hidden)] + pub fn error_metadata() -> #frame_support::__private::metadata_ir::PalletErrorMetadataIR { + #frame_support::__private::metadata_ir::PalletErrorMetadataIR { + ty: #frame_support::__private::scale_info::meta_type::<#error_ident<#type_use_gen>>(), + deprecation_info: #deprecation, + } + } + } ) } diff --git a/substrate/frame/support/procedural/src/pallet/expand/event.rs b/substrate/frame/support/procedural/src/pallet/expand/event.rs index 655fc5507d26..8519143179d6 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/event.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/event.rs @@ -71,7 +71,6 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { let frame_support = &def.frame_support; 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 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 { @@ -96,6 +95,19 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { event_item.variants.push(variant); } + let deprecation = match crate::deprecation::get_deprecation_enum( + "e::quote! {#frame_support}, + &event.attrs, + event_item.variants.iter().enumerate().map(|(index, item)| { + let index = crate::deprecation::variant_index_for_deprecation(index as u8, item); + + (index, item.attrs.as_ref()) + }), + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + if get_doc_literals(&event_item.attrs).is_empty() { event_item .attrs @@ -170,5 +182,16 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { impl<#event_impl_gen> From<#event_ident<#event_use_gen>> for () #event_where_clause { fn from(_: #event_ident<#event_use_gen>) {} } + + impl<#event_impl_gen> #event_ident<#event_use_gen> #event_where_clause { + #[allow(dead_code)] + #[doc(hidden)] + pub fn event_metadata() -> #frame_support::__private::metadata_ir::PalletEventMetadataIR { + #frame_support::__private::metadata_ir::PalletEventMetadataIR { + ty: #frame_support::__private::scale_info::meta_type::(), + deprecation_info: #deprecation, + } + } + } ) } diff --git a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs index 7ebc4bb2e9dc..c6166ff45b19 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -83,9 +83,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> #pallet_ident<#type_use_gen> #config_where_clause { #[doc(hidden)] pub fn error_metadata() -> Option<#frame_support::__private::metadata_ir::PalletErrorMetadataIR> { - Some(#frame_support::__private::metadata_ir::PalletErrorMetadataIR { - ty: #frame_support::__private::scale_info::meta_type::<#error_ident<#type_use_gen>>() - }) + Some(<#error_ident<#type_use_gen>>::error_metadata()) } } ) @@ -187,7 +185,12 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } } ]; - + let deprecation_status = + match crate::deprecation::get_deprecation("e::quote! {#frame_support}, &def.item.attrs) + { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; quote::quote_spanned!(def.pallet_struct.attr_span => #pallet_error_metadata @@ -286,5 +289,13 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { #storage_info #whitelisted_storage_keys_impl + + impl<#type_use_gen> #pallet_ident<#type_use_gen> { + #[allow(dead_code)] + #[doc(hidden)] + pub fn deprecation_info() -> #frame_support::__private::metadata_ir::DeprecationStatusIR { + #deprecation_status + } + } ) } diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index 9abb3029bbd9..e5bfa2793cbb 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -62,7 +62,7 @@ fn check_prefix_duplicates( if let Some(other_dup_err) = used_prefixes.insert(prefix.clone(), dup_err.clone()) { let mut err = dup_err; err.combine(other_dup_err); - return Err(err) + return Err(err); } if let Metadata::CountedMap { .. } = storage_def.metadata { @@ -79,7 +79,7 @@ fn check_prefix_duplicates( if let Some(other_dup_err) = used_prefixes.insert(counter_prefix, counter_dup_err.clone()) { let mut err = counter_dup_err; err.combine(other_dup_err); - return Err(err) + return Err(err); } } @@ -152,7 +152,7 @@ pub fn process_generics(def: &mut Def) -> syn::Result syn::Result proc_macro2::TokenStream { .filter_map(|storage_def| check_prefix_duplicates(storage_def, &mut prefix_set).err()); if let Some(mut final_error) = errors.next() { errors.for_each(|error| final_error.combine(error)); - return final_error.into_compile_error() + return final_error.into_compile_error(); } let frame_support = &def.frame_support; let frame_system = &def.frame_system; let pallet_ident = &def.pallet_struct.pallet; - - let entries_builder = def.storages.iter().map(|storage| { + let mut entries_builder = vec![]; + for storage in def.storages.iter() { let no_docs = vec![]; let docs = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &storage.docs }; @@ -418,19 +418,26 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> ); let cfg_attrs = &storage.cfg_attrs; - - quote::quote_spanned!(storage.attr_span => + let deprecation = match crate::deprecation::get_deprecation( + "e::quote! { #frame_support }, + &storage.attrs, + ) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; + entries_builder.push(quote::quote_spanned!(storage.attr_span => #(#cfg_attrs)* { <#full_ident as #frame_support::storage::StorageEntryMetadataBuilder>::build_metadata( + #deprecation, #frame_support::__private::vec![ #( #docs, )* ], &mut entries, ); } - ) - }); + )) + } let getters = def.storages.iter().map(|storage| { if let Some(getter) = &storage.getter { diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 68c2cb8bd1b3..346dff46f12e 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -51,6 +51,8 @@ pub struct CallDef { pub docs: Vec, /// The optional `weight` attribute on the `pallet::call`. pub inherited_call_weight: Option, + /// attributes + pub attrs: Vec, } /// The weight of a call. @@ -124,7 +126,7 @@ impl syn::parse::Parse for FunctionAttr { let index = call_index_content.parse::()?; if !index.suffix().is_empty() { let msg = "Number literal must not have a suffix"; - return Err(syn::Error::new(index.span(), msg)) + return Err(syn::Error::new(index.span(), msg)); } Ok(FunctionAttr::CallIndex(index.base10_parse()?)) } else if lookahead.peek(keyword::feeless_if) { @@ -200,9 +202,9 @@ pub fn check_dispatchable_first_arg_type(ty: &syn::Type, is_ref: bool) -> syn::R } else { "Invalid type: expected `OriginFor` or `T::RuntimeOrigin`" }; - return Err(syn::Error::new(ty.span(), msg)) + return Err(syn::Error::new(ty.span(), msg)); }, - } + }; } impl CallDef { @@ -216,9 +218,8 @@ impl CallDef { let item_impl = if let syn::Item::Impl(item) = item { item } else { - return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl")) + return Err(syn::Error::new(item.span(), "Invalid pallet::call, expected item impl")); }; - let instances = vec![ helper::check_impl_gen(&item_impl.generics, item_impl.impl_token.span())?, helper::check_pallet_struct_usage(&item_impl.self_ty)?, @@ -227,7 +228,7 @@ impl CallDef { if let Some((_, _, for_)) = item_impl.trait_ { let msg = "Invalid pallet::call, expected no trait ident as in \ `impl<..> Pallet<..> { .. }`"; - return Err(syn::Error::new(for_.span(), msg)) + return Err(syn::Error::new(for_.span(), msg)); } let mut methods = vec![]; @@ -244,18 +245,18 @@ impl CallDef { _ => method.vis.span(), }; - return Err(syn::Error::new(span, msg)) + return Err(syn::Error::new(span, msg)); } match method.sig.inputs.first() { None => { let msg = "Invalid pallet::call, must have at least origin arg"; - return Err(syn::Error::new(method.sig.span(), msg)) + return Err(syn::Error::new(method.sig.span(), msg)); }, Some(syn::FnArg::Receiver(_)) => { let msg = "Invalid pallet::call, first argument must be a typed argument, \ e.g. `origin: OriginFor`"; - return Err(syn::Error::new(method.sig.span(), msg)) + return Err(syn::Error::new(method.sig.span(), msg)); }, Some(syn::FnArg::Typed(arg)) => { check_dispatchable_first_arg_type(&arg.ty, false)?; @@ -304,13 +305,13 @@ impl CallDef { }, _ => { let msg = "Invalid pallet::call, too many weight attributes given"; - return Err(syn::Error::new(method.sig.span(), msg)) + return Err(syn::Error::new(method.sig.span(), msg)); }, }; if call_idx_attrs.len() > 1 { let msg = "Invalid pallet::call, too many call_index attributes given"; - return Err(syn::Error::new(method.sig.span(), msg)) + return Err(syn::Error::new(method.sig.span(), msg)); } let call_index = call_idx_attrs.pop().map(|attr| match attr { FunctionAttr::CallIndex(idx) => idx, @@ -335,7 +336,7 @@ impl CallDef { ); let mut err = syn::Error::new(used_fn.span(), &msg); err.combine(syn::Error::new(method.sig.ident.span(), msg)); - return Err(err) + return Err(err); } let mut args = vec![]; @@ -351,14 +352,14 @@ impl CallDef { if arg_attrs.len() > 1 { let msg = "Invalid pallet::call, argument has too many attributes"; - return Err(syn::Error::new(arg.span(), msg)) + return Err(syn::Error::new(arg.span(), msg)); } let arg_ident = if let syn::Pat::Ident(pat) = &*arg.pat { pat.ident.clone() } else { let msg = "Invalid pallet::call, argument must be ident"; - return Err(syn::Error::new(arg.pat.span(), msg)) + return Err(syn::Error::new(arg.pat.span(), msg)); }; args.push((!arg_attrs.is_empty(), arg_ident, arg.ty.clone())); @@ -368,7 +369,7 @@ impl CallDef { if feeless_attrs.len() > 1 { let msg = "Invalid pallet::call, there can only be one feeless_if attribute"; - return Err(syn::Error::new(feeless_attrs[1].0, msg)) + return Err(syn::Error::new(feeless_attrs[1].0, msg)); } let feeless_check: Option = feeless_attrs.pop().map(|(_, attr)| match attr { @@ -380,13 +381,13 @@ impl CallDef { if feeless_check.inputs.len() != args.len() + 1 { let msg = "Invalid pallet::call, feeless_if closure must have same \ number of arguments as the dispatchable function"; - return Err(syn::Error::new(feeless_check.span(), msg)) + return Err(syn::Error::new(feeless_check.span(), msg)); } match feeless_check.inputs.first() { None => { let msg = "Invalid pallet::call, feeless_if closure must have at least origin arg"; - return Err(syn::Error::new(feeless_check.span(), msg)) + return Err(syn::Error::new(feeless_check.span(), msg)); }, Some(syn::Pat::Type(arg)) => { check_dispatchable_first_arg_type(&arg.ty, true)?; @@ -394,7 +395,7 @@ impl CallDef { _ => { let msg = "Invalid pallet::call, feeless_if closure first argument must be a typed argument, \ e.g. `origin: OriginFor`"; - return Err(syn::Error::new(feeless_check.span(), msg)) + return Err(syn::Error::new(feeless_check.span(), msg)); }, } @@ -405,18 +406,18 @@ impl CallDef { pat.elem.clone() } else { let msg = "Invalid pallet::call, feeless_if closure argument must be a reference"; - return Err(syn::Error::new(ty.span(), msg)) + return Err(syn::Error::new(ty.span(), msg)); } } else { let msg = "Invalid pallet::call, feeless_if closure argument must be a type ascription pattern"; - return Err(syn::Error::new(feeless_arg.span(), msg)) + return Err(syn::Error::new(feeless_arg.span(), msg)); }; if feeless_arg_type != arg.2 { let msg = "Invalid pallet::call, feeless_if closure argument must have \ a reference to the same type as the dispatchable function argument"; - return Err(syn::Error::new(feeless_arg.span(), msg)) + return Err(syn::Error::new(feeless_arg.span(), msg)); } } @@ -429,7 +430,7 @@ impl CallDef { }; if !valid_return { let msg = "Invalid pallet::call, feeless_if closure must return `bool`"; - return Err(syn::Error::new(feeless_check.output.span(), msg)) + return Err(syn::Error::new(feeless_check.output.span(), msg)); } } @@ -447,7 +448,7 @@ impl CallDef { }); } else { let msg = "Invalid pallet::call, only method accepted"; - return Err(syn::Error::new(item.span(), msg)) + return Err(syn::Error::new(item.span(), msg)); } } @@ -459,6 +460,7 @@ impl CallDef { where_clause: item_impl.generics.where_clause.clone(), docs: get_doc_literals(&item_impl.attrs), inherited_call_weight, + attrs: item_impl.attrs.clone(), }) } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 6febaac9ffa3..9a59d7114202 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -78,6 +78,8 @@ pub struct ConstMetadataDef { pub type_: syn::Type, /// The doc associated pub doc: Vec, + /// attributes + pub attrs: Vec, } impl TryFrom<&syn::TraitItemType> for ConstMetadataDef { @@ -100,22 +102,22 @@ impl TryFrom<&syn::TraitItemType> for ConstMetadataDef { .ok_or_else(|| err(trait_ty.span(), "`Get` trait bound not found"))?; let syn::PathArguments::AngleBracketed(ref ab) = bound.arguments else { - return Err(err(bound.span(), "Expected trait generic args")) + return Err(err(bound.span(), "Expected trait generic args")); }; // Only one type argument is expected. if ab.args.len() != 1 { - return Err(err(bound.span(), "Expected a single type argument")) + return Err(err(bound.span(), "Expected a single type argument")); } let syn::GenericArgument::Type(ref type_arg) = ab.args[0] else { - return Err(err(ab.args[0].span(), "Expected a type argument")) + return Err(err(ab.args[0].span(), "Expected a type argument")); }; let type_ = syn::parse2::(replace_self_by_t(type_arg.to_token_stream())) .expect("Internal error: replacing `Self` by `T` should result in valid type"); - Ok(Self { ident, type_, doc }) + Ok(Self { ident, type_, doc, attrs: trait_ty.attrs.clone() }) } } @@ -220,7 +222,7 @@ fn check_event_type( let syn::TraitItem::Type(type_) = trait_item else { return Ok(false) }; if type_.ident != "RuntimeEvent" { - return Ok(false) + return Ok(false); } // Check event has no generics @@ -228,7 +230,7 @@ fn check_event_type( let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must have\ no generics nor where_clause"; - return Err(syn::Error::new(trait_item.span(), msg)) + return Err(syn::Error::new(trait_item.span(), msg)); } // Check bound contains IsType and From @@ -242,7 +244,7 @@ fn check_event_type( "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ bound: `IsType<::RuntimeEvent>`" .to_string(); - return Err(syn::Error::new(type_.span(), msg)) + return Err(syn::Error::new(type_.span(), msg)); } let from_event_bound = type_ @@ -254,7 +256,7 @@ fn check_event_type( let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ bound: `From` or `From>` or `From>`"; - return Err(syn::Error::new(type_.span(), msg)) + return Err(syn::Error::new(type_.span(), msg)); }; if from_event_bound.is_generic && (from_event_bound.has_instance != trait_has_instance) { @@ -262,7 +264,7 @@ fn check_event_type( "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` bounds inconsistent \ `From`. Config and generic Event must be both with instance or \ without instance"; - return Err(syn::Error::new(type_.span(), msg)) + return Err(syn::Error::new(type_.span(), msg)); } Ok(true) @@ -274,7 +276,7 @@ fn check_event_type( 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 + return false; } let mut expected_system_config = @@ -329,12 +331,12 @@ impl ConfigDef { ) -> syn::Result { let syn::Item::Trait(item) = item else { let msg = "Invalid pallet::config, expected trait definition"; - return Err(syn::Error::new(item.span(), msg)) + return Err(syn::Error::new(item.span(), msg)); }; if !matches!(item.vis, syn::Visibility::Public(_)) { let msg = "Invalid pallet::config, trait must be public"; - return Err(syn::Error::new(item.span(), msg)) + return Err(syn::Error::new(item.span(), msg)); } syn::parse2::(item.ident.to_token_stream())?; @@ -349,7 +351,7 @@ impl ConfigDef { if item.generics.params.len() > 1 { let msg = "Invalid pallet::config, expected no more than one generic"; - return Err(syn::Error::new(item.generics.params[2].span(), msg)) + return Err(syn::Error::new(item.generics.params[2].span(), msg)); } let has_instance = if item.generics.params.first().is_some() { @@ -391,7 +393,7 @@ impl ConfigDef { return Err(syn::Error::new( pallet_attr._bracket.span.join(), "Duplicate #[pallet::constant] attribute not allowed.", - )) + )); } already_constant = true; consts_metadata.push(ConstMetadataDef::try_from(typ)?); @@ -407,13 +409,13 @@ impl ConfigDef { pallet_attr._bracket.span.join(), "`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \ has been specified" - )) + )); } if already_no_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), "Duplicate #[pallet::no_default] attribute not allowed.", - )) + )); } already_no_default = true; @@ -424,13 +426,13 @@ impl ConfigDef { pallet_attr._bracket.span.join(), "`#[pallet:no_default_bounds]` can only be used if `#[pallet::config(with_default)]` \ has been specified" - )) + )); } if already_no_default_bounds { return Err(syn::Error::new( pallet_attr._bracket.span.join(), "Duplicate #[pallet::no_default_bounds] attribute not allowed.", - )) + )); } already_no_default_bounds = true; }, @@ -472,7 +474,7 @@ impl ConfigDef { frame_system.to_token_stream(), found, ); - return Err(syn::Error::new(item.span(), msg)) + return Err(syn::Error::new(item.span(), msg)); } Ok(Self { diff --git a/substrate/frame/support/procedural/src/pallet/parse/error.rs b/substrate/frame/support/procedural/src/pallet/parse/error.rs index bc4087a0ea76..1a44e79cf0b8 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/error.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/error.rs @@ -53,6 +53,8 @@ pub struct ErrorDef { pub error: keyword::Error, /// The span of the pallet::error attribute. pub attr_span: proc_macro2::Span, + /// Attributes + pub attrs: Vec, } impl ErrorDef { @@ -102,6 +104,6 @@ impl ErrorDef { }) .collect::>()?; - Ok(ErrorDef { attr_span, index, variants, instances, error }) + Ok(ErrorDef { attr_span, index, variants, instances, error, attrs: item.attrs.clone() }) } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/event.rs b/substrate/frame/support/procedural/src/pallet/parse/event.rs index 0fb8ee4f5497..518a9597e2a0 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/event.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/event.rs @@ -43,6 +43,8 @@ pub struct EventDef { pub where_clause: Option, /// The span of the pallet::event attribute. pub attr_span: proc_macro2::Span, + /// event attributes + pub attrs: Vec, } /// Attribute for a pallet's Event. @@ -106,7 +108,7 @@ impl EventDef { } else { return Err(syn::Error::new(item.span(), "Invalid pallet::event, expected enum item")) }; - + let attrs = item.attrs.clone(); let event_attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; let attr_info = PalletEventAttrInfo::from_attrs(event_attrs)?; @@ -136,6 +138,15 @@ impl EventDef { let event = syn::parse2::(item.ident.to_token_stream())?; - Ok(EventDef { attr_span, index, instances, deposit_event, event, gen_kind, where_clause }) + Ok(EventDef { + attr_span, + index, + instances, + deposit_event, + event, + gen_kind, + where_clause, + attrs, + }) } } diff --git a/substrate/frame/support/procedural/src/pallet/parse/extra_constants.rs b/substrate/frame/support/procedural/src/pallet/parse/extra_constants.rs index 12a373db180c..d1960d8c6f01 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/extra_constants.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/extra_constants.rs @@ -51,6 +51,8 @@ pub struct ExtraConstantDef { pub doc: Vec, /// Optional MetaData Name pub metadata_name: Option, + /// Attributes + pub attrs: Vec, } /// Attributes for functions in extra_constants impl block. @@ -82,7 +84,7 @@ impl ExtraConstantsDef { return Err(syn::Error::new( item.span(), "Invalid pallet::extra_constants, expected item impl", - )) + )); }; let instances = vec![ @@ -93,7 +95,7 @@ impl ExtraConstantsDef { if let Some((_, _, for_)) = item.trait_ { let msg = "Invalid pallet::call, expected no trait ident as in \ `impl<..> Pallet<..> { .. }`"; - return Err(syn::Error::new(for_.span(), msg)) + return Err(syn::Error::new(for_.span(), msg)); } let mut extra_constants = vec![]; @@ -102,28 +104,28 @@ impl ExtraConstantsDef { method } else { let msg = "Invalid pallet::call, only method accepted"; - return Err(syn::Error::new(impl_item.span(), msg)) + return Err(syn::Error::new(impl_item.span(), msg)); }; if !method.sig.inputs.is_empty() { let msg = "Invalid pallet::extra_constants, method must have 0 args"; - return Err(syn::Error::new(method.sig.span(), msg)) + return Err(syn::Error::new(method.sig.span(), msg)); } if !method.sig.generics.params.is_empty() { let msg = "Invalid pallet::extra_constants, method must have 0 generics"; - return Err(syn::Error::new(method.sig.generics.params[0].span(), msg)) + return Err(syn::Error::new(method.sig.generics.params[0].span(), msg)); } if method.sig.generics.where_clause.is_some() { let msg = "Invalid pallet::extra_constants, method must have no where clause"; - return Err(syn::Error::new(method.sig.generics.where_clause.span(), msg)) + return Err(syn::Error::new(method.sig.generics.where_clause.span(), msg)); } let type_ = match &method.sig.output { syn::ReturnType::Default => { let msg = "Invalid pallet::extra_constants, method must have a return type"; - return Err(syn::Error::new(method.span(), msg)) + return Err(syn::Error::new(method.span(), msg)); }, syn::ReturnType::Type(_, type_) => *type_.clone(), }; @@ -135,7 +137,7 @@ impl ExtraConstantsDef { if extra_constant_attrs.len() > 1 { let msg = "Invalid attribute in pallet::constant_name, only one attribute is expected"; - return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg)) + return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg)); } let metadata_name = extra_constant_attrs.pop().map(|attr| attr.metadata_name); @@ -145,6 +147,7 @@ impl ExtraConstantsDef { type_, doc: get_doc_literals(&method.attrs), metadata_name, + attrs: method.attrs.clone(), }); } diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index f55b166c7917..b9c7afcab0f9 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -76,7 +76,6 @@ impl Def { pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result { 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 .content @@ -221,7 +220,7 @@ impl Def { genesis_config.as_ref().map_or("unused", |_| "used"), genesis_build.as_ref().map_or("unused", |_| "used"), ); - return Err(syn::Error::new(item_span, msg)) + return Err(syn::Error::new(item_span, msg)); } Self::resolve_tasks(&item_span, &mut tasks, &mut task_enum, items)?; @@ -284,7 +283,7 @@ impl Def { tasks.item_impl.impl_token.span(), "A `#[pallet::tasks_experimental]` attribute must be attached to your `Task` impl if the \ task enum has been omitted", - )) + )); } else { }, _ => (), @@ -313,7 +312,7 @@ impl Def { // `task_enum`. We use a no-op instead of simply removing it from the vec // so that any indices collected by `Def::try_from` remain accurate *item = syn::Item::Verbatim(quote::quote!()); - break + break; } } *task_enum = result; @@ -336,7 +335,7 @@ impl Def { let syn::Type::Path(target_path) = &*item_impl.self_ty else { continue }; let target_path = target_path.path.segments.iter().collect::>(); let (Some(target_ident), None) = (target_path.get(0), target_path.get(1)) else { - continue + continue; }; let matches_task_enum = match task_enum { Some(task_enum) => task_enum.item_enum.ident == target_ident.ident, @@ -344,7 +343,7 @@ impl Def { }; if trait_last_seg.ident == "Task" && matches_task_enum { result = Some(syn::parse2::(item_impl.to_token_stream())?); - break + break; } } *tasks = result; @@ -407,7 +406,7 @@ impl Def { let mut errors = instances.into_iter().filter_map(|instances| { if instances.has_instance == self.config.has_instance { - return None + return None; } let msg = if self.config.has_instance { "Invalid generic declaration, trait is defined with instance but generic use none" @@ -739,7 +738,7 @@ impl syn::parse::Parse for InheritedCallWeightAttr { content.parse::().expect("peeked"); content } else { - return Err(lookahead.error()) + return Err(lookahead.error()); }; Ok(Self { typename: buffer.parse()? }) diff --git a/substrate/frame/support/procedural/src/pallet/parse/storage.rs b/substrate/frame/support/procedural/src/pallet/parse/storage.rs index 9d96a18b5694..352f691151be 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/storage.rs @@ -207,6 +207,8 @@ pub struct StorageDef { pub try_decode: bool, /// Whether or not a default hasher is allowed to replace `_` pub use_default_hasher: bool, + /// Attributes + pub attrs: Vec, } /// The parsed generic from the @@ -373,7 +375,7 @@ fn process_named_generics( let msg = "Invalid pallet::storage, Duplicated named generic"; let mut err = syn::Error::new(arg.ident.span(), msg); err.combine(syn::Error::new(other.ident.span(), msg)); - return Err(err) + return Err(err); } parsed.insert(arg.ident.to_string(), arg.clone()); } @@ -666,7 +668,7 @@ fn process_generics( in order to expand metadata, found `{}`.", found, ); - return Err(syn::Error::new(segment.ident.span(), msg)) + return Err(syn::Error::new(segment.ident.span(), msg)); }, }; @@ -677,7 +679,7 @@ fn process_generics( _ => { let msg = "Invalid pallet::storage, invalid number of generic generic arguments, \ expect more that 0 generic arguments."; - return Err(syn::Error::new(segment.span(), msg)) + return Err(syn::Error::new(segment.span(), msg)); }, }; @@ -724,7 +726,7 @@ fn extract_key(ty: &syn::Type) -> syn::Result { typ } else { let msg = "Invalid pallet::storage, expected type path"; - return Err(syn::Error::new(ty.span(), msg)) + return Err(syn::Error::new(ty.span(), msg)); }; let key_struct = typ.path.segments.last().ok_or_else(|| { @@ -733,14 +735,14 @@ fn extract_key(ty: &syn::Type) -> syn::Result { })?; if key_struct.ident != "Key" && key_struct.ident != "NMapKey" { let msg = "Invalid pallet::storage, expected Key or NMapKey struct"; - return Err(syn::Error::new(key_struct.ident.span(), msg)) + return Err(syn::Error::new(key_struct.ident.span(), msg)); } let ty_params = if let syn::PathArguments::AngleBracketed(args) = &key_struct.arguments { args } else { let msg = "Invalid pallet::storage, expected angle bracketed arguments"; - return Err(syn::Error::new(key_struct.arguments.span(), msg)) + return Err(syn::Error::new(key_struct.arguments.span(), msg)); }; if ty_params.args.len() != 2 { @@ -749,14 +751,14 @@ fn extract_key(ty: &syn::Type) -> syn::Result { for Key struct, expected 2 args, found {}", ty_params.args.len() ); - return Err(syn::Error::new(ty_params.span(), msg)) + return Err(syn::Error::new(ty_params.span(), msg)); } let key = match &ty_params.args[1] { syn::GenericArgument::Type(key_ty) => key_ty.clone(), _ => { let msg = "Invalid pallet::storage, expected type"; - return Err(syn::Error::new(ty_params.args[1].span(), msg)) + return Err(syn::Error::new(ty_params.args[1].span(), msg)); }, }; @@ -790,7 +792,7 @@ impl StorageDef { let item = if let syn::Item::Type(item) = item { item } else { - return Err(syn::Error::new(item.span(), "Invalid pallet::storage, expect item type.")) + return Err(syn::Error::new(item.span(), "Invalid pallet::storage, expect item type.")); }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; @@ -810,12 +812,12 @@ impl StorageDef { typ } else { let msg = "Invalid pallet::storage, expected type path"; - return Err(syn::Error::new(item.ty.span(), msg)) + return Err(syn::Error::new(item.ty.span(), msg)); }; if typ.path.segments.len() != 1 { let msg = "Invalid pallet::storage, expected type path with one segment"; - return Err(syn::Error::new(item.ty.span(), msg)) + return Err(syn::Error::new(item.ty.span(), msg)); } let (named_generics, metadata, query_kind, use_default_hasher) = @@ -858,7 +860,7 @@ impl StorageDef { for ResultQuery, expected 1 type argument, found {}", args.len(), ); - return Err(syn::Error::new(args.span(), msg)) + return Err(syn::Error::new(args.span(), msg)); } args[0].clone() @@ -869,7 +871,7 @@ impl StorageDef { expected angle-bracketed arguments, found `{}`", args.to_token_stream().to_string() ); - return Err(syn::Error::new(args.span(), msg)) + return Err(syn::Error::new(args.span(), msg)); }, }; @@ -885,7 +887,7 @@ impl StorageDef { segments, found {}", err_variant.len(), ); - return Err(syn::Error::new(err_variant.span(), msg)) + return Err(syn::Error::new(err_variant.span(), msg)); } let mut error = err_variant.clone(); let err_variant = error @@ -921,7 +923,7 @@ impl StorageDef { let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \ identifiable. QueryKind must be `OptionQuery`, `ResultQuery`, `ValueQuery`, or default \ one to be identifiable."; - return Err(syn::Error::new(getter.span(), msg)) + return Err(syn::Error::new(getter.span(), msg)); } Ok(StorageDef { @@ -942,6 +944,7 @@ impl StorageDef { whitelisted, try_decode, use_default_hasher, + attrs: item.attrs.clone(), }) } } diff --git a/substrate/frame/support/procedural/src/runtime/parse/mod.rs b/substrate/frame/support/procedural/src/runtime/parse/mod.rs index a3d1c9417df8..27a7c35a7300 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/mod.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/mod.rs @@ -87,7 +87,7 @@ impl syn::parse::Parse for RuntimeAttr { let pallet_index = pallet_index_content.parse::()?; if !pallet_index.suffix().is_empty() { let msg = "Number literal must not have a suffix"; - return Err(syn::Error::new(pallet_index.span(), msg)) + return Err(syn::Error::new(pallet_index.span(), msg)); } Ok(RuntimeAttr::PalletIndex(pallet_index.span(), pallet_index.base10_parse()?)) } else if lookahead.peek(keyword::disable_call) { @@ -171,14 +171,14 @@ impl Def { Some((index, item.clone())) } else { let msg = "Invalid runtime::pallet_index, expected type definition"; - return Err(syn::Error::new(span, msg)) + return Err(syn::Error::new(span, msg)); }; }, RuntimeAttr::DisableCall(_) => disable_call = true, RuntimeAttr::DisableUnsigned(_) => disable_unsigned = true, attr => { let msg = "Invalid duplicated attribute"; - return Err(syn::Error::new(attr.span(), msg)) + return Err(syn::Error::new(attr.span(), msg)); }, } } @@ -196,7 +196,7 @@ impl Def { let mut err = syn::Error::new(used_pallet, &msg); err.combine(syn::Error::new(pallet_decl.name.span(), &msg)); - return Err(err) + return Err(err); } pallet_decls.push(pallet_decl); @@ -219,7 +219,7 @@ impl Def { ); let mut err = syn::Error::new(used_pallet.span(), &msg); err.combine(syn::Error::new(pallet.name.span(), msg)); - return Err(err) + return Err(err); } pallets.push(pallet); @@ -229,7 +229,7 @@ impl Def { } else { if let syn::Item::Type(item) = item { let msg = "Missing pallet index for pallet declaration. Please add `#[runtime::pallet_index(...)]`"; - return Err(syn::Error::new(item.span(), &msg)) + return Err(syn::Error::new(item.span(), &msg)); } } } diff --git a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs index ebfd0c9cccee..de1efa267c89 100644 --- a/substrate/frame/support/procedural/src/runtime/parse/pallet.rs +++ b/substrate/frame/support/procedural/src/runtime/parse/pallet.rs @@ -49,7 +49,7 @@ impl Pallet { return Err(Error::new( attr_span, "Invalid pallet declaration, expected a path or a trait object", - )) + )); }; } @@ -91,6 +91,7 @@ impl Pallet { cfg_pattern, pallet_parts, docs, + attrs: item.attrs.clone(), }) } } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index bd571571ee24..28283f2a5a06 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -1051,6 +1051,12 @@ pub mod pallet_prelude { /// [`StorageInfoTrait`](frame_support::traits::StorageInfoTrait) for the pallet using the /// [`PartialStorageInfoTrait`](frame_support::traits::PartialStorageInfoTrait) /// implementation of storages. +/// +/// ## Note on deprecation. +/// +/// - Usage of `deprecated` attribute will propagate deprecation information to the pallet +/// metadata. +/// - For general usage examples of `deprecated` attribute please refer to pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the `pallet::` macros @@ -1892,6 +1898,15 @@ pub mod pallet_macros { /// /// The macro also implements `From>` for `&'static str` and `From>` for /// `DispatchError`. + /// + /// ## Note on deprecation of Errors + /// + /// - Usage of `deprecated` attribute will propagate deprecation information to the pallet + /// metadata where the item was declared. + /// - For general usage examples of `deprecated` attribute please refer to + /// - It's possible to deprecated either certain variants inside the `Error` or the whole + /// `Error` itself. If both the `Error` and its variants are deprecated a compile error + /// will be returned. pub use frame_support_procedural::error; /// Allows defining pallet events. @@ -1933,6 +1948,15 @@ pub mod pallet_macros { /// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], [`codec::Encode`], /// [`codec::Decode`], and [`Debug`] (on std only). For ease of use, bound by the trait /// `Member`, available in [`frame_support::pallet_prelude`]. + /// + /// ## Note on deprecation of Events + /// + /// - Usage of `deprecated` attribute will propagate deprecation information to the pallet + /// metadata where the item was declared. + /// - For general usage examples of `deprecated` attribute please refer to + /// - It's possible to deprecated either certain variants inside the `Event` or the whole + /// `Event` itself. If both the `Event` and its variants are deprecated a compile error + /// will be returned. pub use frame_support_procedural::event; /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. @@ -2053,6 +2077,12 @@ pub mod pallet_macros { /// pub trait Config: frame_system::Config {} /// } /// ``` + /// + /// ## Note on deprecation of Calls + /// + /// - Usage of `deprecated` attribute will propagate deprecation information to the pallet + /// metadata where the item was declared. + /// - For general usage examples of `deprecated` attribute please refer to pub use frame_support_procedural::call; /// Enforce the index of a variant in the generated `enum Call`. @@ -2185,6 +2215,12 @@ pub mod pallet_macros { /// } /// } /// ``` + /// + /// ## Note on deprecation of constants + /// + /// - Usage of `deprecated` attribute will propagate deprecation information to the pallet + /// metadata where the item was declared. + /// - For general usage examples of `deprecated` attribute please refer to pub use frame_support_procedural::constant; /// Declares a type alias as a storage item. @@ -2403,6 +2439,12 @@ pub mod pallet_macros { /// pub type Foo = StorageValue<_, u32, ValueQuery>; /// } /// ``` + /// + /// ## Note on deprecation of storage items + /// + /// - Usage of `deprecated` attribute will propagate deprecation information to the pallet + /// metadata where the storage item was declared. + /// - For general usage examples of `deprecated` attribute please refer to pub use frame_support_procedural::storage; pub use frame_support_procedural::{ diff --git a/substrate/frame/support/src/storage/generator/map.rs b/substrate/frame/support/src/storage/generator/map.rs index 7a74308fdeac..e905df41a5a6 100644 --- a/substrate/frame/support/src/storage/generator/map.rs +++ b/substrate/frame/support/src/storage/generator/map.rs @@ -136,7 +136,7 @@ where loop { previous_key = Self::translate_next(previous_key, &mut f); if previous_key.is_none() { - break + break; } } } @@ -158,7 +158,7 @@ where "Invalid translation: failed to decode old value for key", array_bytes::bytes2hex("0x", ¤t_key) ); - return Some(current_key) + return Some(current_key); }, }; @@ -170,7 +170,7 @@ where "Invalid translation: failed to decode key", array_bytes::bytes2hex("0x", ¤t_key) ); - return Some(current_key) + return Some(current_key); }, }; diff --git a/substrate/frame/support/src/storage/types/counted_map.rs b/substrate/frame/support/src/storage/types/counted_map.rs index 9adcb33ae074..ae155eab5dd7 100644 --- a/substrate/frame/support/src/storage/types/counted_map.rs +++ b/substrate/frame/support/src/storage/types/counted_map.rs @@ -508,9 +508,14 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { - ::Map::build_metadata(docs, entries); + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { + ::Map::build_metadata(deprecation_status.clone(), docs, entries); CounterFor::::build_metadata( + deprecation_status, if cfg!(feature = "no-metadata-docs") { vec![] } else { @@ -1193,7 +1198,7 @@ mod test { fn test_metadata() { type A = CountedStorageMap; let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); + A::build_metadata(sp_metadata_ir::DeprecationStatusIR::NotDeprecated, vec![], &mut entries); assert_eq!( entries, vec![ @@ -1207,6 +1212,7 @@ mod test { }, default: 97u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "counter_for_foo", @@ -1218,6 +1224,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ] ); diff --git a/substrate/frame/support/src/storage/types/counted_nmap.rs b/substrate/frame/support/src/storage/types/counted_nmap.rs index 13c1b10be39c..45bd82ffe7e5 100644 --- a/substrate/frame/support/src/storage/types/counted_nmap.rs +++ b/substrate/frame/support/src/storage/types/counted_nmap.rs @@ -632,9 +632,14 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { - ::Map::build_metadata(docs, entries); + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { + ::Map::build_metadata(deprecation_status.clone(), docs, entries); CounterFor::::build_metadata( + deprecation_status, vec![&"Counter for the related counted storage map"], entries, ); @@ -859,8 +864,16 @@ mod test { assert_eq!(A::count(), 2); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -874,6 +887,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -885,6 +899,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -896,6 +911,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -907,6 +923,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ] ); @@ -1108,8 +1125,16 @@ mod test { assert_eq!(A::count(), 2); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -1126,6 +1151,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1137,6 +1163,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1151,6 +1178,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1162,6 +1190,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ] ); @@ -1394,8 +1423,16 @@ mod test { assert_eq!(A::count(), 2); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -1413,6 +1450,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1424,6 +1462,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1439,6 +1478,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1450,6 +1490,7 @@ mod test { } else { vec!["Counter for the related counted storage map"] }, + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ] ); diff --git a/substrate/frame/support/src/storage/types/double_map.rs b/substrate/frame/support/src/storage/types/double_map.rs index 3d227feb902f..c70d9de54467 100644 --- a/substrate/frame/support/src/storage/types/double_map.rs +++ b/substrate/frame/support/src/storage/types/double_map.rs @@ -732,7 +732,11 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; let entry = StorageEntryMetadataIR { @@ -745,6 +749,7 @@ where }, default: OnEmpty::get().encode(), docs, + deprecation_info: deprecation_status, }; entries.push(entry); @@ -985,8 +990,16 @@ mod test { assert_eq!(A::iter().collect::>(), vec![(4, 40, 1600), (3, 30, 900)]); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -1003,6 +1016,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated }, StorageEntryMetadataIR { name: "foo", @@ -1017,6 +1031,7 @@ mod test { }, default: 97u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated } ] ); diff --git a/substrate/frame/support/src/storage/types/map.rs b/substrate/frame/support/src/storage/types/map.rs index b70026eea50e..3582448c7dd5 100644 --- a/substrate/frame/support/src/storage/types/map.rs +++ b/substrate/frame/support/src/storage/types/map.rs @@ -490,7 +490,11 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; let entry = StorageEntryMetadataIR { @@ -503,6 +507,7 @@ where }, default: OnEmpty::get().encode(), docs, + deprecation_info: deprecation_status, }; entries.push(entry); @@ -791,8 +796,16 @@ mod test { assert_eq!(A::iter().collect::>(), vec![(3, 10)]); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -806,6 +819,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated }, StorageEntryMetadataIR { name: "foo", @@ -817,6 +831,7 @@ mod test { }, default: 97u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated } ] ); diff --git a/substrate/frame/support/src/storage/types/mod.rs b/substrate/frame/support/src/storage/types/mod.rs index b063e11621d6..b1c8a58fc8fb 100644 --- a/substrate/frame/support/src/storage/types/mod.rs +++ b/substrate/frame/support/src/storage/types/mod.rs @@ -141,7 +141,11 @@ where /// Implemented by each of the storage types: value, map, countedmap, doublemap and nmap. pub trait StorageEntryMetadataBuilder { /// Build into `entries` the storage metadata entries of a storage given some `docs`. - fn build_metadata(doc: Vec<&'static str>, entries: &mut Vec); + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + doc: Vec<&'static str>, + entries: &mut Vec, + ); } #[cfg(test)] diff --git a/substrate/frame/support/src/storage/types/nmap.rs b/substrate/frame/support/src/storage/types/nmap.rs index c3dfd5b3e48c..9ee012f86286 100755 --- a/substrate/frame/support/src/storage/types/nmap.rs +++ b/substrate/frame/support/src/storage/types/nmap.rs @@ -583,7 +583,11 @@ where OnEmpty: Get + 'static, MaxValues: Get>, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; let entry = StorageEntryMetadataIR { @@ -596,6 +600,7 @@ where }, default: OnEmpty::get().encode(), docs, + deprecation_info: deprecation_status, }; entries.push(entry); @@ -820,8 +825,16 @@ mod test { assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -835,6 +848,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -846,6 +860,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, } ] ); @@ -1020,8 +1035,16 @@ mod test { assert_eq!(A::iter().collect::>(), vec![((4, 40), 1600), ((3, 30), 900)]); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -1038,6 +1061,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1052,6 +1076,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, } ] ); @@ -1261,8 +1286,16 @@ mod test { assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 4), ((3, 30, 300), 3)]); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -1280,6 +1313,7 @@ mod test { }, default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Foo", @@ -1295,6 +1329,7 @@ mod test { }, default: 98u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, } ] ); diff --git a/substrate/frame/support/src/storage/types/value.rs b/substrate/frame/support/src/storage/types/value.rs index 9cc985b36d8c..69a8f3bb4b8c 100644 --- a/substrate/frame/support/src/storage/types/value.rs +++ b/substrate/frame/support/src/storage/types/value.rs @@ -277,7 +277,11 @@ where QueryKind: QueryKindTrait, OnEmpty: crate::traits::Get + 'static, { - fn build_metadata(docs: Vec<&'static str>, entries: &mut Vec) { + fn build_metadata( + deprecation_status: sp_metadata_ir::DeprecationStatusIR, + docs: Vec<&'static str>, + entries: &mut Vec, + ) { let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs }; let entry = StorageEntryMetadataIR { @@ -286,6 +290,7 @@ where ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: OnEmpty::get().encode(), docs, + deprecation_info: deprecation_status, }; entries.push(entry); @@ -415,8 +420,16 @@ mod test { assert_eq!(A::try_get(), Err(())); let mut entries = vec![]; - A::build_metadata(vec![], &mut entries); - AValueQueryWithAnOnEmpty::build_metadata(vec![], &mut entries); + A::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); + AValueQueryWithAnOnEmpty::build_metadata( + sp_metadata_ir::DeprecationStatusIR::NotDeprecated, + vec![], + &mut entries, + ); assert_eq!( entries, vec![ @@ -426,6 +439,7 @@ mod test { ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: Option::::None.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated }, StorageEntryMetadataIR { name: "foo", @@ -433,6 +447,7 @@ mod test { ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: 97u32.encode(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated } ] ); diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index a9f8ebdd63f2..5e1bcc777df4 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -14,6 +14,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(deprecated, clippy::deprecated_semver)] use super::*; use sp_io::{MultiRemovalResults, TestExternalities}; @@ -74,6 +75,10 @@ pub mod frame_system { #[pallet::no_default_bounds] type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; + #[pallet::constant] + #[pallet::no_default] + #[deprecated = "this constant is deprecated"] + type ExampleConstant: Get<()>; } #[pallet::error] @@ -97,11 +102,11 @@ pub mod frame_system { #[pallet::weight(task.weight())] pub fn do_task(_origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { if !task.is_valid() { - return Err(Error::::InvalidTask.into()) + return Err(Error::::InvalidTask.into()); } if let Err(_err) = task.run() { - return Err(Error::::FailedTask.into()) + return Err(Error::::FailedTask.into()); } Ok(().into()) @@ -109,18 +114,22 @@ pub mod frame_system { } #[pallet::storage] + #[deprecated] pub type Data = StorageMap<_, Twox64Concat, u32, u64, ValueQuery>; #[pallet::storage] + #[deprecated(note = "test")] pub type OptionLinkedMap = StorageMap<_, Blake2_128Concat, u32, u32, OptionQuery>; #[pallet::storage] #[pallet::getter(fn generic_data)] + #[deprecated(note = "test", since = "test")] pub type GenericData = StorageMap<_, Identity, BlockNumberFor, BlockNumberFor, ValueQuery>; #[pallet::storage] #[pallet::getter(fn generic_data2)] + #[deprecated = "test"] pub type GenericData2 = StorageMap<_, Blake2_128Concat, BlockNumberFor, BlockNumberFor, OptionQuery>; @@ -240,6 +249,7 @@ mod runtime { impl Config for Runtime { type Block = Block; type AccountId = AccountId; + type ExampleConstant = (); } fn new_test_ext() -> TestExternalities { @@ -585,6 +595,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::DeprecatedWithoutNote, }, StorageEntryMetadataIR { name: "OptionLinkedMap", @@ -596,6 +607,10 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::Deprecated { + note: "test", + since: None, + }, }, StorageEntryMetadataIR { name: "GenericData", @@ -607,6 +622,10 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0, 0, 0, 0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::Deprecated { + note: "test", + since: Some("test"), + }, }, StorageEntryMetadataIR { name: "GenericData2", @@ -618,6 +637,10 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::Deprecated { + note: "test", + since: None, + }, }, StorageEntryMetadataIR { name: "DataDM", @@ -629,6 +652,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "GenericDataDM", @@ -640,6 +664,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0, 0, 0, 0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "GenericData2DM", @@ -651,6 +676,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "AppendableDM", @@ -665,6 +691,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Total", @@ -672,6 +699,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<(u32, u32)>()), default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![" Some running total."], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Numbers", @@ -683,6 +711,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: vec![0], docs: vec![" Numbers to be added into the total."], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ], } @@ -694,6 +723,25 @@ fn store_metadata() { pretty_assertions::assert_eq!(expected_metadata(), metadata); } +#[test] +fn constant_metadata() { + let metadata: Vec = + Pallet::::pallet_constants_metadata(); + pretty_assertions::assert_eq!( + metadata, + vec![sp_metadata_ir::PalletConstantMetadataIR { + name: "ExampleConstant", + ty: scale_info::meta_type::<()>(), + value: vec![], + docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::Deprecated { + note: "this constant is deprecated", + since: None + } + },] + ); +} + parameter_types! { storage StorageParameter: u64 = 10; } diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 6f412fe89eab..0f7afb2b9901 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -34,3 +34,23 @@ help: consider importing one of these items | 18 + use frame_system::Event; | + +error[E0433]: failed to resolve: could not find `Event` in `pallet` + --> tests/construct_runtime_ui/undefined_event_part.rs:66:1 + | +66 | / construct_runtime! { +67 | | pub struct Runtime +68 | | { +69 | | System: frame_system expanded::{}::{Pallet, Call, Storage, Config, Event}, +70 | | Pallet: pallet expanded::{}::{Pallet, Event}, +71 | | } +72 | | } + | |_^ could not find `Event` in `pallet` + | + = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider importing one of these items + | +18 + use frame_support_test::Event; + | +18 + use frame_system::Event; + | diff --git a/substrate/frame/support/test/tests/enum_deprecation.rs b/substrate/frame/support/test/tests/enum_deprecation.rs new file mode 100644 index 000000000000..ed9b2b5a735d --- /dev/null +++ b/substrate/frame/support/test/tests/enum_deprecation.rs @@ -0,0 +1,173 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#![allow(useless_deprecated, deprecated, clippy::deprecated_semver)] + +use std::collections::BTreeMap; + +use frame_support::{ + derive_impl, + dispatch::Parameter, + parameter_types, + traits::{ConstU32, StorageVersion}, + OrdNoBound, PartialOrdNoBound, +}; +use scale_info::TypeInfo; + +parameter_types! { + /// Used to control if the storage version should be updated. + storage UpdateStorageVersion: bool = false; +} + +pub struct SomeType1; +impl From for u64 { + fn from(_t: SomeType1) -> Self { + 0u64 + } +} + +pub trait SomeAssociation1 { + type _1: Parameter + codec::MaxEncodedLen + TypeInfo; +} +impl SomeAssociation1 for u64 { + type _1 = u64; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(10); + + #[pallet::config] + pub trait Config: frame_system::Config + where + ::AccountId: From + SomeAssociation1, + { + type Balance: Parameter + Default + TypeInfo; + + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::error] + #[derive(PartialEq, Eq)] + pub enum Error { + /// error doc comment put in metadata + InsufficientProposersBalance, + NonExistentStorageValue, + Code(u8), + #[codec(skip)] + Skipped(u128), + CompactU8(#[codec(compact)] u8), + } + + #[pallet::event] + pub enum Event + where + T::AccountId: SomeAssociation1 + From, + { + #[deprecated = "second"] + A, + #[deprecated = "first"] + #[codec(index = 0)] + B, + } + + #[pallet::origin] + #[derive( + EqNoBound, + RuntimeDebugNoBound, + CloneNoBound, + PartialEqNoBound, + PartialOrdNoBound, + OrdNoBound, + Encode, + Decode, + TypeInfo, + MaxEncodedLen, + )] + pub struct Origin(PhantomData); +} + +frame_support::parameter_types!( + pub const MyGetParam3: u32 = 12; +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type MaxConsumers = ConstU32<16>; +} +impl pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = u64; +} + +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = + sp_runtime::testing::TestXt>; + +frame_support::construct_runtime!( + pub struct Runtime { + // Exclude part `Storage` in order not to check its metadata in tests. + System: frame_system exclude_parts { Pallet, Storage }, + Example: pallet, + + } +); + +#[test] +fn pallet_metadata() { + use sp_metadata_ir::{DeprecationInfoIR, DeprecationStatusIR}; + let pallets = Runtime::metadata_ir().pallets; + let example = pallets[0].clone(); + { + // Example pallet events are partially and fully deprecated + let meta = example.event.unwrap(); + assert_eq!( + // Result should be this, but instead we get the result below + // see: https://github.com/paritytech/parity-scale-codec/issues/507 + // + // DeprecationInfoIR::VariantsDeprecated(BTreeMap::from([ + // (codec::Compact(0), DeprecationStatusIR::Deprecated { note: "first", since: None + // }), ( + // codec::Compact(1), + // DeprecationStatusIR::Deprecated { note: "second", since: None } + // ) + // ])), + DeprecationInfoIR::VariantsDeprecated(BTreeMap::from([( + codec::Compact(0), + DeprecationStatusIR::Deprecated { note: "first", since: None } + ),])), + meta.deprecation_info + ); + } +} diff --git a/substrate/frame/support/test/tests/instance.rs b/substrate/frame/support/test/tests/instance.rs index 30b8338bc5c7..7f8423a0127e 100644 --- a/substrate/frame/support/test/tests/instance.rs +++ b/substrate/frame/support/test/tests/instance.rs @@ -441,6 +441,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { ty: StorageEntryTypeIR::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0], docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Map", @@ -452,6 +453,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: [0u8; 8].to_vec(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, StorageEntryMetadataIR { name: "DoubleMap", @@ -463,6 +465,7 @@ fn expected_metadata() -> PalletStorageMetadataIR { }, default: [0u8; 8].to_vec(), docs: vec![], + deprecation_info: sp_metadata_ir::DeprecationStatusIR::NotDeprecated, }, ], } diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index eed8a22e8e79..7f1ce0556eab 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -14,6 +14,9 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(useless_deprecated, deprecated, clippy::deprecated_semver)] + +use std::collections::BTreeMap; use frame_support::{ assert_ok, derive_impl, @@ -212,6 +215,7 @@ pub mod pallet { /// call foo doc comment put in metadata #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(*foo as u64, 0))] + #[deprecated = "test"] pub fn foo( origin: OriginFor, #[pallet::compact] foo: u32, @@ -272,6 +276,7 @@ pub mod pallet { pub enum Error { /// error doc comment put in metadata InsufficientProposersBalance, + #[deprecated = "test"] NonExistentStorageValue, Code(u8), #[codec(skip)] @@ -283,6 +288,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] + #[deprecated = "test"] pub enum Event where T::AccountId: SomeAssociation1 + From, @@ -486,7 +492,7 @@ pub mod pallet { let _ = T::AccountId::from(SomeType1); // Test for where clause let _ = T::AccountId::from(SomeType5); // Test for where clause if matches!(call, Call::foo_storage_layer { .. }) { - return Ok(ValidTransaction::default()) + return Ok(ValidTransaction::default()); } Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) } @@ -553,6 +559,7 @@ pub mod pallet { // Test that a pallet with non generic event and generic genesis_config is correctly handled // and that a pallet with the attribute without_storage_info is correctly handled. #[frame_support::pallet] +#[deprecated = "test"] pub mod pallet2 { use super::{SomeAssociation1, SomeType1, UpdateStorageVersion}; use frame_support::pallet_prelude::*; @@ -2478,3 +2485,56 @@ fn test_error_feature_parsing() { pallet::Error::__Ignore(_, _) => (), } } + +#[test] +fn pallet_metadata() { + use sp_metadata_ir::{DeprecationInfoIR, DeprecationStatusIR}; + let pallets = Runtime::metadata_ir().pallets; + let example = pallets[0].clone(); + let example2 = pallets[1].clone(); + { + // Example2 pallet is deprecated + assert_eq!( + &DeprecationStatusIR::Deprecated { note: "test", since: None }, + &example2.deprecation_info + ) + } + { + // Example pallet calls is fully and partially deprecated + let meta = &example.calls.unwrap(); + assert_eq!( + DeprecationInfoIR::VariantsDeprecated(BTreeMap::from([( + codec::Compact(0), + DeprecationStatusIR::Deprecated { note: "test", since: None } + )])), + meta.deprecation_info + ) + } + { + // Example pallet errors are partially and fully deprecated + let meta = &example.error.unwrap(); + assert_eq!( + DeprecationInfoIR::VariantsDeprecated(BTreeMap::from([( + codec::Compact(2), + DeprecationStatusIR::Deprecated { note: "test", since: None } + )])), + meta.deprecation_info + ) + } + { + // Example pallet events are partially and fully deprecated + let meta = example.event.unwrap(); + assert_eq!( + DeprecationInfoIR::ItemDeprecated(DeprecationStatusIR::Deprecated { + note: "test", + since: None + }), + meta.deprecation_info + ); + } + { + // Example2 pallet events are not deprecated + let meta = example2.event.unwrap(); + assert_eq!(DeprecationInfoIR::NotDeprecated, meta.deprecation_info); + } +} diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 48e4d975eb08..81377210eb43 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -14,11 +14,13 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +#![allow(useless_deprecated, deprecated, clippy::deprecated_semver)] use frame_support::{derive_impl, traits::ConstU32}; use scale_info::{form::MetaForm, meta_type}; use sp_metadata_ir::{ - RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, + DeprecationStatusIR, RuntimeApiMetadataIR, RuntimeApiMethodMetadataIR, + RuntimeApiMethodParamMetadataIR, }; use sp_runtime::traits::Block as BlockT; @@ -64,12 +66,16 @@ sp_api::decl_runtime_apis! { /// ApiWithCustomVersion trait documentation /// /// Documentation on multiline. + #[deprecated] pub trait Api { fn test(data: u64); /// something_with_block. fn something_with_block(block: Block) -> Block; + #[deprecated = "example"] fn function_with_two_args(data: u64, block: Block); + #[deprecated(note = "example", since = "example")] fn same_name(); + #[deprecated(note = "example")] fn wild_card(_: u32); } } @@ -128,6 +134,7 @@ fn runtime_metadata() { }], output: meta_type::<()>(), docs: vec![], + deprecation_info: DeprecationStatusIR::NotDeprecated, }, RuntimeApiMethodMetadataIR { name: "something_with_block", @@ -137,6 +144,7 @@ fn runtime_metadata() { }], output: meta_type::(), docs: maybe_docs(vec![" something_with_block."]), + deprecation_info: DeprecationStatusIR::NotDeprecated, }, RuntimeApiMethodMetadataIR { name: "function_with_two_args", @@ -152,13 +160,21 @@ fn runtime_metadata() { ], output: meta_type::<()>(), docs: vec![], + deprecation_info: DeprecationStatusIR::Deprecated { + note: "example", + since: None, + } }, RuntimeApiMethodMetadataIR { name: "same_name", inputs: vec![], output: meta_type::<()>(), docs: vec![], - }, + deprecation_info: DeprecationStatusIR::Deprecated { + note: "example", + since: Some("example"), + } + }, RuntimeApiMethodMetadataIR { name: "wild_card", inputs: vec![RuntimeApiMethodParamMetadataIR:: { @@ -167,6 +183,10 @@ fn runtime_metadata() { }], output: meta_type::<()>(), docs: vec![], + deprecation_info: DeprecationStatusIR::Deprecated { + note: "example", + since: None, + } }, ], docs: maybe_docs(vec![ @@ -174,6 +194,8 @@ fn runtime_metadata() { "", " Documentation on multiline.", ]), + deprecation_info: DeprecationStatusIR::DeprecatedWithoutNote, + }, RuntimeApiMetadataIR { name: "Core", @@ -183,6 +205,7 @@ fn runtime_metadata() { inputs: vec![], output: meta_type::(), docs: maybe_docs(vec![" Returns the version of the runtime."]), + deprecation_info: DeprecationStatusIR::NotDeprecated, }, RuntimeApiMethodMetadataIR { name: "execute_block", @@ -192,6 +215,8 @@ fn runtime_metadata() { }], output: meta_type::<()>(), docs: maybe_docs(vec![" Execute the given block."]), + deprecation_info: DeprecationStatusIR::NotDeprecated, + }, RuntimeApiMethodMetadataIR { name: "initialize_block", @@ -201,11 +226,13 @@ fn runtime_metadata() { }], output: meta_type::(), docs: maybe_docs(vec![" Initialize a block with the given header and return the runtime executive mode."]), + deprecation_info: DeprecationStatusIR::NotDeprecated, }, ], docs: maybe_docs(vec![ " The `Core` runtime api that every Substrate runtime needs to implement.", ]), + deprecation_info: DeprecationStatusIR::NotDeprecated, }, ]; diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index 2c423f8c28dd..21397abc8fc6 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -471,7 +471,7 @@ fn extend_with_api_version(mut trait_: Path, version: Option) -> Path { v } else { // nothing to do - return trait_ + return trait_; }; let trait_name = &mut trait_ @@ -762,7 +762,7 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result { error.combine(Error::new(other_span, "First trait implementation.")); - return Err(error) + return Err(error); } let id: Path = parse_quote!( #path ID ); @@ -892,7 +892,7 @@ fn extract_cfg_api_version(attrs: &Vec, span: Span) -> Result, span: Span) -> Result Each runtime API can have only one version.", API_VERSION_ATTRIBUTE ), - )) + )); } // Parse the runtime version if there exists one. diff --git a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs index 9944927d5573..4cba524dbe25 100644 --- a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs @@ -94,7 +94,7 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { let is_changed_in = method.attrs.iter().any(|attr| attr.path().is_ident(CHANGED_IN_ATTRIBUTE)); if is_changed_in { - continue + continue; } let mut inputs = Vec::new(); @@ -131,6 +131,10 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { // Include the method metadata only if its `cfg` features are enabled. let attrs = filter_cfg_attributes(&method.attrs); + let deprecation = match crate::utils::get_deprecation(&crate_, &method.attrs) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; methods.push(quote!( #( #attrs )* #crate_::metadata_ir::RuntimeApiMethodMetadataIR { @@ -138,6 +142,7 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { inputs: #crate_::vec![ #( #inputs, )* ], output: #output, docs: #docs, + deprecation_info: #deprecation, } )); } @@ -145,6 +150,10 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { let trait_name_ident = &decl.ident; let trait_name = trait_name_ident.to_string(); let docs = collect_docs(&decl.attrs, &crate_); + let deprecation = match crate::utils::get_deprecation(&crate_, &decl.attrs) { + Ok(deprecation) => deprecation, + Err(e) => return e.into_compile_error(), + }; let attrs = filter_cfg_attributes(&decl.attrs); // The trait generics where already extended with `Block: BlockT`. let mut generics = decl.generics.clone(); @@ -174,6 +183,7 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { name: #trait_name, methods: #crate_::vec![ #( #methods, )* ], docs: #docs, + deprecation_info: #deprecation, } } } @@ -187,7 +197,7 @@ pub fn generate_decl_runtime_metadata(decl: &ItemTrait) -> TokenStream2 { /// exposed by `generate_decl_runtime_metadata`. pub fn generate_impl_runtime_metadata(impls: &[ItemImpl]) -> Result { if impls.is_empty() { - return Ok(quote!()) + return Ok(quote!()); } let crate_ = generate_crate_access(); diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index 36577670a40c..94da6748cbdb 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -21,8 +21,9 @@ use proc_macro2::{Span, TokenStream}; use proc_macro_crate::{crate_name, FoundCrate}; use quote::{format_ident, quote}; use syn::{ - parse_quote, spanned::Spanned, token::And, Attribute, Error, FnArg, GenericArgument, Ident, - ImplItem, ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, + parse_quote, punctuated::Punctuated, spanned::Spanned, token::And, Attribute, Error, Expr, + ExprLit, FnArg, GenericArgument, Ident, ImplItem, ItemImpl, Lit, Meta, MetaNameValue, Pat, + Path, PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, }; /// Generates the access to the `sc_client` crate. @@ -33,7 +34,7 @@ pub fn generate_crate_access() -> TokenStream { let renamed_name = Ident::new(&renamed_name, Span::call_site()); quote!(#renamed_name::__private) }, - Err(e) => + Err(e) => { if let Ok(FoundCrate::Name(name)) = crate_name(&"polkadot-sdk-frame").or_else(|_| crate_name(&"frame")) { @@ -47,7 +48,8 @@ pub fn generate_crate_access() -> TokenStream { } else { let err = Error::new(Span::call_site(), e).to_compile_error(); quote!( #err ) - }, + } + }, } } @@ -144,7 +146,7 @@ pub fn extract_parameter_names_types_and_borrows( return Err(Error::new(input.span(), "`self` parameter not supported!")), FnArg::Receiver(recv) => if recv.mutability.is_some() || recv.reference.is_none() { - return Err(Error::new(recv.span(), "Only `&self` is supported!")) + return Err(Error::new(recv.span(), "Only `&self` is supported!")); }, } } @@ -284,6 +286,85 @@ pub fn filter_cfg_attributes(attrs: &[syn::Attribute]) -> Vec { attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect() } +fn deprecation_msg_formatter(msg: &str) -> String { + format!( + r#"{msg} + help: the following are the possible correct uses +| +| #[deprecated = "reason"] +| +| #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] +| +| #[deprecated] +|"# + ) +} + +fn parse_deprecated_meta(crate_: &TokenStream, attr: &syn::Attribute) -> Result { + match &attr.meta { + Meta::List(meta_list) => { + let parsed = meta_list + .parse_args_with(Punctuated::::parse_terminated) + .map_err(|e| Error::new(attr.span(), e.to_string()))?; + let (note, since) = parsed.iter().try_fold((None, None), |mut acc, item| { + let value = match &item.value { + Expr::Lit(ExprLit { lit: lit @ Lit::Str(_), .. }) => Ok(lit), + _ => Err(Error::new( + attr.span(), + deprecation_msg_formatter( + "Invalid deprecation attribute: expected string literal", + ), + )), + }?; + if item.path.is_ident("note") { + acc.0.replace(value); + } else if item.path.is_ident("since") { + acc.1.replace(value); + } + Ok::<(Option<&syn::Lit>, Option<&syn::Lit>), Error>(acc) + })?; + note.map_or_else( + || Err(Error::new(attr.span(), deprecation_msg_formatter( + "Invalid deprecation attribute: missing `note`"))), + |note| { + let since = if let Some(str) = since { + quote! { Some(#str) } + } else { + quote! { None } + }; + let doc = quote! { #crate_::metadata_ir::DeprecationStatusIR::Deprecated { note: #note, since: #since }}; + Ok(doc) + }, + ) + }, + Meta::NameValue(MetaNameValue { + value: Expr::Lit(ExprLit { lit: lit @ Lit::Str(_), .. }), + .. + }) => { + // #[deprecated = "lit"] + let doc = quote! { #crate_::metadata_ir::DeprecationStatusIR::Deprecated { note: #lit, since: None } }; + Ok(doc) + }, + Meta::Path(_) => { + // #[deprecated] + Ok(quote! { #crate_::metadata_ir::DeprecationStatusIR::DeprecatedWithoutNote }) + }, + _ => Err(Error::new( + attr.span(), + deprecation_msg_formatter("Invalid deprecation attribute: expected string literal"), + )), + } +} + +/// collects deprecation attribute if its present. +pub fn get_deprecation(crate_: &TokenStream, attrs: &[syn::Attribute]) -> Result { + attrs + .iter() + .find(|a| a.path().is_ident("deprecated")) + .map(|a| parse_deprecated_meta(&crate_, a)) + .unwrap_or_else(|| Ok(quote! {#crate_::metadata_ir::DeprecationStatusIR::NotDeprecated})) +} + #[cfg(test)] mod tests { use assert_matches::assert_matches; @@ -330,4 +411,38 @@ mod tests { assert_eq!(cfg_std, filtered[0]); assert_eq!(cfg_benchmarks, filtered[1]); } + + #[test] + fn check_deprecated_attr() { + const FIRST: &'static str = "hello"; + const SECOND: &'static str = "WORLD"; + + let simple: Attribute = parse_quote!(#[deprecated]); + let simple_path: Attribute = parse_quote!(#[deprecated = #FIRST]); + let meta_list: Attribute = parse_quote!(#[deprecated(note = #FIRST)]); + let meta_list_with_since: Attribute = + parse_quote!(#[deprecated(note = #FIRST, since = #SECOND)]); + let extra_fields: Attribute = + parse_quote!(#[deprecated(note = #FIRST, since = #SECOND, extra = "Test")]); + assert_eq!( + get_deprecation("e! { crate }, &[simple]).unwrap().to_string(), + quote! { crate::metadata_ir::DeprecationStatusIR::DeprecatedWithoutNote }.to_string() + ); + assert_eq!( + get_deprecation("e! { crate }, &[simple_path]).unwrap().to_string(), + quote! { crate::metadata_ir::DeprecationStatusIR::Deprecated { note: #FIRST, since: None } }.to_string() + ); + assert_eq!( + get_deprecation("e! { crate }, &[meta_list]).unwrap().to_string(), + quote! { crate::metadata_ir::DeprecationStatusIR::Deprecated { note: #FIRST, since: None } }.to_string() + ); + assert_eq!( + get_deprecation("e! { crate }, &[meta_list_with_since]).unwrap().to_string(), + quote! { crate::metadata_ir::DeprecationStatusIR::Deprecated { note: #FIRST, since: Some(#SECOND) }}.to_string() + ); + assert_eq!( + get_deprecation("e! { crate }, &[extra_fields]).unwrap().to_string(), + quote! { crate::metadata_ir::DeprecationStatusIR::Deprecated { note: #FIRST, since: Some(#SECOND) }}.to_string() + ); + } } diff --git a/substrate/primitives/api/src/lib.rs b/substrate/primitives/api/src/lib.rs index 4b5c35562bde..700e212688c8 100644 --- a/substrate/primitives/api/src/lib.rs +++ b/substrate/primitives/api/src/lib.rs @@ -258,6 +258,11 @@ pub const MAX_EXTRINSIC_DEPTH: u32 = 256; /// ``` /// Note that the latest version (4 in our example above) always contains all methods from all /// the versions before. +/// +/// ## Note on deprecation. +/// +/// - Usage of `deprecated` attribute will propagate deprecation information to the metadata. +/// - For general usage examples of `deprecated` attribute please refer to pub use sp_api_proc_macro::decl_runtime_apis; /// Tags given trait implementations as runtime apis. diff --git a/substrate/primitives/api/test/tests/ui/deprecation_info.rs b/substrate/primitives/api/test/tests/ui/deprecation_info.rs new file mode 100644 index 000000000000..61f93fcd921d --- /dev/null +++ b/substrate/primitives/api/test/tests/ui/deprecation_info.rs @@ -0,0 +1,29 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +sp_api::decl_runtime_apis! { + pub trait Api { + #[deprecated(unknown_kw = "test")] + fn test(); + #[deprecated(since = 5)] + fn test2(); + #[deprecated = 5] + fn test3(); + } +} + +fn main() {} diff --git a/substrate/primitives/api/test/tests/ui/deprecation_info.stderr b/substrate/primitives/api/test/tests/ui/deprecation_info.stderr new file mode 100644 index 000000000000..2466c3ea5d50 --- /dev/null +++ b/substrate/primitives/api/test/tests/ui/deprecation_info.stderr @@ -0,0 +1,25 @@ +error: Invalid deprecation attribute: missing `note` + help: the following are the possible correct uses + | + | #[deprecated = "reason"] + | + | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | + | #[deprecated] + | + --> tests/ui/deprecation_info.rs:20:3 + | +20 | #[deprecated(unknown_kw = "test")] + | ^ + +error[E0541]: unknown meta item 'unknown_kw' + --> tests/ui/deprecation_info.rs:20:16 + | +20 | #[deprecated(unknown_kw = "test")] + | ^^^^^^^^^^^^^^^^^^^ expected one of `since`, `note` + +error[E0565]: literal in `deprecated` value must be a string + --> tests/ui/deprecation_info.rs:22:24 + | +22 | #[deprecated(since = 5)] + | ^ diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index b05f26ff55d4..4ebe8c25a675 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use codec::Encode; +use codec::{Compact, Encode}; use scale_info::{ form::{Form, MetaForm, PortableForm}, - prelude::vec::Vec, - IntoPortable, MetaType, Registry, + prelude::{collections::BTreeMap, vec::Vec}, + IntoPortable, Registry, }; /// The intermediate representation for the runtime metadata. @@ -52,6 +52,8 @@ pub struct RuntimeApiMetadataIR { pub methods: Vec>, /// Trait documentation. pub docs: Vec, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR, } impl IntoPortable for RuntimeApiMetadataIR { @@ -62,6 +64,7 @@ impl IntoPortable for RuntimeApiMetadataIR { name: self.name.into_portable(registry), methods: registry.map_into_portable(self.methods), docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } @@ -77,6 +80,8 @@ pub struct RuntimeApiMethodMetadataIR { pub output: T::Type, /// Method documentation. pub docs: Vec, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR, } impl IntoPortable for RuntimeApiMethodMetadataIR { @@ -88,6 +93,7 @@ impl IntoPortable for RuntimeApiMethodMetadataIR { inputs: registry.map_into_portable(self.inputs), output: registry.register_type(&self.output), docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } @@ -132,6 +138,8 @@ pub struct PalletMetadataIR { pub index: u8, /// Pallet documentation. pub docs: Vec, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR, } impl IntoPortable for PalletMetadataIR { @@ -147,6 +155,7 @@ impl IntoPortable for PalletMetadataIR { error: self.error.map(|error| error.into_portable(registry)), index: self.index, docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } @@ -245,6 +254,8 @@ pub struct StorageEntryMetadataIR { pub default: Vec, /// Storage entry documentation. pub docs: Vec, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR, } impl IntoPortable for StorageEntryMetadataIR { @@ -257,6 +268,7 @@ impl IntoPortable for StorageEntryMetadataIR { ty: self.ty.into_portable(registry), default: self.default, docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } @@ -331,19 +343,18 @@ impl IntoPortable for StorageEntryTypeIR { pub struct PalletCallMetadataIR { /// The corresponding enum type for the pallet call. pub ty: T::Type, + /// Deprecation status of the pallet call + pub deprecation_info: DeprecationInfoIR, } impl IntoPortable for PalletCallMetadataIR { type Output = PalletCallMetadataIR; fn into_portable(self, registry: &mut Registry) -> Self::Output { - PalletCallMetadataIR { ty: registry.register_type(&self.ty) } - } -} - -impl From for PalletCallMetadataIR { - fn from(ty: MetaType) -> Self { - Self { ty } + PalletCallMetadataIR { + ty: registry.register_type(&self.ty), + deprecation_info: self.deprecation_info.into_portable(registry), + } } } @@ -352,19 +363,18 @@ impl From for PalletCallMetadataIR { pub struct PalletEventMetadataIR { /// The Event type. pub ty: T::Type, + /// Deprecation info of the event + pub deprecation_info: DeprecationInfoIR, } impl IntoPortable for PalletEventMetadataIR { type Output = PalletEventMetadataIR; fn into_portable(self, registry: &mut Registry) -> Self::Output { - PalletEventMetadataIR { ty: registry.register_type(&self.ty) } - } -} - -impl From for PalletEventMetadataIR { - fn from(ty: MetaType) -> Self { - Self { ty } + PalletEventMetadataIR { + ty: registry.register_type(&self.ty), + deprecation_info: self.deprecation_info.into_portable(registry), + } } } @@ -379,6 +389,8 @@ pub struct PalletConstantMetadataIR { pub value: Vec, /// Documentation of the constant. pub docs: Vec, + /// Deprecation info + pub deprecation_info: DeprecationStatusIR, } impl IntoPortable for PalletConstantMetadataIR { @@ -390,6 +402,7 @@ impl IntoPortable for PalletConstantMetadataIR { ty: registry.register_type(&self.ty), value: self.value, docs: registry.map_into_portable(self.docs), + deprecation_info: self.deprecation_info.into_portable(registry), } } } @@ -399,19 +412,18 @@ impl IntoPortable for PalletConstantMetadataIR { pub struct PalletErrorMetadataIR { /// The error type information. pub ty: T::Type, + /// Deprecation info + pub deprecation_info: DeprecationInfoIR, } impl IntoPortable for PalletErrorMetadataIR { type Output = PalletErrorMetadataIR; fn into_portable(self, registry: &mut Registry) -> Self::Output { - PalletErrorMetadataIR { ty: registry.register_type(&self.ty) } - } -} - -impl From for PalletErrorMetadataIR { - fn from(ty: MetaType) -> Self { - Self { ty } + PalletErrorMetadataIR { + ty: registry.register_type(&self.ty), + deprecation_info: self.deprecation_info.into_portable(registry), + } } } @@ -451,3 +463,61 @@ impl IntoPortable for OuterEnumsIR { } } } + +/// Deprecation status for an entry inside MetadataIR +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub enum DeprecationStatusIR { + /// Entry is not deprecated + NotDeprecated, + /// Deprecated without a note. + DeprecatedWithoutNote, + /// Entry is deprecated with an note and an optional `since` field. + Deprecated { + /// Note explaining the deprecation + note: T::String, + /// Optional value for denoting version when the deprecation occured + since: Option, + }, +} +impl IntoPortable for DeprecationStatusIR { + type Output = DeprecationStatusIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + match self { + Self::Deprecated { note, since } => { + let note = note.into_portable(registry); + let since = since.map(|x| x.into_portable(registry)); + DeprecationStatusIR::Deprecated { note, since } + }, + Self::DeprecatedWithoutNote => DeprecationStatusIR::DeprecatedWithoutNote, + Self::NotDeprecated => DeprecationStatusIR::NotDeprecated, + } + } +} +/// Deprecation info for an enums/errors/calls. +/// Denotes full/partial deprecation of the type +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub enum DeprecationInfoIR { + /// Type is not deprecated + NotDeprecated, + /// Entry is fully deprecated. + ItemDeprecated(DeprecationStatusIR), + /// Entry is partially deprecated. + VariantsDeprecated(BTreeMap, DeprecationStatusIR>), +} +impl IntoPortable for DeprecationInfoIR { + type Output = DeprecationInfoIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + match self { + Self::VariantsDeprecated(entries) => { + let entries = + entries.into_iter().map(|(k, entry)| (k, entry.into_portable(registry))); + DeprecationInfoIR::VariantsDeprecated(entries.collect()) + }, + Self::ItemDeprecated(deprecation) => + DeprecationInfoIR::ItemDeprecated(deprecation.into_portable(registry)), + Self::NotDeprecated => DeprecationInfoIR::NotDeprecated, + } + } +}