Skip to main content

syn_locator/
loc.rs

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