ruff/crates/ruff_macros/src/derive_message_formats.rs
Anders Kaseorg df13e69c3c
Format let-else with rustfmt nightly (#5461)
Support for `let…else` formatting was just merged to nightly
(rust-lang/rust#113225). Rerun `cargo fmt` with Rust nightly 2023-07-02
to pick this up. Followup to #939.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-07-03 02:13:35 +00:00

59 lines
1.8 KiB
Rust

use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{Block, Expr, ItemFn, Stmt};
pub(crate) fn derive_message_formats(func: &ItemFn) -> TokenStream {
let mut strings = quote!();
if let Err(err) = parse_block(&func.block, &mut strings) {
return err;
}
quote! {
#func
fn message_formats() -> &'static [&'static str] {
&[#strings]
}
}
}
fn parse_block(block: &Block, strings: &mut TokenStream) -> Result<(), TokenStream> {
let Some(Stmt::Expr(last, _)) = block.stmts.last() else {
panic!("expected last statement in block to be an expression")
};
parse_expr(last, strings)?;
Ok(())
}
fn parse_expr(expr: &Expr, strings: &mut TokenStream) -> Result<(), TokenStream> {
match expr {
Expr::Macro(mac) if mac.mac.path.is_ident("format") => {
let Some(first_token) = mac.mac.tokens.to_token_stream().into_iter().next() else {
return Err(
quote_spanned!(expr.span() => compile_error!("expected format! to have an argument")),
);
};
strings.extend(quote! {#first_token,});
Ok(())
}
Expr::Block(block) => parse_block(&block.block, strings),
Expr::If(expr) => {
parse_block(&expr.then_branch, strings)?;
if let Some((_, then)) = &expr.else_branch {
parse_expr(then, strings)?;
}
Ok(())
}
Expr::Match(block) => {
for arm in &block.arms {
parse_expr(&arm.body, strings)?;
}
Ok(())
}
_ => Err(quote_spanned!(
expr.span() =>
compile_error!("expected last expression to be a format! macro or a match block")
)),
}
}