about summary refs log tree commit diff
path: root/src/librustdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/clean/auto_trait.rs26
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs69
-rw-r--r--src/librustdoc/clean/types.rs117
-rw-r--r--src/librustdoc/clean/utils.rs16
-rw-r--r--src/librustdoc/config.rs33
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/doctest.rs8
-rw-r--r--src/librustdoc/formats/cache.rs12
-rw-r--r--src/librustdoc/html/format.rs10
-rw-r--r--src/librustdoc/html/highlight.rs104
-rw-r--r--src/librustdoc/html/highlight/fixtures/decorations.html2
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html4
-rw-r--r--src/librustdoc/html/highlight/tests.rs25
-rw-r--r--src/librustdoc/html/layout.rs8
-rw-r--r--src/librustdoc/html/markdown.rs64
-rw-r--r--src/librustdoc/html/render/cache.rs43
-rw-r--r--src/librustdoc/html/render/context.rs36
-rw-r--r--src/librustdoc/html/render/mod.rs389
-rw-r--r--src/librustdoc/html/render/print_item.rs292
-rw-r--r--src/librustdoc/html/render/span_map.rs49
-rw-r--r--src/librustdoc/html/render/write_shared.rs16
-rw-r--r--src/librustdoc/html/sources.rs34
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css230
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css21
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css21
-rw-r--r--src/librustdoc/html/static/css/themes/light.css2
-rw-r--r--src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt (renamed from src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt)12
-rw-r--r--src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woffbin0 -> 677868 bytes
-rw-r--r--src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2bin0 -> 399468 bytes
-rw-r--r--src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular.woffbin287068 -> 0 bytes
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js86
-rw-r--r--src/librustdoc/html/static_files.rs43
-rw-r--r--src/librustdoc/html/templates/page.html3
-rw-r--r--src/librustdoc/json/conversions.rs6
-rw-r--r--src/librustdoc/json/mod.rs2
-rw-r--r--src/librustdoc/lib.rs34
-rw-r--r--src/librustdoc/passes/bare_urls.rs2
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs10
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs21
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs4
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs4
-rw-r--r--src/librustdoc/passes/stripper.rs6
-rw-r--r--src/librustdoc/scrape_examples.rs266
-rw-r--r--src/librustdoc/visit_ast.rs25
46 files changed, 1619 insertions, 560 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index f9d16669771..ba701f42c66 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -136,7 +136,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         let f = auto_trait::AutoTraitFinder::new(tcx);
 
         debug!("get_auto_trait_impls({:?})", ty);
-        let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+        let auto_traits: Vec<_> = self.cx.auto_traits.iter().copied().collect();
         let mut auto_traits: Vec<Item> = auto_traits
             .into_iter()
             .filter_map(|trait_def_id| {
@@ -193,8 +193,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         // to its smaller and larger regions. Note that 'larger' regions correspond
         // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
         for constraint in regions.constraints.keys() {
-            match constraint {
-                &Constraint::VarSubVar(r1, r2) => {
+            match *constraint {
+                Constraint::VarSubVar(r1, r2) => {
                     {
                         let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
                         deps1.larger.insert(RegionTarget::RegionVid(r2));
@@ -203,15 +203,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
                     deps2.smaller.insert(RegionTarget::RegionVid(r1));
                 }
-                &Constraint::RegSubVar(region, vid) => {
+                Constraint::RegSubVar(region, vid) => {
                     let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
                     deps.smaller.insert(RegionTarget::Region(region));
                 }
-                &Constraint::VarSubReg(vid, region) => {
+                Constraint::VarSubReg(vid, region) => {
                     let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
                     deps.larger.insert(RegionTarget::Region(region));
                 }
-                &Constraint::RegSubReg(r1, r2) => {
+                Constraint::RegSubReg(r1, r2) => {
                     // The constraint is already in the form that we want, so we're done with it
                     // Desired order is 'larger, smaller', so flip then
                     if region_name(r1) != region_name(r2) {
@@ -513,8 +513,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                         // as we want to combine them with any 'Output' qpaths
                         // later
 
-                        let is_fn = match &mut b {
-                            &mut GenericBound::TraitBound(ref mut p, _) => {
+                        let is_fn = match b {
+                            GenericBound::TraitBound(ref mut p, _) => {
                                 // Insert regions into the for_generics hash map first, to ensure
                                 // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
                                 for_generics.extend(p.generic_params.clone());
@@ -576,7 +576,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                                         rhs,
                                     });
                                     continue; // If something other than a Fn ends up
-                                    // with parenthesis, leave it alone
+                                    // with parentheses, leave it alone
                                 }
                             }
 
@@ -699,8 +699,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
 }
 
 fn region_name(region: Region<'_>) -> Option<Symbol> {
-    match region {
-        &ty::ReEarlyBound(r) => Some(r.name),
+    match *region {
+        ty::ReEarlyBound(r) => Some(r.name),
         _ => None,
     }
 }
@@ -717,8 +717,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        (match r {
-            &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+        (match *r {
+            ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
             _ => None,
         })
         .unwrap_or_else(|| r.super_fold_with(self))
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e11b802a09a..c5e05875819 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -14,9 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
-use crate::clean::{
-    self, utils, Attributes, AttributesExt, GetDefId, ItemId, NestedAttributesExt, Type,
-};
+use crate::clean::{self, utils, Attributes, AttributesExt, ItemId, NestedAttributesExt, Type};
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
@@ -325,7 +323,7 @@ fn merge_attrs(
     }
 }
 
-/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
+/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
 crate fn build_impl(
     cx: &mut DocContext<'_>,
     parent_module: impl Into<Option<DefId>>,
@@ -376,7 +374,7 @@ crate fn build_impl(
     // Only inline impl if the implementing type is
     // reachable in rustdoc generated documentation
     if !did.is_local() {
-        if let Some(did) = for_.def_id() {
+        if let Some(did) = for_.def_id(&cx.cache) {
             if !cx.cache.access_levels.is_public(did) {
                 return;
             }
@@ -464,7 +462,7 @@ crate fn build_impl(
     }
 
     while let Some(ty) = stack.pop() {
-        if let Some(did) = ty.def_id() {
+        if let Some(did) = ty.def_id(&cx.cache) {
             if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
                 return;
             }
@@ -481,7 +479,11 @@ crate fn build_impl(
     let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
     trace!("merged_attrs={:?}", merged_attrs);
 
-    trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id());
+    trace!(
+        "build_impl: impl {:?} for {:?}",
+        trait_.as_ref().map(|t| t.def_id()),
+        for_.def_id(&cx.cache)
+    );
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         None,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9d102d68783..9ea3112f178 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -216,17 +216,15 @@ impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
 impl Clean<Lifetime> for hir::Lifetime {
     fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
         let def = cx.tcx.named_region(self.hir_id);
-        match def {
-            Some(
-                rl::Region::EarlyBound(_, node_id, _)
-                | rl::Region::LateBound(_, _, node_id, _)
-                | rl::Region::Free(_, node_id),
-            ) => {
-                if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
-                    return lt;
-                }
+        if let Some(
+            rl::Region::EarlyBound(_, node_id, _)
+            | rl::Region::LateBound(_, _, node_id, _)
+            | rl::Region::Free(_, node_id),
+        ) = def
+        {
+            if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
+                return lt;
             }
-            _ => {}
         }
         Lifetime(self.name.ident().name)
     }
@@ -385,7 +383,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
         let self_type = self.self_ty().clean(cx);
         Type::QPath {
             name: cx.tcx.associated_item(self.item_def_id).ident.name,
-            self_def_id: self_type.def_id(),
+            self_def_id: self_type.def_id(&cx.cache),
             self_type: box self_type,
             trait_,
         }
@@ -421,7 +419,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
                     GenericParamDefKind::Type {
                         did: self.def_id,
                         bounds: vec![], // These are filled in from the where-clauses.
-                        default,
+                        default: default.map(Box::new),
                         synthetic,
                     },
                 )
@@ -430,9 +428,9 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
-                    ty: cx.tcx.type_of(self.def_id).clean(cx),
+                    ty: Box::new(cx.tcx.type_of(self.def_id).clean(cx)),
                     default: match has_default {
-                        true => Some(cx.tcx.const_param_default(self.def_id).to_string()),
+                        true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
                         false => None,
                     },
                 },
@@ -462,7 +460,7 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
                 GenericParamDefKind::Type {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
                     bounds: self.bounds.clean(cx),
-                    default: default.clean(cx),
+                    default: default.clean(cx).map(Box::new),
                     synthetic,
                 },
             ),
@@ -470,10 +468,10 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
                 self.name.ident().name,
                 GenericParamDefKind::Const {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
-                    ty: ty.clean(cx),
+                    ty: Box::new(ty.clean(cx)),
                     default: default.map(|ct| {
                         let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
-                        ty::Const::from_anon_const(cx.tcx, def_id).to_string()
+                        Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
                     }),
                 },
             ),
@@ -828,7 +826,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
                 .iter()
                 .enumerate()
                 .map(|(i, ty)| Argument {
-                    name: name_from_pat(&body.params[i].pat),
+                    name: name_from_pat(body.params[i].pat),
                     type_: ty.clean(cx),
                 })
                 .collect(),
@@ -924,7 +922,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     }
                     MethodItem(m, None)
                 }
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
+                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
                     let (generics, decl) = enter_impl_trait(cx, |cx| {
                         (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                     });
@@ -936,7 +934,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     }
                     TyMethodItem(t)
                 }
-                hir::TraitItemKind::Type(ref bounds, ref default) => {
+                hir::TraitItemKind::Type(bounds, ref default) => {
                     AssocTypeItem(bounds.clean(cx), default.clean(cx))
                 }
             };
@@ -1260,7 +1258,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
             let path = path.clean(cx);
             resolve_type(cx, path)
         }
-        hir::QPath::Resolved(Some(ref qself), ref p) => {
+        hir::QPath::Resolved(Some(ref qself), p) => {
             // Try to normalize `<X as Y>::T` to a type
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let Some(normalized_value) = normalize(cx, ty) {
@@ -1281,7 +1279,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 trait_,
             }
         }
-        hir::QPath::TypeRelative(ref qself, ref segment) => {
+        hir::QPath::TypeRelative(ref qself, segment) => {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             let res = match ty.kind() {
                 ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
@@ -1337,7 +1335,7 @@ impl Clean<Type> for hir::Ty<'_> {
                 let length = print_const(cx, ct.eval(cx.tcx, param_env));
                 Array(box ty.clean(cx), length)
             }
-            TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
+            TyKind::Tup(tys) => Tuple(tys.clean(cx)),
             TyKind::OpaqueDef(item_id, _) => {
                 let item = cx.tcx.hir().item(item_id);
                 if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
@@ -1346,8 +1344,8 @@ impl Clean<Type> for hir::Ty<'_> {
                     unreachable!()
                 }
             }
-            TyKind::Path(_) => clean_qpath(&self, cx),
-            TyKind::TraitObject(ref bounds, ref lifetime, _) => {
+            TyKind::Path(_) => clean_qpath(self, cx),
+            TyKind::TraitObject(bounds, ref lifetime, _) => {
                 let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
                 let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
                 DynTrait(bounds, lifetime)
@@ -1441,7 +1439,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did }
             }
-            ty::Dynamic(ref obj, ref reg) => {
+            ty::Dynamic(obj, ref reg) => {
                 // HACK: pick the first `did` as the `did` of the trait object. Someone
                 // might want to implement "native" support for marker-trait-only
                 // trait objects.
@@ -1481,9 +1479,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 DynTrait(bounds, lifetime)
             }
-            ty::Tuple(ref t) => {
-                Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
-            }
+            ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx)),
 
             ty::Projection(ref data) => data.clean(cx),
 
@@ -1821,9 +1817,9 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
                     clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
                 }
                 ItemKind::Macro(ref macro_def) => MacroItem(Macro {
-                    source: display_macro_source(cx, name, &macro_def, def_id, &item.vis),
+                    source: display_macro_source(cx, name, macro_def, def_id, &item.vis),
                 }),
-                ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+                ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
                     let items = item_ids
                         .iter()
                         .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
@@ -1887,7 +1883,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
     }
 
     let for_ = impl_.self_ty.clean(cx);
-    let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+    let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
         DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
         _ => None,
     });
@@ -2062,12 +2058,13 @@ fn clean_use_statement(
 impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let (item, renamed) = self;
-        cx.with_param_env(item.def_id.to_def_id(), |cx| {
+        let def_id = item.def_id.to_def_id();
+        cx.with_param_env(def_id, |cx| {
             let kind = match item.kind {
-                hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
+                hir::ForeignItemKind::Fn(decl, names, ref generics) => {
                     let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
                     let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        (generics.clean(cx), (&**decl, &names[..]).clean(cx))
+                        (generics.clean(cx), (&*decl, &names[..]).clean(cx))
                     });
                     ForeignFunctionItem(Function {
                         decl,
@@ -2112,7 +2109,7 @@ impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
             hir::TypeBindingKind::Equality { ref ty } => {
                 TypeBindingKind::Equality { ty: ty.clean(cx) }
             }
-            hir::TypeBindingKind::Constraint { ref bounds } => {
+            hir::TypeBindingKind::Constraint { bounds } => {
                 TypeBindingKind::Constraint { bounds: bounds.iter().map(|b| b.clean(cx)).collect() }
             }
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d4cea8b4a9d..6ae057abb3d 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -204,7 +204,7 @@ impl ExternalCrate {
             .filter_map(|a| a.value_str())
             .map(to_remote)
             .next()
-            .or(extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
+            .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
             .unwrap_or(Unknown) // Well, at least we tried.
     }
 
@@ -238,7 +238,7 @@ impl ExternalCrate {
                         hir::ItemKind::Mod(_) => {
                             as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                        hir::ItemKind::Use(path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
                             as_keyword(path.res.expect_non_local())
@@ -304,7 +304,7 @@ impl ExternalCrate {
                         hir::ItemKind::Mod(_) => {
                             as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                        hir::ItemKind::Use(path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
                             as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
@@ -381,7 +381,7 @@ impl Item {
         {
             *span
         } else {
-            self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(|| Span::dummy())
+            self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
         }
     }
 
@@ -562,7 +562,7 @@ impl Item {
     }
 
     crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
-        self.stability(tcx).as_ref().and_then(|ref s| {
+        self.stability(tcx).as_ref().and_then(|s| {
             let mut classes = Vec::with_capacity(2);
 
             if s.level.is_unstable() {
@@ -820,9 +820,9 @@ impl AttributesExt for [ast::Attribute] {
                         // #[doc(cfg(...))]
                         if let Some(cfg_mi) = item
                             .meta_item()
-                            .and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
+                            .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
                         {
-                            match Cfg::parse(&cfg_mi) {
+                            match Cfg::parse(cfg_mi) {
                                 Ok(new_cfg) => cfg &= new_cfg,
                                 Err(e) => sess.span_err(e.span, e.msg),
                             }
@@ -934,7 +934,7 @@ impl<'a> FromIterator<&'a DocFragment> for String {
         T: IntoIterator<Item = &'a DocFragment>,
     {
         iter.into_iter().fold(String::new(), |mut acc, frag| {
-            add_doc_fragment(&mut acc, &frag);
+            add_doc_fragment(&mut acc, frag);
             acc
         })
     }
@@ -1061,12 +1061,12 @@ impl Attributes {
 
         let ori = iter.next()?;
         let mut out = String::new();
-        add_doc_fragment(&mut out, &ori);
-        while let Some(new_frag) = iter.next() {
+        add_doc_fragment(&mut out, ori);
+        for new_frag in iter {
             if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
                 break;
             }
-            add_doc_fragment(&mut out, &new_frag);
+            add_doc_fragment(&mut out, new_frag);
         }
         if out.is_empty() { None } else { Some(out) }
     }
@@ -1079,7 +1079,7 @@ impl Attributes {
 
         for new_frag in self.doc_strings.iter() {
             let out = ret.entry(new_frag.parent_module).or_default();
-            add_doc_fragment(out, &new_frag);
+            add_doc_fragment(out, new_frag);
         }
         ret
     }
@@ -1219,13 +1219,13 @@ crate enum GenericParamDefKind {
     Type {
         did: DefId,
         bounds: Vec<GenericBound>,
-        default: Option<Type>,
+        default: Option<Box<Type>>,
         synthetic: Option<hir::SyntheticTyParamKind>,
     },
     Const {
         did: DefId,
-        ty: Type,
-        default: Option<String>,
+        ty: Box<Type>,
+        default: Option<Box<String>>,
     },
 }
 
@@ -1239,8 +1239,8 @@ impl GenericParamDefKind {
     // any embedded types, but `get_type` seems to be the wrong name for that.
     crate fn get_type(&self) -> Option<Type> {
         match self {
-            GenericParamDefKind::Type { default, .. } => default.clone(),
-            GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
+            GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
+            GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
             GenericParamDefKind::Lifetime { .. } => None,
         }
     }
@@ -1252,6 +1252,10 @@ crate struct GenericParamDef {
     crate kind: GenericParamDefKind,
 }
 
+// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(GenericParamDef, 56);
+
 impl GenericParamDef {
     crate fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
@@ -1366,17 +1370,10 @@ crate enum FnRetTy {
     DefaultReturn,
 }
 
-impl GetDefId for FnRetTy {
-    fn def_id(&self) -> Option<DefId> {
-        match *self {
-            Return(ref ty) => ty.def_id(),
-            DefaultReturn => None,
-        }
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        match *self {
-            Return(ref ty) => ty.def_id_full(cache),
+impl FnRetTy {
+    crate fn as_return(&self) -> Option<&Type> {
+        match self {
+            Return(ret) => Some(ret),
             DefaultReturn => None,
         }
     }
@@ -1450,33 +1447,9 @@ crate enum Type {
     ImplTrait(Vec<GenericBound>),
 }
 
-crate trait GetDefId {
-    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
-    /// This will return [`None`] when called on a primitive [`clean::Type`].
-    /// Use [`Self::def_id_full`] if you want to include primitives.
-    ///
-    /// [`clean`]: crate::clean
-    /// [`clean::Type`]: crate::clean::Type
-    // FIXME: get rid of this function and always use `def_id_full`
-    fn def_id(&self) -> Option<DefId>;
-
-    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
-    ///
-    /// See [`Self::def_id`] for more.
-    ///
-    /// [clean]: crate::clean
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
-    fn def_id(&self) -> Option<DefId> {
-        self.as_ref().and_then(|d| d.def_id())
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.as_ref().and_then(|d| d.def_id_full(cache))
-    }
-}
+// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Type, 72);
 
 impl Type {
     crate fn primitive_type(&self) -> Option<PrimitiveType> {
@@ -1556,17 +1529,27 @@ impl Type {
             QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
             Generic(_) | Infer | ImplTrait(_) => return None,
         };
-        cache.and_then(|c| Primitive(t).def_id_full(c))
+        cache.and_then(|c| Primitive(t).def_id(c))
     }
-}
 
-impl GetDefId for Type {
-    fn def_id(&self) -> Option<DefId> {
-        self.inner_def_id(None)
+    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+    ///
+    /// See [`Self::def_id_no_primitives`] for more.
+    ///
+    /// [clean]: crate::clean
+    crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
+        self.inner_def_id(Some(cache))
     }
 
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.inner_def_id(Some(cache))
+    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+    /// This will return [`None`] when called on a primitive [`clean::Type`].
+    /// Use [`Self::def_id`] if you want to include primitives.
+    ///
+    /// [`clean`]: crate::clean
+    /// [`clean::Type`]: crate::clean::Type
+    // FIXME: get rid of this function and always use `def_id`
+    crate fn def_id_no_primitives(&self) -> Option<DefId> {
+        self.inner_def_id(None)
     }
 }
 
@@ -2084,16 +2067,6 @@ crate struct Typedef {
     crate item_type: Option<Type>,
 }
 
-impl GetDefId for Typedef {
-    fn def_id(&self) -> Option<DefId> {
-        self.type_.def_id()
-    }
-
-    fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
-        self.type_.def_id_full(cache)
-    }
-}
-
 #[derive(Clone, Debug)]
 crate struct OpaqueTy {
     crate bounds: Vec<GenericBound>,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index de43daff6f0..0573a1ada3a 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -171,8 +171,8 @@ crate fn strip_path_generics(path: Path) -> Path {
 
 crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {
     let segments = match *p {
-        hir::QPath::Resolved(_, ref path) => &path.segments,
-        hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+        hir::QPath::Resolved(_, path) => &path.segments,
+        hir::QPath::TypeRelative(_, segment) => return segment.ident.to_string(),
         hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
     };
 
@@ -217,15 +217,15 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
         PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
         PatKind::Binding(_, _, ident, _) => return ident.name,
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
-        PatKind::Or(ref pats) => {
+        PatKind::Or(pats) => {
             pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
         }
-        PatKind::Tuple(ref elts, _) => format!(
+        PatKind::Tuple(elts, _) => format!(
             "({})",
             elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
         ),
-        PatKind::Box(ref p) => return name_from_pat(&**p),
-        PatKind::Ref(ref p, _) => return name_from_pat(&**p),
+        PatKind::Box(p) => return name_from_pat(&*p),
+        PatKind::Ref(p, _) => return name_from_pat(&*p),
         PatKind::Lit(..) => {
             warn!(
                 "tried to get argument name from PatKind::Lit, which is silly in function arguments"
@@ -233,7 +233,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
             return Symbol::intern("()");
         }
         PatKind::Range(..) => return kw::Underscore,
-        PatKind::Slice(ref begin, ref mid, ref end) => {
+        PatKind::Slice(begin, ref mid, end) => {
             let begin = begin.iter().map(|p| name_from_pat(p).to_string());
             let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
             let end = end.iter().map(|p| name_from_pat(p).to_string());
@@ -507,7 +507,7 @@ crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool {
 /// so that the channel is consistent.
 ///
 /// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
-crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
 
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index ac440a39515..493aa56fce6 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -25,6 +25,7 @@ use crate::html::render::StylePath;
 use crate::html::static_files;
 use crate::opts;
 use crate::passes::{self, Condition, DefaultPassOption};
+use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
 use crate::theme;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -158,6 +159,10 @@ crate struct Options {
     crate json_unused_externs: bool,
     /// Whether to skip capturing stdout and stderr of tests.
     crate nocapture: bool,
+
+    /// Configuration for scraping examples from the current crate. If this option is Some(..) then
+    /// the compiler will scrape examples and not generate documentation.
+    crate scrape_examples_options: Option<ScrapeExamplesOptions>,
 }
 
 impl fmt::Debug for Options {
@@ -202,6 +207,7 @@ impl fmt::Debug for Options {
             .field("run_check", &self.run_check)
             .field("no_run", &self.no_run)
             .field("nocapture", &self.nocapture)
+            .field("scrape_examples_options", &self.scrape_examples_options)
             .finish()
     }
 }
@@ -280,6 +286,7 @@ crate struct RenderOptions {
     crate emit: Vec<EmitType>,
     /// If `true`, HTML source pages will generate links for items to their definition.
     crate generate_link_to_definition: bool,
+    crate call_locations: AllCallLocations,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -314,13 +321,13 @@ impl Options {
     /// been printed, returns `Err` with the exit code.
     crate fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
         // Check for unstable options.
-        nightly_options::check_nightly_options(&matches, &opts());
+        nightly_options::check_nightly_options(matches, &opts());
 
         if matches.opt_present("h") || matches.opt_present("help") {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version("rustdoc", &matches);
+            rustc_driver::version("rustdoc", matches);
             return Err(0);
         }
 
@@ -356,10 +363,10 @@ impl Options {
             return Err(0);
         }
 
-        let color = config::parse_color(&matches);
+        let color = config::parse_color(matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(&matches);
-        let error_format = config::parse_error_format(&matches, color, json_rendered);
+            config::parse_json(matches);
+        let error_format = config::parse_error_format(matches, color, json_rendered);
 
         let codegen_options = CodegenOptions::build(matches, error_format);
         let debugging_opts = DebuggingOptions::build(matches, error_format);
@@ -367,7 +374,7 @@ impl Options {
         let diag = new_handler(error_format, None, &debugging_opts);
 
         // check for deprecated options
-        check_deprecated_options(&matches, &diag);
+        check_deprecated_options(matches, &diag);
 
         let mut emit = Vec::new();
         for list in matches.opt_strs("emit") {
@@ -433,8 +440,8 @@ impl Options {
             .iter()
             .map(|s| SearchPath::from_cli_opt(s, error_format))
             .collect();
-        let externs = parse_externs(&matches, &debugging_opts, error_format);
-        let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+        let externs = parse_externs(matches, &debugging_opts, error_format);
+        let extern_html_root_urls = match parse_extern_html_roots(matches) {
             Ok(ex) => ex,
             Err(err) => {
                 diag.struct_err(err).emit();
@@ -553,7 +560,7 @@ impl Options {
             }
         }
 
-        let edition = config::parse_crate_edition(&matches);
+        let edition = config::parse_crate_edition(matches);
 
         let mut id_map = html::markdown::IdMap::new();
         let external_html = match ExternalHtml::load(
@@ -562,7 +569,7 @@ impl Options {
             &matches.opt_strs("html-after-content"),
             &matches.opt_strs("markdown-before-content"),
             &matches.opt_strs("markdown-after-content"),
-            nightly_options::match_is_nightly_build(&matches),
+            nightly_options::match_is_nightly_build(matches),
             &diag,
             &mut id_map,
             edition,
@@ -671,6 +678,10 @@ impl Options {
             return Err(1);
         }
 
+        let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?;
+        let with_examples = matches.opt_strs("with-examples");
+        let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
         Ok(Options {
@@ -737,10 +748,12 @@ impl Options {
                 ),
                 emit,
                 generate_link_to_definition,
+                call_locations,
             },
             crate_name,
             output_format,
             json_unused_externs,
+            scrape_examples_options,
         })
     }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 074744b3d11..b7251e8f571 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -85,7 +85,7 @@ crate struct DocContext<'tcx> {
 
 impl<'tcx> DocContext<'tcx> {
     crate fn sess(&self) -> &'tcx Session {
-        &self.tcx.sess
+        self.tcx.sess
     }
 
     crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
@@ -464,7 +464,7 @@ crate fn run_global_ctxt(
                 _ => continue,
             };
             for name in value.as_str().split_whitespace() {
-                let span = attr.name_value_literal_span().unwrap_or(attr.span());
+                let span = attr.name_value_literal_span().unwrap_or_else(|| attr.span());
                 manual_passes.extend(parse_pass(name, Some(span)));
             }
         }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 9e64d200b43..9b32ad979e3 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -73,7 +73,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
         search_paths: options.libs.clone(),
         crate_types,
         lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
-        lint_cap: Some(options.lint_cap.unwrap_or_else(|| lint::Forbid)),
+        lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
         cg: options.codegen_options.clone(),
         externs: options.externs.clone(),
         unstable_features: options.render_options.unstable_features,
@@ -176,7 +176,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
                 .iter()
                 .map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
                 .fold(extern_names, |uextsa, uextsb| {
-                    uextsa.intersection(&uextsb).map(|v| *v).collect::<FxHashSet<&String>>()
+                    uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>()
                 })
                 .iter()
                 .map(|v| (*v).clone())
@@ -423,7 +423,7 @@ fn run_test(
 
     // Add a \n to the end to properly terminate the last line,
     // but only if there was output to be printed
-    if out_lines.len() > 0 {
+    if !out_lines.is_empty() {
         out_lines.push("");
     }
 
@@ -1124,7 +1124,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
         let mut attrs = Attributes::from_ast(ast_attrs, None);
 
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
-            if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
+            if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
                 return;
             }
         }
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 8b883ffaaf0..6b9c9a9669b 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -6,7 +6,7 @@ use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
-use crate::clean::{self, GetDefId, ItemId, PrimitiveType};
+use crate::clean::{self, ItemId, PrimitiveType};
 use crate::config::RenderOptions;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
@@ -206,7 +206,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                 || i.trait_
                     .as_ref()
                     .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
-                || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
+                || i.for_
+                    .def_id(self.cache)
+                    .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
             {
                 return None;
             }
@@ -292,7 +294,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // inserted later on when serializing the search-index.
                     if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
                         let desc = item.doc_value().map_or_else(String::new, |x| {
-                            short_markdown_summary(&x.as_str(), &item.link_names(&self.cache))
+                            short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
                         self.cache.search_index.push(IndexItem {
                             ty: item.type_(),
@@ -454,7 +456,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
 
             if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
                 for bound in generics {
-                    if let Some(did) = bound.def_id() {
+                    if let Some(did) = bound.def_id(self.cache) {
                         dids.insert(did);
                     }
                 }
@@ -462,7 +464,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             let impl_item = Impl { impl_item: item };
             if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
-                    self.cache.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+                    self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
                 }
             } else {
                 let trait_did = impl_item.trait_did().expect("no trait did");
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index f2751947c7e..c51bda60b73 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -597,7 +597,7 @@ crate fn href_relative_parts<'a>(fqp: &'a [String], relative_to_fqp: &'a [String
 
 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
 /// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path<'a, 'cx: 'a>(
+fn resolved_path<'cx>(
     w: &mut fmt::Formatter<'_>,
     did: DefId,
     path: &clean::Path,
@@ -696,7 +696,7 @@ fn primitive_link(
 
 /// Helper to render type parameters
 fn tybounds<'a, 'tcx: 'a>(
-    bounds: &'a Vec<clean::PolyTrait>,
+    bounds: &'a [clean::PolyTrait],
     lt: &'a Option<clean::Lifetime>,
     cx: &'a Context<'tcx>,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
@@ -886,7 +886,7 @@ fn fmt_type<'cx>(
                     if bounds.len() > 1 || trait_lt.is_some() =>
                 {
                     write!(f, "{}{}{}(", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cx)?;
+                    fmt_type(ty, f, use_absolute, cx)?;
                     write!(f, ")")
                 }
                 clean::Generic(..) => {
@@ -896,11 +896,11 @@ fn fmt_type<'cx>(
                         &format!("{}{}{}", amp, lt, m),
                         cx,
                     )?;
-                    fmt_type(&ty, f, use_absolute, cx)
+                    fmt_type(ty, f, use_absolute, cx)
                 }
                 _ => {
                     write!(f, "{}{}{}", amp, lt, m)?;
-                    fmt_type(&ty, f, use_absolute, cx)
+                    fmt_type(ty, f, use_absolute, cx)
                 }
             }
         }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 8ed69962875..a33bb3479ce 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -12,6 +12,7 @@ use crate::html::render::Context;
 use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
@@ -30,6 +31,10 @@ crate struct ContextInfo<'a, 'b, 'c> {
     crate root_path: &'c str,
 }
 
+/// Decorations are represented as a map from CSS class to vector of character ranges.
+/// Each range will be wrapped in a span with that class.
+crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
+
 /// Highlights `src`, returning the HTML output.
 crate fn render_with_highlighting(
     src: &str,
@@ -40,6 +45,7 @@ crate fn render_with_highlighting(
     edition: Edition,
     extra_content: Option<Buffer>,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
     if let Some((edition_info, class)) = tooltip {
@@ -56,7 +62,7 @@ crate fn render_with_highlighting(
     }
 
     write_header(out, class, extra_content);
-    write_code(out, &src, edition, context_info);
+    write_code(out, src, edition, context_info, decoration_info);
     write_footer(out, playground_button);
 }
 
@@ -89,17 +95,23 @@ fn write_code(
     src: &str,
     edition: Edition,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
-        .highlight(&mut |highlight| {
-            match highlight {
-                Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
-                Highlight::EnterSpan { class } => enter_span(out, class),
-                Highlight::ExitSpan => exit_span(out),
-            };
-        });
+    Classifier::new(
+        &src,
+        edition,
+        context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+        decoration_info,
+    )
+    .highlight(&mut |highlight| {
+        match highlight {
+            Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+            Highlight::EnterSpan { class } => enter_span(out, class),
+            Highlight::ExitSpan => exit_span(out),
+        };
+    });
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -127,6 +139,7 @@ enum Class {
     PreludeTy,
     PreludeVal,
     QuestionMark,
+    Decoration(&'static str),
 }
 
 impl Class {
@@ -150,6 +163,7 @@ impl Class {
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
             Class::QuestionMark => "question-mark",
+            Class::Decoration(kind) => kind,
         }
     }
 
@@ -248,6 +262,24 @@ impl Iterator for PeekIter<'a> {
     }
 }
 
+/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls
+struct Decorations {
+    starts: Vec<(u32, &'static str)>,
+    ends: Vec<u32>,
+}
+
+impl Decorations {
+    fn new(info: DecorationInfo) -> Self {
+        let (starts, ends) = info
+            .0
+            .into_iter()
+            .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+            .flatten()
+            .unzip();
+        Decorations { starts, ends }
+    }
+}
+
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
 struct Classifier<'a> {
@@ -259,13 +291,20 @@ struct Classifier<'a> {
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
+    decorations: Option<Decorations>,
 }
 
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
+    fn new(
+        src: &str,
+        edition: Edition,
+        file_span: Span,
+        decoration_info: Option<DecorationInfo>,
+    ) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
+        let decorations = decoration_info.map(Decorations::new);
         Classifier {
             tokens,
             in_attribute: false,
@@ -275,6 +314,7 @@ impl<'a> Classifier<'a> {
             byte_pos: 0,
             file_span,
             src,
+            decorations,
         }
     }
 
@@ -356,6 +396,19 @@ impl<'a> Classifier<'a> {
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
         loop {
+            if let Some(decs) = self.decorations.as_mut() {
+                let byte_pos = self.byte_pos;
+                let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count();
+                for (_, kind) in decs.starts.drain(0..n_starts) {
+                    sink(Highlight::EnterSpan { class: Class::Decoration(kind) });
+                }
+
+                let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count();
+                for _ in decs.ends.drain(0..n_ends) {
+                    sink(Highlight::ExitSpan);
+                }
+            }
+
             if self
                 .tokens
                 .peek()
@@ -416,22 +469,37 @@ impl<'a> Classifier<'a> {
             // Assume that '&' or '*' is the reference or dereference operator
             // or a reference or pointer type. Unless, of course, it looks like
             // a logical and or a multiplication operator: `&&` or `* `.
-            TokenKind::Star => match self.peek() {
-                Some(TokenKind::Whitespace) => Class::Op,
+            TokenKind::Star => match self.tokens.peek() {
+                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Ident, "mut")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
+                    return;
+                }
+                Some((TokenKind::Ident, "const")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) });
+                    return;
+                }
                 _ => Class::RefKeyWord,
             },
-            TokenKind::And => match lookahead {
-                Some(TokenKind::And) => {
+            TokenKind::And => match self.tokens.peek() {
+                Some((TokenKind::And, _)) => {
                     self.next();
                     sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                     return;
                 }
-                Some(TokenKind::Eq) => {
+                Some((TokenKind::Eq, _)) => {
                     self.next();
                     sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                     return;
                 }
-                Some(TokenKind::Whitespace) => Class::Op,
+                Some((TokenKind::Whitespace, _)) => Class::Op,
+                Some((TokenKind::Ident, "mut")) => {
+                    self.next();
+                    sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
+                    return;
+                }
                 _ => Class::RefKeyWord,
             },
 
@@ -657,7 +725,7 @@ fn string<T: Display>(
                 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
                 match href {
                     LinkFromSrc::Local(span) => context
-                        .href_from_span(*span)
+                        .href_from_span(*span, true)
                         .map(|s| format!("{}{}", context_info.root_path, s)),
                     LinkFromSrc::External(def_id) => {
                         format::href_with_root_path(*def_id, context, Some(context_info.root_path))
@@ -665,7 +733,7 @@ fn string<T: Display>(
                             .map(|(url, _, _)| url)
                     }
                     LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                        PrimitiveType::primitive_locations(context.tcx())[&prim],
+                        PrimitiveType::primitive_locations(context.tcx())[prim],
                         context,
                         Some(context_info.root_path),
                     )
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
new file mode 100644
index 00000000000..45f567880c9
--- /dev/null
+++ b/src/librustdoc/html/highlight/fixtures/decorations.html
@@ -0,0 +1,2 @@
+<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index 22e650af7e2..b117a12e39f 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -15,11 +15,11 @@
 <span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">&quot;linux&quot;</span>)]</span>
 <span class="kw">fn</span> <span class="ident">main</span>() -&gt; () {
     <span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&amp;&amp;</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
-    <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*</span><span class="kw">const</span> () <span class="op">=</span> <span class="number">0</span>;
+    <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">foo</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&amp;&amp;</span><span class="ident">foo</span>;
     <span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
-    <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
+    <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;mut</span> <span class="ident">bar</span>);
     <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
     <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
     <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 450bbfea1ea..1fea7e983b4 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,6 +1,7 @@
-use super::write_code;
+use super::{write_code, DecorationInfo};
 use crate::html::format::Buffer;
 use expect_test::expect_file;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
 use rustc_span::edition::Edition;
 
@@ -22,7 +23,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018, None);
+            write_code(&mut out, src, Edition::Edition2018, None, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -36,7 +37,7 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
@@ -50,7 +51,7 @@ let x = super::b::foo;
 let y = Self::whatever;";
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
     });
 }
@@ -60,7 +61,21 @@ fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
     });
 }
+
+#[test]
+fn test_decorations() {
+    create_default_session_globals_then(|| {
+        let src = "let x = 1;
+let y = 2;";
+        let mut decorations = FxHashMap::default();
+        decorations.insert("example", vec![(0, 10)]);
+
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+        expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+    });
+}
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 6ed603c96bb..71d7cc1a09d 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -22,6 +22,8 @@ crate struct Layout {
     /// If false, the `select` element to have search filtering by crates on rendered docs
     /// won't be generated.
     crate generate_search_filter: bool,
+    /// If true, then scrape-examples.js will be included in the output HTML file
+    crate scrape_examples_extension: bool,
 }
 
 #[derive(Serialize)]
@@ -66,10 +68,8 @@ crate fn render<T: Print, S: Print>(
     let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
     let style_files = style_files
         .iter()
-        .filter_map(|t| {
-            if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
-        })
-        .filter_map(|t| if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None })
+        .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
+        .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
         .map(|t| {
             format!(
                 r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 9f2e282fce1..47772651bf9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -178,7 +178,7 @@ fn map_line(s: &str) -> Line<'_> {
         Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
     } else if let Some(stripped) = trimmed.strip_prefix("# ") {
         // # text
-        Line::Hidden(&stripped)
+        Line::Hidden(stripped)
     } else if trimmed == "#" {
         // We cannot handle '#text' because it could be #[attr].
         Line::Hidden("")
@@ -258,7 +258,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
                 let parse_result =
-                    LangString::parse_without_check(&lang, self.check_error_codes, false);
+                    LangString::parse_without_check(lang, self.check_error_codes, false);
                 if !parse_result.rust {
                     return Some(Event::Html(
                         format!(
@@ -360,6 +360,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             edition,
             None,
             None,
+            None,
         );
         Some(Event::Html(s.into_inner().into()))
     }
@@ -668,7 +669,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
         loop {
             match self.inner.next() {
                 Some((Event::FootnoteReference(ref reference), range)) => {
-                    let entry = self.get_entry(&reference);
+                    let entry = self.get_entry(reference);
                     let reference = format!(
                         "<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
                         (*entry).1
@@ -765,7 +766,7 @@ crate fn find_testable_code<T: doctest::Tester>(
                 // If there are characters between the preceding line ending and
                 // this code block, `str::lines` will return an additional line,
                 // which we subtract here.
-                if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with("\n") {
+                if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') {
                     nb_lines -= 1;
                 }
                 let line = tests.get_line() + nb_lines + 1;
@@ -903,7 +904,7 @@ impl LangString {
         string
             .split(|c| c == ',' || c == ' ' || c == '\t')
             .map(str::trim)
-            .map(|token| if token.chars().next() == Some('.') { &token[1..] } else { token })
+            .map(|token| token.strip_prefix('.').unwrap_or(token))
             .filter(|token| !token.is_empty())
     }
 
@@ -973,7 +974,10 @@ impl LangString {
                 }
                 x if extra.is_some() => {
                     let s = x.to_lowercase();
-                    match if s == "compile-fail" || s == "compile_fail" || s == "compilefail" {
+                    if let Some((flag, help)) = if s == "compile-fail"
+                        || s == "compile_fail"
+                        || s == "compilefail"
+                    {
                         Some((
                             "compile_fail",
                             "the code block will either not be tested if not marked as a rust one \
@@ -1006,15 +1010,12 @@ impl LangString {
                     } else {
                         None
                     } {
-                        Some((flag, help)) => {
-                            if let Some(ref extra) = extra {
-                                extra.error_invalid_codeblock_attr(
-                                    &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
-                                    help,
-                                );
-                            }
+                        if let Some(extra) = extra {
+                            extra.error_invalid_codeblock_attr(
+                                &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
+                                help,
+                            );
                         }
-                        None => {}
                     }
                     seen_other_tags = true;
                 }
@@ -1050,13 +1051,10 @@ impl Markdown<'_> {
             return String::new();
         }
         let mut replacer = |broken_link: BrokenLink<'_>| {
-            if let Some(link) =
-                links.iter().find(|link| &*link.original_text == broken_link.reference)
-            {
-                Some((link.href.as_str().into(), link.new_text.as_str().into()))
-            } else {
-                None
-            }
+            links
+                .iter()
+                .find(|link| &*link.original_text == broken_link.reference)
+                .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
         };
 
         let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
@@ -1134,13 +1132,10 @@ impl MarkdownSummaryLine<'_> {
         }
 
         let mut replacer = |broken_link: BrokenLink<'_>| {
-            if let Some(link) =
-                links.iter().find(|link| &*link.original_text == broken_link.reference)
-            {
-                Some((link.href.as_str().into(), link.new_text.as_str().into()))
-            } else {
-                None
-            }
+            links
+                .iter()
+                .find(|link| &*link.original_text == broken_link.reference)
+                .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
         };
 
         let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
@@ -1171,13 +1166,10 @@ fn markdown_summary_with_limit(
     }
 
     let mut replacer = |broken_link: BrokenLink<'_>| {
-        if let Some(link) =
-            link_names.iter().find(|link| &*link.original_text == broken_link.reference)
-        {
-            Some((link.href.as_str().into(), link.new_text.as_str().into()))
-        } else {
-            None
-        }
+        link_names
+            .iter()
+            .find(|link| &*link.original_text == broken_link.reference)
+            .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
     };
 
     let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
@@ -1412,7 +1404,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
                 CodeBlockKind::Indented => {
                     // The ending of the offset goes too far sometime so we reduce it by one in
                     // these cases.
-                    if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
+                    if offset.end > offset.start && md.get(offset.end..=offset.end) == Some("\n") {
                         (
                             LangString::default(),
                             offset.start,
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 9c05c80d55d..0bbc510f7cb 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -1,3 +1,4 @@
+use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -6,9 +7,7 @@ use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
-use crate::clean::types::{
-    FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
-};
+use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::markdown::short_markdown_summary;
@@ -36,7 +35,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
         if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
             let desc = item
                 .doc_value()
-                .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(&cache)));
+                .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
             cache.search_index.push(IndexItem {
                 ty: item.type_(),
                 name: item.name.unwrap().to_string(),
@@ -44,7 +43,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(&item, tcx),
+                search_type: get_index_search_type(item, tcx),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -53,7 +52,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
     let crate_doc = krate
         .module
         .doc_value()
-        .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(&cache)));
+        .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache)));
 
     let Cache { ref mut search_index, ref paths, .. } = *cache;
 
@@ -72,7 +71,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
     // Set up alias indexes.
     for (i, item) in search_index.iter().enumerate() {
         for alias in &item.aliases[..] {
-            aliases.entry(alias.to_lowercase()).or_insert(Vec::new()).push(i);
+            aliases.entry(alias.to_lowercase()).or_insert_with(Vec::new).push(i);
         }
     }
 
@@ -82,12 +81,11 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
     let mut lastpathid = 0usize;
 
     for item in search_index {
-        item.parent_idx = item.parent.and_then(|defid| {
-            if defid_to_pathid.contains_key(&defid) {
-                defid_to_pathid.get(&defid).copied()
-            } else {
+        item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+            Entry::Occupied(entry) => Some(*entry.get()),
+            Entry::Vacant(entry) => {
                 let pathid = lastpathid;
-                defid_to_pathid.insert(defid, pathid);
+                entry.insert(pathid);
                 lastpathid += 1;
 
                 if let Some(&(ref fqp, short)) = paths.get(&defid) {
@@ -203,12 +201,12 @@ crate fn get_index_search_type<'tcx>(
 
     let inputs = all_types
         .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(ty), *kind)))
         .filter(|a| a.ty.name.is_some())
         .collect();
     let output = ret_types
         .iter()
-        .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
+        .map(|(ty, kind)| TypeWithKind::from((get_index_type(ty), *kind)))
         .filter(|a| a.ty.name.is_some())
         .collect::<Vec<_>>();
     let output = if output.is_empty() { None } else { Some(output) };
@@ -278,7 +276,7 @@ crate fn get_real_types<'tcx>(
     res: &mut FxHashSet<(Type, ItemType)>,
 ) -> usize {
     fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
-        if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
+        if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
             res.insert((ty, kind));
             1
         } else if ty.is_primitive() {
@@ -296,9 +294,11 @@ crate fn get_real_types<'tcx>(
     }
     let mut nb_added = 0;
 
-    if let &Type::Generic(arg_s) = arg {
+    if let Type::Generic(arg_s) = *arg {
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
-            WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
+            WherePredicate::BoundPredicate { ty, .. } => {
+                ty.def_id_no_primitives() == arg.def_id_no_primitives()
+            }
             _ => false,
         }) {
             let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
@@ -365,7 +365,8 @@ crate fn get_all_types<'tcx>(
         if !args.is_empty() {
             all_types.extend(args);
         } else {
-            if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
+            if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+            {
                 all_types.insert((arg.type_.clone(), kind));
             }
         }
@@ -374,9 +375,11 @@ crate fn get_all_types<'tcx>(
     let ret_types = match decl.output {
         FnRetTy::Return(ref return_type) => {
             let mut ret = FxHashSet::default();
-            get_real_types(generics, &return_type, tcx, 0, &mut ret);
+            get_real_types(generics, return_type, tcx, 0, &mut ret);
             if ret.is_empty() {
-                if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
+                if let Some(kind) =
+                    return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+                {
                     ret.insert((return_type.clone(), kind));
                 }
             }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 011d3cfcf72..0e29cc85f9e 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -34,6 +34,7 @@ use crate::html::escape::Escape;
 use crate::html::format::Buffer;
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
 use crate::html::{layout, sources};
+use crate::scrape_examples::AllCallLocations;
 
 /// Major driving force in all rustdoc rendering. This contains information
 /// about where in the tree-like hierarchy rendering is occurring and controls
@@ -123,6 +124,8 @@ crate struct SharedContext<'tcx> {
     crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
     /// The [`Cache`] used during rendering.
     crate cache: Cache,
+
+    crate call_locations: AllCallLocations,
 }
 
 impl SharedContext<'_> {
@@ -157,7 +160,7 @@ impl<'tcx> Context<'tcx> {
     }
 
     pub(super) fn sess(&self) -> &'tcx Session {
-        &self.shared.tcx.sess
+        self.shared.tcx.sess
     }
 
     pub(super) fn derive_id(&self, id: String) -> String {
@@ -185,7 +188,7 @@ impl<'tcx> Context<'tcx> {
         };
         title.push_str(" - Rust");
         let tyname = it.type_();
-        let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
+        let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(doc));
         let desc = if let Some(desc) = desc {
             desc
         } else if it.is_crate() {
@@ -291,10 +294,10 @@ impl<'tcx> Context<'tcx> {
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
     pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
-        self.href_from_span(item.span(self.tcx()))
+        self.href_from_span(item.span(self.tcx()), true)
     }
 
-    crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+    crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
         if span.is_dummy() {
             return None;
         }
@@ -341,16 +344,26 @@ impl<'tcx> Context<'tcx> {
             (&*symbol, &path)
         };
 
-        let loline = span.lo(self.sess()).line;
-        let hiline = span.hi(self.sess()).line;
-        let lines =
-            if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
+        let anchor = if with_lines {
+            let loline = span.lo(self.sess()).line;
+            let hiline = span.hi(self.sess()).line;
+            format!(
+                "#{}",
+                if loline == hiline {
+                    loline.to_string()
+                } else {
+                    format!("{}-{}", loline, hiline)
+                }
+            )
+        } else {
+            "".to_string()
+        };
         Some(format!(
-            "{root}src/{krate}/{path}#{lines}",
+            "{root}src/{krate}/{path}{anchor}",
             root = Escape(&root),
             krate = krate,
             path = path,
-            lines = lines
+            anchor = anchor
         ))
     }
 }
@@ -388,6 +401,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             generate_redirect_map,
             show_type_layout,
             generate_link_to_definition,
+            call_locations,
             ..
         } = options;
 
@@ -412,6 +426,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             krate: krate.name.to_string(),
             css_file_extension: extension_css,
             generate_search_filter,
+            scrape_examples_extension: !call_locations.is_empty(),
         };
         let mut issue_tracker_base_url = None;
         let mut include_sources = true;
@@ -474,6 +489,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             templates,
             span_correspondance_map: matches,
             cache,
+            call_locations,
         };
 
         // Add the default themes to the `Vec` of stylepaths
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index dc5aec3b084..a1b86c87d3a 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -40,24 +40,29 @@ crate use span_map::{collect_spans_and_sources, LinkFromSrc};
 use std::collections::VecDeque;
 use std::default::Default;
 use std::fmt;
+use std::fs;
+use std::iter::Peekable;
 use std::path::PathBuf;
 use std::str;
 use std::string::ToString;
 
 use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{
+    symbol::{kw, sym, Symbol},
+    BytePos, FileName, RealFileName,
+};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, GetDefId, ItemId, RenderedLink, SelfTy};
+use crate::clean::{self, ItemId, RenderedLink, SelfTy};
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -68,7 +73,10 @@ use crate::html::format::{
     href, print_abi_with_space, print_constness_with_space, print_default_space,
     print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
 };
+use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use crate::html::sources;
+use crate::scrape_examples::CallData;
 
 /// A pair of name and its optional document.
 crate type NameDoc = (String, Option<String>);
@@ -118,8 +126,8 @@ impl Serialize for IndexItemFunctionType {
         // If we couldn't figure out a type, just write `null`.
         let mut iter = self.inputs.iter();
         if match self.output {
-            Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
-            None => iter.any(|ref i| i.ty.name.is_none()),
+            Some(ref output) => iter.chain(output.iter()).any(|i| i.ty.name.is_none()),
+            None => iter.any(|i| i.ty.name.is_none()),
         } {
             serializer.serialize_none()
         } else {
@@ -585,6 +593,14 @@ fn document_full_inner(
             render_markdown(w, cx, &s, item.links(cx), heading_offset);
         }
     }
+
+    let kind = match &*item.kind {
+        clean::ItemKind::StrippedItem(box kind) | kind => kind,
+    };
+
+    if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
+        render_call_locations(w, cx, item);
+    }
 }
 
 /// Add extra information about an item such as:
@@ -890,7 +906,7 @@ fn render_assoc_item(
             AssocItemLink::GotoSource(did, provided_methods) => {
                 // We're creating a link from an impl-item to the corresponding
                 // trait-item and need to map the anchored type accordingly.
-                let ty = if provided_methods.contains(&name) {
+                let ty = if provided_methods.contains(name) {
                     ItemType::Method
                 } else {
                     ItemType::TyMethod
@@ -949,7 +965,7 @@ fn render_assoc_item(
             name = name,
             generics = g.print(cx),
             decl = d.full_print(header_len, indent, header.asyncness, cx),
-            notable_traits = notable_traits_decl(&d, cx),
+            notable_traits = notable_traits_decl(d, cx),
             where_clause = print_where_clause(g, cx, indent, end_newline),
         )
     }
@@ -992,7 +1008,7 @@ fn attributes(it: &clean::Item) -> Vec<String> {
         .iter()
         .filter_map(|attr| {
             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
-                Some(pprust::attribute_to_string(&attr).replace("\n", "").replace("  ", " "))
+                Some(pprust::attribute_to_string(attr).replace("\n", "").replace("  ", " "))
             } else {
                 None
             }
@@ -1025,7 +1041,7 @@ enum AssocItemLink<'a> {
 impl<'a> AssocItemLink<'a> {
     fn anchor(&self, id: &'a str) -> Self {
         match *self {
-            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
+            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
             ref other => *other,
         }
     }
@@ -1104,7 +1120,7 @@ fn render_assoc_items(
         let (blanket_impl, concrete): (Vec<&&Impl>, _) =
             concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
 
-        let mut impls = Buffer::empty_from(&w);
+        let mut impls = Buffer::empty_from(w);
         render_impls(cx, &mut impls, &concrete, containing_item);
         let impls = impls.into_inner();
         if !impls.is_empty() {
@@ -1168,8 +1184,8 @@ fn render_deref_methods(
     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
     let what =
         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
-    if let Some(did) = target.def_id_full(cache) {
-        if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cache) {
+    if let Some(did) = target.def_id(cache) {
+        if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
             // `impl Deref<Target = S> for S`
             if did == type_did {
                 // Avoid infinite cycles
@@ -1215,7 +1231,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
 fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
     let mut out = Buffer::html();
 
-    if let Some(did) = decl.output.def_id_full(cx.cache()) {
+    if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
         if let Some(impls) = cx.cache().impls.get(&did) {
             for i in impls {
                 let impl_ = i.inner_impl();
@@ -1317,7 +1333,7 @@ fn render_impl(
             && match render_mode {
                 RenderMode::Normal => true,
                 RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(&item, deref_mut_, cx.tcx())
+                    should_render_item(item, deref_mut_, cx.tcx())
                 }
             };
 
@@ -1550,7 +1566,7 @@ fn render_impl(
                 &mut impl_items,
                 cx,
                 &t.trait_,
-                &i.inner_impl(),
+                i.inner_impl(),
                 &i.impl_item,
                 parent,
                 render_mode,
@@ -1811,23 +1827,53 @@ fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
     format!("{}-{}", url, add)
 }
 
+struct SidebarLink {
+    name: Symbol,
+    url: String,
+}
+
+impl fmt::Display for SidebarLink {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "<a href=\"#{}\">{}</a>", self.url, self.name)
+    }
+}
+
+impl PartialEq for SidebarLink {
+    fn eq(&self, other: &Self) -> bool {
+        self.url == other.url
+    }
+}
+
+impl Eq for SidebarLink {}
+
+impl PartialOrd for SidebarLink {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SidebarLink {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.url.cmp(&other.url)
+    }
+}
+
 fn get_methods(
     i: &clean::Impl,
     for_deref: bool,
     used_links: &mut FxHashSet<String>,
     deref_mut: bool,
     tcx: TyCtxt<'_>,
-) -> Vec<String> {
+) -> Vec<SidebarLink> {
     i.items
         .iter()
         .filter_map(|item| match item.name {
-            Some(ref name) if !name.is_empty() && item.is_method() => {
+            Some(name) if !name.is_empty() && item.is_method() => {
                 if !for_deref || should_render_item(item, deref_mut, tcx) {
-                    Some(format!(
-                        "<a href=\"#{}\">{}</a>",
-                        get_next_url(used_links, format!("method.{}", name)),
-                        name
-                    ))
+                    Some(SidebarLink {
+                        name,
+                        url: get_next_url(used_links, format!("method.{}", name)),
+                    })
                 } else {
                     None
                 }
@@ -1837,6 +1883,22 @@ fn get_methods(
         .collect::<Vec<_>>()
 }
 
+fn get_associated_constants(
+    i: &clean::Impl,
+    used_links: &mut FxHashSet<String>,
+) -> Vec<SidebarLink> {
+    i.items
+        .iter()
+        .filter_map(|item| match item.name {
+            Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink {
+                name,
+                url: get_next_url(used_links, format!("associatedconstant.{}", name)),
+            }),
+            _ => None,
+        })
+        .collect::<Vec<_>>()
+}
+
 // The point is to url encode any potential character from a type with genericity.
 fn small_url_encode(s: String) -> String {
     let mut st = String::new();
@@ -1881,23 +1943,40 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
 
         {
             let used_links_bor = &mut used_links;
-            let mut ret = v
+            let mut assoc_consts = v
+                .iter()
+                .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor))
+                .collect::<Vec<_>>();
+            if !assoc_consts.is_empty() {
+                // We want links' order to be reproducible so we don't use unstable sort.
+                assoc_consts.sort();
+
+                out.push_str(
+                    "<h3 class=\"sidebar-title\">\
+                        <a href=\"#implementations\">Associated Constants</a>\
+                     </h3>\
+                     <div class=\"sidebar-links\">",
+                );
+                for line in assoc_consts {
+                    write!(out, "{}", line);
+                }
+                out.push_str("</div>");
+            }
+            let mut methods = v
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_none())
-                .flat_map(move |i| {
-                    get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())
-                })
+                .flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx()))
                 .collect::<Vec<_>>();
-            if !ret.is_empty() {
+            if !methods.is_empty() {
                 // We want links' order to be reproducible so we don't use unstable sort.
-                ret.sort();
+                methods.sort();
 
                 out.push_str(
                     "<h3 class=\"sidebar-title\"><a href=\"#implementations\">Methods</a></h3>\
                      <div class=\"sidebar-links\">",
                 );
-                for line in ret {
-                    out.push_str(&line);
+                for line in methods {
+                    write!(out, "{}", line);
                 }
                 out.push_str("</div>");
             }
@@ -1981,7 +2060,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
     }
 }
 
-fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
+fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &[Impl]) {
     let c = cx.cache();
 
     debug!("found Deref: {:?}", impl_);
@@ -1995,8 +2074,8 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
         })
     {
         debug!("found target, real_target: {:?} {:?}", target, real_target);
-        if let Some(did) = target.def_id_full(c) {
-            if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
+        if let Some(did) = target.def_id(c) {
+            if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
                 // `impl Deref<Target = S> for S`
                 if did == type_did {
                     // Avoid infinite cycles
@@ -2006,7 +2085,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
         }
         let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
         let inner_impl = target
-            .def_id_full(c)
+            .def_id(c)
             .or_else(|| {
                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
             })
@@ -2032,7 +2111,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 ret.sort();
                 out.push_str("<div class=\"sidebar-links\">");
                 for link in ret {
-                    out.push_str(&link);
+                    write!(out, "{}", link);
                 }
                 out.push_str("</div>");
             }
@@ -2080,16 +2159,14 @@ fn get_id_for_impl_on_foreign_type(
 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
     match *item.kind {
         clean::ItemKind::ImplItem(ref i) => {
-            if let Some(ref trait_) = i.trait_ {
+            i.trait_.as_ref().map(|trait_| {
                 // Alternative format produces no URLs,
                 // so this parameter does nothing.
-                Some((
+                (
                     format!("{:#}", i.for_.print(cx)),
                     get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
-                ))
-            } else {
-                None
-            }
+                )
+            })
         }
         _ => None,
     }
@@ -2169,10 +2246,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
         let mut res = implementors
             .iter()
             .filter(|i| {
-                i.inner_impl()
-                    .for_
-                    .def_id_full(cache)
-                    .map_or(false, |d| !cache.paths.contains_key(&d))
+                i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
             })
             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
             .collect::<Vec<_>>();
@@ -2264,9 +2338,10 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
     let mut variants = e
         .variants
         .iter()
-        .filter_map(|v| match v.name {
-            Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
-            _ => None,
+        .filter_map(|v| {
+            v.name
+                .as_ref()
+                .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
         })
         .collect::<Vec<_>>();
     if !variants.is_empty() {
@@ -2427,3 +2502,221 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     }
     out
 }
+
+const MAX_FULL_EXAMPLES: usize = 5;
+const NUM_VISIBLE_LINES: usize = 10;
+
+/// Generates the HTML for example call locations generated via the --scrape-examples flag.
+fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
+    let tcx = cx.tcx();
+    let def_id = item.def_id.expect_def_id();
+    let key = tcx.def_path_hash(def_id);
+    let call_locations = match cx.shared.call_locations.get(&key) {
+        Some(call_locations) => call_locations,
+        _ => {
+            return;
+        }
+    };
+
+    // Generate a unique ID so users can link to this section for a given method
+    let id = cx.id_map.borrow_mut().derive("scraped-examples");
+    write!(
+        w,
+        "<div class=\"docblock scraped-example-list\">\
+          <span></span>\
+          <h5 id=\"{id}\" class=\"section-header\">\
+             <a href=\"#{id}\">Examples found in repository</a>\
+          </h5>",
+        id = id
+    );
+
+    // Generate the HTML for a single example, being the title and code block
+    let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
+        let contents = match fs::read_to_string(&path) {
+            Ok(contents) => contents,
+            Err(err) => {
+                let span = item.span(tcx).inner();
+                tcx.sess
+                    .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
+                return false;
+            }
+        };
+
+        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
+        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
+        assert!(!call_data.locations.is_empty());
+        let min_loc =
+            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
+        let byte_min = min_loc.enclosing_item.byte_span.0;
+        let line_min = min_loc.enclosing_item.line_span.0;
+        let max_loc =
+            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
+        let byte_max = max_loc.enclosing_item.byte_span.1;
+        let line_max = max_loc.enclosing_item.line_span.1;
+
+        // The output code is limited to that byte range.
+        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
+
+        // The call locations need to be updated to reflect that the size of the program has changed.
+        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
+        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
+            .locations
+            .iter()
+            .map(|loc| {
+                let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+                let (line_lo, line_hi) = loc.call_expr.line_span;
+                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
+                let line_range = (line_lo - line_min, line_hi - line_min);
+                let (anchor, line_title) = if line_lo == line_hi {
+                    (format!("{}", line_lo + 1), format!("line {}", line_lo + 1))
+                } else {
+                    (
+                        format!("{}-{}", line_lo + 1, line_hi + 1),
+                        format!("lines {}-{}", line_lo + 1, line_hi + 1),
+                    )
+                };
+                let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+
+                (byte_range, (line_range, line_url, line_title))
+            })
+            .unzip();
+
+        let (_, init_url, init_title) = &line_ranges[0];
+        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
+        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
+
+        write!(
+            w,
+            "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
+                <div class=\"scraped-example-title\">\
+                   {name} (<a href=\"{url}\">{title}</a>)\
+                </div>\
+                <div class=\"code-wrapper\">",
+            expanded_cls = if needs_expansion { "" } else { "expanded" },
+            name = call_data.display_name,
+            url = init_url,
+            title = init_title,
+            // The locations are encoded as a data attribute, so they can be read
+            // later by the JS for interactions.
+            locations = Escape(&locations_encoded)
+        );
+
+        if line_ranges.len() > 1 {
+            write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
+        }
+
+        if needs_expansion {
+            write!(w, r#"<span class="expand">&varr;</span>"#);
+        }
+
+        // Look for the example file in the source map if it exists, otherwise return a dummy span
+        let file_span = (|| {
+            let source_map = tcx.sess.source_map();
+            let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+            let abs_crate_src = crate_src.canonicalize().ok()?;
+            let crate_root = abs_crate_src.parent()?.parent()?;
+            let rel_path = path.strip_prefix(crate_root).ok()?;
+            let files = source_map.files();
+            let file = files.iter().find(|file| match &file.name {
+                FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
+                _ => false,
+            })?;
+            Some(rustc_span::Span::with_root_ctxt(
+                file.start_pos + BytePos(byte_min),
+                file.start_pos + BytePos(byte_max),
+            ))
+        })()
+        .unwrap_or(rustc_span::DUMMY_SP);
+
+        // The root path is the inverse of Context::current
+        let root_path = vec!["../"; cx.current.len() - 1].join("");
+
+        let mut decoration_info = FxHashMap::default();
+        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+        decoration_info.insert("highlight", byte_ranges);
+
+        sources::print_src(
+            w,
+            contents_subset,
+            call_data.edition,
+            file_span,
+            cx,
+            &root_path,
+            Some(highlight::DecorationInfo(decoration_info)),
+            sources::SourceContext::Embedded { offset: line_min },
+        );
+        write!(w, "</div></div>");
+
+        true
+    };
+
+    // The call locations are output in sequence, so that sequence needs to be determined.
+    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
+    // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
+    // understand at a glance.
+    let ordered_locations = {
+        let sort_criterion = |(_, call_data): &(_, &CallData)| {
+            // Use the first location because that's what the user will see initially
+            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
+            hi - lo
+        };
+
+        let mut locs = call_locations.into_iter().collect::<Vec<_>>();
+        locs.sort_by_key(sort_criterion);
+        locs
+    };
+
+    let mut it = ordered_locations.into_iter().peekable();
+
+    // An example may fail to write if its source can't be read for some reason, so this method
+    // continues iterating until a write suceeds
+    let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+        while let Some(example) = it.next() {
+            if write_example(&mut *w, example) {
+                break;
+            }
+        }
+    };
+
+    // Write just one example that's visible by default in the method's description.
+    write_and_skip_failure(w, &mut it);
+
+    // Then add the remaining examples in a hidden section.
+    if it.peek().is_some() {
+        write!(
+            w,
+            "<details class=\"rustdoc-toggle more-examples-toggle\">\
+                  <summary class=\"hideme\">\
+                     <span>More examples</span>\
+                  </summary>\
+                  <div class=\"more-scraped-examples\">\
+                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
+                    <div class=\"more-scraped-examples-inner\">"
+        );
+
+        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
+        // make the page arbitrarily huge!
+        for _ in 0..MAX_FULL_EXAMPLES {
+            write_and_skip_failure(w, &mut it);
+        }
+
+        // For the remaining examples, generate a <ul> containing links to the source files.
+        if it.peek().is_some() {
+            write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
+            it.for_each(|(_, call_data)| {
+                write!(
+                    w,
+                    r#"<li><a href="{root}{url}">{name}</a></li>"#,
+                    root = cx.root_path(),
+                    url = call_data.url,
+                    name = call_data.display_name
+                );
+            });
+            write!(w, "</ul></div>");
+        }
+
+        write!(w, "</div></div></details>");
+    }
+
+    write!(w, "</div>");
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 4cfc57ac995..1677b4adf82 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -21,7 +21,7 @@ use super::{
     render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
     ImplRenderingParameters,
 };
-use crate::clean::{self, GetDefId};
+use crate::clean;
 use crate::formats::item_type::ItemType;
 use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
@@ -34,10 +34,10 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 
 use serde::Serialize;
 
-const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &'static str = "</div>";
-const ITEM_TABLE_ROW_OPEN: &'static str = "<div class=\"item-row\">";
-const ITEM_TABLE_ROW_CLOSE: &'static str = "</div>";
+const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
+const ITEM_TABLE_CLOSE: &str = "</div>";
+const ITEM_TABLE_ROW_OPEN: &str = "<div class=\"item-row\">";
+const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
 
 // A component in a `use` path, like `string` in std::string::ToString
 #[derive(Serialize)]
@@ -482,24 +482,26 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         + name.as_str().len()
         + generics_len;
 
-    wrap_item(w, "fn", |w| {
-        render_attributes_in_pre(w, it, "");
-        w.reserve(header_len);
-        write!(
-            w,
-            "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-             {name}{generics}{decl}{notable_traits}{where_clause}",
-            vis = vis,
-            constness = constness,
-            asyncness = asyncness,
-            unsafety = unsafety,
-            abi = abi,
-            name = name,
-            generics = f.generics.print(cx),
-            where_clause = print_where_clause(&f.generics, cx, 0, true),
-            decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
-            notable_traits = notable_traits_decl(&f.decl, cx),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "fn", |w| {
+            render_attributes_in_pre(w, it, "");
+            w.reserve(header_len);
+            write!(
+                w,
+                "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+                 {name}{generics}{decl}{notable_traits}{where_clause}",
+                vis = vis,
+                constness = constness,
+                asyncness = asyncness,
+                unsafety = unsafety,
+                abi = abi,
+                name = name,
+                generics = f.generics.print(cx),
+                where_clause = print_where_clause(&f.generics, cx, 0, true),
+                decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx),
+                notable_traits = notable_traits_decl(&f.decl, cx),
+            );
+        });
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
@@ -740,7 +742,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         }
 
         let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
-            i.inner_impl().for_.def_id_full(cache).map_or(true, |d| cache.paths.contains_key(&d))
+            i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
         });
 
         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
@@ -759,7 +761,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 render_impl(
                     w,
                     cx,
-                    &implementor,
+                    implementor,
                     it,
                     assoc_link,
                     RenderMode::Normal,
@@ -844,16 +846,18 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
 }
 
 fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
-    wrap_item(w, "trait-alias", |w| {
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "trait {}{}{} = {};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            print_where_clause(&t.generics, cx, 0, true),
-            bounds(&t.bounds, true, cx)
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "trait-alias", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "trait {}{}{} = {};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                print_where_clause(&t.generics, cx, 0, true),
+                bounds(&t.bounds, true, cx)
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -866,16 +870,18 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
-    wrap_item(w, "opaque", |w| {
-        render_attributes_in_pre(w, it, "");
-        write!(
-            w,
-            "type {}{}{where_clause} = impl {bounds};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, true),
-            bounds = bounds(&t.bounds, false, cx),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "opaque", |w| {
+            render_attributes_in_pre(w, it, "");
+            write!(
+                w,
+                "type {}{}{where_clause} = impl {bounds};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                bounds = bounds(&t.bounds, false, cx),
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -894,20 +900,37 @@ fn item_typedef(
     t: &clean::Typedef,
     is_associated: bool,
 ) {
-    wrap_item(w, "typedef", |w| {
-        render_attributes_in_pre(w, it, "");
-        if !is_associated {
-            write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
-        }
-        write!(
-            w,
-            "type {}{}{where_clause} = {type_};",
-            it.name.as_ref().unwrap(),
-            t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, true),
-            type_ = t.type_.print(cx),
-        );
-    });
+    fn write_content(
+        w: &mut Buffer,
+        cx: &Context<'_>,
+        it: &clean::Item,
+        t: &clean::Typedef,
+        is_associated: bool,
+    ) {
+        wrap_item(w, "typedef", |w| {
+            render_attributes_in_pre(w, it, "");
+            if !is_associated {
+                write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
+            }
+            write!(
+                w,
+                "type {}{}{where_clause} = {type_};",
+                it.name.as_ref().unwrap(),
+                t.generics.print(cx),
+                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                type_ = t.type_.print(cx),
+            );
+        });
+    }
+
+    // If this is an associated typedef, we don't want to wrap it into a docblock.
+    if is_associated {
+        write_content(w, cx, it, t, is_associated);
+    } else {
+        wrap_into_docblock(w, |w| {
+            write_content(w, cx, it, t, is_associated);
+        });
+    }
 
     document(w, cx, it, None, HeadingOffset::H2);
 
@@ -1136,38 +1159,41 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             it.span(cx.tcx()).inner().edition(),
             None,
             None,
+            None,
         );
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
-    let name = it.name.as_ref().expect("proc-macros always have names");
-    match m.kind {
-        MacroKind::Bang => {
-            wrap_item(w, "macro", |w| {
-                write!(w, "{}!() {{ /* proc-macro */ }}", name);
-            });
-        }
-        MacroKind::Attr => {
-            wrap_item(w, "attr", |w| {
-                write!(w, "#[{}]", name);
-            });
-        }
-        MacroKind::Derive => {
-            wrap_item(w, "derive", |w| {
-                write!(w, "#[derive({})]", name);
-                if !m.helpers.is_empty() {
-                    w.push_str("\n{\n");
-                    w.push_str("    // Attributes available to this derive:\n");
-                    for attr in &m.helpers {
-                        writeln!(w, "    #[{}]", attr);
+    wrap_into_docblock(w, |w| {
+        let name = it.name.as_ref().expect("proc-macros always have names");
+        match m.kind {
+            MacroKind::Bang => {
+                wrap_item(w, "macro", |w| {
+                    write!(w, "{}!() {{ /* proc-macro */ }}", name);
+                });
+            }
+            MacroKind::Attr => {
+                wrap_item(w, "attr", |w| {
+                    write!(w, "#[{}]", name);
+                });
+            }
+            MacroKind::Derive => {
+                wrap_item(w, "derive", |w| {
+                    write!(w, "#[derive({})]", name);
+                    if !m.helpers.is_empty() {
+                        w.push_str("\n{\n");
+                        w.push_str("    // Attributes available to this derive:\n");
+                        for attr in &m.helpers {
+                            writeln!(w, "    #[{}]", attr);
+                        }
+                        w.push_str("}\n");
                     }
-                    w.push_str("}\n");
-                }
-            });
+                });
+            }
         }
-    }
+    });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
@@ -1177,38 +1203,40 @@ fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
-    wrap_item(w, "const", |w| {
-        render_attributes_in_code(w, it);
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "const", |w| {
+            render_attributes_in_code(w, it);
 
-        write!(
-            w,
-            "{vis}const {name}: {typ}",
-            vis = it.visibility.print_with_space(it.def_id, cx),
-            name = it.name.as_ref().unwrap(),
-            typ = c.type_.print(cx),
-        );
+            write!(
+                w,
+                "{vis}const {name}: {typ}",
+                vis = it.visibility.print_with_space(it.def_id, cx),
+                name = it.name.as_ref().unwrap(),
+                typ = c.type_.print(cx),
+            );
 
-        let value = c.value(cx.tcx());
-        let is_literal = c.is_literal(cx.tcx());
-        let expr = c.expr(cx.tcx());
-        if value.is_some() || is_literal {
-            write!(w, " = {expr};", expr = Escape(&expr));
-        } else {
-            w.write_str(";");
-        }
+            let value = c.value(cx.tcx());
+            let is_literal = c.is_literal(cx.tcx());
+            let expr = c.expr(cx.tcx());
+            if value.is_some() || is_literal {
+                write!(w, " = {expr};", expr = Escape(&expr));
+            } else {
+                w.write_str(";");
+            }
 
-        if !is_literal {
-            if let Some(value) = &value {
-                let value_lowercase = value.to_lowercase();
-                let expr_lowercase = expr.to_lowercase();
+            if !is_literal {
+                if let Some(value) = &value {
+                    let value_lowercase = value.to_lowercase();
+                    let expr_lowercase = expr.to_lowercase();
 
-                if value_lowercase != expr_lowercase
-                    && value_lowercase.trim_end_matches("i32") != expr_lowercase
-                {
-                    write!(w, " // {value}", value = Escape(value));
+                    if value_lowercase != expr_lowercase
+                        && value_lowercase.trim_end_matches("i32") != expr_lowercase
+                    {
+                        write!(w, " // {value}", value = Escape(value));
+                    }
                 }
             }
-        }
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2)
@@ -1268,30 +1296,34 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
 }
 
 fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
-    wrap_item(w, "static", |w| {
-        render_attributes_in_code(w, it);
-        write!(
-            w,
-            "{vis}static {mutability}{name}: {typ}",
-            vis = it.visibility.print_with_space(it.def_id, cx),
-            mutability = s.mutability.print_with_space(),
-            name = it.name.as_ref().unwrap(),
-            typ = s.type_.print(cx)
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "static", |w| {
+            render_attributes_in_code(w, it);
+            write!(
+                w,
+                "{vis}static {mutability}{name}: {typ}",
+                vis = it.visibility.print_with_space(it.def_id, cx),
+                mutability = s.mutability.print_with_space(),
+                name = it.name.as_ref().unwrap(),
+                typ = s.type_.print(cx)
+            );
+        });
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    wrap_item(w, "foreigntype", |w| {
-        w.write_str("extern {\n");
-        render_attributes_in_code(w, it);
-        write!(
-            w,
-            "    {}type {};\n}}",
-            it.visibility.print_with_space(it.def_id, cx),
-            it.name.as_ref().unwrap(),
-        );
+    wrap_into_docblock(w, |w| {
+        wrap_item(w, "foreigntype", |w| {
+            w.write_str("extern {\n");
+            render_attributes_in_code(w, it);
+            write!(
+                w,
+                "    {}type {};\n}}",
+                it.visibility.print_with_space(it.def_id, cx),
+                it.name.as_ref().unwrap(),
+            );
+        });
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -1374,7 +1406,7 @@ fn wrap_into_docblock<F>(w: &mut Buffer, f: F)
 where
     F: FnOnce(&mut Buffer),
 {
-    w.write_str("<div class=\"docblock type-decl\">");
+    w.write_str("<div class=\"docblock item-decl\">");
     f(w);
     w.write_str("</div>")
 }
@@ -1465,7 +1497,7 @@ fn render_union(
     );
     if let Some(g) = g {
         write!(w, "{}", g.print(cx));
-        write!(w, "{}", print_where_clause(&g, cx, 0, true));
+        write!(w, "{}", print_where_clause(g, cx, 0, true));
     }
 
     write!(w, " {{\n{}", tab);
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index d517f3ac0e3..1a8562d05ea 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -105,7 +105,7 @@ impl Visitor<'tcx> for SpanMapVisitor<'tcx> {
         }
         for bound in p.bounds {
             if let Some(trait_ref) = bound.trait_ref() {
-                self.handle_path(&trait_ref.path, None);
+                self.handle_path(trait_ref.path, None);
             }
         }
     }
@@ -121,42 +121,33 @@ impl Visitor<'tcx> for SpanMapVisitor<'tcx> {
         if !span.overlaps(m.inner) {
             // Now that we confirmed it's a file import, we want to get the span for the module
             // name only and not all the "mod foo;".
-            if let Some(node) = self.tcx.hir().find(id) {
-                match node {
-                    Node::Item(item) => {
-                        self.matches
-                            .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
-                    }
-                    _ => {}
-                }
+            if let Some(Node::Item(item)) = self.tcx.hir().find(id) {
+                self.matches.insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
             }
         }
         intravisit::walk_mod(self, m, id);
     }
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        match expr.kind {
-            ExprKind::MethodCall(segment, method_span, _, _) => {
-                if let Some(hir_id) = segment.hir_id {
-                    let hir = self.tcx.hir();
-                    let body_id = hir.enclosing_body_owner(hir_id);
-                    let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
-                        self.tcx.typeck_body(
-                            hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
-                        )
-                    });
-                    if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
-                        self.matches.insert(
-                            method_span,
-                            match hir.span_if_local(def_id) {
-                                Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
-                                None => LinkFromSrc::External(def_id),
-                            },
-                        );
-                    }
+        if let ExprKind::MethodCall(segment, method_span, _, _) = expr.kind {
+            if let Some(hir_id) = segment.hir_id {
+                let hir = self.tcx.hir();
+                let body_id = hir.enclosing_body_owner(hir_id);
+                let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+                    self.tcx.typeck_body(
+                        hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+                    )
+                });
+                if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+                    self.matches.insert(
+                        method_span,
+                        match hir.span_if_local(def_id) {
+                            Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+                            None => LinkFromSrc::External(def_id),
+                        },
+                    );
                 }
             }
-            _ => {}
         }
         intravisit::walk_expr(self, expr);
     }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index c1a83ad5820..34f1b4cd684 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -39,8 +39,9 @@ static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
         "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
         "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
         "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
-        "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR,
-        "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
+        "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
+        "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+        "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
         "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
         "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
         "COPYRIGHT.txt" => static_files::COPYRIGHT,
@@ -127,7 +128,7 @@ impl Context<'_> {
     ) -> Result<(), Error> {
         if minify {
             let contents = contents.as_ref();
-            let contents = if resource.extension() == Some(&OsStr::new("css")) {
+            let contents = if resource.extension() == Some(OsStr::new("css")) {
                 minifier::css::minify(contents).map_err(|e| {
                     Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
                 })?
@@ -303,6 +304,15 @@ pub(super) fn write_shared(
         )?;
     }
 
+    if cx.shared.layout.scrape_examples_extension {
+        cx.write_minify(
+            SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
+            static_files::SCRAPE_EXAMPLES_JS,
+            options.enable_minification,
+            &options.emit,
+        )?;
+    }
+
     if let Some(ref css) = cx.shared.layout.css_file_extension {
         let buffer = try_err!(fs::read_to_string(css), css);
         // This varies based on the invocation, so it can't go through the write_minify wrapper.
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 71c64231a21..667bbc24ba5 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -67,7 +67,7 @@ impl LocalSourcesCollector<'_, '_> {
         }
 
         let mut href = String::new();
-        clean_path(&self.src_root, &p, false, |component| {
+        clean_path(self.src_root, &p, false, |component| {
             href.push_str(&component.to_string_lossy());
             href.push('/');
         });
@@ -168,7 +168,7 @@ impl SourceCollector<'_, 'tcx> {
         };
 
         // Remove the utf-8 BOM if any
-        let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
+        let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents);
 
         // Create the intermediate directories
         let mut cur = self.dst.clone();
@@ -204,7 +204,16 @@ impl SourceCollector<'_, 'tcx> {
             &page,
             "",
             |buf: &mut _| {
-                print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+                print_src(
+                    buf,
+                    contents,
+                    self.cx.shared.edition(),
+                    file_span,
+                    self.cx,
+                    &root_path,
+                    None,
+                    SourceContext::Standalone,
+                )
             },
             &self.cx.shared.style_files,
         );
@@ -241,15 +250,22 @@ where
     }
 }
 
+crate enum SourceContext {
+    Standalone,
+    Embedded { offset: usize },
+}
+
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(
+crate fn print_src(
     buf: &mut Buffer,
     s: &str,
     edition: Edition,
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
+    decoration_info: Option<highlight::DecorationInfo>,
+    source_context: SourceContext,
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
@@ -261,7 +277,14 @@ fn print_src(
     }
     line_numbers.write_str("<pre class=\"line-numbers\">");
     for i in 1..=lines {
-        writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
+        match source_context {
+            SourceContext::Standalone => {
+                writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols)
+            }
+            SourceContext::Embedded { offset } => {
+                writeln!(line_numbers, "<span>{0:1$}</span>", i + offset, cols)
+            }
+        }
     }
     line_numbers.write_str("</pre>");
     highlight::render_with_highlighting(
@@ -273,5 +296,6 @@ fn print_src(
         edition,
         Some(line_numbers),
         Some(highlight::ContextInfo { context, file_span, root_path }),
+        decoration_info,
     );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 962af66368d..b98dae85ba0 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -75,12 +75,13 @@
 	font-display: swap;
 }
 
-/* Avoid using legacy CJK serif fonts in Windows like Batang */
+/* Avoid using legacy CJK serif fonts in Windows like Batang. */
 @font-face {
-	font-family: 'Noto Sans KR';
-	src: url("noto-sans-kr-v13-korean-regular.woff") format("woff");
+	font-family: 'NanumBarunGothic';
+	src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
+		url("NanumBarunGothic.ttf.woff") format("woff");
 	font-display: swap;
-	unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;
+	unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
 }
 
 * {
@@ -107,7 +108,7 @@ html {
 /* General structure and fonts */
 
 body {
-	font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
+	font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
 	margin: 0;
 	position: relative;
 	padding: 10px 15px 20px 15px;
@@ -128,9 +129,14 @@ h3 {
 }
 h1, h2, h3, h4, h5, h6 {
 	font-weight: 500;
+}
+h1, h2, h3, h4 {
 	margin: 20px 0 15px 0;
 	padding-bottom: 6px;
 }
+h5, h6 {
+	margin: 15px 0 5px 0;
+}
 h1.fqn {
 	display: flex;
 	border-bottom: 1px dashed;
@@ -146,10 +152,15 @@ h1.fqn > .in-band > a:hover {
 h2, h3, h4 {
 	border-bottom: 1px solid;
 }
-h3.code-header, h4.code-header {
+h3.code-header {
+	font-size: 1.1em;
+}
+h4.code-header {
 	font-size: 1em;
+}
+h3.code-header, h4.code-header {
 	font-weight: 600;
-	border: none;
+	border-bottom-style: none;
 	padding: 0;
 	margin: 0;
 }
@@ -168,12 +179,6 @@ h3.code-header, h4.code-header {
 	margin-bottom: 10px;
 	position: relative;
 }
-.impl, .method.trait-impl,
-.type.trait-impl,
-.associatedconstant.trait-impl,
-.associatedtype.trait-impl {
-	padding-left: 15px;
-}
 
 div.impl-items > div {
 	padding-left: 0;
@@ -191,7 +196,7 @@ div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate, a.srclink,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
-	font-family: "Fira Sans", Arial, sans-serif;
+	font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
 }
 
 .content ul.crate a.crate {
@@ -253,7 +258,10 @@ code, pre, a.test-arrow, .code-header {
 pre {
 	padding: 14px;
 }
-.type-decl pre {
+.docblock.item-decl {
+	margin-left: 0;
+}
+.item-decl pre {
 	overflow-x: auto;
 }
 
@@ -458,6 +466,11 @@ nav.sub {
 	overflow-x: auto;
 }
 
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+	width: auto;
+	overflow-x: visible;
+}
+
 .rustdoc .example-wrap > pre {
 	margin: 0;
 }
@@ -501,14 +514,12 @@ nav.sub {
 	white-space: pre-wrap;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
-	border-bottom: 1px solid;
-}
-
 .top-doc .docblock h2 { font-size: 1.3em; }
 .top-doc .docblock h3 { font-size: 1.15em; }
 .top-doc .docblock h4,
-.top-doc .docblock h5,
+.top-doc .docblock h5 {
+	font-size: 1.1em;
+}
 .top-doc .docblock h6 {
 	font-size: 1em;
 }
@@ -521,7 +532,7 @@ nav.sub {
 	position: relative;
 }
 
-.docblock > * {
+.docblock > :not(.information) {
 	max-width: 100%;
 	overflow-x: auto;
 }
@@ -549,6 +560,7 @@ nav.sub {
 	flex-grow: 1;
 	margin: 0px;
 	padding: 0px;
+	overflow-wrap: anywhere;
 }
 
 .in-band > code, .in-band > .code-header {
@@ -661,13 +673,6 @@ nav.sub {
 	left: -19px;
 }
 
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
-.impl-items > .associatedtype, .content .impl-items details > summary > .type,
-.impl-items details > summary > .associatedconstant,
-.impl-items details > summary > .associatedtype {
-	margin-left: 20px;
-}
-
 .content .impl-items .docblock, .content .impl-items .item-info {
 	margin-bottom: .6em;
 }
@@ -738,7 +743,7 @@ a {
 .anchor {
 	display: none;
 	position: absolute;
-	left: 0;
+	left: -0.5em;
 	background: none !important;
 }
 .anchor.field {
@@ -1571,14 +1576,14 @@ details.rustdoc-toggle > summary.hideme::before {
 
 details.rustdoc-toggle > summary:not(.hideme)::before {
 	position: absolute;
-	left: -23px;
+	left: -24px;
 	top: 3px;
 }
 
 .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
 .undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
 	position: absolute;
-	left: -2px;
+	left: -24px;
 }
 
 /* When a "hideme" summary is open and the "Expand description" or "Show
@@ -1972,3 +1977,166 @@ details.undocumented[open] > summary::before {
 		overflow-wrap: anywhere;
 	}
 }
+
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-title {
+	font-family: 'Fira Sans';
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+	overflow: hidden;
+	max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+	overflow-y: hidden;
+	max-height: 240px;
+	padding-bottom: 0;
+}
+
+.scraped-example .code-wrapper .prev {
+	position: absolute;
+	top: 0.25em;
+	right: 2.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+	position: absolute;
+	top: 0.25em;
+	right: 1.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+	position: absolute;
+	top: 0.25em;
+	right: 0.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper {
+	position: relative;
+	display: flex;
+	flex-direction: row;
+	flex-wrap: wrap;
+	width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+	content: " ";
+	width: 100%;
+	height: 5px;
+	position: absolute;
+	z-index: 100;
+	top: 0;
+	background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+	content: " ";
+	width: 100%;
+	height: 5px;
+	position: absolute;
+	z-index: 100;
+	bottom: 0;
+	background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+	overflow: hidden;
+	max-height: 240px;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+	margin: 0;
+	padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+	padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+	flex: 1;
+	overflow-x: auto;
+	overflow-y: hidden;
+	margin-bottom: 0;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+	overflow-x: inherit;
+	width: inherit;
+	overflow-y: hidden;
+}
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: #fcffd6;
+}
+
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: #f6fdb0;
+}
+
+.more-examples-toggle {
+	margin-top: 10px;
+}
+
+.more-examples-toggle summary {
+	color: #999;
+	font-family: 'Fira Sans';
+}
+
+.more-scraped-examples {
+	margin-left: 25px;
+	display: flex;
+	flex-direction: row;
+	width: calc(100% - 25px);
+}
+
+.more-scraped-examples-inner {
+	/* 20px is width of toggle-line + toggle-line-inner */
+	width: calc(100% - 20px);
+}
+
+.toggle-line {
+	align-self: stretch;
+	margin-right: 10px;
+	margin-top: 5px;
+	padding: 0 4px;
+	cursor: pointer;
+}
+
+.toggle-line:hover .toggle-line-inner {
+	background: #aaa;
+}
+
+.toggle-line-inner {
+	min-width: 2px;
+	background: #ddd;
+	height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+	margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+	margin-bottom: 0;
+}
+
+.example-links a {
+	margin-top: 20px;
+	font-family: 'Fira Sans';
+}
+
+.example-links ul {
+	margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 0fd6462a8f5..f9c84dc3e31 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -220,7 +220,7 @@ body.source .example-wrap pre.rust a {
 	background: #333;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
 	color: #39AFD7;
@@ -613,3 +613,22 @@ div.files > .selected {
 input:checked + .slider {
 	background-color: #ffb454 !important;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+	background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+	background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+	background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+	background: ##898989;
+}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d863701dd73..9a38277d559 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -181,7 +181,7 @@ body.source .example-wrap pre.rust a {
 	background: #333;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
 	color: #D2991D;
@@ -485,3 +485,22 @@ div.files > .selected {
 .setting-line > .title {
 	border-bottom-color: #ddd;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+	background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+	background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+	background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+	background: ##898989;
+}
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 28d2e99a3d0..fba8231caac 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -176,7 +176,7 @@ body.source .example-wrap pre.rust a {
 	background: #eee;
 }
 
-.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
+.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
 .docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
 #help a {
 	color: #3873AD;
diff --git a/src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt b/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt
index 922d5fdc18d..0bf46682b5b 100644
--- a/src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt
+++ b/src/librustdoc/html/static/fonts/NanumBarunGothic-LICENSE.txt
@@ -1,8 +1,14 @@
-Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
 
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
+NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
+Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
+NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
+Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
 
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
 
 
 -----------------------------------------------------------
diff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff
new file mode 100644
index 00000000000..fb063e8fb7d
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff
Binary files differdiff --git a/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2 b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2
new file mode 100644
index 00000000000..1866ad4bcea
--- /dev/null
+++ b/src/librustdoc/html/static/fonts/NanumBarunGothic.ttf.woff2
Binary files differdiff --git a/src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular.woff b/src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular.woff
deleted file mode 100644
index 01d6b6b5466..00000000000
--- a/src/librustdoc/html/static/fonts/noto-sans-kr-v13-korean-regular.woff
+++ /dev/null
Binary files differdiff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
new file mode 100644
index 00000000000..664b187e33e
--- /dev/null
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -0,0 +1,86 @@
+/* global addClass, hasClass, removeClass, onEach */
+
+(function () {
+    // Scroll code block to put the given code location in the middle of the viewer
+    function scrollToLoc(elt, loc) {
+        var wrapper = elt.querySelector(".code-wrapper");
+        var halfHeight = wrapper.offsetHeight / 2;
+        var lines = elt.querySelector('.line-numbers');
+        var offsetMid = (lines.children[loc[0]].offsetTop
+                         + lines.children[loc[1]].offsetTop) / 2;
+        var scrollOffset = offsetMid - halfHeight;
+        lines.scrollTo(0, scrollOffset);
+        elt.querySelector(".rust").scrollTo(0, scrollOffset);
+    }
+
+    function updateScrapedExample(example) {
+        var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+        var locIndex = 0;
+        var highlights = example.querySelectorAll('.highlight');
+        var link = example.querySelector('.scraped-example-title a');
+
+        if (locs.length > 1) {
+            // Toggle through list of examples in a given file
+            var onChangeLoc = function(changeIndex) {
+                removeClass(highlights[locIndex], 'focus');
+                changeIndex();
+                scrollToLoc(example, locs[locIndex][0]);
+                addClass(highlights[locIndex], 'focus');
+
+                var url = locs[locIndex][1];
+                var title = locs[locIndex][2];
+
+                link.href = url;
+                link.innerHTML = title;
+            };
+
+            example.querySelector('.prev')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex - 1 + locs.length) % locs.length;
+                    });
+                });
+
+            example.querySelector('.next')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex + 1) % locs.length;
+                    });
+                });
+        }
+
+        var expandButton = example.querySelector('.expand');
+        if (expandButton) {
+            expandButton.addEventListener('click', function () {
+                if (hasClass(example, "expanded")) {
+                    removeClass(example, "expanded");
+                    scrollToLoc(example, locs[0][0]);
+                } else {
+                    addClass(example, "expanded");
+                }
+            });
+        }
+
+        // Start with the first example in view
+        scrollToLoc(example, locs[0][0]);
+    }
+
+    var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+    onEach(firstExamples, updateScrapedExample);
+    onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+        // Allow users to click the left border of the <details> section to close it,
+        // since the section can be large and finding the [+] button is annoying.
+        toggle.querySelector('.toggle-line').addEventListener('click', function() {
+            toggle.open = false;
+        });
+
+        var moreExamples = toggle.querySelectorAll('.scraped-example');
+        toggle.querySelector('summary').addEventListener('click', function() {
+            // Wrapping in setTimeout ensures the update happens after the elements are actually
+            // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+            // depends on offsetHeight, a property that requires an element to be visible to
+            // compute correctly.
+            setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+        }, {once: true});
+    });
+})();
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index ccc25e6cc49..56c5399d074 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -35,6 +35,10 @@ crate static SETTINGS_JS: &str = include_str!("static/js/settings.js");
 /// Storage, used to store documentation settings.
 crate static STORAGE_JS: &str = include_str!("static/js/storage.js");
 
+/// The file contents of `scraped-examples.js`, which contains functionality related to the
+/// --scrape-examples flag that inserts automatically-found examples of usages of items.
+crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
+
 /// The file contents of `brush.svg`, the icon used for the theme-switch button.
 crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
 
@@ -156,16 +160,35 @@ crate mod source_code_pro {
     crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
 }
 
-crate mod noto_sans_kr {
-    /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR
-    /// font.
-    crate static REGULAR: &[u8] =
-        include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular.woff");
-
-    /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR
-    /// font.
-    crate static LICENSE: &[u8] =
-        include_bytes!("static/fonts/noto-sans-kr-v13-korean-regular-LICENSE.txt");
+/// Files related to the Nanum Barun Gothic font.
+///
+/// These files are used to avoid some legacy CJK serif fonts in Windows.
+///
+/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
+/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
+/// rendering that distorts OpenType fonts too much.
+///
+/// The font files were generated with these commands:
+///
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
+/// ```
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
+/// ```
+crate mod nanum_barun_gothic {
+    /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
+    crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
+
+    /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
+    crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+
+    /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
+    crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
 }
 
 /// Files related to the sidebar in rustdoc sources.
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 38dc3b30e72..b0174d59a7b 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -109,6 +109,9 @@
          data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
     </div>
     <script src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- if layout.scrape_examples_extension -%}
+    <script src="{{static_root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- endif -%}
     {%- for script in page.static_extra_scripts -%}
     <script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
     {% endfor %}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 4098f17db81..443ac282134 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -330,10 +330,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
             },
             Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-                default: default.map(|x| x.into_tcx(tcx)),
+                default: default.map(|x| (*x).into_tcx(tcx)),
             },
             Const { did: _, ty, default } => {
-                GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default }
+                GenericParamDefKind::Const { ty: (*ty).into_tcx(tcx), default: default.map(|x| *x) }
             }
         }
     }
@@ -412,7 +412,7 @@ impl FromWithTcx<clean::Type> for Type {
                         .map(|t| {
                             clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
                         })
-                        .chain(lt.into_iter().map(|lt| clean::GenericBound::Outlives(lt)))
+                        .chain(lt.map(clean::GenericBound::Outlives))
                         .map(|bound| bound.into_tcx(tcx))
                         .collect(),
                 }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 637e5f2288d..0031e3915fa 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -255,7 +255,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                     )
                 })
                 .collect(),
-            format_version: 9,
+            format_version: types::FORMAT_VERSION,
         };
         let mut p = self.out_path.clone();
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ff0a6ef6cb7..93dffc27659 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -48,11 +48,13 @@ extern crate rustc_interface;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_lint_defs;
+extern crate rustc_macros;
 extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_parse;
 extern crate rustc_passes;
 extern crate rustc_resolve;
+extern crate rustc_serialize;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -120,6 +122,7 @@ mod json;
 crate mod lint;
 mod markdown;
 mod passes;
+mod scrape_examples;
 mod theme;
 mod visit_ast;
 mod visit_lib;
@@ -619,6 +622,30 @@ fn opts() -> Vec<RustcOptGroup> {
                 "Make the identifiers in the HTML source code pages navigable",
             )
         }),
+        unstable("scrape-examples-output-path", |o| {
+            o.optopt(
+                "",
+                "scrape-examples-output-path",
+                "",
+                "collect function call information and output at the given path",
+            )
+        }),
+        unstable("scrape-examples-target-crate", |o| {
+            o.optmulti(
+                "",
+                "scrape-examples-target-crate",
+                "",
+                "collect function call information for functions from the target crate",
+            )
+        }),
+        unstable("with-examples", |o| {
+            o.optmulti(
+                "",
+                "with-examples",
+                "",
+                "path to function call information (for displaying examples in the documentation)",
+            )
+        }),
     ]
 }
 
@@ -732,6 +759,7 @@ fn main_options(options: config::Options) -> MainResult {
     // FIXME: fix this clone (especially render_options)
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();
+    let scrape_examples_options = options.scrape_examples_options.clone();
     let config = core::create_config(options);
 
     interface::create_compiler_and_run(config, |compiler| {
@@ -747,7 +775,7 @@ fn main_options(options: config::Options) -> MainResult {
             // We need to hold on to the complete resolver, so we cause everything to be
             // cloned for the analysis passes to use. Suboptimal, but necessary in the
             // current architecture.
-            let resolver = core::create_resolver(queries, &sess);
+            let resolver = core::create_resolver(queries, sess);
 
             if sess.has_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
@@ -768,6 +796,10 @@ fn main_options(options: config::Options) -> MainResult {
                 });
                 info!("finished with rustc");
 
+                if let Some(options) = scrape_examples_options {
+                    return scrape_examples::run(krate, render_opts, cache, tcx, options);
+                }
+
                 cache.crate_version = crate_version;
 
                 if show_coverage {
diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs
index 37faa674292..4501914fe0c 100644
--- a/src/librustdoc/passes/bare_urls.rs
+++ b/src/librustdoc/passes/bare_urls.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> BareUrlsLinter<'a, 'tcx> {
     ) {
         trace!("looking for raw urls in {}", text);
         // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
-        for match_ in URL_REGEX.find_iter(&text) {
+        for match_ in URL_REGEX.find_iter(text) {
             let url = match_.as_str();
             let url_range = match_.range();
             f(
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index d2b3c5239c7..b18208d26e2 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -36,7 +36,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
         let source = dox[code_block.code].to_owned();
         let sess = ParseSess::with_span_handler(handler, sm);
 
-        let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+        let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition());
         let expn_data = ExpnData::default(
             ExpnKind::AstPass(AstPass::TestHarness),
             DUMMY_SP,
@@ -77,7 +77,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
         // The span and whether it is precise or not.
         let (sp, precise_span) = match super::source_span_for_markdown_range(
             self.cx.tcx,
-            &dox,
+            dox,
             &code_block.range,
             &item.attrs,
         ) {
@@ -123,7 +123,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
 
             // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
             for message in buffer.messages.iter() {
-                diag.note(&message);
+                diag.note(message);
             }
 
             diag.emit();
@@ -150,8 +150,8 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
                 item.def_id.expect_def_id(),
                 sp,
             );
-            for code_block in markdown::rust_code_blocks(&dox, &extra) {
-                self.check_rust_syntax(&item, &dox, code_block);
+            for code_block in markdown::rust_code_blocks(dox, &extra) {
+                self.check_rust_syntax(&item, dox, code_block);
             }
         }
 
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 1f7d6054233..69a526d4618 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -115,10 +115,10 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
 
     let mut tests = Tests { found_tests: 0 };
 
-    find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
+    find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
 
     if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
-        if should_have_doc_example(cx, &item) {
+        if should_have_doc_example(cx, item) {
             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
             let sp = item.attr_span(cx.tcx);
             cx.tcx.struct_span_lint_hir(
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 318c897bcbd..9b2fe0c77e6 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -289,7 +289,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
-            module_id: module_id,
+            module_id,
             partial_res: None,
             unresolved: path_str.into(),
         };
@@ -437,7 +437,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
         let result = self.cx.enter_resolver(|resolver| {
             resolver
-                .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+                .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
                 .and_then(|(_, res)| res.try_into())
         });
         debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
@@ -543,7 +543,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             ty::Uint(uty) => Res::Primitive(uty.into()),
             ty::Float(fty) => Res::Primitive(fty.into()),
             ty::Str => Res::Primitive(Str),
-            ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
+            ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
             ty::Tuple(_) => Res::Primitive(Tuple),
             ty::Array(..) => Res::Primitive(Array),
             ty::Slice(_) => Res::Primitive(Slice),
@@ -978,13 +978,13 @@ fn preprocess_link<'a>(
     }
 
     // Parse and strip the disambiguator from the link, if present.
-    let (disambiguator, path_str, link_text) = match Disambiguator::from_str(&link) {
+    let (disambiguator, path_str, link_text) = match Disambiguator::from_str(link) {
         Ok(Some((d, path, link_text))) => (Some(d), path.trim(), link_text.trim()),
         Ok(None) => (None, link.trim(), link.trim()),
         Err((err_msg, relative_range)) => {
             // Only report error if we would not have ignored this link. See issue #83859.
             if !should_ignore_link_with_disambiguators(link) {
-                let no_backticks_range = range_between_backticks(&ori_link);
+                let no_backticks_range = range_between_backticks(ori_link);
                 let disambiguator_range = (no_backticks_range.start + relative_range.start)
                     ..(no_backticks_range.start + relative_range.end);
                 return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
@@ -1000,7 +1000,7 @@ fn preprocess_link<'a>(
 
     // Strip generics from the path.
     let path_str = if path_str.contains(['<', '>'].as_slice()) {
-        match strip_generics_from_path(&path_str) {
+        match strip_generics_from_path(path_str) {
             Ok(path) => path,
             Err(err_kind) => {
                 debug!("link has malformed generics: {}", path_str);
@@ -1228,7 +1228,7 @@ impl LinkCollector<'_, '_> {
                 if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
                     && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
                 {
-                    privacy_error(self.cx, &diag_info, &path_str);
+                    privacy_error(self.cx, &diag_info, path_str);
                 }
             }
 
@@ -1766,8 +1766,8 @@ fn report_diagnostic(
 
         let span =
             super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
-                if dox.bytes().nth(link_range.start) == Some(b'`')
-                    && dox.bytes().nth(link_range.end - 1) == Some(b'`')
+                if dox.as_bytes().get(link_range.start) == Some(&b'`')
+                    && dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
                 {
                     sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
                 } else {
@@ -1868,8 +1868,7 @@ fn resolution_failure(
                         };
                         name = start;
                         for ns in [TypeNS, ValueNS, MacroNS] {
-                            if let Some(res) =
-                                collector.check_full_res(ns, &start, module_id, &None)
+                            if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index cd90528ab9c..565bcb8bd13 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -34,7 +34,7 @@ impl IntraLinkCrateLoader {
         let attrs = crate::clean::Attributes::from_ast(attrs, None);
         for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
             debug!(?doc);
-            for link in markdown_links(&doc.as_str()) {
+            for link in markdown_links(doc.as_str()) {
                 debug!(?link.link);
                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
                     x.path_str
@@ -46,7 +46,7 @@ impl IntraLinkCrateLoader {
                         span,
                         &path_str,
                         TypeNS,
-                        parent_module.unwrap_or(self.current_mod.to_def_id()),
+                        parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
                     );
                 });
             }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 319dd7b42b0..91a0cb413eb 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -70,7 +70,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
 
                 if let Some(prim) = target.primitive_type() {
                     cleaner.prims.insert(prim);
-                } else if let Some(did) = target.def_id() {
+                } else if let Some(did) = target.def_id(&cx.cache) {
                     cleaner.items.insert(did.into());
                 }
             }
@@ -187,7 +187,7 @@ impl BadImplStripper {
             true
         } else if let Some(prim) = ty.primitive_type() {
             self.prims.contains(&prim)
-        } else if let Some(did) = ty.def_id() {
+        } else if let Some(did) = ty.def_id_no_primitives() {
             self.keep_impl_with_def_id(did.into())
         } else {
             false
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 8b1fd662f85..74a9a2da06d 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -2,7 +2,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::privacy::AccessLevels;
 use std::mem;
 
-use crate::clean::{self, GetDefId, Item, ItemIdSet};
+use crate::clean::{self, Item, ItemIdSet};
 use crate::fold::{strip_item, DocFolder};
 
 crate struct Stripper<'a> {
@@ -127,7 +127,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             if imp.trait_.is_none() && imp.items.is_empty() {
                 return None;
             }
-            if let Some(did) = imp.for_.def_id() {
+            if let Some(did) = imp.for_.def_id_no_primitives() {
                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
                 {
                     debug!("ImplStripper: impl item for stripped type; removing");
@@ -142,7 +142,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             }
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
-                    if let Some(did) = typaram.def_id() {
+                    if let Some(did) = typaram.def_id_no_primitives() {
                         if did.is_local() && !self.retained.contains(&did.into()) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
new file mode 100644
index 00000000000..fc54e55b876
--- /dev/null
+++ b/src/librustdoc/scrape_examples.rs
@@ -0,0 +1,266 @@
+//! This module analyzes crates to find call sites that can serve as examples in the documentation.
+
+use crate::clean;
+use crate::config;
+use crate::formats;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{
+    self as hir,
+    intravisit::{self, Visitor},
+    HirId,
+};
+use rustc_interface::interface;
+use rustc_macros::{Decodable, Encodable};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_serialize::{
+    opaque::{Decoder, FileEncoder},
+    Decodable, Encodable,
+};
+use rustc_session::getopts;
+use rustc_span::{
+    def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
+    edition::Edition,
+    BytePos, FileName, SourceFile,
+};
+
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+crate struct ScrapeExamplesOptions {
+    output_path: PathBuf,
+    target_crates: Vec<String>,
+}
+
+impl ScrapeExamplesOptions {
+    crate fn new(
+        matches: &getopts::Matches,
+        diag: &rustc_errors::Handler,
+    ) -> Result<Option<Self>, i32> {
+        let output_path = matches.opt_str("scrape-examples-output-path");
+        let target_crates = matches.opt_strs("scrape-examples-target-crate");
+        match (output_path, !target_crates.is_empty()) {
+            (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
+                output_path: PathBuf::from(output_path),
+                target_crates,
+            })),
+            (Some(_), false) | (None, true) => {
+                diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+                Err(1)
+            }
+            (None, false) => Ok(None),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct SyntaxRange {
+    crate byte_span: (u32, u32),
+    crate line_span: (usize, usize),
+}
+
+impl SyntaxRange {
+    fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+        let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
+        let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+
+        SyntaxRange {
+            byte_span: (get_pos(span.lo()), get_pos(span.hi())),
+            line_span: (get_line(span.lo()), get_line(span.hi())),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallLocation {
+    crate call_expr: SyntaxRange,
+    crate enclosing_item: SyntaxRange,
+}
+
+impl CallLocation {
+    fn new(
+        tcx: TyCtxt<'_>,
+        expr_span: rustc_span::Span,
+        expr_id: HirId,
+        source_file: &SourceFile,
+    ) -> Self {
+        let enclosing_item_span =
+            tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite();
+        assert!(enclosing_item_span.contains(expr_span));
+
+        CallLocation {
+            call_expr: SyntaxRange::new(expr_span, source_file),
+            enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallData {
+    crate locations: Vec<CallLocation>,
+    crate url: String,
+    crate display_name: String,
+    crate edition: Edition,
+}
+
+crate type FnCallLocations = FxHashMap<PathBuf, CallData>;
+crate type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+
+/// Visitor for traversing a crate and finding instances of function calls.
+struct FindCalls<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    map: Map<'tcx>,
+    cx: Context<'tcx>,
+    target_crates: Vec<CrateNum>,
+    calls: &'a mut AllCallLocations,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
+where
+    'tcx: 'a,
+{
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::OnlyBodies(self.map)
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        intravisit::walk_expr(self, ex);
+
+        // Get type of function if expression is a function call
+        let tcx = self.tcx;
+        let (ty, span) = match ex.kind {
+            hir::ExprKind::Call(f, _) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                (types.node_type(f.hir_id), ex.span)
+            }
+            hir::ExprKind::MethodCall(_, _, _, span) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+                (tcx.type_of(def_id), span)
+            }
+            _ => {
+                return;
+            }
+        };
+
+        // If this span comes from a macro expansion, then the source code may not actually show
+        // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
+        if span.from_expansion() {
+            return;
+        }
+
+        // Save call site if the function resolves to a concrete definition
+        if let ty::FnDef(def_id, _) = ty.kind() {
+            // Ignore functions not from the crate being documented
+            if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+                return;
+            }
+
+            let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+            let file_path = match file.name.clone() {
+                FileName::Real(real_filename) => real_filename.into_local_path(),
+                _ => None,
+            };
+
+            if let Some(file_path) = file_path {
+                let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+                let cx = &self.cx;
+                let mk_call_data = || {
+                    let clean_span = crate::clean::types::Span::new(span);
+                    let url = cx.href_from_span(clean_span, false).unwrap();
+                    let display_name = file_path.display().to_string();
+                    let edition = span.edition();
+                    CallData { locations: Vec::new(), url, display_name, edition }
+                };
+
+                let fn_key = tcx.def_path_hash(*def_id);
+                let fn_entries = self.calls.entry(fn_key).or_default();
+
+                let location = CallLocation::new(tcx, span, ex.hir_id, &file);
+                fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
+            }
+        }
+    }
+}
+
+crate fn run(
+    krate: clean::Crate,
+    renderopts: config::RenderOptions,
+    cache: formats::cache::Cache,
+    tcx: TyCtxt<'_>,
+    options: ScrapeExamplesOptions,
+) -> interface::Result<()> {
+    let inner = move || -> Result<(), String> {
+        // Generates source files for examples
+        let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
+
+        // Collect CrateIds corresponding to provided target crates
+        // If two different versions of the crate in the dependency tree, then examples will be collcted from both.
+        let all_crates = tcx
+            .crates(())
+            .iter()
+            .chain([&LOCAL_CRATE])
+            .map(|crate_num| (crate_num, tcx.crate_name(*crate_num)))
+            .collect::<Vec<_>>();
+        let target_crates = options
+            .target_crates
+            .into_iter()
+            .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
+            .flatten()
+            .map(|(crate_num, _)| **crate_num)
+            .collect::<Vec<_>>();
+
+        debug!("All crates in TyCtxt: {:?}", all_crates);
+        debug!("Scrape examples target_crates: {:?}", target_crates);
+
+        // Run call-finder on all items
+        let mut calls = FxHashMap::default();
+        let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
+        tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+
+        // Save output to provided path
+        let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
+        calls.encode(&mut encoder).map_err(|e| e.to_string())?;
+        encoder.flush().map_err(|e| e.to_string())?;
+
+        Ok(())
+    };
+
+    if let Err(e) = inner() {
+        tcx.sess.fatal(&e);
+    }
+
+    Ok(())
+}
+
+// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+crate fn load_call_locations(
+    with_examples: Vec<String>,
+    diag: &rustc_errors::Handler,
+) -> Result<AllCallLocations, i32> {
+    let inner = || {
+        let mut all_calls: AllCallLocations = FxHashMap::default();
+        for path in with_examples {
+            let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+            let mut decoder = Decoder::new(&bytes, 0);
+            let calls = AllCallLocations::decode(&mut decoder)?;
+
+            for (function, fn_calls) in calls.into_iter() {
+                all_calls.entry(function).or_default().extend(fn_calls.into_iter());
+            }
+        }
+
+        Ok(all_calls)
+    };
+
+    inner().map_err(|e: String| {
+        diag.err(&format!("failed to load examples: {}", e));
+        1
+    })
+}
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 36b1a14f6c1..5d1f934240f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -9,7 +9,6 @@ use rustc_hir::Node;
 use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
-use rustc_span;
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -87,13 +86,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         // the rexport defines the path that a user will actually see. Accordingly,
         // we add the rexport as an item here, and then skip over the original
         // definition in `visit_item()` below.
+        //
+        // We also skip `#[macro_export] macro_rules!` that have already been inserted,
+        // it can happen if within the same module a `#[macro_export] macro_rules!`
+        // is declared but also a reexport of itself producing two exports of the same
+        // macro in the same module.
+        let mut inserted = FxHashSet::default();
         for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
             if let Res::Def(DefKind::Macro(_), def_id) = export.res {
                 if let Some(local_def_id) = def_id.as_local() {
                     if self.cx.tcx.has_attr(def_id, sym::macro_export) {
-                        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
-                        let item = self.cx.tcx.hir().expect_item(hir_id);
-                        top_level_module.items.push((item, None));
+                        if inserted.insert(def_id) {
+                            let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+                            let item = self.cx.tcx.hir().expect_item(hir_id);
+                            top_level_module.items.push((item, None));
+                        }
                     }
                 }
             }
@@ -113,11 +120,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     .unwrap_or(&[])
                     .iter()
                     .filter_map(|attr| {
-                        Some(
-                            Cfg::parse(attr.meta_item()?)
-                                .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
-                                .ok()?,
-                        )
+                        Cfg::parse(attr.meta_item()?)
+                            .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
+                            .ok()
                     })
                     .collect::<Vec<_>>()
             })
@@ -271,7 +276,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             _ if self.inlining && !is_pub => {}
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
-            hir::ItemKind::Use(ref path, kind) => {
+            hir::ItemKind::Use(path, kind) => {
                 let is_glob = kind == hir::UseKind::Glob;
 
                 // Struct and variant constructors and proc macro stubs always show up alongside