syn_locator/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{
4    any::{Any, TypeId},
5    cell::RefCell,
6    collections::HashMap,
7    fmt,
8    pin::Pin,
9};
10
11pub trait LocateEntry: Locate {
12    fn locate_as_entry(self: Pin<&Self>, file_path: &str, code: &str) {
13        let loc = self.location(file_path, code);
14        self.locate(loc.file_path, code, 0);
15    }
16
17    #[doc(hidden)]
18    fn location(self: Pin<&Self>, file_path: &str, code: &str) -> Location {
19        LOCATOR.with_borrow_mut(|locator| locator.insert_file(&*self, file_path, code))
20    }
21}
22
23impl<T: Locate> LocateEntry for T {}
24
25pub trait Locate: Any {
26    // impl
27    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location;
28
29    fn relocate(&self, loc: Location) {
30        LOCATOR.with_borrow_mut(|locator| {
31            locator.set_location(self, loc);
32        });
33    }
34
35    // call from parent node
36    fn locate(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
37        let loc = self.find_loc(file_path, code, offset);
38        LOCATOR.with_borrow_mut(|locator| {
39            locator.set_location(self, loc);
40        });
41        loc
42    }
43
44    fn location(&self) -> Location
45    where
46        Self: fmt::Debug,
47    {
48        LOCATOR
49            .with_borrow(|locator| locator.get_location(self))
50            .unwrap_or_else(|| {
51                panic!(
52                    "failed to find the location of `{self:?}`. did you forget `Locate::locate`?"
53                )
54            })
55    }
56
57    fn location_message(&self) -> String
58    where
59        Self: fmt::Debug,
60    {
61        LOCATOR
62            .with_borrow(|locator| {
63                let loc = locator.get_location(self)?;
64                let path = loc.file_path;
65                let code = locator.get_code(path)?;
66                let line = code.as_bytes()[..loc.start]
67                    .iter()
68                    .filter(|&&b| b == b'\n')
69                    .count()
70                    + 1;
71                let content = &code[loc.start..loc.end];
72
73                Some(format!("{path}:{line}: {content}"))
74            })
75            .unwrap_or_else(|| {
76                panic!(
77                    "failed to find the location of `{self:?}`. did you forget `Locate::locate`?"
78                )
79            })
80    }
81
82    fn code(&self) -> String
83    where
84        Self: fmt::Debug,
85    {
86        LOCATOR
87            .with_borrow(|locator| {
88                let loc = locator.get_location(self)?;
89                let path = loc.file_path;
90                let code = locator.get_code(path)?;
91                let content = &code[loc.start..loc.end];
92
93                Some(content.to_owned())
94            })
95            .unwrap_or_else(|| {
96                panic!(
97                    "failed to find the location of `{self:?}`. did you forget `Locate::locate`?"
98                )
99            })
100    }
101}
102
103pub trait LocateGroup {
104    fn locate_as_group(&self, file_path: &'static str, code: &str, offset: usize) -> Location;
105    fn relocate_as_group(&self, loc: Location);
106}
107
108macro_rules! impl_locate_group {
109    ( $($i:expr),* ; $($ri:expr),* ) => {
110        paste::paste! {
111            impl<'a, $([<A $i>]: Locate),*> LocateGroup for ( $( &'a [<A $i>] ),* ) {
112                #[allow(unused_assignments)]
113                fn locate_as_group(&self, file_path: &'static str, code: &str, offset: usize)
114                    -> Location
115                {
116                    let ( $( [<this $i>] ),* ) = self;
117
118                    // Calls locate() on children.
119                    let mut end = offset;
120                    $(
121                        let [<loc $i>] = [<this $i>].locate(file_path, code, end);
122                        end = [<loc $i>].end;
123                    )*
124
125                    // Determines start.
126                    let mut start = usize::MAX;
127                    $(
128                        if [<loc $i>].start != [<loc $i>].end {
129                            start = start.min( [<loc $i>].start );
130                        }
131                    )*
132                    if start == usize::MAX {
133                        start = offset;
134                    }
135
136                    // Relocates empty children to the closest non-empty child.
137                    let mut cur = end;
138                    $(
139                        if [<loc $ri>].start == [<loc $ri>].end {
140                            [<this $ri>].relocate(Location {
141                                file_path,
142                                start: cur,
143                                end: cur
144                            });
145                        } else {
146                            cur = [<loc $ri>].start;
147                        }
148                    )*
149
150                    Location {
151                        file_path,
152                        start,
153                        end
154                    }
155                }
156
157                fn relocate_as_group(&self, loc: Location) {
158                    let ( $( [<this $i>] ),* ) = self;
159
160                    // Calls relocate() on children.
161                    $(
162                        [<this $i>].relocate(loc);
163                    )*
164                }
165            }
166        }
167    };
168}
169
170impl LocateGroup for () {
171    fn locate_as_group(&self, file_path: &'static str, _code: &str, offset: usize) -> Location {
172        Location {
173            file_path,
174            start: offset,
175            end: offset,
176        }
177    }
178
179    fn relocate_as_group(&self, _: Location) {}
180}
181
182impl<T: Locate> LocateGroup for &T {
183    fn locate_as_group(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
184        self.locate(file_path, code, offset)
185    }
186
187    fn relocate_as_group(&self, loc: Location) {
188        self.relocate(loc)
189    }
190}
191
192impl_locate_group!(0, 1 ; 1, 0);
193impl_locate_group!(0, 1, 2 ; 2, 1, 0);
194impl_locate_group!(0, 1, 2, 3 ; 3, 2, 1, 0);
195impl_locate_group!(0, 1, 2, 3, 4 ; 4, 3, 2, 1, 0);
196impl_locate_group!(0, 1, 2, 3, 4, 5 ; 5, 4, 3, 2, 1, 0);
197impl_locate_group!(0, 1, 2, 3, 4, 5, 6 ; 6, 5, 4, 3, 2, 1, 0);
198impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7 ; 7, 6, 5, 4, 3, 2, 1, 0);
199impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8 ; 8, 7, 6, 5, 4, 3, 2, 1, 0);
200impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ; 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
201impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
202
203pub struct Surround<'s, F, S, I, B> {
204    pub front: F,
205    pub surround: &'s S,
206    pub inner: I,
207    pub back: B,
208}
209
210impl<F, S, I, B> Surround<'_, F, S, I, B>
211where
212    F: LocateGroup,
213    S: Locate,
214    I: LocateGroup,
215    B: LocateGroup,
216{
217    pub fn locate(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
218        // Calls locate() on fields.
219        let front_loc = self.front.locate_as_group(file_path, code, offset);
220        let surround_loc = self.surround.locate(file_path, code, front_loc.end);
221        self.inner
222            .locate_as_group(file_path, code, surround_loc.start + 1);
223        let back_loc = self.back.locate_as_group(file_path, code, surround_loc.end);
224
225        // Relocates front if needed
226        let mut start = front_loc.start;
227        if front_loc.start == front_loc.end {
228            self.front.relocate_as_group(Location {
229                file_path,
230                start: surround_loc.start,
231                end: surround_loc.start,
232            });
233            start = surround_loc.start;
234        }
235
236        // Relocates back if needed
237        let mut end = back_loc.end;
238        if back_loc.start == back_loc.end {
239            self.back.relocate_as_group(Location {
240                file_path,
241                start: surround_loc.end,
242                end: surround_loc.end,
243            });
244            end = surround_loc.end;
245        }
246
247        Location {
248            file_path,
249            start,
250            end,
251        }
252    }
253}
254
255pub struct Qualified<'a, F, B> {
256    pub front: F,
257    pub qself: &'a syn::QSelf,
258    pub path: &'a syn::Path,
259    pub back: B,
260}
261
262impl<F, B> Qualified<'_, F, B>
263where
264    F: LocateGroup,
265    B: LocateGroup,
266{
267    pub fn locate(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
268        // Calls locate() on fields.
269        let front_loc = self.front.locate_as_group(file_path, code, offset);
270
271        let qself_loc = self.qself.locate(file_path, code, front_loc.end);
272        let qself_mid_loc = self.qself.as_token.location();
273
274        // Path will be evaluated on something like `a::b::Trait>::Assoc`. The
275        // string contains '>' though, it would be fine because we will skip it
276        // during string matching.
277        let path_loc = self.path.locate(file_path, code, qself_mid_loc.end);
278
279        let back_loc = self.back.locate_as_group(file_path, code, path_loc.end);
280
281        // Relocates front if needed
282        let mut start = front_loc.start;
283        if front_loc.start == front_loc.end {
284            self.front.relocate_as_group(Location {
285                file_path,
286                start: qself_loc.start,
287                end: qself_loc.start,
288            });
289            start = qself_loc.start;
290        }
291
292        // Relocates back if needed
293        let mut end = back_loc.end;
294        if back_loc.start == back_loc.end {
295            self.back.relocate_as_group(Location {
296                file_path,
297                start: path_loc.end,
298                end: path_loc.end,
299            });
300            end = path_loc.end;
301        }
302
303        Location {
304            file_path,
305            start,
306            end,
307        }
308    }
309}
310
311pub struct Locator {
312    files: HashMap<&'static str, File>,
313    map: HashMap<LocationKey, Location>,
314}
315
316impl Locator {
317    fn new() -> Self {
318        Self {
319            files: HashMap::new(),
320            map: HashMap::new(),
321        }
322    }
323
324    /// Inserts file then returns its index.
325    fn insert_file<T: Any + ?Sized>(
326        &mut self,
327        syn_file: &T,
328        file_path: &str,
329        code: &str,
330    ) -> Location {
331        fn inner(this: &mut Locator, key: LocationKey, file_path: &str, code: &str) -> Location {
332            if let Some(loc) = this.map.get(&key) {
333                return *loc;
334            }
335            if this.files.contains_key(file_path) {
336                panic!("duplicate `{file_path}`");
337            }
338
339            let file_path: Box<str> = file_path.into();
340            let file_path = Box::leak(file_path);
341            this.files.insert(file_path, File::new(code));
342
343            let loc = Location {
344                file_path,
345                start: 0,
346                end: code.len(),
347            };
348            this.map.insert(key, loc);
349
350            loc
351        }
352
353        inner(self, LocationKey::new(syn_file), file_path, code)
354    }
355
356    fn set_location<T: Any + ?Sized>(&mut self, syn_node: &T, loc: Location) {
357        self.map.insert(LocationKey::new(syn_node), loc);
358    }
359
360    fn get_location<T: Any + ?Sized>(&self, syn_node: &T) -> Option<Location> {
361        self.map.get(&LocationKey::new(syn_node)).cloned()
362    }
363
364    fn get_code(&self, file_path: &str) -> Option<&str> {
365        self.files.get(file_path).map(|file| file.code.as_str())
366    }
367}
368
369impl Drop for Locator {
370    fn drop(&mut self) {
371        for (file_path, _) in self.files.drain() {
372            let ptr = file_path as *const str as *mut str;
373            unsafe { drop(Box::from_raw(ptr)) };
374        }
375    }
376}
377
378struct File {
379    /// Filtered Rust code.
380    code: String,
381}
382
383impl File {
384    fn new(code: &str) -> Self {
385        Self {
386            code: Self::remove_non_tokens(code),
387        }
388    }
389
390    /// Replaces comments with white spaces from the given code for further
391    /// token matching.
392    fn remove_non_tokens(code: &str) -> String {
393        use regex::{Captures, Regex};
394
395        // Regex doesn't support recursion, so that we cannot remove nested
396        // comments. We need to write code from scratch to do that.
397        thread_local! {
398            static RE: Regex = Regex::new(r#"(?x)
399                (//[^\n]*)  # Single line comment
400                |
401                (?s)
402                (/\*.*?\*/) # Block comment (Recursion is not supported)
403            "#).unwrap();
404        }
405
406        RE.with(|re| re.replace_all(code, |caps: &Captures| " ".repeat(caps[0].len())))
407            .into_owned()
408    }
409}
410
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
412struct LocationKey {
413    ptr: *const (),
414
415    // Because pointer of a struct is the same as pointer of the first child of
416    // it, we distinguash them using type id.
417    ty: TypeId,
418}
419
420impl LocationKey {
421    fn new<T: Any + ?Sized>(t: &T) -> Self {
422        Self {
423            ptr: t as *const T as *const (),
424            ty: TypeId::of::<T>(),
425        }
426    }
427}
428
429#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
430pub struct Location {
431    pub file_path: &'static str,
432
433    /// Byte index to the code.
434    pub start: usize,
435
436    /// Byte index to the code. Exclusive
437    pub end: usize,
438}
439
440thread_local! {
441    static LOCATOR: RefCell<Locator> = RefCell::new(Locator::new());
442}
443
444macro_rules! impl_locate_for_token {
445    ($ty:ty, $token:literal, char) => {
446        impl Locate for $ty {
447            fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
448                helper::char_location(file_path, code, offset, $token)
449            }
450        }
451    };
452    ($ty:ty, $token:literal, str) => {
453        impl Locate for $ty {
454            fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
455                helper::str_location(file_path, code, offset, $token)
456            }
457        }
458    };
459}
460
461impl_locate_for_token!(syn::Token![abstract], "abstract", str);
462impl_locate_for_token!(syn::Token![as], "as", str);
463impl_locate_for_token!(syn::Token![async], "async", str);
464impl_locate_for_token!(syn::Token![auto], "auto", str);
465impl_locate_for_token!(syn::Token![await], "await", str);
466impl_locate_for_token!(syn::Token![become], "become", str);
467impl_locate_for_token!(syn::Token![box], "box", str);
468impl_locate_for_token!(syn::Token![break], "break", str);
469impl_locate_for_token!(syn::Token![const], "const", str);
470impl_locate_for_token!(syn::Token![continue], "continue", str);
471impl_locate_for_token!(syn::Token![crate], "crate", str);
472impl_locate_for_token!(syn::Token![default], "default", str);
473impl_locate_for_token!(syn::Token![do], "do", str);
474impl_locate_for_token!(syn::Token![dyn], "dyn", str);
475impl_locate_for_token!(syn::Token![else], "else", str);
476impl_locate_for_token!(syn::Token![enum], "enum", str);
477impl_locate_for_token!(syn::Token![extern], "extern", str);
478impl_locate_for_token!(syn::Token![final], "final", str);
479impl_locate_for_token!(syn::Token![fn], "fn", str);
480impl_locate_for_token!(syn::Token![for], "for", str);
481impl_locate_for_token!(syn::Token![if], "if", str);
482impl_locate_for_token!(syn::Token![impl], "impl", str);
483impl_locate_for_token!(syn::Token![in], "in", str);
484impl_locate_for_token!(syn::Token![let], "let", str);
485impl_locate_for_token!(syn::Token![loop], "loop", str);
486impl_locate_for_token!(syn::Token![macro], "macro", str);
487impl_locate_for_token!(syn::Token![match], "match", str);
488impl_locate_for_token!(syn::Token![mod], "mod", str);
489impl_locate_for_token!(syn::Token![move], "move", str);
490impl_locate_for_token!(syn::Token![mut], "mut", str);
491impl_locate_for_token!(syn::Token![override], "override", str);
492impl_locate_for_token!(syn::Token![priv], "priv", str);
493impl_locate_for_token!(syn::Token![pub], "pub", str);
494impl_locate_for_token!(syn::Token![raw], "raw", str);
495impl_locate_for_token!(syn::Token![ref], "ref", str);
496impl_locate_for_token!(syn::Token![return], "return", str);
497impl_locate_for_token!(syn::Token![Self], "Self", str);
498impl_locate_for_token!(syn::Token![self], "self", str);
499impl_locate_for_token!(syn::Token![static], "static", str);
500impl_locate_for_token!(syn::Token![struct], "struct", str);
501impl_locate_for_token!(syn::Token![super], "super", str);
502impl_locate_for_token!(syn::Token![trait], "trait", str);
503impl_locate_for_token!(syn::Token![try], "try", str);
504impl_locate_for_token!(syn::Token![type], "type", str);
505impl_locate_for_token!(syn::Token![typeof], "typeof", str);
506impl_locate_for_token!(syn::Token![union], "union", str);
507impl_locate_for_token!(syn::Token![unsafe], "unsafe", str);
508impl_locate_for_token!(syn::Token![unsized], "unsized", str);
509impl_locate_for_token!(syn::Token![use], "use", str);
510impl_locate_for_token!(syn::Token![virtual], "virtual", str);
511impl_locate_for_token!(syn::Token![where], "where", str);
512impl_locate_for_token!(syn::Token![while], "while", str);
513impl_locate_for_token!(syn::Token![yield], "yield", str);
514impl_locate_for_token!(syn::Token![&], '&', char);
515impl_locate_for_token!(syn::Token![&&], "&&", str);
516impl_locate_for_token!(syn::Token![&=], "&=", str);
517impl_locate_for_token!(syn::Token![@], '@', char);
518impl_locate_for_token!(syn::Token![^], '^', char);
519impl_locate_for_token!(syn::Token![^=], "^=", str);
520impl_locate_for_token!(syn::Token![:], ':', char);
521impl_locate_for_token!(syn::Token![,], ',', char);
522impl_locate_for_token!(syn::Token![$], '$', char);
523impl_locate_for_token!(syn::Token![.], '.', char);
524impl_locate_for_token!(syn::Token![..], "..", str);
525impl_locate_for_token!(syn::Token![...], "...", str);
526impl_locate_for_token!(syn::Token![..=], "..=", str);
527impl_locate_for_token!(syn::Token![=], '=', char);
528impl_locate_for_token!(syn::Token![==], "==", str);
529impl_locate_for_token!(syn::Token![=>], "=>", str);
530impl_locate_for_token!(syn::Token![>=], ">=", str);
531impl_locate_for_token!(syn::Token![>], '>', char);
532impl_locate_for_token!(syn::Token![<-], "<-", str);
533impl_locate_for_token!(syn::Token![<=], "<=", str);
534impl_locate_for_token!(syn::Token![<], '<', char);
535impl_locate_for_token!(syn::Token![-], '-', char);
536impl_locate_for_token!(syn::Token![-=], "-=", str);
537impl_locate_for_token!(syn::Token![!=], "!=", str);
538impl_locate_for_token!(syn::Token![!], '!', char);
539impl_locate_for_token!(syn::Token![|], '|', char);
540impl_locate_for_token!(syn::Token![|=], "|=", str);
541impl_locate_for_token!(syn::Token![||], "||", str);
542impl_locate_for_token!(syn::Token![::], "::", str);
543impl_locate_for_token!(syn::Token![%], '%', char);
544impl_locate_for_token!(syn::Token![%=], "%=", str);
545impl_locate_for_token!(syn::Token![+], '+', char);
546impl_locate_for_token!(syn::Token![+=], "+=", str);
547impl_locate_for_token!(syn::Token![#], '#', char);
548impl_locate_for_token!(syn::Token![?], '?', char);
549impl_locate_for_token!(syn::Token![->], "->", str);
550impl_locate_for_token!(syn::Token![;], ';', char);
551impl_locate_for_token!(syn::Token![<<], "<<", str);
552impl_locate_for_token!(syn::Token![<<=], "<<=", str);
553impl_locate_for_token!(syn::Token![>>], ">>", str);
554impl_locate_for_token!(syn::Token![>>=], ">>=", str);
555impl_locate_for_token!(syn::Token![/], '/', char);
556impl_locate_for_token!(syn::Token![/=], "/=", str);
557impl_locate_for_token!(syn::Token![*], '*', char);
558impl_locate_for_token!(syn::Token![*=], "*=", str);
559impl_locate_for_token!(syn::Token![~], '~', char);
560impl_locate_for_token!(syn::Token![_], '_', char);
561
562impl Locate for syn::token::Group {
563    fn find_loc(&self, file_path: &'static str, _code: &str, offset: usize) -> Location {
564        Location {
565            file_path,
566            start: offset,
567            end: offset,
568        }
569    }
570}
571
572macro_rules! impl_locate_for_pair_tokens {
573    ($ty:ty, $open:literal, $close:literal) => {
574        impl Locate for $ty {
575            fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
576                const OPEN: char = $open;
577                const CLOSE: char = $close;
578
579                let code = &code[offset..];
580
581                let mut start = 0;
582                let mut end = 0;
583                let mut cur = offset;
584                let mut level = 0;
585
586                for c in code.chars() {
587                    if c == OPEN {
588                        if level == 0 {
589                            start = cur;
590                        }
591                        level += 1;
592                    } else if c == CLOSE {
593                        if level == 1 {
594                            end = cur + CLOSE.len_utf8();
595                            break;
596                        }
597                        if level > 0 {
598                            level -= 1;
599                        }
600                    }
601                    cur += c.len_utf8();
602                }
603
604                if start >= end {
605                    panic!("expected `{OPEN}..{CLOSE}` from {code}");
606                }
607
608                Location {
609                    file_path,
610                    start,
611                    end,
612                }
613            }
614        }
615    };
616}
617
618impl_locate_for_pair_tokens!(syn::token::Brace, '{', '}');
619impl_locate_for_pair_tokens!(syn::token::Bracket, '[', ']');
620impl_locate_for_pair_tokens!(syn::token::Paren, '(', ')');
621
622impl Locate for syn::Abi {
623    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
624        (&self.extern_token, &self.name).locate_as_group(file_path, code, offset)
625    }
626}
627
628impl Locate for syn::AngleBracketedGenericArguments {
629    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
630        (
631            &self.colon2_token,
632            &self.lt_token,
633            &self.args,
634            &self.gt_token,
635        )
636            .locate_as_group(file_path, code, offset)
637    }
638}
639
640impl Locate for syn::Arm {
641    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
642        if let Some((if_token, guard)) = &self.guard {
643            (
644                &self.attrs,
645                &self.pat,
646                if_token,
647                guard,
648                &self.fat_arrow_token,
649                &self.body,
650                &self.comma,
651            )
652                .locate_as_group(file_path, code, offset)
653        } else {
654            (
655                &self.attrs,
656                &self.pat,
657                &self.fat_arrow_token,
658                &self.body,
659                &self.comma,
660            )
661                .locate_as_group(file_path, code, offset)
662        }
663    }
664}
665
666impl Locate for syn::AssocConst {
667    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
668        (&self.ident, &self.generics, &self.eq_token, &self.value)
669            .locate_as_group(file_path, code, offset)
670    }
671}
672
673impl Locate for syn::AssocType {
674    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
675        (&self.ident, &self.generics, &self.eq_token, &self.ty)
676            .locate_as_group(file_path, code, offset)
677    }
678}
679
680impl Locate for syn::Attribute {
681    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
682        let pound_loc = self.pound_token.locate(file_path, code, offset);
683        let bracket_loc = self.bracket_token.locate(file_path, code, pound_loc.end);
684        self.meta.locate(file_path, code, bracket_loc.start + 1);
685
686        Location {
687            file_path,
688            start: pound_loc.start,
689            end: bracket_loc.end,
690        }
691    }
692}
693
694impl Locate for syn::BareFnArg {
695    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
696        if let Some((name, colon_token)) = &self.name {
697            (&self.attrs, name, colon_token, &self.ty).locate_as_group(file_path, code, offset)
698        } else {
699            (&self.attrs, &self.ty).locate_as_group(file_path, code, offset)
700        }
701    }
702}
703
704impl Locate for syn::BareVariadic {
705    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
706        if let Some((name, colon_token)) = &self.name {
707            (&self.attrs, name, colon_token, &self.dots, &self.comma)
708                .locate_as_group(file_path, code, offset)
709        } else {
710            (&self.attrs, &self.dots, &self.comma).locate_as_group(file_path, code, offset)
711        }
712    }
713}
714
715impl Locate for syn::BinOp {
716    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
717        match self {
718            Self::Add(v) => v.locate(file_path, code, offset),
719            Self::Sub(v) => v.locate(file_path, code, offset),
720            Self::Mul(v) => v.locate(file_path, code, offset),
721            Self::Div(v) => v.locate(file_path, code, offset),
722            Self::Rem(v) => v.locate(file_path, code, offset),
723            Self::And(v) => v.locate(file_path, code, offset),
724            Self::Or(v) => v.locate(file_path, code, offset),
725            Self::BitXor(v) => v.locate(file_path, code, offset),
726            Self::BitAnd(v) => v.locate(file_path, code, offset),
727            Self::BitOr(v) => v.locate(file_path, code, offset),
728            Self::Shl(v) => v.locate(file_path, code, offset),
729            Self::Shr(v) => v.locate(file_path, code, offset),
730            Self::Eq(v) => v.locate(file_path, code, offset),
731            Self::Lt(v) => v.locate(file_path, code, offset),
732            Self::Le(v) => v.locate(file_path, code, offset),
733            Self::Ne(v) => v.locate(file_path, code, offset),
734            Self::Ge(v) => v.locate(file_path, code, offset),
735            Self::Gt(v) => v.locate(file_path, code, offset),
736            Self::AddAssign(v) => v.locate(file_path, code, offset),
737            Self::SubAssign(v) => v.locate(file_path, code, offset),
738            Self::MulAssign(v) => v.locate(file_path, code, offset),
739            Self::DivAssign(v) => v.locate(file_path, code, offset),
740            Self::RemAssign(v) => v.locate(file_path, code, offset),
741            Self::BitXorAssign(v) => v.locate(file_path, code, offset),
742            Self::BitAndAssign(v) => v.locate(file_path, code, offset),
743            Self::BitOrAssign(v) => v.locate(file_path, code, offset),
744            Self::ShlAssign(v) => v.locate(file_path, code, offset),
745            Self::ShrAssign(v) => v.locate(file_path, code, offset),
746            _ => Location {
747                file_path,
748                start: offset,
749                end: offset,
750            },
751        }
752    }
753}
754
755impl Locate for syn::Block {
756    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
757        Surround {
758            front: (),
759            surround: &self.brace_token,
760            inner: &self.stmts,
761            back: (),
762        }
763        .locate(file_path, code, offset)
764    }
765}
766
767impl Locate for syn::BoundLifetimes {
768    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
769        (
770            &self.for_token,
771            &self.lt_token,
772            &self.lifetimes,
773            &self.gt_token,
774        )
775            .locate_as_group(file_path, code, offset)
776    }
777}
778
779impl Locate for syn::CapturedParam {
780    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
781        match self {
782            Self::Lifetime(v) => v.locate(file_path, code, offset),
783            Self::Ident(v) => v.locate(file_path, code, offset),
784            _ => Location {
785                file_path,
786                start: offset,
787                end: offset,
788            },
789        }
790    }
791}
792
793impl Locate for syn::ConstParam {
794    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
795        (
796            &self.attrs,
797            &self.const_token,
798            &self.ident,
799            &self.colon_token,
800            &self.ty,
801            &self.eq_token,
802            &self.default,
803        )
804            .locate_as_group(file_path, code, offset)
805    }
806}
807
808impl Locate for syn::Constraint {
809    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
810        (&self.ident, &self.generics, &self.colon_token, &self.bounds)
811            .locate_as_group(file_path, code, offset)
812    }
813}
814
815impl Locate for syn::Expr {
816    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
817        match self {
818            Self::Array(v) => v.locate(file_path, code, offset),
819            Self::Assign(v) => v.locate(file_path, code, offset),
820            Self::Async(v) => v.locate(file_path, code, offset),
821            Self::Await(v) => v.locate(file_path, code, offset),
822            Self::Binary(v) => v.locate(file_path, code, offset),
823            Self::Block(v) => v.locate(file_path, code, offset),
824            Self::Break(v) => v.locate(file_path, code, offset),
825            Self::Call(v) => v.locate(file_path, code, offset),
826            Self::Cast(v) => v.locate(file_path, code, offset),
827            Self::Closure(v) => v.locate(file_path, code, offset),
828            Self::Const(v) => v.locate(file_path, code, offset),
829            Self::Continue(v) => v.locate(file_path, code, offset),
830            Self::Field(v) => v.locate(file_path, code, offset),
831            Self::ForLoop(v) => v.locate(file_path, code, offset),
832            Self::Group(v) => v.locate(file_path, code, offset),
833            Self::If(v) => v.locate(file_path, code, offset),
834            Self::Index(v) => v.locate(file_path, code, offset),
835            Self::Infer(v) => v.locate(file_path, code, offset),
836            Self::Let(v) => v.locate(file_path, code, offset),
837            Self::Lit(v) => v.locate(file_path, code, offset),
838            Self::Loop(v) => v.locate(file_path, code, offset),
839            Self::Macro(v) => v.locate(file_path, code, offset),
840            Self::Match(v) => v.locate(file_path, code, offset),
841            Self::MethodCall(v) => v.locate(file_path, code, offset),
842            Self::Paren(v) => v.locate(file_path, code, offset),
843            Self::Path(v) => v.locate(file_path, code, offset),
844            Self::Range(v) => v.locate(file_path, code, offset),
845            Self::RawAddr(v) => v.locate(file_path, code, offset),
846            Self::Reference(v) => v.locate(file_path, code, offset),
847            Self::Repeat(v) => v.locate(file_path, code, offset),
848            Self::Return(v) => v.locate(file_path, code, offset),
849            Self::Struct(v) => v.locate(file_path, code, offset),
850            Self::Try(v) => v.locate(file_path, code, offset),
851            Self::TryBlock(v) => v.locate(file_path, code, offset),
852            Self::Tuple(v) => v.locate(file_path, code, offset),
853            Self::Unary(v) => v.locate(file_path, code, offset),
854            Self::Unsafe(v) => v.locate(file_path, code, offset),
855            Self::Verbatim(_) => Location {
856                file_path,
857                start: offset,
858                end: offset,
859            },
860            Self::While(v) => v.locate(file_path, code, offset),
861            Self::Yield(v) => v.locate(file_path, code, offset),
862            _ => Location {
863                file_path,
864                start: offset,
865                end: offset,
866            },
867        }
868    }
869}
870
871impl Locate for syn::ExprArray {
872    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
873        Surround {
874            front: &self.attrs,
875            surround: &self.bracket_token,
876            inner: &self.elems,
877            back: (),
878        }
879        .locate(file_path, code, offset)
880    }
881}
882
883impl Locate for syn::ExprAssign {
884    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
885        (&self.attrs, &self.left, &self.eq_token, &self.right)
886            .locate_as_group(file_path, code, offset)
887    }
888}
889
890impl Locate for syn::ExprAsync {
891    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
892        (&self.attrs, &self.async_token, &self.capture, &self.block)
893            .locate_as_group(file_path, code, offset)
894    }
895}
896
897impl Locate for syn::ExprAwait {
898    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
899        (&self.attrs, &self.base, &self.dot_token, &self.await_token)
900            .locate_as_group(file_path, code, offset)
901    }
902}
903
904impl Locate for syn::ExprBinary {
905    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
906        (&self.attrs, &self.left, &self.op, &self.right).locate_as_group(file_path, code, offset)
907    }
908}
909
910impl Locate for syn::ExprBlock {
911    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
912        (&self.attrs, &self.label, &self.block).locate_as_group(file_path, code, offset)
913    }
914}
915
916impl Locate for syn::ExprBreak {
917    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
918        (&self.attrs, &self.break_token, &self.label, &self.expr)
919            .locate_as_group(file_path, code, offset)
920    }
921}
922
923impl Locate for syn::ExprCall {
924    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
925        Surround {
926            front: (&self.attrs, &self.func),
927            surround: &self.paren_token,
928            inner: &self.args,
929            back: (),
930        }
931        .locate(file_path, code, offset)
932    }
933}
934
935impl Locate for syn::ExprCast {
936    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
937        (&self.attrs, &self.expr, &self.as_token, &self.ty).locate_as_group(file_path, code, offset)
938    }
939}
940
941impl Locate for syn::ExprClosure {
942    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
943        (
944            &self.attrs,
945            &self.lifetimes,
946            &self.constness,
947            &self.movability,
948            &self.asyncness,
949            &self.capture,
950            &self.or1_token,
951            &self.inputs,
952            &self.or2_token,
953            &self.output,
954            &self.body,
955        )
956            .locate_as_group(file_path, code, offset)
957    }
958}
959
960impl Locate for syn::ExprConst {
961    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
962        (&self.attrs, &self.const_token, &self.block).locate_as_group(file_path, code, offset)
963    }
964}
965
966impl Locate for syn::ExprContinue {
967    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
968        (&self.attrs, &self.continue_token, &self.label).locate_as_group(file_path, code, offset)
969    }
970}
971
972impl Locate for syn::ExprField {
973    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
974        (&self.attrs, &self.base, &self.dot_token, &self.member)
975            .locate_as_group(file_path, code, offset)
976    }
977}
978
979impl Locate for syn::ExprForLoop {
980    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
981        (
982            &self.attrs,
983            &self.label,
984            &self.for_token,
985            &self.pat,
986            &self.in_token,
987            &self.expr,
988            &self.body,
989        )
990            .locate_as_group(file_path, code, offset)
991    }
992}
993
994impl Locate for syn::ExprGroup {
995    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
996        (&self.attrs, &self.group_token, &self.expr).locate_as_group(file_path, code, offset)
997    }
998}
999
1000impl Locate for syn::ExprIf {
1001    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1002        if let Some((else_token, else_branch)) = &self.else_branch {
1003            (
1004                &self.attrs,
1005                &self.if_token,
1006                &self.cond,
1007                &self.then_branch,
1008                else_token,
1009                else_branch,
1010            )
1011                .locate_as_group(file_path, code, offset)
1012        } else {
1013            (&self.attrs, &self.if_token, &self.cond, &self.then_branch)
1014                .locate_as_group(file_path, code, offset)
1015        }
1016    }
1017}
1018
1019impl Locate for syn::ExprIndex {
1020    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1021        Surround {
1022            front: (&self.attrs, &self.expr),
1023            surround: &self.bracket_token,
1024            inner: &self.index,
1025            back: (),
1026        }
1027        .locate(file_path, code, offset)
1028    }
1029}
1030
1031impl Locate for syn::ExprInfer {
1032    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1033        (&self.attrs, &self.underscore_token).locate_as_group(file_path, code, offset)
1034    }
1035}
1036
1037impl Locate for syn::ExprLet {
1038    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1039        (
1040            &self.attrs,
1041            &self.let_token,
1042            &self.pat,
1043            &self.eq_token,
1044            &self.expr,
1045        )
1046            .locate_as_group(file_path, code, offset)
1047    }
1048}
1049
1050impl Locate for syn::ExprLit {
1051    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1052        (&self.attrs, &self.lit).locate_as_group(file_path, code, offset)
1053    }
1054}
1055
1056impl Locate for syn::ExprLoop {
1057    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1058        (&self.attrs, &self.label, &self.loop_token, &self.body)
1059            .locate_as_group(file_path, code, offset)
1060    }
1061}
1062
1063impl Locate for syn::ExprMacro {
1064    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1065        (&self.attrs, &self.mac).locate_as_group(file_path, code, offset)
1066    }
1067}
1068
1069impl Locate for syn::ExprMatch {
1070    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1071        Surround {
1072            front: (&self.attrs, &self.match_token, &self.expr),
1073            surround: &self.brace_token,
1074            inner: &self.arms,
1075            back: (),
1076        }
1077        .locate(file_path, code, offset)
1078    }
1079}
1080
1081impl Locate for syn::ExprMethodCall {
1082    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1083        Surround {
1084            front: (
1085                &self.attrs,
1086                &self.receiver,
1087                &self.dot_token,
1088                &self.method,
1089                &self.turbofish,
1090            ),
1091            surround: &self.paren_token,
1092            inner: &self.args,
1093            back: (),
1094        }
1095        .locate(file_path, code, offset)
1096    }
1097}
1098
1099impl Locate for syn::ExprParen {
1100    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1101        Surround {
1102            front: &self.attrs,
1103            surround: &self.paren_token,
1104            inner: &self.expr,
1105            back: (),
1106        }
1107        .locate(file_path, code, offset)
1108    }
1109}
1110
1111impl Locate for syn::ExprPath {
1112    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1113        if let Some(qself) = &self.qself {
1114            Qualified {
1115                front: &self.attrs,
1116                qself,
1117                path: &self.path,
1118                back: (),
1119            }
1120            .locate(file_path, code, offset)
1121        } else {
1122            (&self.attrs, &self.path).locate_as_group(file_path, code, offset)
1123        }
1124    }
1125}
1126
1127impl Locate for syn::ExprRange {
1128    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1129        match (&self.start, &self.end) {
1130            (Some(start), Some(end)) => {
1131                (&self.attrs, start, &self.limits, end).locate_as_group(file_path, code, offset)
1132            }
1133            (Some(start), None) => {
1134                (&self.attrs, start, &self.limits).locate_as_group(file_path, code, offset)
1135            }
1136            (None, Some(end)) => {
1137                (&self.attrs, &self.limits, end).locate_as_group(file_path, code, offset)
1138            }
1139            (None, None) => (&self.attrs, &self.limits).locate_as_group(file_path, code, offset),
1140        }
1141    }
1142}
1143
1144impl Locate for syn::ExprRawAddr {
1145    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1146        (
1147            &self.attrs,
1148            &self.and_token,
1149            &self.raw,
1150            &self.mutability,
1151            &self.expr,
1152        )
1153            .locate_as_group(file_path, code, offset)
1154    }
1155}
1156
1157impl Locate for syn::ExprReference {
1158    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1159        (&self.attrs, &self.and_token, &self.mutability, &self.expr)
1160            .locate_as_group(file_path, code, offset)
1161    }
1162}
1163
1164impl Locate for syn::ExprRepeat {
1165    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1166        Surround {
1167            front: &self.attrs,
1168            surround: &self.bracket_token,
1169            inner: (&self.expr, &self.semi_token, &self.len),
1170            back: (),
1171        }
1172        .locate(file_path, code, offset)
1173    }
1174}
1175
1176impl Locate for syn::ExprReturn {
1177    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1178        (&self.attrs, &self.return_token, &self.expr).locate_as_group(file_path, code, offset)
1179    }
1180}
1181
1182impl Locate for syn::ExprStruct {
1183    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1184        let front_loc = if let Some(qself) = &self.qself {
1185            Qualified {
1186                front: &self.attrs,
1187                qself,
1188                path: &self.path,
1189                back: (),
1190            }
1191            .locate(file_path, code, offset)
1192        } else {
1193            (&self.attrs, &self.path).locate_as_group(file_path, code, offset)
1194        };
1195
1196        let back_loc = Surround {
1197            front: (),
1198            surround: &self.brace_token,
1199            inner: (&self.fields, &self.dot2_token, &self.rest),
1200            back: (),
1201        }
1202        .locate(file_path, code, front_loc.end);
1203
1204        Location {
1205            file_path,
1206            start: front_loc.start,
1207            end: back_loc.end,
1208        }
1209    }
1210}
1211
1212impl Locate for syn::ExprTry {
1213    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1214        (&self.attrs, &self.expr, &self.question_token).locate_as_group(file_path, code, offset)
1215    }
1216}
1217
1218impl Locate for syn::ExprTryBlock {
1219    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1220        (&self.attrs, &self.try_token, &self.block).locate_as_group(file_path, code, offset)
1221    }
1222}
1223
1224impl Locate for syn::ExprTuple {
1225    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1226        Surround {
1227            front: &self.attrs,
1228            surround: &self.paren_token,
1229            inner: &self.elems,
1230            back: (),
1231        }
1232        .locate(file_path, code, offset)
1233    }
1234}
1235
1236impl Locate for syn::ExprUnary {
1237    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1238        (&self.attrs, &self.op, &self.expr).locate_as_group(file_path, code, offset)
1239    }
1240}
1241
1242impl Locate for syn::ExprUnsafe {
1243    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1244        (&self.attrs, &self.unsafe_token, &self.block).locate_as_group(file_path, code, offset)
1245    }
1246}
1247
1248impl Locate for syn::ExprWhile {
1249    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1250        (
1251            &self.attrs,
1252            &self.label,
1253            &self.while_token,
1254            &self.cond,
1255            &self.body,
1256        )
1257            .locate_as_group(file_path, code, offset)
1258    }
1259}
1260
1261impl Locate for syn::ExprYield {
1262    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1263        (&self.attrs, &self.yield_token, &self.expr).locate_as_group(file_path, code, offset)
1264    }
1265}
1266
1267impl Locate for syn::Field {
1268    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1269        (
1270            &self.attrs,
1271            &self.vis,
1272            &self.mutability,
1273            &self.ident,
1274            &self.colon_token,
1275            &self.ty,
1276        )
1277            .locate_as_group(file_path, code, offset)
1278    }
1279}
1280
1281impl Locate for syn::FieldMutability {
1282    fn find_loc(&self, file_path: &'static str, _code: &str, offset: usize) -> Location {
1283        Location {
1284            file_path,
1285            start: offset,
1286            end: offset,
1287        }
1288    }
1289}
1290
1291impl Locate for syn::FieldPat {
1292    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1293        (&self.attrs, &self.member, &self.colon_token, &self.pat)
1294            .locate_as_group(file_path, code, offset)
1295    }
1296}
1297
1298impl Locate for syn::Fields {
1299    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1300        match self {
1301            Self::Named(v) => v.locate(file_path, code, offset),
1302            Self::Unnamed(v) => v.locate(file_path, code, offset),
1303            Self::Unit => Location {
1304                file_path,
1305                start: offset,
1306                end: offset,
1307            },
1308        }
1309    }
1310}
1311
1312impl Locate for syn::FieldsNamed {
1313    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1314        Surround {
1315            front: (),
1316            surround: &self.brace_token,
1317            inner: &self.named,
1318            back: (),
1319        }
1320        .locate(file_path, code, offset)
1321    }
1322}
1323
1324impl Locate for syn::FieldsUnnamed {
1325    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1326        Surround {
1327            front: (),
1328            surround: &self.paren_token,
1329            inner: &self.unnamed,
1330            back: (),
1331        }
1332        .locate(file_path, code, offset)
1333    }
1334}
1335
1336impl Locate for syn::FieldValue {
1337    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1338        (&self.attrs, &self.member, &self.colon_token, &self.expr)
1339            .locate_as_group(file_path, code, offset)
1340    }
1341}
1342
1343impl Locate for syn::File {
1344    fn find_loc(&self, file_path: &'static str, code: &str, _offset: usize) -> Location {
1345        (&self.attrs, &self.items).locate_as_group(file_path, code, 0)
1346    }
1347}
1348
1349impl Locate for syn::FnArg {
1350    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1351        match self {
1352            Self::Receiver(v) => v.locate(file_path, code, offset),
1353            Self::Typed(v) => v.locate(file_path, code, offset),
1354        }
1355    }
1356}
1357
1358impl Locate for syn::ForeignItem {
1359    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1360        match self {
1361            Self::Fn(v) => v.locate(file_path, code, offset),
1362            Self::Static(v) => v.locate(file_path, code, offset),
1363            Self::Type(v) => v.locate(file_path, code, offset),
1364            Self::Macro(v) => v.locate(file_path, code, offset),
1365            Self::Verbatim(_) => Location {
1366                file_path,
1367                start: offset,
1368                end: offset,
1369            },
1370            _ => Location {
1371                file_path,
1372                start: offset,
1373                end: offset,
1374            },
1375        }
1376    }
1377}
1378
1379impl Locate for syn::ForeignItemFn {
1380    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1381        (&self.attrs, &self.vis, &self.sig, &self.semi_token)
1382            .locate_as_group(file_path, code, offset)
1383    }
1384}
1385
1386impl Locate for syn::ForeignItemStatic {
1387    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1388        (
1389            &self.attrs,
1390            &self.vis,
1391            &self.static_token,
1392            &self.mutability,
1393            &self.ident,
1394            &self.colon_token,
1395            &self.ty,
1396            &self.semi_token,
1397        )
1398            .locate_as_group(file_path, code, offset)
1399    }
1400}
1401
1402impl Locate for syn::ForeignItemType {
1403    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1404        (
1405            &self.attrs,
1406            &self.vis,
1407            &self.type_token,
1408            &self.ident,
1409            &self.generics,
1410            &self.semi_token,
1411        )
1412            .locate_as_group(file_path, code, offset)
1413    }
1414}
1415
1416impl Locate for syn::ForeignItemMacro {
1417    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1418        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(file_path, code, offset)
1419    }
1420}
1421
1422impl Locate for syn::GenericArgument {
1423    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1424        match self {
1425            Self::Lifetime(v) => v.locate(file_path, code, offset),
1426            Self::Type(v) => v.locate(file_path, code, offset),
1427            Self::Const(v) => v.locate(file_path, code, offset),
1428            Self::AssocType(v) => v.locate(file_path, code, offset),
1429            Self::AssocConst(v) => v.locate(file_path, code, offset),
1430            Self::Constraint(v) => v.locate(file_path, code, offset),
1431            _ => Location {
1432                file_path,
1433                start: offset,
1434                end: offset,
1435            },
1436        }
1437    }
1438}
1439
1440impl Locate for syn::GenericParam {
1441    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1442        match self {
1443            Self::Lifetime(v) => v.locate(file_path, code, offset),
1444            Self::Type(v) => v.locate(file_path, code, offset),
1445            Self::Const(v) => v.locate(file_path, code, offset),
1446        }
1447    }
1448}
1449
1450impl Locate for syn::Generics {
1451    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1452        (
1453            &self.lt_token,
1454            &self.params,
1455            &self.gt_token,
1456            &self.where_clause,
1457        )
1458            .locate_as_group(file_path, code, offset)
1459    }
1460}
1461
1462impl Locate for syn::Ident {
1463    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1464        let code = &code[offset..];
1465
1466        let ident = self.to_string();
1467        let start = offset
1468            + code
1469                .find(&ident)
1470                .unwrap_or_else(|| panic!("expected `{ident}` from `{code}`"));
1471
1472        Location {
1473            file_path,
1474            start,
1475            end: start + ident.len(),
1476        }
1477    }
1478}
1479
1480impl Locate for syn::ImplItem {
1481    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1482        match self {
1483            Self::Const(v) => v.locate(file_path, code, offset),
1484            Self::Fn(v) => v.locate(file_path, code, offset),
1485            Self::Type(v) => v.locate(file_path, code, offset),
1486            Self::Macro(v) => v.locate(file_path, code, offset),
1487            Self::Verbatim(_) => Location {
1488                file_path,
1489                start: offset,
1490                end: offset,
1491            },
1492            _ => Location {
1493                file_path,
1494                start: offset,
1495                end: offset,
1496            },
1497        }
1498    }
1499}
1500
1501impl Locate for syn::ImplItemConst {
1502    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1503        (
1504            &self.attrs,
1505            &self.vis,
1506            &self.defaultness,
1507            &self.const_token,
1508            &self.ident,
1509            &self.generics,
1510            &self.colon_token,
1511            &self.ty,
1512            &self.eq_token,
1513            &self.expr,
1514            &self.semi_token,
1515        )
1516            .locate_as_group(file_path, code, offset)
1517    }
1518}
1519
1520impl Locate for syn::ImplItemFn {
1521    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1522        (
1523            &self.attrs,
1524            &self.vis,
1525            &self.defaultness,
1526            &self.sig,
1527            &self.block,
1528        )
1529            .locate_as_group(file_path, code, offset)
1530    }
1531}
1532
1533impl Locate for syn::ImplItemType {
1534    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1535        (
1536            &self.attrs,
1537            &self.vis,
1538            &self.defaultness,
1539            &self.type_token,
1540            &self.ident,
1541            &self.generics,
1542            &self.eq_token,
1543            &self.ty,
1544            &self.semi_token,
1545        )
1546            .locate_as_group(file_path, code, offset)
1547    }
1548}
1549
1550impl Locate for syn::ImplItemMacro {
1551    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1552        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(file_path, code, offset)
1553    }
1554}
1555
1556impl Locate for syn::ImplRestriction {
1557    fn find_loc(&self, file_path: &'static str, _code: &str, offset: usize) -> Location {
1558        Location {
1559            file_path,
1560            start: offset,
1561            end: offset,
1562        }
1563    }
1564}
1565
1566impl Locate for syn::Index {
1567    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1568        let value = self.index.to_string();
1569        helper::str_location(file_path, code, offset, &value)
1570    }
1571}
1572
1573impl Locate for syn::Item {
1574    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1575        match self {
1576            Self::Const(v) => v.locate(file_path, code, offset),
1577            Self::Enum(v) => v.locate(file_path, code, offset),
1578            Self::ExternCrate(v) => v.locate(file_path, code, offset),
1579            Self::Fn(v) => v.locate(file_path, code, offset),
1580            Self::ForeignMod(v) => v.locate(file_path, code, offset),
1581            Self::Impl(v) => v.locate(file_path, code, offset),
1582            Self::Macro(v) => v.locate(file_path, code, offset),
1583            Self::Mod(v) => v.locate(file_path, code, offset),
1584            Self::Static(v) => v.locate(file_path, code, offset),
1585            Self::Struct(v) => v.locate(file_path, code, offset),
1586            Self::Trait(v) => v.locate(file_path, code, offset),
1587            Self::TraitAlias(v) => v.locate(file_path, code, offset),
1588            Self::Type(v) => v.locate(file_path, code, offset),
1589            Self::Union(v) => v.locate(file_path, code, offset),
1590            Self::Use(v) => v.locate(file_path, code, offset),
1591            Self::Verbatim(_) => Location {
1592                file_path,
1593                start: offset,
1594                end: offset,
1595            },
1596            _ => Location {
1597                file_path,
1598                start: offset,
1599                end: offset,
1600            },
1601        }
1602    }
1603}
1604
1605impl Locate for syn::ItemConst {
1606    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1607        (
1608            &self.attrs,
1609            &self.vis,
1610            &self.const_token,
1611            &self.ident,
1612            &self.generics,
1613            &self.colon_token,
1614            &self.ty,
1615            &self.eq_token,
1616            &self.expr,
1617            &self.semi_token,
1618        )
1619            .locate_as_group(file_path, code, offset)
1620    }
1621}
1622
1623impl Locate for syn::ItemEnum {
1624    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1625        Surround {
1626            front: (
1627                &self.attrs,
1628                &self.vis,
1629                &self.enum_token,
1630                &self.ident,
1631                &self.generics,
1632            ),
1633            surround: &self.brace_token,
1634            inner: &self.variants,
1635            back: (),
1636        }
1637        .locate(file_path, code, offset)
1638    }
1639}
1640
1641impl Locate for syn::ItemExternCrate {
1642    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1643        if let Some((as_token, rename)) = &self.rename {
1644            (
1645                &self.attrs,
1646                &self.vis,
1647                &self.extern_token,
1648                &self.crate_token,
1649                &self.ident,
1650                as_token,
1651                rename,
1652                &self.semi_token,
1653            )
1654                .locate_as_group(file_path, code, offset)
1655        } else {
1656            (
1657                &self.attrs,
1658                &self.vis,
1659                &self.extern_token,
1660                &self.crate_token,
1661                &self.ident,
1662                &self.semi_token,
1663            )
1664                .locate_as_group(file_path, code, offset)
1665        }
1666    }
1667}
1668
1669impl Locate for syn::ItemFn {
1670    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1671        (&self.attrs, &self.vis, &self.sig, &self.block).locate_as_group(file_path, code, offset)
1672    }
1673}
1674
1675impl Locate for syn::ItemForeignMod {
1676    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1677        Surround {
1678            front: (&self.attrs, &self.unsafety, &self.abi),
1679            surround: &self.brace_token,
1680            inner: &self.items,
1681            back: (),
1682        }
1683        .locate(file_path, code, offset)
1684    }
1685}
1686
1687impl Locate for syn::ItemImpl {
1688    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1689        if let Some((exc_token, path, for_token)) = &self.trait_ {
1690            Surround {
1691                front: (
1692                    &self.attrs,
1693                    &self.defaultness,
1694                    &self.unsafety,
1695                    &self.impl_token,
1696                    &self.generics,
1697                    exc_token,
1698                    path,
1699                    for_token,
1700                    &self.self_ty,
1701                ),
1702                surround: &self.brace_token,
1703                inner: &self.items,
1704                back: (),
1705            }
1706            .locate(file_path, code, offset)
1707        } else {
1708            Surround {
1709                front: (
1710                    &self.attrs,
1711                    &self.defaultness,
1712                    &self.unsafety,
1713                    &self.impl_token,
1714                    &self.generics,
1715                    &self.self_ty,
1716                ),
1717                surround: &self.brace_token,
1718                inner: &self.items,
1719                back: (),
1720            }
1721            .locate(file_path, code, offset)
1722        }
1723    }
1724}
1725
1726impl Locate for syn::ItemMacro {
1727    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1728        (&self.attrs, &self.ident, &self.mac, &self.semi_token)
1729            .locate_as_group(file_path, code, offset)
1730    }
1731}
1732
1733impl Locate for syn::ItemMod {
1734    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1735        match (&self.content, &self.semi) {
1736            (Some((brace, items)), Some(semi_token)) => Surround {
1737                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
1738                surround: brace,
1739                inner: items,
1740                back: semi_token,
1741            }
1742            .locate(file_path, code, offset),
1743            (Some((brace, items)), None) => Surround {
1744                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
1745                surround: brace,
1746                inner: items,
1747                back: (),
1748            }
1749            .locate(file_path, code, offset),
1750            (None, Some(semi_token)) => (
1751                &self.attrs,
1752                &self.vis,
1753                &self.mod_token,
1754                &self.ident,
1755                semi_token,
1756            )
1757                .locate_as_group(file_path, code, offset),
1758            (None, None) => (&self.attrs, &self.vis, &self.mod_token, &self.ident)
1759                .locate_as_group(file_path, code, offset),
1760        }
1761    }
1762}
1763
1764impl Locate for syn::ItemStatic {
1765    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1766        (
1767            &self.attrs,
1768            &self.vis,
1769            &self.static_token,
1770            &self.mutability,
1771            &self.ident,
1772            &self.colon_token,
1773            &self.ty,
1774            &self.eq_token,
1775            &self.expr,
1776            &self.semi_token,
1777        )
1778            .locate_as_group(file_path, code, offset)
1779    }
1780}
1781
1782impl Locate for syn::ItemStruct {
1783    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1784        (
1785            &self.attrs,
1786            &self.vis,
1787            &self.struct_token,
1788            &self.ident,
1789            &self.generics,
1790            &self.fields,
1791            &self.semi_token,
1792        )
1793            .locate_as_group(file_path, code, offset)
1794    }
1795}
1796
1797impl Locate for syn::ItemTrait {
1798    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1799        Surround {
1800            front: (
1801                &self.attrs,
1802                &self.vis,
1803                &self.unsafety,
1804                &self.auto_token,
1805                &self.restriction,
1806                &self.trait_token,
1807                &self.ident,
1808                &self.generics,
1809                &self.colon_token,
1810                &self.supertraits,
1811            ),
1812            surround: &self.brace_token,
1813            inner: &self.items,
1814            back: (),
1815        }
1816        .locate(file_path, code, offset)
1817    }
1818}
1819
1820impl Locate for syn::ItemTraitAlias {
1821    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1822        (
1823            &self.attrs,
1824            &self.vis,
1825            &self.trait_token,
1826            &self.ident,
1827            &self.generics,
1828            &self.eq_token,
1829            &self.bounds,
1830            &self.semi_token,
1831        )
1832            .locate_as_group(file_path, code, offset)
1833    }
1834}
1835
1836impl Locate for syn::ItemType {
1837    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1838        (
1839            &self.attrs,
1840            &self.vis,
1841            &self.type_token,
1842            &self.ident,
1843            &self.generics,
1844            &self.eq_token,
1845            &self.ty,
1846            &self.semi_token,
1847        )
1848            .locate_as_group(file_path, code, offset)
1849    }
1850}
1851
1852impl Locate for syn::ItemUnion {
1853    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1854        (
1855            &self.attrs,
1856            &self.vis,
1857            &self.union_token,
1858            &self.ident,
1859            &self.generics,
1860            &self.fields,
1861        )
1862            .locate_as_group(file_path, code, offset)
1863    }
1864}
1865
1866impl Locate for syn::ItemUse {
1867    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1868        (
1869            &self.attrs,
1870            &self.vis,
1871            &self.use_token,
1872            &self.leading_colon,
1873            &self.tree,
1874            &self.semi_token,
1875        )
1876            .locate_as_group(file_path, code, offset)
1877    }
1878}
1879
1880impl Locate for syn::Label {
1881    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1882        (&self.name, &self.colon_token).locate_as_group(file_path, code, offset)
1883    }
1884}
1885
1886impl Locate for syn::Lifetime {
1887    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1888        let code = &code[offset..];
1889
1890        let start = offset
1891            + code
1892                .find('\'')
1893                .unwrap_or_else(|| panic!("expected ' from {code}"));
1894        let end = self.ident.locate(file_path, code, start + 1).end;
1895
1896        Location {
1897            file_path,
1898            start,
1899            end,
1900        }
1901    }
1902}
1903
1904impl Locate for syn::LifetimeParam {
1905    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1906        (&self.attrs, &self.lifetime, &self.colon_token, &self.bounds)
1907            .locate_as_group(file_path, code, offset)
1908    }
1909}
1910
1911impl Locate for syn::Lit {
1912    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1913        match self {
1914            Self::Str(v) => v.locate(file_path, code, offset),
1915            Self::ByteStr(v) => v.locate(file_path, code, offset),
1916            Self::CStr(v) => v.locate(file_path, code, offset),
1917            Self::Byte(v) => v.locate(file_path, code, offset),
1918            Self::Char(v) => v.locate(file_path, code, offset),
1919            Self::Int(v) => v.locate(file_path, code, offset),
1920            Self::Float(v) => v.locate(file_path, code, offset),
1921            Self::Bool(v) => v.locate(file_path, code, offset),
1922            Self::Verbatim(_) => Location {
1923                file_path,
1924                start: offset,
1925                end: offset,
1926            },
1927            _ => Location {
1928                file_path,
1929                start: offset,
1930                end: offset,
1931            },
1932        }
1933    }
1934}
1935
1936impl Locate for syn::LitStr {
1937    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1938        let lit = self.token().to_string();
1939        helper::str_location(file_path, code, offset, &lit)
1940    }
1941}
1942
1943impl Locate for syn::LitByteStr {
1944    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1945        let lit = self.token().to_string();
1946        helper::str_location(file_path, code, offset, &lit)
1947    }
1948}
1949
1950impl Locate for syn::LitCStr {
1951    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1952        let lit = self.token().to_string();
1953        helper::str_location(file_path, code, offset, &lit)
1954    }
1955}
1956
1957impl Locate for syn::LitByte {
1958    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1959        let lit = self.token().to_string();
1960        helper::str_location(file_path, code, offset, &lit)
1961    }
1962}
1963
1964impl Locate for syn::LitChar {
1965    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1966        let lit = self.token().to_string();
1967        helper::str_location(file_path, code, offset, &lit)
1968    }
1969}
1970
1971impl Locate for syn::LitInt {
1972    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1973        let lit = self.token().to_string();
1974        helper::str_location(file_path, code, offset, &lit)
1975    }
1976}
1977
1978impl Locate for syn::LitFloat {
1979    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1980        let lit = self.token().to_string();
1981        helper::str_location(file_path, code, offset, &lit)
1982    }
1983}
1984
1985impl Locate for syn::LitBool {
1986    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1987        let lit = self.token().to_string();
1988        helper::str_location(file_path, code, offset, &lit)
1989    }
1990}
1991
1992impl Locate for syn::Local {
1993    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
1994        (
1995            &self.attrs,
1996            &self.let_token,
1997            &self.pat,
1998            &self.init,
1999            &self.semi_token,
2000        )
2001            .locate_as_group(file_path, code, offset)
2002    }
2003}
2004
2005impl Locate for syn::LocalInit {
2006    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2007        if let Some((else_token, diverge)) = &self.diverge {
2008            (&self.eq_token, &self.expr, else_token, diverge)
2009                .locate_as_group(file_path, code, offset)
2010        } else {
2011            (&self.eq_token, &self.expr).locate_as_group(file_path, code, offset)
2012        }
2013    }
2014}
2015
2016impl Locate for syn::Macro {
2017    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2018        match &self.delimiter {
2019            syn::MacroDelimiter::Paren(paren) => Surround {
2020                front: (&self.path, &self.bang_token),
2021                surround: paren,
2022                inner: (),
2023                back: (),
2024            }
2025            .locate(file_path, code, offset),
2026            syn::MacroDelimiter::Brace(brace) => Surround {
2027                front: (&self.path, &self.bang_token),
2028                surround: brace,
2029                inner: (),
2030                back: (),
2031            }
2032            .locate(file_path, code, offset),
2033            syn::MacroDelimiter::Bracket(bracket) => Surround {
2034                front: (&self.path, &self.bang_token),
2035                surround: bracket,
2036                inner: (),
2037                back: (),
2038            }
2039            .locate(file_path, code, offset),
2040        }
2041    }
2042}
2043
2044impl Locate for syn::Member {
2045    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2046        match self {
2047            Self::Named(v) => v.locate(file_path, code, offset),
2048            Self::Unnamed(v) => v.locate(file_path, code, offset),
2049        }
2050    }
2051}
2052
2053impl Locate for syn::Meta {
2054    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2055        match self {
2056            Self::Path(v) => v.locate(file_path, code, offset),
2057            Self::List(v) => v.locate(file_path, code, offset),
2058            Self::NameValue(v) => v.locate(file_path, code, offset),
2059        }
2060    }
2061}
2062
2063impl Locate for syn::MetaList {
2064    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2065        match &self.delimiter {
2066            syn::MacroDelimiter::Paren(paren) => Surround {
2067                front: &self.path,
2068                surround: paren,
2069                inner: (),
2070                back: (),
2071            }
2072            .locate(file_path, code, offset),
2073            syn::MacroDelimiter::Brace(brace) => Surround {
2074                front: &self.path,
2075                surround: brace,
2076                inner: (),
2077                back: (),
2078            }
2079            .locate(file_path, code, offset),
2080            syn::MacroDelimiter::Bracket(bracket) => Surround {
2081                front: &self.path,
2082                surround: bracket,
2083                inner: (),
2084                back: (),
2085            }
2086            .locate(file_path, code, offset),
2087        }
2088    }
2089}
2090
2091impl Locate for syn::MetaNameValue {
2092    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2093        (&self.path, &self.eq_token, &self.value).locate_as_group(file_path, code, offset)
2094    }
2095}
2096
2097impl Locate for syn::ParenthesizedGenericArguments {
2098    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2099        Surround {
2100            front: (),
2101            surround: &self.paren_token,
2102            inner: &self.inputs,
2103            back: &self.output,
2104        }
2105        .locate(file_path, code, offset)
2106    }
2107}
2108
2109impl Locate for syn::Pat {
2110    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2111        match self {
2112            Self::Const(v) => v.locate(file_path, code, offset),
2113            Self::Ident(v) => v.locate(file_path, code, offset),
2114            Self::Lit(v) => v.locate(file_path, code, offset),
2115            Self::Macro(v) => v.locate(file_path, code, offset),
2116            Self::Or(v) => v.locate(file_path, code, offset),
2117            Self::Paren(v) => v.locate(file_path, code, offset),
2118            Self::Path(v) => v.locate(file_path, code, offset),
2119            Self::Range(v) => v.locate(file_path, code, offset),
2120            Self::Reference(v) => v.locate(file_path, code, offset),
2121            Self::Rest(v) => v.locate(file_path, code, offset),
2122            Self::Slice(v) => v.locate(file_path, code, offset),
2123            Self::Struct(v) => v.locate(file_path, code, offset),
2124            Self::Tuple(v) => v.locate(file_path, code, offset),
2125            Self::TupleStruct(v) => v.locate(file_path, code, offset),
2126            Self::Type(v) => v.locate(file_path, code, offset),
2127            Self::Verbatim(_) => Location {
2128                file_path,
2129                start: offset,
2130                end: offset,
2131            },
2132            Self::Wild(v) => v.locate(file_path, code, offset),
2133            _ => Location {
2134                file_path,
2135                start: offset,
2136                end: offset,
2137            },
2138        }
2139    }
2140}
2141
2142impl Locate for syn::PatIdent {
2143    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2144        if let Some((at_token, subpat)) = &self.subpat {
2145            (
2146                &self.attrs,
2147                &self.by_ref,
2148                &self.mutability,
2149                &self.ident,
2150                at_token,
2151                subpat,
2152            )
2153                .locate_as_group(file_path, code, offset)
2154        } else {
2155            (&self.attrs, &self.by_ref, &self.mutability, &self.ident)
2156                .locate_as_group(file_path, code, offset)
2157        }
2158    }
2159}
2160
2161impl Locate for syn::PatOr {
2162    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2163        (&self.attrs, &self.leading_vert, &self.cases).locate_as_group(file_path, code, offset)
2164    }
2165}
2166
2167impl Locate for syn::PatParen {
2168    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2169        Surround {
2170            front: &self.attrs,
2171            surround: &self.paren_token,
2172            inner: &self.pat,
2173            back: (),
2174        }
2175        .locate(file_path, code, offset)
2176    }
2177}
2178
2179impl Locate for syn::PatReference {
2180    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2181        (&self.attrs, &self.and_token, &self.mutability, &self.pat)
2182            .locate_as_group(file_path, code, offset)
2183    }
2184}
2185
2186impl Locate for syn::PatRest {
2187    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2188        (&self.attrs, &self.dot2_token).locate_as_group(file_path, code, offset)
2189    }
2190}
2191
2192impl Locate for syn::PatSlice {
2193    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2194        Surround {
2195            front: &self.attrs,
2196            surround: &self.bracket_token,
2197            inner: &self.elems,
2198            back: (),
2199        }
2200        .locate(file_path, code, offset)
2201    }
2202}
2203
2204impl Locate for syn::PatStruct {
2205    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2206        let front_loc = if let Some(qself) = &self.qself {
2207            Qualified {
2208                front: &self.attrs,
2209                qself,
2210                path: &self.path,
2211                back: (),
2212            }
2213            .locate(file_path, code, offset)
2214        } else {
2215            (&self.attrs, &self.path).locate_as_group(file_path, code, offset)
2216        };
2217
2218        let back_loc = Surround {
2219            front: (),
2220            surround: &self.brace_token,
2221            inner: (&self.fields, &self.rest),
2222            back: (),
2223        }
2224        .locate(file_path, code, front_loc.end);
2225
2226        Location {
2227            file_path,
2228            start: front_loc.start,
2229            end: back_loc.end,
2230        }
2231    }
2232}
2233
2234impl Locate for syn::PatTuple {
2235    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2236        Surround {
2237            front: &self.attrs,
2238            surround: &self.paren_token,
2239            inner: &self.elems,
2240            back: (),
2241        }
2242        .locate(file_path, code, offset)
2243    }
2244}
2245
2246impl Locate for syn::PatTupleStruct {
2247    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2248        let front_loc = if let Some(qself) = &self.qself {
2249            Qualified {
2250                front: &self.attrs,
2251                qself,
2252                path: &self.path,
2253                back: (),
2254            }
2255            .locate(file_path, code, offset)
2256        } else {
2257            (&self.attrs, &self.path).locate_as_group(file_path, code, offset)
2258        };
2259
2260        let back_loc = Surround {
2261            front: (),
2262            surround: &self.paren_token,
2263            inner: &self.elems,
2264            back: (),
2265        }
2266        .locate(file_path, code, front_loc.end);
2267
2268        Location {
2269            file_path,
2270            start: front_loc.start,
2271            end: back_loc.end,
2272        }
2273    }
2274}
2275
2276impl Locate for syn::PatType {
2277    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2278        (&self.attrs, &self.pat, &self.colon_token, &self.ty)
2279            .locate_as_group(file_path, code, offset)
2280    }
2281}
2282
2283impl Locate for syn::PatWild {
2284    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2285        (&self.attrs, &self.underscore_token).locate_as_group(file_path, code, offset)
2286    }
2287}
2288
2289impl Locate for syn::Path {
2290    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2291        (&self.leading_colon, &self.segments).locate_as_group(file_path, code, offset)
2292    }
2293}
2294
2295impl Locate for syn::PathArguments {
2296    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2297        match self {
2298            Self::None => Location {
2299                file_path,
2300                start: offset,
2301                end: offset,
2302            },
2303            Self::AngleBracketed(v) => v.locate(file_path, code, offset),
2304            Self::Parenthesized(v) => v.locate(file_path, code, offset),
2305        }
2306    }
2307}
2308
2309impl Locate for syn::PathSegment {
2310    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2311        (&self.ident, &self.arguments).locate_as_group(file_path, code, offset)
2312    }
2313}
2314
2315impl Locate for syn::PointerMutability {
2316    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2317        match self {
2318            Self::Const(v) => v.locate(file_path, code, offset),
2319            Self::Mut(v) => v.locate(file_path, code, offset),
2320        }
2321    }
2322}
2323
2324impl Locate for syn::PreciseCapture {
2325    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2326        (
2327            &self.use_token,
2328            &self.lt_token,
2329            &self.params,
2330            &self.gt_token,
2331        )
2332            .locate_as_group(file_path, code, offset)
2333    }
2334}
2335
2336impl Locate for syn::PredicateLifetime {
2337    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2338        (&self.lifetime, &self.colon_token, &self.bounds).locate_as_group(file_path, code, offset)
2339    }
2340}
2341
2342impl Locate for syn::PredicateType {
2343    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2344        (
2345            &self.lifetimes,
2346            &self.bounded_ty,
2347            &self.colon_token,
2348            &self.bounds,
2349        )
2350            .locate_as_group(file_path, code, offset)
2351    }
2352}
2353
2354impl Locate for syn::QSelf {
2355    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2356        let front_loc =
2357            (&self.lt_token, &self.ty, &self.as_token).locate_as_group(file_path, code, offset);
2358
2359        const OPEN: char = '<';
2360        const CLOSE: char = '>';
2361
2362        let code = &code[front_loc.end..];
2363
2364        let mut cur = front_loc.end;
2365        let mut level = 1;
2366
2367        for c in code.chars() {
2368            if c == OPEN {
2369                level += 1;
2370            } else if c == CLOSE {
2371                if level == 1 {
2372                    break;
2373                }
2374                level -= 1;
2375            }
2376            cur += c.len_utf8();
2377        }
2378
2379        let end = self.gt_token.locate(file_path, code, cur).end;
2380
2381        Location {
2382            file_path,
2383            start: front_loc.start,
2384            end,
2385        }
2386    }
2387}
2388
2389impl Locate for syn::RangeLimits {
2390    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2391        match self {
2392            Self::HalfOpen(v) => v.locate(file_path, code, offset),
2393            Self::Closed(v) => v.locate(file_path, code, offset),
2394        }
2395    }
2396}
2397
2398impl Locate for syn::Receiver {
2399    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2400        if let Some((and_token, reference)) = &self.reference {
2401            (
2402                &self.attrs,
2403                and_token,
2404                reference,
2405                &self.mutability,
2406                &self.self_token,
2407                &self.colon_token,
2408                &self.ty,
2409            )
2410                .locate_as_group(file_path, code, offset)
2411        } else {
2412            (
2413                &self.attrs,
2414                &self.mutability,
2415                &self.self_token,
2416                &self.colon_token,
2417                &self.ty,
2418            )
2419                .locate_as_group(file_path, code, offset)
2420        }
2421    }
2422}
2423
2424impl Locate for syn::ReturnType {
2425    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2426        match self {
2427            Self::Default => Location {
2428                file_path,
2429                start: offset,
2430                end: offset,
2431            },
2432            Self::Type(arrow_token, ty) => {
2433                (arrow_token, ty).locate_as_group(file_path, code, offset)
2434            }
2435        }
2436    }
2437}
2438
2439impl Locate for syn::Signature {
2440    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2441        Surround {
2442            front: (
2443                &self.constness,
2444                &self.asyncness,
2445                &self.unsafety,
2446                &self.abi,
2447                &self.fn_token,
2448                &self.ident,
2449                &self.generics,
2450            ),
2451            surround: &self.paren_token,
2452            inner: (&self.inputs, &self.variadic),
2453            back: &self.output,
2454        }
2455        .locate(file_path, code, offset)
2456    }
2457}
2458
2459impl Locate for syn::StaticMutability {
2460    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2461        match self {
2462            Self::Mut(v) => v.locate(file_path, code, offset),
2463            Self::None => Location {
2464                file_path,
2465                start: offset,
2466                end: offset,
2467            },
2468            _ => Location {
2469                file_path,
2470                start: offset,
2471                end: offset,
2472            },
2473        }
2474    }
2475}
2476
2477impl Locate for syn::Stmt {
2478    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2479        match self {
2480            Self::Local(v) => v.locate(file_path, code, offset),
2481            Self::Item(v) => v.locate(file_path, code, offset),
2482            Self::Expr(expr, semi_token) => {
2483                (expr, semi_token).locate_as_group(file_path, code, offset)
2484            }
2485            Self::Macro(v) => v.locate(file_path, code, offset),
2486        }
2487    }
2488}
2489
2490impl Locate for syn::StmtMacro {
2491    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2492        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(file_path, code, offset)
2493    }
2494}
2495
2496impl Locate for syn::TraitBound {
2497    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2498        // self.paren_token is always Null according to syn parsing.
2499        (&self.modifier, &self.lifetimes, &self.path).locate_as_group(file_path, code, offset)
2500    }
2501}
2502
2503impl Locate for syn::TraitBoundModifier {
2504    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2505        match self {
2506            Self::None => Location {
2507                file_path,
2508                start: offset,
2509                end: offset,
2510            },
2511            Self::Maybe(v) => v.locate(file_path, code, offset),
2512        }
2513    }
2514}
2515
2516impl Locate for syn::TraitItem {
2517    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2518        match self {
2519            Self::Const(v) => v.locate(file_path, code, offset),
2520            Self::Fn(v) => v.locate(file_path, code, offset),
2521            Self::Type(v) => v.locate(file_path, code, offset),
2522            Self::Macro(v) => v.locate(file_path, code, offset),
2523            Self::Verbatim(_) => Location {
2524                file_path,
2525                start: offset,
2526                end: offset,
2527            },
2528            _ => Location {
2529                file_path,
2530                start: offset,
2531                end: offset,
2532            },
2533        }
2534    }
2535}
2536
2537impl Locate for syn::TraitItemConst {
2538    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2539        if let Some((eq_token, default)) = &self.default {
2540            (
2541                &self.attrs,
2542                &self.const_token,
2543                &self.ident,
2544                &self.generics,
2545                &self.colon_token,
2546                &self.ty,
2547                eq_token,
2548                default,
2549                &self.semi_token,
2550            )
2551                .locate_as_group(file_path, code, offset)
2552        } else {
2553            (
2554                &self.attrs,
2555                &self.const_token,
2556                &self.ident,
2557                &self.generics,
2558                &self.colon_token,
2559                &self.ty,
2560                &self.semi_token,
2561            )
2562                .locate_as_group(file_path, code, offset)
2563        }
2564    }
2565}
2566
2567impl Locate for syn::TraitItemFn {
2568    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2569        (&self.attrs, &self.sig, &self.default, &self.semi_token)
2570            .locate_as_group(file_path, code, offset)
2571    }
2572}
2573
2574impl Locate for syn::TraitItemType {
2575    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2576        if let Some((eq_token, default)) = &self.default {
2577            (
2578                &self.attrs,
2579                &self.type_token,
2580                &self.ident,
2581                &self.generics,
2582                &self.colon_token,
2583                &self.bounds,
2584                eq_token,
2585                default,
2586                &self.semi_token,
2587            )
2588                .locate_as_group(file_path, code, offset)
2589        } else {
2590            (
2591                &self.attrs,
2592                &self.type_token,
2593                &self.ident,
2594                &self.generics,
2595                &self.colon_token,
2596                &self.bounds,
2597                &self.semi_token,
2598            )
2599                .locate_as_group(file_path, code, offset)
2600        }
2601    }
2602}
2603
2604impl Locate for syn::TraitItemMacro {
2605    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2606        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(file_path, code, offset)
2607    }
2608}
2609
2610impl Locate for syn::Type {
2611    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2612        match self {
2613            Self::Array(v) => v.locate(file_path, code, offset),
2614            Self::BareFn(v) => v.locate(file_path, code, offset),
2615            Self::Group(v) => v.locate(file_path, code, offset),
2616            Self::ImplTrait(v) => v.locate(file_path, code, offset),
2617            Self::Infer(v) => v.locate(file_path, code, offset),
2618            Self::Macro(v) => v.locate(file_path, code, offset),
2619            Self::Never(v) => v.locate(file_path, code, offset),
2620            Self::Paren(v) => v.locate(file_path, code, offset),
2621            Self::Path(v) => v.locate(file_path, code, offset),
2622            Self::Ptr(v) => v.locate(file_path, code, offset),
2623            Self::Reference(v) => v.locate(file_path, code, offset),
2624            Self::Slice(v) => v.locate(file_path, code, offset),
2625            Self::TraitObject(v) => v.locate(file_path, code, offset),
2626            Self::Tuple(v) => v.locate(file_path, code, offset),
2627            Self::Verbatim(_) => Location {
2628                file_path,
2629                start: offset,
2630                end: offset,
2631            },
2632            _ => Location {
2633                file_path,
2634                start: offset,
2635                end: offset,
2636            },
2637        }
2638    }
2639}
2640
2641impl Locate for syn::TypeArray {
2642    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2643        Surround {
2644            front: (),
2645            surround: &self.bracket_token,
2646            inner: (&self.elem, &self.semi_token, &self.len),
2647            back: (),
2648        }
2649        .locate(file_path, code, offset)
2650    }
2651}
2652
2653impl Locate for syn::TypeBareFn {
2654    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2655        Surround {
2656            front: (&self.lifetimes, &self.unsafety, &self.abi, &self.fn_token),
2657            surround: &self.paren_token,
2658            inner: (&self.inputs, &self.variadic),
2659            back: &self.output,
2660        }
2661        .locate(file_path, code, offset)
2662    }
2663}
2664
2665impl Locate for syn::TypeGroup {
2666    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2667        (&self.group_token, &self.elem).locate_as_group(file_path, code, offset)
2668    }
2669}
2670
2671impl Locate for syn::TypeImplTrait {
2672    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2673        (&self.impl_token, &self.bounds).locate_as_group(file_path, code, offset)
2674    }
2675}
2676
2677impl Locate for syn::TypeInfer {
2678    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2679        self.underscore_token.locate(file_path, code, offset)
2680    }
2681}
2682
2683impl Locate for syn::TypeMacro {
2684    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2685        self.mac.locate(file_path, code, offset)
2686    }
2687}
2688
2689impl Locate for syn::TypeNever {
2690    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2691        self.bang_token.locate(file_path, code, offset)
2692    }
2693}
2694
2695impl Locate for syn::TypeParen {
2696    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2697        Surround {
2698            front: (),
2699            surround: &self.paren_token,
2700            inner: &self.elem,
2701            back: (),
2702        }
2703        .locate(file_path, code, offset)
2704    }
2705}
2706
2707impl Locate for syn::TypePath {
2708    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2709        if let Some(qself) = &self.qself {
2710            Qualified {
2711                front: (),
2712                qself,
2713                path: &self.path,
2714                back: (),
2715            }
2716            .locate(file_path, code, offset)
2717        } else {
2718            self.path.locate(file_path, code, offset)
2719        }
2720    }
2721}
2722
2723impl Locate for syn::TypePtr {
2724    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2725        (
2726            &self.star_token,
2727            &self.const_token,
2728            &self.mutability,
2729            &self.elem,
2730        )
2731            .locate_as_group(file_path, code, offset)
2732    }
2733}
2734
2735impl Locate for syn::TypeReference {
2736    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2737        (
2738            &self.and_token,
2739            &self.lifetime,
2740            &self.mutability,
2741            &self.elem,
2742        )
2743            .locate_as_group(file_path, code, offset)
2744    }
2745}
2746
2747impl Locate for syn::TypeSlice {
2748    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2749        Surround {
2750            front: (),
2751            surround: &self.bracket_token,
2752            inner: &self.elem,
2753            back: (),
2754        }
2755        .locate(file_path, code, offset)
2756    }
2757}
2758
2759impl Locate for syn::TypeTraitObject {
2760    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2761        (&self.dyn_token, &self.bounds).locate_as_group(file_path, code, offset)
2762    }
2763}
2764
2765impl Locate for syn::TypeTuple {
2766    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2767        Surround {
2768            front: (),
2769            surround: &self.paren_token,
2770            inner: &self.elems,
2771            back: (),
2772        }
2773        .locate(file_path, code, offset)
2774    }
2775}
2776
2777impl Locate for syn::TypeParam {
2778    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2779        (
2780            &self.attrs,
2781            &self.ident,
2782            &self.colon_token,
2783            &self.bounds,
2784            &self.eq_token,
2785            &self.default,
2786        )
2787            .locate_as_group(file_path, code, offset)
2788    }
2789}
2790
2791impl Locate for syn::TypeParamBound {
2792    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2793        match self {
2794            Self::Trait(v) => v.locate(file_path, code, offset),
2795            Self::Lifetime(v) => v.locate(file_path, code, offset),
2796            Self::PreciseCapture(v) => v.locate(file_path, code, offset),
2797            Self::Verbatim(_) => Location {
2798                file_path,
2799                start: offset,
2800                end: offset,
2801            },
2802            _ => Location {
2803                file_path,
2804                start: offset,
2805                end: offset,
2806            },
2807        }
2808    }
2809}
2810
2811impl Locate for syn::UnOp {
2812    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2813        match self {
2814            Self::Deref(v) => v.locate(file_path, code, offset),
2815            Self::Not(v) => v.locate(file_path, code, offset),
2816            Self::Neg(v) => v.locate(file_path, code, offset),
2817            _ => Location {
2818                file_path,
2819                start: offset,
2820                end: offset,
2821            },
2822        }
2823    }
2824}
2825
2826impl Locate for syn::UseGlob {
2827    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2828        self.star_token.locate(file_path, code, offset)
2829    }
2830}
2831
2832impl Locate for syn::UseGroup {
2833    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2834        Surround {
2835            front: (),
2836            surround: &self.brace_token,
2837            inner: &self.items,
2838            back: (),
2839        }
2840        .locate(file_path, code, offset)
2841    }
2842}
2843
2844impl Locate for syn::UseName {
2845    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2846        self.ident.locate(file_path, code, offset)
2847    }
2848}
2849
2850impl Locate for syn::UsePath {
2851    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2852        (&self.ident, &self.colon2_token, &self.tree).locate_as_group(file_path, code, offset)
2853    }
2854}
2855
2856impl Locate for syn::UseRename {
2857    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2858        (&self.ident, &self.as_token, &self.rename).locate_as_group(file_path, code, offset)
2859    }
2860}
2861
2862impl Locate for syn::UseTree {
2863    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2864        match self {
2865            Self::Path(v) => v.locate(file_path, code, offset),
2866            Self::Name(v) => v.locate(file_path, code, offset),
2867            Self::Rename(v) => v.locate(file_path, code, offset),
2868            Self::Glob(v) => v.locate(file_path, code, offset),
2869            Self::Group(v) => v.locate(file_path, code, offset),
2870        }
2871    }
2872}
2873
2874impl Locate for syn::Variadic {
2875    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2876        if let Some((pat, colon_token)) = &self.pat {
2877            (&self.attrs, pat, colon_token, &self.dots, &self.comma)
2878                .locate_as_group(file_path, code, offset)
2879        } else {
2880            (&self.attrs, &self.dots, &self.comma).locate_as_group(file_path, code, offset)
2881        }
2882    }
2883}
2884
2885impl Locate for syn::Variant {
2886    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2887        if let Some((eq_token, discriminant)) = &self.discriminant {
2888            (
2889                &self.attrs,
2890                &self.ident,
2891                &self.fields,
2892                eq_token,
2893                discriminant,
2894            )
2895                .locate_as_group(file_path, code, offset)
2896        } else {
2897            (&self.attrs, &self.ident, &self.fields).locate_as_group(file_path, code, offset)
2898        }
2899    }
2900}
2901
2902impl Locate for syn::Visibility {
2903    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2904        match self {
2905            Self::Public(v) => v.locate(file_path, code, offset),
2906            Self::Restricted(v) => v.locate(file_path, code, offset),
2907            Self::Inherited => Location {
2908                file_path,
2909                start: offset,
2910                end: offset,
2911            },
2912        }
2913    }
2914}
2915
2916impl Locate for syn::VisRestricted {
2917    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2918        Surround {
2919            front: &self.pub_token,
2920            surround: &self.paren_token,
2921            inner: (&self.in_token, &self.path),
2922            back: (),
2923        }
2924        .locate(file_path, code, offset)
2925    }
2926}
2927
2928impl Locate for syn::WhereClause {
2929    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2930        (&self.where_token, &self.predicates).locate_as_group(file_path, code, offset)
2931    }
2932}
2933
2934impl Locate for syn::WherePredicate {
2935    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2936        match self {
2937            Self::Lifetime(v) => v.locate(file_path, code, offset),
2938            Self::Type(v) => v.locate(file_path, code, offset),
2939            _ => Location {
2940                file_path,
2941                start: offset,
2942                end: offset,
2943            },
2944        }
2945    }
2946}
2947
2948// === Composite types ===
2949
2950impl<T: Locate> Locate for Option<T> {
2951    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2952        if let Some(inner) = self {
2953            inner.locate(file_path, code, offset)
2954        } else {
2955            Location {
2956                file_path,
2957                start: offset,
2958                end: offset,
2959            }
2960        }
2961    }
2962}
2963
2964impl<T: Locate> Locate for Box<T> {
2965    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2966        let t = &**self;
2967        t.locate(file_path, code, offset)
2968    }
2969}
2970
2971impl<T: Locate> Locate for Vec<T> {
2972    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2973        let mut start = usize::MAX;
2974        let mut end = offset;
2975
2976        for item in self {
2977            let loc = item.locate(file_path, code, end);
2978            start = start.min(loc.start);
2979            end = loc.end;
2980        }
2981
2982        Location {
2983            file_path,
2984            start: if start != usize::MAX { start } else { offset },
2985            end,
2986        }
2987    }
2988}
2989
2990impl<T, S> Locate for syn::punctuated::Punctuated<T, S>
2991where
2992    T: Locate,
2993    S: Locate,
2994{
2995    fn find_loc(&self, file_path: &'static str, code: &str, offset: usize) -> Location {
2996        let mut start = usize::MAX;
2997        let mut end = offset;
2998
2999        for item in self {
3000            let loc = item.locate(file_path, code, end);
3001            start = start.min(loc.start);
3002            end = loc.end;
3003        }
3004
3005        Location {
3006            file_path,
3007            start: if start != usize::MAX { start } else { offset },
3008            end,
3009        }
3010    }
3011}
3012
3013// === Helper functions ===
3014
3015pub mod helper {
3016    use super::*;
3017
3018    pub fn char_location(
3019        file_path: &'static str,
3020        code: &str,
3021        offset: usize,
3022        content: char,
3023    ) -> Location {
3024        let code = &code[offset..];
3025        let start = offset
3026            + code
3027                .find(content)
3028                .unwrap_or_else(|| panic!("expected `{content}` from `{code}`"));
3029
3030        Location {
3031            file_path,
3032            start,
3033            end: start + content.len_utf8(),
3034        }
3035    }
3036
3037    pub fn str_location(
3038        file_path: &'static str,
3039        code: &str,
3040        offset: usize,
3041        content: &str,
3042    ) -> Location {
3043        let code = &code[offset..];
3044
3045        let start = offset
3046            + code
3047                .find(content)
3048                .unwrap_or_else(|| panic!("expected `{content}` from `{code}`"));
3049
3050        Location {
3051            file_path,
3052            start,
3053            end: start + content.len(),
3054        }
3055    }
3056}