-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathviolation.rs
93 lines (83 loc) · 2.78 KB
/
violation.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Attribute, Error, ItemStruct, Lit, LitStr, Meta, Result};
fn parse_attr<'a, const LEN: usize>(
path: [&'static str; LEN],
attr: &'a Attribute,
) -> Option<&'a LitStr> {
if let Meta::NameValue(name_value) = &attr.meta {
let path_idents = name_value
.path
.segments
.iter()
.map(|segment| &segment.ident);
if itertools::equal(path_idents, path) {
if let syn::Expr::Lit(syn::ExprLit {
lit: Lit::Str(lit), ..
}) = &name_value.value
{
return Some(lit);
}
}
}
None
}
/// 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(crate) 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)]
#violation
impl From<#ident> for ruff_diagnostics::DiagnosticKind {
fn from(value: #ident) -> Self {
use ruff_diagnostics::Violation;
Self {
body: Violation::message(&value),
suggestion: Violation::autofix_title(&value),
name: stringify!(#ident).to_string(),
}
}
}
}
} else {
quote! {
#[derive(Debug, PartialEq, Eq)]
#violation
impl #ident {
pub fn explanation() -> Option<&'static str> {
Some(#explanation)
}
}
impl From<#ident> for ruff_diagnostics::DiagnosticKind {
fn from(value: #ident) -> Self {
use ruff_diagnostics::Violation;
Self {
body: Violation::message(&value),
suggestion: Violation::autofix_title(&value),
name: stringify!(#ident).to_string(),
}
}
}
}
};
Ok(violation)
}