mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
GotoDefinition on a Range or InclusiveRange operator will link to the struct definition
This commit is contained in:
parent
b0b5d38768
commit
3bc6e27993
2 changed files with 68 additions and 4 deletions
|
@ -1,7 +1,7 @@
|
||||||
//! See [`FamousDefs`].
|
//! See [`FamousDefs`].
|
||||||
|
|
||||||
use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
|
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;
|
use crate::RootDatabase;
|
||||||
|
|
||||||
|
@ -102,6 +102,14 @@ impl FamousDefs<'_, '_> {
|
||||||
self.find_trait("core:ops:Drop")
|
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> {
|
pub fn core_marker_Copy(&self) -> Option<Trait> {
|
||||||
self.find_trait("core:marker:Copy")
|
self.find_trait("core:marker:Copy")
|
||||||
}
|
}
|
||||||
|
@ -137,6 +145,13 @@ impl FamousDefs<'_, '_> {
|
||||||
.flatten()
|
.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> {
|
fn find_trait(&self, path: &str) -> Option<Trait> {
|
||||||
match self.find_def(path)? {
|
match self.find_def(path)? {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
navigation_target::{self, ToNav},
|
navigation_target::{self, ToNav},
|
||||||
FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
|
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::{
|
use ide_db::{
|
||||||
base_db::{AnchoredPath, FileLoader, SourceDatabase},
|
base_db::{AnchoredPath, FileLoader, SourceDatabase},
|
||||||
defs::{Definition, IdentClass},
|
defs::{Definition, IdentClass},
|
||||||
|
@ -13,7 +13,7 @@ use ide_db::{
|
||||||
RootDatabase, SymbolKind,
|
RootDatabase, SymbolKind,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use ide_db::famous_defs::FamousDefs;
|
||||||
use span::{Edition, FileId};
|
use span::{Edition, FileId};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasLoopBody},
|
ast::{self, HasLoopBody},
|
||||||
|
@ -41,6 +41,22 @@ pub(crate) fn goto_definition(
|
||||||
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
||||||
let sema = &Semantics::new(db);
|
let sema = &Semantics::new(db);
|
||||||
let file = sema.parse_guess_edition(file_id).syntax().clone();
|
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 =
|
let edition =
|
||||||
sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
|
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 {
|
let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
|
||||||
|
@ -420,7 +436,7 @@ fn expr_to_nav(
|
||||||
mod tests {
|
mod tests {
|
||||||
use ide_db::FileRange;
|
use ide_db::FileRange;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use syntax::SmolStr;
|
||||||
use crate::fixture;
|
use crate::fixture;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -450,6 +466,39 @@ mod tests {
|
||||||
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
|
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]
|
#[test]
|
||||||
fn goto_def_in_included_file() {
|
fn goto_def_in_included_file() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue