Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: goto definition on range operators #18362

Merged
merged 4 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion crates/ide-db/src/famous_defs.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -102,6 +102,14 @@ impl FamousDefs<'_, '_> {
self.find_trait("core:ops:Drop")
}

pub fn core_ops_Range(&self) -> Option<Struct> {
self.find_struct("core:ops:Range")
}

pub fn core_ops_RangeInclusive(&self) -> Option<Struct> {
self.find_struct("core:ops:RangeInclusive")
}

pub fn core_marker_Copy(&self) -> Option<Trait> {
self.find_trait("core:marker:Copy")
}
Expand Down Expand Up @@ -137,6 +145,13 @@ impl FamousDefs<'_, '_> {
.flatten()
}

fn find_struct(&self, path: &str) -> Option<Struct> {
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<Trait> {
match self.find_def(path)? {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
Expand Down
55 changes: 52 additions & 3 deletions crates/ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ 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},
helpers::pick_best_token,
RootDatabase, SymbolKind,
};
use itertools::Itertools;

use ide_db::famous_defs::FamousDefs;
use span::{Edition, FileId};
use syntax::{
ast::{self, HasLoopBody},
Expand Down Expand Up @@ -41,6 +41,22 @@ pub(crate) fn goto_definition(
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
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 {
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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(
Expand Down
Loading