zoet_macro/lib.rs
1//! [`zoet`](https://docs.rs/zoet/)'s proc-macro implementation. See that crate for documentation,
2//! and do not use this crate directly.
3
4/* Firstly, if we have the "clippy-insane" feature and a dev build -- it's assumed that a release
5 * build has taken the diagnostics into account -- we turn on far too many warnings. */
6#![cfg_attr(
7 all(feature = "clippy-insane", debug_assertions),
8 warn(
9 /* Turn the "allow" lints listed by `rustc -W help` ["rustc 1.77.1 (7cf61ebde 2024-03-27)"]
10 * into warn lints: */
11
12 absolute_paths_not_starting_with_crate,deprecated_in_future, elided_lifetimes_in_paths,
13 explicit_outlives_requirements, ffi_unwind_calls, keyword_idents_2018, keyword_idents_2024,
14 let_underscore_drop, macro_use_extern_crate, meta_variable_misuse, missing_abi,
15 missing_copy_implementations, missing_debug_implementations, missing_docs, non_ascii_idents,
16 non_local_definitions, redundant_lifetimes, rust_2021_incompatible_closure_captures,
17 rust_2021_incompatible_or_patterns, rust_2021_prefixes_incompatible_syntax,
18 rust_2021_prelude_collisions, single_use_lifetimes, trivial_casts, trivial_numeric_casts,
19 unit_bindings, unnameable_types, unreachable_pub, unsafe_code, unsafe_op_in_unsafe_fn,
20 unstable_features, unused_crate_dependencies, unused_extern_crates, unused_import_braces,
21 unused_lifetimes, unused_macro_rules, unused_qualifications, unused_results,
22 variant_size_differences,
23
24 //// stable compiler claims this is unstable, but unstable compiler claims it doesn't exist.
25 // dereferencing_mut_binding,
26
27 /* Ditto for clippy lint categories (see https://github.com/rust-lang/rust-clippy): */
28 clippy::all, clippy::nursery, clippy::pedantic, clippy::restriction,
29 // clippy::cargo,
30 ),
31 /* Sometimes there are lints listed in the stable compiler's -W help output which are actually
32 * nightly-only. If there are any, they get listed here instead of above. */
33 cfg_attr(
34 feature = "nightly",
35 feature(
36 multiple_supertrait_upcastable,
37 must_not_suspend,
38 non_exhaustive_omitted_patterns_lint,
39 strict_provenance,
40 ),
41 warn(
42 fuzzy_provenance_casts,
43 lossy_provenance_casts,
44 multiple_supertrait_upcastable,
45 must_not_suspend,
46 non_exhaustive_omitted_patterns,
47 )
48 ),
49 /* Now go back and turn back off any lints which turned out to be too noisy or annoying. In
50 * particular, clippy::all and clippy::restriction are "blanket" lints which turn on a lot of
51 * things, not all of which are useful. */
52 allow(
53 clippy::blanket_clippy_restriction_lints,
54 /* Turn off individual noisy/buggy lints enabled by broader categories above: */
55 clippy::allow_attributes, // recommended "expect" does not have the desired behaviour
56 clippy::allow_attributes_without_reason, // #(allow, reason="...") is nightly-only
57 clippy::implicit_return, // not idiomatic Rust
58 clippy::min_ident_chars, // single character idents are okay
59 clippy::missing_docs_in_private_items, // don't care
60 clippy::needless_borrowed_reference, // can't decide if this is good or bad
61 clippy::option_if_let_else, // `.map_or{_else}` is not the same thing.
62 clippy::pub_with_shorthand, // demands `pub(in crate)` but rustfmt disagrees
63 clippy::question_mark_used, //
64 clippy::redundant_pub_crate, // conflicts with unreachable_pub
65 clippy::ref_patterns, //
66 clippy::shadow_reuse, // e.g. `let foo = bar(foo)`
67 clippy::single_call_fn, // What am I expected to do with this information?
68 clippy::single_char_lifetime_names, //
69 clippy::std_instead_of_alloc, // don't care
70 clippy::std_instead_of_core, // `proc_macro_error` again; also don't care
71 clippy::wildcard_enum_match_arm, // excessively pedantic
72 elided_lifetimes_in_paths, // demands adding <'_> noise
73 non_exhaustive_omitted_patterns, // TODO: Sort of useful but loads of noise.
74
75 // reason = "can't see the wood for the trees"
76 ))]
77/* Any nightly-only features we actually want. This should be relatively small because we want the
78 * crate to run on stable, and so nightly-only features can only be used for enhancement, such as
79 * better error messages during development. */
80// #![cfg_attr(
81// feature = "nightly",
82// // TODO: #[deny(internal_features)] is now the default, which forbids rustc_attrs. Should we
83// // take the hint and find some other way to achieve our ends than rustc_attrs?
84// allow(unstable_features, internal_features),
85// feature(negative_impls, rustc_attrs),
86// feature(doc_auto_cfg, doc_cfg, doc_notable_trait)
87// )]
88//#![cfg_attr(test, feature(test))]
89//#![no_std]
90#![forbid(unsafe_code)]
91
92macro_rules! diagnostic_error {
93 ($SPAN:expr, $($REST:tt)+) => {
94 ::proc_macro_error::diagnostic!($SPAN, ::proc_macro_error::Level::Error, $($REST)+)
95 }
96}
97
98mod function_args;
99mod self_replacer;
100mod traits;
101mod with_tokens;
102mod zoet;
103
104pub(crate) type Error = proc_macro_error::Diagnostic;
105pub(crate) type Result<T, E = Error> = core::result::Result<T, E>;
106
107/// The `#[zoet]` macro.
108#[proc_macro_error::proc_macro_error]
109#[proc_macro_attribute]
110pub fn zoet(
111 attr: proc_macro::TokenStream, item: proc_macro::TokenStream,
112) -> proc_macro::TokenStream {
113 zoet::zoet(&attr.into(), &item.into()).into()
114}