Remove old define_violation! (in favor of #[violation]) (#3310)

This commit is contained in:
konstin 2023-03-06 18:00:29 +01:00 committed by GitHub
parent d1c48016eb
commit 709dba2e71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 119 deletions

View file

@ -1,117 +0,0 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Attribute, Error, Ident, ItemStruct, Lit, LitStr, Meta, Result, Token};
fn parse_attr<const LEN: usize>(path: [&'static str; LEN], attr: &Attribute) -> Option<LitStr> {
if let Meta::NameValue(name_value) = attr.parse_meta().ok()? {
let path_idents = name_value
.path
.segments
.iter()
.map(|segment| &segment.ident);
if itertools::equal(path_idents, path) {
if let Lit::Str(lit) = name_value.lit {
return Some(lit);
}
}
}
None
}
pub struct LintMeta {
explanation: String,
name: Ident,
}
impl Parse for LintMeta {
fn parse(input: ParseStream) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let mut explanation = String::new();
for attr in &attrs {
if let Some(lit) = parse_attr(["doc"], attr) {
let value = lit.value();
let line = value.strip_prefix(' ').unwrap_or(&value);
explanation.push_str(line);
explanation.push('\n');
} else {
return Err(Error::new_spanned(attr, "unexpected attribute"));
}
}
input.parse::<Token![pub]>()?;
input.parse::<Token![struct]>()?;
let name = input.parse()?;
// Ignore the rest of the input.
input.parse::<TokenStream>()?;
Ok(Self { explanation, name })
}
}
pub fn define_violation(input: &TokenStream, meta: LintMeta) -> TokenStream {
let LintMeta { explanation, name } = meta;
if explanation.is_empty() {
quote! {
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#input
}
} else {
quote! {
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#input
impl #name {
pub fn explanation() -> Option<&'static str> {
Some(#explanation)
}
}
}
}
}
/// Collect all doc comment attributes into a string
fn get_docs(attrs: &[Attribute]) -> Result<String> {
let mut explanation = String::new();
for attr in attrs {
if attr.path.is_ident("doc") {
if let Some(lit) = parse_attr(["doc"], attr) {
let value = lit.value();
// `/// ` adds
let line = value.strip_prefix(' ').unwrap_or(&value);
explanation.push_str(line);
explanation.push('\n');
} else {
return Err(Error::new_spanned(attr, "unimplemented doc comment style"));
}
}
}
Ok(explanation)
}
pub fn violation(violation: &ItemStruct) -> Result<TokenStream> {
let ident = &violation.ident;
let explanation = get_docs(&violation.attrs)?;
let violation = if explanation.trim().is_empty() {
quote! {
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#violation
}
} else {
quote! {
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#violation
impl #ident {
pub fn explanation() -> Option<&'static str> {
Some(#explanation)
}
}
}
};
Ok(violation)
}