]>
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, |
3dfed10e XL |
5 | GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime, |
6 | MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, | |
7 | TypeBinding, TypeKind, Visibility, WherePredicate, | |
60c5eb7d | 8 | }; |
dfeec247 | 9 | use crate::core::DocContext; |
60c5eb7d | 10 | |
dfeec247 | 11 | use itertools::Itertools; |
dfeec247 XL |
12 | use rustc_data_structures::fx::FxHashSet; |
13 | use rustc_hir as hir; | |
14 | use rustc_hir::def::{DefKind, Res}; | |
15 | use rustc_hir::def_id::{DefId, LOCAL_CRATE}; | |
ba9703b0 XL |
16 | use rustc_middle::mir::interpret::{sign_extend, ConstValue, Scalar}; |
17 | use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; | |
18 | use rustc_middle::ty::{self, DefIdTree, Ty}; | |
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() { | |
3dfed10e XL |
124 | GenericArgKind::Lifetime(lt) => match lt { |
125 | ty::ReLateBound(_, ty::BrAnon(_)) => Some(GenericArg::Lifetime(Lifetime::elided())), | |
126 | _ => lt.clean(cx).map(GenericArg::Lifetime), | |
127 | }, | |
dfeec247 XL |
128 | GenericArgKind::Type(_) if skip_self => { |
129 | skip_self = false; | |
130 | None | |
131 | } | |
132 | GenericArgKind::Type(ty) => { | |
1b1a35ee | 133 | ty_kind = Some(ty.kind()); |
dfeec247 XL |
134 | Some(GenericArg::Type(ty.clean(cx))) |
135 | } | |
136 | GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), | |
137 | }) | |
138 | .collect(); | |
60c5eb7d XL |
139 | |
140 | match trait_did { | |
141 | // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C | |
74b04a01 | 142 | Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => { |
60c5eb7d XL |
143 | assert!(ty_kind.is_some()); |
144 | let inputs = match ty_kind { | |
145 | Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(), | |
146 | _ => return GenericArgs::AngleBracketed { args, bindings }, | |
147 | }; | |
148 | let output = None; | |
149 | // FIXME(#20299) return type comes from a projection now | |
150 | // match types[1].kind { | |
151 | // ty::Tuple(ref v) if v.is_empty() => None, // -> () | |
152 | // _ => Some(types[1].clean(cx)) | |
153 | // }; | |
154 | GenericArgs::Parenthesized { inputs, output } | |
60c5eb7d | 155 | } |
dfeec247 | 156 | _ => GenericArgs::AngleBracketed { args, bindings }, |
60c5eb7d XL |
157 | } |
158 | } | |
159 | ||
160 | // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar | |
161 | // from Fn<(A, B,), C> to Fn(A, B) -> C | |
dfeec247 XL |
162 | pub fn external_path( |
163 | cx: &DocContext<'_>, | |
164 | name: Symbol, | |
165 | trait_did: Option<DefId>, | |
166 | has_self: bool, | |
167 | bindings: Vec<TypeBinding>, | |
168 | substs: SubstsRef<'_>, | |
169 | ) -> Path { | |
60c5eb7d XL |
170 | Path { |
171 | global: false, | |
172 | res: Res::Err, | |
173 | segments: vec![PathSegment { | |
174 | name: name.to_string(), | |
dfeec247 | 175 | args: external_generic_args(cx, trait_did, has_self, bindings, substs), |
60c5eb7d XL |
176 | }], |
177 | } | |
178 | } | |
179 | ||
180 | /// The point of this function is to replace bounds with types. | |
181 | /// | |
182 | /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return | |
183 | /// `[Display, Option]` (we just returns the list of the types, we don't care about the | |
184 | /// wrapped types in here). | |
185 | pub fn get_real_types( | |
186 | generics: &Generics, | |
187 | arg: &Type, | |
188 | cx: &DocContext<'_>, | |
189 | recurse: i32, | |
ba9703b0 | 190 | ) -> FxHashSet<(Type, TypeKind)> { |
60c5eb7d XL |
191 | let arg_s = arg.print().to_string(); |
192 | let mut res = FxHashSet::default(); | |
dfeec247 XL |
193 | if recurse >= 10 { |
194 | // FIXME: remove this whole recurse thing when the recursion bug is fixed | |
60c5eb7d XL |
195 | return res; |
196 | } | |
197 | if arg.is_full_generic() { | |
dfeec247 XL |
198 | if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { |
199 | &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(), | |
200 | _ => false, | |
60c5eb7d XL |
201 | }) { |
202 | let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); | |
203 | for bound in bounds.iter() { | |
ba9703b0 XL |
204 | if let GenericBound::TraitBound(ref poly_trait, _) = *bound { |
205 | for x in poly_trait.generic_params.iter() { | |
206 | if !x.is_type() { | |
207 | continue; | |
208 | } | |
209 | if let Some(ty) = x.get_type() { | |
210 | let adds = get_real_types(generics, &ty, cx, recurse + 1); | |
211 | if !adds.is_empty() { | |
212 | res.extend(adds); | |
213 | } else if !ty.is_full_generic() { | |
214 | if let Some(kind) = | |
f9f354fc | 215 | ty.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) |
ba9703b0 XL |
216 | { |
217 | res.insert((ty, kind)); | |
60c5eb7d XL |
218 | } |
219 | } | |
220 | } | |
221 | } | |
60c5eb7d XL |
222 | } |
223 | } | |
224 | } | |
dfeec247 | 225 | if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { |
60c5eb7d XL |
226 | for bound in bound.get_bounds().unwrap_or_else(|| &[]) { |
227 | if let Some(ty) = bound.get_trait_type() { | |
228 | let adds = get_real_types(generics, &ty, cx, recurse + 1); | |
229 | if !adds.is_empty() { | |
230 | res.extend(adds); | |
231 | } else if !ty.is_full_generic() { | |
f9f354fc | 232 | if let Some(kind) = ty.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { |
ba9703b0 XL |
233 | res.insert((ty.clone(), kind)); |
234 | } | |
60c5eb7d XL |
235 | } |
236 | } | |
237 | } | |
238 | } | |
239 | } else { | |
f9f354fc | 240 | if let Some(kind) = arg.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { |
ba9703b0 XL |
241 | res.insert((arg.clone(), kind)); |
242 | } | |
60c5eb7d XL |
243 | if let Some(gens) = arg.generics() { |
244 | for gen in gens.iter() { | |
245 | if gen.is_full_generic() { | |
246 | let adds = get_real_types(generics, gen, cx, recurse + 1); | |
247 | if !adds.is_empty() { | |
248 | res.extend(adds); | |
249 | } | |
f9f354fc | 250 | } else if let Some(kind) = gen.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { |
ba9703b0 | 251 | res.insert((gen.clone(), kind)); |
60c5eb7d XL |
252 | } |
253 | } | |
254 | } | |
255 | } | |
256 | res | |
257 | } | |
258 | ||
259 | /// Return the full list of types when bounds have been resolved. | |
260 | /// | |
261 | /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return | |
262 | /// `[u32, Display, Option]`. | |
263 | pub fn get_all_types( | |
264 | generics: &Generics, | |
265 | decl: &FnDecl, | |
266 | cx: &DocContext<'_>, | |
ba9703b0 | 267 | ) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) { |
60c5eb7d XL |
268 | let mut all_types = FxHashSet::default(); |
269 | for arg in decl.inputs.values.iter() { | |
270 | if arg.type_.is_self_type() { | |
271 | continue; | |
272 | } | |
273 | let args = get_real_types(generics, &arg.type_, cx, 0); | |
274 | if !args.is_empty() { | |
275 | all_types.extend(args); | |
276 | } else { | |
f9f354fc | 277 | if let Some(kind) = arg.type_.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { |
ba9703b0 XL |
278 | all_types.insert((arg.type_.clone(), kind)); |
279 | } | |
60c5eb7d XL |
280 | } |
281 | } | |
282 | ||
283 | let ret_types = match decl.output { | |
74b04a01 | 284 | FnRetTy::Return(ref return_type) => { |
60c5eb7d XL |
285 | let mut ret = get_real_types(generics, &return_type, cx, 0); |
286 | if ret.is_empty() { | |
f9f354fc | 287 | if let Some(kind) = return_type.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { |
ba9703b0 XL |
288 | ret.insert((return_type.clone(), kind)); |
289 | } | |
60c5eb7d XL |
290 | } |
291 | ret.into_iter().collect() | |
292 | } | |
293 | _ => Vec::new(), | |
294 | }; | |
295 | (all_types.into_iter().collect(), ret_types) | |
296 | } | |
297 | ||
298 | pub fn strip_type(ty: Type) -> Type { | |
299 | match ty { | |
300 | Type::ResolvedPath { path, param_names, did, is_generic } => { | |
301 | Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic } | |
302 | } | |
303 | Type::Tuple(inner_tys) => { | |
304 | Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) | |
305 | } | |
306 | Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), | |
307 | Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), | |
308 | Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), | |
309 | Type::BorrowedRef { lifetime, mutability, type_ } => { | |
310 | Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } | |
311 | } | |
dfeec247 XL |
312 | Type::QPath { name, self_type, trait_ } => Type::QPath { |
313 | name, | |
314 | self_type: Box::new(strip_type(*self_type)), | |
315 | trait_: Box::new(strip_type(*trait_)), | |
316 | }, | |
317 | _ => ty, | |
60c5eb7d XL |
318 | } |
319 | } | |
320 | ||
321 | pub fn strip_path(path: &Path) -> Path { | |
dfeec247 XL |
322 | let segments = path |
323 | .segments | |
324 | .iter() | |
325 | .map(|s| PathSegment { | |
60c5eb7d | 326 | name: s.name.clone(), |
dfeec247 XL |
327 | args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] }, |
328 | }) | |
329 | .collect(); | |
60c5eb7d | 330 | |
dfeec247 | 331 | Path { global: path.global, res: path.res, segments } |
60c5eb7d XL |
332 | } |
333 | ||
f035d41b | 334 | pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { |
60c5eb7d XL |
335 | let segments = match *p { |
336 | hir::QPath::Resolved(_, ref path) => &path.segments, | |
337 | hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(), | |
3dfed10e | 338 | hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(), |
60c5eb7d XL |
339 | }; |
340 | ||
341 | let mut s = String::new(); | |
342 | for (i, seg) in segments.iter().enumerate() { | |
343 | if i > 0 { | |
344 | s.push_str("::"); | |
345 | } | |
346 | if seg.ident.name != kw::PathRoot { | |
347 | s.push_str(&seg.ident.as_str()); | |
348 | } | |
349 | } | |
350 | s | |
351 | } | |
352 | ||
dfeec247 | 353 | pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut Vec<Item>) { |
60c5eb7d XL |
354 | let tcx = cx.tcx; |
355 | ||
356 | for item in items { | |
357 | let target = match item.inner { | |
358 | ItemEnum::TypedefItem(ref t, true) => &t.type_, | |
359 | _ => continue, | |
360 | }; | |
361 | let primitive = match *target { | |
362 | ResolvedPath { did, .. } if did.is_local() => continue, | |
363 | ResolvedPath { did, .. } => { | |
364 | ret.extend(inline::build_impls(cx, did, None)); | |
dfeec247 | 365 | continue; |
60c5eb7d XL |
366 | } |
367 | _ => match target.primitive_type() { | |
368 | Some(prim) => prim, | |
369 | None => continue, | |
dfeec247 | 370 | }, |
60c5eb7d | 371 | }; |
3dfed10e | 372 | for &did in primitive.impls(tcx) { |
60c5eb7d XL |
373 | if !did.is_local() { |
374 | inline::build_impl(cx, did, None, ret); | |
375 | } | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
380 | pub trait ToSource { | |
381 | fn to_src(&self, cx: &DocContext<'_>) -> String; | |
382 | } | |
383 | ||
dfeec247 | 384 | impl ToSource for rustc_span::Span { |
60c5eb7d XL |
385 | fn to_src(&self, cx: &DocContext<'_>) -> String { |
386 | debug!("converting span {:?} to snippet", self.clean(cx)); | |
387 | let sn = match cx.sess().source_map().span_to_snippet(*self) { | |
388 | Ok(x) => x, | |
dfeec247 | 389 | Err(_) => String::new(), |
60c5eb7d XL |
390 | }; |
391 | debug!("got snippet {}", sn); | |
392 | sn | |
393 | } | |
394 | } | |
395 | ||
f035d41b | 396 | pub fn name_from_pat(p: &hir::Pat<'_>) -> String { |
dfeec247 | 397 | use rustc_hir::*; |
60c5eb7d XL |
398 | debug!("trying to get a name from pattern: {:?}", p); |
399 | ||
400 | match p.kind { | |
401 | PatKind::Wild => "_".to_string(), | |
402 | PatKind::Binding(_, _, ident, _) => ident.to_string(), | |
403 | PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), | |
dfeec247 XL |
404 | PatKind::Struct(ref name, ref fields, etc) => format!( |
405 | "{} {{ {}{} }}", | |
406 | qpath_to_string(name), | |
407 | fields | |
408 | .iter() | |
409 | .map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat))) | |
410 | .collect::<Vec<String>>() | |
411 | .join(", "), | |
412 | if etc { ", .." } else { "" } | |
413 | ), | |
60c5eb7d XL |
414 | PatKind::Or(ref pats) => { |
415 | pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ") | |
416 | } | |
dfeec247 XL |
417 | PatKind::Tuple(ref elts, _) => format!( |
418 | "({})", | |
419 | elts.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(", ") | |
420 | ), | |
60c5eb7d XL |
421 | PatKind::Box(ref p) => name_from_pat(&**p), |
422 | PatKind::Ref(ref p, _) => name_from_pat(&**p), | |
423 | PatKind::Lit(..) => { | |
dfeec247 | 424 | warn!( |
1b1a35ee | 425 | "tried to get argument name from PatKind::Lit, which is silly in function arguments" |
dfeec247 | 426 | ); |
60c5eb7d | 427 | "()".to_string() |
dfeec247 XL |
428 | } |
429 | PatKind::Range(..) => panic!( | |
430 | "tried to get argument name from PatKind::Range, \ | |
1b1a35ee | 431 | which is not allowed in function arguments" |
dfeec247 | 432 | ), |
60c5eb7d XL |
433 | PatKind::Slice(ref begin, ref mid, ref end) => { |
434 | let begin = begin.iter().map(|p| name_from_pat(&**p)); | |
435 | let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); | |
436 | let end = end.iter().map(|p| name_from_pat(&**p)); | |
437 | format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", ")) | |
dfeec247 | 438 | } |
60c5eb7d XL |
439 | } |
440 | } | |
441 | ||
74b04a01 | 442 | pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { |
60c5eb7d | 443 | match n.val { |
3dfed10e XL |
444 | ty::ConstKind::Unevaluated(def, _, promoted) => { |
445 | let mut s = if let Some(def) = def.as_local() { | |
446 | let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); | |
60c5eb7d XL |
447 | print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id)) |
448 | } else { | |
3dfed10e | 449 | inline::print_inlined_const(cx, def.did) |
dfeec247 XL |
450 | }; |
451 | if let Some(promoted) = promoted { | |
452 | s.push_str(&format!("::{:?}", promoted)) | |
60c5eb7d | 453 | } |
dfeec247 XL |
454 | s |
455 | } | |
60c5eb7d XL |
456 | _ => { |
457 | let mut s = n.to_string(); | |
458 | // array lengths are obviously usize | |
f035d41b XL |
459 | if s.ends_with("_usize") { |
460 | let n = s.len() - "_usize".len(); | |
60c5eb7d XL |
461 | s.truncate(n); |
462 | if s.ends_with(": ") { | |
463 | let n = s.len() - ": ".len(); | |
464 | s.truncate(n); | |
465 | } | |
466 | } | |
467 | s | |
dfeec247 XL |
468 | } |
469 | } | |
470 | } | |
471 | ||
472 | pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option<String> { | |
ba9703b0 | 473 | cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { |
74b04a01 | 474 | let ty = cx.tcx.type_of(def_id); |
1b1a35ee | 475 | match (val, ty.kind()) { |
74b04a01 XL |
476 | (_, &ty::Ref(..)) => None, |
477 | (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, | |
478 | (ConstValue::Scalar(_), _) => { | |
479 | let const_ = ty::Const::from_value(cx.tcx, val, ty); | |
480 | Some(print_const_with_custom_print_scalar(cx, const_)) | |
dfeec247 XL |
481 | } |
482 | _ => None, | |
74b04a01 | 483 | } |
ba9703b0 | 484 | }) |
dfeec247 XL |
485 | } |
486 | ||
487 | fn format_integer_with_underscore_sep(num: &str) -> String { | |
488 | let num_chars: Vec<_> = num.chars().collect(); | |
489 | let num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 }; | |
490 | ||
491 | num_chars[..num_start_index] | |
492 | .iter() | |
493 | .chain(num_chars[num_start_index..].rchunks(3).rev().intersperse(&['_']).flatten()) | |
494 | .collect() | |
495 | } | |
496 | ||
497 | fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { | |
498 | // Use a slightly different format for integer types which always shows the actual value. | |
499 | // For all other types, fallback to the original `pretty_print_const`. | |
1b1a35ee | 500 | match (ct.val, ct.ty.kind()) { |
dfeec247 XL |
501 | (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Uint(ui)) => { |
502 | format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str()) | |
503 | } | |
504 | (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Int(i)) => { | |
505 | let ty = cx.tcx.lift(&ct.ty).unwrap(); | |
506 | let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; | |
507 | let sign_extended_data = sign_extend(data, size) as i128; | |
508 | ||
509 | format!( | |
510 | "{}{}", | |
511 | format_integer_with_underscore_sep(&sign_extended_data.to_string()), | |
512 | i.name_str() | |
513 | ) | |
514 | } | |
515 | _ => ct.to_string(), | |
516 | } | |
517 | } | |
518 | ||
519 | pub fn is_literal_expr(cx: &DocContext<'_>, hir_id: hir::HirId) -> bool { | |
520 | if let hir::Node::Expr(expr) = cx.tcx.hir().get(hir_id) { | |
521 | if let hir::ExprKind::Lit(_) = &expr.kind { | |
522 | return true; | |
523 | } | |
524 | ||
525 | if let hir::ExprKind::Unary(hir::UnOp::UnNeg, expr) = &expr.kind { | |
526 | if let hir::ExprKind::Lit(_) = &expr.kind { | |
527 | return true; | |
528 | } | |
529 | } | |
60c5eb7d | 530 | } |
dfeec247 XL |
531 | |
532 | false | |
60c5eb7d XL |
533 | } |
534 | ||
535 | pub fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String { | |
dfeec247 XL |
536 | let value = &cx.tcx.hir().body(body).value; |
537 | ||
538 | let snippet = if !value.span.from_expansion() { | |
539 | cx.sess().source_map().span_to_snippet(value.span).ok() | |
540 | } else { | |
541 | None | |
542 | }; | |
543 | ||
ba9703b0 | 544 | snippet.unwrap_or_else(|| rustc_hir_pretty::id_to_string(&cx.tcx.hir(), body.hir_id)) |
60c5eb7d XL |
545 | } |
546 | ||
547 | /// Given a type Path, resolve it to a Type using the TyCtxt | |
dfeec247 | 548 | pub fn resolve_type(cx: &DocContext<'_>, path: Path, id: hir::HirId) -> Type { |
ba9703b0 | 549 | debug!("resolve_type({:?},{:?})", path, id); |
60c5eb7d XL |
550 | |
551 | let is_generic = match path.res { | |
74b04a01 | 552 | Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), |
60c5eb7d XL |
553 | Res::SelfTy(..) if path.segments.len() == 1 => { |
554 | return Generic(kw::SelfUpper.to_string()); | |
555 | } | |
556 | Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { | |
557 | return Generic(format!("{:#}", path.print())); | |
558 | } | |
ba9703b0 | 559 | Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, |
60c5eb7d XL |
560 | _ => false, |
561 | }; | |
562 | let did = register_res(&*cx, path.res); | |
563 | ResolvedPath { path, param_names: None, did, is_generic } | |
564 | } | |
565 | ||
566 | pub fn get_auto_trait_and_blanket_impls( | |
567 | cx: &DocContext<'tcx>, | |
568 | ty: Ty<'tcx>, | |
569 | param_env_def_id: DefId, | |
570 | ) -> impl Iterator<Item = Item> { | |
dfeec247 XL |
571 | AutoTraitFinder::new(cx) |
572 | .get_auto_trait_impls(ty, param_env_def_id) | |
573 | .into_iter() | |
60c5eb7d XL |
574 | .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)) |
575 | } | |
576 | ||
577 | pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { | |
578 | debug!("register_res({:?})", res); | |
579 | ||
580 | let (did, kind) = match res { | |
581 | Res::Def(DefKind::Fn, i) => (i, TypeKind::Function), | |
582 | Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef), | |
583 | Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum), | |
584 | Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait), | |
3dfed10e XL |
585 | Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => { |
586 | (cx.tcx.parent(i).unwrap(), TypeKind::Trait) | |
587 | } | |
60c5eb7d XL |
588 | Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct), |
589 | Res::Def(DefKind::Union, i) => (i, TypeKind::Union), | |
590 | Res::Def(DefKind::Mod, i) => (i, TypeKind::Module), | |
591 | Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign), | |
592 | Res::Def(DefKind::Const, i) => (i, TypeKind::Const), | |
593 | Res::Def(DefKind::Static, i) => (i, TypeKind::Static), | |
dfeec247 XL |
594 | Res::Def(DefKind::Variant, i) => { |
595 | (cx.tcx.parent(i).expect("cannot get parent def id"), TypeKind::Enum) | |
596 | } | |
60c5eb7d XL |
597 | Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind { |
598 | MacroKind::Bang => (i, TypeKind::Macro), | |
599 | MacroKind::Attr => (i, TypeKind::Attr), | |
600 | MacroKind::Derive => (i, TypeKind::Derive), | |
601 | }, | |
602 | Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), | |
603 | Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), | |
1b1a35ee | 604 | Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id, |
dfeec247 | 605 | _ => return res.def_id(), |
60c5eb7d | 606 | }; |
dfeec247 XL |
607 | if did.is_local() { |
608 | return did; | |
609 | } | |
60c5eb7d XL |
610 | inline::record_extern_fqn(cx, did, kind); |
611 | if let TypeKind::Trait = kind { | |
612 | inline::record_extern_trait(cx, did); | |
613 | } | |
614 | did | |
615 | } | |
616 | ||
617 | pub fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { | |
618 | ImportSource { | |
dfeec247 | 619 | did: if path.res.opt_def_id().is_none() { None } else { Some(register_res(cx, path.res)) }, |
60c5eb7d XL |
620 | path, |
621 | } | |
622 | } | |
623 | ||
624 | pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R | |
625 | where | |
626 | F: FnOnce() -> R, | |
627 | { | |
628 | let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut()); | |
629 | let r = f(); | |
630 | assert!(cx.impl_trait_bounds.borrow().is_empty()); | |
631 | *cx.impl_trait_bounds.borrow_mut() = old_bounds; | |
632 | r | |
633 | } |