1use std::ops::ControlFlow;
2
3use crate::ast;
4use crate::symbol::{ConstOwner, Symbol};
5
6#[derive(Clone, Copy)]
8pub enum SymbolFilter {
9 ItemsOnly,
11 ItemsAndItemElements,
13 All,
15}
16
17pub fn walk_symbols<'a, F: FnMut(Symbol<'a>)>(ast: &'a ast::Aidl, filter: SymbolFilter, mut f: F) {
21 walk_symbols_with_control_flow(ast, filter, |smb| -> ControlFlow<()> {
22 f(smb);
23 ControlFlow::Continue(())
24 });
25}
26
27pub fn filter_symbols<'a, F>(ast: &'a ast::Aidl, filter: SymbolFilter, mut f: F) -> Vec<Symbol<'a>>
34where
35 F: FnMut(&Symbol<'a>) -> bool,
36{
37 let mut v = Vec::new();
38 walk_symbols(ast, filter, |symbol| {
39 if f(&symbol) {
40 v.push(symbol);
41 }
42 });
43
44 v
45}
46
47pub fn find_symbol<'a, F>(ast: &'a ast::Aidl, filter: SymbolFilter, mut f: F) -> Option<Symbol<'a>>
54where
55 F: FnMut(&Symbol<'a>) -> bool,
56{
57 let res = walk_symbols_with_control_flow(ast, filter, |smb| -> ControlFlow<Symbol<'a>> {
58 if f(&smb) {
59 ControlFlow::Break(smb)
60 } else {
61 ControlFlow::Continue(())
62 }
63 });
64
65 match res {
66 ControlFlow::Continue(_) => None,
67 ControlFlow::Break(smb) => Some(smb),
68 }
69}
70
71pub fn find_symbol_at_line_col(
78 ast: &ast::Aidl,
79 filter: SymbolFilter,
80 line_col: (usize, usize),
81) -> Option<Symbol> {
82 find_symbol(ast, filter, |smb| range_contains(smb.get_range(), line_col))
83}
84
85#[allow(clippy::needless_borrow)] fn walk_symbols_with_control_flow<'a, V, F>(
87 ast: &'a ast::Aidl,
88 filter: SymbolFilter,
89 mut f: F,
90) -> ControlFlow<V>
91where
92 F: FnMut(Symbol<'a>) -> ControlFlow<V>,
93{
94 macro_rules! visit_type_helper {
95 ($t:expr, $f:ident) => {
96 if $t.kind == ast::TypeKind::Array {
97 $t.generic_types
99 .iter()
100 .try_for_each(|t| $f(Symbol::Type(t)))?;
101 $f(Symbol::Type($t))?;
102 } else {
103 $f(Symbol::Type($t))?;
105 $t.generic_types
106 .iter()
107 .try_for_each(|t| $f(Symbol::Type(t)))?;
108 }
109 };
110 }
111
112 if let SymbolFilter::All = filter {
113 f(Symbol::Package(&ast.package));
114
115 for import in &ast.imports {
116 f(Symbol::Import(import))?;
117 }
118 }
119
120 match ast.item {
121 ast::Item::Interface(ref i) => {
122 f(Symbol::Interface(i, &ast.package))?;
123 if let SymbolFilter::ItemsOnly = filter {
124 return ControlFlow::Continue(());
125 }
126
127 i.elements.iter().try_for_each(|el| match el {
128 ast::InterfaceElement::Method(m) => {
129 f(Symbol::Method(m, i))?;
130 if let SymbolFilter::All = filter {
131 visit_type_helper!(&m.return_type, f);
132 m.args.iter().try_for_each(|arg| {
133 f(Symbol::Arg(arg, m))?;
134 visit_type_helper!(&arg.arg_type, f);
135 ControlFlow::Continue(())
136 })?;
137 }
138 ControlFlow::Continue(())
139 }
140 ast::InterfaceElement::Const(c) => {
141 f(Symbol::Const(c, ConstOwner::Interface(i)))?;
142 if let SymbolFilter::All = filter {
143 visit_type_helper!(&c.const_type, f);
144 }
145 ControlFlow::Continue(())
146 }
147 })?;
148 }
149 ast::Item::Parcelable(ref p) => {
150 f(Symbol::Parcelable(p, &ast.package))?;
151 if let SymbolFilter::ItemsOnly = filter {
152 return ControlFlow::Continue(());
153 }
154
155 p.elements.iter().try_for_each(|el| match el {
156 ast::ParcelableElement::Field(fi) => {
157 f(Symbol::Field(fi, p))?;
158 if let SymbolFilter::All = filter {
159 visit_type_helper!(&fi.field_type, f);
160 }
161
162 ControlFlow::Continue(())
163 }
164 ast::ParcelableElement::Const(c) => {
165 f(Symbol::Const(c, ConstOwner::Parcelable(p)))?;
166 if let SymbolFilter::All = filter {
167 visit_type_helper!(&c.const_type, f);
168 }
169 ControlFlow::Continue(())
170 }
171 })?;
172 }
173 ast::Item::Enum(ref e) => {
174 f(Symbol::Enum(e, &ast.package))?;
175 if let SymbolFilter::ItemsOnly = filter {
176 return ControlFlow::Continue(());
177 }
178
179 e.elements.iter().try_for_each(|el| {
180 f(Symbol::EnumElement(el, e))?;
181 ControlFlow::Continue(())
182 })?;
183 }
184 }
185
186 ControlFlow::Continue(())
187}
188
189fn range_contains(range: &ast::Range, line_col: (usize, usize)) -> bool {
190 if range.start.line_col.0 > line_col.0 {
191 return false;
192 }
193
194 if range.start.line_col.0 == line_col.0 && range.start.line_col.1 > line_col.1 {
195 return false;
196 }
197
198 if range.end.line_col.0 < line_col.0 {
199 return false;
200 }
201
202 if range.end.line_col.0 == line_col.0 && range.end.line_col.1 < line_col.1 {
203 return false;
204 }
205
206 true
207}
208
209pub fn walk_types<F: FnMut(&ast::Type)>(ast: &ast::Aidl, mut f: F) {
211 let mut visit_type_helper = move |type_: &ast::Type| {
212 if type_.kind == ast::TypeKind::Array {
213 type_.generic_types.iter().for_each(&mut f);
215 f(type_);
216 } else {
217 f(type_);
219 type_.generic_types.iter().for_each(&mut f);
220 }
221 };
222
223 match ast.item {
224 ast::Item::Interface(ref i) => {
225 i.elements.iter().for_each(|el| match el {
226 ast::InterfaceElement::Method(m) => {
227 visit_type_helper(&m.return_type);
228 m.args.iter().for_each(|arg| {
229 visit_type_helper(&arg.arg_type);
230 })
231 }
232 ast::InterfaceElement::Const(c) => {
233 visit_type_helper(&c.const_type);
234 }
235 });
236 }
237 ast::Item::Parcelable(ref p) => {
238 p.elements.iter().for_each(|el| match el {
239 ast::ParcelableElement::Field(fi) => {
240 visit_type_helper(&fi.field_type);
241 }
242 ast::ParcelableElement::Const(c) => {
243 visit_type_helper(&c.const_type);
244 }
245 });
246 }
247 ast::Item::Enum(_) => (),
248 }
249}
250
251pub(crate) fn walk_types_mut<F: FnMut(&mut ast::Type)>(ast: &mut ast::Aidl, mut f: F) {
252 let mut visit_type_helper = move |type_: &mut ast::Type| {
253 f(type_);
254 type_.generic_types.iter_mut().for_each(&mut f);
255 };
256
257 match ast.item {
258 ast::Item::Interface(ref mut i) => {
259 i.elements.iter_mut().for_each(|el| match el {
260 ast::InterfaceElement::Method(m) => {
261 visit_type_helper(&mut m.return_type);
262 m.args.iter_mut().for_each(|arg| {
263 visit_type_helper(&mut arg.arg_type);
264 })
265 }
266 ast::InterfaceElement::Const(c) => {
267 visit_type_helper(&mut c.const_type);
268 }
269 });
270 }
271 ast::Item::Parcelable(ref mut p) => {
272 p.elements.iter_mut().for_each(|el| match el {
273 ast::ParcelableElement::Field(fi) => {
274 visit_type_helper(&mut fi.field_type);
275 }
276 ast::ParcelableElement::Const(c) => {
277 visit_type_helper(&mut c.const_type);
278 }
279 });
280 }
281 ast::Item::Enum(_) => (),
282 }
283}
284
285pub fn walk_methods<'a, F: FnMut(&'a ast::Method)>(ast: &'a ast::Aidl, mut f: F) {
287 match ast.item {
288 ast::Item::Interface(ref i) => {
289 i.elements.iter().for_each(|el| match el {
290 ast::InterfaceElement::Method(m) => f(m),
291 ast::InterfaceElement::Const(_) => (),
292 });
293 }
294 ast::Item::Parcelable(_) => (),
295 ast::Item::Enum(_) => (),
296 }
297}
298
299pub fn walk_args<'a, F: FnMut(&'a ast::Method, &'a ast::Arg)>(ast: &'a ast::Aidl, mut f: F) {
301 match ast.item {
302 ast::Item::Interface(ref i) => {
303 i.elements.iter().for_each(|el| match el {
304 ast::InterfaceElement::Method(m) => m.args.iter().for_each(|arg| {
305 f(m, arg);
306 }),
307 ast::InterfaceElement::Const(_) => (),
308 });
309 }
310 ast::Item::Parcelable(_) => (),
311 ast::Item::Enum(_) => (),
312 }
313}