syn_locator/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "find")]
4mod find;
5#[cfg(feature = "find")]
6pub use find::Find;
7
8use std::{
9    any::{self, Any, TypeId},
10    cell::{Cell, RefCell, RefMut},
11    cmp,
12    collections::HashMap,
13    ops,
14    pin::Pin,
15    sync::{LazyLock, Mutex, MutexGuard, OnceLock},
16};
17
18type Result<T> = std::result::Result<T, Error>;
19type Error = Box<dyn std::error::Error + Send + Sync>;
20
21/// Global location storage that can be accessed across threads.
22static LOCATOR: LazyLock<Mutex<Locator>> = LazyLock::new(|| Mutex::new(Locator::new()));
23
24thread_local! {
25    static EN_TL_LOCATOR: Cell<bool> = const { Cell::new(false) };
26
27    /// Per-thread global location storage.
28    static TL_LOCATOR: RefCell<Locator> = RefCell::new(Locator::new());
29}
30
31pub fn enable_thread_local(en: bool) {
32    EN_TL_LOCATOR.replace(en);
33}
34
35pub fn is_located(file_path: &str) -> bool {
36    if EN_TL_LOCATOR.get() {
37        TL_LOCATOR.with(|locator| locator.borrow().contains_file(file_path))
38    } else {
39        LOCATOR.lock().unwrap().contains_file(file_path)
40    }
41}
42
43/// Clears the global location storage.
44pub fn clear() {
45    if EN_TL_LOCATOR.get() {
46        TL_LOCATOR.with_borrow_mut(|locator| locator.clear());
47    } else {
48        let mut locator = LOCATOR.lock().unwrap();
49        locator.clear();
50    }
51}
52
53pub enum LocatorGuard<'a> {
54    Mutex(MutexGuard<'a, Locator>),
55    RefMut(RefMut<'a, Locator>),
56}
57
58impl<'a> ops::Deref for LocatorGuard<'a> {
59    type Target = Locator;
60
61    fn deref(&self) -> &Self::Target {
62        match self {
63            Self::Mutex(v) => v,
64            Self::RefMut(v) => v,
65        }
66    }
67}
68
69impl ops::DerefMut for LocatorGuard<'_> {
70    fn deref_mut(&mut self) -> &mut Self::Target {
71        match self {
72            Self::Mutex(v) => v,
73            Self::RefMut(v) => v,
74        }
75    }
76}
77
78pub trait LocateEntry: Locate {
79    fn locate_as_entry(self: Pin<&Self>, file_path: &str, code: &str) -> Result<()> {
80        let loc = self.location(file_path, code)?;
81
82        if EN_TL_LOCATOR.get() {
83            TL_LOCATOR.with(|locator| {
84                let mut locator = LocatorGuard::RefMut(locator.borrow_mut());
85                let Some(code) = locator.filtered_code_ptr(file_path) else {
86                    drop(locator);
87                    panic!("failed to find `{file_path}`");
88                };
89
90                // Safety: Locating doesn't modify code itself. Therefore, the address
91                // and its content will never change until end of this block.
92                unsafe {
93                    let code = code.as_ref().unwrap_unchecked();
94                    self.locate(&mut locator, loc.file_path, code, 0);
95                }
96            });
97        } else {
98            let mut locator = LocatorGuard::Mutex(LOCATOR.lock().unwrap());
99            let Some(code) = locator.filtered_code_ptr(file_path) else {
100                drop(locator);
101                panic!("failed to find `{file_path}`");
102            };
103
104            // Safety: Locating doesn't modify code itself. Therefore, the address
105            // and its content will never change until end of this block.
106            unsafe {
107                let code = code.as_ref().unwrap_unchecked();
108                self.locate(&mut locator, loc.file_path, code, 0);
109            }
110        }
111
112        Ok(())
113    }
114
115    #[doc(hidden)]
116    fn location(self: Pin<&Self>, file_path: &str, code: &str) -> Result<Location> {
117        let code: Box<str> = code.into();
118
119        if EN_TL_LOCATOR.get() {
120            TL_LOCATOR.with_borrow_mut(|locator| locator.insert_file(&*self, file_path, code))
121        } else {
122            LOCATOR.lock().unwrap().insert_file(&*self, file_path, code)
123        }
124    }
125}
126
127impl<T: Locate> LocateEntry for T {}
128
129pub trait Locate: Any {
130    /// Finds a location in the given file path, code, and offset.
131    ///
132    /// This method takes a mutex guard for the global location storage. Do not
133    /// call methods shown below which try to lock the storage.
134    /// - [`Locate::location`]
135    /// - [`Locate::location_message`]
136    /// - [`Locate::code`]
137    ///
138    /// But you have some alternatives like,
139    /// - [`Locate::_location`]
140    fn find_loc(
141        &self,
142        locator: &mut LocatorGuard,
143        file_path: &'static str,
144        code: &str,
145        offset: usize,
146    ) -> Location;
147
148    fn relocate(&self, locator: &mut LocatorGuard, loc: Location) {
149        locator.set_location(self, loc);
150    }
151
152    // call from parent node
153    fn locate(
154        &self,
155        locator: &mut LocatorGuard,
156        file_path: &'static str,
157        code: &str,
158        offset: usize,
159    ) -> Location {
160        let loc = self.find_loc(locator, file_path, code, offset);
161        locator.set_location(self, loc);
162        loc
163    }
164
165    /// This method tries to lock the global location storage. If you have a
166    /// mutex guard for it already, do not call this method.
167    fn location(&self) -> Location {
168        if EN_TL_LOCATOR.get() {
169            TL_LOCATOR
170                .with_borrow_mut(|locator| locator.get_location(self))
171                .unwrap_or_else(|| {
172                    panic!(
173                        "failed to find the location of `{}`. did you forget `Locate::locate`?",
174                        any::type_name_of_val(self)
175                    )
176                })
177        } else {
178            let locator = LOCATOR.lock().unwrap();
179            let Some(loc) = locator.get_location(self) else {
180                drop(locator);
181                panic!(
182                    "failed to find the location of `{}`. did you forget `Locate::locate`?",
183                    any::type_name_of_val(self)
184                )
185            };
186            loc
187        }
188    }
189
190    fn _location(&self, locator: &LocatorGuard) -> Location {
191        locator.get_location(self).unwrap_or_else(|| {
192            panic!(
193                "failed to find the location of `{}`. did you forget `Locate::locate`?",
194                any::type_name_of_val(self)
195            )
196        })
197    }
198
199    /// This method tries to lock the global location storage. If you have a
200    /// mutex guard for it already, do not call this method.
201    fn location_message(&self) -> String {
202        if EN_TL_LOCATOR.get() {
203            TL_LOCATOR
204                .with_borrow_mut(|locator| {
205                    let loc = locator.get_location(self)?;
206                    let path = loc.file_path;
207                    let code = locator.get_original_code(path)?;
208                    let line = code.as_bytes()[..loc.start]
209                        .iter()
210                        .filter(|&&b| b == b'\n')
211                        .count()
212                        + 1;
213                    let content = &code[loc.start..loc.end];
214
215                    Some(format!("{path}:{line}: {content}"))
216                })
217                .unwrap_or_else(|| {
218                    panic!(
219                        "failed to find the location of `{}`. did you forget `Locate::locate`?",
220                        any::type_name_of_val(self)
221                    )
222                })
223        } else {
224            let panic = || -> ! {
225                panic!(
226                    "failed to find the location of `{}`. did you forget `Locate::locate`?",
227                    any::type_name_of_val(self)
228                )
229            };
230
231            let locator = LOCATOR.lock().unwrap();
232
233            let Some(loc) = locator.get_location(self) else {
234                drop(locator);
235                panic();
236            };
237
238            let path = loc.file_path;
239            let Some(code) = locator.get_original_code(path) else {
240                drop(locator);
241                panic();
242            };
243
244            let line = code.as_bytes()[..loc.start]
245                .iter()
246                .filter(|&&b| b == b'\n')
247                .count()
248                + 1;
249
250            let content = &code[loc.start..loc.end];
251            format!("{path}:{line}: {content}")
252        }
253    }
254
255    /// This method tries to lock the global location storage. If you have a
256    /// mutex guard for it already, do not call this method.
257    fn code(&self) -> String {
258        if EN_TL_LOCATOR.get() {
259            TL_LOCATOR
260                .with_borrow_mut(|locator| {
261                    let loc = locator.get_location(self)?;
262                    let path = loc.file_path;
263                    let code = locator.get_original_code(path)?;
264                    let content = &code[loc.start..loc.end];
265
266                    Some(content.to_owned())
267                })
268                .unwrap_or_else(|| {
269                    panic!(
270                        "failed to find the location of `{}`. did you forget `Locate::locate`?",
271                        any::type_name_of_val(self)
272                    )
273                })
274        } else {
275            let panic = || -> ! {
276                panic!(
277                    "failed to find the location of `{}`. did you forget `Locate::locate`?",
278                    any::type_name_of_val(self)
279                )
280            };
281
282            let locator = LOCATOR.lock().unwrap();
283
284            let Some(loc) = locator.get_location(self) else {
285                drop(locator);
286                panic();
287            };
288
289            let path = loc.file_path;
290            let Some(code) = locator.get_original_code(path) else {
291                drop(locator);
292                panic();
293            };
294
295            let content = &code[loc.start..loc.end];
296            content.to_owned()
297        }
298    }
299}
300
301pub trait LocateGroup {
302    fn locate_as_group(
303        &self,
304        locator: &mut LocatorGuard,
305        file_path: &'static str,
306        code: &str,
307        offset: usize,
308    ) -> Location;
309    fn relocate_as_group(&self, locator: &mut LocatorGuard, loc: Location);
310}
311
312macro_rules! impl_locate_group {
313    ( $($i:expr),* ; $($ri:expr),* ) => {
314        paste::paste! {
315            impl<'a, $([<A $i>]: Locate),*> LocateGroup for ( $( &'a [<A $i>] ),* ) {
316                #[allow(unused_assignments)]
317                fn locate_as_group(
318                    &self,
319                    locator: &mut LocatorGuard,
320                    file_path: &'static str,
321                    code: &str,
322                    offset: usize
323                ) -> Location
324                {
325                    let ( $( [<this $i>] ),* ) = self;
326
327                    // Calls locate() on children.
328                    let mut end = offset;
329                    $(
330                        let [<loc $i>] = [<this $i>].locate(locator, file_path, code, end);
331                        end = [<loc $i>].end;
332                    )*
333
334                    // Determines start.
335                    let mut start = usize::MAX;
336                    $(
337                        if [<loc $i>].start != [<loc $i>].end {
338                            start = start.min( [<loc $i>].start );
339                        }
340                    )*
341                    if start == usize::MAX {
342                        start = offset;
343                    }
344
345                    // Relocates empty children to the closest non-empty child.
346                    let mut cur = end;
347                    $(
348                        if [<loc $ri>].start == [<loc $ri>].end {
349                            [<this $ri>].relocate(locator, Location {
350                                file_path,
351                                start: cur,
352                                end: cur
353                            });
354                        } else {
355                            cur = [<loc $ri>].start;
356                        }
357                    )*
358
359                    Location {
360                        file_path,
361                        start,
362                        end
363                    }
364                }
365
366                fn relocate_as_group(&self, locator: &mut LocatorGuard, loc: Location) {
367                    let ( $( [<this $i>] ),* ) = self;
368
369                    // Calls relocate() on children.
370                    $(
371                        [<this $i>].relocate(locator, loc);
372                    )*
373                }
374            }
375        }
376    };
377}
378
379impl LocateGroup for () {
380    fn locate_as_group(
381        &self,
382        _: &mut LocatorGuard,
383        file_path: &'static str,
384        _code: &str,
385        offset: usize,
386    ) -> Location {
387        Location {
388            file_path,
389            start: offset,
390            end: offset,
391        }
392    }
393
394    fn relocate_as_group(&self, _: &mut LocatorGuard, _: Location) {}
395}
396
397impl<T: Locate> LocateGroup for &T {
398    fn locate_as_group(
399        &self,
400        locator: &mut LocatorGuard,
401        file_path: &'static str,
402        code: &str,
403        offset: usize,
404    ) -> Location {
405        self.locate(locator, file_path, code, offset)
406    }
407
408    fn relocate_as_group(&self, locator: &mut LocatorGuard, loc: Location) {
409        self.relocate(locator, loc)
410    }
411}
412
413impl_locate_group!(0, 1 ; 1, 0);
414impl_locate_group!(0, 1, 2 ; 2, 1, 0);
415impl_locate_group!(0, 1, 2, 3 ; 3, 2, 1, 0);
416impl_locate_group!(0, 1, 2, 3, 4 ; 4, 3, 2, 1, 0);
417impl_locate_group!(0, 1, 2, 3, 4, 5 ; 5, 4, 3, 2, 1, 0);
418impl_locate_group!(0, 1, 2, 3, 4, 5, 6 ; 6, 5, 4, 3, 2, 1, 0);
419impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7 ; 7, 6, 5, 4, 3, 2, 1, 0);
420impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8 ; 8, 7, 6, 5, 4, 3, 2, 1, 0);
421impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ; 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
422impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
423impl_locate_group!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ; 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
424
425pub struct Surround<'s, F, S, I, B> {
426    pub front: F,
427    pub surround: &'s S,
428    pub inner: I,
429    pub back: B,
430}
431
432impl<F, S, I, B> Surround<'_, F, S, I, B>
433where
434    F: LocateGroup,
435    S: Locate,
436    I: LocateGroup,
437    B: LocateGroup,
438{
439    pub fn locate(
440        &self,
441        locator: &mut LocatorGuard,
442        file_path: &'static str,
443        code: &str,
444        offset: usize,
445    ) -> Location {
446        // Calls locate() on fields.
447        let front_loc = self.front.locate_as_group(locator, file_path, code, offset);
448        let surround_loc = self
449            .surround
450            .locate(locator, file_path, code, front_loc.end);
451        self.inner
452            .locate_as_group(locator, file_path, code, surround_loc.start + 1);
453        let back_loc = self
454            .back
455            .locate_as_group(locator, file_path, code, surround_loc.end);
456
457        // Relocates front if needed
458        let mut start = front_loc.start;
459        if front_loc.start == front_loc.end {
460            self.front.relocate_as_group(
461                locator,
462                Location {
463                    file_path,
464                    start: surround_loc.start,
465                    end: surround_loc.start,
466                },
467            );
468            start = surround_loc.start;
469        }
470
471        // Relocates back if needed
472        let mut end = back_loc.end;
473        if back_loc.start == back_loc.end {
474            self.back.relocate_as_group(
475                locator,
476                Location {
477                    file_path,
478                    start: surround_loc.end,
479                    end: surround_loc.end,
480                },
481            );
482            end = surround_loc.end;
483        }
484
485        Location {
486            file_path,
487            start,
488            end,
489        }
490    }
491}
492
493pub struct Qualified<'a, F, B> {
494    pub front: F,
495    pub qself: &'a syn::QSelf,
496    pub path: &'a syn::Path,
497    pub back: B,
498}
499
500impl<F, B> Qualified<'_, F, B>
501where
502    F: LocateGroup,
503    B: LocateGroup,
504{
505    pub fn locate(
506        &self,
507        locator: &mut LocatorGuard,
508        file_path: &'static str,
509        code: &str,
510        offset: usize,
511    ) -> Location {
512        // Calls locate() on fields.
513        let front_loc = self.front.locate_as_group(locator, file_path, code, offset);
514
515        let qself_loc = self.qself.locate(locator, file_path, code, front_loc.end);
516        let qself_mid_loc = self.qself.as_token._location(locator);
517
518        // Path will be evaluated on something like `a::b::Trait>::Assoc`. The
519        // string contains '>' though, it would be fine because we will skip it
520        // during string matching.
521        let path_loc = self
522            .path
523            .locate(locator, file_path, code, qself_mid_loc.end);
524
525        let back_loc = self
526            .back
527            .locate_as_group(locator, file_path, code, path_loc.end);
528
529        // Relocates front if needed
530        let mut start = front_loc.start;
531        if front_loc.start == front_loc.end {
532            self.front.relocate_as_group(
533                locator,
534                Location {
535                    file_path,
536                    start: qself_loc.start,
537                    end: qself_loc.start,
538                },
539            );
540            start = qself_loc.start;
541        }
542
543        // Relocates back if needed
544        let mut end = back_loc.end;
545        if back_loc.start == back_loc.end {
546            self.back.relocate_as_group(
547                locator,
548                Location {
549                    file_path,
550                    start: path_loc.end,
551                    end: path_loc.end,
552                },
553            );
554            end = path_loc.end;
555        }
556
557        Location {
558            file_path,
559            start,
560            end,
561        }
562    }
563}
564
565pub struct Locator {
566    files: HashMap<&'static str, Content>,
567    map: HashMap<LocationKey, Location>,
568}
569
570impl Locator {
571    fn new() -> Self {
572        Self {
573            files: HashMap::new(),
574            map: HashMap::new(),
575        }
576    }
577
578    fn clear(&mut self) {
579        for (file_path, _) in self.files.drain() {
580            let ptr = file_path as *const str as *mut str;
581            unsafe { drop(Box::from_raw(ptr)) };
582        }
583
584        self.map.clear();
585    }
586
587    fn contains_file(&self, file_path: &str) -> bool {
588        self.files.contains_key(file_path)
589    }
590
591    /// Inserts file then returns its index.
592    fn insert_file<T: Any + ?Sized>(
593        &mut self,
594        syn_file: &T,
595        file_path: &str,
596        code: Box<str>,
597    ) -> Result<Location> {
598        fn inner(
599            this: &mut Locator,
600            key: LocationKey,
601            file_path: &str,
602            code: Box<str>,
603        ) -> Result<Location> {
604            if let Some(loc) = this.map.get(&key) {
605                return Ok(*loc);
606            }
607            if this.contains_file(file_path) {
608                return Err(
609                    format!("`syn-locator` detected duplicate file path: `{file_path}`").into(),
610                );
611            }
612
613            let file_path: Box<str> = file_path.into();
614            let file_path = Box::leak(file_path);
615            let loc = Location {
616                file_path,
617                start: 0,
618                end: code.len(),
619            };
620            this.files.insert(file_path, Content::new(code));
621            this.map.insert(key, loc);
622
623            Ok(loc)
624        }
625
626        inner(self, LocationKey::new(syn_file), file_path, code)
627    }
628
629    fn set_location<T: Any + ?Sized>(&mut self, syn_node: &T, loc: Location) {
630        self.map.insert(LocationKey::new(syn_node), loc);
631    }
632
633    fn get_location<T: Any + ?Sized>(&self, syn_node: &T) -> Option<Location> {
634        self.map.get(&LocationKey::new(syn_node)).cloned()
635    }
636
637    fn get_original_code(&self, file_path: &str) -> Option<&str> {
638        self.files
639            .get(file_path)
640            .map(|file| (*file.original_code).as_ref())
641    }
642
643    fn filtered_code_ptr(&self, file_path: &str) -> Option<*const str> {
644        self.files.get(file_path).map(|file| {
645            let code = &*file.filtered_code.as_ref();
646            code as *const _
647        })
648    }
649}
650
651impl Drop for Locator {
652    fn drop(&mut self) {
653        self.clear();
654    }
655}
656
657struct Content {
658    original_code: Pin<Box<str>>,
659    filtered_code: Pin<Box<str>>,
660}
661
662impl Content {
663    fn new(code: Box<str>) -> Self {
664        let filtered_code = Self::remove_non_tokens((*code).as_ref());
665        Self {
666            original_code: Pin::new(code),
667            filtered_code,
668        }
669    }
670
671    /// Replaces comments with white spaces from the given code for further
672    /// token matching.
673    fn remove_non_tokens(code: &str) -> Pin<Box<str>> {
674        use regex::{Captures, Regex};
675
676        static RE: OnceLock<Regex> = OnceLock::new();
677
678        // Regex doesn't support recursion, so that we cannot remove nested
679        // comments. We need to write code from scratch to do that.
680        let re = RE.get_or_init(|| {
681            Regex::new(
682                r#"(?x)
683                (//[^\n]*)  # Single line comment
684                |
685                (?s)
686                (/\*.*?\*/) # Block comment (Recursion is not supported)
687            "#,
688            )
689            .unwrap()
690        });
691
692        let s: Box<str> = re
693            .replace_all(code, |caps: &Captures| " ".repeat(caps[0].len()))
694            .into();
695        Box::into_pin(s)
696    }
697}
698
699#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
700struct LocationKey {
701    /// For hashing.
702    ptr: usize,
703
704    // Because pointer of a struct is the same as pointer of the first child of
705    // it, we distinguash them using type id.
706    ty: TypeId,
707}
708
709impl LocationKey {
710    fn new<T: Any + ?Sized>(t: &T) -> Self {
711        Self {
712            ptr: t as *const T as *const () as usize,
713            ty: TypeId::of::<T>(),
714        }
715    }
716}
717
718#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
719pub struct Location {
720    pub file_path: &'static str,
721
722    /// Byte index to the code.
723    pub start: usize,
724
725    /// Byte index to the code. Exclusive
726    pub end: usize,
727}
728
729impl PartialOrd for Location {
730    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
731        Some(self.cmp(other))
732    }
733}
734
735impl Ord for Location {
736    fn cmp(&self, other: &Self) -> cmp::Ordering {
737        match self.file_path.cmp(other.file_path) {
738            cmp::Ordering::Equal => match self.start.cmp(&other.start) {
739                cmp::Ordering::Equal => self.end.cmp(&other.end),
740                o => o,
741            },
742            o => o,
743        }
744    }
745}
746
747macro_rules! impl_locate_for_token {
748    ($ty:ty, $token:literal, char) => {
749        impl Locate for $ty {
750            fn find_loc(
751                &self,
752                _: &mut LocatorGuard,
753                file_path: &'static str,
754                code: &str,
755                offset: usize,
756            ) -> Location {
757                helper::char_location(file_path, code, offset, $token)
758            }
759        }
760    };
761    ($ty:ty, $token:literal, str) => {
762        impl Locate for $ty {
763            fn find_loc(
764                &self,
765                _: &mut LocatorGuard,
766                file_path: &'static str,
767                code: &str,
768                offset: usize,
769            ) -> Location {
770                helper::str_location(file_path, code, offset, $token)
771            }
772        }
773    };
774}
775
776impl_locate_for_token!(syn::Token![abstract], "abstract", str);
777impl_locate_for_token!(syn::Token![as], "as", str);
778impl_locate_for_token!(syn::Token![async], "async", str);
779impl_locate_for_token!(syn::Token![auto], "auto", str);
780impl_locate_for_token!(syn::Token![await], "await", str);
781impl_locate_for_token!(syn::Token![become], "become", str);
782impl_locate_for_token!(syn::Token![box], "box", str);
783impl_locate_for_token!(syn::Token![break], "break", str);
784impl_locate_for_token!(syn::Token![const], "const", str);
785impl_locate_for_token!(syn::Token![continue], "continue", str);
786impl_locate_for_token!(syn::Token![crate], "crate", str);
787impl_locate_for_token!(syn::Token![default], "default", str);
788impl_locate_for_token!(syn::Token![do], "do", str);
789impl_locate_for_token!(syn::Token![dyn], "dyn", str);
790impl_locate_for_token!(syn::Token![else], "else", str);
791impl_locate_for_token!(syn::Token![enum], "enum", str);
792impl_locate_for_token!(syn::Token![extern], "extern", str);
793impl_locate_for_token!(syn::Token![final], "final", str);
794impl_locate_for_token!(syn::Token![fn], "fn", str);
795impl_locate_for_token!(syn::Token![for], "for", str);
796impl_locate_for_token!(syn::Token![if], "if", str);
797impl_locate_for_token!(syn::Token![impl], "impl", str);
798impl_locate_for_token!(syn::Token![in], "in", str);
799impl_locate_for_token!(syn::Token![let], "let", str);
800impl_locate_for_token!(syn::Token![loop], "loop", str);
801impl_locate_for_token!(syn::Token![macro], "macro", str);
802impl_locate_for_token!(syn::Token![match], "match", str);
803impl_locate_for_token!(syn::Token![mod], "mod", str);
804impl_locate_for_token!(syn::Token![move], "move", str);
805impl_locate_for_token!(syn::Token![mut], "mut", str);
806impl_locate_for_token!(syn::Token![override], "override", str);
807impl_locate_for_token!(syn::Token![priv], "priv", str);
808impl_locate_for_token!(syn::Token![pub], "pub", str);
809impl_locate_for_token!(syn::Token![raw], "raw", str);
810impl_locate_for_token!(syn::Token![ref], "ref", str);
811impl_locate_for_token!(syn::Token![return], "return", str);
812impl_locate_for_token!(syn::Token![Self], "Self", str);
813impl_locate_for_token!(syn::Token![self], "self", str);
814impl_locate_for_token!(syn::Token![static], "static", str);
815impl_locate_for_token!(syn::Token![struct], "struct", str);
816impl_locate_for_token!(syn::Token![super], "super", str);
817impl_locate_for_token!(syn::Token![trait], "trait", str);
818impl_locate_for_token!(syn::Token![try], "try", str);
819impl_locate_for_token!(syn::Token![type], "type", str);
820impl_locate_for_token!(syn::Token![typeof], "typeof", str);
821impl_locate_for_token!(syn::Token![union], "union", str);
822impl_locate_for_token!(syn::Token![unsafe], "unsafe", str);
823impl_locate_for_token!(syn::Token![unsized], "unsized", str);
824impl_locate_for_token!(syn::Token![use], "use", str);
825impl_locate_for_token!(syn::Token![virtual], "virtual", str);
826impl_locate_for_token!(syn::Token![where], "where", str);
827impl_locate_for_token!(syn::Token![while], "while", str);
828impl_locate_for_token!(syn::Token![yield], "yield", str);
829impl_locate_for_token!(syn::Token![&], '&', char);
830impl_locate_for_token!(syn::Token![&&], "&&", str);
831impl_locate_for_token!(syn::Token![&=], "&=", str);
832impl_locate_for_token!(syn::Token![@], '@', char);
833impl_locate_for_token!(syn::Token![^], '^', char);
834impl_locate_for_token!(syn::Token![^=], "^=", str);
835impl_locate_for_token!(syn::Token![:], ':', char);
836impl_locate_for_token!(syn::Token![,], ',', char);
837impl_locate_for_token!(syn::Token![$], '$', char);
838impl_locate_for_token!(syn::Token![.], '.', char);
839impl_locate_for_token!(syn::Token![..], "..", str);
840impl_locate_for_token!(syn::Token![...], "...", str);
841impl_locate_for_token!(syn::Token![..=], "..=", str);
842impl_locate_for_token!(syn::Token![=], '=', char);
843impl_locate_for_token!(syn::Token![==], "==", str);
844impl_locate_for_token!(syn::Token![=>], "=>", str);
845impl_locate_for_token!(syn::Token![>=], ">=", str);
846impl_locate_for_token!(syn::Token![>], '>', char);
847impl_locate_for_token!(syn::Token![<-], "<-", str);
848impl_locate_for_token!(syn::Token![<=], "<=", str);
849impl_locate_for_token!(syn::Token![<], '<', char);
850impl_locate_for_token!(syn::Token![-], '-', char);
851impl_locate_for_token!(syn::Token![-=], "-=", str);
852impl_locate_for_token!(syn::Token![!=], "!=", str);
853impl_locate_for_token!(syn::Token![!], '!', char);
854impl_locate_for_token!(syn::Token![|], '|', char);
855impl_locate_for_token!(syn::Token![|=], "|=", str);
856impl_locate_for_token!(syn::Token![||], "||", str);
857impl_locate_for_token!(syn::Token![::], "::", str);
858impl_locate_for_token!(syn::Token![%], '%', char);
859impl_locate_for_token!(syn::Token![%=], "%=", str);
860impl_locate_for_token!(syn::Token![+], '+', char);
861impl_locate_for_token!(syn::Token![+=], "+=", str);
862impl_locate_for_token!(syn::Token![#], '#', char);
863impl_locate_for_token!(syn::Token![?], '?', char);
864impl_locate_for_token!(syn::Token![->], "->", str);
865impl_locate_for_token!(syn::Token![;], ';', char);
866impl_locate_for_token!(syn::Token![<<], "<<", str);
867impl_locate_for_token!(syn::Token![<<=], "<<=", str);
868impl_locate_for_token!(syn::Token![>>], ">>", str);
869impl_locate_for_token!(syn::Token![>>=], ">>=", str);
870impl_locate_for_token!(syn::Token![/], '/', char);
871impl_locate_for_token!(syn::Token![/=], "/=", str);
872impl_locate_for_token!(syn::Token![*], '*', char);
873impl_locate_for_token!(syn::Token![*=], "*=", str);
874impl_locate_for_token!(syn::Token![~], '~', char);
875impl_locate_for_token!(syn::Token![_], '_', char);
876
877impl Locate for syn::token::Group {
878    fn find_loc(
879        &self,
880        _: &mut LocatorGuard,
881        file_path: &'static str,
882        _code: &str,
883        offset: usize,
884    ) -> Location {
885        Location {
886            file_path,
887            start: offset,
888            end: offset,
889        }
890    }
891}
892
893macro_rules! impl_locate_for_pair_tokens {
894    ($ty:ty, $open:literal, $close:literal) => {
895        impl Locate for $ty {
896            fn find_loc(
897                &self,
898                _: &mut LocatorGuard,
899                file_path: &'static str,
900                code: &str,
901                offset: usize,
902            ) -> Location {
903                const OPEN: char = $open;
904                const CLOSE: char = $close;
905
906                let cur_code = &code[offset..];
907
908                let mut start = 0;
909                let mut end = 0;
910                let mut cur = offset;
911                let mut level = 0;
912
913                for c in cur_code.chars() {
914                    if c == OPEN {
915                        if level == 0 {
916                            start = cur;
917                        }
918                        level += 1;
919                    } else if c == CLOSE {
920                        if level == 1 {
921                            end = cur + CLOSE.len_utf8();
922                            break;
923                        }
924                        if level > 0 {
925                            level -= 1;
926                        }
927                    }
928                    cur += c.len_utf8();
929                }
930
931                if start >= end {
932                    panic!("expected `{OPEN}..{CLOSE}` from {cur_code}");
933                }
934
935                Location {
936                    file_path,
937                    start,
938                    end,
939                }
940            }
941        }
942    };
943}
944
945impl_locate_for_pair_tokens!(syn::token::Brace, '{', '}');
946impl_locate_for_pair_tokens!(syn::token::Bracket, '[', ']');
947impl_locate_for_pair_tokens!(syn::token::Paren, '(', ')');
948
949impl Locate for syn::Abi {
950    fn find_loc(
951        &self,
952        locator: &mut LocatorGuard,
953        file_path: &'static str,
954        code: &str,
955        offset: usize,
956    ) -> Location {
957        (&self.extern_token, &self.name).locate_as_group(locator, file_path, code, offset)
958    }
959}
960
961impl Locate for syn::AngleBracketedGenericArguments {
962    fn find_loc(
963        &self,
964        locator: &mut LocatorGuard,
965        file_path: &'static str,
966        code: &str,
967        offset: usize,
968    ) -> Location {
969        (
970            &self.colon2_token,
971            &self.lt_token,
972            &self.args,
973            &self.gt_token,
974        )
975            .locate_as_group(locator, file_path, code, offset)
976    }
977}
978
979impl Locate for syn::Arm {
980    fn find_loc(
981        &self,
982        locator: &mut LocatorGuard,
983        file_path: &'static str,
984        code: &str,
985        offset: usize,
986    ) -> Location {
987        if let Some((if_token, guard)) = &self.guard {
988            (
989                &self.attrs,
990                &self.pat,
991                if_token,
992                guard,
993                &self.fat_arrow_token,
994                &self.body,
995                &self.comma,
996            )
997                .locate_as_group(locator, file_path, code, offset)
998        } else {
999            (
1000                &self.attrs,
1001                &self.pat,
1002                &self.fat_arrow_token,
1003                &self.body,
1004                &self.comma,
1005            )
1006                .locate_as_group(locator, file_path, code, offset)
1007        }
1008    }
1009}
1010
1011impl Locate for syn::AssocConst {
1012    fn find_loc(
1013        &self,
1014        locator: &mut LocatorGuard,
1015        file_path: &'static str,
1016        code: &str,
1017        offset: usize,
1018    ) -> Location {
1019        (&self.ident, &self.generics, &self.eq_token, &self.value)
1020            .locate_as_group(locator, file_path, code, offset)
1021    }
1022}
1023
1024impl Locate for syn::AssocType {
1025    fn find_loc(
1026        &self,
1027        locator: &mut LocatorGuard,
1028        file_path: &'static str,
1029        code: &str,
1030        offset: usize,
1031    ) -> Location {
1032        (&self.ident, &self.generics, &self.eq_token, &self.ty)
1033            .locate_as_group(locator, file_path, code, offset)
1034    }
1035}
1036
1037impl Locate for syn::Attribute {
1038    fn find_loc(
1039        &self,
1040        locator: &mut LocatorGuard,
1041        file_path: &'static str,
1042        code: &str,
1043        offset: usize,
1044    ) -> Location {
1045        Surround {
1046            front: (&self.pound_token, &self.style),
1047            surround: &self.bracket_token,
1048            inner: &self.meta,
1049            back: (),
1050        }
1051        .locate(locator, file_path, code, offset)
1052    }
1053}
1054
1055impl Locate for syn::AttrStyle {
1056    fn find_loc(
1057        &self,
1058        locator: &mut LocatorGuard,
1059        file_path: &'static str,
1060        code: &str,
1061        offset: usize,
1062    ) -> Location {
1063        match self {
1064            Self::Outer => Location {
1065                file_path,
1066                start: offset,
1067                end: offset,
1068            },
1069            Self::Inner(v) => v.find_loc(locator, file_path, code, offset),
1070        }
1071    }
1072}
1073
1074impl Locate for syn::BareFnArg {
1075    fn find_loc(
1076        &self,
1077        locator: &mut LocatorGuard,
1078        file_path: &'static str,
1079        code: &str,
1080        offset: usize,
1081    ) -> Location {
1082        if let Some((name, colon_token)) = &self.name {
1083            (&self.attrs, name, colon_token, &self.ty)
1084                .locate_as_group(locator, file_path, code, offset)
1085        } else {
1086            (&self.attrs, &self.ty).locate_as_group(locator, file_path, code, offset)
1087        }
1088    }
1089}
1090
1091impl Locate for syn::BareVariadic {
1092    fn find_loc(
1093        &self,
1094        locator: &mut LocatorGuard,
1095        file_path: &'static str,
1096        code: &str,
1097        offset: usize,
1098    ) -> Location {
1099        if let Some((name, colon_token)) = &self.name {
1100            (&self.attrs, name, colon_token, &self.dots, &self.comma)
1101                .locate_as_group(locator, file_path, code, offset)
1102        } else {
1103            (&self.attrs, &self.dots, &self.comma).locate_as_group(locator, file_path, code, offset)
1104        }
1105    }
1106}
1107
1108impl Locate for syn::BinOp {
1109    fn find_loc(
1110        &self,
1111        locator: &mut LocatorGuard,
1112        file_path: &'static str,
1113        code: &str,
1114        offset: usize,
1115    ) -> Location {
1116        match self {
1117            Self::Add(v) => v.locate(locator, file_path, code, offset),
1118            Self::Sub(v) => v.locate(locator, file_path, code, offset),
1119            Self::Mul(v) => v.locate(locator, file_path, code, offset),
1120            Self::Div(v) => v.locate(locator, file_path, code, offset),
1121            Self::Rem(v) => v.locate(locator, file_path, code, offset),
1122            Self::And(v) => v.locate(locator, file_path, code, offset),
1123            Self::Or(v) => v.locate(locator, file_path, code, offset),
1124            Self::BitXor(v) => v.locate(locator, file_path, code, offset),
1125            Self::BitAnd(v) => v.locate(locator, file_path, code, offset),
1126            Self::BitOr(v) => v.locate(locator, file_path, code, offset),
1127            Self::Shl(v) => v.locate(locator, file_path, code, offset),
1128            Self::Shr(v) => v.locate(locator, file_path, code, offset),
1129            Self::Eq(v) => v.locate(locator, file_path, code, offset),
1130            Self::Lt(v) => v.locate(locator, file_path, code, offset),
1131            Self::Le(v) => v.locate(locator, file_path, code, offset),
1132            Self::Ne(v) => v.locate(locator, file_path, code, offset),
1133            Self::Ge(v) => v.locate(locator, file_path, code, offset),
1134            Self::Gt(v) => v.locate(locator, file_path, code, offset),
1135            Self::AddAssign(v) => v.locate(locator, file_path, code, offset),
1136            Self::SubAssign(v) => v.locate(locator, file_path, code, offset),
1137            Self::MulAssign(v) => v.locate(locator, file_path, code, offset),
1138            Self::DivAssign(v) => v.locate(locator, file_path, code, offset),
1139            Self::RemAssign(v) => v.locate(locator, file_path, code, offset),
1140            Self::BitXorAssign(v) => v.locate(locator, file_path, code, offset),
1141            Self::BitAndAssign(v) => v.locate(locator, file_path, code, offset),
1142            Self::BitOrAssign(v) => v.locate(locator, file_path, code, offset),
1143            Self::ShlAssign(v) => v.locate(locator, file_path, code, offset),
1144            Self::ShrAssign(v) => v.locate(locator, file_path, code, offset),
1145            _ => Location {
1146                file_path,
1147                start: offset,
1148                end: offset,
1149            },
1150        }
1151    }
1152}
1153
1154impl Locate for syn::Block {
1155    fn find_loc(
1156        &self,
1157        locator: &mut LocatorGuard,
1158        file_path: &'static str,
1159        code: &str,
1160        offset: usize,
1161    ) -> Location {
1162        Surround {
1163            front: (),
1164            surround: &self.brace_token,
1165            inner: &self.stmts,
1166            back: (),
1167        }
1168        .locate(locator, file_path, code, offset)
1169    }
1170}
1171
1172impl Locate for syn::BoundLifetimes {
1173    fn find_loc(
1174        &self,
1175        locator: &mut LocatorGuard,
1176        file_path: &'static str,
1177        code: &str,
1178        offset: usize,
1179    ) -> Location {
1180        (
1181            &self.for_token,
1182            &self.lt_token,
1183            &self.lifetimes,
1184            &self.gt_token,
1185        )
1186            .locate_as_group(locator, file_path, code, offset)
1187    }
1188}
1189
1190impl Locate for syn::CapturedParam {
1191    fn find_loc(
1192        &self,
1193        locator: &mut LocatorGuard,
1194        file_path: &'static str,
1195        code: &str,
1196        offset: usize,
1197    ) -> Location {
1198        match self {
1199            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
1200            Self::Ident(v) => v.locate(locator, file_path, code, offset),
1201            _ => Location {
1202                file_path,
1203                start: offset,
1204                end: offset,
1205            },
1206        }
1207    }
1208}
1209
1210impl Locate for syn::ConstParam {
1211    fn find_loc(
1212        &self,
1213        locator: &mut LocatorGuard,
1214        file_path: &'static str,
1215        code: &str,
1216        offset: usize,
1217    ) -> Location {
1218        (
1219            &self.attrs,
1220            &self.const_token,
1221            &self.ident,
1222            &self.colon_token,
1223            &self.ty,
1224            &self.eq_token,
1225            &self.default,
1226        )
1227            .locate_as_group(locator, file_path, code, offset)
1228    }
1229}
1230
1231impl Locate for syn::Constraint {
1232    fn find_loc(
1233        &self,
1234        locator: &mut LocatorGuard,
1235        file_path: &'static str,
1236        code: &str,
1237        offset: usize,
1238    ) -> Location {
1239        (&self.ident, &self.generics, &self.colon_token, &self.bounds)
1240            .locate_as_group(locator, file_path, code, offset)
1241    }
1242}
1243
1244impl Locate for syn::Expr {
1245    fn find_loc(
1246        &self,
1247        locator: &mut LocatorGuard,
1248        file_path: &'static str,
1249        code: &str,
1250        offset: usize,
1251    ) -> Location {
1252        match self {
1253            Self::Array(v) => v.locate(locator, file_path, code, offset),
1254            Self::Assign(v) => v.locate(locator, file_path, code, offset),
1255            Self::Async(v) => v.locate(locator, file_path, code, offset),
1256            Self::Await(v) => v.locate(locator, file_path, code, offset),
1257            Self::Binary(v) => v.locate(locator, file_path, code, offset),
1258            Self::Block(v) => v.locate(locator, file_path, code, offset),
1259            Self::Break(v) => v.locate(locator, file_path, code, offset),
1260            Self::Call(v) => v.locate(locator, file_path, code, offset),
1261            Self::Cast(v) => v.locate(locator, file_path, code, offset),
1262            Self::Closure(v) => v.locate(locator, file_path, code, offset),
1263            Self::Const(v) => v.locate(locator, file_path, code, offset),
1264            Self::Continue(v) => v.locate(locator, file_path, code, offset),
1265            Self::Field(v) => v.locate(locator, file_path, code, offset),
1266            Self::ForLoop(v) => v.locate(locator, file_path, code, offset),
1267            Self::Group(v) => v.locate(locator, file_path, code, offset),
1268            Self::If(v) => v.locate(locator, file_path, code, offset),
1269            Self::Index(v) => v.locate(locator, file_path, code, offset),
1270            Self::Infer(v) => v.locate(locator, file_path, code, offset),
1271            Self::Let(v) => v.locate(locator, file_path, code, offset),
1272            Self::Lit(v) => v.locate(locator, file_path, code, offset),
1273            Self::Loop(v) => v.locate(locator, file_path, code, offset),
1274            Self::Macro(v) => v.locate(locator, file_path, code, offset),
1275            Self::Match(v) => v.locate(locator, file_path, code, offset),
1276            Self::MethodCall(v) => v.locate(locator, file_path, code, offset),
1277            Self::Paren(v) => v.locate(locator, file_path, code, offset),
1278            Self::Path(v) => v.locate(locator, file_path, code, offset),
1279            Self::Range(v) => v.locate(locator, file_path, code, offset),
1280            Self::RawAddr(v) => v.locate(locator, file_path, code, offset),
1281            Self::Reference(v) => v.locate(locator, file_path, code, offset),
1282            Self::Repeat(v) => v.locate(locator, file_path, code, offset),
1283            Self::Return(v) => v.locate(locator, file_path, code, offset),
1284            Self::Struct(v) => v.locate(locator, file_path, code, offset),
1285            Self::Try(v) => v.locate(locator, file_path, code, offset),
1286            Self::TryBlock(v) => v.locate(locator, file_path, code, offset),
1287            Self::Tuple(v) => v.locate(locator, file_path, code, offset),
1288            Self::Unary(v) => v.locate(locator, file_path, code, offset),
1289            Self::Unsafe(v) => v.locate(locator, file_path, code, offset),
1290            Self::Verbatim(_) => Location {
1291                file_path,
1292                start: offset,
1293                end: offset,
1294            },
1295            Self::While(v) => v.locate(locator, file_path, code, offset),
1296            Self::Yield(v) => v.locate(locator, file_path, code, offset),
1297            _ => Location {
1298                file_path,
1299                start: offset,
1300                end: offset,
1301            },
1302        }
1303    }
1304}
1305
1306impl Locate for syn::ExprArray {
1307    fn find_loc(
1308        &self,
1309        locator: &mut LocatorGuard,
1310        file_path: &'static str,
1311        code: &str,
1312        offset: usize,
1313    ) -> Location {
1314        Surround {
1315            front: &self.attrs,
1316            surround: &self.bracket_token,
1317            inner: &self.elems,
1318            back: (),
1319        }
1320        .locate(locator, file_path, code, offset)
1321    }
1322}
1323
1324impl Locate for syn::ExprAssign {
1325    fn find_loc(
1326        &self,
1327        locator: &mut LocatorGuard,
1328        file_path: &'static str,
1329        code: &str,
1330        offset: usize,
1331    ) -> Location {
1332        (&self.attrs, &self.left, &self.eq_token, &self.right)
1333            .locate_as_group(locator, file_path, code, offset)
1334    }
1335}
1336
1337impl Locate for syn::ExprAsync {
1338    fn find_loc(
1339        &self,
1340        locator: &mut LocatorGuard,
1341        file_path: &'static str,
1342        code: &str,
1343        offset: usize,
1344    ) -> Location {
1345        (&self.attrs, &self.async_token, &self.capture, &self.block)
1346            .locate_as_group(locator, file_path, code, offset)
1347    }
1348}
1349
1350impl Locate for syn::ExprAwait {
1351    fn find_loc(
1352        &self,
1353        locator: &mut LocatorGuard,
1354        file_path: &'static str,
1355        code: &str,
1356        offset: usize,
1357    ) -> Location {
1358        (&self.attrs, &self.base, &self.dot_token, &self.await_token)
1359            .locate_as_group(locator, file_path, code, offset)
1360    }
1361}
1362
1363impl Locate for syn::ExprBinary {
1364    fn find_loc(
1365        &self,
1366        locator: &mut LocatorGuard,
1367        file_path: &'static str,
1368        code: &str,
1369        offset: usize,
1370    ) -> Location {
1371        (&self.attrs, &self.left, &self.op, &self.right)
1372            .locate_as_group(locator, file_path, code, offset)
1373    }
1374}
1375
1376impl Locate for syn::ExprBlock {
1377    fn find_loc(
1378        &self,
1379        locator: &mut LocatorGuard,
1380        file_path: &'static str,
1381        code: &str,
1382        offset: usize,
1383    ) -> Location {
1384        (&self.attrs, &self.label, &self.block).locate_as_group(locator, file_path, code, offset)
1385    }
1386}
1387
1388impl Locate for syn::ExprBreak {
1389    fn find_loc(
1390        &self,
1391        locator: &mut LocatorGuard,
1392        file_path: &'static str,
1393        code: &str,
1394        offset: usize,
1395    ) -> Location {
1396        (&self.attrs, &self.break_token, &self.label, &self.expr)
1397            .locate_as_group(locator, file_path, code, offset)
1398    }
1399}
1400
1401impl Locate for syn::ExprCall {
1402    fn find_loc(
1403        &self,
1404        locator: &mut LocatorGuard,
1405        file_path: &'static str,
1406        code: &str,
1407        offset: usize,
1408    ) -> Location {
1409        Surround {
1410            front: (&self.attrs, &self.func),
1411            surround: &self.paren_token,
1412            inner: &self.args,
1413            back: (),
1414        }
1415        .locate(locator, file_path, code, offset)
1416    }
1417}
1418
1419impl Locate for syn::ExprCast {
1420    fn find_loc(
1421        &self,
1422        locator: &mut LocatorGuard,
1423        file_path: &'static str,
1424        code: &str,
1425        offset: usize,
1426    ) -> Location {
1427        (&self.attrs, &self.expr, &self.as_token, &self.ty)
1428            .locate_as_group(locator, file_path, code, offset)
1429    }
1430}
1431
1432impl Locate for syn::ExprClosure {
1433    fn find_loc(
1434        &self,
1435        locator: &mut LocatorGuard,
1436        file_path: &'static str,
1437        code: &str,
1438        offset: usize,
1439    ) -> Location {
1440        (
1441            &self.attrs,
1442            &self.lifetimes,
1443            &self.constness,
1444            &self.movability,
1445            &self.asyncness,
1446            &self.capture,
1447            &self.or1_token,
1448            &self.inputs,
1449            &self.or2_token,
1450            &self.output,
1451            &self.body,
1452        )
1453            .locate_as_group(locator, file_path, code, offset)
1454    }
1455}
1456
1457impl Locate for syn::ExprConst {
1458    fn find_loc(
1459        &self,
1460        locator: &mut LocatorGuard,
1461        file_path: &'static str,
1462        code: &str,
1463        offset: usize,
1464    ) -> Location {
1465        (&self.attrs, &self.const_token, &self.block)
1466            .locate_as_group(locator, file_path, code, offset)
1467    }
1468}
1469
1470impl Locate for syn::ExprContinue {
1471    fn find_loc(
1472        &self,
1473        locator: &mut LocatorGuard,
1474        file_path: &'static str,
1475        code: &str,
1476        offset: usize,
1477    ) -> Location {
1478        (&self.attrs, &self.continue_token, &self.label)
1479            .locate_as_group(locator, file_path, code, offset)
1480    }
1481}
1482
1483impl Locate for syn::ExprField {
1484    fn find_loc(
1485        &self,
1486        locator: &mut LocatorGuard,
1487        file_path: &'static str,
1488        code: &str,
1489        offset: usize,
1490    ) -> Location {
1491        (&self.attrs, &self.base, &self.dot_token, &self.member)
1492            .locate_as_group(locator, file_path, code, offset)
1493    }
1494}
1495
1496impl Locate for syn::ExprForLoop {
1497    fn find_loc(
1498        &self,
1499        locator: &mut LocatorGuard,
1500        file_path: &'static str,
1501        code: &str,
1502        offset: usize,
1503    ) -> Location {
1504        (
1505            &self.attrs,
1506            &self.label,
1507            &self.for_token,
1508            &self.pat,
1509            &self.in_token,
1510            &self.expr,
1511            &self.body,
1512        )
1513            .locate_as_group(locator, file_path, code, offset)
1514    }
1515}
1516
1517impl Locate for syn::ExprGroup {
1518    fn find_loc(
1519        &self,
1520        locator: &mut LocatorGuard,
1521        file_path: &'static str,
1522        code: &str,
1523        offset: usize,
1524    ) -> Location {
1525        (&self.attrs, &self.group_token, &self.expr)
1526            .locate_as_group(locator, file_path, code, offset)
1527    }
1528}
1529
1530impl Locate for syn::ExprIf {
1531    fn find_loc(
1532        &self,
1533        locator: &mut LocatorGuard,
1534        file_path: &'static str,
1535        code: &str,
1536        offset: usize,
1537    ) -> Location {
1538        if let Some((else_token, else_branch)) = &self.else_branch {
1539            (
1540                &self.attrs,
1541                &self.if_token,
1542                &self.cond,
1543                &self.then_branch,
1544                else_token,
1545                else_branch,
1546            )
1547                .locate_as_group(locator, file_path, code, offset)
1548        } else {
1549            (&self.attrs, &self.if_token, &self.cond, &self.then_branch)
1550                .locate_as_group(locator, file_path, code, offset)
1551        }
1552    }
1553}
1554
1555impl Locate for syn::ExprIndex {
1556    fn find_loc(
1557        &self,
1558        locator: &mut LocatorGuard,
1559        file_path: &'static str,
1560        code: &str,
1561        offset: usize,
1562    ) -> Location {
1563        Surround {
1564            front: (&self.attrs, &self.expr),
1565            surround: &self.bracket_token,
1566            inner: &self.index,
1567            back: (),
1568        }
1569        .locate(locator, file_path, code, offset)
1570    }
1571}
1572
1573impl Locate for syn::ExprInfer {
1574    fn find_loc(
1575        &self,
1576        locator: &mut LocatorGuard,
1577        file_path: &'static str,
1578        code: &str,
1579        offset: usize,
1580    ) -> Location {
1581        (&self.attrs, &self.underscore_token).locate_as_group(locator, file_path, code, offset)
1582    }
1583}
1584
1585impl Locate for syn::ExprLet {
1586    fn find_loc(
1587        &self,
1588        locator: &mut LocatorGuard,
1589        file_path: &'static str,
1590        code: &str,
1591        offset: usize,
1592    ) -> Location {
1593        (
1594            &self.attrs,
1595            &self.let_token,
1596            &self.pat,
1597            &self.eq_token,
1598            &self.expr,
1599        )
1600            .locate_as_group(locator, file_path, code, offset)
1601    }
1602}
1603
1604impl Locate for syn::ExprLit {
1605    fn find_loc(
1606        &self,
1607        locator: &mut LocatorGuard,
1608        file_path: &'static str,
1609        code: &str,
1610        offset: usize,
1611    ) -> Location {
1612        (&self.attrs, &self.lit).locate_as_group(locator, file_path, code, offset)
1613    }
1614}
1615
1616impl Locate for syn::ExprLoop {
1617    fn find_loc(
1618        &self,
1619        locator: &mut LocatorGuard,
1620        file_path: &'static str,
1621        code: &str,
1622        offset: usize,
1623    ) -> Location {
1624        (&self.attrs, &self.label, &self.loop_token, &self.body)
1625            .locate_as_group(locator, file_path, code, offset)
1626    }
1627}
1628
1629impl Locate for syn::ExprMacro {
1630    fn find_loc(
1631        &self,
1632        locator: &mut LocatorGuard,
1633        file_path: &'static str,
1634        code: &str,
1635        offset: usize,
1636    ) -> Location {
1637        (&self.attrs, &self.mac).locate_as_group(locator, file_path, code, offset)
1638    }
1639}
1640
1641impl Locate for syn::ExprMatch {
1642    fn find_loc(
1643        &self,
1644        locator: &mut LocatorGuard,
1645        file_path: &'static str,
1646        code: &str,
1647        offset: usize,
1648    ) -> Location {
1649        Surround {
1650            front: (&self.attrs, &self.match_token, &self.expr),
1651            surround: &self.brace_token,
1652            inner: &self.arms,
1653            back: (),
1654        }
1655        .locate(locator, file_path, code, offset)
1656    }
1657}
1658
1659impl Locate for syn::ExprMethodCall {
1660    fn find_loc(
1661        &self,
1662        locator: &mut LocatorGuard,
1663        file_path: &'static str,
1664        code: &str,
1665        offset: usize,
1666    ) -> Location {
1667        Surround {
1668            front: (
1669                &self.attrs,
1670                &self.receiver,
1671                &self.dot_token,
1672                &self.method,
1673                &self.turbofish,
1674            ),
1675            surround: &self.paren_token,
1676            inner: &self.args,
1677            back: (),
1678        }
1679        .locate(locator, file_path, code, offset)
1680    }
1681}
1682
1683impl Locate for syn::ExprParen {
1684    fn find_loc(
1685        &self,
1686        locator: &mut LocatorGuard,
1687        file_path: &'static str,
1688        code: &str,
1689        offset: usize,
1690    ) -> Location {
1691        Surround {
1692            front: &self.attrs,
1693            surround: &self.paren_token,
1694            inner: &self.expr,
1695            back: (),
1696        }
1697        .locate(locator, file_path, code, offset)
1698    }
1699}
1700
1701impl Locate for syn::ExprPath {
1702    fn find_loc(
1703        &self,
1704        locator: &mut LocatorGuard,
1705        file_path: &'static str,
1706        code: &str,
1707        offset: usize,
1708    ) -> Location {
1709        if let Some(qself) = &self.qself {
1710            Qualified {
1711                front: &self.attrs,
1712                qself,
1713                path: &self.path,
1714                back: (),
1715            }
1716            .locate(locator, file_path, code, offset)
1717        } else {
1718            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
1719        }
1720    }
1721}
1722
1723impl Locate for syn::ExprRange {
1724    fn find_loc(
1725        &self,
1726        locator: &mut LocatorGuard,
1727        file_path: &'static str,
1728        code: &str,
1729        offset: usize,
1730    ) -> Location {
1731        match (&self.start, &self.end) {
1732            (Some(start), Some(end)) => (&self.attrs, start, &self.limits, end)
1733                .locate_as_group(locator, file_path, code, offset),
1734            (Some(start), None) => {
1735                (&self.attrs, start, &self.limits).locate_as_group(locator, file_path, code, offset)
1736            }
1737            (None, Some(end)) => {
1738                (&self.attrs, &self.limits, end).locate_as_group(locator, file_path, code, offset)
1739            }
1740            (None, None) => {
1741                (&self.attrs, &self.limits).locate_as_group(locator, file_path, code, offset)
1742            }
1743        }
1744    }
1745}
1746
1747impl Locate for syn::ExprRawAddr {
1748    fn find_loc(
1749        &self,
1750        locator: &mut LocatorGuard,
1751        file_path: &'static str,
1752        code: &str,
1753        offset: usize,
1754    ) -> Location {
1755        (
1756            &self.attrs,
1757            &self.and_token,
1758            &self.raw,
1759            &self.mutability,
1760            &self.expr,
1761        )
1762            .locate_as_group(locator, file_path, code, offset)
1763    }
1764}
1765
1766impl Locate for syn::ExprReference {
1767    fn find_loc(
1768        &self,
1769        locator: &mut LocatorGuard,
1770        file_path: &'static str,
1771        code: &str,
1772        offset: usize,
1773    ) -> Location {
1774        (&self.attrs, &self.and_token, &self.mutability, &self.expr)
1775            .locate_as_group(locator, file_path, code, offset)
1776    }
1777}
1778
1779impl Locate for syn::ExprRepeat {
1780    fn find_loc(
1781        &self,
1782        locator: &mut LocatorGuard,
1783        file_path: &'static str,
1784        code: &str,
1785        offset: usize,
1786    ) -> Location {
1787        Surround {
1788            front: &self.attrs,
1789            surround: &self.bracket_token,
1790            inner: (&self.expr, &self.semi_token, &self.len),
1791            back: (),
1792        }
1793        .locate(locator, file_path, code, offset)
1794    }
1795}
1796
1797impl Locate for syn::ExprReturn {
1798    fn find_loc(
1799        &self,
1800        locator: &mut LocatorGuard,
1801        file_path: &'static str,
1802        code: &str,
1803        offset: usize,
1804    ) -> Location {
1805        (&self.attrs, &self.return_token, &self.expr)
1806            .locate_as_group(locator, file_path, code, offset)
1807    }
1808}
1809
1810impl Locate for syn::ExprStruct {
1811    fn find_loc(
1812        &self,
1813        locator: &mut LocatorGuard,
1814        file_path: &'static str,
1815        code: &str,
1816        offset: usize,
1817    ) -> Location {
1818        let front_loc = if let Some(qself) = &self.qself {
1819            Qualified {
1820                front: &self.attrs,
1821                qself,
1822                path: &self.path,
1823                back: (),
1824            }
1825            .locate(locator, file_path, code, offset)
1826        } else {
1827            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
1828        };
1829
1830        let back_loc = Surround {
1831            front: (),
1832            surround: &self.brace_token,
1833            inner: (&self.fields, &self.dot2_token, &self.rest),
1834            back: (),
1835        }
1836        .locate(locator, file_path, code, front_loc.end);
1837
1838        Location {
1839            file_path,
1840            start: front_loc.start,
1841            end: back_loc.end,
1842        }
1843    }
1844}
1845
1846impl Locate for syn::ExprTry {
1847    fn find_loc(
1848        &self,
1849        locator: &mut LocatorGuard,
1850        file_path: &'static str,
1851        code: &str,
1852        offset: usize,
1853    ) -> Location {
1854        (&self.attrs, &self.expr, &self.question_token)
1855            .locate_as_group(locator, file_path, code, offset)
1856    }
1857}
1858
1859impl Locate for syn::ExprTryBlock {
1860    fn find_loc(
1861        &self,
1862        locator: &mut LocatorGuard,
1863        file_path: &'static str,
1864        code: &str,
1865        offset: usize,
1866    ) -> Location {
1867        (&self.attrs, &self.try_token, &self.block)
1868            .locate_as_group(locator, file_path, code, offset)
1869    }
1870}
1871
1872impl Locate for syn::ExprTuple {
1873    fn find_loc(
1874        &self,
1875        locator: &mut LocatorGuard,
1876        file_path: &'static str,
1877        code: &str,
1878        offset: usize,
1879    ) -> Location {
1880        Surround {
1881            front: &self.attrs,
1882            surround: &self.paren_token,
1883            inner: &self.elems,
1884            back: (),
1885        }
1886        .locate(locator, file_path, code, offset)
1887    }
1888}
1889
1890impl Locate for syn::ExprUnary {
1891    fn find_loc(
1892        &self,
1893        locator: &mut LocatorGuard,
1894        file_path: &'static str,
1895        code: &str,
1896        offset: usize,
1897    ) -> Location {
1898        (&self.attrs, &self.op, &self.expr).locate_as_group(locator, file_path, code, offset)
1899    }
1900}
1901
1902impl Locate for syn::ExprUnsafe {
1903    fn find_loc(
1904        &self,
1905        locator: &mut LocatorGuard,
1906        file_path: &'static str,
1907        code: &str,
1908        offset: usize,
1909    ) -> Location {
1910        (&self.attrs, &self.unsafe_token, &self.block)
1911            .locate_as_group(locator, file_path, code, offset)
1912    }
1913}
1914
1915impl Locate for syn::ExprWhile {
1916    fn find_loc(
1917        &self,
1918        locator: &mut LocatorGuard,
1919        file_path: &'static str,
1920        code: &str,
1921        offset: usize,
1922    ) -> Location {
1923        (
1924            &self.attrs,
1925            &self.label,
1926            &self.while_token,
1927            &self.cond,
1928            &self.body,
1929        )
1930            .locate_as_group(locator, file_path, code, offset)
1931    }
1932}
1933
1934impl Locate for syn::ExprYield {
1935    fn find_loc(
1936        &self,
1937        locator: &mut LocatorGuard,
1938        file_path: &'static str,
1939        code: &str,
1940        offset: usize,
1941    ) -> Location {
1942        (&self.attrs, &self.yield_token, &self.expr)
1943            .locate_as_group(locator, file_path, code, offset)
1944    }
1945}
1946
1947impl Locate for syn::Field {
1948    fn find_loc(
1949        &self,
1950        locator: &mut LocatorGuard,
1951        file_path: &'static str,
1952        code: &str,
1953        offset: usize,
1954    ) -> Location {
1955        (
1956            &self.attrs,
1957            &self.vis,
1958            &self.mutability,
1959            &self.ident,
1960            &self.colon_token,
1961            &self.ty,
1962        )
1963            .locate_as_group(locator, file_path, code, offset)
1964    }
1965}
1966
1967impl Locate for syn::FieldMutability {
1968    fn find_loc(
1969        &self,
1970        _: &mut LocatorGuard,
1971        file_path: &'static str,
1972        _code: &str,
1973        offset: usize,
1974    ) -> Location {
1975        Location {
1976            file_path,
1977            start: offset,
1978            end: offset,
1979        }
1980    }
1981}
1982
1983// `member` is parsed from token stream. But if there's no following colon token
1984// and `pat` after the member, `pat` is cloned from the `member` instead of
1985// being parsed from token stream.
1986// ref: https://github.com/dtolnay/syn/blob/5357c8fb6bd29fd7c829e0aede1dab4b45a6e00f/src/pat.rs#L562-L594
1987impl Locate for syn::FieldPat {
1988    fn find_loc(
1989        &self,
1990        locator: &mut LocatorGuard,
1991        file_path: &'static str,
1992        code: &str,
1993        offset: usize,
1994    ) -> Location {
1995        if self.colon_token.is_some() || !matches!(self.member, syn::Member::Named(_)) {
1996            (&self.attrs, &self.member, &self.colon_token, &self.pat)
1997                .locate_as_group(locator, file_path, code, offset)
1998        } else {
1999            let loc = (&self.attrs, &self.colon_token, &self.pat)
2000                .locate_as_group(locator, file_path, code, offset);
2001            self.member
2002                .locate(locator, file_path, code, self.attrs._location(locator).end);
2003            loc
2004        }
2005    }
2006}
2007
2008impl Locate for syn::Fields {
2009    fn find_loc(
2010        &self,
2011        locator: &mut LocatorGuard,
2012        file_path: &'static str,
2013        code: &str,
2014        offset: usize,
2015    ) -> Location {
2016        match self {
2017            Self::Named(v) => v.locate(locator, file_path, code, offset),
2018            Self::Unnamed(v) => v.locate(locator, file_path, code, offset),
2019            Self::Unit => Location {
2020                file_path,
2021                start: offset,
2022                end: offset,
2023            },
2024        }
2025    }
2026}
2027
2028impl Locate for syn::FieldsNamed {
2029    fn find_loc(
2030        &self,
2031        locator: &mut LocatorGuard,
2032        file_path: &'static str,
2033        code: &str,
2034        offset: usize,
2035    ) -> Location {
2036        Surround {
2037            front: (),
2038            surround: &self.brace_token,
2039            inner: &self.named,
2040            back: (),
2041        }
2042        .locate(locator, file_path, code, offset)
2043    }
2044}
2045
2046impl Locate for syn::FieldsUnnamed {
2047    fn find_loc(
2048        &self,
2049        locator: &mut LocatorGuard,
2050        file_path: &'static str,
2051        code: &str,
2052        offset: usize,
2053    ) -> Location {
2054        Surround {
2055            front: (),
2056            surround: &self.paren_token,
2057            inner: &self.unnamed,
2058            back: (),
2059        }
2060        .locate(locator, file_path, code, offset)
2061    }
2062}
2063
2064// `member` is parsed from token stream. But if there's no following colon token
2065// and `expr` after the member, `expr` is cloned from the `member` instead of
2066// being parsed from token stream.
2067// ref: https://github.com/dtolnay/syn/blob/5357c8fb6bd29fd7c829e0aede1dab4b45a6e00f/src/expr.rs#L2744-L2755
2068impl Locate for syn::FieldValue {
2069    fn find_loc(
2070        &self,
2071        locator: &mut LocatorGuard,
2072        file_path: &'static str,
2073        code: &str,
2074        offset: usize,
2075    ) -> Location {
2076        if self.colon_token.is_some() || !matches!(self.member, syn::Member::Named(_)) {
2077            (&self.attrs, &self.member, &self.colon_token, &self.expr)
2078                .locate_as_group(locator, file_path, code, offset)
2079        } else {
2080            let loc = (&self.attrs, &self.member, &self.colon_token)
2081                .locate_as_group(locator, file_path, code, offset);
2082            self.expr
2083                .locate(locator, file_path, code, self.attrs._location(locator).end);
2084            loc
2085        }
2086    }
2087}
2088
2089impl Locate for syn::File {
2090    fn find_loc(
2091        &self,
2092        locator: &mut LocatorGuard,
2093        file_path: &'static str,
2094        code: &str,
2095        offset: usize,
2096    ) -> Location {
2097        (&self.attrs, &self.items).locate_as_group(locator, file_path, code, offset)
2098    }
2099}
2100
2101impl Locate for syn::FnArg {
2102    fn find_loc(
2103        &self,
2104        locator: &mut LocatorGuard,
2105        file_path: &'static str,
2106        code: &str,
2107        offset: usize,
2108    ) -> Location {
2109        match self {
2110            Self::Receiver(v) => v.locate(locator, file_path, code, offset),
2111            Self::Typed(v) => v.locate(locator, file_path, code, offset),
2112        }
2113    }
2114}
2115
2116impl Locate for syn::ForeignItem {
2117    fn find_loc(
2118        &self,
2119        locator: &mut LocatorGuard,
2120        file_path: &'static str,
2121        code: &str,
2122        offset: usize,
2123    ) -> Location {
2124        match self {
2125            Self::Fn(v) => v.locate(locator, file_path, code, offset),
2126            Self::Static(v) => v.locate(locator, file_path, code, offset),
2127            Self::Type(v) => v.locate(locator, file_path, code, offset),
2128            Self::Macro(v) => v.locate(locator, file_path, code, offset),
2129            Self::Verbatim(_) => Location {
2130                file_path,
2131                start: offset,
2132                end: offset,
2133            },
2134            _ => Location {
2135                file_path,
2136                start: offset,
2137                end: offset,
2138            },
2139        }
2140    }
2141}
2142
2143impl Locate for syn::ForeignItemFn {
2144    fn find_loc(
2145        &self,
2146        locator: &mut LocatorGuard,
2147        file_path: &'static str,
2148        code: &str,
2149        offset: usize,
2150    ) -> Location {
2151        (&self.attrs, &self.vis, &self.sig, &self.semi_token)
2152            .locate_as_group(locator, file_path, code, offset)
2153    }
2154}
2155
2156impl Locate for syn::ForeignItemStatic {
2157    fn find_loc(
2158        &self,
2159        locator: &mut LocatorGuard,
2160        file_path: &'static str,
2161        code: &str,
2162        offset: usize,
2163    ) -> Location {
2164        (
2165            &self.attrs,
2166            &self.vis,
2167            &self.static_token,
2168            &self.mutability,
2169            &self.ident,
2170            &self.colon_token,
2171            &self.ty,
2172            &self.semi_token,
2173        )
2174            .locate_as_group(locator, file_path, code, offset)
2175    }
2176}
2177
2178impl Locate for syn::ForeignItemType {
2179    fn find_loc(
2180        &self,
2181        locator: &mut LocatorGuard,
2182        file_path: &'static str,
2183        code: &str,
2184        offset: usize,
2185    ) -> Location {
2186        (
2187            &self.attrs,
2188            &self.vis,
2189            &self.type_token,
2190            &self.ident,
2191            &self.generics,
2192            &self.semi_token,
2193        )
2194            .locate_as_group(locator, file_path, code, offset)
2195    }
2196}
2197
2198impl Locate for syn::ForeignItemMacro {
2199    fn find_loc(
2200        &self,
2201        locator: &mut LocatorGuard,
2202        file_path: &'static str,
2203        code: &str,
2204        offset: usize,
2205    ) -> Location {
2206        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
2207    }
2208}
2209
2210impl Locate for syn::GenericArgument {
2211    fn find_loc(
2212        &self,
2213        locator: &mut LocatorGuard,
2214        file_path: &'static str,
2215        code: &str,
2216        offset: usize,
2217    ) -> Location {
2218        match self {
2219            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
2220            Self::Type(v) => v.locate(locator, file_path, code, offset),
2221            Self::Const(v) => v.locate(locator, file_path, code, offset),
2222            Self::AssocType(v) => v.locate(locator, file_path, code, offset),
2223            Self::AssocConst(v) => v.locate(locator, file_path, code, offset),
2224            Self::Constraint(v) => v.locate(locator, file_path, code, offset),
2225            _ => Location {
2226                file_path,
2227                start: offset,
2228                end: offset,
2229            },
2230        }
2231    }
2232}
2233
2234impl Locate for syn::GenericParam {
2235    fn find_loc(
2236        &self,
2237        locator: &mut LocatorGuard,
2238        file_path: &'static str,
2239        code: &str,
2240        offset: usize,
2241    ) -> Location {
2242        match self {
2243            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
2244            Self::Type(v) => v.locate(locator, file_path, code, offset),
2245            Self::Const(v) => v.locate(locator, file_path, code, offset),
2246        }
2247    }
2248}
2249
2250impl Locate for syn::Generics {
2251    fn find_loc(
2252        &self,
2253        locator: &mut LocatorGuard,
2254        file_path: &'static str,
2255        code: &str,
2256        offset: usize,
2257    ) -> Location {
2258        (
2259            &self.lt_token,
2260            &self.params,
2261            &self.gt_token,
2262            &self.where_clause,
2263        )
2264            .locate_as_group(locator, file_path, code, offset)
2265    }
2266}
2267
2268impl Locate for syn::Ident {
2269    fn find_loc(
2270        &self,
2271        _: &mut LocatorGuard,
2272        file_path: &'static str,
2273        code: &str,
2274        offset: usize,
2275    ) -> Location {
2276        let cur_code = &code[offset..];
2277
2278        let ident = self.to_string();
2279        let start = offset
2280            + cur_code
2281                .find(&ident)
2282                .unwrap_or_else(|| panic!("expected `{ident}` from `{cur_code}`"));
2283
2284        Location {
2285            file_path,
2286            start,
2287            end: start + ident.len(),
2288        }
2289    }
2290}
2291
2292impl Locate for syn::ImplItem {
2293    fn find_loc(
2294        &self,
2295        locator: &mut LocatorGuard,
2296        file_path: &'static str,
2297        code: &str,
2298        offset: usize,
2299    ) -> Location {
2300        match self {
2301            Self::Const(v) => v.locate(locator, file_path, code, offset),
2302            Self::Fn(v) => v.locate(locator, file_path, code, offset),
2303            Self::Type(v) => v.locate(locator, file_path, code, offset),
2304            Self::Macro(v) => v.locate(locator, file_path, code, offset),
2305            Self::Verbatim(_) => Location {
2306                file_path,
2307                start: offset,
2308                end: offset,
2309            },
2310            _ => Location {
2311                file_path,
2312                start: offset,
2313                end: offset,
2314            },
2315        }
2316    }
2317}
2318
2319impl Locate for syn::ImplItemConst {
2320    fn find_loc(
2321        &self,
2322        locator: &mut LocatorGuard,
2323        file_path: &'static str,
2324        code: &str,
2325        offset: usize,
2326    ) -> Location {
2327        (
2328            &self.attrs,
2329            &self.vis,
2330            &self.defaultness,
2331            &self.const_token,
2332            &self.ident,
2333            &self.generics,
2334            &self.colon_token,
2335            &self.ty,
2336            &self.eq_token,
2337            &self.expr,
2338            &self.semi_token,
2339        )
2340            .locate_as_group(locator, file_path, code, offset)
2341    }
2342}
2343
2344impl Locate for syn::ImplItemFn {
2345    fn find_loc(
2346        &self,
2347        locator: &mut LocatorGuard,
2348        file_path: &'static str,
2349        code: &str,
2350        offset: usize,
2351    ) -> Location {
2352        (
2353            &self.attrs,
2354            &self.vis,
2355            &self.defaultness,
2356            &self.sig,
2357            &self.block,
2358        )
2359            .locate_as_group(locator, file_path, code, offset)
2360    }
2361}
2362
2363impl Locate for syn::ImplItemType {
2364    fn find_loc(
2365        &self,
2366        locator: &mut LocatorGuard,
2367        file_path: &'static str,
2368        code: &str,
2369        offset: usize,
2370    ) -> Location {
2371        (
2372            &self.attrs,
2373            &self.vis,
2374            &self.defaultness,
2375            &self.type_token,
2376            &self.ident,
2377            &self.generics,
2378            &self.eq_token,
2379            &self.ty,
2380            &self.semi_token,
2381        )
2382            .locate_as_group(locator, file_path, code, offset)
2383    }
2384}
2385
2386impl Locate for syn::ImplItemMacro {
2387    fn find_loc(
2388        &self,
2389        locator: &mut LocatorGuard,
2390        file_path: &'static str,
2391        code: &str,
2392        offset: usize,
2393    ) -> Location {
2394        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
2395    }
2396}
2397
2398impl Locate for syn::ImplRestriction {
2399    fn find_loc(
2400        &self,
2401        _: &mut LocatorGuard,
2402        file_path: &'static str,
2403        _code: &str,
2404        offset: usize,
2405    ) -> Location {
2406        Location {
2407            file_path,
2408            start: offset,
2409            end: offset,
2410        }
2411    }
2412}
2413
2414impl Locate for syn::Index {
2415    fn find_loc(
2416        &self,
2417        _: &mut LocatorGuard,
2418        file_path: &'static str,
2419        code: &str,
2420        offset: usize,
2421    ) -> Location {
2422        let value = self.index.to_string();
2423        helper::str_location(file_path, code, offset, &value)
2424    }
2425}
2426
2427impl Locate for syn::Item {
2428    fn find_loc(
2429        &self,
2430        locator: &mut LocatorGuard,
2431        file_path: &'static str,
2432        code: &str,
2433        offset: usize,
2434    ) -> Location {
2435        match self {
2436            Self::Const(v) => v.locate(locator, file_path, code, offset),
2437            Self::Enum(v) => v.locate(locator, file_path, code, offset),
2438            Self::ExternCrate(v) => v.locate(locator, file_path, code, offset),
2439            Self::Fn(v) => v.locate(locator, file_path, code, offset),
2440            Self::ForeignMod(v) => v.locate(locator, file_path, code, offset),
2441            Self::Impl(v) => v.locate(locator, file_path, code, offset),
2442            Self::Macro(v) => v.locate(locator, file_path, code, offset),
2443            Self::Mod(v) => v.locate(locator, file_path, code, offset),
2444            Self::Static(v) => v.locate(locator, file_path, code, offset),
2445            Self::Struct(v) => v.locate(locator, file_path, code, offset),
2446            Self::Trait(v) => v.locate(locator, file_path, code, offset),
2447            Self::TraitAlias(v) => v.locate(locator, file_path, code, offset),
2448            Self::Type(v) => v.locate(locator, file_path, code, offset),
2449            Self::Union(v) => v.locate(locator, file_path, code, offset),
2450            Self::Use(v) => v.locate(locator, file_path, code, offset),
2451            Self::Verbatim(_) => Location {
2452                file_path,
2453                start: offset,
2454                end: offset,
2455            },
2456            _ => Location {
2457                file_path,
2458                start: offset,
2459                end: offset,
2460            },
2461        }
2462    }
2463}
2464
2465impl Locate for syn::ItemConst {
2466    fn find_loc(
2467        &self,
2468        locator: &mut LocatorGuard,
2469        file_path: &'static str,
2470        code: &str,
2471        offset: usize,
2472    ) -> Location {
2473        (
2474            &self.attrs,
2475            &self.vis,
2476            &self.const_token,
2477            &self.ident,
2478            &self.generics,
2479            &self.colon_token,
2480            &self.ty,
2481            &self.eq_token,
2482            &self.expr,
2483            &self.semi_token,
2484        )
2485            .locate_as_group(locator, file_path, code, offset)
2486    }
2487}
2488
2489impl Locate for syn::ItemEnum {
2490    fn find_loc(
2491        &self,
2492        locator: &mut LocatorGuard,
2493        file_path: &'static str,
2494        code: &str,
2495        offset: usize,
2496    ) -> Location {
2497        Surround {
2498            front: (
2499                &self.attrs,
2500                &self.vis,
2501                &self.enum_token,
2502                &self.ident,
2503                &self.generics,
2504            ),
2505            surround: &self.brace_token,
2506            inner: &self.variants,
2507            back: (),
2508        }
2509        .locate(locator, file_path, code, offset)
2510    }
2511}
2512
2513impl Locate for syn::ItemExternCrate {
2514    fn find_loc(
2515        &self,
2516        locator: &mut LocatorGuard,
2517        file_path: &'static str,
2518        code: &str,
2519        offset: usize,
2520    ) -> Location {
2521        if let Some((as_token, rename)) = &self.rename {
2522            (
2523                &self.attrs,
2524                &self.vis,
2525                &self.extern_token,
2526                &self.crate_token,
2527                &self.ident,
2528                as_token,
2529                rename,
2530                &self.semi_token,
2531            )
2532                .locate_as_group(locator, file_path, code, offset)
2533        } else {
2534            (
2535                &self.attrs,
2536                &self.vis,
2537                &self.extern_token,
2538                &self.crate_token,
2539                &self.ident,
2540                &self.semi_token,
2541            )
2542                .locate_as_group(locator, file_path, code, offset)
2543        }
2544    }
2545}
2546
2547impl Locate for syn::ItemFn {
2548    fn find_loc(
2549        &self,
2550        locator: &mut LocatorGuard,
2551        file_path: &'static str,
2552        code: &str,
2553        offset: usize,
2554    ) -> Location {
2555        (&self.attrs, &self.vis, &self.sig, &self.block)
2556            .locate_as_group(locator, file_path, code, offset)
2557    }
2558}
2559
2560impl Locate for syn::ItemForeignMod {
2561    fn find_loc(
2562        &self,
2563        locator: &mut LocatorGuard,
2564        file_path: &'static str,
2565        code: &str,
2566        offset: usize,
2567    ) -> Location {
2568        Surround {
2569            front: (&self.attrs, &self.unsafety, &self.abi),
2570            surround: &self.brace_token,
2571            inner: &self.items,
2572            back: (),
2573        }
2574        .locate(locator, file_path, code, offset)
2575    }
2576}
2577
2578impl Locate for syn::ItemImpl {
2579    fn find_loc(
2580        &self,
2581        locator: &mut LocatorGuard,
2582        file_path: &'static str,
2583        code: &str,
2584        offset: usize,
2585    ) -> Location {
2586        let loc = if let Some((exc_token, path, for_token)) = &self.trait_ {
2587            Surround {
2588                front: (
2589                    &self.attrs,
2590                    &self.defaultness,
2591                    &self.unsafety,
2592                    &self.impl_token,
2593                    // `generics.where_clause` is behind the `self_ty`
2594                    &self.generics.lt_token,
2595                    &self.generics.params,
2596                    &self.generics.gt_token,
2597                    exc_token,
2598                    path,
2599                    for_token,
2600                    &self.self_ty,
2601                    &self.generics.where_clause,
2602                ),
2603                surround: &self.brace_token,
2604                inner: &self.items,
2605                back: (),
2606            }
2607            .locate(locator, file_path, code, offset)
2608        } else {
2609            Surround {
2610                front: (
2611                    &self.attrs,
2612                    &self.defaultness,
2613                    &self.unsafety,
2614                    &self.impl_token,
2615                    // `generics.where_clause` is behind the `self_ty`
2616                    &self.generics.lt_token,
2617                    &self.generics.params,
2618                    &self.generics.gt_token,
2619                    &self.self_ty,
2620                    &self.generics.where_clause,
2621                ),
2622                surround: &self.brace_token,
2623                inner: &self.items,
2624                back: (),
2625            }
2626            .locate(locator, file_path, code, offset)
2627        };
2628
2629        // Sets location of the `generics` manually. Because where clause is behind the `self_ty`,
2630        // the location will include the `self_ty`.
2631        let start = locator.get_location(&self.generics.lt_token).unwrap().start;
2632        let end = locator
2633            .get_location(&self.generics.where_clause)
2634            .unwrap()
2635            .end;
2636        locator.set_location(
2637            &self.generics,
2638            Location {
2639                file_path,
2640                start,
2641                end,
2642            },
2643        );
2644
2645        loc
2646    }
2647}
2648
2649// Parse order is not the same as the order they are declared.
2650// ref: https://github.com/dtolnay/syn/blob/5357c8fb6bd29fd7c829e0aede1dab4b45a6e00f/src/item.rs#L1240
2651impl Locate for syn::ItemMacro {
2652    fn find_loc(
2653        &self,
2654        locator: &mut LocatorGuard,
2655        file_path: &'static str,
2656        code: &str,
2657        offset: usize,
2658    ) -> Location {
2659        Surround {
2660            front: (
2661                &self.attrs,
2662                &self.mac.path,
2663                &self.mac.bang_token,
2664                &self.ident,
2665            ),
2666            surround: &self.mac.delimiter,
2667            inner: (), // tokens are not processed yet.
2668            back: &self.semi_token,
2669        }
2670        .locate(locator, file_path, code, offset)
2671    }
2672}
2673
2674impl Locate for syn::ItemMod {
2675    fn find_loc(
2676        &self,
2677        locator: &mut LocatorGuard,
2678        file_path: &'static str,
2679        code: &str,
2680        offset: usize,
2681    ) -> Location {
2682        match (&self.content, &self.semi) {
2683            (Some((brace, items)), Some(semi_token)) => Surround {
2684                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
2685                surround: brace,
2686                inner: items,
2687                back: semi_token,
2688            }
2689            .locate(locator, file_path, code, offset),
2690            (Some((brace, items)), None) => Surround {
2691                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
2692                surround: brace,
2693                inner: items,
2694                back: (),
2695            }
2696            .locate(locator, file_path, code, offset),
2697            (None, Some(semi_token)) => (
2698                &self.attrs,
2699                &self.vis,
2700                &self.mod_token,
2701                &self.ident,
2702                semi_token,
2703            )
2704                .locate_as_group(locator, file_path, code, offset),
2705            (None, None) => (&self.attrs, &self.vis, &self.mod_token, &self.ident)
2706                .locate_as_group(locator, file_path, code, offset),
2707        }
2708    }
2709}
2710
2711impl Locate for syn::ItemStatic {
2712    fn find_loc(
2713        &self,
2714        locator: &mut LocatorGuard,
2715        file_path: &'static str,
2716        code: &str,
2717        offset: usize,
2718    ) -> Location {
2719        (
2720            &self.attrs,
2721            &self.vis,
2722            &self.static_token,
2723            &self.mutability,
2724            &self.ident,
2725            &self.colon_token,
2726            &self.ty,
2727            &self.eq_token,
2728            &self.expr,
2729            &self.semi_token,
2730        )
2731            .locate_as_group(locator, file_path, code, offset)
2732    }
2733}
2734
2735impl Locate for syn::ItemStruct {
2736    fn find_loc(
2737        &self,
2738        locator: &mut LocatorGuard,
2739        file_path: &'static str,
2740        code: &str,
2741        offset: usize,
2742    ) -> Location {
2743        (
2744            &self.attrs,
2745            &self.vis,
2746            &self.struct_token,
2747            &self.ident,
2748            &self.generics,
2749            &self.fields,
2750            &self.semi_token,
2751        )
2752            .locate_as_group(locator, file_path, code, offset)
2753    }
2754}
2755
2756impl Locate for syn::ItemTrait {
2757    fn find_loc(
2758        &self,
2759        locator: &mut LocatorGuard,
2760        file_path: &'static str,
2761        code: &str,
2762        offset: usize,
2763    ) -> Location {
2764        Surround {
2765            front: (
2766                &self.attrs,
2767                &self.vis,
2768                &self.unsafety,
2769                &self.auto_token,
2770                &self.restriction,
2771                &self.trait_token,
2772                &self.ident,
2773                &self.generics,
2774                &self.colon_token,
2775                &self.supertraits,
2776            ),
2777            surround: &self.brace_token,
2778            inner: &self.items,
2779            back: (),
2780        }
2781        .locate(locator, file_path, code, offset)
2782    }
2783}
2784
2785impl Locate for syn::ItemTraitAlias {
2786    fn find_loc(
2787        &self,
2788        locator: &mut LocatorGuard,
2789        file_path: &'static str,
2790        code: &str,
2791        offset: usize,
2792    ) -> Location {
2793        (
2794            &self.attrs,
2795            &self.vis,
2796            &self.trait_token,
2797            &self.ident,
2798            &self.generics,
2799            &self.eq_token,
2800            &self.bounds,
2801            &self.semi_token,
2802        )
2803            .locate_as_group(locator, file_path, code, offset)
2804    }
2805}
2806
2807impl Locate for syn::ItemType {
2808    fn find_loc(
2809        &self,
2810        locator: &mut LocatorGuard,
2811        file_path: &'static str,
2812        code: &str,
2813        offset: usize,
2814    ) -> Location {
2815        (
2816            &self.attrs,
2817            &self.vis,
2818            &self.type_token,
2819            &self.ident,
2820            &self.generics,
2821            &self.eq_token,
2822            &self.ty,
2823            &self.semi_token,
2824        )
2825            .locate_as_group(locator, file_path, code, offset)
2826    }
2827}
2828
2829impl Locate for syn::ItemUnion {
2830    fn find_loc(
2831        &self,
2832        locator: &mut LocatorGuard,
2833        file_path: &'static str,
2834        code: &str,
2835        offset: usize,
2836    ) -> Location {
2837        (
2838            &self.attrs,
2839            &self.vis,
2840            &self.union_token,
2841            &self.ident,
2842            &self.generics,
2843            &self.fields,
2844        )
2845            .locate_as_group(locator, file_path, code, offset)
2846    }
2847}
2848
2849impl Locate for syn::ItemUse {
2850    fn find_loc(
2851        &self,
2852        locator: &mut LocatorGuard,
2853        file_path: &'static str,
2854        code: &str,
2855        offset: usize,
2856    ) -> Location {
2857        (
2858            &self.attrs,
2859            &self.vis,
2860            &self.use_token,
2861            &self.leading_colon,
2862            &self.tree,
2863            &self.semi_token,
2864        )
2865            .locate_as_group(locator, file_path, code, offset)
2866    }
2867}
2868
2869impl Locate for syn::Label {
2870    fn find_loc(
2871        &self,
2872        locator: &mut LocatorGuard,
2873        file_path: &'static str,
2874        code: &str,
2875        offset: usize,
2876    ) -> Location {
2877        (&self.name, &self.colon_token).locate_as_group(locator, file_path, code, offset)
2878    }
2879}
2880
2881impl Locate for syn::Lifetime {
2882    fn find_loc(
2883        &self,
2884        locator: &mut LocatorGuard,
2885        file_path: &'static str,
2886        code: &str,
2887        offset: usize,
2888    ) -> Location {
2889        let cur_code = &code[offset..];
2890
2891        let start = offset
2892            + cur_code
2893                .find('\'')
2894                .unwrap_or_else(|| panic!("expected ' from {cur_code}"));
2895        let end = self.ident.locate(locator, file_path, code, start + 1).end;
2896
2897        Location {
2898            file_path,
2899            start,
2900            end,
2901        }
2902    }
2903}
2904
2905impl Locate for syn::LifetimeParam {
2906    fn find_loc(
2907        &self,
2908        locator: &mut LocatorGuard,
2909        file_path: &'static str,
2910        code: &str,
2911        offset: usize,
2912    ) -> Location {
2913        (&self.attrs, &self.lifetime, &self.colon_token, &self.bounds)
2914            .locate_as_group(locator, file_path, code, offset)
2915    }
2916}
2917
2918impl Locate for syn::Lit {
2919    fn find_loc(
2920        &self,
2921        locator: &mut LocatorGuard,
2922        file_path: &'static str,
2923        code: &str,
2924        offset: usize,
2925    ) -> Location {
2926        match self {
2927            Self::Str(v) => v.locate(locator, file_path, code, offset),
2928            Self::ByteStr(v) => v.locate(locator, file_path, code, offset),
2929            Self::CStr(v) => v.locate(locator, file_path, code, offset),
2930            Self::Byte(v) => v.locate(locator, file_path, code, offset),
2931            Self::Char(v) => v.locate(locator, file_path, code, offset),
2932            Self::Int(v) => v.locate(locator, file_path, code, offset),
2933            Self::Float(v) => v.locate(locator, file_path, code, offset),
2934            Self::Bool(v) => v.locate(locator, file_path, code, offset),
2935            Self::Verbatim(_) => Location {
2936                file_path,
2937                start: offset,
2938                end: offset,
2939            },
2940            _ => Location {
2941                file_path,
2942                start: offset,
2943                end: offset,
2944            },
2945        }
2946    }
2947}
2948
2949impl Locate for syn::LitStr {
2950    fn find_loc(
2951        &self,
2952        _: &mut LocatorGuard,
2953        file_path: &'static str,
2954        code: &str,
2955        offset: usize,
2956    ) -> Location {
2957        let lit = self.token().to_string();
2958        helper::str_location(file_path, code, offset, &lit)
2959    }
2960}
2961
2962impl Locate for syn::LitByteStr {
2963    fn find_loc(
2964        &self,
2965        _: &mut LocatorGuard,
2966        file_path: &'static str,
2967        code: &str,
2968        offset: usize,
2969    ) -> Location {
2970        let lit = self.token().to_string();
2971        helper::str_location(file_path, code, offset, &lit)
2972    }
2973}
2974
2975impl Locate for syn::LitCStr {
2976    fn find_loc(
2977        &self,
2978        _: &mut LocatorGuard,
2979        file_path: &'static str,
2980        code: &str,
2981        offset: usize,
2982    ) -> Location {
2983        let lit = self.token().to_string();
2984        helper::str_location(file_path, code, offset, &lit)
2985    }
2986}
2987
2988impl Locate for syn::LitByte {
2989    fn find_loc(
2990        &self,
2991        _: &mut LocatorGuard,
2992        file_path: &'static str,
2993        code: &str,
2994        offset: usize,
2995    ) -> Location {
2996        let lit = self.token().to_string();
2997        helper::str_location(file_path, code, offset, &lit)
2998    }
2999}
3000
3001impl Locate for syn::LitChar {
3002    fn find_loc(
3003        &self,
3004        _: &mut LocatorGuard,
3005        file_path: &'static str,
3006        code: &str,
3007        offset: usize,
3008    ) -> Location {
3009        let lit = self.token().to_string();
3010        helper::str_location(file_path, code, offset, &lit)
3011    }
3012}
3013
3014impl Locate for syn::LitInt {
3015    fn find_loc(
3016        &self,
3017        _: &mut LocatorGuard,
3018        file_path: &'static str,
3019        code: &str,
3020        offset: usize,
3021    ) -> Location {
3022        let lit = self.token().to_string();
3023        helper::str_location(file_path, code, offset, &lit)
3024    }
3025}
3026
3027impl Locate for syn::LitFloat {
3028    fn find_loc(
3029        &self,
3030        _: &mut LocatorGuard,
3031        file_path: &'static str,
3032        code: &str,
3033        offset: usize,
3034    ) -> Location {
3035        let lit = self.token().to_string();
3036        helper::str_location(file_path, code, offset, &lit)
3037    }
3038}
3039
3040impl Locate for syn::LitBool {
3041    fn find_loc(
3042        &self,
3043        _: &mut LocatorGuard,
3044        file_path: &'static str,
3045        code: &str,
3046        offset: usize,
3047    ) -> Location {
3048        let lit = self.token().to_string();
3049        helper::str_location(file_path, code, offset, &lit)
3050    }
3051}
3052
3053impl Locate for syn::Local {
3054    fn find_loc(
3055        &self,
3056        locator: &mut LocatorGuard,
3057        file_path: &'static str,
3058        code: &str,
3059        offset: usize,
3060    ) -> Location {
3061        (
3062            &self.attrs,
3063            &self.let_token,
3064            &self.pat,
3065            &self.init,
3066            &self.semi_token,
3067        )
3068            .locate_as_group(locator, file_path, code, offset)
3069    }
3070}
3071
3072impl Locate for syn::LocalInit {
3073    fn find_loc(
3074        &self,
3075        locator: &mut LocatorGuard,
3076        file_path: &'static str,
3077        code: &str,
3078        offset: usize,
3079    ) -> Location {
3080        if let Some((else_token, diverge)) = &self.diverge {
3081            (&self.eq_token, &self.expr, else_token, diverge)
3082                .locate_as_group(locator, file_path, code, offset)
3083        } else {
3084            (&self.eq_token, &self.expr).locate_as_group(locator, file_path, code, offset)
3085        }
3086    }
3087}
3088
3089impl Locate for syn::Macro {
3090    fn find_loc(
3091        &self,
3092        locator: &mut LocatorGuard,
3093        file_path: &'static str,
3094        code: &str,
3095        offset: usize,
3096    ) -> Location {
3097        match &self.delimiter {
3098            syn::MacroDelimiter::Paren(paren) => Surround {
3099                front: (&self.path, &self.bang_token),
3100                surround: paren,
3101                inner: (),
3102                back: (),
3103            }
3104            .locate(locator, file_path, code, offset),
3105            syn::MacroDelimiter::Brace(brace) => Surround {
3106                front: (&self.path, &self.bang_token),
3107                surround: brace,
3108                inner: (),
3109                back: (),
3110            }
3111            .locate(locator, file_path, code, offset),
3112            syn::MacroDelimiter::Bracket(bracket) => Surround {
3113                front: (&self.path, &self.bang_token),
3114                surround: bracket,
3115                inner: (),
3116                back: (),
3117            }
3118            .locate(locator, file_path, code, offset),
3119        }
3120    }
3121}
3122
3123impl Locate for syn::MacroDelimiter {
3124    fn find_loc(
3125        &self,
3126        locator: &mut LocatorGuard,
3127        file_path: &'static str,
3128        code: &str,
3129        offset: usize,
3130    ) -> Location {
3131        match self {
3132            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3133            Self::Brace(v) => v.locate(locator, file_path, code, offset),
3134            Self::Bracket(v) => v.locate(locator, file_path, code, offset),
3135        }
3136    }
3137}
3138
3139impl Locate for syn::Member {
3140    fn find_loc(
3141        &self,
3142        locator: &mut LocatorGuard,
3143        file_path: &'static str,
3144        code: &str,
3145        offset: usize,
3146    ) -> Location {
3147        match self {
3148            Self::Named(v) => v.locate(locator, file_path, code, offset),
3149            Self::Unnamed(v) => v.locate(locator, file_path, code, offset),
3150        }
3151    }
3152}
3153
3154impl Locate for syn::Meta {
3155    fn find_loc(
3156        &self,
3157        locator: &mut LocatorGuard,
3158        file_path: &'static str,
3159        code: &str,
3160        offset: usize,
3161    ) -> Location {
3162        match self {
3163            Self::Path(v) => v.locate(locator, file_path, code, offset),
3164            Self::List(v) => v.locate(locator, file_path, code, offset),
3165            Self::NameValue(v) => v.locate(locator, file_path, code, offset),
3166        }
3167    }
3168}
3169
3170impl Locate for syn::MetaList {
3171    fn find_loc(
3172        &self,
3173        locator: &mut LocatorGuard,
3174        file_path: &'static str,
3175        code: &str,
3176        offset: usize,
3177    ) -> Location {
3178        match &self.delimiter {
3179            syn::MacroDelimiter::Paren(paren) => Surround {
3180                front: &self.path,
3181                surround: paren,
3182                inner: (),
3183                back: (),
3184            }
3185            .locate(locator, file_path, code, offset),
3186            syn::MacroDelimiter::Brace(brace) => Surround {
3187                front: &self.path,
3188                surround: brace,
3189                inner: (),
3190                back: (),
3191            }
3192            .locate(locator, file_path, code, offset),
3193            syn::MacroDelimiter::Bracket(bracket) => Surround {
3194                front: &self.path,
3195                surround: bracket,
3196                inner: (),
3197                back: (),
3198            }
3199            .locate(locator, file_path, code, offset),
3200        }
3201    }
3202}
3203
3204impl Locate for syn::MetaNameValue {
3205    fn find_loc(
3206        &self,
3207        locator: &mut LocatorGuard,
3208        file_path: &'static str,
3209        code: &str,
3210        offset: usize,
3211    ) -> Location {
3212        (&self.path, &self.eq_token, &self.value).locate_as_group(locator, file_path, code, offset)
3213    }
3214}
3215
3216impl Locate for syn::ParenthesizedGenericArguments {
3217    fn find_loc(
3218        &self,
3219        locator: &mut LocatorGuard,
3220        file_path: &'static str,
3221        code: &str,
3222        offset: usize,
3223    ) -> Location {
3224        Surround {
3225            front: (),
3226            surround: &self.paren_token,
3227            inner: &self.inputs,
3228            back: &self.output,
3229        }
3230        .locate(locator, file_path, code, offset)
3231    }
3232}
3233
3234impl Locate for syn::Pat {
3235    fn find_loc(
3236        &self,
3237        locator: &mut LocatorGuard,
3238        file_path: &'static str,
3239        code: &str,
3240        offset: usize,
3241    ) -> Location {
3242        match self {
3243            Self::Const(v) => v.locate(locator, file_path, code, offset),
3244            Self::Ident(v) => v.locate(locator, file_path, code, offset),
3245            Self::Lit(v) => v.locate(locator, file_path, code, offset),
3246            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3247            Self::Or(v) => v.locate(locator, file_path, code, offset),
3248            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3249            Self::Path(v) => v.locate(locator, file_path, code, offset),
3250            Self::Range(v) => v.locate(locator, file_path, code, offset),
3251            Self::Reference(v) => v.locate(locator, file_path, code, offset),
3252            Self::Rest(v) => v.locate(locator, file_path, code, offset),
3253            Self::Slice(v) => v.locate(locator, file_path, code, offset),
3254            Self::Struct(v) => v.locate(locator, file_path, code, offset),
3255            Self::Tuple(v) => v.locate(locator, file_path, code, offset),
3256            Self::TupleStruct(v) => v.locate(locator, file_path, code, offset),
3257            Self::Type(v) => v.locate(locator, file_path, code, offset),
3258            Self::Verbatim(_) => Location {
3259                file_path,
3260                start: offset,
3261                end: offset,
3262            },
3263            Self::Wild(v) => v.locate(locator, file_path, code, offset),
3264            _ => Location {
3265                file_path,
3266                start: offset,
3267                end: offset,
3268            },
3269        }
3270    }
3271}
3272
3273impl Locate for syn::PatIdent {
3274    fn find_loc(
3275        &self,
3276        locator: &mut LocatorGuard,
3277        file_path: &'static str,
3278        code: &str,
3279        offset: usize,
3280    ) -> Location {
3281        if let Some((at_token, subpat)) = &self.subpat {
3282            (
3283                &self.attrs,
3284                &self.by_ref,
3285                &self.mutability,
3286                &self.ident,
3287                at_token,
3288                subpat,
3289            )
3290                .locate_as_group(locator, file_path, code, offset)
3291        } else {
3292            (&self.attrs, &self.by_ref, &self.mutability, &self.ident)
3293                .locate_as_group(locator, file_path, code, offset)
3294        }
3295    }
3296}
3297
3298impl Locate for syn::PatOr {
3299    fn find_loc(
3300        &self,
3301        locator: &mut LocatorGuard,
3302        file_path: &'static str,
3303        code: &str,
3304        offset: usize,
3305    ) -> Location {
3306        (&self.attrs, &self.leading_vert, &self.cases)
3307            .locate_as_group(locator, file_path, code, offset)
3308    }
3309}
3310
3311impl Locate for syn::PatParen {
3312    fn find_loc(
3313        &self,
3314        locator: &mut LocatorGuard,
3315        file_path: &'static str,
3316        code: &str,
3317        offset: usize,
3318    ) -> Location {
3319        Surround {
3320            front: &self.attrs,
3321            surround: &self.paren_token,
3322            inner: &self.pat,
3323            back: (),
3324        }
3325        .locate(locator, file_path, code, offset)
3326    }
3327}
3328
3329impl Locate for syn::PatReference {
3330    fn find_loc(
3331        &self,
3332        locator: &mut LocatorGuard,
3333        file_path: &'static str,
3334        code: &str,
3335        offset: usize,
3336    ) -> Location {
3337        (&self.attrs, &self.and_token, &self.mutability, &self.pat)
3338            .locate_as_group(locator, file_path, code, offset)
3339    }
3340}
3341
3342impl Locate for syn::PatRest {
3343    fn find_loc(
3344        &self,
3345        locator: &mut LocatorGuard,
3346        file_path: &'static str,
3347        code: &str,
3348        offset: usize,
3349    ) -> Location {
3350        (&self.attrs, &self.dot2_token).locate_as_group(locator, file_path, code, offset)
3351    }
3352}
3353
3354impl Locate for syn::PatSlice {
3355    fn find_loc(
3356        &self,
3357        locator: &mut LocatorGuard,
3358        file_path: &'static str,
3359        code: &str,
3360        offset: usize,
3361    ) -> Location {
3362        Surround {
3363            front: &self.attrs,
3364            surround: &self.bracket_token,
3365            inner: &self.elems,
3366            back: (),
3367        }
3368        .locate(locator, file_path, code, offset)
3369    }
3370}
3371
3372impl Locate for syn::PatStruct {
3373    fn find_loc(
3374        &self,
3375        locator: &mut LocatorGuard,
3376        file_path: &'static str,
3377        code: &str,
3378        offset: usize,
3379    ) -> Location {
3380        let front_loc = if let Some(qself) = &self.qself {
3381            Qualified {
3382                front: &self.attrs,
3383                qself,
3384                path: &self.path,
3385                back: (),
3386            }
3387            .locate(locator, file_path, code, offset)
3388        } else {
3389            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
3390        };
3391
3392        let back_loc = Surround {
3393            front: (),
3394            surround: &self.brace_token,
3395            inner: (&self.fields, &self.rest),
3396            back: (),
3397        }
3398        .locate(locator, file_path, code, front_loc.end);
3399
3400        Location {
3401            file_path,
3402            start: front_loc.start,
3403            end: back_loc.end,
3404        }
3405    }
3406}
3407
3408impl Locate for syn::PatTuple {
3409    fn find_loc(
3410        &self,
3411        locator: &mut LocatorGuard,
3412        file_path: &'static str,
3413        code: &str,
3414        offset: usize,
3415    ) -> Location {
3416        Surround {
3417            front: &self.attrs,
3418            surround: &self.paren_token,
3419            inner: &self.elems,
3420            back: (),
3421        }
3422        .locate(locator, file_path, code, offset)
3423    }
3424}
3425
3426impl Locate for syn::PatTupleStruct {
3427    fn find_loc(
3428        &self,
3429        locator: &mut LocatorGuard,
3430        file_path: &'static str,
3431        code: &str,
3432        offset: usize,
3433    ) -> Location {
3434        let front_loc = if let Some(qself) = &self.qself {
3435            Qualified {
3436                front: &self.attrs,
3437                qself,
3438                path: &self.path,
3439                back: (),
3440            }
3441            .locate(locator, file_path, code, offset)
3442        } else {
3443            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
3444        };
3445
3446        let back_loc = Surround {
3447            front: (),
3448            surround: &self.paren_token,
3449            inner: &self.elems,
3450            back: (),
3451        }
3452        .locate(locator, file_path, code, front_loc.end);
3453
3454        Location {
3455            file_path,
3456            start: front_loc.start,
3457            end: back_loc.end,
3458        }
3459    }
3460}
3461
3462impl Locate for syn::PatType {
3463    fn find_loc(
3464        &self,
3465        locator: &mut LocatorGuard,
3466        file_path: &'static str,
3467        code: &str,
3468        offset: usize,
3469    ) -> Location {
3470        (&self.attrs, &self.pat, &self.colon_token, &self.ty)
3471            .locate_as_group(locator, file_path, code, offset)
3472    }
3473}
3474
3475impl Locate for syn::PatWild {
3476    fn find_loc(
3477        &self,
3478        locator: &mut LocatorGuard,
3479        file_path: &'static str,
3480        code: &str,
3481        offset: usize,
3482    ) -> Location {
3483        (&self.attrs, &self.underscore_token).locate_as_group(locator, file_path, code, offset)
3484    }
3485}
3486
3487impl Locate for syn::Path {
3488    fn find_loc(
3489        &self,
3490        locator: &mut LocatorGuard,
3491        file_path: &'static str,
3492        code: &str,
3493        offset: usize,
3494    ) -> Location {
3495        (&self.leading_colon, &self.segments).locate_as_group(locator, file_path, code, offset)
3496    }
3497}
3498
3499impl Locate for syn::PathArguments {
3500    fn find_loc(
3501        &self,
3502        locator: &mut LocatorGuard,
3503        file_path: &'static str,
3504        code: &str,
3505        offset: usize,
3506    ) -> Location {
3507        match self {
3508            Self::None => Location {
3509                file_path,
3510                start: offset,
3511                end: offset,
3512            },
3513            Self::AngleBracketed(v) => v.locate(locator, file_path, code, offset),
3514            Self::Parenthesized(v) => v.locate(locator, file_path, code, offset),
3515        }
3516    }
3517}
3518
3519impl Locate for syn::PathSegment {
3520    fn find_loc(
3521        &self,
3522        locator: &mut LocatorGuard,
3523        file_path: &'static str,
3524        code: &str,
3525        offset: usize,
3526    ) -> Location {
3527        (&self.ident, &self.arguments).locate_as_group(locator, file_path, code, offset)
3528    }
3529}
3530
3531impl Locate for syn::PointerMutability {
3532    fn find_loc(
3533        &self,
3534        locator: &mut LocatorGuard,
3535        file_path: &'static str,
3536        code: &str,
3537        offset: usize,
3538    ) -> Location {
3539        match self {
3540            Self::Const(v) => v.locate(locator, file_path, code, offset),
3541            Self::Mut(v) => v.locate(locator, file_path, code, offset),
3542        }
3543    }
3544}
3545
3546impl Locate for syn::PreciseCapture {
3547    fn find_loc(
3548        &self,
3549        locator: &mut LocatorGuard,
3550        file_path: &'static str,
3551        code: &str,
3552        offset: usize,
3553    ) -> Location {
3554        (
3555            &self.use_token,
3556            &self.lt_token,
3557            &self.params,
3558            &self.gt_token,
3559        )
3560            .locate_as_group(locator, file_path, code, offset)
3561    }
3562}
3563
3564impl Locate for syn::PredicateLifetime {
3565    fn find_loc(
3566        &self,
3567        locator: &mut LocatorGuard,
3568        file_path: &'static str,
3569        code: &str,
3570        offset: usize,
3571    ) -> Location {
3572        (&self.lifetime, &self.colon_token, &self.bounds)
3573            .locate_as_group(locator, file_path, code, offset)
3574    }
3575}
3576
3577impl Locate for syn::PredicateType {
3578    fn find_loc(
3579        &self,
3580        locator: &mut LocatorGuard,
3581        file_path: &'static str,
3582        code: &str,
3583        offset: usize,
3584    ) -> Location {
3585        (
3586            &self.lifetimes,
3587            &self.bounded_ty,
3588            &self.colon_token,
3589            &self.bounds,
3590        )
3591            .locate_as_group(locator, file_path, code, offset)
3592    }
3593}
3594
3595impl Locate for syn::QSelf {
3596    fn find_loc(
3597        &self,
3598        locator: &mut LocatorGuard,
3599        file_path: &'static str,
3600        code: &str,
3601        offset: usize,
3602    ) -> Location {
3603        let front_loc = (&self.lt_token, &self.ty, &self.as_token)
3604            .locate_as_group(locator, file_path, code, offset);
3605
3606        const OPEN: char = '<';
3607        const CLOSE: char = '>';
3608
3609        let cur_code = &code[front_loc.end..];
3610
3611        let mut cur = front_loc.end;
3612        let mut level = 1;
3613
3614        for c in cur_code.chars() {
3615            if c == OPEN {
3616                level += 1;
3617            } else if c == CLOSE {
3618                if level == 1 {
3619                    break;
3620                }
3621                level -= 1;
3622            }
3623            cur += c.len_utf8();
3624        }
3625
3626        let end = self.gt_token.locate(locator, file_path, code, cur).end;
3627
3628        Location {
3629            file_path,
3630            start: front_loc.start,
3631            end,
3632        }
3633    }
3634}
3635
3636impl Locate for syn::RangeLimits {
3637    fn find_loc(
3638        &self,
3639        locator: &mut LocatorGuard,
3640        file_path: &'static str,
3641        code: &str,
3642        offset: usize,
3643    ) -> Location {
3644        match self {
3645            Self::HalfOpen(v) => v.locate(locator, file_path, code, offset),
3646            Self::Closed(v) => v.locate(locator, file_path, code, offset),
3647        }
3648    }
3649}
3650
3651impl Locate for syn::Receiver {
3652    fn find_loc(
3653        &self,
3654        locator: &mut LocatorGuard,
3655        file_path: &'static str,
3656        code: &str,
3657        offset: usize,
3658    ) -> Location {
3659        // If there is no colon, `self.ty` must be ignored because it is not
3660        // constructed from source code.
3661
3662        if let Some((and_token, reference)) = &self.reference {
3663            if let Some(colon_token) = &self.colon_token {
3664                (
3665                    &self.attrs,
3666                    and_token,
3667                    reference,
3668                    &self.mutability,
3669                    &self.self_token,
3670                    colon_token,
3671                    &self.ty,
3672                )
3673                    .locate_as_group(locator, file_path, code, offset)
3674            } else {
3675                (
3676                    &self.attrs,
3677                    and_token,
3678                    reference,
3679                    &self.mutability,
3680                    &self.self_token,
3681                )
3682                    .locate_as_group(locator, file_path, code, offset)
3683            }
3684        } else if let Some(colon_token) = &self.colon_token {
3685            (
3686                &self.attrs,
3687                &self.mutability,
3688                &self.self_token,
3689                colon_token,
3690                &self.ty,
3691            )
3692                .locate_as_group(locator, file_path, code, offset)
3693        } else {
3694            (&self.attrs, &self.mutability, &self.self_token)
3695                .locate_as_group(locator, file_path, code, offset)
3696        }
3697    }
3698}
3699
3700impl Locate for syn::ReturnType {
3701    fn find_loc(
3702        &self,
3703        locator: &mut LocatorGuard,
3704        file_path: &'static str,
3705        code: &str,
3706        offset: usize,
3707    ) -> Location {
3708        match self {
3709            Self::Default => Location {
3710                file_path,
3711                start: offset,
3712                end: offset,
3713            },
3714            Self::Type(arrow_token, ty) => {
3715                (arrow_token, ty).locate_as_group(locator, file_path, code, offset)
3716            }
3717        }
3718    }
3719}
3720
3721impl Locate for syn::Signature {
3722    fn find_loc(
3723        &self,
3724        locator: &mut LocatorGuard,
3725        file_path: &'static str,
3726        code: &str,
3727        offset: usize,
3728    ) -> Location {
3729        let loc = Surround {
3730            front: (
3731                &self.constness,
3732                &self.asyncness,
3733                &self.unsafety,
3734                &self.abi,
3735                &self.fn_token,
3736                &self.ident,
3737                // `generics.where_clause` is behind the `output`
3738                &self.generics.lt_token,
3739                &self.generics.params,
3740                &self.generics.gt_token,
3741            ),
3742            surround: &self.paren_token,
3743            inner: (&self.inputs, &self.variadic),
3744            back: (&self.output, &self.generics.where_clause),
3745        }
3746        .locate(locator, file_path, code, offset);
3747
3748        // Sets location of the `generics` manually. Because where clause is behind the `output`,
3749        // the location will include the `output`.
3750        let start = locator.get_location(&self.generics.lt_token).unwrap().start;
3751        let end = locator
3752            .get_location(&self.generics.where_clause)
3753            .unwrap()
3754            .end;
3755        locator.set_location(
3756            &self.generics,
3757            Location {
3758                file_path,
3759                start,
3760                end,
3761            },
3762        );
3763
3764        loc
3765    }
3766}
3767
3768impl Locate for syn::StaticMutability {
3769    fn find_loc(
3770        &self,
3771        locator: &mut LocatorGuard,
3772        file_path: &'static str,
3773        code: &str,
3774        offset: usize,
3775    ) -> Location {
3776        match self {
3777            Self::Mut(v) => v.locate(locator, file_path, code, offset),
3778            Self::None => Location {
3779                file_path,
3780                start: offset,
3781                end: offset,
3782            },
3783            _ => Location {
3784                file_path,
3785                start: offset,
3786                end: offset,
3787            },
3788        }
3789    }
3790}
3791
3792impl Locate for syn::Stmt {
3793    fn find_loc(
3794        &self,
3795        locator: &mut LocatorGuard,
3796        file_path: &'static str,
3797        code: &str,
3798        offset: usize,
3799    ) -> Location {
3800        match self {
3801            Self::Local(v) => v.locate(locator, file_path, code, offset),
3802            Self::Item(v) => v.locate(locator, file_path, code, offset),
3803            Self::Expr(expr, semi_token) => {
3804                (expr, semi_token).locate_as_group(locator, file_path, code, offset)
3805            }
3806            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3807        }
3808    }
3809}
3810
3811impl Locate for syn::StmtMacro {
3812    fn find_loc(
3813        &self,
3814        locator: &mut LocatorGuard,
3815        file_path: &'static str,
3816        code: &str,
3817        offset: usize,
3818    ) -> Location {
3819        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
3820    }
3821}
3822
3823impl Locate for syn::TraitBound {
3824    fn find_loc(
3825        &self,
3826        locator: &mut LocatorGuard,
3827        file_path: &'static str,
3828        code: &str,
3829        offset: usize,
3830    ) -> Location {
3831        // self.paren_token is always Null according to syn parsing.
3832        (&self.modifier, &self.lifetimes, &self.path)
3833            .locate_as_group(locator, file_path, code, offset)
3834    }
3835}
3836
3837impl Locate for syn::TraitBoundModifier {
3838    fn find_loc(
3839        &self,
3840        locator: &mut LocatorGuard,
3841        file_path: &'static str,
3842        code: &str,
3843        offset: usize,
3844    ) -> Location {
3845        match self {
3846            Self::None => Location {
3847                file_path,
3848                start: offset,
3849                end: offset,
3850            },
3851            Self::Maybe(v) => v.locate(locator, file_path, code, offset),
3852        }
3853    }
3854}
3855
3856impl Locate for syn::TraitItem {
3857    fn find_loc(
3858        &self,
3859        locator: &mut LocatorGuard,
3860        file_path: &'static str,
3861        code: &str,
3862        offset: usize,
3863    ) -> Location {
3864        match self {
3865            Self::Const(v) => v.locate(locator, file_path, code, offset),
3866            Self::Fn(v) => v.locate(locator, file_path, code, offset),
3867            Self::Type(v) => v.locate(locator, file_path, code, offset),
3868            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3869            Self::Verbatim(_) => Location {
3870                file_path,
3871                start: offset,
3872                end: offset,
3873            },
3874            _ => Location {
3875                file_path,
3876                start: offset,
3877                end: offset,
3878            },
3879        }
3880    }
3881}
3882
3883impl Locate for syn::TraitItemConst {
3884    fn find_loc(
3885        &self,
3886        locator: &mut LocatorGuard,
3887        file_path: &'static str,
3888        code: &str,
3889        offset: usize,
3890    ) -> Location {
3891        if let Some((eq_token, default)) = &self.default {
3892            (
3893                &self.attrs,
3894                &self.const_token,
3895                &self.ident,
3896                &self.generics,
3897                &self.colon_token,
3898                &self.ty,
3899                eq_token,
3900                default,
3901                &self.semi_token,
3902            )
3903                .locate_as_group(locator, file_path, code, offset)
3904        } else {
3905            (
3906                &self.attrs,
3907                &self.const_token,
3908                &self.ident,
3909                &self.generics,
3910                &self.colon_token,
3911                &self.ty,
3912                &self.semi_token,
3913            )
3914                .locate_as_group(locator, file_path, code, offset)
3915        }
3916    }
3917}
3918
3919impl Locate for syn::TraitItemFn {
3920    fn find_loc(
3921        &self,
3922        locator: &mut LocatorGuard,
3923        file_path: &'static str,
3924        code: &str,
3925        offset: usize,
3926    ) -> Location {
3927        (&self.attrs, &self.sig, &self.default, &self.semi_token)
3928            .locate_as_group(locator, file_path, code, offset)
3929    }
3930}
3931
3932impl Locate for syn::TraitItemType {
3933    fn find_loc(
3934        &self,
3935        locator: &mut LocatorGuard,
3936        file_path: &'static str,
3937        code: &str,
3938        offset: usize,
3939    ) -> Location {
3940        if let Some((eq_token, default)) = &self.default {
3941            (
3942                &self.attrs,
3943                &self.type_token,
3944                &self.ident,
3945                &self.generics,
3946                &self.colon_token,
3947                &self.bounds,
3948                eq_token,
3949                default,
3950                &self.semi_token,
3951            )
3952                .locate_as_group(locator, file_path, code, offset)
3953        } else {
3954            (
3955                &self.attrs,
3956                &self.type_token,
3957                &self.ident,
3958                &self.generics,
3959                &self.colon_token,
3960                &self.bounds,
3961                &self.semi_token,
3962            )
3963                .locate_as_group(locator, file_path, code, offset)
3964        }
3965    }
3966}
3967
3968impl Locate for syn::TraitItemMacro {
3969    fn find_loc(
3970        &self,
3971        locator: &mut LocatorGuard,
3972        file_path: &'static str,
3973        code: &str,
3974        offset: usize,
3975    ) -> Location {
3976        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
3977    }
3978}
3979
3980impl Locate for syn::Type {
3981    fn find_loc(
3982        &self,
3983        locator: &mut LocatorGuard,
3984        file_path: &'static str,
3985        code: &str,
3986        offset: usize,
3987    ) -> Location {
3988        match self {
3989            Self::Array(v) => v.locate(locator, file_path, code, offset),
3990            Self::BareFn(v) => v.locate(locator, file_path, code, offset),
3991            Self::Group(v) => v.locate(locator, file_path, code, offset),
3992            Self::ImplTrait(v) => v.locate(locator, file_path, code, offset),
3993            Self::Infer(v) => v.locate(locator, file_path, code, offset),
3994            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3995            Self::Never(v) => v.locate(locator, file_path, code, offset),
3996            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3997            Self::Path(v) => v.locate(locator, file_path, code, offset),
3998            Self::Ptr(v) => v.locate(locator, file_path, code, offset),
3999            Self::Reference(v) => v.locate(locator, file_path, code, offset),
4000            Self::Slice(v) => v.locate(locator, file_path, code, offset),
4001            Self::TraitObject(v) => v.locate(locator, file_path, code, offset),
4002            Self::Tuple(v) => v.locate(locator, file_path, code, offset),
4003            Self::Verbatim(_) => Location {
4004                file_path,
4005                start: offset,
4006                end: offset,
4007            },
4008            _ => Location {
4009                file_path,
4010                start: offset,
4011                end: offset,
4012            },
4013        }
4014    }
4015}
4016
4017impl Locate for syn::TypeArray {
4018    fn find_loc(
4019        &self,
4020        locator: &mut LocatorGuard,
4021        file_path: &'static str,
4022        code: &str,
4023        offset: usize,
4024    ) -> Location {
4025        Surround {
4026            front: (),
4027            surround: &self.bracket_token,
4028            inner: (&self.elem, &self.semi_token, &self.len),
4029            back: (),
4030        }
4031        .locate(locator, file_path, code, offset)
4032    }
4033}
4034
4035impl Locate for syn::TypeBareFn {
4036    fn find_loc(
4037        &self,
4038        locator: &mut LocatorGuard,
4039        file_path: &'static str,
4040        code: &str,
4041        offset: usize,
4042    ) -> Location {
4043        Surround {
4044            front: (&self.lifetimes, &self.unsafety, &self.abi, &self.fn_token),
4045            surround: &self.paren_token,
4046            inner: (&self.inputs, &self.variadic),
4047            back: &self.output,
4048        }
4049        .locate(locator, file_path, code, offset)
4050    }
4051}
4052
4053impl Locate for syn::TypeGroup {
4054    fn find_loc(
4055        &self,
4056        locator: &mut LocatorGuard,
4057        file_path: &'static str,
4058        code: &str,
4059        offset: usize,
4060    ) -> Location {
4061        (&self.group_token, &self.elem).locate_as_group(locator, file_path, code, offset)
4062    }
4063}
4064
4065impl Locate for syn::TypeImplTrait {
4066    fn find_loc(
4067        &self,
4068        locator: &mut LocatorGuard,
4069        file_path: &'static str,
4070        code: &str,
4071        offset: usize,
4072    ) -> Location {
4073        (&self.impl_token, &self.bounds).locate_as_group(locator, file_path, code, offset)
4074    }
4075}
4076
4077impl Locate for syn::TypeInfer {
4078    fn find_loc(
4079        &self,
4080        locator: &mut LocatorGuard,
4081        file_path: &'static str,
4082        code: &str,
4083        offset: usize,
4084    ) -> Location {
4085        self.underscore_token
4086            .locate(locator, file_path, code, offset)
4087    }
4088}
4089
4090impl Locate for syn::TypeMacro {
4091    fn find_loc(
4092        &self,
4093        locator: &mut LocatorGuard,
4094        file_path: &'static str,
4095        code: &str,
4096        offset: usize,
4097    ) -> Location {
4098        self.mac.locate(locator, file_path, code, offset)
4099    }
4100}
4101
4102impl Locate for syn::TypeNever {
4103    fn find_loc(
4104        &self,
4105        locator: &mut LocatorGuard,
4106        file_path: &'static str,
4107        code: &str,
4108        offset: usize,
4109    ) -> Location {
4110        self.bang_token.locate(locator, file_path, code, offset)
4111    }
4112}
4113
4114impl Locate for syn::TypeParen {
4115    fn find_loc(
4116        &self,
4117        locator: &mut LocatorGuard,
4118        file_path: &'static str,
4119        code: &str,
4120        offset: usize,
4121    ) -> Location {
4122        Surround {
4123            front: (),
4124            surround: &self.paren_token,
4125            inner: &self.elem,
4126            back: (),
4127        }
4128        .locate(locator, file_path, code, offset)
4129    }
4130}
4131
4132impl Locate for syn::TypePath {
4133    fn find_loc(
4134        &self,
4135        locator: &mut LocatorGuard,
4136        file_path: &'static str,
4137        code: &str,
4138        offset: usize,
4139    ) -> Location {
4140        if let Some(qself) = &self.qself {
4141            Qualified {
4142                front: (),
4143                qself,
4144                path: &self.path,
4145                back: (),
4146            }
4147            .locate(locator, file_path, code, offset)
4148        } else {
4149            self.path.locate(locator, file_path, code, offset)
4150        }
4151    }
4152}
4153
4154impl Locate for syn::TypePtr {
4155    fn find_loc(
4156        &self,
4157        locator: &mut LocatorGuard,
4158        file_path: &'static str,
4159        code: &str,
4160        offset: usize,
4161    ) -> Location {
4162        (
4163            &self.star_token,
4164            &self.const_token,
4165            &self.mutability,
4166            &self.elem,
4167        )
4168            .locate_as_group(locator, file_path, code, offset)
4169    }
4170}
4171
4172impl Locate for syn::TypeReference {
4173    fn find_loc(
4174        &self,
4175        locator: &mut LocatorGuard,
4176        file_path: &'static str,
4177        code: &str,
4178        offset: usize,
4179    ) -> Location {
4180        (
4181            &self.and_token,
4182            &self.lifetime,
4183            &self.mutability,
4184            &self.elem,
4185        )
4186            .locate_as_group(locator, file_path, code, offset)
4187    }
4188}
4189
4190impl Locate for syn::TypeSlice {
4191    fn find_loc(
4192        &self,
4193        locator: &mut LocatorGuard,
4194        file_path: &'static str,
4195        code: &str,
4196        offset: usize,
4197    ) -> Location {
4198        Surround {
4199            front: (),
4200            surround: &self.bracket_token,
4201            inner: &self.elem,
4202            back: (),
4203        }
4204        .locate(locator, file_path, code, offset)
4205    }
4206}
4207
4208impl Locate for syn::TypeTraitObject {
4209    fn find_loc(
4210        &self,
4211        locator: &mut LocatorGuard,
4212        file_path: &'static str,
4213        code: &str,
4214        offset: usize,
4215    ) -> Location {
4216        (&self.dyn_token, &self.bounds).locate_as_group(locator, file_path, code, offset)
4217    }
4218}
4219
4220impl Locate for syn::TypeTuple {
4221    fn find_loc(
4222        &self,
4223        locator: &mut LocatorGuard,
4224        file_path: &'static str,
4225        code: &str,
4226        offset: usize,
4227    ) -> Location {
4228        Surround {
4229            front: (),
4230            surround: &self.paren_token,
4231            inner: &self.elems,
4232            back: (),
4233        }
4234        .locate(locator, file_path, code, offset)
4235    }
4236}
4237
4238impl Locate for syn::TypeParam {
4239    fn find_loc(
4240        &self,
4241        locator: &mut LocatorGuard,
4242        file_path: &'static str,
4243        code: &str,
4244        offset: usize,
4245    ) -> Location {
4246        (
4247            &self.attrs,
4248            &self.ident,
4249            &self.colon_token,
4250            &self.bounds,
4251            &self.eq_token,
4252            &self.default,
4253        )
4254            .locate_as_group(locator, file_path, code, offset)
4255    }
4256}
4257
4258impl Locate for syn::TypeParamBound {
4259    fn find_loc(
4260        &self,
4261        locator: &mut LocatorGuard,
4262        file_path: &'static str,
4263        code: &str,
4264        offset: usize,
4265    ) -> Location {
4266        match self {
4267            Self::Trait(v) => v.locate(locator, file_path, code, offset),
4268            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
4269            Self::PreciseCapture(v) => v.locate(locator, file_path, code, offset),
4270            Self::Verbatim(_) => Location {
4271                file_path,
4272                start: offset,
4273                end: offset,
4274            },
4275            _ => Location {
4276                file_path,
4277                start: offset,
4278                end: offset,
4279            },
4280        }
4281    }
4282}
4283
4284impl Locate for syn::UnOp {
4285    fn find_loc(
4286        &self,
4287        locator: &mut LocatorGuard,
4288        file_path: &'static str,
4289        code: &str,
4290        offset: usize,
4291    ) -> Location {
4292        match self {
4293            Self::Deref(v) => v.locate(locator, file_path, code, offset),
4294            Self::Not(v) => v.locate(locator, file_path, code, offset),
4295            Self::Neg(v) => v.locate(locator, file_path, code, offset),
4296            _ => Location {
4297                file_path,
4298                start: offset,
4299                end: offset,
4300            },
4301        }
4302    }
4303}
4304
4305impl Locate for syn::UseGlob {
4306    fn find_loc(
4307        &self,
4308        locator: &mut LocatorGuard,
4309        file_path: &'static str,
4310        code: &str,
4311        offset: usize,
4312    ) -> Location {
4313        self.star_token.locate(locator, file_path, code, offset)
4314    }
4315}
4316
4317impl Locate for syn::UseGroup {
4318    fn find_loc(
4319        &self,
4320        locator: &mut LocatorGuard,
4321        file_path: &'static str,
4322        code: &str,
4323        offset: usize,
4324    ) -> Location {
4325        Surround {
4326            front: (),
4327            surround: &self.brace_token,
4328            inner: &self.items,
4329            back: (),
4330        }
4331        .locate(locator, file_path, code, offset)
4332    }
4333}
4334
4335impl Locate for syn::UseName {
4336    fn find_loc(
4337        &self,
4338        locator: &mut LocatorGuard,
4339        file_path: &'static str,
4340        code: &str,
4341        offset: usize,
4342    ) -> Location {
4343        self.ident.locate(locator, file_path, code, offset)
4344    }
4345}
4346
4347impl Locate for syn::UsePath {
4348    fn find_loc(
4349        &self,
4350        locator: &mut LocatorGuard,
4351        file_path: &'static str,
4352        code: &str,
4353        offset: usize,
4354    ) -> Location {
4355        (&self.ident, &self.colon2_token, &self.tree)
4356            .locate_as_group(locator, file_path, code, offset)
4357    }
4358}
4359
4360impl Locate for syn::UseRename {
4361    fn find_loc(
4362        &self,
4363        locator: &mut LocatorGuard,
4364        file_path: &'static str,
4365        code: &str,
4366        offset: usize,
4367    ) -> Location {
4368        (&self.ident, &self.as_token, &self.rename)
4369            .locate_as_group(locator, file_path, code, offset)
4370    }
4371}
4372
4373impl Locate for syn::UseTree {
4374    fn find_loc(
4375        &self,
4376        locator: &mut LocatorGuard,
4377        file_path: &'static str,
4378        code: &str,
4379        offset: usize,
4380    ) -> Location {
4381        match self {
4382            Self::Path(v) => v.locate(locator, file_path, code, offset),
4383            Self::Name(v) => v.locate(locator, file_path, code, offset),
4384            Self::Rename(v) => v.locate(locator, file_path, code, offset),
4385            Self::Glob(v) => v.locate(locator, file_path, code, offset),
4386            Self::Group(v) => v.locate(locator, file_path, code, offset),
4387        }
4388    }
4389}
4390
4391impl Locate for syn::Variadic {
4392    fn find_loc(
4393        &self,
4394        locator: &mut LocatorGuard,
4395        file_path: &'static str,
4396        code: &str,
4397        offset: usize,
4398    ) -> Location {
4399        if let Some((pat, colon_token)) = &self.pat {
4400            (&self.attrs, pat, colon_token, &self.dots, &self.comma)
4401                .locate_as_group(locator, file_path, code, offset)
4402        } else {
4403            (&self.attrs, &self.dots, &self.comma).locate_as_group(locator, file_path, code, offset)
4404        }
4405    }
4406}
4407
4408impl Locate for syn::Variant {
4409    fn find_loc(
4410        &self,
4411        locator: &mut LocatorGuard,
4412        file_path: &'static str,
4413        code: &str,
4414        offset: usize,
4415    ) -> Location {
4416        if let Some((eq_token, discriminant)) = &self.discriminant {
4417            (
4418                &self.attrs,
4419                &self.ident,
4420                &self.fields,
4421                eq_token,
4422                discriminant,
4423            )
4424                .locate_as_group(locator, file_path, code, offset)
4425        } else {
4426            (&self.attrs, &self.ident, &self.fields)
4427                .locate_as_group(locator, file_path, code, offset)
4428        }
4429    }
4430}
4431
4432impl Locate for syn::Visibility {
4433    fn find_loc(
4434        &self,
4435        locator: &mut LocatorGuard,
4436        file_path: &'static str,
4437        code: &str,
4438        offset: usize,
4439    ) -> Location {
4440        match self {
4441            Self::Public(v) => v.locate(locator, file_path, code, offset),
4442            Self::Restricted(v) => v.locate(locator, file_path, code, offset),
4443            Self::Inherited => Location {
4444                file_path,
4445                start: offset,
4446                end: offset,
4447            },
4448        }
4449    }
4450}
4451
4452impl Locate for syn::VisRestricted {
4453    fn find_loc(
4454        &self,
4455        locator: &mut LocatorGuard,
4456        file_path: &'static str,
4457        code: &str,
4458        offset: usize,
4459    ) -> Location {
4460        Surround {
4461            front: &self.pub_token,
4462            surround: &self.paren_token,
4463            inner: (&self.in_token, &self.path),
4464            back: (),
4465        }
4466        .locate(locator, file_path, code, offset)
4467    }
4468}
4469
4470impl Locate for syn::WhereClause {
4471    fn find_loc(
4472        &self,
4473        locator: &mut LocatorGuard,
4474        file_path: &'static str,
4475        code: &str,
4476        offset: usize,
4477    ) -> Location {
4478        (&self.where_token, &self.predicates).locate_as_group(locator, file_path, code, offset)
4479    }
4480}
4481
4482impl Locate for syn::WherePredicate {
4483    fn find_loc(
4484        &self,
4485        locator: &mut LocatorGuard,
4486        file_path: &'static str,
4487        code: &str,
4488        offset: usize,
4489    ) -> Location {
4490        match self {
4491            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
4492            Self::Type(v) => v.locate(locator, file_path, code, offset),
4493            _ => Location {
4494                file_path,
4495                start: offset,
4496                end: offset,
4497            },
4498        }
4499    }
4500}
4501
4502// === Composite types ===
4503
4504impl<T: Locate> Locate for Option<T> {
4505    fn find_loc(
4506        &self,
4507        locator: &mut LocatorGuard,
4508        file_path: &'static str,
4509        code: &str,
4510        offset: usize,
4511    ) -> Location {
4512        if let Some(inner) = self {
4513            inner.locate(locator, file_path, code, offset)
4514        } else {
4515            Location {
4516                file_path,
4517                start: offset,
4518                end: offset,
4519            }
4520        }
4521    }
4522}
4523
4524impl<T: Locate> Locate for Box<T> {
4525    fn find_loc(
4526        &self,
4527        locator: &mut LocatorGuard,
4528        file_path: &'static str,
4529        code: &str,
4530        offset: usize,
4531    ) -> Location {
4532        let t = &**self;
4533        t.locate(locator, file_path, code, offset)
4534    }
4535}
4536
4537impl<T: Locate> Locate for Vec<T> {
4538    fn find_loc(
4539        &self,
4540        locator: &mut LocatorGuard,
4541        file_path: &'static str,
4542        code: &str,
4543        offset: usize,
4544    ) -> Location {
4545        let mut start = usize::MAX;
4546        let mut end = offset;
4547
4548        for item in self {
4549            let loc = item.locate(locator, file_path, code, end);
4550            start = start.min(loc.start);
4551            end = loc.end;
4552        }
4553
4554        Location {
4555            file_path,
4556            start: if start != usize::MAX { start } else { offset },
4557            end,
4558        }
4559    }
4560}
4561
4562impl<T, S> Locate for syn::punctuated::Punctuated<T, S>
4563where
4564    T: Locate,
4565    S: Locate,
4566{
4567    fn find_loc(
4568        &self,
4569        locator: &mut LocatorGuard,
4570        file_path: &'static str,
4571        code: &str,
4572        offset: usize,
4573    ) -> Location {
4574        let mut start = usize::MAX;
4575        let mut end = offset;
4576
4577        for item in self {
4578            let loc = item.locate(locator, file_path, code, end);
4579            start = start.min(loc.start);
4580            end = loc.end;
4581        }
4582
4583        Location {
4584            file_path,
4585            start: if start != usize::MAX { start } else { offset },
4586            end,
4587        }
4588    }
4589}
4590
4591// === Helper functions ===
4592
4593pub mod helper {
4594    use super::*;
4595
4596    pub fn char_location(
4597        file_path: &'static str,
4598        code: &str,
4599        offset: usize,
4600        content: char,
4601    ) -> Location {
4602        let cur_code = &code[offset..];
4603        let start = offset
4604            + cur_code
4605                .find(content)
4606                .unwrap_or_else(|| panic!("expected `{content}` from `{cur_code}`"));
4607
4608        Location {
4609            file_path,
4610            start,
4611            end: start + content.len_utf8(),
4612        }
4613    }
4614
4615    pub fn str_location(
4616        file_path: &'static str,
4617        code: &str,
4618        offset: usize,
4619        content: &str,
4620    ) -> Location {
4621        let cur_code = &code[offset..];
4622
4623        let start = offset
4624            + cur_code
4625                .find(content)
4626                .unwrap_or_else(|| panic!("expected `{content}` from `{cur_code}`"));
4627
4628        Location {
4629            file_path,
4630            start,
4631            end: start + content.len(),
4632        }
4633    }
4634}