Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/goto_definition.rs')
| -rw-r--r-- | crates/ide/src/goto_definition.rs | 268 |
1 files changed, 245 insertions, 23 deletions
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 60a904233a..b894e85752 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -1,28 +1,28 @@ use std::{iter, mem::discriminant}; use crate::{ + FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult, doc_links::token_as_doc_comment, navigation_target::{self, ToNav}, - FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult, }; use hir::{ - sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt, - ModuleDef, Semantics, + AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym, }; use ide_db::{ - base_db::{AnchoredPath, FileLoader, SourceDatabase}, + RootDatabase, SymbolKind, + base_db::{AnchoredPath, SourceDatabase}, defs::{Definition, IdentClass}, famous_defs::FamousDefs, helpers::pick_best_token, - RootDatabase, SymbolKind, }; use itertools::Itertools; use span::{Edition, FileId}; use syntax::{ - ast::{self, HasLoopBody}, - match_ast, AstNode, AstToken, + AstNode, AstToken, SyntaxKind::*, - SyntaxNode, SyntaxToken, TextRange, T, + SyntaxNode, SyntaxToken, T, TextRange, + ast::{self, HasLoopBody}, + match_ast, }; // Feature: Go to Definition @@ -43,7 +43,7 @@ pub(crate) fn goto_definition( let sema = &Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); 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(db)).unwrap_or(Edition::CURRENT); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT | INT_NUMBER @@ -91,16 +91,19 @@ pub(crate) fn goto_definition( .descend_into_macros_no_opaque(original_token.clone()) .into_iter() .filter_map(|token| { - let parent = token.parent()?; + let parent = token.value.parent()?; - if let Some(token) = ast::String::cast(token.clone()) { - if let Some(x) = try_lookup_include_path(sema, token, file_id) { + let token_file_id = token.file_id; + if let Some(token) = ast::String::cast(token.value.clone()) { + if let Some(x) = + try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id) + { return Some(vec![x]); } } if ast::TokenTree::can_cast(parent.kind()) { - if let Some(x) = try_lookup_macro_def_in_macro_use(sema, token) { + if let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) { return Some(vec![x]); } } @@ -204,20 +207,22 @@ fn find_definition_for_known_blanket_dual_impls( fn try_lookup_include_path( sema: &Semantics<'_, RootDatabase>, - token: ast::String, + token: InFile<ast::String>, file_id: FileId, ) -> Option<NavigationTarget> { - let file = sema.hir_file_for(&token.syntax().parent()?).macro_file()?; + let file = token.file_id.macro_file()?; + + // Check that we are in the eager argument expansion of an include macro + // that is we are the string input of it if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file()) - // Check that we are in the eager argument expansion of an include macro .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none()) { return None; } - let path = token.value().ok()?; + let path = token.value.value().ok()?; let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?; - let size = sema.db.file_text(file_id).len().try_into().ok()?; + let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?; Some(NavigationTarget { file_id, full_range: TextRange::new(0.into(), size), @@ -358,7 +363,7 @@ fn nav_for_exit_points( if let Some(FileRange { file_id, range }) = focus_frange { let contains_frange = |nav: &NavigationTarget| { - nav.file_id == file_id && nav.full_range.contains_range(range) + nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range) }; if let Some(def_site) = nav.def_site.as_mut() { @@ -2047,7 +2052,10 @@ fn main() { ); } + // macros in this position are not yet supported #[test] + // FIXME + #[should_panic] fn goto_doc_include_str() { check( r#" @@ -2190,8 +2198,8 @@ where T : Bound struct A; impl Bound for A{} fn f() { - let gen = Gen::<A>(A); - gen.g$0(); + let g = Gen::<A>(A); + g.g$0(); } "#, ); @@ -2216,8 +2224,8 @@ where T : Bound struct A; impl Bound for A{} fn f() { - let gen = Gen::<A>(A); - gen.g$0(); + let g = Gen::<A>(A); + g.g$0(); } "#, ); @@ -3324,4 +3332,218 @@ fn main() { "#, ); } + + #[test] + fn struct_shadow_by_module() { + check( + r#" +mod foo { + pub mod bar { + // ^^^ + pub type baz = usize; + } +} +struct bar; +fn main() { + use foo::bar; + let x: ba$0r::baz = 5; + +} +"#, + ); + } + + #[test] + fn type_alias_shadow_by_module() { + check( + r#" +mod foo { + pub mod bar { + // ^^^ + pub fn baz() {} + } +} + +trait Qux {} + +fn item<bar: Qux>() { + use foo::bar; + ba$0r::baz(); +} +} +"#, + ); + + check( + r#" +mod foo { + pub mod bar { + // ^^^ + pub fn baz() {} + } +} + +fn item<bar>(x: bar) { + use foo::bar; + let x: bar$0 = x; +} +"#, + ); + } + + #[test] + fn trait_shadow_by_module() { + check( + r#" +pub mod foo { + pub mod Bar {} + // ^^^ +} + +trait Bar {} + +fn main() { + use foo::Bar; + fn f<Qux: B$0ar>() {} +} + "#, + ); + } + + #[test] + fn const_shadow_by_module() { + check( + r#" +pub mod foo { + pub struct u8 {} + pub mod bar { + pub mod u8 {} + } +} + +fn main() { + use foo::u8; + { + use foo::bar::u8; + + fn f1<const N: u$08>() {} + } + fn f2<const N: u8>() {} +} +"#, + ); + + check( + r#" +pub mod foo { + pub struct u8 {} + // ^^ + pub mod bar { + pub mod u8 {} + } +} + +fn main() { + use foo::u8; + { + use foo::bar::u8; + + fn f1<const N: u8>() {} + } + fn f2<const N: u$08>() {} +} +"#, + ); + + check( + r#" +pub mod foo { + pub struct buz {} + pub mod bar { + pub mod buz {} + // ^^^ + } +} + +fn main() { + use foo::buz; + { + use foo::bar::buz; + + fn f1<const N: buz$0>() {} + } +} +"#, + ); + } + + #[test] + fn offset_of() { + check( + r#" +//- minicore: offset_of +struct Foo { + field: i32, + // ^^^^^ +} + +fn foo() { + let _ = core::mem::offset_of!(Foo, fiel$0d); +} + "#, + ); + + check( + r#" +//- minicore: offset_of +struct Bar(Foo); +struct Foo { + field: i32, + // ^^^^^ +} + +fn foo() { + let _ = core::mem::offset_of!(Bar, 0.fiel$0d); +} + "#, + ); + + check( + r#" +//- minicore: offset_of +struct Bar(Baz); +enum Baz { + Abc(Foo), + None, +} +struct Foo { + field: i32, + // ^^^^^ +} + +fn foo() { + let _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d); +} + "#, + ); + + check( + r#" +//- minicore: offset_of +struct Bar(Baz); +enum Baz { + Abc(Foo), + // ^^^ + None, +} +struct Foo { + field: i32, +} + +fn foo() { + let _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field); +} + "#, + ); + } } |