summaryrefslogtreecommitdiff
path: root/vendor/syn/tests/common/visit.rs
blob: 2d2a6c5382d53b0c9931bc2b06122462cc02d47d (plain)
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use std::mem;
use syn::visit_mut::{self, VisitMut};
use syn::{Expr, File, Generics, LifetimeParam, MacroDelimiter, Stmt, StmtMacro, TypeParam};

pub struct FlattenParens {
    discard_paren_attrs: bool,
}

impl FlattenParens {
    pub fn discard_attrs() -> Self {
        FlattenParens {
            discard_paren_attrs: true,
        }
    }

    pub fn combine_attrs() -> Self {
        FlattenParens {
            discard_paren_attrs: false,
        }
    }

    pub fn visit_token_stream_mut(tokens: &mut TokenStream) {
        *tokens = mem::take(tokens)
            .into_iter()
            .flat_map(|tt| {
                if let TokenTree::Group(group) = tt {
                    let delimiter = group.delimiter();
                    let mut content = group.stream();
                    Self::visit_token_stream_mut(&mut content);
                    if let Delimiter::Parenthesis = delimiter {
                        content
                    } else {
                        TokenStream::from(TokenTree::Group(Group::new(delimiter, content)))
                    }
                } else {
                    TokenStream::from(tt)
                }
            })
            .collect();
    }
}

impl VisitMut for FlattenParens {
    fn visit_expr_mut(&mut self, e: &mut Expr) {
        while let Expr::Paren(paren) = e {
            let paren_attrs = mem::take(&mut paren.attrs);
            *e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER);
            if !paren_attrs.is_empty() && !self.discard_paren_attrs {
                let nested_attrs = match e {
                    Expr::Assign(e) => &mut e.attrs,
                    Expr::Binary(e) => &mut e.attrs,
                    Expr::Cast(e) => &mut e.attrs,
                    _ => unimplemented!(),
                };
                assert!(nested_attrs.is_empty());
                *nested_attrs = paren_attrs;
            }
        }
        visit_mut::visit_expr_mut(self, e);
    }
}

pub struct AsIfPrinted;

impl VisitMut for AsIfPrinted {
    fn visit_file_mut(&mut self, file: &mut File) {
        file.shebang = None;
        visit_mut::visit_file_mut(self, file);
    }

    fn visit_generics_mut(&mut self, generics: &mut Generics) {
        if generics.params.is_empty() {
            generics.lt_token = None;
            generics.gt_token = None;
        }
        if let Some(where_clause) = &generics.where_clause {
            if where_clause.predicates.is_empty() {
                generics.where_clause = None;
            }
        }
        visit_mut::visit_generics_mut(self, generics);
    }

    fn visit_lifetime_param_mut(&mut self, param: &mut LifetimeParam) {
        if param.bounds.is_empty() {
            param.colon_token = None;
        }
        visit_mut::visit_lifetime_param_mut(self, param);
    }

    fn visit_stmt_mut(&mut self, stmt: &mut Stmt) {
        if let Stmt::Expr(expr, semi) = stmt {
            if let Expr::Macro(e) = expr {
                if match e.mac.delimiter {
                    MacroDelimiter::Brace(_) => true,
                    MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => semi.is_some(),
                } {
                    let Expr::Macro(expr) = mem::replace(expr, Expr::PLACEHOLDER) else {
                        unreachable!();
                    };
                    *stmt = Stmt::Macro(StmtMacro {
                        attrs: expr.attrs,
                        mac: expr.mac,
                        semi_token: *semi,
                    });
                }
            }
        }
        visit_mut::visit_stmt_mut(self, stmt);
    }

    fn visit_type_param_mut(&mut self, param: &mut TypeParam) {
        if param.bounds.is_empty() {
            param.colon_token = None;
        }
        visit_mut::visit_type_param_mut(self, param);
    }
}