about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-01-05 10:57:23 -0500
committerGitHub <noreply@github.com>2024-01-05 10:57:23 -0500
commit3f19de635203f0e8dbef04fff4cda524d76d4021 (patch)
tree9fb057d28617774b2dd9df7221e59890fd85f5d2
parent8bea1df254ca5225c547e8b2fdeb434dd8ac0226 (diff)
parent5bc76873517d152fc5753c28059b247daabbf341 (diff)
Rollup merge of #119586 - GuillaumeGomez:jump-to-def-static-methods, r=notriddle
[rustdoc] Fix invalid handling for static method calls in jump to definition feature

I realized when working on a clippy lint that static method calls on `Self` could not give me the method `Res`. For that, we need to use `typeck` and so that's what I did in here.

It fixes the linking to static method calls.

r? ````@notriddle````
-rw-r--r--src/librustdoc/html/render/span_map.rs52
-rw-r--r--tests/rustdoc/check-source-code-urls-to-def.rs2
-rw-r--r--tests/rustdoc/jump-to-def-doc-links-calls.rs27
3 files changed, 60 insertions, 21 deletions
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index d1ece73374d..b055e355b78 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -154,6 +154,28 @@ impl<'tcx> SpanMapVisitor<'tcx> {
         self.matches.insert(new_span, link_from_src);
         true
     }
+
+    fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
+        let hir = self.tcx.hir();
+        let body_id = hir.enclosing_body_owner(hir_id);
+        // FIXME: this is showing error messages for parts of the code that are not
+        // compiled (because of cfg)!
+        //
+        // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
+        let typeck_results = self
+            .tcx
+            .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
+        // Interestingly enough, for method calls, we need the whole expression whereas for static
+        // method/function calls, we need the call expression specifically.
+        if let Some(def_id) = typeck_results.type_dependent_def_id(expr_hir_id.unwrap_or(hir_id)) {
+            let link = if def_id.as_local().is_some() {
+                LinkFromSrc::Local(rustc_span(def_id, self.tcx))
+            } else {
+                LinkFromSrc::External(def_id)
+            };
+            self.matches.insert(span, link);
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@@ -191,27 +213,17 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        if let ExprKind::MethodCall(segment, ..) = expr.kind {
-            let hir = self.tcx.hir();
-            let body_id = hir.enclosing_body_owner(segment.hir_id);
-            // FIXME: this is showing error messages for parts of the code that are not
-            // compiled (because of cfg)!
-            //
-            // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
-            let typeck_results = 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) {
-                let link = if def_id.as_local().is_some() {
-                    LinkFromSrc::Local(rustc_span(def_id, self.tcx))
-                } else {
-                    LinkFromSrc::External(def_id)
-                };
-                self.matches.insert(segment.ident.span, link);
+        match expr.kind {
+            ExprKind::MethodCall(segment, ..) => {
+                self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span)
+            }
+            ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span),
+            _ => {
+                if self.handle_macro(expr.span) {
+                    // We don't want to go deeper into the macro.
+                    return;
+                }
             }
-        } else if self.handle_macro(expr.span) {
-            // We don't want to go deeper into the macro.
-            return;
         }
         intravisit::walk_expr(self, expr);
     }
diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/check-source-code-urls-to-def.rs
index b803c7e9e86..c31c579030e 100644
--- a/tests/rustdoc/check-source-code-urls-to-def.rs
+++ b/tests/rustdoc/check-source-code-urls-to-def.rs
@@ -62,7 +62,7 @@ pub trait AnotherTrait2 {}
 
 // @has - '//pre[@class="rust"]//a[@href="#61"]' 'AnotherTrait2'
 pub fn foo4() {
-    let x: Vec<AnotherTrait2> = Vec::new();
+    let x: Vec<&dyn AnotherTrait2> = Vec::new();
 }
 
 // @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool'
diff --git a/tests/rustdoc/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def-doc-links-calls.rs
new file mode 100644
index 00000000000..549d068528e
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-doc-links-calls.rs
@@ -0,0 +1,27 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+// @has 'src/foo/jump-to-def-doc-links-calls.rs.html'
+
+// @has - '//a[@href="../../foo/struct.Bar.html"]' 'Bar'
+pub struct Bar;
+
+impl std::default::Default for Bar {
+    // @has - '//a[@href="#20-22"]' 'Self::new'
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+// @has - '//a[@href="#8"]' 'Bar'
+impl Bar {
+     // @has - '//a[@href="#24-26"]' 'Self::bar'
+     pub fn new()-> Self {
+         Self::bar()
+     }
+
+     pub fn bar() -> Self {
+         Self
+     }
+}