use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
use proc_macro2::Ident;
use quote::ToTokens as _;
use syn::parse::discouraged::Speculative as _;
use syn::visit_mut::VisitMut;
fn canonical(counter: &mut usize) -> String {
let name = format!("_canon_{counter}");
*counter += 1;
name
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Ns {
Value,
Type,
Lifetime,
Label,
Macro,
}
#[derive(Default)]
struct Frame([BTreeMap<String, String>; 5]);
impl Frame {
fn bind(&mut self, ns: Ns, name: String, canon: String) {
self.0[ns as usize].insert(name, canon);
}
fn lookup(&self, ns: Ns, name: &str) -> Option<&String> {
self.0[ns as usize].get(name)
}
fn lookup_any(&self, ns: &[Ns], name: &str) -> Option<&String> {
ns.iter().find_map(|ns| self.lookup(*ns, name))
}
}
fn rename(ident: &mut Ident, canon: &str) {
*ident = Ident::new(canon, ident.span());
}
struct Renamer {
frames: Vec<Frame>,
counter: usize,
mod_frames: BTreeMap<String, Frame>,
self_ty: Option<syn::Type>,
in_type: bool,
}
impl Renamer {
fn new() -> Self {
Self {
frames: vec![Frame::default()],
counter: 0,
mod_frames: BTreeMap::new(),
self_ty: None,
in_type: false,
}
}
fn push(&mut self) {
self.frames.push(Frame::default());
}
fn pop(&mut self) {
self.frames.pop();
}
fn bind(&mut self, ns: Ns, name: &str) -> String {
let canon = canonical(&mut self.counter);
self.top_bind(ns, name, canon.clone());
canon
}
fn top_bind(&mut self, ns: Ns, name: &str, canon: String) {
self.frames
.last_mut()
.expect("a scope frame")
.bind(ns, name.to_string(), canon);
}
fn bind_ident(&mut self, ns: Ns, ident: &mut Ident) -> String {
let canon = self.bind(ns, &ident.to_string());
rename(ident, &canon);
canon
}
fn bind_value_and_type(&mut self, name: &str) -> String {
let canon = self.bind(Ns::Value, name);
self.top_bind(Ns::Type, name, canon.clone());
canon
}
fn lookup(&self, ns: &[Ns], name: &str) -> Option<String> {
for ns in ns {
for frame in self.frames.iter().rev() {
if let Some(canon) = frame.lookup(*ns, name) {
return Some(canon.clone());
}
}
}
None
}
fn rename_binder(&mut self, ns: Ns, ident: &mut Ident) -> String {
let name = ident.to_string();
let canon = match self.frames.last().and_then(|frame| frame.lookup(ns, &name)) {
Some(canon) => canon.clone(),
None => self.bind(ns, &name),
};
rename(ident, &canon);
canon
}
fn resolve(&self, ns: &[Ns], ident: &mut Ident) {
if let Some(canon) = self.lookup(ns, &ident.to_string()) {
rename(ident, &canon);
}
}
fn visit_attrs(&mut self, attrs: &mut [syn::Attribute]) {
for attr in attrs {
self.visit_attribute_mut(attr);
}
}
fn bind_label(&mut self, label: Option<&mut syn::Label>) {
if let Some(label) = label {
self.bind_ident(Ns::Label, &mut label.name.ident);
}
}
fn rename_label(&self, lifetime: &mut syn::Lifetime) {
self.resolve(&[Ns::Label], &mut lifetime.ident);
}
fn unroot(&self, leading_colon: &mut Option<syn::Token![::]>, first: Option<&Ident>) {
if first.is_some_and(|first| self.lookup(&[Ns::Type], &first.to_string()).is_none()) {
*leading_colon = None;
}
}
fn rename_tokens(&mut self, tokens: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let mut out = Vec::new();
let mut iter = tokens.into_iter().peekable();
while let Some(tree) = iter.next() {
out.push(match tree {
proc_macro2::TokenTree::Ident(mut ident) => {
let bang = matches!(iter.peek(), Some(proc_macro2::TokenTree::Punct(p)) if p.as_char() == '!');
let ns: &[Ns] = if bang {
&[Ns::Value, Ns::Type, Ns::Macro]
} else {
&[Ns::Value, Ns::Type]
};
self.resolve(ns, &mut ident);
proc_macro2::TokenTree::Ident(ident)
}
proc_macro2::TokenTree::Group(group) => {
crate::drift::map_group(&group, |inner| self.rename_tokens(inner))
}
other => other,
});
}
proc_macro2::TokenStream::from_iter(out)
}
fn rewrite_macro_tokens(
&mut self,
tokens: proc_macro2::TokenStream,
format_at: Option<usize>,
) -> proc_macro2::TokenStream {
let Ok(mut args) = syn::parse2::<MacroArgs>(tokens.clone()) else {
return self.rename_tokens(tokens);
};
for (index, expr) in args.iter_mut().enumerate() {
self.visit_expr_mut(expr);
if Some(index) == format_at
&& let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = expr
{
*lit = rewrite_format_str(self, lit);
}
}
args.to_token_stream()
}
}
enum MacroArgs {
List(syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>),
Repeat(syn::punctuated::Punctuated<syn::Expr, syn::Token![;]>),
}
impl MacroArgs {
fn iter_mut(&mut self) -> syn::punctuated::IterMut<'_, syn::Expr> {
match self {
Self::List(exprs) => exprs.iter_mut(),
Self::Repeat(exprs) => exprs.iter_mut(),
}
}
}
impl syn::parse::Parse for MacroArgs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let list = input.fork();
if let Ok(exprs) = list.call(syn::punctuated::Punctuated::parse_terminated) {
input.advance_to(&list);
return Ok(Self::List(exprs));
}
let span = input.span();
let exprs: syn::punctuated::Punctuated<syn::Expr, syn::Token![;]> =
input.call(syn::punctuated::Punctuated::parse_terminated)?;
if exprs.len() == 2 && !exprs.trailing_punct() {
Ok(Self::Repeat(exprs))
} else {
Err(syn::Error::new(span, "not a repeat"))
}
}
}
impl quote::ToTokens for MacroArgs {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
match self {
Self::List(exprs) => exprs.to_tokens(tokens),
Self::Repeat(exprs) => exprs.to_tokens(tokens),
}
}
}
fn push_format_name(renamer: &Renamer, name: &str, out: &mut String) {
out.push_str(
renamer
.lookup(&[Ns::Value], name)
.as_deref()
.unwrap_or(name),
);
}
fn rewrite_format_arg(renamer: &Renamer, arg: &str, out: &mut String) {
let (name, spec) = arg
.split_once(':')
.map_or((arg, None), |(n, s)| (n, Some(s)));
push_format_name(renamer, name, out);
let Some(spec) = spec else {
return;
};
out.push(':');
let mut rest = spec;
while let Some((before, after)) = rest.split_once('$') {
let start = before
.char_indices()
.rfind(|&(_, c)| !c.is_alphanumeric() && c != '_')
.map_or(0, |(p, c)| p + c.len_utf8());
out.push_str(&before[..start]);
push_format_name(renamer, &before[start..], out);
out.push('$');
rest = after;
}
out.push_str(rest);
}
fn rewrite_format_str(renamer: &Renamer, lit: &syn::LitStr) -> syn::LitStr {
let value = lit.value();
let mut out = String::with_capacity(value.len());
let mut chars = value.chars().peekable();
while let Some(c) = chars.next() {
match c {
'{' | '}' if chars.peek() == Some(&c) => {
chars.next();
out.push(c);
out.push(c);
}
'{' => {
let mut inner = String::new();
let mut closed = false;
for c in chars.by_ref() {
if c == '}' {
closed = true;
break;
}
inner.push(c);
}
out.push('{');
rewrite_format_arg(renamer, &inner, &mut out);
if closed {
out.push('}');
}
}
other => out.push(other),
}
}
syn::LitStr::new(&out, lit.span())
}
pub(crate) fn normalize_file(file: &mut syn::File) {
let mut renamer = Renamer::new();
renamer.visit_file_mut(file);
}
fn is_unit_path(id: &syn::PatIdent) -> bool {
id.by_ref.is_none()
&& id.mutability.is_none()
&& id.subpat.is_none()
&& id.ident.to_string().starts_with(|c: char| c.is_uppercase())
}
fn walk_pat_idents(pat: &mut syn::Pat, f: &mut impl FnMut(&mut syn::PatIdent)) {
match pat {
syn::Pat::Ident(id) => {
f(id);
if let Some((_, sub)) = &mut id.subpat {
walk_pat_idents(sub, f);
}
}
syn::Pat::Tuple(syn::PatTuple { elems, .. })
| syn::Pat::Slice(syn::PatSlice { elems, .. })
| syn::Pat::TupleStruct(syn::PatTupleStruct { elems, .. }) => {
for pat in elems {
walk_pat_idents(pat, f);
}
}
syn::Pat::Struct(r#struct) => {
for field in &mut r#struct.fields {
field.colon_token.get_or_insert_with(Default::default);
walk_pat_idents(&mut field.pat, f);
}
}
syn::Pat::Or(r#or) => {
for pat in &mut r#or.cases {
walk_pat_idents(pat, f);
}
}
syn::Pat::Reference(syn::PatReference { pat, .. })
| syn::Pat::Type(syn::PatType { pat, .. })
| syn::Pat::Guard(syn::PatGuard { pat, .. }) => walk_pat_idents(pat, f),
_ => {}
}
}
fn rewrite_pat_bindings(renamer: &Renamer, pat: &mut syn::Pat) {
walk_pat_idents(pat, &mut |id| {
let ns: &[Ns] = if is_unit_path(id) {
&[Ns::Value, Ns::Type]
} else {
&[Ns::Value]
};
renamer.resolve(ns, &mut id.ident);
});
}
fn pattern_names(pat: &mut syn::Pat, out: &mut Vec<String>) {
walk_pat_idents(pat, &mut |id| {
if !is_unit_path(id) {
out.push(id.ident.to_string());
}
});
}
fn fn_param_names<'a>(inputs: impl Iterator<Item = &'a mut syn::FnArg>) -> Vec<String> {
let mut out = Vec::new();
for input in inputs {
if let syn::FnArg::Typed(pat_type) = input {
pattern_names(&mut pat_type.pat, &mut out);
}
}
out
}
fn prebind<'a>(renamer: &mut Renamer, items: impl Iterator<Item = &'a syn::Item>) {
for item in items {
let (ns, ident) = match item {
syn::Item::Fn(i) => (Ns::Value, &i.sig.ident),
syn::Item::Const(i) => (Ns::Value, &i.ident),
syn::Item::Static(i) => (Ns::Value, &i.ident),
syn::Item::Struct(i) => (Ns::Type, &i.ident),
syn::Item::Enum(i) => (Ns::Type, &i.ident),
syn::Item::Union(i) => (Ns::Type, &i.ident),
syn::Item::Type(i) => (Ns::Type, &i.ident),
syn::Item::Trait(i) => (Ns::Type, &i.ident),
syn::Item::TraitAlias(i) => (Ns::Type, &i.ident),
syn::Item::Mod(i) => (Ns::Type, &i.ident),
_ => continue,
};
let canon = renamer.bind(ns, &ident.to_string());
if let syn::Item::Mod(syn::ItemMod {
content: Some((_, items)),
..
}) = item
{
renamer.push();
prebind(renamer, items.iter());
let frame = renamer.frames.pop().expect("a scope frame");
renamer.mod_frames.insert(canon, frame);
}
}
}
impl Renamer {
fn bind_use_tree(&mut self, tree: syn::UseTree) -> syn::UseTree {
match tree {
syn::UseTree::Path(mut path) => {
path.tree = Box::new(self.bind_use_tree(*path.tree));
syn::UseTree::Path(path)
}
syn::UseTree::Name(syn::UseName { ident }) => {
let canon = self.bind_value_and_type(&ident.to_string());
syn::UseTree::Rename(syn::UseRename {
rename: Ident::new(&canon, ident.span()),
ident,
as_token: <syn::Token![as]>::default(),
})
}
syn::UseTree::Rename(mut alias) => {
let canon = self.bind_value_and_type(&alias.rename.to_string());
rename(&mut alias.rename, &canon);
syn::UseTree::Rename(alias)
}
syn::UseTree::Group(mut group) => {
group.items = group
.items
.into_pairs()
.map(|pair| {
let (tree, comma) = pair.into_tuple();
syn::punctuated::Pair::new(self.bind_use_tree(tree), comma)
})
.collect();
syn::UseTree::Group(group)
}
glob @ syn::UseTree::Glob(_) => glob,
}
}
fn bind_pat(&mut self, pat: &mut syn::Pat) {
let mut names = Vec::new();
pattern_names(pat, &mut names);
for name in &names {
self.bind(Ns::Value, name);
}
syn::visit_mut::visit_pat_mut(self, pat);
rewrite_pat_bindings(self, pat);
}
fn visit_fn(
&mut self,
attrs: &mut [syn::Attribute],
sig: &mut syn::Signature,
body: Option<&mut syn::Block>,
) {
begin_generics(self, &mut sig.generics);
self.visit_attrs(attrs);
self.push();
for param in fn_param_names(sig.inputs.iter_mut()) {
self.bind(Ns::Value, ¶m);
}
visit_fn_inputs(self, sig.inputs.iter_mut());
syn::visit_mut::visit_return_type_mut(self, &mut sig.output);
if let Some(body) = body {
self.visit_block_mut(body);
}
self.pop();
self.pop();
}
fn begin_type_item(
&mut self,
ident: &mut Ident,
generics: &mut syn::Generics,
attrs: &mut [syn::Attribute],
) {
self.rename_binder(Ns::Type, ident);
begin_generics(self, generics);
self.visit_attrs(attrs);
}
}
fn visit_fn_inputs<'a>(renamer: &mut Renamer, inputs: impl Iterator<Item = &'a mut syn::FnArg>) {
for input in inputs {
syn::visit_mut::visit_fn_arg_mut(renamer, input);
if let syn::FnArg::Typed(pat_type) = input {
rewrite_pat_bindings(renamer, &mut pat_type.pat);
}
}
}
fn single_segment_type_name(ty: &syn::Type) -> Option<String> {
let syn::Type::Path(path) = ty else {
return None;
};
if path.qself.is_some() || path.path.segments.len() != 1 {
return None;
}
let segment = path.path.segments.first()?;
if matches!(
segment.arguments,
syn::PathArguments::None | syn::PathArguments::AngleBracketed(_)
) {
Some(segment.ident.to_string())
} else {
None
}
}
fn begin_generics(renamer: &mut Renamer, generics: &mut syn::Generics) {
renamer.push();
for param in &mut generics.params {
match param {
syn::GenericParam::Lifetime(lifetime) => {
renamer.bind_ident(Ns::Lifetime, &mut lifetime.lifetime.ident);
}
syn::GenericParam::Type(ty_param) => {
renamer.bind_ident(Ns::Type, &mut ty_param.ident);
}
syn::GenericParam::Const(r#const) => {
let canon = renamer.bind_value_and_type(&r#const.ident.to_string());
rename(&mut r#const.ident, &canon);
}
}
}
for param in &mut generics.params {
syn::visit_mut::visit_generic_param_mut(renamer, param);
}
if let Some(where_clause) = &mut generics.where_clause {
syn::visit_mut::visit_where_clause_mut(renamer, where_clause);
}
}
fn walk_let_cond(renamer: &mut Renamer, cond: &mut syn::Expr) {
match cond {
syn::Expr::Binary(binary) => {
walk_let_cond(renamer, &mut binary.left);
walk_let_cond(renamer, &mut binary.right);
}
syn::Expr::Let(let_expr) => bind_let(renamer, let_expr),
other => syn::visit_mut::visit_expr_mut(renamer, other),
}
}
fn bind_let(renamer: &mut Renamer, let_expr: &mut syn::ExprLet) {
syn::visit_mut::visit_expr_mut(renamer, &mut let_expr.expr);
renamer.bind_pat(&mut let_expr.pat);
}
impl VisitMut for Renamer {
fn visit_file_mut(&mut self, file: &mut syn::File) {
prebind(self, file.items.iter());
syn::visit_mut::visit_file_mut(self, file);
}
fn visit_block_mut(&mut self, block: &mut syn::Block) {
self.push();
prebind(
self,
block.stmts.iter().filter_map(|stmt| match stmt {
syn::Stmt::Item(item) => Some(item),
_ => None,
}),
);
syn::visit_mut::visit_block_mut(self, block);
self.pop();
}
fn visit_local_mut(&mut self, local: &mut syn::Local) {
if let Some(init) = &mut local.init {
syn::visit_mut::visit_expr_mut(self, &mut init.expr);
if let Some(diverge) = &mut init.diverge {
syn::visit_mut::visit_expr_mut(self, &mut diverge.1);
}
}
self.bind_pat(&mut local.pat);
}
fn visit_item_fn_mut(&mut self, item: &mut syn::ItemFn) {
self.rename_binder(Ns::Value, &mut item.sig.ident);
self.visit_fn(&mut item.attrs, &mut item.sig, Some(&mut item.block));
}
fn visit_impl_item_fn_mut(&mut self, item: &mut syn::ImplItemFn) {
self.visit_fn(&mut item.attrs, &mut item.sig, Some(&mut item.block));
}
fn visit_trait_item_fn_mut(&mut self, item: &mut syn::TraitItemFn) {
self.visit_fn(&mut item.attrs, &mut item.sig, item.default.as_mut());
}
fn visit_item_struct_mut(&mut self, item: &mut syn::ItemStruct) {
self.begin_type_item(&mut item.ident, &mut item.generics, &mut item.attrs);
syn::visit_mut::visit_fields_mut(self, &mut item.fields);
self.pop();
}
fn visit_item_enum_mut(&mut self, item: &mut syn::ItemEnum) {
self.begin_type_item(&mut item.ident, &mut item.generics, &mut item.attrs);
for variant in &mut item.variants {
syn::visit_mut::visit_variant_mut(self, variant);
}
self.pop();
}
fn visit_item_union_mut(&mut self, item: &mut syn::ItemUnion) {
self.begin_type_item(&mut item.ident, &mut item.generics, &mut item.attrs);
syn::visit_mut::visit_fields_named_mut(self, &mut item.fields);
self.pop();
}
fn visit_item_type_mut(&mut self, item: &mut syn::ItemType) {
self.begin_type_item(&mut item.ident, &mut item.generics, &mut item.attrs);
syn::visit_mut::visit_type_mut(self, &mut item.ty);
self.pop();
}
fn visit_item_trait_mut(&mut self, item: &mut syn::ItemTrait) {
let canon = self.rename_binder(Ns::Type, &mut item.ident);
self.top_bind(Ns::Type, "Self", canon);
begin_generics(self, &mut item.generics);
self.visit_attrs(&mut item.attrs);
for trait_item in &mut item.items {
syn::visit_mut::visit_trait_item_mut(self, trait_item);
}
self.pop();
}
fn visit_item_trait_alias_mut(&mut self, item: &mut syn::ItemTraitAlias) {
self.begin_type_item(&mut item.ident, &mut item.generics, &mut item.attrs);
for bound in &mut item.bounds {
syn::visit_mut::visit_type_param_bound_mut(self, bound);
}
self.pop();
}
fn visit_item_impl_mut(&mut self, item: &mut syn::ItemImpl) {
self.push();
if let Some(name) = single_segment_type_name(&item.self_ty)
&& let Some(canon) = self.lookup(&[Ns::Type], &name)
{
self.top_bind(Ns::Type, "Self", canon);
}
let has_generics = item.generics.lt_token.is_some();
if has_generics {
begin_generics(self, &mut item.generics);
}
self.visit_attrs(&mut item.attrs);
if let Some((path, _)) = &mut item.trait_ {
let outer = core::mem::replace(&mut self.in_type, true);
self.visit_path_mut(path);
self.in_type = outer;
}
syn::visit_mut::visit_type_mut(self, &mut item.self_ty);
let outer = self.self_ty.replace(item.self_ty.as_ref().clone());
for impl_item in &mut item.items {
syn::visit_mut::visit_impl_item_mut(self, impl_item);
}
self.self_ty = outer;
if has_generics {
self.pop();
}
self.pop();
}
fn visit_item_const_mut(&mut self, item: &mut syn::ItemConst) {
self.rename_binder(Ns::Value, &mut item.ident);
self.visit_attrs(&mut item.attrs);
syn::visit_mut::visit_type_mut(self, &mut item.ty);
syn::visit_mut::visit_expr_mut(self, &mut item.expr);
}
fn visit_item_static_mut(&mut self, item: &mut syn::ItemStatic) {
self.rename_binder(Ns::Value, &mut item.ident);
self.visit_attrs(&mut item.attrs);
syn::visit_mut::visit_type_mut(self, &mut item.ty);
syn::visit_mut::visit_expr_mut(self, &mut item.expr);
}
fn visit_item_macro_mut(&mut self, item: &mut syn::ItemMacro) {
if let Some(ident) = item.ident.as_mut() {
self.bind_ident(Ns::Macro, ident);
self.visit_attrs(&mut item.attrs);
} else {
self.visit_attrs(&mut item.attrs);
self.visit_macro_mut(&mut item.mac);
}
}
fn visit_item_use_mut(&mut self, item: &mut syn::ItemUse) {
self.visit_attrs(&mut item.attrs);
let first = match &item.tree {
syn::UseTree::Path(path) => Some(&path.ident),
syn::UseTree::Name(name) => Some(&name.ident),
syn::UseTree::Rename(rename) => Some(&rename.ident),
syn::UseTree::Glob(_) | syn::UseTree::Group(_) => None,
};
self.unroot(&mut item.leading_colon, first);
let glob = syn::UseTree::Glob(syn::UseGlob {
star_token: <syn::Token![*]>::default(),
});
item.tree = self.bind_use_tree(core::mem::replace(&mut item.tree, glob));
}
fn visit_item_mod_mut(&mut self, item: &mut syn::ItemMod) {
let canon = self.rename_binder(Ns::Type, &mut item.ident);
self.visit_attrs(&mut item.attrs);
if let Some((_, items)) = &mut item.content {
let frame = self.mod_frames.remove(&canon).unwrap_or_default();
self.frames.push(frame);
for sub_item in items.iter_mut() {
syn::visit_mut::visit_item_mut(self, sub_item);
}
let frame = self.frames.pop().expect("a scope frame");
self.mod_frames.insert(canon, frame);
}
}
fn visit_expr_closure_mut(&mut self, closure: &mut syn::ExprClosure) {
self.push();
if let Some(bound) = &mut closure.lifetimes {
self.visit_bound_lifetimes_mut(bound);
}
let mut names = Vec::new();
for input in &mut closure.inputs {
pattern_names(input, &mut names);
}
for name in &names {
self.bind(Ns::Value, name);
}
for input in &mut closure.inputs {
syn::visit_mut::visit_pat_mut(self, input);
rewrite_pat_bindings(self, input);
}
syn::visit_mut::visit_return_type_mut(self, &mut closure.output);
syn::visit_mut::visit_expr_mut(self, &mut closure.body);
self.pop();
}
fn visit_arm_mut(&mut self, arm: &mut syn::Arm) {
self.push();
self.bind_pat(&mut arm.pat);
syn::visit_mut::visit_expr_mut(self, &mut arm.body);
self.pop();
}
fn visit_expr_for_loop_mut(&mut self, for_loop: &mut syn::ExprForLoop) {
syn::visit_mut::visit_expr_mut(self, &mut for_loop.expr);
self.push();
self.bind_label(for_loop.label.as_mut());
self.bind_pat(&mut for_loop.pat);
self.visit_block_mut(&mut for_loop.body);
self.pop();
}
fn visit_expr_if_mut(&mut self, expr: &mut syn::ExprIf) {
self.push();
walk_let_cond(self, &mut expr.cond);
self.visit_block_mut(&mut expr.then_branch);
self.pop();
if let Some((_, else_expr)) = &mut expr.else_branch {
syn::visit_mut::visit_expr_mut(self, else_expr);
}
}
fn visit_expr_while_mut(&mut self, expr: &mut syn::ExprWhile) {
self.push();
self.bind_label(expr.label.as_mut());
walk_let_cond(self, &mut expr.cond);
self.visit_block_mut(&mut expr.body);
self.pop();
}
fn visit_expr_loop_mut(&mut self, expr: &mut syn::ExprLoop) {
self.push();
self.bind_label(expr.label.as_mut());
self.visit_block_mut(&mut expr.body);
self.pop();
}
fn visit_expr_block_mut(&mut self, expr: &mut syn::ExprBlock) {
self.push();
self.bind_label(expr.label.as_mut());
self.visit_block_mut(&mut expr.block);
self.pop();
}
fn visit_expr_struct_mut(&mut self, expr: &mut syn::ExprStruct) {
for field in &mut expr.fields {
if field.colon_token.is_none()
&& let syn::Member::Named(ident) = &field.member
&& self.lookup(&[Ns::Value], &ident.to_string()).is_some()
{
field.colon_token = Some(syn::token::Colon::default());
}
}
syn::visit_mut::visit_expr_struct_mut(self, expr);
}
fn visit_path_mut(&mut self, path: &mut syn::Path) {
self.unroot(
&mut path.leading_colon,
path.segments.first().map(|s| &s.ident),
);
let ns: &[Ns] = if self.in_type {
&[Ns::Type]
} else {
&[Ns::Value, Ns::Type]
};
if path.leading_colon.is_none()
&& let Some(first) = path.segments.first_mut()
&& let Some(mut canon) = self.lookup(ns, &first.ident.to_string())
{
rename(&mut first.ident, &canon);
for segment in path.segments.iter_mut().skip(1) {
let Some(next) = self
.mod_frames
.get(&canon)
.and_then(|frame| frame.lookup_any(ns, &segment.ident.to_string()))
else {
break;
};
canon = next.clone();
rename(&mut segment.ident, &canon);
}
}
for segment in &mut path.segments {
match &mut segment.arguments {
syn::PathArguments::AngleBracketed(args) => {
for arg in &mut args.args {
if matches!(arg, syn::GenericArgument::Const(_)) {
let outer = core::mem::replace(&mut self.in_type, false);
syn::visit_mut::visit_generic_argument_mut(self, arg);
self.in_type = outer;
} else {
syn::visit_mut::visit_generic_argument_mut(self, arg);
}
}
}
syn::PathArguments::Parenthesized(args) => {
for input in &mut args.inputs {
self.visit_named_arg_mut(input);
}
syn::visit_mut::visit_return_type_mut(self, &mut args.output);
}
syn::PathArguments::None => {}
}
}
}
fn visit_macro_mut(&mut self, mac: &mut syn::Macro) {
self.unroot(
&mut mac.path.leading_colon,
mac.path.segments.first().map(|s| &s.ident),
);
if let Some(first) = mac.path.segments.first_mut() {
self.resolve(&[Ns::Macro], &mut first.ident);
}
let format_at = crate::drift::format_operand(&mac.path).map(|(at, _)| at);
mac.tokens = self.rewrite_macro_tokens(core::mem::take(&mut mac.tokens), format_at);
}
fn visit_type_path_mut(&mut self, node: &mut syn::TypePath) {
let outer = core::mem::replace(&mut self.in_type, true);
syn::visit_mut::visit_type_path_mut(self, node);
self.in_type = outer;
}
fn visit_type_mut(&mut self, ty: &mut syn::Type) {
if let Some(self_ty) = &self.self_ty
&& let syn::Type::Path(path) = &*ty
&& path.qself.is_none()
&& path.path.is_ident("Self")
{
*ty = self_ty.clone();
return;
}
syn::visit_mut::visit_type_mut(self, ty);
}
fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) {
self.resolve(&[Ns::Lifetime], &mut lifetime.ident);
}
fn visit_expr_break_mut(&mut self, node: &mut syn::ExprBreak) {
self.visit_attrs(&mut node.attrs);
if let Some(label) = &mut node.label {
self.rename_label(label);
}
if let Some(expr) = &mut node.expr {
syn::visit_mut::visit_expr_mut(self, expr);
}
}
fn visit_expr_continue_mut(&mut self, node: &mut syn::ExprContinue) {
self.visit_attrs(&mut node.attrs);
if let Some(label) = &mut node.label {
self.rename_label(label);
}
}
fn visit_pat_guard_mut(&mut self, node: &mut syn::PatGuard) {
syn::visit_mut::visit_pat_mut(self, &mut node.pat);
walk_let_cond(self, &mut node.guard);
}
fn visit_bound_lifetimes_mut(&mut self, node: &mut syn::BoundLifetimes) {
for param in &mut node.lifetimes {
if let syn::GenericParam::Lifetime(lifetime) = param {
self.bind_ident(Ns::Lifetime, &mut lifetime.lifetime.ident);
}
}
syn::visit_mut::visit_bound_lifetimes_mut(self, node);
}
fn visit_type_fn_ptr_mut(&mut self, node: &mut syn::TypeFnPtr) {
self.push();
syn::visit_mut::visit_type_fn_ptr_mut(self, node);
self.pop();
}
fn visit_trait_bound_mut(&mut self, node: &mut syn::TraitBound) {
self.push();
let outer = core::mem::replace(&mut self.in_type, true);
syn::visit_mut::visit_trait_bound_mut(self, node);
self.in_type = outer;
self.pop();
}
fn visit_named_arg_mut(&mut self, node: &mut syn::NamedArg) {
node.name = None;
syn::visit_mut::visit_named_arg_mut(self, node);
}
fn visit_attribute_mut(&mut self, attribute: &mut syn::Attribute) {
if let syn::Meta::NameValue(name_value) = &mut attribute.meta {
syn::visit_mut::visit_expr_mut(self, &mut name_value.value);
}
}
}