diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs index ba6e50abf6..9b4273ab10 100644 --- a/crates/ide-db/src/famous_defs.rs +++ b/crates/ide-db/src/famous_defs.rs @@ -1,7 +1,7 @@ //! See [`FamousDefs`]. use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}; -use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait}; +use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Struct, Trait}; use crate::RootDatabase; @@ -102,6 +102,14 @@ impl FamousDefs<'_, '_> { self.find_trait("core:ops:Drop") } + pub fn core_ops_Range(&self) -> Option { + self.find_struct("core:ops:Range") + } + + pub fn core_ops_RangeInclusive(&self) -> Option { + self.find_struct("core:ops:RangeInclusive") + } + pub fn core_marker_Copy(&self) -> Option { self.find_trait("core:marker:Copy") } @@ -137,6 +145,13 @@ impl FamousDefs<'_, '_> { .flatten() } + fn find_struct(&self, path: &str) -> Option { + match self.find_def(path)? { + hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(it))) => Some(it), + _ => None, + } + } + fn find_trait(&self, path: &str) -> Option { match self.find_def(path)? { hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index c61b2ba84f..3ac7cc823e 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -5,7 +5,7 @@ use crate::{ navigation_target::{self, ToNav}, FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult, }; -use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics}; +use hir::{Adt, AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics}; use ide_db::{ base_db::{AnchoredPath, FileLoader, SourceDatabase}, defs::{Definition, IdentClass}, @@ -13,7 +13,7 @@ use ide_db::{ RootDatabase, SymbolKind, }; use itertools::Itertools; - +use ide_db::famous_defs::FamousDefs; use span::{Edition, FileId}; use syntax::{ ast::{self, HasLoopBody}, @@ -41,6 +41,22 @@ pub(crate) fn goto_definition( ) -> Option>> { let sema = &Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); + + if let syntax::TokenAtOffset::Single(tok) = file.token_at_offset(offset) { + if let Some(module) = sema.file_to_module_def(file_id) { + let famous_defs = FamousDefs(sema, module.krate()); + let maybe_famous_struct = match tok.kind() { + T![..] => famous_defs.core_ops_Range(), + T![..=] => famous_defs.core_ops_RangeInclusive(), + _ => None + }; + if let Some(fstruct) = maybe_famous_struct { + let target = def_to_nav(db, Definition::Adt(Adt::Struct(fstruct))); + return Some(RangeInfo::new(tok.text_range(), target)); + } + } + } + let edition = sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { @@ -420,7 +436,7 @@ fn expr_to_nav( mod tests { use ide_db::FileRange; use itertools::Itertools; - + use syntax::SmolStr; use crate::fixture; #[track_caller] @@ -450,6 +466,39 @@ mod tests { assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } + + #[test] + fn goto_def_range_inclusive() { + let ra_fixture = r#" +//- minicore: range +fn f(a: usize, b: usize) { + for _ in a..$0=b { + + } +} +"#; + let (analysis, position, _) = fixture::annotations(ra_fixture); + let mut navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let Some(target) = navs.pop() else { panic!("no target found") }; + assert_eq!(target.name, SmolStr::new_inline("RangeInclusive")); + } + + #[test] + fn goto_def_range_half_open() { + let ra_fixture = r#" +//- minicore: range +fn f(a: usize, b: usize) { + for _ in a.$0.b { + + } +} +"#; + let (analysis, position, _) = fixture::annotations(ra_fixture); + let mut navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let Some(target) = navs.pop() else { panic!("no target found") }; + assert_eq!(target.name, SmolStr::new_inline("Range")); + } + #[test] fn goto_def_in_included_file() { check(