Skip to content

Commit 255cafe

Browse files
Rollup merge of rust-lang#134216 - GuillaumeGomez:jump-to-def-pats, r=fmease
Enable "jump to def" feature on patterns Part of rust-lang#89095. Pattern (as in "patterns in pattern matching") were not handled by the feature, it's now added. It all started when I realized that prelude values like `Some` or `Err` were not getting a link generated either (added support for it in the first commit). r? `@fmease`
2 parents c074d8e + 12a12c9 commit 255cafe

File tree

3 files changed

+91
-9
lines changed

3 files changed

+91
-9
lines changed

src/librustdoc/html/highlight.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ enum Class {
337337
Ident(Span),
338338
Lifetime,
339339
PreludeTy(Span),
340-
PreludeVal,
340+
PreludeVal(Span),
341341
QuestionMark,
342342
Decoration(&'static str),
343343
}
@@ -385,7 +385,7 @@ impl Class {
385385
Class::Ident(_) => "",
386386
Class::Lifetime => "lifetime",
387387
Class::PreludeTy(_) => "prelude-ty",
388-
Class::PreludeVal => "prelude-val",
388+
Class::PreludeVal(_) => "prelude-val",
389389
Class::QuestionMark => "question-mark",
390390
Class::Decoration(kind) => kind,
391391
}
@@ -395,7 +395,11 @@ impl Class {
395395
/// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
396396
fn get_span(self) -> Option<Span> {
397397
match self {
398-
Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) | Self::PreludeTy(sp) => Some(sp),
398+
Self::Ident(sp)
399+
| Self::Self_(sp)
400+
| Self::Macro(sp)
401+
| Self::PreludeTy(sp)
402+
| Self::PreludeVal(sp) => Some(sp),
399403
Self::Comment
400404
| Self::DocComment
401405
| Self::Attribute
@@ -406,7 +410,6 @@ impl Class {
406410
| Self::Number
407411
| Self::Bool
408412
| Self::Lifetime
409-
| Self::PreludeVal
410413
| Self::QuestionMark
411414
| Self::Decoration(_) => None,
412415
}
@@ -851,7 +854,9 @@ impl<'src> Classifier<'src> {
851854
TokenKind::Ident => match get_real_ident_class(text, false) {
852855
None => match text {
853856
"Option" | "Result" => Class::PreludeTy(self.new_span(before, text)),
854-
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
857+
"Some" | "None" | "Ok" | "Err" => {
858+
Class::PreludeVal(self.new_span(before, text))
859+
}
855860
// "union" is a weak keyword and is only considered as a keyword when declaring
856861
// a union type.
857862
"union" if self.check_if_is_union_keyword() => Class::KeyWord,

src/librustdoc/html/render/span_map.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
44
use rustc_hir::def::{DefKind, Res};
55
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
66
use rustc_hir::intravisit::{self, Visitor};
7-
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node};
7+
use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath};
88
use rustc_middle::hir::nested_filter;
99
use rustc_middle::ty::TyCtxt;
1010
use rustc_span::hygiene::MacroKind;
@@ -170,7 +170,7 @@ impl SpanMapVisitor<'_> {
170170
true
171171
}
172172

173-
fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
173+
fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
174174
let hir = self.tcx.hir();
175175
let body_id = hir.enclosing_body_owner(hir_id);
176176
// FIXME: this is showing error messages for parts of the code that are not
@@ -189,6 +189,27 @@ impl SpanMapVisitor<'_> {
189189
self.matches.insert(span, link);
190190
}
191191
}
192+
193+
fn handle_pat(&mut self, p: &Pat<'_>) {
194+
match p.kind {
195+
PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
196+
PatKind::Struct(qpath, _, _)
197+
| PatKind::TupleStruct(qpath, _, _)
198+
| PatKind::Path(qpath) => match qpath {
199+
QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
200+
self.infer_id(path.hir_id, Some(p.hir_id), qpath.span());
201+
}
202+
QPath::Resolved(_, path) => self.handle_path(path),
203+
_ => {}
204+
},
205+
PatKind::Or(pats) => {
206+
for pat in pats {
207+
self.handle_pat(pat);
208+
}
209+
}
210+
_ => {}
211+
}
212+
}
192213
}
193214

194215
impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@@ -206,6 +227,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
206227
intravisit::walk_path(self, path);
207228
}
208229

230+
fn visit_pat(&mut self, p: &Pat<'tcx>) {
231+
self.handle_pat(p);
232+
}
233+
209234
fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
210235
// To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
211236
// file, we want to link to it. Otherwise no need to create a link.
@@ -228,9 +253,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
228253
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
229254
match expr.kind {
230255
ExprKind::MethodCall(segment, ..) => {
231-
self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span)
256+
self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span)
232257
}
233-
ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span),
258+
ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span),
234259
_ => {
235260
if self.handle_macro(expr.span) {
236261
// We don't want to go deeper into the macro.

tests/rustdoc/jump-to-def-pats.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// This test ensures that patterns also get a link generated.
2+
3+
//@ compile-flags: -Zunstable-options --generate-link-to-definition
4+
5+
#![crate_name = "foo"]
6+
7+
//@ has 'src/foo/jump-to-def-pats.rs.html'
8+
9+
use std::fmt;
10+
11+
pub enum MyEnum<T, E> {
12+
Ok(T),
13+
Err(E),
14+
Some(T),
15+
None,
16+
}
17+
18+
pub enum X {
19+
A,
20+
}
21+
22+
pub fn foo() -> Result<(), ()> {
23+
// FIXME: would be nice to be able to check both the class and the href at the same time so
24+
// we could check the text as well...
25+
//@ has - '//a[@class="prelude-val"]/@href' '{{channel}}/core/result/enum.Result.html#variant.Ok'
26+
//@ has - '//a[@href="{{channel}}/core/result/enum.Result.html#variant.Ok"]' 'Ok'
27+
Ok(())
28+
}
29+
30+
impl<T, E> fmt::Display for MyEnum<T, E> {
31+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32+
match self {
33+
//@ has - '//a[@href="#12"]' 'Self::Ok'
34+
Self::Ok(_) => f.write_str("MyEnum::Ok"),
35+
//@ has - '//a[@href="#13"]' 'MyEnum::Err'
36+
MyEnum::Err(_) => f.write_str("MyEnum::Err"),
37+
//@ has - '//a[@href="#14"]' 'Self::Some'
38+
Self::Some(_) => f.write_str("MyEnum::Some"),
39+
//@ has - '//a[@href="#15"]' 'Self::None'
40+
Self::None => f.write_str("MyEnum::None"),
41+
}
42+
}
43+
}
44+
45+
impl X {
46+
fn p(&self) -> &str {
47+
match self {
48+
//@ has - '//a[@href="#19"]' 'Self::A'
49+
Self::A => "X::A",
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)