diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 2716a10343..d0e45f530b 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -203,6 +203,10 @@ impl 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 { + self.imp.resolve_range_pat(range_pat).map(Struct::from) + } + pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option { 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 { + self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat) + } + fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option { 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..9d32229e8f 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/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 { + 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/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index bc291e966b..fdac4dd2ef 100644 --- a/crates/ide-db/src/defs.rs +++ b/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 { + sema.resolve_range_pat(range_pat).map(OperatorClass::Range) + } + + pub fn classify_range_expr( sema: &Semantics<'_, RootDatabase>, range_expr: &ast::RangeExpr, ) -> Option { diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index ae3ef3e443..1d42a66995 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,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#"