]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
Auto merge of #82530 - Aaron1011:rollup-aalwq15, r=Aaron1011
[rust.git] / src / librustdoc / html / format.rs
1 //! HTML formatting module
2 //!
3 //! This module contains a large number of `fmt::Display` implementations for
4 //! various types in `rustdoc::clean`. These implementations all currently
5 //! assume that HTML output is desired, although it may be possible to redesign
6 //! them in the future to instead emit any format desired.
7
8 use std::borrow::Cow;
9 use std::cell::Cell;
10 use std::fmt;
11
12 use rustc_data_structures::fx::FxHashSet;
13 use rustc_hir as hir;
14 use rustc_middle::ty::TyCtxt;
15 use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
16 use rustc_target::spec::abi::Abi;
17
18 use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType};
19 use crate::formats::cache::Cache;
20 use crate::formats::item_type::ItemType;
21 use crate::html::escape::Escape;
22 use crate::html::render::cache::ExternalLocation;
23 use crate::html::render::CURRENT_DEPTH;
24
25 crate trait Print {
26     fn print(self, buffer: &mut Buffer);
27 }
28
29 impl<F> Print for F
30 where
31     F: FnOnce(&mut Buffer),
32 {
33     fn print(self, buffer: &mut Buffer) {
34         (self)(buffer)
35     }
36 }
37
38 impl Print for String {
39     fn print(self, buffer: &mut Buffer) {
40         buffer.write_str(&self);
41     }
42 }
43
44 impl Print for &'_ str {
45     fn print(self, buffer: &mut Buffer) {
46         buffer.write_str(self);
47     }
48 }
49
50 #[derive(Debug, Clone)]
51 crate struct Buffer {
52     for_html: bool,
53     buffer: String,
54 }
55
56 impl Buffer {
57     crate fn empty_from(v: &Buffer) -> Buffer {
58         Buffer { for_html: v.for_html, buffer: String::new() }
59     }
60
61     crate fn html() -> Buffer {
62         Buffer { for_html: true, buffer: String::new() }
63     }
64
65     crate fn new() -> Buffer {
66         Buffer { for_html: false, buffer: String::new() }
67     }
68
69     crate fn is_empty(&self) -> bool {
70         self.buffer.is_empty()
71     }
72
73     crate fn into_inner(self) -> String {
74         self.buffer
75     }
76
77     crate fn insert_str(&mut self, idx: usize, s: &str) {
78         self.buffer.insert_str(idx, s);
79     }
80
81     crate fn push_str(&mut self, s: &str) {
82         self.buffer.push_str(s);
83     }
84
85     // Intended for consumption by write! and writeln! (std::fmt) but without
86     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
87     // import).
88     crate fn write_str(&mut self, s: &str) {
89         self.buffer.push_str(s);
90     }
91
92     // Intended for consumption by write! and writeln! (std::fmt) but without
93     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
94     // import).
95     crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
96         use fmt::Write;
97         self.buffer.write_fmt(v).unwrap();
98     }
99
100     crate fn to_display<T: Print>(mut self, t: T) -> String {
101         t.print(&mut self);
102         self.into_inner()
103     }
104
105     crate fn is_for_html(&self) -> bool {
106         self.for_html
107     }
108 }
109
110 /// Wrapper struct for properly emitting a function or method declaration.
111 crate struct Function<'a> {
112     /// The declaration to emit.
113     crate decl: &'a clean::FnDecl,
114     /// The length of the function header and name. In other words, the number of characters in the
115     /// function declaration up to but not including the parentheses.
116     ///
117     /// Used to determine line-wrapping.
118     crate header_len: usize,
119     /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
120     crate indent: usize,
121     /// Whether the function is async or not.
122     crate asyncness: hir::IsAsync,
123 }
124
125 /// Wrapper struct for emitting a where-clause from Generics.
126 crate struct WhereClause<'a> {
127     /// The Generics from which to emit a where-clause.
128     crate gens: &'a clean::Generics,
129     /// The number of spaces to indent each line with.
130     crate indent: usize,
131     /// Whether the where-clause needs to add a comma and newline after the last bound.
132     crate end_newline: bool,
133 }
134
135 fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
136     display_fn(move |f| {
137         for (i, item) in items.enumerate() {
138             if i != 0 {
139                 write!(f, ", ")?;
140             }
141             fmt::Display::fmt(&item, f)?;
142         }
143         Ok(())
144     })
145 }
146
147 crate fn print_generic_bounds<'a>(
148     bounds: &'a [clean::GenericBound],
149     cache: &'a Cache,
150 ) -> impl fmt::Display + 'a {
151     display_fn(move |f| {
152         let mut bounds_dup = FxHashSet::default();
153
154         for (i, bound) in
155             bounds.iter().filter(|b| bounds_dup.insert(b.print(cache).to_string())).enumerate()
156         {
157             if i > 0 {
158                 f.write_str(" + ")?;
159             }
160             fmt::Display::fmt(&bound.print(cache), f)?;
161         }
162         Ok(())
163     })
164 }
165
166 impl clean::GenericParamDef {
167     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
168         display_fn(move |f| match self.kind {
169             clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
170             clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
171                 f.write_str(&*self.name.as_str())?;
172
173                 if !bounds.is_empty() {
174                     if f.alternate() {
175                         write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
176                     } else {
177                         write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
178                     }
179                 }
180
181                 if let Some(ref ty) = default {
182                     if f.alternate() {
183                         write!(f, " = {:#}", ty.print(cache))?;
184                     } else {
185                         write!(f, "&nbsp;=&nbsp;{}", ty.print(cache))?;
186                     }
187                 }
188
189                 Ok(())
190             }
191             clean::GenericParamDefKind::Const { ref ty, .. } => {
192                 if f.alternate() {
193                     write!(f, "const {}: {:#}", self.name, ty.print(cache))
194                 } else {
195                     write!(f, "const {}:&nbsp;{}", self.name, ty.print(cache))
196                 }
197             }
198         })
199     }
200 }
201
202 impl clean::Generics {
203     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
204         display_fn(move |f| {
205             let real_params =
206                 self.params.iter().filter(|p| !p.is_synthetic_type_param()).collect::<Vec<_>>();
207             if real_params.is_empty() {
208                 return Ok(());
209             }
210             if f.alternate() {
211                 write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cache))))
212             } else {
213                 write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print(cache))))
214             }
215         })
216     }
217 }
218
219 impl<'a> WhereClause<'a> {
220     crate fn print<'b>(&'b self, cache: &'b Cache) -> impl fmt::Display + 'b {
221         display_fn(move |f| {
222             let &WhereClause { gens, indent, end_newline } = self;
223             if gens.where_predicates.is_empty() {
224                 return Ok(());
225             }
226             let mut clause = String::new();
227             if f.alternate() {
228                 clause.push_str(" where");
229             } else {
230                 if end_newline {
231                     clause.push_str(" <span class=\"where fmt-newline\">where");
232                 } else {
233                     clause.push_str(" <span class=\"where\">where");
234                 }
235             }
236             for (i, pred) in gens.where_predicates.iter().enumerate() {
237                 if f.alternate() {
238                     clause.push(' ');
239                 } else {
240                     clause.push_str("<br>");
241                 }
242
243                 match pred {
244                     clean::WherePredicate::BoundPredicate { ty, bounds } => {
245                         let bounds = bounds;
246                         if f.alternate() {
247                             clause.push_str(&format!(
248                                 "{:#}: {:#}",
249                                 ty.print(cache),
250                                 print_generic_bounds(bounds, cache)
251                             ));
252                         } else {
253                             clause.push_str(&format!(
254                                 "{}: {}",
255                                 ty.print(cache),
256                                 print_generic_bounds(bounds, cache)
257                             ));
258                         }
259                     }
260                     clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
261                         clause.push_str(&format!(
262                             "{}: {}",
263                             lifetime.print(),
264                             bounds
265                                 .iter()
266                                 .map(|b| b.print(cache).to_string())
267                                 .collect::<Vec<_>>()
268                                 .join(" + ")
269                         ));
270                     }
271                     clean::WherePredicate::EqPredicate { lhs, rhs } => {
272                         if f.alternate() {
273                             clause.push_str(&format!(
274                                 "{:#} == {:#}",
275                                 lhs.print(cache),
276                                 rhs.print(cache)
277                             ));
278                         } else {
279                             clause.push_str(&format!(
280                                 "{} == {}",
281                                 lhs.print(cache),
282                                 rhs.print(cache)
283                             ));
284                         }
285                     }
286                 }
287
288                 if i < gens.where_predicates.len() - 1 || end_newline {
289                     clause.push(',');
290                 }
291             }
292
293             if end_newline {
294                 // add a space so stripping <br> tags and breaking spaces still renders properly
295                 if f.alternate() {
296                     clause.push(' ');
297                 } else {
298                     clause.push_str("&nbsp;");
299                 }
300             }
301
302             if !f.alternate() {
303                 clause.push_str("</span>");
304                 let padding = "&nbsp;".repeat(indent + 4);
305                 clause = clause.replace("<br>", &format!("<br>{}", padding));
306                 clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
307                 if !end_newline {
308                     clause.insert_str(0, "<br>");
309                 }
310             }
311             write!(f, "{}", clause)
312         })
313     }
314 }
315
316 impl clean::Lifetime {
317     crate fn print(&self) -> impl fmt::Display + '_ {
318         self.get_ref()
319     }
320 }
321
322 impl clean::Constant {
323     crate fn print(&self) -> impl fmt::Display + '_ {
324         display_fn(move |f| {
325             if f.alternate() {
326                 f.write_str(&self.expr)
327             } else {
328                 write!(f, "{}", Escape(&self.expr))
329             }
330         })
331     }
332 }
333
334 impl clean::PolyTrait {
335     fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
336         display_fn(move |f| {
337             if !self.generic_params.is_empty() {
338                 if f.alternate() {
339                     write!(
340                         f,
341                         "for<{:#}> ",
342                         comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
343                     )?;
344                 } else {
345                     write!(
346                         f,
347                         "for&lt;{}&gt; ",
348                         comma_sep(self.generic_params.iter().map(|g| g.print(cache)))
349                     )?;
350                 }
351             }
352             if f.alternate() {
353                 write!(f, "{:#}", self.trait_.print(cache))
354             } else {
355                 write!(f, "{}", self.trait_.print(cache))
356             }
357         })
358     }
359 }
360
361 impl clean::GenericBound {
362     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
363         display_fn(move |f| match self {
364             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
365             clean::GenericBound::TraitBound(ty, modifier) => {
366                 let modifier_str = match modifier {
367                     hir::TraitBoundModifier::None => "",
368                     hir::TraitBoundModifier::Maybe => "?",
369                     hir::TraitBoundModifier::MaybeConst => "?const",
370                 };
371                 if f.alternate() {
372                     write!(f, "{}{:#}", modifier_str, ty.print(cache))
373                 } else {
374                     write!(f, "{}{}", modifier_str, ty.print(cache))
375                 }
376             }
377         })
378     }
379 }
380
381 impl clean::GenericArgs {
382     fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
383         display_fn(move |f| {
384             match self {
385                 clean::GenericArgs::AngleBracketed { args, bindings } => {
386                     if !args.is_empty() || !bindings.is_empty() {
387                         if f.alternate() {
388                             f.write_str("<")?;
389                         } else {
390                             f.write_str("&lt;")?;
391                         }
392                         let mut comma = false;
393                         for arg in args {
394                             if comma {
395                                 f.write_str(", ")?;
396                             }
397                             comma = true;
398                             if f.alternate() {
399                                 write!(f, "{:#}", arg.print(cache))?;
400                             } else {
401                                 write!(f, "{}", arg.print(cache))?;
402                             }
403                         }
404                         for binding in bindings {
405                             if comma {
406                                 f.write_str(", ")?;
407                             }
408                             comma = true;
409                             if f.alternate() {
410                                 write!(f, "{:#}", binding.print(cache))?;
411                             } else {
412                                 write!(f, "{}", binding.print(cache))?;
413                             }
414                         }
415                         if f.alternate() {
416                             f.write_str(">")?;
417                         } else {
418                             f.write_str("&gt;")?;
419                         }
420                     }
421                 }
422                 clean::GenericArgs::Parenthesized { inputs, output } => {
423                     f.write_str("(")?;
424                     let mut comma = false;
425                     for ty in inputs {
426                         if comma {
427                             f.write_str(", ")?;
428                         }
429                         comma = true;
430                         if f.alternate() {
431                             write!(f, "{:#}", ty.print(cache))?;
432                         } else {
433                             write!(f, "{}", ty.print(cache))?;
434                         }
435                     }
436                     f.write_str(")")?;
437                     if let Some(ref ty) = *output {
438                         if f.alternate() {
439                             write!(f, " -> {:#}", ty.print(cache))?;
440                         } else {
441                             write!(f, " -&gt; {}", ty.print(cache))?;
442                         }
443                     }
444                 }
445             }
446             Ok(())
447         })
448     }
449 }
450
451 impl clean::PathSegment {
452     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
453         display_fn(move |f| {
454             if f.alternate() {
455                 write!(f, "{}{:#}", self.name, self.args.print(cache))
456             } else {
457                 write!(f, "{}{}", self.name, self.args.print(cache))
458             }
459         })
460     }
461 }
462
463 impl clean::Path {
464     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
465         display_fn(move |f| {
466             if self.global {
467                 f.write_str("::")?
468             }
469
470             for (i, seg) in self.segments.iter().enumerate() {
471                 if i > 0 {
472                     f.write_str("::")?
473                 }
474                 if f.alternate() {
475                     write!(f, "{:#}", seg.print(cache))?;
476                 } else {
477                     write!(f, "{}", seg.print(cache))?;
478                 }
479             }
480             Ok(())
481         })
482     }
483 }
484
485 crate fn href(did: DefId, cache: &Cache) -> Option<(String, ItemType, Vec<String>)> {
486     if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
487         return None;
488     }
489
490     let depth = CURRENT_DEPTH.with(|l| l.get());
491     let (fqp, shortty, mut url) = match cache.paths.get(&did) {
492         Some(&(ref fqp, shortty)) => (fqp, shortty, "../".repeat(depth)),
493         None => {
494             let &(ref fqp, shortty) = cache.external_paths.get(&did)?;
495             (
496                 fqp,
497                 shortty,
498                 match cache.extern_locations[&did.krate] {
499                     (.., ExternalLocation::Remote(ref s)) => s.to_string(),
500                     (.., ExternalLocation::Local) => "../".repeat(depth),
501                     (.., ExternalLocation::Unknown) => return None,
502                 },
503             )
504         }
505     };
506     for component in &fqp[..fqp.len() - 1] {
507         url.push_str(component);
508         url.push('/');
509     }
510     match shortty {
511         ItemType::Module => {
512             url.push_str(fqp.last().unwrap());
513             url.push_str("/index.html");
514         }
515         _ => {
516             url.push_str(shortty.as_str());
517             url.push('.');
518             url.push_str(fqp.last().unwrap());
519             url.push_str(".html");
520         }
521     }
522     Some((url, shortty, fqp.to_vec()))
523 }
524
525 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
526 /// rendering function with the necessary arguments for linking to a local path.
527 fn resolved_path(
528     w: &mut fmt::Formatter<'_>,
529     did: DefId,
530     path: &clean::Path,
531     print_all: bool,
532     use_absolute: bool,
533     cache: &Cache,
534 ) -> fmt::Result {
535     let last = path.segments.last().unwrap();
536
537     if print_all {
538         for seg in &path.segments[..path.segments.len() - 1] {
539             write!(w, "{}::", seg.name)?;
540         }
541     }
542     if w.alternate() {
543         write!(w, "{}{:#}", &last.name, last.args.print(cache))?;
544     } else {
545         let path = if use_absolute {
546             if let Some((_, _, fqp)) = href(did, cache) {
547                 format!(
548                     "{}::{}",
549                     fqp[..fqp.len() - 1].join("::"),
550                     anchor(did, fqp.last().unwrap(), cache)
551                 )
552             } else {
553                 last.name.to_string()
554             }
555         } else {
556             anchor(did, &*last.name.as_str(), cache).to_string()
557         };
558         write!(w, "{}{}", path, last.args.print(cache))?;
559     }
560     Ok(())
561 }
562
563 fn primitive_link(
564     f: &mut fmt::Formatter<'_>,
565     prim: clean::PrimitiveType,
566     name: &str,
567     m: &Cache,
568 ) -> fmt::Result {
569     let mut needs_termination = false;
570     if !f.alternate() {
571         match m.primitive_locations.get(&prim) {
572             Some(&def_id) if def_id.is_local() => {
573                 let len = CURRENT_DEPTH.with(|s| s.get());
574                 let len = if len == 0 { 0 } else { len - 1 };
575                 write!(
576                     f,
577                     "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
578                     "../".repeat(len),
579                     prim.to_url_str()
580                 )?;
581                 needs_termination = true;
582             }
583             Some(&def_id) => {
584                 let loc = match m.extern_locations[&def_id.krate] {
585                     (ref cname, _, ExternalLocation::Remote(ref s)) => Some((cname, s.to_string())),
586                     (ref cname, _, ExternalLocation::Local) => {
587                         let len = CURRENT_DEPTH.with(|s| s.get());
588                         Some((cname, "../".repeat(len)))
589                     }
590                     (.., ExternalLocation::Unknown) => None,
591                 };
592                 if let Some((cname, root)) = loc {
593                     write!(
594                         f,
595                         "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
596                         root,
597                         cname,
598                         prim.to_url_str()
599                     )?;
600                     needs_termination = true;
601                 }
602             }
603             None => {}
604         }
605     }
606     write!(f, "{}", name)?;
607     if needs_termination {
608         write!(f, "</a>")?;
609     }
610     Ok(())
611 }
612
613 /// Helper to render type parameters
614 fn tybounds<'a>(
615     param_names: &'a Option<Vec<clean::GenericBound>>,
616     cache: &'a Cache,
617 ) -> impl fmt::Display + 'a {
618     display_fn(move |f| match *param_names {
619         Some(ref params) => {
620             for param in params {
621                 write!(f, " + ")?;
622                 fmt::Display::fmt(&param.print(cache), f)?;
623             }
624             Ok(())
625         }
626         None => Ok(()),
627     })
628 }
629
630 crate fn anchor<'a>(did: DefId, text: &'a str, cache: &'a Cache) -> impl fmt::Display + 'a {
631     display_fn(move |f| {
632         if let Some((url, short_ty, fqp)) = href(did, cache) {
633             write!(
634                 f,
635                 r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
636                 short_ty,
637                 url,
638                 short_ty,
639                 fqp.join("::"),
640                 text
641             )
642         } else {
643             write!(f, "{}", text)
644         }
645     })
646 }
647
648 fn fmt_type(
649     t: &clean::Type,
650     f: &mut fmt::Formatter<'_>,
651     use_absolute: bool,
652     cache: &Cache,
653 ) -> fmt::Result {
654     debug!("fmt_type(t = {:?})", t);
655
656     match *t {
657         clean::Generic(name) => write!(f, "{}", name),
658         clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
659             if param_names.is_some() {
660                 f.write_str("dyn ")?;
661             }
662             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
663             resolved_path(f, did, path, is_generic, use_absolute, cache)?;
664             fmt::Display::fmt(&tybounds(param_names, cache), f)
665         }
666         clean::Infer => write!(f, "_"),
667         clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cache),
668         clean::BareFunction(ref decl) => {
669             if f.alternate() {
670                 write!(
671                     f,
672                     "{:#}{}{:#}fn{:#}",
673                     decl.print_hrtb_with_space(cache),
674                     decl.unsafety.print_with_space(),
675                     print_abi_with_space(decl.abi),
676                     decl.decl.print(cache)
677                 )
678             } else {
679                 write!(
680                     f,
681                     "{}{}{}",
682                     decl.print_hrtb_with_space(cache),
683                     decl.unsafety.print_with_space(),
684                     print_abi_with_space(decl.abi)
685                 )?;
686                 primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
687                 write!(f, "{}", decl.decl.print(cache))
688             }
689         }
690         clean::Tuple(ref typs) => {
691             match &typs[..] {
692                 &[] => primitive_link(f, PrimitiveType::Unit, "()", cache),
693                 &[ref one] => {
694                     primitive_link(f, PrimitiveType::Tuple, "(", cache)?;
695                     // Carry `f.alternate()` into this display w/o branching manually.
696                     fmt::Display::fmt(&one.print(cache), f)?;
697                     primitive_link(f, PrimitiveType::Tuple, ",)", cache)
698                 }
699                 many => {
700                     primitive_link(f, PrimitiveType::Tuple, "(", cache)?;
701                     for (i, item) in many.iter().enumerate() {
702                         if i != 0 {
703                             write!(f, ", ")?;
704                         }
705                         fmt::Display::fmt(&item.print(cache), f)?;
706                     }
707                     primitive_link(f, PrimitiveType::Tuple, ")", cache)
708                 }
709             }
710         }
711         clean::Slice(ref t) => {
712             primitive_link(f, PrimitiveType::Slice, "[", cache)?;
713             fmt::Display::fmt(&t.print(cache), f)?;
714             primitive_link(f, PrimitiveType::Slice, "]", cache)
715         }
716         clean::Array(ref t, ref n) => {
717             primitive_link(f, PrimitiveType::Array, "[", cache)?;
718             fmt::Display::fmt(&t.print(cache), f)?;
719             if f.alternate() {
720                 primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cache)
721             } else {
722                 primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cache)
723             }
724         }
725         clean::Never => primitive_link(f, PrimitiveType::Never, "!", cache),
726         clean::RawPointer(m, ref t) => {
727             let m = match m {
728                 hir::Mutability::Mut => "mut",
729                 hir::Mutability::Not => "const",
730             };
731             match **t {
732                 clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => {
733                     if f.alternate() {
734                         primitive_link(
735                             f,
736                             clean::PrimitiveType::RawPointer,
737                             &format!("*{} {:#}", m, t.print(cache)),
738                             cache,
739                         )
740                     } else {
741                         primitive_link(
742                             f,
743                             clean::PrimitiveType::RawPointer,
744                             &format!("*{} {}", m, t.print(cache)),
745                             cache,
746                         )
747                     }
748                 }
749                 _ => {
750                     primitive_link(
751                         f,
752                         clean::PrimitiveType::RawPointer,
753                         &format!("*{} ", m),
754                         cache,
755                     )?;
756                     fmt::Display::fmt(&t.print(cache), f)
757                 }
758             }
759         }
760         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
761             let lt = match l {
762                 Some(l) => format!("{} ", l.print()),
763                 _ => String::new(),
764             };
765             let m = mutability.print_with_space();
766             let amp = if f.alternate() { "&".to_string() } else { "&amp;".to_string() };
767             match **ty {
768                 clean::Slice(ref bt) => {
769                     // `BorrowedRef{ ... Slice(T) }` is `&[T]`
770                     match **bt {
771                         clean::Generic(_) => {
772                             if f.alternate() {
773                                 primitive_link(
774                                     f,
775                                     PrimitiveType::Slice,
776                                     &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cache)),
777                                     cache,
778                                 )
779                             } else {
780                                 primitive_link(
781                                     f,
782                                     PrimitiveType::Slice,
783                                     &format!("{}{}{}[{}]", amp, lt, m, bt.print(cache)),
784                                     cache,
785                                 )
786                             }
787                         }
788                         _ => {
789                             primitive_link(
790                                 f,
791                                 PrimitiveType::Slice,
792                                 &format!("{}{}{}[", amp, lt, m),
793                                 cache,
794                             )?;
795                             if f.alternate() {
796                                 write!(f, "{:#}", bt.print(cache))?;
797                             } else {
798                                 write!(f, "{}", bt.print(cache))?;
799                             }
800                             primitive_link(f, PrimitiveType::Slice, "]", cache)
801                         }
802                     }
803                 }
804                 clean::ResolvedPath { param_names: Some(ref v), .. } if !v.is_empty() => {
805                     write!(f, "{}{}{}(", amp, lt, m)?;
806                     fmt_type(&ty, f, use_absolute, cache)?;
807                     write!(f, ")")
808                 }
809                 clean::Generic(..) => {
810                     primitive_link(
811                         f,
812                         PrimitiveType::Reference,
813                         &format!("{}{}{}", amp, lt, m),
814                         cache,
815                     )?;
816                     fmt_type(&ty, f, use_absolute, cache)
817                 }
818                 _ => {
819                     write!(f, "{}{}{}", amp, lt, m)?;
820                     fmt_type(&ty, f, use_absolute, cache)
821                 }
822             }
823         }
824         clean::ImplTrait(ref bounds) => {
825             if f.alternate() {
826                 write!(f, "impl {:#}", print_generic_bounds(bounds, cache))
827             } else {
828                 write!(f, "impl {}", print_generic_bounds(bounds, cache))
829             }
830         }
831         clean::QPath { ref name, ref self_type, ref trait_ } => {
832             let should_show_cast = match *trait_ {
833                 box clean::ResolvedPath { ref path, .. } => {
834                     !path.segments.is_empty() && !self_type.is_self_type()
835                 }
836                 _ => true,
837             };
838             if f.alternate() {
839                 if should_show_cast {
840                     write!(f, "<{:#} as {:#}>::", self_type.print(cache), trait_.print(cache))?
841                 } else {
842                     write!(f, "{:#}::", self_type.print(cache))?
843                 }
844             } else {
845                 if should_show_cast {
846                     write!(f, "&lt;{} as {}&gt;::", self_type.print(cache), trait_.print(cache))?
847                 } else {
848                     write!(f, "{}::", self_type.print(cache))?
849                 }
850             };
851             match *trait_ {
852                 // It's pretty unsightly to look at `<A as B>::C` in output, and
853                 // we've got hyperlinking on our side, so try to avoid longer
854                 // notation as much as possible by making `C` a hyperlink to trait
855                 // `B` to disambiguate.
856                 //
857                 // FIXME: this is still a lossy conversion and there should probably
858                 //        be a better way of representing this in general? Most of
859                 //        the ugliness comes from inlining across crates where
860                 //        everything comes in as a fully resolved QPath (hard to
861                 //        look at).
862                 box clean::ResolvedPath { did, ref param_names, .. } => {
863                     match href(did, cache) {
864                         Some((ref url, _, ref path)) if !f.alternate() => {
865                             write!(
866                                 f,
867                                 "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
868                                     title=\"type {path}::{name}\">{name}</a>",
869                                 url = url,
870                                 shortty = ItemType::AssocType,
871                                 name = name,
872                                 path = path.join("::")
873                             )?;
874                         }
875                         _ => write!(f, "{}", name)?,
876                     }
877
878                     // FIXME: `param_names` are not rendered, and this seems bad?
879                     drop(param_names);
880                     Ok(())
881                 }
882                 _ => write!(f, "{}", name),
883             }
884         }
885     }
886 }
887
888 impl clean::Type {
889     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
890         display_fn(move |f| fmt_type(self, f, false, cache))
891     }
892 }
893
894 impl clean::Impl {
895     crate fn print<'a>(&'a self, cache: &'a Cache, use_absolute: bool) -> impl fmt::Display + 'a {
896         display_fn(move |f| {
897             if f.alternate() {
898                 write!(f, "impl{:#} ", self.generics.print(cache))?;
899             } else {
900                 write!(f, "impl{} ", self.generics.print(cache))?;
901             }
902
903             if let Some(ref ty) = self.trait_ {
904                 if self.negative_polarity {
905                     write!(f, "!")?;
906                 }
907                 fmt::Display::fmt(&ty.print(cache), f)?;
908                 write!(f, " for ")?;
909             }
910
911             if let Some(ref ty) = self.blanket_impl {
912                 fmt_type(ty, f, use_absolute, cache)?;
913             } else {
914                 fmt_type(&self.for_, f, use_absolute, cache)?;
915             }
916
917             let where_clause = WhereClause { gens: &self.generics, indent: 0, end_newline: true };
918             fmt::Display::fmt(&where_clause.print(cache), f)?;
919             Ok(())
920         })
921     }
922 }
923
924 impl clean::Arguments {
925     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
926         display_fn(move |f| {
927             for (i, input) in self.values.iter().enumerate() {
928                 if !input.name.is_empty() {
929                     write!(f, "{}: ", input.name)?;
930                 }
931                 if f.alternate() {
932                     write!(f, "{:#}", input.type_.print(cache))?;
933                 } else {
934                     write!(f, "{}", input.type_.print(cache))?;
935                 }
936                 if i + 1 < self.values.len() {
937                     write!(f, ", ")?;
938                 }
939             }
940             Ok(())
941         })
942     }
943 }
944
945 impl clean::FnRetTy {
946     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
947         display_fn(move |f| match self {
948             clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()),
949             clean::Return(ty) if f.alternate() => write!(f, " -> {:#}", ty.print(cache)),
950             clean::Return(ty) => write!(f, " -&gt; {}", ty.print(cache)),
951             clean::DefaultReturn => Ok(()),
952         })
953     }
954 }
955
956 impl clean::BareFunctionDecl {
957     fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
958         display_fn(move |f| {
959             if !self.generic_params.is_empty() {
960                 write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache))))
961             } else {
962                 Ok(())
963             }
964         })
965     }
966 }
967
968 impl clean::FnDecl {
969     crate fn print<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
970         display_fn(move |f| {
971             let ellipsis = if self.c_variadic { ", ..." } else { "" };
972             if f.alternate() {
973                 write!(
974                     f,
975                     "({args:#}{ellipsis}){arrow:#}",
976                     args = self.inputs.print(cache),
977                     ellipsis = ellipsis,
978                     arrow = self.output.print(cache)
979                 )
980             } else {
981                 write!(
982                     f,
983                     "({args}{ellipsis}){arrow}",
984                     args = self.inputs.print(cache),
985                     ellipsis = ellipsis,
986                     arrow = self.output.print(cache)
987                 )
988             }
989         })
990     }
991 }
992
993 impl Function<'_> {
994     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
995         display_fn(move |f| {
996             let &Function { decl, header_len, indent, asyncness } = self;
997             let amp = if f.alternate() { "&" } else { "&amp;" };
998             let mut args = String::new();
999             let mut args_plain = String::new();
1000             for (i, input) in decl.inputs.values.iter().enumerate() {
1001                 if i == 0 {
1002                     args.push_str("<br>");
1003                 }
1004
1005                 if let Some(selfty) = input.to_self() {
1006                     match selfty {
1007                         clean::SelfValue => {
1008                             args.push_str("self");
1009                             args_plain.push_str("self");
1010                         }
1011                         clean::SelfBorrowed(Some(ref lt), mtbl) => {
1012                             args.push_str(&format!(
1013                                 "{}{} {}self",
1014                                 amp,
1015                                 lt.print(),
1016                                 mtbl.print_with_space()
1017                             ));
1018                             args_plain.push_str(&format!(
1019                                 "&{} {}self",
1020                                 lt.print(),
1021                                 mtbl.print_with_space()
1022                             ));
1023                         }
1024                         clean::SelfBorrowed(None, mtbl) => {
1025                             args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
1026                             args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
1027                         }
1028                         clean::SelfExplicit(ref typ) => {
1029                             if f.alternate() {
1030                                 args.push_str(&format!("self: {:#}", typ.print(cache)));
1031                             } else {
1032                                 args.push_str(&format!("self: {}", typ.print(cache)));
1033                             }
1034                             args_plain.push_str(&format!("self: {:#}", typ.print(cache)));
1035                         }
1036                     }
1037                 } else {
1038                     if i > 0 {
1039                         args.push_str(" <br>");
1040                         args_plain.push(' ');
1041                     }
1042                     if !input.name.is_empty() {
1043                         args.push_str(&format!("{}: ", input.name));
1044                         args_plain.push_str(&format!("{}: ", input.name));
1045                     }
1046
1047                     if f.alternate() {
1048                         args.push_str(&format!("{:#}", input.type_.print(cache)));
1049                     } else {
1050                         args.push_str(&input.type_.print(cache).to_string());
1051                     }
1052                     args_plain.push_str(&format!("{:#}", input.type_.print(cache)));
1053                 }
1054                 if i + 1 < decl.inputs.values.len() {
1055                     args.push(',');
1056                     args_plain.push(',');
1057                 }
1058             }
1059
1060             let mut args_plain = format!("({})", args_plain);
1061
1062             if decl.c_variadic {
1063                 args.push_str(",<br> ...");
1064                 args_plain.push_str(", ...");
1065             }
1066
1067             let output = if let hir::IsAsync::Async = asyncness {
1068                 Cow::Owned(decl.sugared_async_return_type())
1069             } else {
1070                 Cow::Borrowed(&decl.output)
1071             };
1072
1073             let arrow_plain = format!("{:#}", &output.print(cache));
1074             let arrow = if f.alternate() {
1075                 format!("{:#}", &output.print(cache))
1076             } else {
1077                 output.print(cache).to_string()
1078             };
1079
1080             let declaration_len = header_len + args_plain.len() + arrow_plain.len();
1081             let output = if declaration_len > 80 {
1082                 let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
1083                 let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
1084                 format!(
1085                     "({args}{close}){arrow}",
1086                     args = args.replace("<br>", &full_pad),
1087                     close = close_pad,
1088                     arrow = arrow
1089                 )
1090             } else {
1091                 format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
1092             };
1093
1094             if f.alternate() {
1095                 write!(f, "{}", output.replace("<br>", "\n"))
1096             } else {
1097                 write!(f, "{}", output)
1098             }
1099         })
1100     }
1101 }
1102
1103 impl clean::Visibility {
1104     crate fn print_with_space<'tcx>(
1105         self,
1106         tcx: TyCtxt<'tcx>,
1107         item_did: DefId,
1108         cache: &Cache,
1109     ) -> impl fmt::Display + 'tcx {
1110         use rustc_span::symbol::kw;
1111
1112         let to_print = match self {
1113             clean::Public => "pub ".to_owned(),
1114             clean::Inherited => String::new(),
1115             clean::Visibility::Restricted(vis_did) => {
1116                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
1117                 //                 However, rustdoc currently never displays a module's
1118                 //                 visibility, so it shouldn't matter.
1119                 let parent_module = find_nearest_parent_module(tcx, item_did);
1120
1121                 if vis_did.index == CRATE_DEF_INDEX {
1122                     "pub(crate) ".to_owned()
1123                 } else if parent_module == Some(vis_did) {
1124                     // `pub(in foo)` where `foo` is the parent module
1125                     // is the same as no visibility modifier
1126                     String::new()
1127                 } else if parent_module
1128                     .map(|parent| find_nearest_parent_module(tcx, parent))
1129                     .flatten()
1130                     == Some(vis_did)
1131                 {
1132                     "pub(super) ".to_owned()
1133                 } else {
1134                     let path = tcx.def_path(vis_did);
1135                     debug!("path={:?}", path);
1136                     let first_name =
1137                         path.data[0].data.get_opt_name().expect("modules are always named");
1138                     // modified from `resolved_path()` to work with `DefPathData`
1139                     let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
1140                     let anchor = anchor(vis_did, &last_name.as_str(), cache).to_string();
1141
1142                     let mut s = "pub(".to_owned();
1143                     if path.data.len() != 1
1144                         || (first_name != kw::SelfLower && first_name != kw::Super)
1145                     {
1146                         s.push_str("in ");
1147                     }
1148                     for seg in &path.data[..path.data.len() - 1] {
1149                         s.push_str(&format!("{}::", seg.data.get_opt_name().unwrap()));
1150                     }
1151                     s.push_str(&format!("{}) ", anchor));
1152                     s
1153                 }
1154             }
1155         };
1156         display_fn(move |f| f.write_str(&to_print))
1157     }
1158 }
1159
1160 crate trait PrintWithSpace {
1161     fn print_with_space(&self) -> &str;
1162 }
1163
1164 impl PrintWithSpace for hir::Unsafety {
1165     fn print_with_space(&self) -> &str {
1166         match self {
1167             hir::Unsafety::Unsafe => "unsafe ",
1168             hir::Unsafety::Normal => "",
1169         }
1170     }
1171 }
1172
1173 impl PrintWithSpace for hir::Constness {
1174     fn print_with_space(&self) -> &str {
1175         match self {
1176             hir::Constness::Const => "const ",
1177             hir::Constness::NotConst => "",
1178         }
1179     }
1180 }
1181
1182 impl PrintWithSpace for hir::IsAsync {
1183     fn print_with_space(&self) -> &str {
1184         match self {
1185             hir::IsAsync::Async => "async ",
1186             hir::IsAsync::NotAsync => "",
1187         }
1188     }
1189 }
1190
1191 impl PrintWithSpace for hir::Mutability {
1192     fn print_with_space(&self) -> &str {
1193         match self {
1194             hir::Mutability::Not => "",
1195             hir::Mutability::Mut => "mut ",
1196         }
1197     }
1198 }
1199
1200 impl clean::Import {
1201     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
1202         display_fn(move |f| match self.kind {
1203             clean::ImportKind::Simple(name) => {
1204                 if name == self.source.path.last() {
1205                     write!(f, "use {};", self.source.print(cache))
1206                 } else {
1207                     write!(f, "use {} as {};", self.source.print(cache), name)
1208                 }
1209             }
1210             clean::ImportKind::Glob => {
1211                 if self.source.path.segments.is_empty() {
1212                     write!(f, "use *;")
1213                 } else {
1214                     write!(f, "use {}::*;", self.source.print(cache))
1215                 }
1216             }
1217         })
1218     }
1219 }
1220
1221 impl clean::ImportSource {
1222     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
1223         display_fn(move |f| match self.did {
1224             Some(did) => resolved_path(f, did, &self.path, true, false, cache),
1225             _ => {
1226                 for seg in &self.path.segments[..self.path.segments.len() - 1] {
1227                     write!(f, "{}::", seg.name)?;
1228                 }
1229                 let name = self.path.last_name();
1230                 if let hir::def::Res::PrimTy(p) = self.path.res {
1231                     primitive_link(f, PrimitiveType::from(p), &*name, cache)?;
1232                 } else {
1233                     write!(f, "{}", name)?;
1234                 }
1235                 Ok(())
1236             }
1237         })
1238     }
1239 }
1240
1241 impl clean::TypeBinding {
1242     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
1243         display_fn(move |f| {
1244             f.write_str(&*self.name.as_str())?;
1245             match self.kind {
1246                 clean::TypeBindingKind::Equality { ref ty } => {
1247                     if f.alternate() {
1248                         write!(f, " = {:#}", ty.print(cache))?;
1249                     } else {
1250                         write!(f, " = {}", ty.print(cache))?;
1251                     }
1252                 }
1253                 clean::TypeBindingKind::Constraint { ref bounds } => {
1254                     if !bounds.is_empty() {
1255                         if f.alternate() {
1256                             write!(f, ": {:#}", print_generic_bounds(bounds, cache))?;
1257                         } else {
1258                             write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cache))?;
1259                         }
1260                     }
1261                 }
1262             }
1263             Ok(())
1264         })
1265     }
1266 }
1267
1268 crate fn print_abi_with_space(abi: Abi) -> impl fmt::Display {
1269     display_fn(move |f| {
1270         let quot = if f.alternate() { "\"" } else { "&quot;" };
1271         match abi {
1272             Abi::Rust => Ok(()),
1273             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1274         }
1275     })
1276 }
1277
1278 crate fn print_default_space<'a>(v: bool) -> &'a str {
1279     if v { "default " } else { "" }
1280 }
1281
1282 impl clean::GenericArg {
1283     crate fn print<'b, 'a: 'b>(&'a self, cache: &'b Cache) -> impl fmt::Display + 'b {
1284         display_fn(move |f| match self {
1285             clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
1286             clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cache), f),
1287             clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(), f),
1288         })
1289     }
1290 }
1291
1292 crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
1293     struct WithFormatter<F>(Cell<Option<F>>);
1294
1295     impl<F> fmt::Display for WithFormatter<F>
1296     where
1297         F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
1298     {
1299         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1300             (self.0.take()).unwrap()(f)
1301         }
1302     }
1303
1304     WithFormatter(Cell::new(Some(f)))
1305 }