]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use crate::clean::auto_trait::AutoTraitFinder; |
2 | use crate::clean::blanket_impl::BlanketImplFinder; | |
60c5eb7d | 3 | use crate::clean::{ |
74b04a01 | 4 | inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, |
dfeec247 | 5 | GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, MacroKind, Path, |
60c5eb7d | 6 | PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, TypeBinding, |
dfeec247 | 7 | TypeKind, Visibility, WherePredicate, |
60c5eb7d | 8 | }; |
dfeec247 | 9 | use crate::core::DocContext; |
60c5eb7d | 10 | |
dfeec247 XL |
11 | use itertools::Itertools; |
12 | use rustc::mir::interpret::{sign_extend, ConstValue, Scalar}; | |
13 | use rustc::ty::subst::{GenericArgKind, SubstsRef}; | |
60c5eb7d | 14 | use rustc::ty::{self, DefIdTree, Ty}; |
dfeec247 XL |
15 | use rustc_data_structures::fx::FxHashSet; |
16 | use rustc_hir as hir; | |
17 | use rustc_hir::def::{DefKind, Res}; | |
18 | use rustc_hir::def_id::{DefId, LOCAL_CRATE}; | |
dfeec247 | 19 | use rustc_span::symbol::{kw, sym, Symbol}; |
60c5eb7d XL |
20 | use std::mem; |
21 | ||
22 | pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { | |
23 | use crate::visit_lib::LibEmbargoVisitor; | |
24 | ||
25 | let krate = cx.tcx.hir().krate(); | |
26 | let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); | |
27 | ||
28 | let mut r = cx.renderinfo.get_mut(); | |
29 | r.deref_trait_did = cx.tcx.lang_items().deref_trait(); | |
30 | r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); | |
31 | r.owned_box_did = cx.tcx.lang_items().owned_box(); | |
32 | ||
33 | let mut externs = Vec::new(); | |
34 | for &cnum in cx.tcx.crates().iter() { | |
35 | externs.push((cnum, cnum.clean(cx))); | |
36 | // Analyze doc-reachability for extern items | |
37 | LibEmbargoVisitor::new(&mut cx).visit_lib(cnum); | |
38 | } | |
39 | externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); | |
40 | ||
74b04a01 | 41 | // Clean the crate, translating the entire librustc_ast AST to one that is |
60c5eb7d XL |
42 | // understood by rustdoc. |
43 | let mut module = module.clean(cx); | |
44 | let mut masked_crates = FxHashSet::default(); | |
45 | ||
46 | match module.inner { | |
47 | ItemEnum::ModuleItem(ref module) => { | |
48 | for it in &module.items { | |
49 | // `compiler_builtins` should be masked too, but we can't apply | |
50 | // `#[doc(masked)]` to the injected `extern crate` because it's unstable. | |
51 | if it.is_extern_crate() | |
52 | && (it.attrs.has_doc_flag(sym::masked) | |
53 | || cx.tcx.is_compiler_builtins(it.def_id.krate)) | |
54 | { | |
55 | masked_crates.insert(it.def_id.krate); | |
56 | } | |
57 | } | |
58 | } | |
59 | _ => unreachable!(), | |
60 | } | |
61 | ||
62 | let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); | |
63 | { | |
64 | let m = match module.inner { | |
65 | ItemEnum::ModuleItem(ref mut m) => m, | |
66 | _ => unreachable!(), | |
67 | }; | |
dfeec247 XL |
68 | m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| Item { |
69 | source: Span::empty(), | |
70 | name: Some(prim.to_url_str().to_string()), | |
71 | attrs: attrs.clone(), | |
72 | visibility: Visibility::Public, | |
73 | stability: get_stability(cx, def_id), | |
74 | deprecation: get_deprecation(cx, def_id), | |
75 | def_id, | |
76 | inner: ItemEnum::PrimitiveItem(prim), | |
60c5eb7d | 77 | })); |
dfeec247 XL |
78 | m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| Item { |
79 | source: Span::empty(), | |
80 | name: Some(kw.clone()), | |
81 | attrs, | |
82 | visibility: Visibility::Public, | |
83 | stability: get_stability(cx, def_id), | |
84 | deprecation: get_deprecation(cx, def_id), | |
85 | def_id, | |
86 | inner: ItemEnum::KeywordItem(kw), | |
60c5eb7d XL |
87 | })); |
88 | } | |
89 | ||
90 | Crate { | |
91 | name, | |
92 | version: None, | |
93 | src, | |
94 | module: Some(module), | |
95 | externs, | |
96 | primitives, | |
97 | external_traits: cx.external_traits.clone(), | |
98 | masked_crates, | |
99 | collapsed: false, | |
100 | } | |
101 | } | |
102 | ||
103 | // extract the stability index for a node from tcx, if possible | |
104 | pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> { | |
105 | cx.tcx.lookup_stability(def_id).clean(cx) | |
106 | } | |
107 | ||
108 | pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> { | |
109 | cx.tcx.lookup_deprecation(def_id).clean(cx) | |
110 | } | |
111 | ||
112 | pub fn external_generic_args( | |
113 | cx: &DocContext<'_>, | |
114 | trait_did: Option<DefId>, | |
115 | has_self: bool, | |
116 | bindings: Vec<TypeBinding>, | |
117 | substs: SubstsRef<'_>, | |
118 | ) -> GenericArgs { | |
119 | let mut skip_self = has_self; | |
120 | let mut ty_kind = None; | |
dfeec247 XL |
121 | let args: Vec<_> = substs |
122 | .iter() | |
123 | .filter_map(|kind| match kind.unpack() { | |
74b04a01 | 124 | GenericArgKind::Lifetime(lt) => lt.clean(cx).map(|lt| GenericArg::Lifetime(lt)), |
dfeec247 XL |
125 | GenericArgKind::Type(_) if skip_self => { |
126 | skip_self = false; | |
127 | None | |
128 | } | |
129 | GenericArgKind::Type(ty) => { | |
130 | ty_kind = Some(&ty.kind); | |
131 | Some(GenericArg::Type(ty.clean(cx))) | |
132 | } | |
133 | GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), | |
134 | }) | |
135 | .collect(); | |
60c5eb7d XL |
136 | |
137 | match trait_did { | |
138 | // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C | |
74b04a01 | 139 | Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => { |
60c5eb7d XL |
140 | assert!(ty_kind.is_some()); |
141 | let inputs = match ty_kind { | |
142 | Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), | |
143 | _ => return GenericArgs::AngleBracketed { args, bindings }, | |
144 | }; | |
145 | let output = None; | |
146 | // FIXME(#20299) return type comes from a projection now | |
147 | // match types[1].kind { | |
148 | // ty::Tuple(ref v) if v.is_empty() => None, // -> () | |
149 | // _ => Some(types[1].clean(cx)) | |
150 | // }; | |
151 | GenericArgs::Parenthesized { inputs, output } | |
60c5eb7d | 152 | } |
dfeec247 | 153 | _ => GenericArgs::AngleBracketed { args, bindings }, |
60c5eb7d XL |
154 | } |
155 | } | |
156 | ||
157 | // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar | |
158 | // from Fn<(A, B,), C> to Fn(A, B) -> C | |
dfeec247 XL |
159 | pub fn external_path( |
160 | cx: &DocContext<'_>, | |
161 | name: Symbol, | |
162 | trait_did: Option<DefId>, | |
163 | has_self: bool, | |
164 | bindings: Vec<TypeBinding>, | |
165 | substs: SubstsRef<'_>, | |
166 | ) -> Path { | |
60c5eb7d XL |
167 | Path { |
168 | global: false, | |
169 | res: Res::Err, | |
170 | segments: vec![PathSegment { | |
171 | name: name.to_string(), | |
dfeec247 | 172 | args: external_generic_args(cx, trait_did, has_self, bindings, substs), |
60c5eb7d XL |
173 | }], |
174 | } | |
175 | } | |
176 | ||
177 | /// The point of this function is to replace bounds with types. | |
178 | /// | |
179 | /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return | |
180 | /// `[Display, Option]` (we just returns the list of the types, we don't care about the | |
181 | /// wrapped types in here). | |
182 | pub fn get_real_types( | |
183 | generics: &Generics, | |
184 | arg: &Type, | |
185 | cx: &DocContext<'_>, | |
186 | recurse: i32, | |
187 | ) -> FxHashSet<Type> { | |
188 | let arg_s = arg.print().to_string(); | |
189 | let mut res = FxHashSet::default(); | |
dfeec247 XL |
190 | if recurse >= 10 { |
191 | // FIXME: remove this whole recurse thing when the recursion bug is fixed | |
60c5eb7d XL |
192 | return res; |
193 | } | |
194 | if arg.is_full_generic() { | |
dfeec247 XL |
195 | if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { |
196 | &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(), | |
197 | _ => false, | |
60c5eb7d XL |
198 | }) { |
199 | let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); | |
200 | for bound in bounds.iter() { | |
201 | match *bound { | |
202 | GenericBound::TraitBound(ref poly_trait, _) => { | |
203 | for x in poly_trait.generic_params.iter() { | |
204 | if !x.is_type() { | |
dfeec247 | 205 | continue; |
60c5eb7d XL |
206 | } |
207 | if let Some(ty) = x.get_type() { | |
208 | let adds = get_real_types(generics, &ty, cx, recurse + 1); | |
209 | if !adds.is_empty() { | |
210 | res.extend(adds); | |
211 | } else if !ty.is_full_generic() { | |
212 | res.insert(ty); | |
213 | } | |
214 | } | |
215 | } | |
216 | } | |
217 | _ => {} | |
218 | } | |
219 | } | |
220 | } | |
dfeec247 | 221 | if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { |
60c5eb7d XL |
222 | for bound in bound.get_bounds().unwrap_or_else(|| &[]) { |
223 | if let Some(ty) = bound.get_trait_type() { | |
224 | let adds = get_real_types(generics, &ty, cx, recurse + 1); | |
225 | if !adds.is_empty() { | |
226 | res.extend(adds); | |
227 | } else if !ty.is_full_generic() { | |
228 | res.insert(ty.clone()); | |
229 | } | |
230 | } | |
231 | } | |
232 | } | |
233 | } else { | |
234 | res.insert(arg.clone()); | |
235 | if let Some(gens) = arg.generics() { | |
236 | for gen in gens.iter() { | |
237 | if gen.is_full_generic() { | |
238 | let adds = get_real_types(generics, gen, cx, recurse + 1); | |
239 | if !adds.is_empty() { | |
240 | res.extend(adds); | |
241 | } | |
242 | } else { | |
243 | res.insert(gen.clone()); | |
244 | } | |
245 | } | |
246 | } | |
247 | } | |
248 | res | |
249 | } | |
250 | ||
251 | /// Return the full list of types when bounds have been resolved. | |
252 | /// | |
253 | /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return | |
254 | /// `[u32, Display, Option]`. | |
255 | pub fn get_all_types( | |
256 | generics: &Generics, | |
257 | decl: &FnDecl, | |
258 | cx: &DocContext<'_>, | |
259 | ) -> (Vec<Type>, Vec<Type>) { | |
260 | let mut all_types = FxHashSet::default(); | |
261 | for arg in decl.inputs.values.iter() { | |
262 | if arg.type_.is_self_type() { | |
263 | continue; | |
264 | } | |
265 | let args = get_real_types(generics, &arg.type_, cx, 0); | |
266 | if !args.is_empty() { | |
267 | all_types.extend(args); | |
268 | } else { | |
269 | all_types.insert(arg.type_.clone()); | |
270 | } | |
271 | } | |
272 | ||
273 | let ret_types = match decl.output { | |
74b04a01 | 274 | FnRetTy::Return(ref return_type) => { |
60c5eb7d XL |
275 | let mut ret = get_real_types(generics, &return_type, cx, 0); |
276 | if ret.is_empty() { | |
277 | ret.insert(return_type.clone()); | |
278 | } | |
279 | ret.into_iter().collect() | |
280 | } | |
281 | _ => Vec::new(), | |
282 | }; | |
283 | (all_types.into_iter().collect(), ret_types) | |
284 | } | |
285 | ||
286 | pub fn strip_type(ty: Type) -> Type { | |
287 | match ty { | |
288 | Type::ResolvedPath { path, param_names, did, is_generic } => { | |
289 | Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic } | |
290 | } | |
291 | Type::Tuple(inner_tys) => { | |
292 | Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) | |
293 | } | |
294 | Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), | |
295 | Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), | |
296 | Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), | |
297 | Type::BorrowedRef { lifetime, mutability, type_ } => { | |
298 | Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } | |
299 | } | |
dfeec247 XL |
300 | Type::QPath { name, self_type, trait_ } => Type::QPath { |
301 | name, | |
302 | self_type: Box::new(strip_type(*self_type)), | |
303 | trait_: Box::new(strip_type(*trait_)), | |
304 | }, | |
305 | _ => ty, | |
60c5eb7d XL |
306 | } |
307 | } | |
308 | ||
309 | pub fn strip_path(path: &Path) -> Path { | |
dfeec247 XL |
310 | let segments = path |
311 | .segments | |
312 | .iter() | |
313 | .map(|s| PathSegment { | |
60c5eb7d | 314 | name: s.name.clone(), |
dfeec247 XL |
315 | args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] }, |
316 | }) | |
317 | .collect(); | |
60c5eb7d | 318 | |
dfeec247 | 319 | Path { global: path.global, res: path.res, segments } |
60c5eb7d XL |
320 | } |
321 | ||
322 | pub fn qpath_to_string(p: &hir::QPath) -> String { | |
323 | let segments = match *p { | |
324 | hir::QPath::Resolved(_, ref path) => &path.segments, | |
325 | hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(), | |
326 | }; | |
327 | ||
328 | let mut s = String::new(); | |
329 | for (i, seg) in segments.iter().enumerate() { | |
330 | if i > 0 { | |
331 | s.push_str("::"); | |
332 | } | |
333 | if seg.ident.name != kw::PathRoot { | |
334 | s.push_str(&seg.ident.as_str()); | |
335 | } | |
336 | } | |
337 | s | |
338 | } | |
339 | ||
dfeec247 | 340 | pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) { |
60c5eb7d XL |
341 | use self::PrimitiveType::*; |
342 | let tcx = cx.tcx; | |
343 | ||
344 | for item in items { | |
345 | let target = match item.inner { | |
346 | ItemEnum::TypedefItem(ref t, true) => &t.type_, | |
347 | _ => continue, | |
348 | }; | |
349 | let primitive = match *target { | |
350 | ResolvedPath { did, .. } if did.is_local() => continue, | |
351 | ResolvedPath { did, .. } => { | |
352 | ret.extend(inline::build_impls(cx, did, None)); | |
dfeec247 | 353 | continue; |
60c5eb7d XL |
354 | } |
355 | _ => match target.primitive_type() { | |
356 | Some(prim) => prim, | |
357 | None => continue, | |
dfeec247 | 358 | }, |
60c5eb7d XL |
359 | }; |
360 | let did = match primitive { | |
361 | Isize => tcx.lang_items().isize_impl(), | |
362 | I8 => tcx.lang_items().i8_impl(), | |
363 | I16 => tcx.lang_items().i16_impl(), | |
364 | I32 => tcx.lang_items().i32_impl(), | |
365 | I64 => tcx.lang_items().i64_impl(), | |
366 | I128 => tcx.lang_items().i128_impl(), | |
367 | Usize => tcx.lang_items().usize_impl(), | |
368 | U8 => tcx.lang_items().u8_impl(), | |
369 | U16 => tcx.lang_items().u16_impl(), | |
370 | U32 => tcx.lang_items().u32_impl(), | |
371 | U64 => tcx.lang_items().u64_impl(), | |
372 | U128 => tcx.lang_items().u128_impl(), | |
373 | F32 => tcx.lang_items().f32_impl(), | |
374 | F64 => tcx.lang_items().f64_impl(), | |
375 | Char => tcx.lang_items().char_impl(), | |
376 | Bool => tcx.lang_items().bool_impl(), | |
377 | Str => tcx.lang_items().str_impl(), | |
378 | Slice => tcx.lang_items().slice_impl(), | |
379 | Array => tcx.lang_items().slice_impl(), | |
380 | Tuple => None, | |
381 | Unit => None, | |
382 | RawPointer => tcx.lang_items().const_ptr_impl(), | |
383 | Reference => None, | |
384 | Fn => None, | |
385 | Never => None, | |
386 | }; | |
387 | if let Some(did) = did { | |
388 | if !did.is_local() { | |
389 | inline::build_impl(cx, did, None, ret); | |
390 | } | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | pub trait ToSource { | |
396 | fn to_src(&self, cx: &DocContext<'_>) -> String; | |
397 | } | |
398 | ||
dfeec247 | 399 | impl ToSource for rustc_span::Span { |
60c5eb7d XL |
400 | fn to_src(&self, cx: &DocContext<'_>) -> String { |
401 | debug!("converting span {:?} to snippet", self.clean(cx)); | |
402 | let sn = match cx.sess().source_map().span_to_snippet(*self) { | |
403 | Ok(x) => x, | |
dfeec247 | 404 | Err(_) => String::new(), |
60c5eb7d XL |
405 | }; |
406 | debug!("got snippet {}", sn); | |
407 | sn | |
408 | } | |
409 | } | |
410 | ||
411 | pub fn name_from_pat(p: &hir::Pat) -> String { | |
dfeec247 | 412 | use rustc_hir::*; |
60c5eb7d XL |
413 | debug!("trying to get a name from pattern: {:?}", p); |
414 | ||
415 | match p.kind { | |
416 | PatKind::Wild => "_".to_string(), | |
417 | PatKind::Binding(_, _, ident, _) => ident.to_string(), | |
418 | PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), | |
dfeec247 XL |
419 | PatKind::Struct(ref name, ref fields, etc) => format!( |
420 | "{} {{ {}{} }}", | |
421 | qpath_to_string(name), | |
422 | fields | |
423 | .iter() | |
424 | .map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat))) | |
425 | .collect::<Vec<String>>() | |
426 | .join(", "), | |
427 | if etc { ", .." } else { "" } | |
428 | ), | |
60c5eb7d XL |
429 | PatKind::Or(ref pats) => { |
430 | pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ") | |
431 | } | |
dfeec247 XL |
432 | PatKind::Tuple(ref elts, _) => format!( |
433 | "({})", | |
434 | elts.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(", ") | |
435 | ), | |
60c5eb7d XL |
436 | PatKind::Box(ref p) => name_from_pat(&**p), |
437 | PatKind::Ref(ref p, _) => name_from_pat(&**p), | |
438 | PatKind::Lit(..) => { | |
dfeec247 XL |
439 | warn!( |
440 | "tried to get argument name from PatKind::Lit, \ | |
441 | which is silly in function arguments" | |
442 | ); | |
60c5eb7d | 443 | "()".to_string() |
dfeec247 XL |
444 | } |
445 | PatKind::Range(..) => panic!( | |
446 | "tried to get argument name from PatKind::Range, \ | |
447 | which is not allowed in function arguments" | |
448 | ), | |
60c5eb7d XL |
449 | PatKind::Slice(ref begin, ref mid, ref end) => { |
450 | let begin = begin.iter().map(|p| name_from_pat(&**p)); | |
451 | let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); | |
452 | let end = end.iter().map(|p| name_from_pat(&**p)); | |
453 | format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", ")) | |
dfeec247 | 454 | } |
60c5eb7d XL |
455 | } |
456 | } | |
457 | ||
74b04a01 | 458 | pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { |
60c5eb7d | 459 | match n.val { |
dfeec247 XL |
460 | ty::ConstKind::Unevaluated(def_id, _, promoted) => { |
461 | let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { | |
60c5eb7d XL |
462 | print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id)) |
463 | } else { | |
464 | inline::print_inlined_const(cx, def_id) | |
dfeec247 XL |
465 | }; |
466 | if let Some(promoted) = promoted { | |
467 | s.push_str(&format!("::{:?}", promoted)) | |
60c5eb7d | 468 | } |
dfeec247 XL |
469 | s |
470 | } | |
60c5eb7d XL |
471 | _ => { |
472 | let mut s = n.to_string(); | |
473 | // array lengths are obviously usize | |
474 | if s.ends_with("usize") { | |
475 | let n = s.len() - "usize".len(); | |
476 | s.truncate(n); | |
477 | if s.ends_with(": ") { | |
478 | let n = s.len() - ": ".len(); | |
479 | s.truncate(n); | |
480 | } | |
481 | } | |
482 | s | |
dfeec247 XL |
483 | } |
484 | } | |
485 | } | |
486 | ||
487 | pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option<String> { | |
74b04a01 XL |
488 | let value = cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { |
489 | let ty = cx.tcx.type_of(def_id); | |
490 | match (val, &ty.kind) { | |
491 | (_, &ty::Ref(..)) => None, | |
492 | (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, | |
493 | (ConstValue::Scalar(_), _) => { | |
494 | let const_ = ty::Const::from_value(cx.tcx, val, ty); | |
495 | Some(print_const_with_custom_print_scalar(cx, const_)) | |
dfeec247 XL |
496 | } |
497 | _ => None, | |
74b04a01 XL |
498 | } |
499 | }); | |
dfeec247 XL |
500 | |
501 | value | |
502 | } | |
503 | ||
504 | fn format_integer_with_underscore_sep(num: &str) -> String { | |
505 | let num_chars: Vec<_> = num.chars().collect(); | |
506 | let num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 }; | |
507 | ||
508 | num_chars[..num_start_index] | |
509 | .iter() | |
510 | .chain(num_chars[num_start_index..].rchunks(3).rev().intersperse(&['_']).flatten()) | |
511 | .collect() | |
512 | } | |
513 | ||
514 | fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { | |
515 | // Use a slightly different format for integer types which always shows the actual value. | |
516 | // For all other types, fallback to the original `pretty_print_const`. | |
517 | match (ct.val, &ct.ty.kind) { | |
518 | (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Uint(ui)) => { | |
519 | format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str()) | |
520 | } | |
521 | (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Int(i)) => { | |
522 | let ty = cx.tcx.lift(&ct.ty).unwrap(); | |
523 | let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; | |
524 | let sign_extended_data = sign_extend(data, size) as i128; | |
525 | ||
526 | format!( | |
527 | "{}{}", | |
528 | format_integer_with_underscore_sep(&sign_extended_data.to_string()), | |
529 | i.name_str() | |
530 | ) | |
531 | } | |
532 | _ => ct.to_string(), | |
533 | } | |
534 | } | |
535 | ||
536 | pub fn is_literal_expr(cx: &DocContext<'_>, hir_id: hir::HirId) -> bool { | |
537 | if let hir::Node::Expr(expr) = cx.tcx.hir().get(hir_id) { | |
538 | if let hir::ExprKind::Lit(_) = &expr.kind { | |
539 | return true; | |
540 | } | |
541 | ||
542 | if let hir::ExprKind::Unary(hir::UnOp::UnNeg, expr) = &expr.kind { | |
543 | if let hir::ExprKind::Lit(_) = &expr.kind { | |
544 | return true; | |
545 | } | |
546 | } | |
60c5eb7d | 547 | } |
dfeec247 XL |
548 | |
549 | false | |
60c5eb7d XL |
550 | } |
551 | ||
552 | pub fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String { | |
dfeec247 XL |
553 | let value = &cx.tcx.hir().body(body).value; |
554 | ||
555 | let snippet = if !value.span.from_expansion() { | |
556 | cx.sess().source_map().span_to_snippet(value.span).ok() | |
557 | } else { | |
558 | None | |
559 | }; | |
560 | ||
561 | snippet.unwrap_or_else(|| cx.tcx.hir().hir_to_pretty_string(body.hir_id)) | |
60c5eb7d XL |
562 | } |
563 | ||
564 | /// Given a type Path, resolve it to a Type using the TyCtxt | |
dfeec247 | 565 | pub fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type { |
60c5eb7d XL |
566 | if id == hir::DUMMY_HIR_ID { |
567 | debug!("resolve_type({:?})", path); | |
568 | } else { | |
569 | debug!("resolve_type({:?},{:?})", path, id); | |
570 | } | |
571 | ||
572 | let is_generic = match path.res { | |
74b04a01 | 573 | Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), |
60c5eb7d XL |
574 | Res::SelfTy(..) if path.segments.len() == 1 => { |
575 | return Generic(kw::SelfUpper.to_string()); | |
576 | } | |
577 | Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { | |
578 | return Generic(format!("{:#}", path.print())); | |
579 | } | |
dfeec247 | 580 | Res::SelfTy(..) | Res::Def(DefKind::TyParam, _) | Res::Def(DefKind::AssocTy, _) => true, |
60c5eb7d XL |
581 | _ => false, |
582 | }; | |
583 | let did = register_res(&*cx, path.res); | |
584 | ResolvedPath { path, param_names: None, did, is_generic } | |
585 | } | |
586 | ||
587 | pub fn get_auto_trait_and_blanket_impls( | |
588 | cx: &DocContext<'tcx>, | |
589 | ty: Ty<'tcx>, | |
590 | param_env_def_id: DefId, | |
591 | ) -> impl Iterator<Item = Item> { | |
dfeec247 XL |
592 | AutoTraitFinder::new(cx) |
593 | .get_auto_trait_impls(ty, param_env_def_id) | |
594 | .into_iter() | |
60c5eb7d XL |
595 | .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)) |
596 | } | |
597 | ||
598 | pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { | |
599 | debug!("register_res({:?})", res); | |
600 | ||
601 | let (did, kind) = match res { | |
602 | Res::Def(DefKind::Fn, i) => (i, TypeKind::Function), | |
603 | Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef), | |
604 | Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum), | |
605 | Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait), | |
606 | Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct), | |
607 | Res::Def(DefKind::Union, i) => (i, TypeKind::Union), | |
608 | Res::Def(DefKind::Mod, i) => (i, TypeKind::Module), | |
609 | Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign), | |
610 | Res::Def(DefKind::Const, i) => (i, TypeKind::Const), | |
611 | Res::Def(DefKind::Static, i) => (i, TypeKind::Static), | |
dfeec247 XL |
612 | Res::Def(DefKind::Variant, i) => { |
613 | (cx.tcx.parent(i).expect("cannot get parent def id"), TypeKind::Enum) | |
614 | } | |
60c5eb7d XL |
615 | Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind { |
616 | MacroKind::Bang => (i, TypeKind::Macro), | |
617 | MacroKind::Attr => (i, TypeKind::Attr), | |
618 | MacroKind::Derive => (i, TypeKind::Derive), | |
619 | }, | |
620 | Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), | |
621 | Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), | |
622 | Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, | |
dfeec247 | 623 | _ => return res.def_id(), |
60c5eb7d | 624 | }; |
dfeec247 XL |
625 | if did.is_local() { |
626 | return did; | |
627 | } | |
60c5eb7d XL |
628 | inline::record_extern_fqn(cx, did, kind); |
629 | if let TypeKind::Trait = kind { | |
630 | inline::record_extern_trait(cx, did); | |
631 | } | |
632 | did | |
633 | } | |
634 | ||
635 | pub fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { | |
636 | ImportSource { | |
dfeec247 | 637 | did: if path.res.opt_def_id().is_none() { None } else { Some(register_res(cx, path.res)) }, |
60c5eb7d XL |
638 | path, |
639 | } | |
640 | } | |
641 | ||
642 | pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R | |
643 | where | |
644 | F: FnOnce() -> R, | |
645 | { | |
646 | let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut()); | |
647 | let r = f(); | |
648 | assert!(cx.impl_trait_bounds.borrow().is_empty()); | |
649 | *cx.impl_trait_bounds.borrow_mut() = old_bounds; | |
650 | r | |
651 | } |