Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 1 | // A signature is a string representation of an item's type signature, excluding |
| 2 | // any body. It also includes ids for any defs or refs in the signature. For |
| 3 | // example: |
| 4 | // |
| 5 | // ``` |
| 6 | // fn foo(x: String) { |
| 7 | // println!("{}", x); |
| 8 | // } |
| 9 | // ``` |
| 10 | // The signature string is something like "fn foo(x: String) {}" and the signature |
| 11 | // will have defs for `foo` and `x` and a ref for `String`. |
| 12 | // |
| 13 | // All signature text should parse in the correct context (i.e., in a module or |
| 14 | // impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a |
| 15 | // signature is not guaranteed to be stable (it may improve or change as the |
| 16 | // syntax changes, or whitespace or punctuation may change). It is also likely |
| 17 | // not to be pretty - no attempt is made to prettify the text. It is recommended |
| 18 | // that clients run the text through Rustfmt. |
| 19 | // |
| 20 | // This module generates Signatures for items by walking the AST and looking up |
| 21 | // references. |
| 22 | // |
| 23 | // Signatures do not include visibility info. I'm not sure if this is a feature |
Jeff Vander Stoep | d59a287 | 2021-02-15 10:22:21 +0100 | [diff] [blame] | 24 | // or an omission (FIXME). |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 25 | // |
| 26 | // FIXME where clauses need implementing, defs/refs in generics are mostly missing. |
| 27 | |
| 28 | use crate::{id_from_def_id, id_from_hir_id, SaveContext}; |
| 29 | |
| 30 | use rls_data::{SigElement, Signature}; |
| 31 | |
| 32 | use rustc_ast::Mutability; |
| 33 | use rustc_hir as hir; |
| 34 | use rustc_hir::def::{DefKind, Res}; |
| 35 | use rustc_hir_pretty::id_to_string; |
| 36 | use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string}; |
| 37 | use rustc_span::symbol::{Ident, Symbol}; |
| 38 | |
| 39 | pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
| 40 | if !scx.config.signatures { |
| 41 | return None; |
| 42 | } |
| 43 | item.make(0, None, scx).ok() |
| 44 | } |
| 45 | |
| 46 | pub fn foreign_item_signature( |
| 47 | item: &hir::ForeignItem<'_>, |
| 48 | scx: &SaveContext<'_>, |
| 49 | ) -> Option<Signature> { |
| 50 | if !scx.config.signatures { |
| 51 | return None; |
| 52 | } |
| 53 | item.make(0, None, scx).ok() |
| 54 | } |
| 55 | |
| 56 | /// Signature for a struct or tuple field declaration. |
| 57 | /// Does not include a trailing comma. |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 58 | pub fn field_signature(field: &hir::FieldDef<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 59 | if !scx.config.signatures { |
| 60 | return None; |
| 61 | } |
| 62 | field.make(0, None, scx).ok() |
| 63 | } |
| 64 | |
| 65 | /// Does not include a trailing comma. |
| 66 | pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> Option<Signature> { |
| 67 | if !scx.config.signatures { |
| 68 | return None; |
| 69 | } |
| 70 | variant.make(0, None, scx).ok() |
| 71 | } |
| 72 | |
| 73 | pub fn method_signature( |
| 74 | id: hir::HirId, |
| 75 | ident: Ident, |
| 76 | generics: &hir::Generics<'_>, |
| 77 | m: &hir::FnSig<'_>, |
| 78 | scx: &SaveContext<'_>, |
| 79 | ) -> Option<Signature> { |
| 80 | if !scx.config.signatures { |
| 81 | return None; |
| 82 | } |
| 83 | make_method_signature(id, ident, generics, m, scx).ok() |
| 84 | } |
| 85 | |
| 86 | pub fn assoc_const_signature( |
| 87 | id: hir::HirId, |
| 88 | ident: Symbol, |
| 89 | ty: &hir::Ty<'_>, |
| 90 | default: Option<&hir::Expr<'_>>, |
| 91 | scx: &SaveContext<'_>, |
| 92 | ) -> Option<Signature> { |
| 93 | if !scx.config.signatures { |
| 94 | return None; |
| 95 | } |
| 96 | make_assoc_const_signature(id, ident, ty, default, scx).ok() |
| 97 | } |
| 98 | |
| 99 | pub fn assoc_type_signature( |
| 100 | id: hir::HirId, |
| 101 | ident: Ident, |
| 102 | bounds: Option<hir::GenericBounds<'_>>, |
| 103 | default: Option<&hir::Ty<'_>>, |
| 104 | scx: &SaveContext<'_>, |
| 105 | ) -> Option<Signature> { |
| 106 | if !scx.config.signatures { |
| 107 | return None; |
| 108 | } |
| 109 | make_assoc_type_signature(id, ident, bounds, default, scx).ok() |
| 110 | } |
| 111 | |
| 112 | type Result = std::result::Result<Signature, &'static str>; |
| 113 | |
| 114 | trait Sig { |
| 115 | fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result; |
| 116 | } |
| 117 | |
| 118 | fn extend_sig( |
| 119 | mut sig: Signature, |
| 120 | text: String, |
| 121 | defs: Vec<SigElement>, |
| 122 | refs: Vec<SigElement>, |
| 123 | ) -> Signature { |
| 124 | sig.text = text; |
| 125 | sig.defs.extend(defs.into_iter()); |
| 126 | sig.refs.extend(refs.into_iter()); |
| 127 | sig |
| 128 | } |
| 129 | |
| 130 | fn replace_text(mut sig: Signature, text: String) -> Signature { |
| 131 | sig.text = text; |
| 132 | sig |
| 133 | } |
| 134 | |
| 135 | fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature { |
| 136 | let mut result = Signature { text, defs: vec![], refs: vec![] }; |
| 137 | |
| 138 | let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip(); |
| 139 | |
| 140 | result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter())); |
| 141 | result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter())); |
| 142 | |
| 143 | result |
| 144 | } |
| 145 | |
| 146 | fn text_sig(text: String) -> Signature { |
| 147 | Signature { text, defs: vec![], refs: vec![] } |
| 148 | } |
| 149 | |
| 150 | impl<'hir> Sig for hir::Ty<'hir> { |
| 151 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
| 152 | let id = Some(self.hir_id); |
| 153 | match self.kind { |
| 154 | hir::TyKind::Slice(ref ty) => { |
| 155 | let nested = ty.make(offset + 1, id, scx)?; |
| 156 | let text = format!("[{}]", nested.text); |
| 157 | Ok(replace_text(nested, text)) |
| 158 | } |
| 159 | hir::TyKind::Ptr(ref mt) => { |
| 160 | let prefix = match mt.mutbl { |
| 161 | hir::Mutability::Mut => "*mut ", |
| 162 | hir::Mutability::Not => "*const ", |
| 163 | }; |
| 164 | let nested = mt.ty.make(offset + prefix.len(), id, scx)?; |
| 165 | let text = format!("{}{}", prefix, nested.text); |
| 166 | Ok(replace_text(nested, text)) |
| 167 | } |
| 168 | hir::TyKind::Rptr(ref lifetime, ref mt) => { |
| 169 | let mut prefix = "&".to_owned(); |
| 170 | prefix.push_str(&lifetime.name.ident().to_string()); |
| 171 | prefix.push(' '); |
| 172 | if let hir::Mutability::Mut = mt.mutbl { |
| 173 | prefix.push_str("mut "); |
| 174 | }; |
| 175 | |
| 176 | let nested = mt.ty.make(offset + prefix.len(), id, scx)?; |
| 177 | let text = format!("{}{}", prefix, nested.text); |
| 178 | Ok(replace_text(nested, text)) |
| 179 | } |
| 180 | hir::TyKind::Never => Ok(text_sig("!".to_owned())), |
| 181 | hir::TyKind::Tup(ts) => { |
| 182 | let mut text = "(".to_owned(); |
| 183 | let mut defs = vec![]; |
| 184 | let mut refs = vec![]; |
| 185 | for t in ts { |
| 186 | let nested = t.make(offset + text.len(), id, scx)?; |
| 187 | text.push_str(&nested.text); |
| 188 | text.push(','); |
| 189 | defs.extend(nested.defs.into_iter()); |
| 190 | refs.extend(nested.refs.into_iter()); |
| 191 | } |
| 192 | text.push(')'); |
| 193 | Ok(Signature { text, defs, refs }) |
| 194 | } |
| 195 | hir::TyKind::BareFn(ref f) => { |
| 196 | let mut text = String::new(); |
| 197 | if !f.generic_params.is_empty() { |
| 198 | // FIXME defs, bounds on lifetimes |
| 199 | text.push_str("for<"); |
| 200 | text.push_str( |
| 201 | &f.generic_params |
| 202 | .iter() |
| 203 | .filter_map(|param| match param.kind { |
| 204 | hir::GenericParamKind::Lifetime { .. } => { |
| 205 | Some(param.name.ident().to_string()) |
| 206 | } |
| 207 | _ => None, |
| 208 | }) |
| 209 | .collect::<Vec<_>>() |
| 210 | .join(", "), |
| 211 | ); |
| 212 | text.push('>'); |
| 213 | } |
| 214 | |
| 215 | if let hir::Unsafety::Unsafe = f.unsafety { |
| 216 | text.push_str("unsafe "); |
| 217 | } |
| 218 | text.push_str("fn("); |
| 219 | |
| 220 | let mut defs = vec![]; |
| 221 | let mut refs = vec![]; |
| 222 | for i in f.decl.inputs { |
| 223 | let nested = i.make(offset + text.len(), Some(i.hir_id), scx)?; |
| 224 | text.push_str(&nested.text); |
| 225 | text.push(','); |
| 226 | defs.extend(nested.defs.into_iter()); |
| 227 | refs.extend(nested.refs.into_iter()); |
| 228 | } |
| 229 | text.push(')'); |
| 230 | if let hir::FnRetTy::Return(ref t) = f.decl.output { |
| 231 | text.push_str(" -> "); |
| 232 | let nested = t.make(offset + text.len(), None, scx)?; |
| 233 | text.push_str(&nested.text); |
| 234 | text.push(','); |
| 235 | defs.extend(nested.defs.into_iter()); |
| 236 | refs.extend(nested.refs.into_iter()); |
| 237 | } |
| 238 | |
| 239 | Ok(Signature { text, defs, refs }) |
| 240 | } |
| 241 | hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.make(offset, id, scx), |
| 242 | hir::TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref path)) => { |
| 243 | let nested_ty = qself.make(offset + 1, id, scx)?; |
| 244 | let prefix = format!( |
| 245 | "<{} as {}>::", |
| 246 | nested_ty.text, |
| 247 | path_segment_to_string(&path.segments[0]) |
| 248 | ); |
| 249 | |
| 250 | let name = path_segment_to_string(path.segments.last().ok_or("Bad path")?); |
| 251 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
| 252 | let id = id_from_def_id(res.def_id()); |
| 253 | if path.segments.len() == 2 { |
| 254 | let start = offset + prefix.len(); |
| 255 | let end = start + name.len(); |
| 256 | |
| 257 | Ok(Signature { |
| 258 | text: prefix + &name, |
| 259 | defs: vec![], |
| 260 | refs: vec![SigElement { id, start, end }], |
| 261 | }) |
| 262 | } else { |
| 263 | let start = offset + prefix.len() + 5; |
| 264 | let end = start + name.len(); |
Thiébaud Weksteen | 5bd94c1 | 2021-01-06 15:18:42 +0100 | [diff] [blame] | 265 | // FIXME should put the proper path in there, not ellipsis. |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 266 | Ok(Signature { |
| 267 | text: prefix + "...::" + &name, |
| 268 | defs: vec![], |
| 269 | refs: vec![SigElement { id, start, end }], |
| 270 | }) |
| 271 | } |
| 272 | } |
| 273 | hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { |
| 274 | let nested_ty = ty.make(offset + 1, id, scx)?; |
Thiébaud Weksteen | 5bd94c1 | 2021-01-06 15:18:42 +0100 | [diff] [blame] | 275 | let prefix = format!("<{}>::", nested_ty.text); |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 276 | |
| 277 | let name = path_segment_to_string(segment); |
| 278 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
| 279 | let id = id_from_def_id(res.def_id()); |
| 280 | |
| 281 | let start = offset + prefix.len(); |
| 282 | let end = start + name.len(); |
| 283 | Ok(Signature { |
| 284 | text: prefix + &name, |
| 285 | defs: vec![], |
| 286 | refs: vec![SigElement { id, start, end }], |
| 287 | }) |
| 288 | } |
| 289 | hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { |
| 290 | Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name()))) |
| 291 | } |
| 292 | hir::TyKind::TraitObject(bounds, ..) => { |
| 293 | // FIXME recurse into bounds |
| 294 | let bounds: Vec<hir::GenericBound<'_>> = bounds |
| 295 | .iter() |
| 296 | .map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| { |
| 297 | hir::GenericBound::Trait( |
| 298 | hir::PolyTraitRef { |
| 299 | bound_generic_params, |
| 300 | trait_ref: hir::TraitRef { |
| 301 | path: trait_ref.path, |
| 302 | hir_ref_id: trait_ref.hir_ref_id, |
| 303 | }, |
| 304 | span: *span, |
| 305 | }, |
| 306 | hir::TraitBoundModifier::None, |
| 307 | ) |
| 308 | }) |
| 309 | .collect(); |
| 310 | let nested = bounds_to_string(&bounds); |
| 311 | Ok(text_sig(nested)) |
| 312 | } |
| 313 | hir::TyKind::Array(ref ty, ref anon_const) => { |
| 314 | let nested_ty = ty.make(offset + 1, id, scx)?; |
| 315 | let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); |
| 316 | let text = format!("[{}; {}]", nested_ty.text, expr); |
| 317 | Ok(replace_text(nested_ty, text)) |
| 318 | } |
| 319 | hir::TyKind::OpaqueDef(item_id, _) => { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 320 | let item = scx.tcx.hir().item(item_id); |
| 321 | item.make(offset, Some(item_id.hir_id()), scx) |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 322 | } |
| 323 | hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"), |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | impl<'hir> Sig for hir::Item<'hir> { |
| 329 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 330 | let id = Some(self.hir_id()); |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 331 | |
| 332 | match self.kind { |
| 333 | hir::ItemKind::Static(ref ty, m, ref body) => { |
| 334 | let mut text = "static ".to_owned(); |
| 335 | if m == hir::Mutability::Mut { |
| 336 | text.push_str("mut "); |
| 337 | } |
| 338 | let name = self.ident.to_string(); |
| 339 | let defs = vec![SigElement { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 340 | id: id_from_def_id(self.def_id.to_def_id()), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 341 | start: offset + text.len(), |
| 342 | end: offset + text.len() + name.len(), |
| 343 | }]; |
| 344 | text.push_str(&name); |
| 345 | text.push_str(": "); |
| 346 | |
| 347 | let ty = ty.make(offset + text.len(), id, scx)?; |
| 348 | text.push_str(&ty.text); |
| 349 | |
| 350 | text.push_str(" = "); |
| 351 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); |
| 352 | text.push_str(&expr); |
| 353 | |
| 354 | text.push(';'); |
| 355 | |
| 356 | Ok(extend_sig(ty, text, defs, vec![])) |
| 357 | } |
| 358 | hir::ItemKind::Const(ref ty, ref body) => { |
| 359 | let mut text = "const ".to_owned(); |
| 360 | let name = self.ident.to_string(); |
| 361 | let defs = vec![SigElement { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 362 | id: id_from_def_id(self.def_id.to_def_id()), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 363 | start: offset + text.len(), |
| 364 | end: offset + text.len() + name.len(), |
| 365 | }]; |
| 366 | text.push_str(&name); |
| 367 | text.push_str(": "); |
| 368 | |
| 369 | let ty = ty.make(offset + text.len(), id, scx)?; |
| 370 | text.push_str(&ty.text); |
| 371 | |
| 372 | text.push_str(" = "); |
| 373 | let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " "); |
| 374 | text.push_str(&expr); |
| 375 | |
| 376 | text.push(';'); |
| 377 | |
| 378 | Ok(extend_sig(ty, text, defs, vec![])) |
| 379 | } |
| 380 | hir::ItemKind::Fn(hir::FnSig { ref decl, header, span: _ }, ref generics, _) => { |
| 381 | let mut text = String::new(); |
| 382 | if let hir::Constness::Const = header.constness { |
| 383 | text.push_str("const "); |
| 384 | } |
| 385 | if hir::IsAsync::Async == header.asyncness { |
| 386 | text.push_str("async "); |
| 387 | } |
| 388 | if let hir::Unsafety::Unsafe = header.unsafety { |
| 389 | text.push_str("unsafe "); |
| 390 | } |
| 391 | text.push_str("fn "); |
| 392 | |
| 393 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 394 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 395 | |
| 396 | sig.text.push('('); |
| 397 | for i in decl.inputs { |
| 398 | // FIXME should descend into patterns to add defs. |
| 399 | sig.text.push_str(": "); |
| 400 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
| 401 | sig.text.push_str(&nested.text); |
| 402 | sig.text.push(','); |
| 403 | sig.defs.extend(nested.defs.into_iter()); |
| 404 | sig.refs.extend(nested.refs.into_iter()); |
| 405 | } |
| 406 | sig.text.push(')'); |
| 407 | |
| 408 | if let hir::FnRetTy::Return(ref t) = decl.output { |
| 409 | sig.text.push_str(" -> "); |
| 410 | let nested = t.make(offset + sig.text.len(), None, scx)?; |
| 411 | sig.text.push_str(&nested.text); |
| 412 | sig.defs.extend(nested.defs.into_iter()); |
| 413 | sig.refs.extend(nested.refs.into_iter()); |
| 414 | } |
| 415 | sig.text.push_str(" {}"); |
| 416 | |
| 417 | Ok(sig) |
| 418 | } |
| 419 | hir::ItemKind::Mod(ref _mod) => { |
| 420 | let mut text = "mod ".to_owned(); |
| 421 | let name = self.ident.to_string(); |
| 422 | let defs = vec![SigElement { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 423 | id: id_from_def_id(self.def_id.to_def_id()), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 424 | start: offset + text.len(), |
| 425 | end: offset + text.len() + name.len(), |
| 426 | }]; |
| 427 | text.push_str(&name); |
| 428 | // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one. |
| 429 | text.push(';'); |
| 430 | |
| 431 | Ok(Signature { text, defs, refs: vec![] }) |
| 432 | } |
| 433 | hir::ItemKind::TyAlias(ref ty, ref generics) => { |
| 434 | let text = "type ".to_owned(); |
| 435 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 436 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 437 | |
| 438 | sig.text.push_str(" = "); |
| 439 | let ty = ty.make(offset + sig.text.len(), id, scx)?; |
| 440 | sig.text.push_str(&ty.text); |
| 441 | sig.text.push(';'); |
| 442 | |
| 443 | Ok(merge_sigs(sig.text.clone(), vec![sig, ty])) |
| 444 | } |
| 445 | hir::ItemKind::Enum(_, ref generics) => { |
| 446 | let text = "enum ".to_owned(); |
| 447 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 448 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 449 | sig.text.push_str(" {}"); |
| 450 | Ok(sig) |
| 451 | } |
| 452 | hir::ItemKind::Struct(_, ref generics) => { |
| 453 | let text = "struct ".to_owned(); |
| 454 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 455 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 456 | sig.text.push_str(" {}"); |
| 457 | Ok(sig) |
| 458 | } |
| 459 | hir::ItemKind::Union(_, ref generics) => { |
| 460 | let text = "union ".to_owned(); |
| 461 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 462 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 463 | sig.text.push_str(" {}"); |
| 464 | Ok(sig) |
| 465 | } |
| 466 | hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => { |
| 467 | let mut text = String::new(); |
| 468 | |
| 469 | if is_auto == hir::IsAuto::Yes { |
| 470 | text.push_str("auto "); |
| 471 | } |
| 472 | |
| 473 | if let hir::Unsafety::Unsafe = unsafety { |
| 474 | text.push_str("unsafe "); |
| 475 | } |
| 476 | text.push_str("trait "); |
| 477 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 478 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 479 | |
| 480 | if !bounds.is_empty() { |
| 481 | sig.text.push_str(": "); |
| 482 | sig.text.push_str(&bounds_to_string(bounds)); |
| 483 | } |
| 484 | // FIXME where clause |
| 485 | sig.text.push_str(" {}"); |
| 486 | |
| 487 | Ok(sig) |
| 488 | } |
| 489 | hir::ItemKind::TraitAlias(ref generics, bounds) => { |
| 490 | let mut text = String::new(); |
| 491 | text.push_str("trait "); |
| 492 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 493 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 494 | |
| 495 | if !bounds.is_empty() { |
| 496 | sig.text.push_str(" = "); |
| 497 | sig.text.push_str(&bounds_to_string(bounds)); |
| 498 | } |
| 499 | // FIXME where clause |
| 500 | sig.text.push(';'); |
| 501 | |
| 502 | Ok(sig) |
| 503 | } |
Jeff Vander Stoep | 59fbe18 | 2021-03-29 10:17:52 +0200 | [diff] [blame] | 504 | hir::ItemKind::Impl(hir::Impl { |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 505 | unsafety, |
| 506 | polarity, |
| 507 | defaultness, |
| 508 | defaultness_span: _, |
| 509 | constness, |
| 510 | ref generics, |
| 511 | ref of_trait, |
| 512 | ref self_ty, |
| 513 | items: _, |
Jeff Vander Stoep | 59fbe18 | 2021-03-29 10:17:52 +0200 | [diff] [blame] | 514 | }) => { |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 515 | let mut text = String::new(); |
| 516 | if let hir::Defaultness::Default { .. } = defaultness { |
| 517 | text.push_str("default "); |
| 518 | } |
| 519 | if let hir::Unsafety::Unsafe = unsafety { |
| 520 | text.push_str("unsafe "); |
| 521 | } |
| 522 | text.push_str("impl"); |
| 523 | if let hir::Constness::Const = constness { |
| 524 | text.push_str(" const"); |
| 525 | } |
| 526 | |
| 527 | let generics_sig = generics.make(offset + text.len(), id, scx)?; |
| 528 | text.push_str(&generics_sig.text); |
| 529 | |
| 530 | text.push(' '); |
| 531 | |
| 532 | let trait_sig = if let Some(ref t) = *of_trait { |
| 533 | if let hir::ImplPolarity::Negative(_) = polarity { |
| 534 | text.push('!'); |
| 535 | } |
| 536 | let trait_sig = t.path.make(offset + text.len(), id, scx)?; |
| 537 | text.push_str(&trait_sig.text); |
| 538 | text.push_str(" for "); |
| 539 | trait_sig |
| 540 | } else { |
| 541 | text_sig(String::new()) |
| 542 | }; |
| 543 | |
| 544 | let ty_sig = self_ty.make(offset + text.len(), id, scx)?; |
| 545 | text.push_str(&ty_sig.text); |
| 546 | |
| 547 | text.push_str(" {}"); |
| 548 | |
| 549 | Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig])) |
| 550 | |
| 551 | // FIXME where clause |
| 552 | } |
Jeff Vander Stoep | d59a287 | 2021-02-15 10:22:21 +0100 | [diff] [blame] | 553 | hir::ItemKind::ForeignMod { .. } => Err("extern mod"), |
Thiébaud Weksteen | 5bd94c1 | 2021-01-06 15:18:42 +0100 | [diff] [blame] | 554 | hir::ItemKind::GlobalAsm(_) => Err("global asm"), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 555 | hir::ItemKind::ExternCrate(_) => Err("extern crate"), |
| 556 | hir::ItemKind::OpaqueTy(..) => Err("opaque type"), |
| 557 | // FIXME should implement this (e.g., pub use). |
| 558 | hir::ItemKind::Use(..) => Err("import"), |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | impl<'hir> Sig for hir::Path<'hir> { |
| 564 | fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
| 565 | let res = scx.get_path_res(id.ok_or("Missing id for Path")?); |
| 566 | |
| 567 | let (name, start, end) = match res { |
| 568 | Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { |
| 569 | return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] }); |
| 570 | } |
| 571 | Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => { |
| 572 | let len = self.segments.len(); |
| 573 | if len < 2 { |
| 574 | return Err("Bad path"); |
| 575 | } |
| 576 | // FIXME: really we should descend into the generics here and add SigElements for |
| 577 | // them. |
| 578 | // FIXME: would be nice to have a def for the first path segment. |
| 579 | let seg1 = path_segment_to_string(&self.segments[len - 2]); |
| 580 | let seg2 = path_segment_to_string(&self.segments[len - 1]); |
| 581 | let start = offset + seg1.len() + 2; |
| 582 | (format!("{}::{}", seg1, seg2), start, start + seg2.len()) |
| 583 | } |
| 584 | _ => { |
| 585 | let name = path_segment_to_string(self.segments.last().ok_or("Bad path")?); |
| 586 | let end = offset + name.len(); |
| 587 | (name, offset, end) |
| 588 | } |
| 589 | }; |
| 590 | |
| 591 | let id = id_from_def_id(res.def_id()); |
| 592 | Ok(Signature { text: name, defs: vec![], refs: vec![SigElement { id, start, end }] }) |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | // This does not cover the where clause, which must be processed separately. |
| 597 | impl<'hir> Sig for hir::Generics<'hir> { |
| 598 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
| 599 | if self.params.is_empty() { |
| 600 | return Ok(text_sig(String::new())); |
| 601 | } |
| 602 | |
| 603 | let mut text = "<".to_owned(); |
| 604 | |
| 605 | let mut defs = Vec::with_capacity(self.params.len()); |
| 606 | for param in self.params { |
| 607 | let mut param_text = String::new(); |
| 608 | if let hir::GenericParamKind::Const { .. } = param.kind { |
| 609 | param_text.push_str("const "); |
| 610 | } |
| 611 | param_text.push_str(¶m.name.ident().as_str()); |
| 612 | defs.push(SigElement { |
| 613 | id: id_from_hir_id(param.hir_id, scx), |
| 614 | start: offset + text.len(), |
| 615 | end: offset + text.len() + param_text.as_str().len(), |
| 616 | }); |
Chris Wailes | 32f7835 | 2021-07-20 14:04:55 -0700 | [diff] [blame^] | 617 | if let hir::GenericParamKind::Const { ref ty, default } = param.kind { |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 618 | param_text.push_str(": "); |
| 619 | param_text.push_str(&ty_to_string(&ty)); |
Chris Wailes | 32f7835 | 2021-07-20 14:04:55 -0700 | [diff] [blame^] | 620 | if let Some(default) = default { |
| 621 | param_text.push_str(" = "); |
| 622 | param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id)); |
Jeff Vander Stoep | 59fbe18 | 2021-03-29 10:17:52 +0200 | [diff] [blame] | 623 | } |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 624 | } |
| 625 | if !param.bounds.is_empty() { |
| 626 | param_text.push_str(": "); |
| 627 | match param.kind { |
| 628 | hir::GenericParamKind::Lifetime { .. } => { |
| 629 | let bounds = param |
| 630 | .bounds |
| 631 | .iter() |
| 632 | .map(|bound| match bound { |
| 633 | hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(), |
| 634 | _ => panic!(), |
| 635 | }) |
| 636 | .collect::<Vec<_>>() |
| 637 | .join(" + "); |
| 638 | param_text.push_str(&bounds); |
| 639 | // FIXME add lifetime bounds refs. |
| 640 | } |
| 641 | hir::GenericParamKind::Type { .. } => { |
| 642 | param_text.push_str(&bounds_to_string(param.bounds)); |
| 643 | // FIXME descend properly into bounds. |
| 644 | } |
| 645 | hir::GenericParamKind::Const { .. } => { |
| 646 | // Const generics cannot contain bounds. |
| 647 | } |
| 648 | } |
| 649 | } |
| 650 | text.push_str(¶m_text); |
| 651 | text.push(','); |
| 652 | } |
| 653 | |
| 654 | text.push('>'); |
| 655 | Ok(Signature { text, defs, refs: vec![] }) |
| 656 | } |
| 657 | } |
| 658 | |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 659 | impl<'hir> Sig for hir::FieldDef<'hir> { |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 660 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
| 661 | let mut text = String::new(); |
| 662 | |
| 663 | text.push_str(&self.ident.to_string()); |
| 664 | let defs = Some(SigElement { |
| 665 | id: id_from_hir_id(self.hir_id, scx), |
| 666 | start: offset, |
| 667 | end: offset + text.len(), |
| 668 | }); |
| 669 | text.push_str(": "); |
| 670 | |
| 671 | let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?; |
| 672 | text.push_str(&ty_sig.text); |
| 673 | ty_sig.text = text; |
| 674 | ty_sig.defs.extend(defs.into_iter()); |
| 675 | Ok(ty_sig) |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | impl<'hir> Sig for hir::Variant<'hir> { |
| 680 | fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
| 681 | let mut text = self.ident.to_string(); |
| 682 | match self.data { |
| 683 | hir::VariantData::Struct(fields, r) => { |
Jeff Vander Stoep | d59a287 | 2021-02-15 10:22:21 +0100 | [diff] [blame] | 684 | let id = parent_id.ok_or("Missing id for Variant's parent")?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 685 | let name_def = SigElement { |
| 686 | id: id_from_hir_id(id, scx), |
| 687 | start: offset, |
| 688 | end: offset + text.len(), |
| 689 | }; |
| 690 | text.push_str(" { "); |
| 691 | let mut defs = vec![name_def]; |
| 692 | let mut refs = vec![]; |
| 693 | if r { |
| 694 | text.push_str("/* parse error */ "); |
| 695 | } else { |
| 696 | for f in fields { |
| 697 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; |
| 698 | text.push_str(&field_sig.text); |
| 699 | text.push_str(", "); |
| 700 | defs.extend(field_sig.defs.into_iter()); |
| 701 | refs.extend(field_sig.refs.into_iter()); |
| 702 | } |
| 703 | } |
| 704 | text.push('}'); |
| 705 | Ok(Signature { text, defs, refs }) |
| 706 | } |
| 707 | hir::VariantData::Tuple(fields, id) => { |
| 708 | let name_def = SigElement { |
| 709 | id: id_from_hir_id(id, scx), |
| 710 | start: offset, |
| 711 | end: offset + text.len(), |
| 712 | }; |
| 713 | text.push('('); |
| 714 | let mut defs = vec![name_def]; |
| 715 | let mut refs = vec![]; |
| 716 | for f in fields { |
| 717 | let field_sig = f.make(offset + text.len(), Some(id), scx)?; |
| 718 | text.push_str(&field_sig.text); |
| 719 | text.push_str(", "); |
| 720 | defs.extend(field_sig.defs.into_iter()); |
| 721 | refs.extend(field_sig.refs.into_iter()); |
| 722 | } |
| 723 | text.push(')'); |
| 724 | Ok(Signature { text, defs, refs }) |
| 725 | } |
| 726 | hir::VariantData::Unit(id) => { |
| 727 | let name_def = SigElement { |
| 728 | id: id_from_hir_id(id, scx), |
| 729 | start: offset, |
| 730 | end: offset + text.len(), |
| 731 | }; |
| 732 | Ok(Signature { text, defs: vec![name_def], refs: vec![] }) |
| 733 | } |
| 734 | } |
| 735 | } |
| 736 | } |
| 737 | |
| 738 | impl<'hir> Sig for hir::ForeignItem<'hir> { |
| 739 | fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 740 | let id = Some(self.hir_id()); |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 741 | match self.kind { |
| 742 | hir::ForeignItemKind::Fn(decl, _, ref generics) => { |
| 743 | let mut text = String::new(); |
| 744 | text.push_str("fn "); |
| 745 | |
| 746 | let mut sig = |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 747 | name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 748 | |
| 749 | sig.text.push('('); |
| 750 | for i in decl.inputs { |
| 751 | sig.text.push_str(": "); |
| 752 | let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?; |
| 753 | sig.text.push_str(&nested.text); |
| 754 | sig.text.push(','); |
| 755 | sig.defs.extend(nested.defs.into_iter()); |
| 756 | sig.refs.extend(nested.refs.into_iter()); |
| 757 | } |
| 758 | sig.text.push(')'); |
| 759 | |
| 760 | if let hir::FnRetTy::Return(ref t) = decl.output { |
| 761 | sig.text.push_str(" -> "); |
| 762 | let nested = t.make(offset + sig.text.len(), None, scx)?; |
| 763 | sig.text.push_str(&nested.text); |
| 764 | sig.defs.extend(nested.defs.into_iter()); |
| 765 | sig.refs.extend(nested.refs.into_iter()); |
| 766 | } |
| 767 | sig.text.push(';'); |
| 768 | |
| 769 | Ok(sig) |
| 770 | } |
| 771 | hir::ForeignItemKind::Static(ref ty, m) => { |
| 772 | let mut text = "static ".to_owned(); |
| 773 | if m == Mutability::Mut { |
| 774 | text.push_str("mut "); |
| 775 | } |
| 776 | let name = self.ident.to_string(); |
| 777 | let defs = vec![SigElement { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 778 | id: id_from_def_id(self.def_id.to_def_id()), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 779 | start: offset + text.len(), |
| 780 | end: offset + text.len() + name.len(), |
| 781 | }]; |
| 782 | text.push_str(&name); |
| 783 | text.push_str(": "); |
| 784 | |
| 785 | let ty_sig = ty.make(offset + text.len(), id, scx)?; |
| 786 | text.push(';'); |
| 787 | |
| 788 | Ok(extend_sig(ty_sig, text, defs, vec![])) |
| 789 | } |
| 790 | hir::ForeignItemKind::Type => { |
| 791 | let mut text = "type ".to_owned(); |
| 792 | let name = self.ident.to_string(); |
| 793 | let defs = vec![SigElement { |
Chris Wailes | e3116c4 | 2021-07-13 14:40:48 -0700 | [diff] [blame] | 794 | id: id_from_def_id(self.def_id.to_def_id()), |
Thiébaud Weksteen | 3b664ca | 2020-11-26 14:41:59 +0100 | [diff] [blame] | 795 | start: offset + text.len(), |
| 796 | end: offset + text.len() + name.len(), |
| 797 | }]; |
| 798 | text.push_str(&name); |
| 799 | text.push(';'); |
| 800 | |
| 801 | Ok(Signature { text, defs, refs: vec![] }) |
| 802 | } |
| 803 | } |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | fn name_and_generics( |
| 808 | mut text: String, |
| 809 | offset: usize, |
| 810 | generics: &hir::Generics<'_>, |
| 811 | id: hir::HirId, |
| 812 | name: Ident, |
| 813 | scx: &SaveContext<'_>, |
| 814 | ) -> Result { |
| 815 | let name = name.to_string(); |
| 816 | let def = SigElement { |
| 817 | id: id_from_hir_id(id, scx), |
| 818 | start: offset + text.len(), |
| 819 | end: offset + text.len() + name.len(), |
| 820 | }; |
| 821 | text.push_str(&name); |
| 822 | let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; |
| 823 | // FIXME where clause |
| 824 | let text = format!("{}{}", text, generics.text); |
| 825 | Ok(extend_sig(generics, text, vec![def], vec![])) |
| 826 | } |
| 827 | |
| 828 | fn make_assoc_type_signature( |
| 829 | id: hir::HirId, |
| 830 | ident: Ident, |
| 831 | bounds: Option<hir::GenericBounds<'_>>, |
| 832 | default: Option<&hir::Ty<'_>>, |
| 833 | scx: &SaveContext<'_>, |
| 834 | ) -> Result { |
| 835 | let mut text = "type ".to_owned(); |
| 836 | let name = ident.to_string(); |
| 837 | let mut defs = vec![SigElement { |
| 838 | id: id_from_hir_id(id, scx), |
| 839 | start: text.len(), |
| 840 | end: text.len() + name.len(), |
| 841 | }]; |
| 842 | let mut refs = vec![]; |
| 843 | text.push_str(&name); |
| 844 | if let Some(bounds) = bounds { |
| 845 | text.push_str(": "); |
| 846 | // FIXME should descend into bounds |
| 847 | text.push_str(&bounds_to_string(bounds)); |
| 848 | } |
| 849 | if let Some(default) = default { |
| 850 | text.push_str(" = "); |
| 851 | let ty_sig = default.make(text.len(), Some(id), scx)?; |
| 852 | text.push_str(&ty_sig.text); |
| 853 | defs.extend(ty_sig.defs.into_iter()); |
| 854 | refs.extend(ty_sig.refs.into_iter()); |
| 855 | } |
| 856 | text.push(';'); |
| 857 | Ok(Signature { text, defs, refs }) |
| 858 | } |
| 859 | |
| 860 | fn make_assoc_const_signature( |
| 861 | id: hir::HirId, |
| 862 | ident: Symbol, |
| 863 | ty: &hir::Ty<'_>, |
| 864 | default: Option<&hir::Expr<'_>>, |
| 865 | scx: &SaveContext<'_>, |
| 866 | ) -> Result { |
| 867 | let mut text = "const ".to_owned(); |
| 868 | let name = ident.to_string(); |
| 869 | let mut defs = vec![SigElement { |
| 870 | id: id_from_hir_id(id, scx), |
| 871 | start: text.len(), |
| 872 | end: text.len() + name.len(), |
| 873 | }]; |
| 874 | let mut refs = vec![]; |
| 875 | text.push_str(&name); |
| 876 | text.push_str(": "); |
| 877 | |
| 878 | let ty_sig = ty.make(text.len(), Some(id), scx)?; |
| 879 | text.push_str(&ty_sig.text); |
| 880 | defs.extend(ty_sig.defs.into_iter()); |
| 881 | refs.extend(ty_sig.refs.into_iter()); |
| 882 | |
| 883 | if let Some(default) = default { |
| 884 | text.push_str(" = "); |
| 885 | text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id)); |
| 886 | } |
| 887 | text.push(';'); |
| 888 | Ok(Signature { text, defs, refs }) |
| 889 | } |
| 890 | |
| 891 | fn make_method_signature( |
| 892 | id: hir::HirId, |
| 893 | ident: Ident, |
| 894 | generics: &hir::Generics<'_>, |
| 895 | m: &hir::FnSig<'_>, |
| 896 | scx: &SaveContext<'_>, |
| 897 | ) -> Result { |
| 898 | // FIXME code dup with function signature |
| 899 | let mut text = String::new(); |
| 900 | if let hir::Constness::Const = m.header.constness { |
| 901 | text.push_str("const "); |
| 902 | } |
| 903 | if hir::IsAsync::Async == m.header.asyncness { |
| 904 | text.push_str("async "); |
| 905 | } |
| 906 | if let hir::Unsafety::Unsafe = m.header.unsafety { |
| 907 | text.push_str("unsafe "); |
| 908 | } |
| 909 | text.push_str("fn "); |
| 910 | |
| 911 | let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?; |
| 912 | |
| 913 | sig.text.push('('); |
| 914 | for i in m.decl.inputs { |
| 915 | sig.text.push_str(": "); |
| 916 | let nested = i.make(sig.text.len(), Some(i.hir_id), scx)?; |
| 917 | sig.text.push_str(&nested.text); |
| 918 | sig.text.push(','); |
| 919 | sig.defs.extend(nested.defs.into_iter()); |
| 920 | sig.refs.extend(nested.refs.into_iter()); |
| 921 | } |
| 922 | sig.text.push(')'); |
| 923 | |
| 924 | if let hir::FnRetTy::Return(ref t) = m.decl.output { |
| 925 | sig.text.push_str(" -> "); |
| 926 | let nested = t.make(sig.text.len(), None, scx)?; |
| 927 | sig.text.push_str(&nested.text); |
| 928 | sig.defs.extend(nested.defs.into_iter()); |
| 929 | sig.refs.extend(nested.refs.into_iter()); |
| 930 | } |
| 931 | sig.text.push_str(" {}"); |
| 932 | |
| 933 | Ok(sig) |
| 934 | } |