diff --git a/codegen/src/ir.rs b/codegen/src/ir.rs index 30faa92294..59bc53c5a9 100644 --- a/codegen/src/ir.rs +++ b/codegen/src/ir.rs @@ -23,7 +23,6 @@ use syn::{ #[derive(Debug, PartialEq, Eq)] pub struct ItemMod { - // attrs: Vec, vis: syn::Visibility, mod_token: token::Mod, pub ident: syn::Ident, @@ -103,6 +102,26 @@ impl From for Item { if let Some(attr) = substitute_attrs.get(0) { let use_path = &use_.tree; let substitute_with: syn::TypePath = syn::parse_quote!( #use_path ); + + let is_crate = substitute_with + .path + .segments + .first() + .map(|segment| segment.ident == "crate") + .unwrap_or(false); + + // Check if the substitute path is a global absolute path, meaning it + // is prefixed with `::` or `crate`. + // + // Note: the leading colon is lost when parsing to `syn::TypePath` via + // `syn::parse_quote!`. Therefore, inspect `use_`'s leading colon. + if use_.leading_colon.is_none() && !is_crate { + abort!( + use_path.span(), + "The substitute path must be a global absolute path; try prefixing with `::` or `crate`" + ) + } + let type_substitute = SubxtItem::TypeSubstitute { generated_type_path: attr.substitute_type(), substitute_with, diff --git a/testing/test-runtime/build.rs b/testing/test-runtime/build.rs index acff4a9641..88937c61e5 100644 --- a/testing/test-runtime/build.rs +++ b/testing/test-runtime/build.rs @@ -108,7 +108,7 @@ async fn run() { )] pub mod node_runtime {{ #[subxt(substitute_type = "sp_arithmetic::per_things::Perbill")] - use sp_runtime::Perbill; + use ::sp_runtime::Perbill; }} "#, metadata_path diff --git a/testing/ui-tests/src/incorrect/substitute_path_not_absolute.rs b/testing/ui-tests/src/incorrect/substitute_path_not_absolute.rs new file mode 100644 index 0000000000..98424f05bc --- /dev/null +++ b/testing/ui-tests/src/incorrect/substitute_path_not_absolute.rs @@ -0,0 +1,7 @@ +#[subxt::subxt(runtime_metadata_path = "../../../artifacts/polkadot_metadata.scale")] +pub mod node_runtime { + #[subxt::subxt(substitute_type = "sp_arithmetic::per_things::Perbill")] + use sp_runtime::Perbill; +} + +fn main() {} diff --git a/testing/ui-tests/src/incorrect/substitute_path_not_absolute.stderr b/testing/ui-tests/src/incorrect/substitute_path_not_absolute.stderr new file mode 100644 index 0000000000..6e8f863a37 --- /dev/null +++ b/testing/ui-tests/src/incorrect/substitute_path_not_absolute.stderr @@ -0,0 +1,5 @@ +error: The substitute path must be a global absolute path; try prefixing with `::` or `crate` + --> src/incorrect/substitute_path_not_absolute.rs:4:9 + | +4 | use sp_runtime::Perbill; + | ^^^^^^^^^^ diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs index bced80fc0c..f63ed64de3 100644 --- a/testing/ui-tests/src/lib.rs +++ b/testing/ui-tests/src/lib.rs @@ -15,6 +15,14 @@ // along with subxt. If not, see . #![cfg(test)] +//! UI test set uses [`trybuild`](https://docs.rs/trybuild/latest/trybuild/index.html) to +//! check whether expected valid examples of code compile correctly, and for incorrect ones +//! errors are helpful and valid (e.g. have correct spans). +//! +//! +//! Use with `TRYBUILD=overwrite` after updating codebase (see `trybuild` docs for more details on that) +//! to automatically regenerate `stderr` files, but don't forget to check that new files make sense. + mod dispatch_errors; mod storage; mod utils; @@ -49,3 +57,9 @@ fn ui_tests() { dispatch_errors::metadata_array_dispatch_error(), )); } + +#[test] +fn ui_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("src/incorrect/*.rs"); +}