about summary refs log tree commit diff
path: root/src/librustdoc/html/render/span_map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render/span_map.rs')
-rw-r--r--src/librustdoc/html/render/span_map.rs70
1 files changed, 43 insertions, 27 deletions
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index ebbc61db688..342cf5073f7 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -65,7 +65,7 @@ struct SpanMapVisitor<'tcx> {
 
 impl SpanMapVisitor<'_> {
     /// This function is where we handle `hir::Path` elements and add them into the "span map".
-    fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: bool) {
         match path.res {
             // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
             // Would be nice to support them too alongside the other `DefKind`
@@ -77,24 +77,36 @@ impl SpanMapVisitor<'_> {
                     LinkFromSrc::External(def_id)
                 };
                 // In case the path ends with generics, we remove them from the span.
-                let span = path
-                    .segments
-                    .last()
-                    .map(|last| {
-                        // In `use` statements, the included item is not in the path segments.
-                        // However, it doesn't matter because you can't have generics on `use`
-                        // statements.
-                        if path.span.contains(last.ident.span) {
-                            path.span.with_hi(last.ident.span.hi())
-                        } else {
-                            path.span
-                        }
-                    })
-                    .unwrap_or(path.span);
+                let span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.segments
+                        .last()
+                        .map(|last| {
+                            // In `use` statements, the included item is not in the path segments.
+                            // However, it doesn't matter because you can't have generics on `use`
+                            // statements.
+                            if path.span.contains(last.ident.span) {
+                                path.span.with_hi(last.ident.span.hi())
+                            } else {
+                                path.span
+                            }
+                        })
+                        .unwrap_or(path.span)
+                };
                 self.matches.insert(span, link);
             }
             Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
-                self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
+                let path_span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.span
+                };
+                self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
@@ -200,37 +212,41 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         if self.handle_macro(path.span) {
             return;
         }
-        self.handle_path(path);
+        self.handle_path(path, false);
         intravisit::walk_path(self, path);
     }
 
-    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, span: Span) {
+    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
         match *qpath {
             QPath::TypeRelative(qself, path) => {
                 if matches!(path.res, Res::Err) {
                     let tcx = self.tcx;
-                    let hir = tcx.hir();
-                    let body_id = hir.enclosing_body_owner(id);
-                    let typeck_results = tcx.typeck_body(hir.body_owned_by(body_id).id());
+                    let body_id = tcx.hir_enclosing_body_owner(id);
+                    let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
                     let path = rustc_hir::Path {
                         // We change the span to not include parens.
-                        span: span.with_hi(path.ident.span.hi()),
+                        span: path.ident.span,
                         res: typeck_results.qpath_res(qpath, id),
                         segments: &[],
                     };
-                    self.handle_path(&path);
+                    self.handle_path(&path, false);
                 } else {
-                    self.infer_id(path.hir_id, Some(id), span);
+                    self.infer_id(path.hir_id, Some(id), path.ident.span);
                 }
 
-                rustc_ast::visit::try_visit!(self.visit_ty(qself));
+                if let Some(qself) = qself.try_as_ambig_ty() {
+                    rustc_ast::visit::try_visit!(self.visit_ty(qself));
+                }
                 self.visit_path_segment(path);
             }
             QPath::Resolved(maybe_qself, path) => {
-                self.handle_path(path);
+                self.handle_path(path, true);
 
+                let maybe_qself = maybe_qself.and_then(|maybe_qself| maybe_qself.try_as_ambig_ty());
                 rustc_ast::visit::visit_opt!(self, visit_ty, maybe_qself);
-                self.visit_path(path, id)
+                if !self.handle_macro(path.span) {
+                    intravisit::walk_path(self, path);
+                }
             }
             _ => {}
         }