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        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}
2630
2631// Parse order is not the same as the order they are declared.
2632// ref: https://github.com/dtolnay/syn/blob/5357c8fb6bd29fd7c829e0aede1dab4b45a6e00f/src/item.rs#L1240
2633impl Locate for syn::ItemMacro {
2634    fn find_loc(
2635        &self,
2636        locator: &mut LocatorGuard,
2637        file_path: &'static str,
2638        code: &str,
2639        offset: usize,
2640    ) -> Location {
2641        Surround {
2642            front: (
2643                &self.attrs,
2644                &self.mac.path,
2645                &self.mac.bang_token,
2646                &self.ident,
2647            ),
2648            surround: &self.mac.delimiter,
2649            inner: (), // tokens are not processed yet.
2650            back: &self.semi_token,
2651        }
2652        .locate(locator, file_path, code, offset)
2653    }
2654}
2655
2656impl Locate for syn::ItemMod {
2657    fn find_loc(
2658        &self,
2659        locator: &mut LocatorGuard,
2660        file_path: &'static str,
2661        code: &str,
2662        offset: usize,
2663    ) -> Location {
2664        match (&self.content, &self.semi) {
2665            (Some((brace, items)), Some(semi_token)) => Surround {
2666                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
2667                surround: brace,
2668                inner: items,
2669                back: semi_token,
2670            }
2671            .locate(locator, file_path, code, offset),
2672            (Some((brace, items)), None) => Surround {
2673                front: (&self.attrs, &self.vis, &self.mod_token, &self.ident),
2674                surround: brace,
2675                inner: items,
2676                back: (),
2677            }
2678            .locate(locator, file_path, code, offset),
2679            (None, Some(semi_token)) => (
2680                &self.attrs,
2681                &self.vis,
2682                &self.mod_token,
2683                &self.ident,
2684                semi_token,
2685            )
2686                .locate_as_group(locator, file_path, code, offset),
2687            (None, None) => (&self.attrs, &self.vis, &self.mod_token, &self.ident)
2688                .locate_as_group(locator, file_path, code, offset),
2689        }
2690    }
2691}
2692
2693impl Locate for syn::ItemStatic {
2694    fn find_loc(
2695        &self,
2696        locator: &mut LocatorGuard,
2697        file_path: &'static str,
2698        code: &str,
2699        offset: usize,
2700    ) -> Location {
2701        (
2702            &self.attrs,
2703            &self.vis,
2704            &self.static_token,
2705            &self.mutability,
2706            &self.ident,
2707            &self.colon_token,
2708            &self.ty,
2709            &self.eq_token,
2710            &self.expr,
2711            &self.semi_token,
2712        )
2713            .locate_as_group(locator, file_path, code, offset)
2714    }
2715}
2716
2717impl Locate for syn::ItemStruct {
2718    fn find_loc(
2719        &self,
2720        locator: &mut LocatorGuard,
2721        file_path: &'static str,
2722        code: &str,
2723        offset: usize,
2724    ) -> Location {
2725        (
2726            &self.attrs,
2727            &self.vis,
2728            &self.struct_token,
2729            &self.ident,
2730            &self.generics,
2731            &self.fields,
2732            &self.semi_token,
2733        )
2734            .locate_as_group(locator, file_path, code, offset)
2735    }
2736}
2737
2738impl Locate for syn::ItemTrait {
2739    fn find_loc(
2740        &self,
2741        locator: &mut LocatorGuard,
2742        file_path: &'static str,
2743        code: &str,
2744        offset: usize,
2745    ) -> Location {
2746        Surround {
2747            front: (
2748                &self.attrs,
2749                &self.vis,
2750                &self.unsafety,
2751                &self.auto_token,
2752                &self.restriction,
2753                &self.trait_token,
2754                &self.ident,
2755                &self.generics,
2756                &self.colon_token,
2757                &self.supertraits,
2758            ),
2759            surround: &self.brace_token,
2760            inner: &self.items,
2761            back: (),
2762        }
2763        .locate(locator, file_path, code, offset)
2764    }
2765}
2766
2767impl Locate for syn::ItemTraitAlias {
2768    fn find_loc(
2769        &self,
2770        locator: &mut LocatorGuard,
2771        file_path: &'static str,
2772        code: &str,
2773        offset: usize,
2774    ) -> Location {
2775        (
2776            &self.attrs,
2777            &self.vis,
2778            &self.trait_token,
2779            &self.ident,
2780            &self.generics,
2781            &self.eq_token,
2782            &self.bounds,
2783            &self.semi_token,
2784        )
2785            .locate_as_group(locator, file_path, code, offset)
2786    }
2787}
2788
2789impl Locate for syn::ItemType {
2790    fn find_loc(
2791        &self,
2792        locator: &mut LocatorGuard,
2793        file_path: &'static str,
2794        code: &str,
2795        offset: usize,
2796    ) -> Location {
2797        (
2798            &self.attrs,
2799            &self.vis,
2800            &self.type_token,
2801            &self.ident,
2802            &self.generics,
2803            &self.eq_token,
2804            &self.ty,
2805            &self.semi_token,
2806        )
2807            .locate_as_group(locator, file_path, code, offset)
2808    }
2809}
2810
2811impl Locate for syn::ItemUnion {
2812    fn find_loc(
2813        &self,
2814        locator: &mut LocatorGuard,
2815        file_path: &'static str,
2816        code: &str,
2817        offset: usize,
2818    ) -> Location {
2819        (
2820            &self.attrs,
2821            &self.vis,
2822            &self.union_token,
2823            &self.ident,
2824            &self.generics,
2825            &self.fields,
2826        )
2827            .locate_as_group(locator, file_path, code, offset)
2828    }
2829}
2830
2831impl Locate for syn::ItemUse {
2832    fn find_loc(
2833        &self,
2834        locator: &mut LocatorGuard,
2835        file_path: &'static str,
2836        code: &str,
2837        offset: usize,
2838    ) -> Location {
2839        (
2840            &self.attrs,
2841            &self.vis,
2842            &self.use_token,
2843            &self.leading_colon,
2844            &self.tree,
2845            &self.semi_token,
2846        )
2847            .locate_as_group(locator, file_path, code, offset)
2848    }
2849}
2850
2851impl Locate for syn::Label {
2852    fn find_loc(
2853        &self,
2854        locator: &mut LocatorGuard,
2855        file_path: &'static str,
2856        code: &str,
2857        offset: usize,
2858    ) -> Location {
2859        (&self.name, &self.colon_token).locate_as_group(locator, file_path, code, offset)
2860    }
2861}
2862
2863impl Locate for syn::Lifetime {
2864    fn find_loc(
2865        &self,
2866        locator: &mut LocatorGuard,
2867        file_path: &'static str,
2868        code: &str,
2869        offset: usize,
2870    ) -> Location {
2871        let cur_code = &code[offset..];
2872
2873        let start = offset
2874            + cur_code
2875                .find('\'')
2876                .unwrap_or_else(|| panic!("expected ' from {cur_code}"));
2877        let end = self.ident.locate(locator, file_path, code, start + 1).end;
2878
2879        Location {
2880            file_path,
2881            start,
2882            end,
2883        }
2884    }
2885}
2886
2887impl Locate for syn::LifetimeParam {
2888    fn find_loc(
2889        &self,
2890        locator: &mut LocatorGuard,
2891        file_path: &'static str,
2892        code: &str,
2893        offset: usize,
2894    ) -> Location {
2895        (&self.attrs, &self.lifetime, &self.colon_token, &self.bounds)
2896            .locate_as_group(locator, file_path, code, offset)
2897    }
2898}
2899
2900impl Locate for syn::Lit {
2901    fn find_loc(
2902        &self,
2903        locator: &mut LocatorGuard,
2904        file_path: &'static str,
2905        code: &str,
2906        offset: usize,
2907    ) -> Location {
2908        match self {
2909            Self::Str(v) => v.locate(locator, file_path, code, offset),
2910            Self::ByteStr(v) => v.locate(locator, file_path, code, offset),
2911            Self::CStr(v) => v.locate(locator, file_path, code, offset),
2912            Self::Byte(v) => v.locate(locator, file_path, code, offset),
2913            Self::Char(v) => v.locate(locator, file_path, code, offset),
2914            Self::Int(v) => v.locate(locator, file_path, code, offset),
2915            Self::Float(v) => v.locate(locator, file_path, code, offset),
2916            Self::Bool(v) => v.locate(locator, file_path, code, offset),
2917            Self::Verbatim(_) => Location {
2918                file_path,
2919                start: offset,
2920                end: offset,
2921            },
2922            _ => Location {
2923                file_path,
2924                start: offset,
2925                end: offset,
2926            },
2927        }
2928    }
2929}
2930
2931impl Locate for syn::LitStr {
2932    fn find_loc(
2933        &self,
2934        _: &mut LocatorGuard,
2935        file_path: &'static str,
2936        code: &str,
2937        offset: usize,
2938    ) -> Location {
2939        let lit = self.token().to_string();
2940        helper::str_location(file_path, code, offset, &lit)
2941    }
2942}
2943
2944impl Locate for syn::LitByteStr {
2945    fn find_loc(
2946        &self,
2947        _: &mut LocatorGuard,
2948        file_path: &'static str,
2949        code: &str,
2950        offset: usize,
2951    ) -> Location {
2952        let lit = self.token().to_string();
2953        helper::str_location(file_path, code, offset, &lit)
2954    }
2955}
2956
2957impl Locate for syn::LitCStr {
2958    fn find_loc(
2959        &self,
2960        _: &mut LocatorGuard,
2961        file_path: &'static str,
2962        code: &str,
2963        offset: usize,
2964    ) -> Location {
2965        let lit = self.token().to_string();
2966        helper::str_location(file_path, code, offset, &lit)
2967    }
2968}
2969
2970impl Locate for syn::LitByte {
2971    fn find_loc(
2972        &self,
2973        _: &mut LocatorGuard,
2974        file_path: &'static str,
2975        code: &str,
2976        offset: usize,
2977    ) -> Location {
2978        let lit = self.token().to_string();
2979        helper::str_location(file_path, code, offset, &lit)
2980    }
2981}
2982
2983impl Locate for syn::LitChar {
2984    fn find_loc(
2985        &self,
2986        _: &mut LocatorGuard,
2987        file_path: &'static str,
2988        code: &str,
2989        offset: usize,
2990    ) -> Location {
2991        let lit = self.token().to_string();
2992        helper::str_location(file_path, code, offset, &lit)
2993    }
2994}
2995
2996impl Locate for syn::LitInt {
2997    fn find_loc(
2998        &self,
2999        _: &mut LocatorGuard,
3000        file_path: &'static str,
3001        code: &str,
3002        offset: usize,
3003    ) -> Location {
3004        let lit = self.token().to_string();
3005        helper::str_location(file_path, code, offset, &lit)
3006    }
3007}
3008
3009impl Locate for syn::LitFloat {
3010    fn find_loc(
3011        &self,
3012        _: &mut LocatorGuard,
3013        file_path: &'static str,
3014        code: &str,
3015        offset: usize,
3016    ) -> Location {
3017        let lit = self.token().to_string();
3018        helper::str_location(file_path, code, offset, &lit)
3019    }
3020}
3021
3022impl Locate for syn::LitBool {
3023    fn find_loc(
3024        &self,
3025        _: &mut LocatorGuard,
3026        file_path: &'static str,
3027        code: &str,
3028        offset: usize,
3029    ) -> Location {
3030        let lit = self.token().to_string();
3031        helper::str_location(file_path, code, offset, &lit)
3032    }
3033}
3034
3035impl Locate for syn::Local {
3036    fn find_loc(
3037        &self,
3038        locator: &mut LocatorGuard,
3039        file_path: &'static str,
3040        code: &str,
3041        offset: usize,
3042    ) -> Location {
3043        (
3044            &self.attrs,
3045            &self.let_token,
3046            &self.pat,
3047            &self.init,
3048            &self.semi_token,
3049        )
3050            .locate_as_group(locator, file_path, code, offset)
3051    }
3052}
3053
3054impl Locate for syn::LocalInit {
3055    fn find_loc(
3056        &self,
3057        locator: &mut LocatorGuard,
3058        file_path: &'static str,
3059        code: &str,
3060        offset: usize,
3061    ) -> Location {
3062        if let Some((else_token, diverge)) = &self.diverge {
3063            (&self.eq_token, &self.expr, else_token, diverge)
3064                .locate_as_group(locator, file_path, code, offset)
3065        } else {
3066            (&self.eq_token, &self.expr).locate_as_group(locator, file_path, code, offset)
3067        }
3068    }
3069}
3070
3071impl Locate for syn::Macro {
3072    fn find_loc(
3073        &self,
3074        locator: &mut LocatorGuard,
3075        file_path: &'static str,
3076        code: &str,
3077        offset: usize,
3078    ) -> Location {
3079        match &self.delimiter {
3080            syn::MacroDelimiter::Paren(paren) => Surround {
3081                front: (&self.path, &self.bang_token),
3082                surround: paren,
3083                inner: (),
3084                back: (),
3085            }
3086            .locate(locator, file_path, code, offset),
3087            syn::MacroDelimiter::Brace(brace) => Surround {
3088                front: (&self.path, &self.bang_token),
3089                surround: brace,
3090                inner: (),
3091                back: (),
3092            }
3093            .locate(locator, file_path, code, offset),
3094            syn::MacroDelimiter::Bracket(bracket) => Surround {
3095                front: (&self.path, &self.bang_token),
3096                surround: bracket,
3097                inner: (),
3098                back: (),
3099            }
3100            .locate(locator, file_path, code, offset),
3101        }
3102    }
3103}
3104
3105impl Locate for syn::MacroDelimiter {
3106    fn find_loc(
3107        &self,
3108        locator: &mut LocatorGuard,
3109        file_path: &'static str,
3110        code: &str,
3111        offset: usize,
3112    ) -> Location {
3113        match self {
3114            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3115            Self::Brace(v) => v.locate(locator, file_path, code, offset),
3116            Self::Bracket(v) => v.locate(locator, file_path, code, offset),
3117        }
3118    }
3119}
3120
3121impl Locate for syn::Member {
3122    fn find_loc(
3123        &self,
3124        locator: &mut LocatorGuard,
3125        file_path: &'static str,
3126        code: &str,
3127        offset: usize,
3128    ) -> Location {
3129        match self {
3130            Self::Named(v) => v.locate(locator, file_path, code, offset),
3131            Self::Unnamed(v) => v.locate(locator, file_path, code, offset),
3132        }
3133    }
3134}
3135
3136impl Locate for syn::Meta {
3137    fn find_loc(
3138        &self,
3139        locator: &mut LocatorGuard,
3140        file_path: &'static str,
3141        code: &str,
3142        offset: usize,
3143    ) -> Location {
3144        match self {
3145            Self::Path(v) => v.locate(locator, file_path, code, offset),
3146            Self::List(v) => v.locate(locator, file_path, code, offset),
3147            Self::NameValue(v) => v.locate(locator, file_path, code, offset),
3148        }
3149    }
3150}
3151
3152impl Locate for syn::MetaList {
3153    fn find_loc(
3154        &self,
3155        locator: &mut LocatorGuard,
3156        file_path: &'static str,
3157        code: &str,
3158        offset: usize,
3159    ) -> Location {
3160        match &self.delimiter {
3161            syn::MacroDelimiter::Paren(paren) => Surround {
3162                front: &self.path,
3163                surround: paren,
3164                inner: (),
3165                back: (),
3166            }
3167            .locate(locator, file_path, code, offset),
3168            syn::MacroDelimiter::Brace(brace) => Surround {
3169                front: &self.path,
3170                surround: brace,
3171                inner: (),
3172                back: (),
3173            }
3174            .locate(locator, file_path, code, offset),
3175            syn::MacroDelimiter::Bracket(bracket) => Surround {
3176                front: &self.path,
3177                surround: bracket,
3178                inner: (),
3179                back: (),
3180            }
3181            .locate(locator, file_path, code, offset),
3182        }
3183    }
3184}
3185
3186impl Locate for syn::MetaNameValue {
3187    fn find_loc(
3188        &self,
3189        locator: &mut LocatorGuard,
3190        file_path: &'static str,
3191        code: &str,
3192        offset: usize,
3193    ) -> Location {
3194        (&self.path, &self.eq_token, &self.value).locate_as_group(locator, file_path, code, offset)
3195    }
3196}
3197
3198impl Locate for syn::ParenthesizedGenericArguments {
3199    fn find_loc(
3200        &self,
3201        locator: &mut LocatorGuard,
3202        file_path: &'static str,
3203        code: &str,
3204        offset: usize,
3205    ) -> Location {
3206        Surround {
3207            front: (),
3208            surround: &self.paren_token,
3209            inner: &self.inputs,
3210            back: &self.output,
3211        }
3212        .locate(locator, file_path, code, offset)
3213    }
3214}
3215
3216impl Locate for syn::Pat {
3217    fn find_loc(
3218        &self,
3219        locator: &mut LocatorGuard,
3220        file_path: &'static str,
3221        code: &str,
3222        offset: usize,
3223    ) -> Location {
3224        match self {
3225            Self::Const(v) => v.locate(locator, file_path, code, offset),
3226            Self::Ident(v) => v.locate(locator, file_path, code, offset),
3227            Self::Lit(v) => v.locate(locator, file_path, code, offset),
3228            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3229            Self::Or(v) => v.locate(locator, file_path, code, offset),
3230            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3231            Self::Path(v) => v.locate(locator, file_path, code, offset),
3232            Self::Range(v) => v.locate(locator, file_path, code, offset),
3233            Self::Reference(v) => v.locate(locator, file_path, code, offset),
3234            Self::Rest(v) => v.locate(locator, file_path, code, offset),
3235            Self::Slice(v) => v.locate(locator, file_path, code, offset),
3236            Self::Struct(v) => v.locate(locator, file_path, code, offset),
3237            Self::Tuple(v) => v.locate(locator, file_path, code, offset),
3238            Self::TupleStruct(v) => v.locate(locator, file_path, code, offset),
3239            Self::Type(v) => v.locate(locator, file_path, code, offset),
3240            Self::Verbatim(_) => Location {
3241                file_path,
3242                start: offset,
3243                end: offset,
3244            },
3245            Self::Wild(v) => v.locate(locator, file_path, code, offset),
3246            _ => Location {
3247                file_path,
3248                start: offset,
3249                end: offset,
3250            },
3251        }
3252    }
3253}
3254
3255impl Locate for syn::PatIdent {
3256    fn find_loc(
3257        &self,
3258        locator: &mut LocatorGuard,
3259        file_path: &'static str,
3260        code: &str,
3261        offset: usize,
3262    ) -> Location {
3263        if let Some((at_token, subpat)) = &self.subpat {
3264            (
3265                &self.attrs,
3266                &self.by_ref,
3267                &self.mutability,
3268                &self.ident,
3269                at_token,
3270                subpat,
3271            )
3272                .locate_as_group(locator, file_path, code, offset)
3273        } else {
3274            (&self.attrs, &self.by_ref, &self.mutability, &self.ident)
3275                .locate_as_group(locator, file_path, code, offset)
3276        }
3277    }
3278}
3279
3280impl Locate for syn::PatOr {
3281    fn find_loc(
3282        &self,
3283        locator: &mut LocatorGuard,
3284        file_path: &'static str,
3285        code: &str,
3286        offset: usize,
3287    ) -> Location {
3288        (&self.attrs, &self.leading_vert, &self.cases)
3289            .locate_as_group(locator, file_path, code, offset)
3290    }
3291}
3292
3293impl Locate for syn::PatParen {
3294    fn find_loc(
3295        &self,
3296        locator: &mut LocatorGuard,
3297        file_path: &'static str,
3298        code: &str,
3299        offset: usize,
3300    ) -> Location {
3301        Surround {
3302            front: &self.attrs,
3303            surround: &self.paren_token,
3304            inner: &self.pat,
3305            back: (),
3306        }
3307        .locate(locator, file_path, code, offset)
3308    }
3309}
3310
3311impl Locate for syn::PatReference {
3312    fn find_loc(
3313        &self,
3314        locator: &mut LocatorGuard,
3315        file_path: &'static str,
3316        code: &str,
3317        offset: usize,
3318    ) -> Location {
3319        (&self.attrs, &self.and_token, &self.mutability, &self.pat)
3320            .locate_as_group(locator, file_path, code, offset)
3321    }
3322}
3323
3324impl Locate for syn::PatRest {
3325    fn find_loc(
3326        &self,
3327        locator: &mut LocatorGuard,
3328        file_path: &'static str,
3329        code: &str,
3330        offset: usize,
3331    ) -> Location {
3332        (&self.attrs, &self.dot2_token).locate_as_group(locator, file_path, code, offset)
3333    }
3334}
3335
3336impl Locate for syn::PatSlice {
3337    fn find_loc(
3338        &self,
3339        locator: &mut LocatorGuard,
3340        file_path: &'static str,
3341        code: &str,
3342        offset: usize,
3343    ) -> Location {
3344        Surround {
3345            front: &self.attrs,
3346            surround: &self.bracket_token,
3347            inner: &self.elems,
3348            back: (),
3349        }
3350        .locate(locator, file_path, code, offset)
3351    }
3352}
3353
3354impl Locate for syn::PatStruct {
3355    fn find_loc(
3356        &self,
3357        locator: &mut LocatorGuard,
3358        file_path: &'static str,
3359        code: &str,
3360        offset: usize,
3361    ) -> Location {
3362        let front_loc = if let Some(qself) = &self.qself {
3363            Qualified {
3364                front: &self.attrs,
3365                qself,
3366                path: &self.path,
3367                back: (),
3368            }
3369            .locate(locator, file_path, code, offset)
3370        } else {
3371            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
3372        };
3373
3374        let back_loc = Surround {
3375            front: (),
3376            surround: &self.brace_token,
3377            inner: (&self.fields, &self.rest),
3378            back: (),
3379        }
3380        .locate(locator, file_path, code, front_loc.end);
3381
3382        Location {
3383            file_path,
3384            start: front_loc.start,
3385            end: back_loc.end,
3386        }
3387    }
3388}
3389
3390impl Locate for syn::PatTuple {
3391    fn find_loc(
3392        &self,
3393        locator: &mut LocatorGuard,
3394        file_path: &'static str,
3395        code: &str,
3396        offset: usize,
3397    ) -> Location {
3398        Surround {
3399            front: &self.attrs,
3400            surround: &self.paren_token,
3401            inner: &self.elems,
3402            back: (),
3403        }
3404        .locate(locator, file_path, code, offset)
3405    }
3406}
3407
3408impl Locate for syn::PatTupleStruct {
3409    fn find_loc(
3410        &self,
3411        locator: &mut LocatorGuard,
3412        file_path: &'static str,
3413        code: &str,
3414        offset: usize,
3415    ) -> Location {
3416        let front_loc = if let Some(qself) = &self.qself {
3417            Qualified {
3418                front: &self.attrs,
3419                qself,
3420                path: &self.path,
3421                back: (),
3422            }
3423            .locate(locator, file_path, code, offset)
3424        } else {
3425            (&self.attrs, &self.path).locate_as_group(locator, file_path, code, offset)
3426        };
3427
3428        let back_loc = Surround {
3429            front: (),
3430            surround: &self.paren_token,
3431            inner: &self.elems,
3432            back: (),
3433        }
3434        .locate(locator, file_path, code, front_loc.end);
3435
3436        Location {
3437            file_path,
3438            start: front_loc.start,
3439            end: back_loc.end,
3440        }
3441    }
3442}
3443
3444impl Locate for syn::PatType {
3445    fn find_loc(
3446        &self,
3447        locator: &mut LocatorGuard,
3448        file_path: &'static str,
3449        code: &str,
3450        offset: usize,
3451    ) -> Location {
3452        (&self.attrs, &self.pat, &self.colon_token, &self.ty)
3453            .locate_as_group(locator, file_path, code, offset)
3454    }
3455}
3456
3457impl Locate for syn::PatWild {
3458    fn find_loc(
3459        &self,
3460        locator: &mut LocatorGuard,
3461        file_path: &'static str,
3462        code: &str,
3463        offset: usize,
3464    ) -> Location {
3465        (&self.attrs, &self.underscore_token).locate_as_group(locator, file_path, code, offset)
3466    }
3467}
3468
3469impl Locate for syn::Path {
3470    fn find_loc(
3471        &self,
3472        locator: &mut LocatorGuard,
3473        file_path: &'static str,
3474        code: &str,
3475        offset: usize,
3476    ) -> Location {
3477        (&self.leading_colon, &self.segments).locate_as_group(locator, file_path, code, offset)
3478    }
3479}
3480
3481impl Locate for syn::PathArguments {
3482    fn find_loc(
3483        &self,
3484        locator: &mut LocatorGuard,
3485        file_path: &'static str,
3486        code: &str,
3487        offset: usize,
3488    ) -> Location {
3489        match self {
3490            Self::None => Location {
3491                file_path,
3492                start: offset,
3493                end: offset,
3494            },
3495            Self::AngleBracketed(v) => v.locate(locator, file_path, code, offset),
3496            Self::Parenthesized(v) => v.locate(locator, file_path, code, offset),
3497        }
3498    }
3499}
3500
3501impl Locate for syn::PathSegment {
3502    fn find_loc(
3503        &self,
3504        locator: &mut LocatorGuard,
3505        file_path: &'static str,
3506        code: &str,
3507        offset: usize,
3508    ) -> Location {
3509        (&self.ident, &self.arguments).locate_as_group(locator, file_path, code, offset)
3510    }
3511}
3512
3513impl Locate for syn::PointerMutability {
3514    fn find_loc(
3515        &self,
3516        locator: &mut LocatorGuard,
3517        file_path: &'static str,
3518        code: &str,
3519        offset: usize,
3520    ) -> Location {
3521        match self {
3522            Self::Const(v) => v.locate(locator, file_path, code, offset),
3523            Self::Mut(v) => v.locate(locator, file_path, code, offset),
3524        }
3525    }
3526}
3527
3528impl Locate for syn::PreciseCapture {
3529    fn find_loc(
3530        &self,
3531        locator: &mut LocatorGuard,
3532        file_path: &'static str,
3533        code: &str,
3534        offset: usize,
3535    ) -> Location {
3536        (
3537            &self.use_token,
3538            &self.lt_token,
3539            &self.params,
3540            &self.gt_token,
3541        )
3542            .locate_as_group(locator, file_path, code, offset)
3543    }
3544}
3545
3546impl Locate for syn::PredicateLifetime {
3547    fn find_loc(
3548        &self,
3549        locator: &mut LocatorGuard,
3550        file_path: &'static str,
3551        code: &str,
3552        offset: usize,
3553    ) -> Location {
3554        (&self.lifetime, &self.colon_token, &self.bounds)
3555            .locate_as_group(locator, file_path, code, offset)
3556    }
3557}
3558
3559impl Locate for syn::PredicateType {
3560    fn find_loc(
3561        &self,
3562        locator: &mut LocatorGuard,
3563        file_path: &'static str,
3564        code: &str,
3565        offset: usize,
3566    ) -> Location {
3567        (
3568            &self.lifetimes,
3569            &self.bounded_ty,
3570            &self.colon_token,
3571            &self.bounds,
3572        )
3573            .locate_as_group(locator, file_path, code, offset)
3574    }
3575}
3576
3577impl Locate for syn::QSelf {
3578    fn find_loc(
3579        &self,
3580        locator: &mut LocatorGuard,
3581        file_path: &'static str,
3582        code: &str,
3583        offset: usize,
3584    ) -> Location {
3585        let front_loc = (&self.lt_token, &self.ty, &self.as_token)
3586            .locate_as_group(locator, file_path, code, offset);
3587
3588        const OPEN: char = '<';
3589        const CLOSE: char = '>';
3590
3591        let cur_code = &code[front_loc.end..];
3592
3593        let mut cur = front_loc.end;
3594        let mut level = 1;
3595
3596        for c in cur_code.chars() {
3597            if c == OPEN {
3598                level += 1;
3599            } else if c == CLOSE {
3600                if level == 1 {
3601                    break;
3602                }
3603                level -= 1;
3604            }
3605            cur += c.len_utf8();
3606        }
3607
3608        let end = self.gt_token.locate(locator, file_path, code, cur).end;
3609
3610        Location {
3611            file_path,
3612            start: front_loc.start,
3613            end,
3614        }
3615    }
3616}
3617
3618impl Locate for syn::RangeLimits {
3619    fn find_loc(
3620        &self,
3621        locator: &mut LocatorGuard,
3622        file_path: &'static str,
3623        code: &str,
3624        offset: usize,
3625    ) -> Location {
3626        match self {
3627            Self::HalfOpen(v) => v.locate(locator, file_path, code, offset),
3628            Self::Closed(v) => v.locate(locator, file_path, code, offset),
3629        }
3630    }
3631}
3632
3633impl Locate for syn::Receiver {
3634    fn find_loc(
3635        &self,
3636        locator: &mut LocatorGuard,
3637        file_path: &'static str,
3638        code: &str,
3639        offset: usize,
3640    ) -> Location {
3641        // If there is no colon, `self.ty` must be ignored because it is not
3642        // constructed from source code.
3643
3644        if let Some((and_token, reference)) = &self.reference {
3645            if let Some(colon_token) = &self.colon_token {
3646                (
3647                    &self.attrs,
3648                    and_token,
3649                    reference,
3650                    &self.mutability,
3651                    &self.self_token,
3652                    colon_token,
3653                    &self.ty,
3654                )
3655                    .locate_as_group(locator, file_path, code, offset)
3656            } else {
3657                (
3658                    &self.attrs,
3659                    and_token,
3660                    reference,
3661                    &self.mutability,
3662                    &self.self_token,
3663                )
3664                    .locate_as_group(locator, file_path, code, offset)
3665            }
3666        } else if let Some(colon_token) = &self.colon_token {
3667            (
3668                &self.attrs,
3669                &self.mutability,
3670                &self.self_token,
3671                colon_token,
3672                &self.ty,
3673            )
3674                .locate_as_group(locator, file_path, code, offset)
3675        } else {
3676            (&self.attrs, &self.mutability, &self.self_token)
3677                .locate_as_group(locator, file_path, code, offset)
3678        }
3679    }
3680}
3681
3682impl Locate for syn::ReturnType {
3683    fn find_loc(
3684        &self,
3685        locator: &mut LocatorGuard,
3686        file_path: &'static str,
3687        code: &str,
3688        offset: usize,
3689    ) -> Location {
3690        match self {
3691            Self::Default => Location {
3692                file_path,
3693                start: offset,
3694                end: offset,
3695            },
3696            Self::Type(arrow_token, ty) => {
3697                (arrow_token, ty).locate_as_group(locator, file_path, code, offset)
3698            }
3699        }
3700    }
3701}
3702
3703impl Locate for syn::Signature {
3704    fn find_loc(
3705        &self,
3706        locator: &mut LocatorGuard,
3707        file_path: &'static str,
3708        code: &str,
3709        offset: usize,
3710    ) -> Location {
3711        Surround {
3712            front: (
3713                &self.constness,
3714                &self.asyncness,
3715                &self.unsafety,
3716                &self.abi,
3717                &self.fn_token,
3718                &self.ident,
3719                // `generics.where_clause` is behind the `output`
3720                &self.generics.lt_token,
3721                &self.generics.params,
3722                &self.generics.gt_token,
3723            ),
3724            surround: &self.paren_token,
3725            inner: (&self.inputs, &self.variadic),
3726            back: (&self.output, &self.generics.where_clause),
3727        }
3728        .locate(locator, file_path, code, offset)
3729    }
3730}
3731
3732impl Locate for syn::StaticMutability {
3733    fn find_loc(
3734        &self,
3735        locator: &mut LocatorGuard,
3736        file_path: &'static str,
3737        code: &str,
3738        offset: usize,
3739    ) -> Location {
3740        match self {
3741            Self::Mut(v) => v.locate(locator, file_path, code, offset),
3742            Self::None => Location {
3743                file_path,
3744                start: offset,
3745                end: offset,
3746            },
3747            _ => Location {
3748                file_path,
3749                start: offset,
3750                end: offset,
3751            },
3752        }
3753    }
3754}
3755
3756impl Locate for syn::Stmt {
3757    fn find_loc(
3758        &self,
3759        locator: &mut LocatorGuard,
3760        file_path: &'static str,
3761        code: &str,
3762        offset: usize,
3763    ) -> Location {
3764        match self {
3765            Self::Local(v) => v.locate(locator, file_path, code, offset),
3766            Self::Item(v) => v.locate(locator, file_path, code, offset),
3767            Self::Expr(expr, semi_token) => {
3768                (expr, semi_token).locate_as_group(locator, file_path, code, offset)
3769            }
3770            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3771        }
3772    }
3773}
3774
3775impl Locate for syn::StmtMacro {
3776    fn find_loc(
3777        &self,
3778        locator: &mut LocatorGuard,
3779        file_path: &'static str,
3780        code: &str,
3781        offset: usize,
3782    ) -> Location {
3783        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
3784    }
3785}
3786
3787impl Locate for syn::TraitBound {
3788    fn find_loc(
3789        &self,
3790        locator: &mut LocatorGuard,
3791        file_path: &'static str,
3792        code: &str,
3793        offset: usize,
3794    ) -> Location {
3795        // self.paren_token is always Null according to syn parsing.
3796        (&self.modifier, &self.lifetimes, &self.path)
3797            .locate_as_group(locator, file_path, code, offset)
3798    }
3799}
3800
3801impl Locate for syn::TraitBoundModifier {
3802    fn find_loc(
3803        &self,
3804        locator: &mut LocatorGuard,
3805        file_path: &'static str,
3806        code: &str,
3807        offset: usize,
3808    ) -> Location {
3809        match self {
3810            Self::None => Location {
3811                file_path,
3812                start: offset,
3813                end: offset,
3814            },
3815            Self::Maybe(v) => v.locate(locator, file_path, code, offset),
3816        }
3817    }
3818}
3819
3820impl Locate for syn::TraitItem {
3821    fn find_loc(
3822        &self,
3823        locator: &mut LocatorGuard,
3824        file_path: &'static str,
3825        code: &str,
3826        offset: usize,
3827    ) -> Location {
3828        match self {
3829            Self::Const(v) => v.locate(locator, file_path, code, offset),
3830            Self::Fn(v) => v.locate(locator, file_path, code, offset),
3831            Self::Type(v) => v.locate(locator, file_path, code, offset),
3832            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3833            Self::Verbatim(_) => Location {
3834                file_path,
3835                start: offset,
3836                end: offset,
3837            },
3838            _ => Location {
3839                file_path,
3840                start: offset,
3841                end: offset,
3842            },
3843        }
3844    }
3845}
3846
3847impl Locate for syn::TraitItemConst {
3848    fn find_loc(
3849        &self,
3850        locator: &mut LocatorGuard,
3851        file_path: &'static str,
3852        code: &str,
3853        offset: usize,
3854    ) -> Location {
3855        if let Some((eq_token, default)) = &self.default {
3856            (
3857                &self.attrs,
3858                &self.const_token,
3859                &self.ident,
3860                &self.generics,
3861                &self.colon_token,
3862                &self.ty,
3863                eq_token,
3864                default,
3865                &self.semi_token,
3866            )
3867                .locate_as_group(locator, file_path, code, offset)
3868        } else {
3869            (
3870                &self.attrs,
3871                &self.const_token,
3872                &self.ident,
3873                &self.generics,
3874                &self.colon_token,
3875                &self.ty,
3876                &self.semi_token,
3877            )
3878                .locate_as_group(locator, file_path, code, offset)
3879        }
3880    }
3881}
3882
3883impl Locate for syn::TraitItemFn {
3884    fn find_loc(
3885        &self,
3886        locator: &mut LocatorGuard,
3887        file_path: &'static str,
3888        code: &str,
3889        offset: usize,
3890    ) -> Location {
3891        (&self.attrs, &self.sig, &self.default, &self.semi_token)
3892            .locate_as_group(locator, file_path, code, offset)
3893    }
3894}
3895
3896impl Locate for syn::TraitItemType {
3897    fn find_loc(
3898        &self,
3899        locator: &mut LocatorGuard,
3900        file_path: &'static str,
3901        code: &str,
3902        offset: usize,
3903    ) -> Location {
3904        if let Some((eq_token, default)) = &self.default {
3905            (
3906                &self.attrs,
3907                &self.type_token,
3908                &self.ident,
3909                &self.generics,
3910                &self.colon_token,
3911                &self.bounds,
3912                eq_token,
3913                default,
3914                &self.semi_token,
3915            )
3916                .locate_as_group(locator, file_path, code, offset)
3917        } else {
3918            (
3919                &self.attrs,
3920                &self.type_token,
3921                &self.ident,
3922                &self.generics,
3923                &self.colon_token,
3924                &self.bounds,
3925                &self.semi_token,
3926            )
3927                .locate_as_group(locator, file_path, code, offset)
3928        }
3929    }
3930}
3931
3932impl Locate for syn::TraitItemMacro {
3933    fn find_loc(
3934        &self,
3935        locator: &mut LocatorGuard,
3936        file_path: &'static str,
3937        code: &str,
3938        offset: usize,
3939    ) -> Location {
3940        (&self.attrs, &self.mac, &self.semi_token).locate_as_group(locator, file_path, code, offset)
3941    }
3942}
3943
3944impl Locate for syn::Type {
3945    fn find_loc(
3946        &self,
3947        locator: &mut LocatorGuard,
3948        file_path: &'static str,
3949        code: &str,
3950        offset: usize,
3951    ) -> Location {
3952        match self {
3953            Self::Array(v) => v.locate(locator, file_path, code, offset),
3954            Self::BareFn(v) => v.locate(locator, file_path, code, offset),
3955            Self::Group(v) => v.locate(locator, file_path, code, offset),
3956            Self::ImplTrait(v) => v.locate(locator, file_path, code, offset),
3957            Self::Infer(v) => v.locate(locator, file_path, code, offset),
3958            Self::Macro(v) => v.locate(locator, file_path, code, offset),
3959            Self::Never(v) => v.locate(locator, file_path, code, offset),
3960            Self::Paren(v) => v.locate(locator, file_path, code, offset),
3961            Self::Path(v) => v.locate(locator, file_path, code, offset),
3962            Self::Ptr(v) => v.locate(locator, file_path, code, offset),
3963            Self::Reference(v) => v.locate(locator, file_path, code, offset),
3964            Self::Slice(v) => v.locate(locator, file_path, code, offset),
3965            Self::TraitObject(v) => v.locate(locator, file_path, code, offset),
3966            Self::Tuple(v) => v.locate(locator, file_path, code, offset),
3967            Self::Verbatim(_) => Location {
3968                file_path,
3969                start: offset,
3970                end: offset,
3971            },
3972            _ => Location {
3973                file_path,
3974                start: offset,
3975                end: offset,
3976            },
3977        }
3978    }
3979}
3980
3981impl Locate for syn::TypeArray {
3982    fn find_loc(
3983        &self,
3984        locator: &mut LocatorGuard,
3985        file_path: &'static str,
3986        code: &str,
3987        offset: usize,
3988    ) -> Location {
3989        Surround {
3990            front: (),
3991            surround: &self.bracket_token,
3992            inner: (&self.elem, &self.semi_token, &self.len),
3993            back: (),
3994        }
3995        .locate(locator, file_path, code, offset)
3996    }
3997}
3998
3999impl Locate for syn::TypeBareFn {
4000    fn find_loc(
4001        &self,
4002        locator: &mut LocatorGuard,
4003        file_path: &'static str,
4004        code: &str,
4005        offset: usize,
4006    ) -> Location {
4007        Surround {
4008            front: (&self.lifetimes, &self.unsafety, &self.abi, &self.fn_token),
4009            surround: &self.paren_token,
4010            inner: (&self.inputs, &self.variadic),
4011            back: &self.output,
4012        }
4013        .locate(locator, file_path, code, offset)
4014    }
4015}
4016
4017impl Locate for syn::TypeGroup {
4018    fn find_loc(
4019        &self,
4020        locator: &mut LocatorGuard,
4021        file_path: &'static str,
4022        code: &str,
4023        offset: usize,
4024    ) -> Location {
4025        (&self.group_token, &self.elem).locate_as_group(locator, file_path, code, offset)
4026    }
4027}
4028
4029impl Locate for syn::TypeImplTrait {
4030    fn find_loc(
4031        &self,
4032        locator: &mut LocatorGuard,
4033        file_path: &'static str,
4034        code: &str,
4035        offset: usize,
4036    ) -> Location {
4037        (&self.impl_token, &self.bounds).locate_as_group(locator, file_path, code, offset)
4038    }
4039}
4040
4041impl Locate for syn::TypeInfer {
4042    fn find_loc(
4043        &self,
4044        locator: &mut LocatorGuard,
4045        file_path: &'static str,
4046        code: &str,
4047        offset: usize,
4048    ) -> Location {
4049        self.underscore_token
4050            .locate(locator, file_path, code, offset)
4051    }
4052}
4053
4054impl Locate for syn::TypeMacro {
4055    fn find_loc(
4056        &self,
4057        locator: &mut LocatorGuard,
4058        file_path: &'static str,
4059        code: &str,
4060        offset: usize,
4061    ) -> Location {
4062        self.mac.locate(locator, file_path, code, offset)
4063    }
4064}
4065
4066impl Locate for syn::TypeNever {
4067    fn find_loc(
4068        &self,
4069        locator: &mut LocatorGuard,
4070        file_path: &'static str,
4071        code: &str,
4072        offset: usize,
4073    ) -> Location {
4074        self.bang_token.locate(locator, file_path, code, offset)
4075    }
4076}
4077
4078impl Locate for syn::TypeParen {
4079    fn find_loc(
4080        &self,
4081        locator: &mut LocatorGuard,
4082        file_path: &'static str,
4083        code: &str,
4084        offset: usize,
4085    ) -> Location {
4086        Surround {
4087            front: (),
4088            surround: &self.paren_token,
4089            inner: &self.elem,
4090            back: (),
4091        }
4092        .locate(locator, file_path, code, offset)
4093    }
4094}
4095
4096impl Locate for syn::TypePath {
4097    fn find_loc(
4098        &self,
4099        locator: &mut LocatorGuard,
4100        file_path: &'static str,
4101        code: &str,
4102        offset: usize,
4103    ) -> Location {
4104        if let Some(qself) = &self.qself {
4105            Qualified {
4106                front: (),
4107                qself,
4108                path: &self.path,
4109                back: (),
4110            }
4111            .locate(locator, file_path, code, offset)
4112        } else {
4113            self.path.locate(locator, file_path, code, offset)
4114        }
4115    }
4116}
4117
4118impl Locate for syn::TypePtr {
4119    fn find_loc(
4120        &self,
4121        locator: &mut LocatorGuard,
4122        file_path: &'static str,
4123        code: &str,
4124        offset: usize,
4125    ) -> Location {
4126        (
4127            &self.star_token,
4128            &self.const_token,
4129            &self.mutability,
4130            &self.elem,
4131        )
4132            .locate_as_group(locator, file_path, code, offset)
4133    }
4134}
4135
4136impl Locate for syn::TypeReference {
4137    fn find_loc(
4138        &self,
4139        locator: &mut LocatorGuard,
4140        file_path: &'static str,
4141        code: &str,
4142        offset: usize,
4143    ) -> Location {
4144        (
4145            &self.and_token,
4146            &self.lifetime,
4147            &self.mutability,
4148            &self.elem,
4149        )
4150            .locate_as_group(locator, file_path, code, offset)
4151    }
4152}
4153
4154impl Locate for syn::TypeSlice {
4155    fn find_loc(
4156        &self,
4157        locator: &mut LocatorGuard,
4158        file_path: &'static str,
4159        code: &str,
4160        offset: usize,
4161    ) -> Location {
4162        Surround {
4163            front: (),
4164            surround: &self.bracket_token,
4165            inner: &self.elem,
4166            back: (),
4167        }
4168        .locate(locator, file_path, code, offset)
4169    }
4170}
4171
4172impl Locate for syn::TypeTraitObject {
4173    fn find_loc(
4174        &self,
4175        locator: &mut LocatorGuard,
4176        file_path: &'static str,
4177        code: &str,
4178        offset: usize,
4179    ) -> Location {
4180        (&self.dyn_token, &self.bounds).locate_as_group(locator, file_path, code, offset)
4181    }
4182}
4183
4184impl Locate for syn::TypeTuple {
4185    fn find_loc(
4186        &self,
4187        locator: &mut LocatorGuard,
4188        file_path: &'static str,
4189        code: &str,
4190        offset: usize,
4191    ) -> Location {
4192        Surround {
4193            front: (),
4194            surround: &self.paren_token,
4195            inner: &self.elems,
4196            back: (),
4197        }
4198        .locate(locator, file_path, code, offset)
4199    }
4200}
4201
4202impl Locate for syn::TypeParam {
4203    fn find_loc(
4204        &self,
4205        locator: &mut LocatorGuard,
4206        file_path: &'static str,
4207        code: &str,
4208        offset: usize,
4209    ) -> Location {
4210        (
4211            &self.attrs,
4212            &self.ident,
4213            &self.colon_token,
4214            &self.bounds,
4215            &self.eq_token,
4216            &self.default,
4217        )
4218            .locate_as_group(locator, file_path, code, offset)
4219    }
4220}
4221
4222impl Locate for syn::TypeParamBound {
4223    fn find_loc(
4224        &self,
4225        locator: &mut LocatorGuard,
4226        file_path: &'static str,
4227        code: &str,
4228        offset: usize,
4229    ) -> Location {
4230        match self {
4231            Self::Trait(v) => v.locate(locator, file_path, code, offset),
4232            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
4233            Self::PreciseCapture(v) => v.locate(locator, file_path, code, offset),
4234            Self::Verbatim(_) => Location {
4235                file_path,
4236                start: offset,
4237                end: offset,
4238            },
4239            _ => Location {
4240                file_path,
4241                start: offset,
4242                end: offset,
4243            },
4244        }
4245    }
4246}
4247
4248impl Locate for syn::UnOp {
4249    fn find_loc(
4250        &self,
4251        locator: &mut LocatorGuard,
4252        file_path: &'static str,
4253        code: &str,
4254        offset: usize,
4255    ) -> Location {
4256        match self {
4257            Self::Deref(v) => v.locate(locator, file_path, code, offset),
4258            Self::Not(v) => v.locate(locator, file_path, code, offset),
4259            Self::Neg(v) => v.locate(locator, file_path, code, offset),
4260            _ => Location {
4261                file_path,
4262                start: offset,
4263                end: offset,
4264            },
4265        }
4266    }
4267}
4268
4269impl Locate for syn::UseGlob {
4270    fn find_loc(
4271        &self,
4272        locator: &mut LocatorGuard,
4273        file_path: &'static str,
4274        code: &str,
4275        offset: usize,
4276    ) -> Location {
4277        self.star_token.locate(locator, file_path, code, offset)
4278    }
4279}
4280
4281impl Locate for syn::UseGroup {
4282    fn find_loc(
4283        &self,
4284        locator: &mut LocatorGuard,
4285        file_path: &'static str,
4286        code: &str,
4287        offset: usize,
4288    ) -> Location {
4289        Surround {
4290            front: (),
4291            surround: &self.brace_token,
4292            inner: &self.items,
4293            back: (),
4294        }
4295        .locate(locator, file_path, code, offset)
4296    }
4297}
4298
4299impl Locate for syn::UseName {
4300    fn find_loc(
4301        &self,
4302        locator: &mut LocatorGuard,
4303        file_path: &'static str,
4304        code: &str,
4305        offset: usize,
4306    ) -> Location {
4307        self.ident.locate(locator, file_path, code, offset)
4308    }
4309}
4310
4311impl Locate for syn::UsePath {
4312    fn find_loc(
4313        &self,
4314        locator: &mut LocatorGuard,
4315        file_path: &'static str,
4316        code: &str,
4317        offset: usize,
4318    ) -> Location {
4319        (&self.ident, &self.colon2_token, &self.tree)
4320            .locate_as_group(locator, file_path, code, offset)
4321    }
4322}
4323
4324impl Locate for syn::UseRename {
4325    fn find_loc(
4326        &self,
4327        locator: &mut LocatorGuard,
4328        file_path: &'static str,
4329        code: &str,
4330        offset: usize,
4331    ) -> Location {
4332        (&self.ident, &self.as_token, &self.rename)
4333            .locate_as_group(locator, file_path, code, offset)
4334    }
4335}
4336
4337impl Locate for syn::UseTree {
4338    fn find_loc(
4339        &self,
4340        locator: &mut LocatorGuard,
4341        file_path: &'static str,
4342        code: &str,
4343        offset: usize,
4344    ) -> Location {
4345        match self {
4346            Self::Path(v) => v.locate(locator, file_path, code, offset),
4347            Self::Name(v) => v.locate(locator, file_path, code, offset),
4348            Self::Rename(v) => v.locate(locator, file_path, code, offset),
4349            Self::Glob(v) => v.locate(locator, file_path, code, offset),
4350            Self::Group(v) => v.locate(locator, file_path, code, offset),
4351        }
4352    }
4353}
4354
4355impl Locate for syn::Variadic {
4356    fn find_loc(
4357        &self,
4358        locator: &mut LocatorGuard,
4359        file_path: &'static str,
4360        code: &str,
4361        offset: usize,
4362    ) -> Location {
4363        if let Some((pat, colon_token)) = &self.pat {
4364            (&self.attrs, pat, colon_token, &self.dots, &self.comma)
4365                .locate_as_group(locator, file_path, code, offset)
4366        } else {
4367            (&self.attrs, &self.dots, &self.comma).locate_as_group(locator, file_path, code, offset)
4368        }
4369    }
4370}
4371
4372impl Locate for syn::Variant {
4373    fn find_loc(
4374        &self,
4375        locator: &mut LocatorGuard,
4376        file_path: &'static str,
4377        code: &str,
4378        offset: usize,
4379    ) -> Location {
4380        if let Some((eq_token, discriminant)) = &self.discriminant {
4381            (
4382                &self.attrs,
4383                &self.ident,
4384                &self.fields,
4385                eq_token,
4386                discriminant,
4387            )
4388                .locate_as_group(locator, file_path, code, offset)
4389        } else {
4390            (&self.attrs, &self.ident, &self.fields)
4391                .locate_as_group(locator, file_path, code, offset)
4392        }
4393    }
4394}
4395
4396impl Locate for syn::Visibility {
4397    fn find_loc(
4398        &self,
4399        locator: &mut LocatorGuard,
4400        file_path: &'static str,
4401        code: &str,
4402        offset: usize,
4403    ) -> Location {
4404        match self {
4405            Self::Public(v) => v.locate(locator, file_path, code, offset),
4406            Self::Restricted(v) => v.locate(locator, file_path, code, offset),
4407            Self::Inherited => Location {
4408                file_path,
4409                start: offset,
4410                end: offset,
4411            },
4412        }
4413    }
4414}
4415
4416impl Locate for syn::VisRestricted {
4417    fn find_loc(
4418        &self,
4419        locator: &mut LocatorGuard,
4420        file_path: &'static str,
4421        code: &str,
4422        offset: usize,
4423    ) -> Location {
4424        Surround {
4425            front: &self.pub_token,
4426            surround: &self.paren_token,
4427            inner: (&self.in_token, &self.path),
4428            back: (),
4429        }
4430        .locate(locator, file_path, code, offset)
4431    }
4432}
4433
4434impl Locate for syn::WhereClause {
4435    fn find_loc(
4436        &self,
4437        locator: &mut LocatorGuard,
4438        file_path: &'static str,
4439        code: &str,
4440        offset: usize,
4441    ) -> Location {
4442        (&self.where_token, &self.predicates).locate_as_group(locator, file_path, code, offset)
4443    }
4444}
4445
4446impl Locate for syn::WherePredicate {
4447    fn find_loc(
4448        &self,
4449        locator: &mut LocatorGuard,
4450        file_path: &'static str,
4451        code: &str,
4452        offset: usize,
4453    ) -> Location {
4454        match self {
4455            Self::Lifetime(v) => v.locate(locator, file_path, code, offset),
4456            Self::Type(v) => v.locate(locator, file_path, code, offset),
4457            _ => Location {
4458                file_path,
4459                start: offset,
4460                end: offset,
4461            },
4462        }
4463    }
4464}
4465
4466// === Composite types ===
4467
4468impl<T: Locate> Locate for Option<T> {
4469    fn find_loc(
4470        &self,
4471        locator: &mut LocatorGuard,
4472        file_path: &'static str,
4473        code: &str,
4474        offset: usize,
4475    ) -> Location {
4476        if let Some(inner) = self {
4477            inner.locate(locator, file_path, code, offset)
4478        } else {
4479            Location {
4480                file_path,
4481                start: offset,
4482                end: offset,
4483            }
4484        }
4485    }
4486}
4487
4488impl<T: Locate> Locate for Box<T> {
4489    fn find_loc(
4490        &self,
4491        locator: &mut LocatorGuard,
4492        file_path: &'static str,
4493        code: &str,
4494        offset: usize,
4495    ) -> Location {
4496        let t = &**self;
4497        t.locate(locator, file_path, code, offset)
4498    }
4499}
4500
4501impl<T: Locate> Locate for Vec<T> {
4502    fn find_loc(
4503        &self,
4504        locator: &mut LocatorGuard,
4505        file_path: &'static str,
4506        code: &str,
4507        offset: usize,
4508    ) -> Location {
4509        let mut start = usize::MAX;
4510        let mut end = offset;
4511
4512        for item in self {
4513            let loc = item.locate(locator, file_path, code, end);
4514            start = start.min(loc.start);
4515            end = loc.end;
4516        }
4517
4518        Location {
4519            file_path,
4520            start: if start != usize::MAX { start } else { offset },
4521            end,
4522        }
4523    }
4524}
4525
4526impl<T, S> Locate for syn::punctuated::Punctuated<T, S>
4527where
4528    T: Locate,
4529    S: Locate,
4530{
4531    fn find_loc(
4532        &self,
4533        locator: &mut LocatorGuard,
4534        file_path: &'static str,
4535        code: &str,
4536        offset: usize,
4537    ) -> Location {
4538        let mut start = usize::MAX;
4539        let mut end = offset;
4540
4541        for item in self {
4542            let loc = item.locate(locator, file_path, code, end);
4543            start = start.min(loc.start);
4544            end = loc.end;
4545        }
4546
4547        Location {
4548            file_path,
4549            start: if start != usize::MAX { start } else { offset },
4550            end,
4551        }
4552    }
4553}
4554
4555// === Helper functions ===
4556
4557pub mod helper {
4558    use super::*;
4559
4560    pub fn char_location(
4561        file_path: &'static str,
4562        code: &str,
4563        offset: usize,
4564        content: char,
4565    ) -> Location {
4566        let cur_code = &code[offset..];
4567        let start = offset
4568            + cur_code
4569                .find(content)
4570                .unwrap_or_else(|| panic!("expected `{content}` from `{cur_code}`"));
4571
4572        Location {
4573            file_path,
4574            start,
4575            end: start + content.len_utf8(),
4576        }
4577    }
4578
4579    pub fn str_location(
4580        file_path: &'static str,
4581        code: &str,
4582        offset: usize,
4583        content: &str,
4584    ) -> Location {
4585        let cur_code = &code[offset..];
4586
4587        let start = offset
4588            + cur_code
4589                .find(content)
4590                .unwrap_or_else(|| panic!("expected `{content}` from `{cur_code}`"));
4591
4592        Location {
4593            file_path,
4594            start,
4595            end: start + content.len(),
4596        }
4597    }
4598}