| 56 | type Error = io::Error; |
| 57 | |
| 58 | fn matched(&mut self, _searcher: &Searcher, mat: &SinkMatch<'_>) -> Result<bool, io::Error> { |
| 59 | let mut captures = self.matcher.new_captures()?; |
| 60 | let line = match from_utf8(mat.bytes()) { |
| 61 | Ok(matched) => matched, |
| 62 | Err(err) => return Err(io::Error::error_message(err)), |
| 63 | }; |
| 64 | self.matcher.captures_iter(mat.bytes(), &mut captures, |captures| -> bool { |
| 65 | // Group 1 contains everything between derive and pub struct/enum |
| 66 | let attrs_section = &line[captures.get(1).unwrap()]; |
| 67 | |
| 68 | // Search for visit attribute in the captured section |
| 69 | // The default (no visit attr) is Children mode per derive macro semantics |
| 70 | let visit_mode = if attrs_section.contains("visit(skip)") { |
| 71 | VisitMode::Skip |
| 72 | } else if attrs_section.contains("visit(children)") { |
| 73 | VisitMode::Children |
| 74 | } else if attrs_section.contains("visit(all)") { |
| 75 | VisitMode::All |
| 76 | } else if attrs_section.contains("visit(self)") { |
| 77 | VisitMode::Self_ |
| 78 | } else if attrs_section.contains("visit") { |
| 79 | // Just `visit` (or `visit()`) means visit self AND children |
| 80 | VisitMode::Self_ |
| 81 | } else { |
| 82 | // No visit attribute found - default is children only (not queryable) |
| 83 | VisitMode::Children |
| 84 | }; |
| 85 | |
| 86 | let capture = format!("{} {} {{}}", &line[captures.get(2).unwrap()], &line[captures.get(5).unwrap()]); |
| 87 | match parse_str::<DeriveInput>(&capture) { |
| 88 | Ok(input) => { |
| 89 | self.matches.insert(VisitableNode { input, visit_mode }); |
| 90 | } |
| 91 | Err(err) => { |
| 92 | panic!("#[visit] or unknown: {capture} {err}"); |
| 93 | } |
| 94 | } |
| 95 | true |
| 96 | })?; |
| 97 | Ok(true) |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | fn build_visit_attr_matcher() -> RegexMatcher { |