Skip to content

Commit 88b9b9d

Browse files
committed
goto definition on RangeFrom, RangeFull, RangeTo, and RangeToInclusive links to respective struct
1 parent 8e69377 commit 88b9b9d

File tree

2 files changed

+65
-36
lines changed

2 files changed

+65
-36
lines changed

src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,17 @@ impl SourceAnalyzer {
353353
db: &dyn HirDatabase,
354354
range_expr: &ast::RangeExpr,
355355
) -> Option<StructId> {
356-
let path = match range_expr.op_kind()? {
357-
RangeOp::Exclusive => path![core::ops::Range],
358-
RangeOp::Inclusive => path![core::ops::RangeInclusive],
356+
let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
357+
(RangeOp::Exclusive, None, None) => path![core::ops::RangeFull],
358+
(RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
359+
(RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
360+
(RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
361+
(RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
362+
(RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
363+
364+
// [E0586] inclusive ranges must be bounded at the end
365+
(RangeOp::Inclusive, None, None) => return None,
366+
(RangeOp::Inclusive, Some(_), None) => return None
359367
};
360368
self.resolver.resolve_known_struct(db.upcast(), &path)
361369
}

src/tools/rust-analyzer/crates/ide/src/goto_definition.rs

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -449,55 +449,76 @@ mod tests {
449449
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
450450
}
451451

452+
fn check_name(expected_name: &str, ra_fixture: &str) {
453+
let (analysis, position, _) = fixture::annotations(ra_fixture);
454+
let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
455+
assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
456+
let Some(target) = navs.into_iter().next() else {
457+
panic!("expected single navigation target but encountered none");
458+
};
459+
assert_eq!(target.name, SmolStr::new_inline(expected_name));
460+
}
461+
452462
#[test]
453-
fn goto_def_range_inclusive_0() {
454-
let ra_fixture = r#"
463+
fn goto_def_range() {
464+
check_name("Range", r#"
455465
//- minicore: range
456-
fn f(a: usize, b: usize) {
457-
for _ in a.$0.=b {
458-
466+
let x = 0.$0.1;
467+
"#
468+
);
459469
}
470+
471+
#[test]
472+
fn goto_def_range_from() {
473+
check_name("RangeFrom", r#"
474+
//- minicore: range
475+
fn f(arr: &[i32]) -> &[i32] {
476+
&arr[0.$0.]
460477
}
461-
"#;
462-
let (analysis, position, _) = fixture::annotations(ra_fixture);
463-
let mut navs =
464-
analysis.goto_definition(position).unwrap().expect("no definition found").info;
465-
let Some(target) = navs.pop() else { panic!("no target found") };
466-
assert_eq!(target.name, SmolStr::new_inline("RangeInclusive"));
478+
"#
479+
);
467480
}
468481

469482
#[test]
470-
fn goto_def_range_inclusive_1() {
471-
let ra_fixture = r#"
483+
fn goto_def_range_inclusive() {
484+
check_name("RangeInclusive", r#"
472485
//- minicore: range
473-
fn f(a: usize, b: usize) {
474-
for _ in a..$0=b {
475-
486+
let x = 0.$0.=1;
487+
"#
488+
);
476489
}
490+
491+
#[test]
492+
fn goto_def_range_full() {
493+
check_name("RangeFull", r#"
494+
//- minicore: range
495+
fn f(arr: &[i32]) -> &[i32] {
496+
&arr[.$0.]
477497
}
478-
"#;
479-
let (analysis, position, _) = fixture::annotations(ra_fixture);
480-
let mut navs =
481-
analysis.goto_definition(position).unwrap().expect("no definition found").info;
482-
let Some(target) = navs.pop() else { panic!("no target found") };
483-
assert_eq!(target.name, SmolStr::new_inline("RangeInclusive"));
498+
"#
499+
);
484500
}
485501

486502
#[test]
487-
fn goto_def_range() {
488-
let ra_fixture = r#"
503+
fn goto_def_range_to() {
504+
check_name("RangeTo", r#"
489505
//- minicore: range
490-
fn f(a: usize, b: usize) {
491-
for _ in a.$0.b {
492-
506+
fn f(arr: &[i32]) -> &[i32] {
507+
&arr[.$0.10]
508+
}
509+
"#
510+
);
493511
}
512+
513+
#[test]
514+
fn goto_def_range_to_inclusive() {
515+
check_name("RangeToInclusive", r#"
516+
//- minicore: range
517+
fn f(arr: &[i32]) -> &[i32] {
518+
&arr[.$0.=10]
494519
}
495-
"#;
496-
let (analysis, position, _) = fixture::annotations(ra_fixture);
497-
let mut navs =
498-
analysis.goto_definition(position).unwrap().expect("no definition found").info;
499-
let Some(target) = navs.pop() else { panic!("no target found") };
500-
assert_eq!(target.name, SmolStr::new_inline("Range"));
520+
"#
521+
);
501522
}
502523

503524
#[test]

0 commit comments

Comments
 (0)