Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix foreign derive proc macro attributes clashing with Veil's #40

Merged
merged 4 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 12 additions & 15 deletions veil-macros/src/flags.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::num::NonZeroU8;

use syn::spanned::Spanned;

#[derive(Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -45,14 +44,14 @@ impl FieldFlags {
let mut head = 0;

for attr in attrs {
if let Some(flags) = Self::parse(attr)? {
if head == AMOUNT {
return Err(syn::Error::new(
attr.span(),
"too many `#[redact(...)]` attributes specified",
));
}
if head == AMOUNT {
return Err(syn::Error::new(
attr.span(),
"too many `#[redact(...)]` attributes specified",
));
}

if let Some(flags) = Self::parse(attr)? {
if flags.skip {
if !skip_allowed {
return Err(syn::Error::new(attr.span(), "`#[redact(skip)]` is not allowed here"));
Expand Down Expand Up @@ -87,16 +86,14 @@ impl FieldFlags {
// The modifiers could be a single value or a list, so we need to handle both cases.
let modifiers = match attr.parse_meta()? {
// List
syn::Meta::List(syn::MetaList { path, nested, .. }) if path.is_ident("redact") => {
nested.into_iter().filter_map(|meta| match meta {
syn::NestedMeta::Meta(meta) => Some(meta),
_ => None,
})
}
syn::Meta::List(syn::MetaList { nested, .. }) => nested.into_iter().filter_map(|meta| match meta {
syn::NestedMeta::Meta(meta) => Some(meta),
_ => None,
}),

// Single value
meta => match meta {
syn::Meta::Path(path) if path.is_ident("redact") => return Ok(Some(flags)),
syn::Meta::Path(_) => return Ok(Some(flags)),
_ => return Ok(None),
},
};
Expand Down
8 changes: 7 additions & 1 deletion veil-macros/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl FormatData<'_> {
// Parse field flags from attributes on this field
let field_flags = match field.attrs.len() {
0 => all_fields_flags,
_ => match FieldFlags::extract::<1>(&field.attrs, all_fields_flags.is_some())? {
1 => match FieldFlags::extract::<1>(&field.attrs, all_fields_flags.is_some())? {
[Some(flags)] => {
if flags.variant {
return Err(syn::Error::new(
Expand All @@ -93,6 +93,12 @@ impl FormatData<'_> {

[None] => None,
},
_ => {
return Err(syn::Error::new(
field.span(),
"only one `#[redact(...)]` attribute is allowed per field",
))
}
};

// If we have field flags...
Expand Down
14 changes: 10 additions & 4 deletions veil-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::spanned::Spanned;

mod enums;
mod flags;
mod fmt;
mod sanitize;
mod structs;

use proc_macro::TokenStream;
use sanitize::DeriveAttributeFilter;
use syn::spanned::Spanned;

/// Keep track of whether we actually redact anything.
///
/// By default fields are not redacted. One must add #[redact(...)] to them.
Expand Down Expand Up @@ -42,7 +44,11 @@ impl Default for UnusedDiagnostic {
///
/// See the [crate level documentation](index.html) for more information.
pub fn derive_redact(item: TokenStream) -> TokenStream {
let item = syn::parse_macro_input!(item as syn::DeriveInput);
let mut item = syn::parse_macro_input!(item as syn::DeriveInput);

// Remove all non-veil attributes to avoid conflicting with other
// derive proc macro attributes.
item.retain_veil_attrs();

// Unfortunately this is somewhat complex to implement at this stage of the macro "pipeline",
// so we'll pass around a mutable reference to this variable, and set it to false if we redact anything.
Expand Down
51 changes: 51 additions & 0 deletions veil-macros/src/sanitize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
trait AttributeFilter {
WilliamVenner marked this conversation as resolved.
Show resolved Hide resolved
fn retain_veil_attrs(&mut self);
}
impl AttributeFilter for Vec<syn::Attribute> {
fn retain_veil_attrs(&mut self) {
self.retain(|attr| attr.path.is_ident("redact"));
}
}
impl AttributeFilter for syn::Field {
fn retain_veil_attrs(&mut self) {
self.attrs.retain_veil_attrs();
}
}
impl AttributeFilter for syn::Fields {
fn retain_veil_attrs(&mut self) {
self.iter_mut().for_each(|field| field.retain_veil_attrs());
}
}
impl AttributeFilter for syn::FieldsNamed {
fn retain_veil_attrs(&mut self) {
self.named.iter_mut().for_each(|field| field.retain_veil_attrs());
}
}
impl AttributeFilter for syn::FieldsUnnamed {
fn retain_veil_attrs(&mut self) {
self.unnamed.iter_mut().for_each(|field| field.retain_veil_attrs());
}
}
impl AttributeFilter for syn::Data {
fn retain_veil_attrs(&mut self) {
match self {
syn::Data::Enum(e) => e.variants.iter_mut().for_each(|variant| {
variant.attrs.retain_veil_attrs();
variant.fields.retain_veil_attrs();
}),
syn::Data::Struct(s) => s.fields.retain_veil_attrs(),
syn::Data::Union(u) => u.fields.retain_veil_attrs(),
}
}
}

pub(crate) trait DeriveAttributeFilter {
/// Removes any non-veil attributes from the derive macro input.
fn retain_veil_attrs(&mut self);
}
impl DeriveAttributeFilter for syn::DeriveInput {
fn retain_veil_attrs(&mut self) {
self.attrs.retain_veil_attrs();
self.data.retain_veil_attrs();
}
}
3 changes: 3 additions & 0 deletions veil-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ trybuild = "1"
regex = "1"
walkdir = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
rand_derive2 = "0.1"
rand = "0.8"
Loading