pin_project_internal/
utils.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use std::mem;
4
5use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
6use quote::{quote, quote_spanned, ToTokens};
7use syn::{
8    parse::{Parse, ParseBuffer, ParseStream},
9    parse_quote,
10    punctuated::Punctuated,
11    token,
12    visit_mut::{self, VisitMut},
13    Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeParam, Macro,
14    PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type,
15    TypeParamBound, TypePath, Variant, Visibility, WherePredicate,
16};
17
18pub(crate) type Variants = Punctuated<Variant, Token![,]>;
19
20macro_rules! parse_quote_spanned {
21    ($span:expr => $($tt:tt)*) => {
22        syn::parse2(quote::quote_spanned!($span => $($tt)*)).unwrap_or_else(|e| panic!("{}", e))
23    };
24}
25
26/// Determines the lifetime names. Ensure it doesn't overlap with any existing
27/// lifetime names.
28pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut Generics) {
29    struct CollectLifetimes(Vec<String>);
30
31    impl VisitMut for CollectLifetimes {
32        fn visit_lifetime_param_mut(&mut self, def: &mut LifetimeParam) {
33            self.0.push(def.lifetime.to_string());
34        }
35    }
36
37    debug_assert!(lifetime_name.starts_with('\''));
38
39    let mut lifetimes = CollectLifetimes(vec![]);
40    lifetimes.visit_generics_mut(generics);
41
42    while lifetimes.0.iter().any(|name| name.starts_with(&**lifetime_name)) {
43        lifetime_name.push('_');
44    }
45}
46
47/// Like `insert_lifetime`, but also generates a bound of the form
48/// `OriginalType<A, B>: 'lifetime`. Used when generating the definition
49/// of a projection type
50pub(crate) fn insert_lifetime_and_bound(
51    generics: &mut Generics,
52    lifetime: Lifetime,
53    orig_generics: &Generics,
54    orig_ident: &Ident,
55) -> WherePredicate {
56    insert_lifetime(generics, lifetime.clone());
57
58    let orig_type: Type = parse_quote!(#orig_ident #orig_generics);
59    let mut punct = Punctuated::new();
60    punct.push(TypeParamBound::Lifetime(lifetime));
61
62    WherePredicate::Type(PredicateType {
63        lifetimes: None,
64        bounded_ty: orig_type,
65        colon_token: <Token![:]>::default(),
66        bounds: punct,
67    })
68}
69
70/// Inserts a `lifetime` at position `0` of `generics.params`.
71pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
72    generics.lt_token.get_or_insert_with(<Token![<]>::default);
73    generics.gt_token.get_or_insert_with(<Token![>]>::default);
74    generics.params.insert(0, LifetimeParam::new(lifetime).into());
75}
76
77/// Determines the visibility of the projected types and projection methods.
78///
79/// If given visibility is `pub`, returned visibility is `pub(crate)`.
80/// Otherwise, returned visibility is the same as given visibility.
81pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
82    if let Visibility::Public(token) = vis {
83        parse_quote_spanned!(token.span => pub(crate))
84    } else {
85        vis.clone()
86    }
87}
88
89pub(crate) fn respan<T>(node: &T, span: Span) -> T
90where
91    T: ToTokens + Parse,
92{
93    let tokens = node.to_token_stream();
94    let respanned = respan_tokens(tokens, span);
95    syn::parse2(respanned).unwrap()
96}
97
98fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream {
99    tokens
100        .into_iter()
101        .map(|mut token| {
102            token.set_span(span);
103            token
104        })
105        .collect()
106}
107
108// -----------------------------------------------------------------------------
109// extension traits
110
111pub(crate) trait SliceExt {
112    fn position_exact(&self, ident: &str) -> Result<Option<usize>>;
113    fn find(&self, ident: &str) -> Option<&Attribute>;
114}
115
116impl SliceExt for [Attribute] {
117    /// # Errors
118    ///
119    /// - There are multiple specified attributes.
120    /// - The `Attribute::tokens` field of the specified attribute is not empty.
121    fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
122        self.iter()
123            .try_fold((0, None), |(i, mut prev), attr| {
124                if attr.path().is_ident(ident) {
125                    if prev.replace(i).is_some() {
126                        bail!(attr, "duplicate #[{}] attribute", ident);
127                    }
128                    attr.meta.require_path_only()?;
129                }
130                Ok((i + 1, prev))
131            })
132            .map(|(_, pos)| pos)
133    }
134
135    fn find(&self, ident: &str) -> Option<&Attribute> {
136        self.iter().position(|attr| attr.path().is_ident(ident)).map(|i| &self[i])
137    }
138}
139
140pub(crate) trait ParseBufferExt<'a> {
141    fn parenthesized(self) -> Result<ParseBuffer<'a>>;
142}
143
144impl<'a> ParseBufferExt<'a> for ParseStream<'a> {
145    fn parenthesized(self) -> Result<ParseBuffer<'a>> {
146        let content;
147        let _: token::Paren = syn::parenthesized!(content in self);
148        Ok(content)
149    }
150}
151
152impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
153    fn parenthesized(self) -> Result<ParseBuffer<'a>> {
154        let content;
155        let _: token::Paren = syn::parenthesized!(content in self);
156        Ok(content)
157    }
158}
159
160// -----------------------------------------------------------------------------
161// visitors
162
163// Replace `self`/`Self` with `__self`/`self_ty`.
164// Based on:
165// - https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs
166// - https://github.com/dtolnay/async-trait/commit/6029cbf375c562ca98fa5748e9d950a8ff93b0e7
167
168pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath);
169
170impl ReplaceReceiver<'_> {
171    fn self_ty(&self, span: Span) -> TypePath {
172        respan(self.0, span)
173    }
174
175    fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
176        if path.leading_colon.is_some() {
177            return;
178        }
179
180        let first = &path.segments[0];
181        if first.ident != "Self" || !first.arguments.is_empty() {
182            return;
183        }
184
185        if path.segments.len() == 1 {
186            self.self_to_expr_path(path);
187            return;
188        }
189
190        let span = first.ident.span();
191        *qself = Some(QSelf {
192            lt_token: Token![<](span),
193            ty: Box::new(self.self_ty(span).into()),
194            position: 0,
195            as_token: None,
196            gt_token: Token![>](span),
197        });
198
199        path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
200
201        let segments = mem::take(&mut path.segments);
202        path.segments = segments.into_pairs().skip(1).collect();
203    }
204
205    fn self_to_expr_path(&self, path: &mut Path) {
206        if path.leading_colon.is_some() {
207            return;
208        }
209
210        let first = &path.segments[0];
211        if first.ident != "Self" || !first.arguments.is_empty() {
212            return;
213        }
214
215        let self_ty = self.self_ty(first.ident.span());
216        let variant = mem::replace(path, self_ty.path);
217        for segment in &mut path.segments {
218            if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
219                if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
220                    bracketed.colon2_token = Some(<Token![::]>::default());
221                }
222            }
223        }
224        if variant.segments.len() > 1 {
225            path.segments.push_punct(<Token![::]>::default());
226            path.segments.extend(variant.segments.into_pairs().skip(1));
227        }
228    }
229
230    fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
231        let mut out = vec![];
232        let mut modified = false;
233        let mut iter = tokens.clone().into_iter().peekable();
234        while let Some(tt) = iter.next() {
235            match tt {
236                TokenTree::Ident(mut ident) => {
237                    modified |= prepend_underscore_to_self(&mut ident);
238                    if ident == "Self" {
239                        modified = true;
240                        let self_ty = self.self_ty(ident.span());
241                        match iter.peek() {
242                            Some(TokenTree::Punct(p))
243                                if p.as_char() == ':' && p.spacing() == Spacing::Joint =>
244                            {
245                                let next = iter.next().unwrap();
246                                match iter.peek() {
247                                    Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
248                                        let span = ident.span();
249                                        out.extend(quote_spanned!(span=> <#self_ty>));
250                                    }
251                                    _ => out.extend(quote!(#self_ty)),
252                                }
253                                out.push(next);
254                            }
255                            _ => out.extend(quote!(#self_ty)),
256                        }
257                    } else {
258                        out.push(TokenTree::Ident(ident));
259                    }
260                }
261                TokenTree::Group(group) => {
262                    let mut content = group.stream();
263                    modified |= self.visit_token_stream(&mut content);
264                    let mut new = Group::new(group.delimiter(), content);
265                    new.set_span(group.span());
266                    out.push(TokenTree::Group(new));
267                }
268                other => out.push(other),
269            }
270        }
271        if modified {
272            *tokens = TokenStream::from_iter(out);
273        }
274        modified
275    }
276}
277
278impl VisitMut for ReplaceReceiver<'_> {
279    // `Self` -> `Receiver`
280    fn visit_type_mut(&mut self, ty: &mut Type) {
281        if let Type::Path(node) = ty {
282            if node.qself.is_none() && node.path.is_ident("Self") {
283                *ty = self.self_ty(node.path.segments[0].ident.span()).into();
284            } else {
285                self.visit_type_path_mut(node);
286            }
287        } else {
288            visit_mut::visit_type_mut(self, ty);
289        }
290    }
291
292    // `Self::Assoc` -> `<Receiver>::Assoc`
293    fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
294        if ty.qself.is_none() {
295            self.self_to_qself(&mut ty.qself, &mut ty.path);
296        }
297        visit_mut::visit_type_path_mut(self, ty);
298    }
299
300    // `Self::method` -> `<Receiver>::method`
301    fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
302        if expr.qself.is_none() {
303            self.self_to_qself(&mut expr.qself, &mut expr.path);
304        }
305        visit_mut::visit_expr_path_mut(self, expr);
306    }
307
308    fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
309        self.self_to_expr_path(&mut expr.path);
310        visit_mut::visit_expr_struct_mut(self, expr);
311    }
312
313    fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
314        self.self_to_expr_path(&mut pat.path);
315        visit_mut::visit_pat_struct_mut(self, pat);
316    }
317
318    fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
319        self.self_to_expr_path(&mut pat.path);
320        visit_mut::visit_pat_tuple_struct_mut(self, pat);
321    }
322
323    fn visit_path_mut(&mut self, path: &mut Path) {
324        if path.segments.len() == 1 {
325            // Replace `self`, but not `self::function`.
326            prepend_underscore_to_self(&mut path.segments[0].ident);
327        }
328        for segment in &mut path.segments {
329            self.visit_path_arguments_mut(&mut segment.arguments);
330        }
331    }
332
333    fn visit_item_mut(&mut self, item: &mut Item) {
334        match item {
335            // Visit `macro_rules!` because locally defined macros can refer to `self`.
336            Item::Macro(item) if item.mac.path.is_ident("macro_rules") => {
337                self.visit_macro_mut(&mut item.mac);
338            }
339            // Otherwise, do not recurse into nested items.
340            _ => {}
341        }
342    }
343
344    fn visit_macro_mut(&mut self, mac: &mut Macro) {
345        // We can't tell in general whether `self` inside a macro invocation
346        // refers to the self in the argument list or a different self
347        // introduced within the macro. Heuristic: if the macro input contains
348        // `fn`, then `self` is more likely to refer to something other than the
349        // outer function's self argument.
350        if !contains_fn(mac.tokens.clone()) {
351            self.visit_token_stream(&mut mac.tokens);
352        }
353    }
354}
355
356fn contains_fn(tokens: TokenStream) -> bool {
357    tokens.into_iter().any(|tt| match tt {
358        TokenTree::Ident(ident) => ident == "fn",
359        TokenTree::Group(group) => contains_fn(group.stream()),
360        _ => false,
361    })
362}
363
364pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
365    let modified = ident == "self";
366    if modified {
367        *ident = Ident::new("__self", ident.span());
368    }
369    modified
370}