1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 use proc_macro2::{Ident, TokenStream}; 4 use quote::{format_ident, ToTokens}; 5 use syn::{Attribute, GenericParam, Generics, Index, Member, Token}; 6 7 use crate::DiagCtxt; 8 9 pub(crate) trait AttrListExt { 10 fn extract_cfg_attrs(&mut self) -> Vec<TokenStream>; 11 12 /// Extract attribute with identifier `path`. 13 /// 14 /// Report error if the attribute appears multiple times. 15 fn extract_single_attr(&mut self, dcx: &DiagCtxt, path: &str) -> Option<Attribute>; 16 } 17 18 impl AttrListExt for Vec<Attribute> { 19 fn extract_cfg_attrs(&mut self) -> Vec<TokenStream> { 20 let cfg: Vec<_> = self 21 .iter() 22 .filter(|a| a.path().is_ident("cfg")) 23 .map(|a| { 24 a.parse_args::<TokenStream>() 25 .expect("parse as token stream cannot fail") 26 }) 27 .collect(); 28 29 if !cfg.is_empty() { 30 self.retain(|a| !a.path().is_ident("cfg")); 31 } 32 33 cfg 34 } 35 36 fn extract_single_attr(&mut self, dcx: &DiagCtxt, path: &str) -> Option<Attribute> { 37 // FIXME: Replace with `extract_if` when MSRV >= 1.85. 38 let attr_pos = self.iter().position(|attr| attr.path().is_ident(path))?; 39 let attr = self.remove(attr_pos); 40 self.retain(|attr| { 41 if !attr.path().is_ident(path) { 42 return true; 43 } 44 45 dcx.error( 46 attr, 47 format!("`#[{path}]` attribute specified more than once"), 48 ); 49 false 50 }); 51 Some(attr) 52 } 53 } 54 55 pub(crate) trait MemberExt { 56 /// Returns an identifier for the member. 57 /// 58 /// Tuple fields have no name of their own, so they are named `_0`, `_1`, ... instead. 59 fn as_ident(&self) -> Ident; 60 61 /// Obtain a display name for the member in diagnostics. 62 fn display_name(&self) -> String; 63 } 64 65 impl MemberExt for Member { 66 fn as_ident(&self) -> Ident { 67 match self { 68 Member::Named(ident) => ident.clone(), 69 Member::Unnamed(Index { index, span }) => format_ident!("_{index}", span = *span), 70 } 71 } 72 73 fn display_name(&self) -> String { 74 match self { 75 Member::Named(ident) => format!("`{ident}`"), 76 Member::Unnamed(Index { index, .. }) => format!("index `{index}`"), 77 } 78 } 79 } 80 81 pub(crate) struct CombinedGenerics<'a>(pub(crate) Vec<&'a Generics>); 82 pub(crate) struct CombinedImplGenerics<'a>(&'a CombinedGenerics<'a>); 83 pub(crate) struct CombinedTypeGenerics<'a>(&'a CombinedGenerics<'a>); 84 85 impl CombinedGenerics<'_> { 86 pub(crate) fn split_for_impl( 87 &self, 88 ) -> ( 89 CombinedImplGenerics<'_>, 90 CombinedTypeGenerics<'_>, 91 // A stub type so `split_for_impl` signature matches that of `syn`'s. 92 impl Sized, 93 ) { 94 (CombinedImplGenerics(self), CombinedTypeGenerics(self), ()) 95 } 96 } 97 98 impl ToTokens for CombinedGenerics<'_> { 99 fn to_tokens(&self, tokens: &mut TokenStream) { 100 // Most of the time we are only adding lifetimes, so we prefer to place 101 // the user provided generics last. 102 self.0 103 .last() 104 .and_then(|x| x.lt_token) 105 .unwrap_or_default() 106 .to_tokens(tokens); 107 108 let comma: Token![,] = Default::default(); 109 110 // Output lifetimes first. 111 for generics in self.0.iter() { 112 for param in generics.params.pairs() { 113 if let GenericParam::Lifetime(lt) = param.value() { 114 lt.to_tokens(tokens); 115 param.punct().unwrap_or(&&comma).to_tokens(tokens); 116 } 117 } 118 } 119 120 for generics in self.0.iter() { 121 for param in generics.params.pairs() { 122 if let GenericParam::Lifetime(_) = param.value() { 123 continue; 124 }; 125 param.value().to_tokens(tokens); 126 param.punct().unwrap_or(&&comma).to_tokens(tokens); 127 } 128 } 129 130 self.0 131 .last() 132 .and_then(|x| x.gt_token) 133 .unwrap_or_default() 134 .to_tokens(tokens); 135 } 136 } 137 138 impl ToTokens for CombinedImplGenerics<'_> { 139 fn to_tokens(&self, tokens: &mut TokenStream) { 140 self.0 141 .0 142 .last() 143 .and_then(|x| x.lt_token) 144 .unwrap_or_default() 145 .to_tokens(tokens); 146 147 let comma: Token![,] = Default::default(); 148 149 // Output lifetimes first. 150 for generics in self.0 .0.iter() { 151 for param in generics.params.pairs() { 152 if let GenericParam::Lifetime(lt) = param.value() { 153 lt.to_tokens(tokens); 154 param.punct().unwrap_or(&&comma).to_tokens(tokens); 155 } 156 } 157 } 158 159 for generics in self.0 .0.iter() { 160 for param in generics.params.pairs() { 161 // Leave out defaults. 162 match param.value() { 163 GenericParam::Lifetime(_) => continue, 164 GenericParam::Type(param) => { 165 param.ident.to_tokens(tokens); 166 if !param.bounds.is_empty() { 167 param 168 .colon_token 169 .unwrap_or_else(Default::default) 170 .to_tokens(tokens); 171 param.bounds.to_tokens(tokens); 172 } 173 } 174 GenericParam::Const(param) => { 175 param.const_token.to_tokens(tokens); 176 param.ident.to_tokens(tokens); 177 param.colon_token.to_tokens(tokens); 178 param.ty.to_tokens(tokens); 179 } 180 } 181 param.punct().unwrap_or(&&comma).to_tokens(tokens); 182 } 183 } 184 185 self.0 186 .0 187 .last() 188 .and_then(|x| x.gt_token) 189 .unwrap_or_default() 190 .to_tokens(tokens); 191 } 192 } 193 194 impl ToTokens for CombinedTypeGenerics<'_> { 195 fn to_tokens(&self, tokens: &mut TokenStream) { 196 self.0 197 .0 198 .last() 199 .and_then(|x| x.lt_token) 200 .unwrap_or_default() 201 .to_tokens(tokens); 202 203 let comma: Token![,] = Default::default(); 204 205 // Output lifetimes first. 206 for generics in self.0 .0.iter() { 207 for param in generics.params.pairs() { 208 if let GenericParam::Lifetime(lt) = param.value() { 209 // Leave out bounds 210 lt.lifetime.to_tokens(tokens); 211 param.punct().unwrap_or(&&comma).to_tokens(tokens); 212 } 213 } 214 } 215 216 for generics in self.0 .0.iter() { 217 for param in generics.params.pairs() { 218 // Leave out bounds and defaults. 219 match param.value() { 220 GenericParam::Lifetime(_) => continue, 221 GenericParam::Type(param) => { 222 param.ident.to_tokens(tokens); 223 } 224 GenericParam::Const(param) => { 225 param.ident.to_tokens(tokens); 226 } 227 } 228 param.punct().unwrap_or(&&comma).to_tokens(tokens); 229 } 230 } 231 232 self.0 233 .0 234 .last() 235 .and_then(|x| x.gt_token) 236 .unwrap_or_default() 237 .to_tokens(tokens); 238 } 239 } 240