rustfmt_nightly/modules/
visitor.rs1use rustc_ast::ast;
2use rustc_ast::visit::Visitor;
3use rustc_span::{Symbol, sym};
4use tracing::debug;
5
6use crate::attr::MetaVisitor;
7use crate::parse::macros::cfg_if::parse_cfg_if;
8use crate::parse::macros::cfg_match::parse_cfg_match;
9use crate::parse::session::ParseSess;
10
11pub(crate) struct ModItem {
12 pub(crate) item: ast::Item,
13}
14
15pub(crate) struct CfgIfVisitor<'a> {
17 psess: &'a ParseSess,
18 mods: Vec<ModItem>,
19}
20
21impl<'a> CfgIfVisitor<'a> {
22 pub(crate) fn new(psess: &'a ParseSess) -> CfgIfVisitor<'a> {
23 CfgIfVisitor {
24 mods: vec![],
25 psess,
26 }
27 }
28
29 pub(crate) fn mods(self) -> Vec<ModItem> {
30 self.mods
31 }
32}
33
34impl<'a, 'ast: 'a> Visitor<'ast> for CfgIfVisitor<'a> {
35 fn visit_mac_call(&mut self, mac: &'ast ast::MacCall) {
36 match self.visit_mac_inner(mac) {
37 Ok(()) => (),
38 Err(e) => debug!("{}", e),
39 }
40 }
41}
42
43impl<'a, 'ast: 'a> CfgIfVisitor<'a> {
44 fn visit_mac_inner(&mut self, mac: &'ast ast::MacCall) -> Result<(), &'static str> {
45 match mac.path.segments.first() {
57 Some(first_segment) => {
58 if first_segment.ident.name != Symbol::intern("cfg_if") {
59 return Err("Expected cfg_if");
60 }
61 }
62 None => {
63 return Err("Expected cfg_if");
64 }
65 };
66
67 let items = parse_cfg_if(self.psess, mac)?;
68 self.mods
69 .append(&mut items.into_iter().map(|item| ModItem { item }).collect());
70
71 Ok(())
72 }
73}
74
75pub(crate) struct CfgMatchVisitor<'a> {
77 psess: &'a ParseSess,
78 mods: Vec<ModItem>,
79}
80
81impl<'a> CfgMatchVisitor<'a> {
82 pub(crate) fn new(psess: &'a ParseSess) -> CfgMatchVisitor<'a> {
83 CfgMatchVisitor {
84 mods: vec![],
85 psess,
86 }
87 }
88
89 pub(crate) fn mods(self) -> Vec<ModItem> {
90 self.mods
91 }
92}
93
94impl<'a, 'ast: 'a> Visitor<'ast> for CfgMatchVisitor<'a> {
95 fn visit_mac_call(&mut self, mac: &'ast ast::MacCall) {
96 match self.visit_mac_inner(mac) {
97 Ok(()) => (),
98 Err(e) => debug!("{}", e),
99 }
100 }
101}
102
103impl<'a, 'ast: 'a> CfgMatchVisitor<'a> {
104 fn visit_mac_inner(&mut self, mac: &'ast ast::MacCall) -> Result<(), &'static str> {
105 match mac.path.segments.last() {
116 Some(last_segment) => {
117 if last_segment.ident.name != Symbol::intern("cfg_match") {
118 return Err("Expected cfg_match");
119 }
120 }
121 None => {
122 return Err("Expected cfg_match");
123 }
124 };
125
126 let items = parse_cfg_match(self.psess, mac)?;
127 self.mods
128 .append(&mut items.into_iter().map(|item| ModItem { item }).collect());
129
130 Ok(())
131 }
132}
133
134#[derive(Default)]
136pub(crate) struct PathVisitor {
137 paths: Vec<String>,
139}
140
141impl PathVisitor {
142 pub(crate) fn paths(self) -> Vec<String> {
143 self.paths
144 }
145}
146
147impl<'ast> MetaVisitor<'ast> for PathVisitor {
148 fn visit_meta_name_value(
149 &mut self,
150 meta_item: &'ast ast::MetaItem,
151 lit: &'ast ast::MetaItemLit,
152 ) {
153 if meta_item.has_name(sym::path) && lit.kind.is_str() {
154 self.paths.push(meta_item_lit_to_str(lit));
155 }
156 }
157}
158
159#[cfg(not(windows))]
160fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String {
161 match lit.kind {
162 ast::LitKind::Str(symbol, ..) => symbol.to_string(),
163 _ => unreachable!(),
164 }
165}
166
167#[cfg(windows)]
168fn meta_item_lit_to_str(lit: &ast::MetaItemLit) -> String {
169 match lit.kind {
170 ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"),
171 _ => unreachable!(),
172 }
173}