1#![warn(
4 missing_docs,
5 rustdoc::all,
6 clippy::missing_docs_in_private_items,
7 clippy::all,
8 clippy::restriction,
9 clippy::pedantic,
10 clippy::nursery,
11 clippy::cargo
12)]
13#![allow(
14 clippy::blanket_clippy_restriction_lints,
15 clippy::exhaustive_structs,
16 clippy::implicit_return,
17 clippy::integer_arithmetic,
18 clippy::mod_module_files,
19 clippy::pattern_type_mismatch,
20 clippy::pub_use,
21 clippy::question_mark_used,
22 clippy::separated_literal_suffix,
23 clippy::string_add,
24 clippy::wildcard_enum_match_arm,
25 clippy::wildcard_imports
26)]
27#![deny(warnings)]
28
29macro_rules! bs_delim_span {
31 ($d:ident) => {
32 proc_macro2::Group::new(proc_macro2::Delimiter::$d, proc_macro2::TokenStream::new())
33 .delim_span()
34 };
35}
36
37macro_rules! token {
39 ($t:ident) => {
40 syn::token::$t {
41 spans: [proc_macro2::Span::call_site()],
42 }
43 };
44}
45
46macro_rules! single_token {
48 ($t:ident) => {
49 syn::token::$t {
50 span: proc_macro2::Span::call_site(),
51 }
52 };
53}
54
55macro_rules! dual_token {
57 ($t:ident) => {
58 syn::token::$t {
59 spans: [
60 proc_macro2::Span::call_site(),
61 proc_macro2::Span::call_site(),
62 ],
63 }
64 };
65}
66
67macro_rules! delim_token {
69 (Paren) => {
70 syn::token::Paren {
71 span: bs_delim_span!(Parenthesis),
72 }
73 };
74 ($d:ident) => {
75 syn::token::$d {
76 span: bs_delim_span!($d),
77 }
78 };
79}
80
81mod mutate;
82mod parse;
83
84const CRATE_NAME: &str = "sleuth";
86
87#[proc_macro_attribute]
89pub fn sleuth(
90 attr: proc_macro::TokenStream,
91 input: proc_macro::TokenStream,
92) -> proc_macro::TokenStream {
93 match mutate::implementation(attr.into(), input.into()) {
94 Ok(ts) => ts,
95 Err(e) => e.to_compile_error(),
96 }
97 .into()
98}
99
100#[inline]
102fn expr_path(
103 leading: bool,
104 punc: syn::punctuated::Punctuated<syn::PathSegment, syn::token::PathSep>,
105) -> syn::Expr {
106 syn::Expr::Path(syn::ExprPath {
107 attrs: vec![],
108 qself: None,
109 path: path(leading, punc),
110 })
111}
112
113#[inline]
115fn path(
116 leading: bool,
117 punc: syn::punctuated::Punctuated<syn::PathSegment, syn::token::PathSep>,
118) -> syn::Path {
119 syn::Path {
120 leading_colon: leading.then(|| dual_token!(PathSep)),
121 segments: punc,
122 }
123}
124
125#[inline]
127fn punctuate<T, P: Default, const N: usize>(vs: [T; N]) -> syn::punctuated::Punctuated<T, P> {
128 let mut punc = syn::punctuated::Punctuated::new();
129 for v in vs {
130 punc.push(v);
131 }
132 punc
133}
134
135#[inline]
137fn ident(s: &str) -> syn::Ident {
138 syn::Ident::new(s, proc_macro2::Span::call_site())
139}
140
141#[inline]
143const fn pathseg(fn_name: syn::Ident) -> syn::PathSegment {
144 syn::PathSegment {
145 ident: fn_name,
146 arguments: syn::PathArguments::None,
147 }
148}
149
150const NO_GENERICS: syn::Generics = syn::Generics {
152 lt_token: None,
153 params: syn::punctuated::Punctuated::new(),
154 gt_token: None,
155 where_clause: None,
156};