From eb28e1230ba4c4b93775eab43723a86885e592c4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 22 Jul 2021 13:06:36 +0100 Subject: [PATCH] Improve docs feature (#116) * Improve doc parsing, attempt to prevent escaped chars * parse_quote lit * Test for docs attr * Fix docs attr stripping * Docs feature disabled, don't capture docs via inline fn * Fix docs feature * Missing feature attribute * Fmt * Move comment on docs fn * Fix UI test * Docs feature not enabled by default --- Cargo.toml | 2 +- derive/src/lib.rs | 20 +++++++--------- src/build.rs | 24 +++++++++++++++++++ test_suite/tests/derive.rs | 15 ++++++++++++ .../tests/ui/fail_missing_derive.stderr | 9 ++++++- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fffd641b..d97ebbb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ derive_more = { version = "0.99.1", default-features = false, features = ["from" scale = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive"] } [features] -default = ["std", "docs"] +default = ["std"] std = [ "bitvec/std", "scale/std", diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 88fa7f0d..6084d459 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -306,19 +306,20 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea } } -#[cfg(feature = "docs")] fn generate_docs(attrs: &[syn::Attribute]) -> Option { let docs = attrs .iter() .filter_map(|attr| { if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { if meta.path.get_ident().map_or(false, |ident| ident == "doc") { - let lit = &meta.lit; - let doc_lit = quote!(#lit).to_string(); - let trimmed_doc_lit = - doc_lit.trim_start_matches(r#"" "#).trim_end_matches('"'); - let lit: syn::Lit = parse_quote!(#trimmed_doc_lit); - Some(lit) + if let syn::Lit::Str(lit) = &meta.lit { + let lit_value = lit.value(); + let stripped = lit_value.strip_prefix(' ').unwrap_or(&lit_value); + let lit: syn::Lit = parse_quote!(#stripped); + Some(lit) + } else { + None + } } else { None } @@ -332,8 +333,3 @@ fn generate_docs(attrs: &[syn::Attribute]) -> Option { .docs(&[ #( #docs ),* ]) }) } - -#[cfg(not(feature = "docs"))] -fn generate_docs(_: &[syn::Attribute]) -> Option { - None -} diff --git a/src/build.rs b/src/build.rs index 43293211..c546e6ca 100644 --- a/src/build.rs +++ b/src/build.rs @@ -210,11 +210,19 @@ impl TypeBuilder { self } + #[cfg(feature = "docs")] /// Set the type documentation pub fn docs(mut self, docs: &[&'static str]) -> Self { self.docs = docs.to_vec(); self } + + #[cfg(not(feature = "docs"))] + #[inline] + /// Doc capture is not enabled via the "docs" feature so this is a no-op. + pub fn docs(self, _docs: &'static [&'static str]) -> Self { + self + } } /// A fields builder has no fields (e.g. a unit struct) @@ -400,6 +408,7 @@ impl FieldBuilder { } } + #[cfg(feature = "docs")] /// Initialize the documentation of a field (optional). pub fn docs(self, docs: &'static [&'static str]) -> FieldBuilder { FieldBuilder { @@ -410,6 +419,13 @@ impl FieldBuilder { marker: PhantomData, } } + + #[cfg(not(feature = "docs"))] + #[inline] + /// Doc capture is not enabled via the "docs" feature so this is a no-op. + pub fn docs(self, _docs: &'static [&'static str]) -> FieldBuilder { + self + } } impl FieldBuilder { @@ -518,11 +534,19 @@ impl VariantBuilder { self } + #[cfg(feature = "docs")] /// Initialize the variant's documentation. pub fn docs(mut self, docs: &[&'static str]) -> Self { self.docs = docs.to_vec(); self } + + #[cfg(not(feature = "docs"))] + #[inline] + /// Doc capture is not enabled via the "docs" feature so this is a no-op. + pub fn docs(self, _docs: &[&'static str]) -> Self { + self + } } impl VariantBuilder { diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index dbd9c355..a368c955 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -733,6 +733,21 @@ fn skip_type_params_with_defaults() { assert_type!(SkipAllTypeParamsWithDefaults, ty); } +#[test] +fn docs_attr() { + #[allow(unused)] + #[derive(TypeInfo)] + #[doc = "Docs attr"] + pub struct S; + + let ty = Type::builder() + .path(Path::new("S", "derive")) + .docs(&["Docs attr"]) + .composite(Fields::unit()); + + assert_type!(S, ty); +} + #[rustversion::nightly] #[test] fn ui_tests() { diff --git a/test_suite/tests/ui/fail_missing_derive.stderr b/test_suite/tests/ui/fail_missing_derive.stderr index 54501aa1..76bcd521 100644 --- a/test_suite/tests/ui/fail_missing_derive.stderr +++ b/test_suite/tests/ui/fail_missing_derive.stderr @@ -7,4 +7,11 @@ error[E0277]: the trait bound `PawType: TypeInfo` is not satisfied 17 | assert_type_info::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TypeInfo` is not implemented for `PawType` | - = note: required because of the requirements on the impl of `TypeInfo` for `Cat` +note: required because of the requirements on the impl of `TypeInfo` for `Cat` + --> $DIR/fail_missing_derive.rs:7:10 + | +7 | #[derive(TypeInfo)] + | ^^^^^^^^ +8 | struct Cat { + | ^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `TypeInfo` (in Nightly builds, run with -Z macro-backtrace for more info)