about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-22 12:24:25 +0000
committerbors <bors@rust-lang.org>2024-10-22 12:24:25 +0000
commit408f924758e554609f2d589cd58691107a302be9 (patch)
tree5dec4a23bd8ae4d31e6337d42c493e3577bd33d3
parent7cad4da1ab1f47a4b4a1f028946d7147eae9861a (diff)
parent273d9d74f92f2c8d633ca120973cc20b31450979 (diff)
downloadrust-408f924758e554609f2d589cd58691107a302be9.tar.gz
rust-408f924758e554609f2d589cd58691107a302be9.zip
Auto merge of #18370 - duncpro:goto-def-ranges, r=Veykril
feat: resolve range patterns to their structs

Closes #18367
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs93
4 files changed, 124 insertions, 8 deletions
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 2716a10343b..d0e45f530bc 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -203,6 +203,10 @@ impl<DB: HirDatabase> Semantics<'_, 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)
     }
@@ -1367,6 +1371,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/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index be0e57b0b1d..9d32229e8f7 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -348,6 +348,25 @@ 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,
+        };
+        self.resolver.resolve_known_struct(db.upcast(), &path)
+    }
+
     pub(crate) fn resolve_range_expr(
         &self,
         db: &dyn HirDatabase,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index bc291e966bc..fdac4dd2efb 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -330,7 +330,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),
@@ -570,7 +571,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/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index ae3ef3e4437..1d42a66995b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/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,87 @@ 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_expr_range() {
         check_name(
             "Range",
             r#"
@@ -471,7 +552,7 @@ let x = 0.$0.1;
     }
 
     #[test]
-    fn goto_def_range_from() {
+    fn goto_def_expr_range_from() {
         check_name(
             "RangeFrom",
             r#"
@@ -484,7 +565,7 @@ fn f(arr: &[i32]) -> &[i32] {
     }
 
     #[test]
-    fn goto_def_range_inclusive() {
+    fn goto_def_expr_range_inclusive() {
         check_name(
             "RangeInclusive",
             r#"
@@ -495,7 +576,7 @@ let x = 0.$0.=1;
     }
 
     #[test]
-    fn goto_def_range_full() {
+    fn goto_def_expr_range_full() {
         check_name(
             "RangeFull",
             r#"
@@ -508,7 +589,7 @@ fn f(arr: &[i32]) -> &[i32] {
     }
 
     #[test]
-    fn goto_def_range_to() {
+    fn goto_def_expr_range_to() {
         check_name(
             "RangeTo",
             r#"
@@ -521,7 +602,7 @@ fn f(arr: &[i32]) -> &[i32] {
     }
 
     #[test]
-    fn goto_def_range_to_inclusive() {
+    fn goto_def_expr_range_to_inclusive() {
         check_name(
             "RangeToInclusive",
             r#"