Unnamed repository; edit this file 'description' to name the repository.
resolve range patterns to the their struct types
Duncan Proctor 2024-10-22
parent 2f6923b · commit 271f64f
-rw-r--r--crates/hir/src/semantics.rs8
-rw-r--r--crates/hir/src/source_analyzer.rs20
-rw-r--r--crates/ide-db/src/defs.rs12
-rw-r--r--crates/ide/src/goto_definition.rs109
4 files changed, 141 insertions, 8 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index fd3172a61a..28f1895fbf 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -203,6 +203,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
}
+ pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
+ self.imp.resolve_range_pat(range_pat).map(Struct::from)
+ }
+
pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
self.imp.resolve_range_expr(range_expr).map(Struct::from)
}
@@ -1361,6 +1365,10 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
+ fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
+ self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
+ }
+
fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index be0e57b0b1..1e28990f43 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -348,6 +348,26 @@ impl SourceAnalyzer {
}
}
+ pub(crate) fn resolve_range_pat(
+ &self,
+ db: &dyn HirDatabase,
+ range_pat: &ast::RangePat,
+ ) -> Option<StructId> {
+ let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
+ (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
+ (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
+ (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
+ (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
+ (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+
+ (RangeOp::Exclusive, None, None) => return None,
+ (RangeOp::Inclusive, None, None) => return None,
+ (RangeOp::Inclusive, Some(_), None) => return None,
+ };
+ let s = self.resolver.resolve_known_struct(db.upcast(), &path);
+ return s;
+ }
+
pub(crate) fn resolve_range_expr(
&self,
db: &dyn HirDatabase,
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index a253e086f8..48daabbf37 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -318,7 +318,8 @@ impl IdentClass {
.map(IdentClass::NameClass)
.or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
},
- ast::RangeExpr(range_expr) => OperatorClass::classify_range(sema, &range_expr).map(IdentClass::Operator),
+ ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
+ ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
@@ -558,7 +559,14 @@ pub enum OperatorClass {
}
impl OperatorClass {
- pub fn classify_range(
+ pub fn classify_range_pat(
+ sema: &Semantics<'_, RootDatabase>,
+ range_pat: &ast::RangePat,
+ ) -> Option<OperatorClass> {
+ sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
+ }
+
+ pub fn classify_range_expr(
sema: &Semantics<'_, RootDatabase>,
range_expr: &ast::RangeExpr,
) -> Option<OperatorClass> {
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 5c9ca0bc89..aa5c8d0041 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -98,6 +98,7 @@ pub(crate) fn goto_definition(
return Some(vec![x]);
}
}
+
Some(
IdentClass::classify_node(sema, &parent)?
.definitions()
@@ -460,7 +461,103 @@ mod tests {
}
#[test]
- fn goto_def_range() {
+ fn goto_def_pat_range_to_inclusive() {
+ check_name(
+ "RangeToInclusive",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ ..$0='z' => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_to() {
+ check_name(
+ "RangeTo",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ .$0.'z' => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range() {
+ check_name(
+ "Range",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'.$0.'z' => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_inclusive() {
+ check_name(
+ "RangeInclusive",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'..$0='z' => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_pat_range_from() {
+ check_name(
+ "RangeFrom",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'..$0 => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_range_pat_inclusive() {
+ check_name(
+ "RangeInclusive",
+ r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+ match ch {
+ 'a'..$0='z' => true,
+ _ => false
+ }
+}
+"#
+ );
+ }
+
+ #[test]
+ fn goto_def_expr_range() {
check_name(
"Range",
r#"
@@ -471,7 +568,7 @@ let x = 0.$0.1;
}
#[test]
- fn goto_def_range_from() {
+ fn goto_def_expr_range_from() {
check_name(
"RangeFrom",
r#"
@@ -484,7 +581,7 @@ fn f(arr: &[i32]) -> &[i32] {
}
#[test]
- fn goto_def_range_inclusive() {
+ fn goto_def_expr_range_inclusive() {
check_name(
"RangeInclusive",
r#"
@@ -495,7 +592,7 @@ let x = 0.$0.=1;
}
#[test]
- fn goto_def_range_full() {
+ fn goto_def_expr_range_full() {
check_name(
"RangeFull",
r#"
@@ -508,7 +605,7 @@ fn f(arr: &[i32]) -> &[i32] {
}
#[test]
- fn goto_def_range_to() {
+ fn goto_def_expr_range_to() {
check_name(
"RangeTo",
r#"
@@ -521,7 +618,7 @@ fn f(arr: &[i32]) -> &[i32] {
}
#[test]
- fn goto_def_range_to_inclusive() {
+ fn goto_def_expr_range_to_inclusive() {
check_name(
"RangeToInclusive",
r#"