]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
Auto merge of #58341 - alexreg:cosmetic-2-doc-comments, r=steveklabnik
[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::fmt;
10
11 use rustc::hir::def_id::DefId;
12 use rustc_target::spec::abi::Abi;
13 use rustc::hir;
14
15 use clean::{self, PrimitiveType};
16 use core::DocAccessLevels;
17 use html::item_type::ItemType;
18 use html::render::{self, cache, CURRENT_LOCATION_KEY};
19
20 /// Helper to render an optional visibility with a space after it (if the
21 /// visibility is preset)
22 #[derive(Copy, Clone)]
23 pub struct VisSpace<'a>(pub &'a Option<clean::Visibility>);
24 /// Similarly to VisSpace, this structure is used to render a function style with a
25 /// space after it.
26 #[derive(Copy, Clone)]
27 pub struct UnsafetySpace(pub hir::Unsafety);
28 /// Similarly to VisSpace, this structure is used to render a function constness
29 /// with a space after it.
30 #[derive(Copy, Clone)]
31 pub struct ConstnessSpace(pub hir::Constness);
32 /// Similarly to VisSpace, this structure is used to render a function asyncness
33 /// with a space after it.
34 #[derive(Copy, Clone)]
35 pub struct AsyncSpace(pub hir::IsAsync);
36 /// Similar to VisSpace, but used for mutability
37 #[derive(Copy, Clone)]
38 pub struct MutableSpace(pub clean::Mutability);
39 /// Similar to VisSpace, but used for mutability
40 #[derive(Copy, Clone)]
41 pub struct RawMutableSpace(pub clean::Mutability);
42 /// Wrapper struct for emitting type parameter bounds.
43 pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
44 /// Wrapper struct for emitting a comma-separated list of items
45 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
46 pub struct AbiSpace(pub Abi);
47
48 /// Wrapper struct for properly emitting a function or method declaration.
49 pub struct Function<'a> {
50     /// The declaration to emit.
51     pub decl: &'a clean::FnDecl,
52     /// The length of the function's "name", used to determine line-wrapping.
53     pub name_len: usize,
54     /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
55     pub indent: usize,
56     /// Whether the function is async or not.
57     pub asyncness: hir::IsAsync,
58 }
59
60 /// Wrapper struct for emitting a where-clause from Generics.
61 pub struct WhereClause<'a>{
62     /// The Generics from which to emit a where-clause.
63     pub gens: &'a clean::Generics,
64     /// The number of spaces to indent each line with.
65     pub indent: usize,
66     /// Whether the where-clause needs to add a comma and newline after the last bound.
67     pub end_newline: bool,
68 }
69
70 pub struct HRef<'a> {
71     pub did: DefId,
72     pub text: &'a str,
73 }
74
75 impl<'a> VisSpace<'a> {
76     pub fn get(self) -> &'a Option<clean::Visibility> {
77         let VisSpace(v) = self; v
78     }
79 }
80
81 impl UnsafetySpace {
82     pub fn get(&self) -> hir::Unsafety {
83         let UnsafetySpace(v) = *self; v
84     }
85 }
86
87 impl ConstnessSpace {
88     pub fn get(&self) -> hir::Constness {
89         let ConstnessSpace(v) = *self; v
90     }
91 }
92
93 impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
94     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95         for (i, item) in self.0.iter().enumerate() {
96             if i != 0 { write!(f, ", ")?; }
97             fmt::Display::fmt(item, f)?;
98         }
99         Ok(())
100     }
101 }
102
103 impl<'a> fmt::Display for GenericBounds<'a> {
104     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105         let &GenericBounds(bounds) = self;
106         for (i, bound) in bounds.iter().enumerate() {
107             if i > 0 {
108                 f.write_str(" + ")?;
109             }
110             fmt::Display::fmt(bound, f)?;
111         }
112         Ok(())
113     }
114 }
115
116 impl fmt::Display for clean::GenericParamDef {
117     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118         match self.kind {
119             clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
120             clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
121                 f.write_str(&self.name)?;
122
123                 if !bounds.is_empty() {
124                     if f.alternate() {
125                         write!(f, ": {:#}", GenericBounds(bounds))?;
126                     } else {
127                         write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
128                     }
129                 }
130
131                 if let Some(ref ty) = default {
132                     if f.alternate() {
133                         write!(f, " = {:#}", ty)?;
134                     } else {
135                         write!(f, "&nbsp;=&nbsp;{}", ty)?;
136                     }
137                 }
138
139                 Ok(())
140             }
141         }
142     }
143 }
144
145 impl fmt::Display for clean::Generics {
146     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147         let real_params = self.params
148             .iter()
149             .filter(|p| !p.is_synthetic_type_param())
150             .collect::<Vec<_>>();
151         if real_params.is_empty() {
152             return Ok(());
153         }
154         if f.alternate() {
155             write!(f, "<{:#}>", CommaSep(&real_params))
156         } else {
157             write!(f, "&lt;{}&gt;", CommaSep(&real_params))
158         }
159     }
160 }
161
162 impl<'a> fmt::Display for WhereClause<'a> {
163     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164         let &WhereClause { gens, indent, end_newline } = self;
165         if gens.where_predicates.is_empty() {
166             return Ok(());
167         }
168         let mut clause = String::new();
169         if f.alternate() {
170             clause.push_str(" where");
171         } else {
172             if end_newline {
173                 clause.push_str(" <span class=\"where fmt-newline\">where");
174             } else {
175                 clause.push_str(" <span class=\"where\">where");
176             }
177         }
178         for (i, pred) in gens.where_predicates.iter().enumerate() {
179             if f.alternate() {
180                 clause.push(' ');
181             } else {
182                 clause.push_str("<br>");
183             }
184
185             match pred {
186                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
187                     let bounds = bounds;
188                     if f.alternate() {
189                         clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds)));
190                     } else {
191                         clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds)));
192                     }
193                 }
194                 &clean::WherePredicate::RegionPredicate { ref lifetime,
195                                                           ref bounds } => {
196                     clause.push_str(&format!("{}: ", lifetime));
197                     for (i, lifetime) in bounds.iter().enumerate() {
198                         if i > 0 {
199                             clause.push_str(" + ");
200                         }
201
202                         clause.push_str(&lifetime.to_string());
203                     }
204                 }
205                 &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
206                     if f.alternate() {
207                         clause.push_str(&format!("{:#} == {:#}", lhs, rhs));
208                     } else {
209                         clause.push_str(&format!("{} == {}", lhs, rhs));
210                     }
211                 }
212             }
213
214             if i < gens.where_predicates.len() - 1 || end_newline {
215                 clause.push(',');
216             }
217         }
218
219         if end_newline {
220             // add a space so stripping <br> tags and breaking spaces still renders properly
221             if f.alternate() {
222                 clause.push(' ');
223             } else {
224                 clause.push_str("&nbsp;");
225             }
226         }
227
228         if !f.alternate() {
229             clause.push_str("</span>");
230             let padding = "&nbsp;".repeat(indent + 4);
231             clause = clause.replace("<br>", &format!("<br>{}", padding));
232             clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
233             if !end_newline {
234                 clause.insert_str(0, "<br>");
235             }
236         }
237         write!(f, "{}", clause)
238     }
239 }
240
241 impl fmt::Display for clean::Lifetime {
242     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243         f.write_str(self.get_ref())?;
244         Ok(())
245     }
246 }
247
248 impl fmt::Display for clean::PolyTrait {
249     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250         if !self.generic_params.is_empty() {
251             if f.alternate() {
252                 write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
253             } else {
254                 write!(f, "for&lt;{}&gt; ", CommaSep(&self.generic_params))?;
255             }
256         }
257         if f.alternate() {
258             write!(f, "{:#}", self.trait_)
259         } else {
260             write!(f, "{}", self.trait_)
261         }
262     }
263 }
264
265 impl fmt::Display for clean::GenericBound {
266     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267         match *self {
268             clean::GenericBound::Outlives(ref lt) => {
269                 write!(f, "{}", *lt)
270             }
271             clean::GenericBound::TraitBound(ref ty, modifier) => {
272                 let modifier_str = match modifier {
273                     hir::TraitBoundModifier::None => "",
274                     hir::TraitBoundModifier::Maybe => "?",
275                 };
276                 if f.alternate() {
277                     write!(f, "{}{:#}", modifier_str, *ty)
278                 } else {
279                     write!(f, "{}{}", modifier_str, *ty)
280                 }
281             }
282         }
283     }
284 }
285
286 impl fmt::Display for clean::GenericArgs {
287     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288         match *self {
289             clean::GenericArgs::AngleBracketed {
290                 ref lifetimes, ref types, ref bindings
291             } => {
292                 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
293                     if f.alternate() {
294                         f.write_str("<")?;
295                     } else {
296                         f.write_str("&lt;")?;
297                     }
298                     let mut comma = false;
299                     for lifetime in lifetimes {
300                         if comma {
301                             f.write_str(", ")?;
302                         }
303                         comma = true;
304                         write!(f, "{}", *lifetime)?;
305                     }
306                     for ty in types {
307                         if comma {
308                             f.write_str(", ")?;
309                         }
310                         comma = true;
311                         if f.alternate() {
312                             write!(f, "{:#}", *ty)?;
313                         } else {
314                             write!(f, "{}", *ty)?;
315                         }
316                     }
317                     for binding in bindings {
318                         if comma {
319                             f.write_str(", ")?;
320                         }
321                         comma = true;
322                         if f.alternate() {
323                             write!(f, "{:#}", *binding)?;
324                         } else {
325                             write!(f, "{}", *binding)?;
326                         }
327                     }
328                     if f.alternate() {
329                         f.write_str(">")?;
330                     } else {
331                         f.write_str("&gt;")?;
332                     }
333                 }
334             }
335             clean::GenericArgs::Parenthesized { ref inputs, ref output } => {
336                 f.write_str("(")?;
337                 let mut comma = false;
338                 for ty in inputs {
339                     if comma {
340                         f.write_str(", ")?;
341                     }
342                     comma = true;
343                     if f.alternate() {
344                         write!(f, "{:#}", *ty)?;
345                     } else {
346                         write!(f, "{}", *ty)?;
347                     }
348                 }
349                 f.write_str(")")?;
350                 if let Some(ref ty) = *output {
351                     if f.alternate() {
352                         write!(f, " -> {:#}", ty)?;
353                     } else {
354                         write!(f, " -&gt; {}", ty)?;
355                     }
356                 }
357             }
358         }
359         Ok(())
360     }
361 }
362
363 impl fmt::Display for clean::PathSegment {
364     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
365         f.write_str(&self.name)?;
366         if f.alternate() {
367             write!(f, "{:#}", self.args)
368         } else {
369             write!(f, "{}", self.args)
370         }
371     }
372 }
373
374 impl fmt::Display for clean::Path {
375     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376         if self.global {
377             f.write_str("::")?
378         }
379
380         for (i, seg) in self.segments.iter().enumerate() {
381             if i > 0 {
382                 f.write_str("::")?
383             }
384             if f.alternate() {
385                 write!(f, "{:#}", seg)?;
386             } else {
387                 write!(f, "{}", seg)?;
388             }
389         }
390         Ok(())
391     }
392 }
393
394 pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
395     let cache = cache();
396     if !did.is_local() && !cache.access_levels.is_doc_reachable(did) {
397         return None
398     }
399
400     let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
401     let (fqp, shortty, mut url) = match cache.paths.get(&did) {
402         Some(&(ref fqp, shortty)) => {
403             (fqp, shortty, "../".repeat(loc.len()))
404         }
405         None => {
406             let &(ref fqp, shortty) = cache.external_paths.get(&did)?;
407             (fqp, shortty, match cache.extern_locations[&did.krate] {
408                 (.., render::Remote(ref s)) => s.to_string(),
409                 (.., render::Local) => "../".repeat(loc.len()),
410                 (.., render::Unknown) => return None,
411             })
412         }
413     };
414     for component in &fqp[..fqp.len() - 1] {
415         url.push_str(component);
416         url.push_str("/");
417     }
418     match shortty {
419         ItemType::Module => {
420             url.push_str(fqp.last().unwrap());
421             url.push_str("/index.html");
422         }
423         _ => {
424             url.push_str(shortty.css_class());
425             url.push_str(".");
426             url.push_str(fqp.last().unwrap());
427             url.push_str(".html");
428         }
429     }
430     Some((url, shortty, fqp.to_vec()))
431 }
432
433 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
434 /// rendering function with the necessary arguments for linking to a local path.
435 fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
436                  print_all: bool, use_absolute: bool) -> fmt::Result {
437     let last = path.segments.last().unwrap();
438
439     if print_all {
440         for seg in &path.segments[..path.segments.len() - 1] {
441             write!(w, "{}::", seg.name)?;
442         }
443     }
444     if w.alternate() {
445         write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?;
446     } else {
447         let path = if use_absolute {
448             match href(did) {
449                 Some((_, _, fqp)) => {
450                     format!("{}::{}",
451                             fqp[..fqp.len() - 1].join("::"),
452                             HRef::new(did, fqp.last().unwrap()))
453                 }
454                 None => HRef::new(did, &last.name).to_string(),
455             }
456         } else {
457             HRef::new(did, &last.name).to_string()
458         };
459         write!(w, "{}{}", path, last.args)?;
460     }
461     Ok(())
462 }
463
464 fn primitive_link(f: &mut fmt::Formatter,
465                   prim: clean::PrimitiveType,
466                   name: &str) -> fmt::Result {
467     let m = cache();
468     let mut needs_termination = false;
469     if !f.alternate() {
470         match m.primitive_locations.get(&prim) {
471             Some(&def_id) if def_id.is_local() => {
472                 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
473                 let len = if len == 0 {0} else {len - 1};
474                 write!(f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
475                        "../".repeat(len),
476                        prim.to_url_str())?;
477                 needs_termination = true;
478             }
479             Some(&def_id) => {
480                 let loc = match m.extern_locations[&def_id.krate] {
481                     (ref cname, _, render::Remote(ref s)) => {
482                         Some((cname, s.to_string()))
483                     }
484                     (ref cname, _, render::Local) => {
485                         let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
486                         Some((cname, "../".repeat(len)))
487                     }
488                     (.., render::Unknown) => None,
489                 };
490                 if let Some((cname, root)) = loc {
491                     write!(f, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
492                            root,
493                            cname,
494                            prim.to_url_str())?;
495                     needs_termination = true;
496                 }
497             }
498             None => {}
499         }
500     }
501     write!(f, "{}", name)?;
502     if needs_termination {
503         write!(f, "</a>")?;
504     }
505     Ok(())
506 }
507
508 /// Helper to render type parameters
509 fn tybounds(w: &mut fmt::Formatter,
510             typarams: &Option<Vec<clean::GenericBound>>) -> fmt::Result {
511     match *typarams {
512         Some(ref params) => {
513             for param in params {
514                 write!(w, " + ")?;
515                 fmt::Display::fmt(param, w)?;
516             }
517             Ok(())
518         }
519         None => Ok(())
520     }
521 }
522
523 impl<'a> HRef<'a> {
524     pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
525         HRef { did: did, text: text }
526     }
527 }
528
529 impl<'a> fmt::Display for HRef<'a> {
530     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
531         match href(self.did) {
532             Some((url, shortty, fqp)) => if !f.alternate() {
533                 write!(f, "<a class=\"{}\" href=\"{}\" title=\"{} {}\">{}</a>",
534                        shortty, url, shortty, fqp.join("::"), self.text)
535             } else {
536                 write!(f, "{}", self.text)
537             },
538             _ => write!(f, "{}", self.text),
539         }
540     }
541 }
542
543 fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
544     match *t {
545         clean::Generic(ref name) => {
546             f.write_str(name)
547         }
548         clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
549             if typarams.is_some() {
550                 f.write_str("dyn ")?;
551             }
552             // Paths like T::Output and Self::Output should be rendered with all segments
553             resolved_path(f, did, path, is_generic, use_absolute)?;
554             tybounds(f, typarams)
555         }
556         clean::Infer => write!(f, "_"),
557         clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
558         clean::BareFunction(ref decl) => {
559             if f.alternate() {
560                 write!(f, "{}{:#}fn{:#}{:#}",
561                        UnsafetySpace(decl.unsafety),
562                        AbiSpace(decl.abi),
563                        CommaSep(&decl.generic_params),
564                        decl.decl)
565             } else {
566                 write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
567                 primitive_link(f, PrimitiveType::Fn, "fn")?;
568                 write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
569             }
570         }
571         clean::Tuple(ref typs) => {
572             match &typs[..] {
573                 &[] => primitive_link(f, PrimitiveType::Unit, "()"),
574                 &[ref one] => {
575                     primitive_link(f, PrimitiveType::Tuple, "(")?;
576                     //carry f.alternate() into this display w/o branching manually
577                     fmt::Display::fmt(one, f)?;
578                     primitive_link(f, PrimitiveType::Tuple, ",)")
579                 }
580                 many => {
581                     primitive_link(f, PrimitiveType::Tuple, "(")?;
582                     fmt::Display::fmt(&CommaSep(many), f)?;
583                     primitive_link(f, PrimitiveType::Tuple, ")")
584                 }
585             }
586         }
587         clean::Slice(ref t) => {
588             primitive_link(f, PrimitiveType::Slice, "[")?;
589             fmt::Display::fmt(t, f)?;
590             primitive_link(f, PrimitiveType::Slice, "]")
591         }
592         clean::Array(ref t, ref n) => {
593             primitive_link(f, PrimitiveType::Array, "[")?;
594             fmt::Display::fmt(t, f)?;
595             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
596         }
597         clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
598         clean::RawPointer(m, ref t) => {
599             match **t {
600                 clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
601                     if f.alternate() {
602                         primitive_link(f, clean::PrimitiveType::RawPointer,
603                                        &format!("*{}{:#}", RawMutableSpace(m), t))
604                     } else {
605                         primitive_link(f, clean::PrimitiveType::RawPointer,
606                                        &format!("*{}{}", RawMutableSpace(m), t))
607                     }
608                 }
609                 _ => {
610                     primitive_link(f, clean::PrimitiveType::RawPointer,
611                                    &format!("*{}", RawMutableSpace(m)))?;
612                     fmt::Display::fmt(t, f)
613                 }
614             }
615         }
616         clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
617             let lt = match *l {
618                 Some(ref l) => format!("{} ", *l),
619                 _ => String::new(),
620             };
621             let m = MutableSpace(mutability);
622             let amp = if f.alternate() {
623                 "&".to_string()
624             } else {
625                 "&amp;".to_string()
626             };
627             match **ty {
628                 clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
629                     match **bt {
630                         clean::Generic(_) => {
631                             if f.alternate() {
632                                 primitive_link(f, PrimitiveType::Slice,
633                                     &format!("{}{}{}[{:#}]", amp, lt, m, **bt))
634                             } else {
635                                 primitive_link(f, PrimitiveType::Slice,
636                                     &format!("{}{}{}[{}]", amp, lt, m, **bt))
637                             }
638                         }
639                         _ => {
640                             primitive_link(f, PrimitiveType::Slice,
641                                            &format!("{}{}{}[", amp, lt, m))?;
642                             if f.alternate() {
643                                 write!(f, "{:#}", **bt)?;
644                             } else {
645                                 write!(f, "{}", **bt)?;
646                             }
647                             primitive_link(f, PrimitiveType::Slice, "]")
648                         }
649                     }
650                 }
651                 clean::ResolvedPath { typarams: Some(ref v), .. } if !v.is_empty() => {
652                     write!(f, "{}{}{}(", amp, lt, m)?;
653                     fmt_type(&ty, f, use_absolute)?;
654                     write!(f, ")")
655                 }
656                 clean::Generic(..) => {
657                     primitive_link(f, PrimitiveType::Reference,
658                                    &format!("{}{}{}", amp, lt, m))?;
659                     fmt_type(&ty, f, use_absolute)
660                 }
661                 _ => {
662                     write!(f, "{}{}{}", amp, lt, m)?;
663                     fmt_type(&ty, f, use_absolute)
664                 }
665             }
666         }
667         clean::ImplTrait(ref bounds) => {
668             write!(f, "impl {}", GenericBounds(bounds))
669         }
670         clean::QPath { ref name, ref self_type, ref trait_ } => {
671             let should_show_cast = match *trait_ {
672                 box clean::ResolvedPath { ref path, .. } => {
673                     !path.segments.is_empty() && !self_type.is_self_type()
674                 }
675                 _ => true,
676             };
677             if f.alternate() {
678                 if should_show_cast {
679                     write!(f, "<{:#} as {:#}>::", self_type, trait_)?
680                 } else {
681                     write!(f, "{:#}::", self_type)?
682                 }
683             } else {
684                 if should_show_cast {
685                     write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
686                 } else {
687                     write!(f, "{}::", self_type)?
688                 }
689             };
690             match *trait_ {
691                 // It's pretty unsightly to look at `<A as B>::C` in output, and
692                 // we've got hyperlinking on our side, so try to avoid longer
693                 // notation as much as possible by making `C` a hyperlink to trait
694                 // `B` to disambiguate.
695                 //
696                 // FIXME: this is still a lossy conversion and there should probably
697                 //        be a better way of representing this in general? Most of
698                 //        the ugliness comes from inlining across crates where
699                 //        everything comes in as a fully resolved QPath (hard to
700                 //        look at).
701                 box clean::ResolvedPath { did, ref typarams, .. } => {
702                     match href(did) {
703                         Some((ref url, _, ref path)) if !f.alternate() => {
704                             write!(f,
705                                    "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
706                                    title=\"type {path}::{name}\">{name}</a>",
707                                    url = url,
708                                    shortty = ItemType::AssociatedType,
709                                    name = name,
710                                    path = path.join("::"))?;
711                         }
712                         _ => write!(f, "{}", name)?,
713                     }
714
715                     // FIXME: `typarams` are not rendered, and this seems bad?
716                     drop(typarams);
717                     Ok(())
718                 }
719                 _ => {
720                     write!(f, "{}", name)
721                 }
722             }
723         }
724         clean::Unique(..) => {
725             panic!("should have been cleaned")
726         }
727     }
728 }
729
730 impl fmt::Display for clean::Type {
731     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
732         fmt_type(self, f, false)
733     }
734 }
735
736 fn fmt_impl(i: &clean::Impl,
737             f: &mut fmt::Formatter,
738             link_trait: bool,
739             use_absolute: bool) -> fmt::Result {
740     if f.alternate() {
741         write!(f, "impl{:#} ", i.generics)?;
742     } else {
743         write!(f, "impl{} ", i.generics)?;
744     }
745
746     if let Some(ref ty) = i.trait_ {
747         if i.polarity == Some(clean::ImplPolarity::Negative) {
748             write!(f, "!")?;
749         }
750
751         if link_trait {
752             fmt::Display::fmt(ty, f)?;
753         } else {
754             match *ty {
755                 clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
756                     let last = path.segments.last().unwrap();
757                     fmt::Display::fmt(&last.name, f)?;
758                     fmt::Display::fmt(&last.args, f)?;
759                 }
760                 _ => unreachable!(),
761             }
762         }
763         write!(f, " for ")?;
764     }
765
766     if let Some(ref ty) = i.blanket_impl {
767         fmt_type(ty, f, use_absolute)?;
768     } else {
769         fmt_type(&i.for_, f, use_absolute)?;
770     }
771
772     fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
773     Ok(())
774 }
775
776 impl fmt::Display for clean::Impl {
777     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
778         fmt_impl(self, f, true, false)
779     }
780 }
781
782 // The difference from above is that trait is not hyperlinked.
783 pub fn fmt_impl_for_trait_page(i: &clean::Impl,
784                                f: &mut fmt::Formatter,
785                                use_absolute: bool) -> fmt::Result {
786     fmt_impl(i, f, false, use_absolute)
787 }
788
789 impl fmt::Display for clean::Arguments {
790     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
791         for (i, input) in self.values.iter().enumerate() {
792             if !input.name.is_empty() {
793                 write!(f, "{}: ", input.name)?;
794             }
795             if f.alternate() {
796                 write!(f, "{:#}", input.type_)?;
797             } else {
798                 write!(f, "{}", input.type_)?;
799             }
800             if i + 1 < self.values.len() { write!(f, ", ")?; }
801         }
802         Ok(())
803     }
804 }
805
806 impl fmt::Display for clean::FunctionRetTy {
807     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
808         match *self {
809             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
810             clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
811             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
812             clean::DefaultReturn => Ok(()),
813         }
814     }
815 }
816
817 impl fmt::Display for clean::FnDecl {
818     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
819         if self.variadic {
820             if f.alternate() {
821                 write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output)
822             } else {
823                 write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
824             }
825         } else {
826             if f.alternate() {
827                 write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
828             } else {
829                 write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
830             }
831         }
832     }
833 }
834
835 impl<'a> fmt::Display for Function<'a> {
836     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
837         let &Function { decl, name_len, indent, asyncness } = self;
838         let amp = if f.alternate() { "&" } else { "&amp;" };
839         let mut args = String::new();
840         let mut args_plain = String::new();
841         for (i, input) in decl.inputs.values.iter().enumerate() {
842             if i == 0 {
843                 args.push_str("<br>");
844             }
845
846             if let Some(selfty) = input.to_self() {
847                 match selfty {
848                     clean::SelfValue => {
849                         args.push_str("self");
850                         args_plain.push_str("self");
851                     }
852                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
853                         args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
854                         args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
855                     }
856                     clean::SelfBorrowed(None, mtbl) => {
857                         args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
858                         args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
859                     }
860                     clean::SelfExplicit(ref typ) => {
861                         if f.alternate() {
862                             args.push_str(&format!("self: {:#}", *typ));
863                         } else {
864                             args.push_str(&format!("self: {}", *typ));
865                         }
866                         args_plain.push_str(&format!("self: {:#}", *typ));
867                     }
868                 }
869             } else {
870                 if i > 0 {
871                     args.push_str(" <br>");
872                     args_plain.push_str(" ");
873                 }
874                 if !input.name.is_empty() {
875                     args.push_str(&format!("{}: ", input.name));
876                     args_plain.push_str(&format!("{}: ", input.name));
877                 }
878
879                 if f.alternate() {
880                     args.push_str(&format!("{:#}", input.type_));
881                 } else {
882                     args.push_str(&input.type_.to_string());
883                 }
884                 args_plain.push_str(&format!("{:#}", input.type_));
885             }
886             if i + 1 < decl.inputs.values.len() {
887                 args.push(',');
888                 args_plain.push(',');
889             }
890         }
891
892         if decl.variadic {
893             args.push_str(",<br> ...");
894             args_plain.push_str(", ...");
895         }
896
897         let output = if let hir::IsAsync::Async = asyncness {
898             Cow::Owned(decl.sugared_async_return_type())
899         } else {
900             Cow::Borrowed(&decl.output)
901         };
902
903         let arrow_plain = format!("{:#}", &output);
904         let arrow = if f.alternate() {
905             format!("{:#}", &output)
906         } else {
907             output.to_string()
908         };
909
910         let pad = " ".repeat(name_len);
911         let plain = format!("{pad}({args}){arrow}",
912                         pad = pad,
913                         args = args_plain,
914                         arrow = arrow_plain);
915
916         let output = if plain.len() > 80 {
917             let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
918             let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
919             format!("({args}{close}){arrow}",
920                     args = args.replace("<br>", &full_pad),
921                     close = close_pad,
922                     arrow = arrow)
923         } else {
924             format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
925         };
926
927         if f.alternate() {
928             write!(f, "{}", output.replace("<br>", "\n"))
929         } else {
930             write!(f, "{}", output)
931         }
932     }
933 }
934
935 impl<'a> fmt::Display for VisSpace<'a> {
936     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
937         match *self.get() {
938             Some(clean::Public) => f.write_str("pub "),
939             Some(clean::Inherited) | None => Ok(()),
940             Some(clean::Visibility::Crate) => write!(f, "pub(crate) "),
941             Some(clean::Visibility::Restricted(did, ref path)) => {
942                 f.write_str("pub(")?;
943                 if path.segments.len() != 1
944                     || (path.segments[0].name != "self" && path.segments[0].name != "super")
945                 {
946                     f.write_str("in ")?;
947                 }
948                 resolved_path(f, did, path, true, false)?;
949                 f.write_str(") ")
950             }
951         }
952     }
953 }
954
955 impl fmt::Display for UnsafetySpace {
956     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
957         match self.get() {
958             hir::Unsafety::Unsafe => write!(f, "unsafe "),
959             hir::Unsafety::Normal => Ok(())
960         }
961     }
962 }
963
964 impl fmt::Display for ConstnessSpace {
965     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
966         match self.get() {
967             hir::Constness::Const => write!(f, "const "),
968             hir::Constness::NotConst => Ok(())
969         }
970     }
971 }
972
973 impl fmt::Display for AsyncSpace {
974     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
975         match self.0 {
976             hir::IsAsync::Async => write!(f, "async "),
977             hir::IsAsync::NotAsync => Ok(()),
978         }
979     }
980 }
981
982 impl fmt::Display for clean::Import {
983     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
984         match *self {
985             clean::Import::Simple(ref name, ref src) => {
986                 if *name == src.path.last_name() {
987                     write!(f, "use {};", *src)
988                 } else {
989                     write!(f, "use {} as {};", *src, *name)
990                 }
991             }
992             clean::Import::Glob(ref src) => {
993                 if src.path.segments.is_empty() {
994                     write!(f, "use *;")
995                 } else {
996                     write!(f, "use {}::*;", *src)
997                 }
998             }
999         }
1000     }
1001 }
1002
1003 impl fmt::Display for clean::ImportSource {
1004     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1005         match self.did {
1006             Some(did) => resolved_path(f, did, &self.path, true, false),
1007             _ => {
1008                 for (i, seg) in self.path.segments.iter().enumerate() {
1009                     if i > 0 {
1010                         write!(f, "::")?
1011                     }
1012                     write!(f, "{}", seg.name)?;
1013                 }
1014                 Ok(())
1015             }
1016         }
1017     }
1018 }
1019
1020 impl fmt::Display for clean::TypeBinding {
1021     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1022         if f.alternate() {
1023             write!(f, "{} = {:#}", self.name, self.ty)
1024         } else {
1025             write!(f, "{} = {}", self.name, self.ty)
1026         }
1027     }
1028 }
1029
1030 impl fmt::Display for MutableSpace {
1031     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1032         match *self {
1033             MutableSpace(clean::Immutable) => Ok(()),
1034             MutableSpace(clean::Mutable) => write!(f, "mut "),
1035         }
1036     }
1037 }
1038
1039 impl fmt::Display for RawMutableSpace {
1040     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1041         match *self {
1042             RawMutableSpace(clean::Immutable) => write!(f, "const "),
1043             RawMutableSpace(clean::Mutable) => write!(f, "mut "),
1044         }
1045     }
1046 }
1047
1048 impl fmt::Display for AbiSpace {
1049     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1050         let quot = if f.alternate() { "\"" } else { "&quot;" };
1051         match self.0 {
1052             Abi::Rust => Ok(()),
1053             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1054         }
1055     }
1056 }