rust/crates/ide/src/goto_definition.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2033 lines
31 KiB
Rust
Raw Normal View History

use std::mem::discriminant;
use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav};
2022-06-15 10:13:15 -05:00
use hir::{AsAssocItem, AssocItem, Semantics};
2020-08-13 09:39:16 -05:00
use ide_db::{
base_db::{AnchoredPath, FileId, FileLoader},
defs::{Definition, IdentClass},
2021-09-22 10:05:54 -05:00
helpers::pick_best_token,
RootDatabase,
2020-03-03 11:54:39 -06:00
};
use itertools::Itertools;
2021-09-22 10:05:54 -05:00
use syntax::{ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, T};
2019-01-08 13:33:36 -06:00
2020-05-31 02:45:41 -05:00
// Feature: Go to Definition
2020-05-30 18:54:54 -05:00
//
// Navigates to the definition of an identifier.
//
2022-05-27 08:47:31 -05:00
// For outline modules, this will navigate to the source file of the module.
//
2020-05-30 18:54:54 -05:00
// |===
// | Editor | Shortcut
//
// | VS Code | kbd:[F12]
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
2019-01-08 16:38:51 -06:00
pub(crate) fn goto_definition(
2019-01-08 13:33:36 -06:00
db: &RootDatabase,
position: FilePosition,
2019-01-15 12:02:42 -06:00
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
let sema = &Semantics::new(db);
let file = sema.parse(position.file_id).syntax().clone();
let original_token =
pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
IDENT
| INT_NUMBER
| LIFETIME_IDENT
| T![self]
| T![super]
| T![crate]
| T![Self]
| COMMENT => 4,
// index and prefix ops
T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
kind if kind.is_keyword() => 2,
T!['('] | T![')'] => 2,
kind if kind.is_trivia() => 0,
_ => 1,
})?;
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
return doc_comment.get_definition_with_descend_at(
sema,
position.offset,
|def, _, link_range| {
let nav = def.try_to_nav(db)?;
Some(RangeInfo::new(link_range, vec![nav]))
},
);
2020-12-19 07:12:51 -06:00
}
let navs = sema
.descend_into_macros(original_token.clone())
.into_iter()
.filter_map(|token| {
let parent = token.parent()?;
2021-10-09 20:50:51 -05:00
if let Some(tt) = ast::TokenTree::cast(parent) {
if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), position.file_id)
2021-09-22 10:05:54 -05:00
{
return Some(vec![x]);
}
2021-09-22 03:07:26 -05:00
}
2021-09-22 10:05:54 -05:00
Some(
IdentClass::classify_token(sema, &token)?
.definitions()
2021-09-22 10:05:54 -05:00
.into_iter()
.flat_map(|def| {
2022-06-24 06:11:35 -05:00
try_filter_trait_item_definition(sema, &def)
2021-09-22 10:05:54 -05:00
.unwrap_or_else(|| def_to_nav(sema.db, def))
})
.collect(),
2021-09-22 10:05:54 -05:00
)
})
.flatten()
.unique()
.collect::<Vec<NavigationTarget>>();
Some(RangeInfo::new(original_token.text_range(), navs))
}
2021-09-22 10:05:54 -05:00
fn try_lookup_include_path(
2022-07-20 08:02:08 -05:00
sema: &Semantics<'_, RootDatabase>,
tt: ast::TokenTree,
token: SyntaxToken,
file_id: FileId,
) -> Option<NavigationTarget> {
2021-10-09 20:50:51 -05:00
let token = ast::String::cast(token)?;
2021-09-22 10:05:54 -05:00
let path = token.value()?.into_owned();
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
let name = macro_call.path()?.segment()?.name_ref()?;
if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
return None;
}
2022-10-06 01:10:28 -05:00
// Ignore non-built-in macros to account for shadowing
if let Some(it) = sema.resolve_macro_call(&macro_call) {
if !matches!(it.kind(sema.db), hir::MacroKind::BuiltIn) {
return None;
}
}
2021-09-22 10:05:54 -05:00
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()?;
Some(NavigationTarget {
2021-09-22 10:05:54 -05:00
file_id,
full_range: TextRange::new(0.into(), size),
name: path.into(),
focus_range: None,
kind: None,
container_name: None,
description: None,
docs: None,
})
}
2022-06-15 10:13:15 -05:00
/// finds the trait definition of an impl'd item, except function
/// e.g.
/// ```rust
2022-06-15 10:13:15 -05:00
/// trait A { type a; }
/// struct S;
2022-06-15 10:13:15 -05:00
/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait
/// ```
2022-06-15 10:13:15 -05:00
fn try_filter_trait_item_definition(
2022-07-20 08:02:08 -05:00
sema: &Semantics<'_, RootDatabase>,
def: &Definition,
) -> Option<Vec<NavigationTarget>> {
2022-06-15 10:13:15 -05:00
let db = sema.db;
let assoc = def.as_assoc_item(db)?;
2022-06-15 10:13:15 -05:00
match assoc {
2022-06-24 06:11:35 -05:00
AssocItem::Function(..) => None,
2022-06-15 10:13:15 -05:00
AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
let imp = match assoc.container(db) {
hir::AssocItemContainer::Impl(imp) => imp,
_ => return None,
};
let trait_ = imp.trait_(db)?;
let name = def.name(db)?;
2022-06-26 09:48:26 -05:00
let discri_value = discriminant(&assoc);
2022-06-15 10:13:15 -05:00
trait_
.items(db)
.iter()
2022-06-26 09:48:26 -05:00
.filter(|itm| discriminant(*itm) == discri_value)
2022-06-15 10:13:15 -05:00
.find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
.map(|it| vec![it])
}
}
}
fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec<NavigationTarget> {
def.try_to_nav(db).map(|it| vec![it]).unwrap_or_default()
}
2019-01-08 13:33:36 -06:00
#[cfg(test)]
mod tests {
2020-10-24 03:39:57 -05:00
use ide_db::base_db::FileRange;
use itertools::Itertools;
2020-06-30 06:03:08 -05:00
2020-10-02 10:34:31 -05:00
use crate::fixture;
2020-06-30 06:03:08 -05:00
#[track_caller]
2020-06-30 06:03:08 -05:00
fn check(ra_fixture: &str) {
let (analysis, position, expected) = fixture::annotations(ra_fixture);
let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
let navs = navs
.into_iter()
.map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
.sorted_by_key(cmp)
.collect::<Vec<_>>();
let expected = expected
.into_iter()
.map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
.sorted_by_key(cmp)
.collect::<Vec<_>>();
assert_eq!(expected, navs);
}
fn check_unresolved(ra_fixture: &str) {
let (analysis, position) = fixture::position(ra_fixture);
let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
}
2022-06-26 09:48:26 -05:00
#[test]
fn goto_def_if_items_same_name() {
check(
r#"
trait Trait {
type A;
const A: i32;
//^
}
struct T;
impl Trait for T {
type A = i32;
const A$0: i32 = -9;
}"#,
);
}
#[test]
fn goto_def_in_mac_call_in_attr_invoc() {
check(
r#"
//- proc_macros: identity
pub struct Struct {
// ^^^^^^
field: i32,
}
macro_rules! identity {
($($tt:tt)*) => {$($tt)*};
}
#[proc_macros::identity]
fn function() {
identity!(Struct$0 { field: 0 });
}
"#,
)
}
#[test]
fn goto_def_for_extern_crate() {
check(
r#"
2021-01-22 06:13:18 -06:00
//- /main.rs crate:main deps:std
extern crate std$0;
//- /std/lib.rs crate:std
// empty
//^file
2021-01-22 06:13:18 -06:00
"#,
)
}
#[test]
fn goto_def_for_renamed_extern_crate() {
check(
r#"
2021-01-22 06:13:18 -06:00
//- /main.rs crate:main deps:std
extern crate std as abc$0;
//- /std/lib.rs crate:std
// empty
//^file
2021-01-22 06:13:18 -06:00
"#,
)
}
2019-01-08 13:33:36 -06:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_in_items() {
check(
r#"
struct Foo;
2020-06-30 06:03:08 -05:00
//^^^
2021-01-06 14:15:48 -06:00
enum E { X(Foo$0) }
"#,
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_at_start_of_item() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
//^^^
2021-01-06 14:15:48 -06:00
enum E { X($0Foo) }
2020-06-30 06:03:08 -05:00
"#,
);
}
#[test]
fn goto_definition_resolves_correct_name() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
use a::Foo;
mod a;
mod b;
2021-01-06 14:15:48 -06:00
enum E { X(Foo$0) }
2019-12-18 07:52:58 -06:00
2020-06-30 06:03:08 -05:00
//- /a.rs
pub struct Foo;
//^^^
2020-06-30 06:03:08 -05:00
//- /b.rs
pub struct Foo;
2020-06-30 06:03:08 -05:00
"#,
2019-01-08 13:33:36 -06:00
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_module_declaration() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
2021-01-06 14:15:48 -06:00
mod $0foo;
2019-12-18 07:52:58 -06:00
//- /foo.rs
// empty
//^file
"#,
2019-01-08 13:33:36 -06:00
);
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
2021-01-06 14:15:48 -06:00
mod $0foo;
2019-12-18 07:52:58 -06:00
//- /foo/mod.rs
// empty
//^file
"#,
2019-01-08 13:33:36 -06:00
);
}
2019-04-24 15:16:50 -05:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_macros() {
2020-06-30 06:03:08 -05:00
check(
r#"
macro_rules! foo { () => { () } }
//^^^
fn bar() {
2021-01-06 14:15:48 -06:00
$0foo!();
2020-06-30 06:03:08 -05:00
}
"#,
2019-04-24 15:16:50 -05:00
);
}
2019-06-01 06:34:19 -05:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_macros_from_other_crates() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs crate:main deps:foo
2020-06-30 06:03:08 -05:00
use foo::foo;
fn bar() {
2021-01-06 14:15:48 -06:00
$0foo!();
2020-06-30 06:03:08 -05:00
}
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules! foo { () => { () } }
2020-06-30 06:03:08 -05:00
//^^^
"#,
2019-06-01 06:34:19 -05:00
);
}
2019-10-31 12:29:56 -05:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_macros_in_use_tree() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs crate:main deps:foo
2021-01-06 14:15:48 -06:00
use foo::foo$0;
2019-10-31 12:29:56 -05:00
//- /foo/lib.rs crate:foo
2020-06-30 06:03:08 -05:00
#[macro_export]
macro_rules! foo { () => { () } }
//^^^
"#,
2019-10-31 12:29:56 -05:00
);
}
2019-11-03 11:49:49 -06:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_macro_defined_fn_with_arg() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
macro_rules! define_fn {
($name:ident) => (fn $name() {})
}
2019-11-03 11:49:49 -06:00
define_fn!(foo);
2020-06-30 06:03:08 -05:00
//^^^
2019-11-03 11:49:49 -06:00
fn bar() {
2021-01-06 14:15:48 -06:00
$0foo();
}
"#,
2019-11-03 11:49:49 -06:00
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_macro_defined_fn_no_arg() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
macro_rules! define_fn {
() => (fn foo() {})
}
2019-11-03 11:49:49 -06:00
2020-06-30 06:03:08 -05:00
define_fn!();
//^^^^^^^^^^^^^
2019-11-03 11:49:49 -06:00
fn bar() {
2021-01-06 14:15:48 -06:00
$0foo();
}
"#,
2019-11-03 11:49:49 -06:00
);
}
#[test]
fn goto_definition_works_for_macro_inside_pattern() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
macro_rules! foo {() => {0}}
//^^^
fn bar() {
match (0,1) {
2021-01-06 14:15:48 -06:00
($0foo!(), _) => {}
2020-06-30 06:03:08 -05:00
}
}
"#,
);
}
#[test]
fn goto_definition_works_for_macro_inside_match_arm_lhs() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
macro_rules! foo {() => {0}}
//^^^
fn bar() {
match 0 {
2021-01-06 14:15:48 -06:00
$0foo!() => {}
2020-06-30 06:03:08 -05:00
}
}
"#,
);
}
#[test]
fn goto_def_for_use_alias() {
check(
r#"
2020-10-02 09:13:48 -05:00
//- /lib.rs crate:main deps:foo
2021-01-06 14:15:48 -06:00
use foo as bar$0;
2020-06-30 06:03:08 -05:00
2020-10-02 09:13:48 -05:00
//- /foo/lib.rs crate:foo
2020-06-30 06:03:08 -05:00
// empty
//^file
2020-06-30 06:03:08 -05:00
"#,
);
}
#[test]
fn goto_def_for_use_alias_foo_macro() {
check(
r#"
2020-10-02 09:13:48 -05:00
//- /lib.rs crate:main deps:foo
2021-01-06 14:15:48 -06:00
use foo::foo as bar$0;
2020-06-30 06:03:08 -05:00
2020-10-02 09:13:48 -05:00
//- /foo/lib.rs crate:foo
2020-06-30 06:03:08 -05:00
#[macro_export]
macro_rules! foo { () => { () } }
//^^^
"#,
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_methods() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
impl Foo {
fn frobnicate(&self) { }
//^^^^^^^^^^
}
2020-06-30 06:03:08 -05:00
fn bar(foo: &Foo) {
2021-01-06 14:15:48 -06:00
foo.frobnicate$0();
2020-06-30 06:03:08 -05:00
}
"#,
);
2019-01-25 11:32:34 -06:00
}
2019-01-25 11:32:34 -06:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_fields() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo {
spam: u32,
} //^^^^
2019-01-25 11:32:34 -06:00
2020-06-30 06:03:08 -05:00
fn bar(foo: &Foo) {
2021-01-06 14:15:48 -06:00
foo.spam$0;
2020-06-30 06:03:08 -05:00
}
"#,
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_record_fields() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
struct Foo {
spam: u32,
} //^^^^
2020-06-30 06:03:08 -05:00
fn bar() -> Foo {
Foo {
2021-01-06 14:15:48 -06:00
spam$0: 0,
2020-06-30 06:03:08 -05:00
}
}
"#,
);
}
#[test]
fn goto_def_for_record_pat_fields() {
2020-06-30 06:03:08 -05:00
check(
r#"
//- /lib.rs
struct Foo {
spam: u32,
} //^^^^
2020-06-30 06:03:08 -05:00
fn bar(foo: Foo) -> Foo {
2021-01-06 14:15:48 -06:00
let Foo { spam$0: _, } = foo
2020-06-30 06:03:08 -05:00
}
"#,
);
}
2019-10-31 09:13:52 -05:00
2020-03-25 07:53:15 -05:00
#[test]
fn goto_def_for_record_fields_macros() {
2020-06-30 06:03:08 -05:00
check(
2020-03-25 07:53:15 -05:00
r"
2020-06-30 06:03:08 -05:00
macro_rules! m { () => { 92 };}
struct Foo { spam: u32 }
//^^^^
2020-03-25 07:53:15 -05:00
2020-06-30 06:03:08 -05:00
fn bar() -> Foo {
2021-01-06 14:15:48 -06:00
Foo { spam$0: m!() }
2020-06-30 06:03:08 -05:00
}
",
2020-03-25 07:53:15 -05:00
);
}
2019-12-13 14:59:25 -06:00
#[test]
fn goto_for_tuple_fields() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo(u32);
//^^^
fn bar() {
let foo = Foo(0);
2021-01-06 14:15:48 -06:00
foo.$00;
2020-06-30 06:03:08 -05:00
}
"#,
2019-12-13 14:59:25 -06:00
);
}
2019-10-31 09:13:52 -05:00
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_ufcs_inherent_methods() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
impl Foo {
fn frobnicate() { }
} //^^^^^^^^^^
2019-10-31 09:13:52 -05:00
2020-06-30 06:03:08 -05:00
fn bar(foo: &Foo) {
2021-01-06 14:15:48 -06:00
Foo::frobnicate$0();
2020-06-30 06:03:08 -05:00
}
"#,
2019-10-31 09:13:52 -05:00
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_ufcs_trait_methods_through_traits() {
2020-06-30 06:03:08 -05:00
check(
r#"
trait Foo {
fn frobnicate();
} //^^^^^^^^^^
2019-10-31 09:13:52 -05:00
2020-06-30 06:03:08 -05:00
fn bar() {
2021-01-06 14:15:48 -06:00
Foo::frobnicate$0();
2020-06-30 06:03:08 -05:00
}
"#,
2019-10-31 09:13:52 -05:00
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_for_ufcs_trait_methods_through_self() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
trait Trait {
fn frobnicate();
} //^^^^^^^^^^
impl Trait for Foo {}
2019-10-31 09:13:52 -05:00
2020-06-30 06:03:08 -05:00
fn bar() {
2021-01-06 14:15:48 -06:00
Foo::frobnicate$0();
2020-06-30 06:03:08 -05:00
}
"#,
2019-10-31 09:13:52 -05:00
);
}
#[test]
fn goto_definition_on_self() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
impl Foo {
//^^^
pub fn new() -> Self {
2021-01-06 14:15:48 -06:00
Self$0 {}
2020-06-30 06:03:08 -05:00
}
}
"#,
);
check(
r#"
struct Foo;
impl Foo {
//^^^
2021-01-06 14:15:48 -06:00
pub fn new() -> Self$0 {
2020-06-30 06:03:08 -05:00
Self {}
}
}
"#,
);
check(
r#"
enum Foo { A }
impl Foo {
//^^^
2021-01-06 14:15:48 -06:00
pub fn new() -> Self$0 {
2020-06-30 06:03:08 -05:00
Foo::A
}
}
"#,
);
check(
r#"
enum Foo { A }
impl Foo {
//^^^
2021-01-06 14:15:48 -06:00
pub fn thing(a: &Self$0) {
2020-06-30 06:03:08 -05:00
}
}
"#,
);
}
#[test]
fn goto_definition_on_self_in_trait_impl() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
trait Make {
fn new() -> Self;
}
impl Make for Foo {
//^^^
fn new() -> Self {
2021-01-06 14:15:48 -06:00
Self$0 {}
2020-06-30 06:03:08 -05:00
}
}
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo;
trait Make {
fn new() -> Self;
}
impl Make for Foo {
//^^^
2021-01-06 14:15:48 -06:00
fn new() -> Self$0 {
2020-06-30 06:03:08 -05:00
Self {}
}
}
"#,
);
}
#[test]
2019-12-20 07:47:01 -06:00
fn goto_def_when_used_on_definition_name_itself() {
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
struct Foo$0 { value: u32 }
2020-06-30 06:03:08 -05:00
//^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2020-06-30 06:03:08 -05:00
struct Foo {
2021-01-06 14:15:48 -06:00
field$0: string,
2020-06-30 06:03:08 -05:00
} //^^^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
fn foo_test$0() { }
2020-06-30 06:03:08 -05:00
//^^^^^^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
enum Foo$0 { Variant }
2020-06-30 06:03:08 -05:00
//^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2020-06-30 06:03:08 -05:00
enum Foo {
Variant1,
2021-01-06 14:15:48 -06:00
Variant2$0,
2020-06-30 06:03:08 -05:00
//^^^^^^^^
Variant3,
}
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
static INNER$0: &str = "";
2020-06-30 06:03:08 -05:00
//^^^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
const INNER$0: &str = "";
2020-06-30 06:03:08 -05:00
//^^^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
type Thing$0 = Option<()>;
2020-06-30 06:03:08 -05:00
//^^^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
trait Foo$0 { }
2020-06-30 06:03:08 -05:00
//^^^
"#,
);
check(
r#"
trait Foo$0 = ;
//^^^
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
mod bar$0 { }
2020-06-30 06:03:08 -05:00
//^^^
"#,
);
}
2019-11-16 07:49:26 -06:00
#[test]
fn goto_from_macro() {
2020-06-30 06:03:08 -05:00
check(
r#"
macro_rules! id {
($($tt:tt)*) => { $($tt)* }
}
fn foo() {}
//^^^
id! {
fn bar() {
2021-01-06 14:15:48 -06:00
fo$0o();
2020-06-30 06:03:08 -05:00
}
}
mod confuse_index { fn foo(); }
"#,
2019-11-16 07:49:26 -06:00
);
}
#[test]
fn goto_through_format() {
2020-06-30 06:03:08 -05:00
check(
r#"
#[macro_export]
macro_rules! format {
($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
}
#[rustc_builtin_macro]
#[macro_export]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
}
pub mod __export {
pub use crate::format_args;
fn foo() {} // for index confusion
}
fn foo() -> i8 {}
//^^^
fn test() {
2021-01-06 14:15:48 -06:00
format!("{}", fo$0o())
2020-06-30 06:03:08 -05:00
}
"#,
);
}
2019-12-07 11:54:18 -06:00
2020-12-22 07:42:28 -06:00
#[test]
fn goto_through_included_file() {
check(
r#"
//- /main.rs
#[rustc_builtin_macro]
macro_rules! include {}
include!("foo.rs");
2020-12-22 07:42:28 -06:00
fn f() {
2021-01-06 14:15:48 -06:00
foo$0();
2020-12-22 07:42:28 -06:00
}
mod confuse_index {
pub fn foo() {}
}
//- /foo.rs
fn foo() {}
//^^^
2020-12-22 07:42:28 -06:00
"#,
);
}
#[test]
fn goto_through_included_file_struct_with_doc_comment() {
check(
r#"
//- /main.rs
#[rustc_builtin_macro]
macro_rules! include {}
include!("foo.rs");
fn f() {
let x = Foo$0;
}
mod confuse_index {
pub struct Foo;
}
//- /foo.rs
/// This is a doc comment
pub struct Foo;
//^^^
"#,
);
}
2019-12-07 11:54:18 -06:00
#[test]
fn goto_for_type_param() {
2020-06-30 06:03:08 -05:00
check(
r#"
2021-01-06 14:15:48 -06:00
struct Foo<T: Clone> { t: $0T }
2020-06-30 06:03:08 -05:00
//^
"#,
2019-12-07 11:54:18 -06:00
);
}
#[test]
fn goto_within_macro() {
2020-06-30 06:03:08 -05:00
check(
r#"
macro_rules! id {
($($tt:tt)*) => ($($tt)*)
}
fn foo() {
let x = 1;
2020-06-30 06:03:08 -05:00
//^
id!({
2021-01-06 14:15:48 -06:00
let y = $0x;
let z = y;
});
}
"#,
);
2020-06-30 06:03:08 -05:00
check(
r#"
macro_rules! id {
($($tt:tt)*) => ($($tt)*)
}
fn foo() {
let x = 1;
id!({
let y = x;
2020-06-30 06:03:08 -05:00
//^
2021-01-06 14:15:48 -06:00
let z = $0y;
});
}
"#,
);
}
2019-12-20 04:19:09 -06:00
#[test]
fn goto_def_in_local_fn() {
2020-06-30 06:03:08 -05:00
check(
r#"
fn main() {
fn foo() {
let x = 92;
//^
2021-01-06 14:15:48 -06:00
$0x;
2020-06-30 06:03:08 -05:00
}
}
"#,
2019-12-20 04:19:09 -06:00
);
}
2019-12-20 07:47:01 -06:00
2020-03-14 01:25:30 -05:00
#[test]
fn goto_def_in_local_macro() {
2020-06-30 06:03:08 -05:00
check(
r#"
fn bar() {
macro_rules! foo { () => { () } }
//^^^
2021-01-06 14:15:48 -06:00
$0foo!();
2020-06-30 06:03:08 -05:00
}
"#,
2020-03-14 01:25:30 -05:00
);
}
2019-12-20 07:47:01 -06:00
#[test]
fn goto_def_for_field_init_shorthand() {
2020-06-30 06:03:08 -05:00
check(
r#"
struct Foo { x: i32 }
//^
2020-06-30 06:03:08 -05:00
fn main() {
let x = 92;
//^
2021-01-06 14:15:48 -06:00
Foo { x$0 };
2020-06-30 06:03:08 -05:00
}
"#,
2019-12-20 07:47:01 -06:00
)
}
2020-06-06 14:16:59 -05:00
#[test]
fn goto_def_for_enum_variant_field() {
2020-06-30 06:03:08 -05:00
check(
r#"
enum Foo {
Bar { x: i32 }
//^
}
2020-06-30 06:03:08 -05:00
fn baz(foo: Foo) {
match foo {
2021-01-06 14:15:48 -06:00
Foo::Bar { x$0 } => x
//^
2020-06-30 06:03:08 -05:00
};
}
"#,
2020-06-06 14:16:59 -05:00
);
}
2020-06-10 12:11:47 -05:00
#[test]
fn goto_def_for_enum_variant_self_pattern_const() {
2020-06-30 06:03:08 -05:00
check(
r#"
enum Foo { Bar }
//^^^
impl Foo {
fn baz(self) {
2021-01-06 14:15:48 -06:00
match self { Self::Bar$0 => {} }
2020-06-30 06:03:08 -05:00
}
}
"#,
2020-06-10 12:11:47 -05:00
);
}
#[test]
fn goto_def_for_enum_variant_self_pattern_record() {
2020-06-30 06:03:08 -05:00
check(
r#"
enum Foo { Bar { val: i32 } }
//^^^
impl Foo {
fn baz(self) -> i32 {
2021-01-06 14:15:48 -06:00
match self { Self::Bar$0 { val } => {} }
2020-06-30 06:03:08 -05:00
}
}
"#,
2020-06-10 12:11:47 -05:00
);
}
#[test]
fn goto_def_for_enum_variant_self_expr_const() {
2020-06-30 06:03:08 -05:00
check(
r#"
enum Foo { Bar }
//^^^
impl Foo {
2021-01-06 14:15:48 -06:00
fn baz(self) { Self::Bar$0; }
2020-06-30 06:03:08 -05:00
}
"#,
2020-06-10 12:11:47 -05:00
);
}
#[test]
fn goto_def_for_enum_variant_self_expr_record() {
2020-06-30 06:03:08 -05:00
check(
r#"
enum Foo { Bar { val: i32 } }
//^^^
impl Foo {
2021-01-06 14:15:48 -06:00
fn baz(self) { Self::Bar$0 {val: 4}; }
2020-06-30 06:03:08 -05:00
}
"#,
2020-06-10 12:11:47 -05:00
);
}
#[test]
fn goto_def_for_type_alias_generic_parameter() {
check(
r#"
2021-01-06 14:15:48 -06:00
type Alias<T> = T$0;
//^
"#,
)
}
#[test]
fn goto_def_for_macro_container() {
check(
r#"
//- /lib.rs crate:main deps:foo
2021-01-06 14:15:48 -06:00
foo::module$0::mac!();
//- /foo/lib.rs crate:foo
pub mod module {
//^^^^^^
#[macro_export]
macro_rules! _mac { () => { () } }
pub use crate::_mac as mac;
}
"#,
);
}
#[test]
fn goto_def_for_assoc_ty_in_path() {
check(
r#"
trait Iterator {
type Item;
//^^^^
}
2021-01-06 14:15:48 -06:00
fn f() -> impl Iterator<Item$0 = u8> {}
"#,
);
}
#[test]
fn goto_def_for_super_assoc_ty_in_path() {
check(
r#"
trait Super {
type Item;
//^^^^
}
trait Sub: Super {}
fn f() -> impl Sub<Item$0 = u8> {}
"#,
);
}
#[test]
fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {
check(
r#"
mod bar {
pub struct Foo {}
//^^^
pub fn Foo() {}
}
fn baz() {
let _foo_enum: bar::Foo$0 = bar::Foo {};
}
"#,
)
}
#[test]
fn unknown_assoc_ty() {
check_unresolved(
r#"
trait Iterator { type Item; }
fn f() -> impl Iterator<Invalid$0 = u8> {}
"#,
)
}
#[test]
fn goto_def_for_assoc_ty_in_path_multiple() {
check(
r#"
trait Iterator {
type A;
//^
type B;
}
2021-01-06 14:15:48 -06:00
fn f() -> impl Iterator<A$0 = u8, B = ()> {}
"#,
);
check(
r#"
trait Iterator {
type A;
type B;
//^
}
2021-01-06 14:15:48 -06:00
fn f() -> impl Iterator<A = u8, B$0 = ()> {}
"#,
);
}
#[test]
fn goto_def_for_assoc_ty_ufcs() {
check(
r#"
trait Iterator {
type Item;
//^^^^
}
2021-01-06 14:15:48 -06:00
fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
"#,
);
}
#[test]
fn goto_def_for_assoc_ty_ufcs_multiple() {
check(
r#"
trait Iterator {
type A;
//^
type B;
}
2021-01-06 14:15:48 -06:00
fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
"#,
);
check(
r#"
trait Iterator {
type A;
type B;
//^
}
2021-01-06 14:15:48 -06:00
fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
"#,
);
}
#[test]
2020-11-28 15:50:59 -06:00
fn goto_self_param_ty_specified() {
check(
r#"
struct Foo {}
impl Foo {
2020-11-28 15:50:59 -06:00
fn bar(self: &Foo) {
//^^^^
2021-01-06 14:15:48 -06:00
let foo = sel$0f;
2020-11-28 15:50:59 -06:00
}
}"#,
)
}
#[test]
2020-11-28 15:50:59 -06:00
fn goto_self_param_on_decl() {
check(
r#"
struct Foo {}
impl Foo {
2021-01-06 14:15:48 -06:00
fn bar(&self$0) {
2020-11-28 15:50:59 -06:00
//^^^^
}
2020-12-16 14:35:15 -06:00
}"#,
)
}
#[test]
fn goto_lifetime_param_on_decl() {
check(
r#"
2021-01-06 14:15:48 -06:00
fn foo<'foobar$0>(_: &'foobar ()) {
2020-12-16 14:35:15 -06:00
//^^^^^^^
}"#,
)
}
#[test]
fn goto_lifetime_param_decl() {
check(
r#"
2021-01-06 14:15:48 -06:00
fn foo<'foobar>(_: &'foobar$0 ()) {
2020-12-16 14:35:15 -06:00
//^^^^^^^
}"#,
)
}
#[test]
fn goto_lifetime_param_decl_nested() {
check(
r#"
fn foo<'foobar>(_: &'foobar ()) {
2021-01-06 14:15:48 -06:00
fn foo<'foobar>(_: &'foobar$0 ()) {}
2020-12-16 14:35:15 -06:00
//^^^^^^^
2020-11-28 15:50:59 -06:00
}"#,
)
}
#[test]
fn goto_lifetime_hrtb() {
// FIXME: requires the HIR to somehow track these hrtb lifetimes
check_unresolved(
r#"
trait Foo<T> {}
2021-01-06 14:15:48 -06:00
fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
//^^
"#,
);
check_unresolved(
r#"
trait Foo<T> {}
2021-01-06 14:15:48 -06:00
fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
//^^
"#,
);
}
#[test]
fn goto_lifetime_hrtb_for_type() {
// FIXME: requires ForTypes to be implemented
check_unresolved(
r#"trait Foo<T> {}
2021-01-06 14:15:48 -06:00
fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
//^^
"#,
);
}
2020-12-23 10:15:01 -06:00
#[test]
fn goto_label() {
check(
r#"
fn foo<'foo>(_: &'foo ()) {
'foo: {
//^^^^
'bar: loop {
2021-01-06 14:15:48 -06:00
break 'foo$0;
2020-12-23 10:15:01 -06:00
}
}
2020-12-19 07:12:51 -06:00
}"#,
)
}
#[test]
fn goto_def_for_intra_doc_link_same_file() {
2020-12-19 07:12:51 -06:00
check(
r#"
/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
2020-12-19 07:12:51 -06:00
pub fn bar() { }
/// You might want to see [`std::fs::read()`] too.
pub fn foo() { }
//^^^
2020-12-23 10:15:01 -06:00
}"#,
)
}
#[test]
fn goto_def_for_intra_doc_link_inner() {
check(
r#"
//- /main.rs
mod m;
struct S;
//^
//- /m.rs
//! [`super::S$0`]
"#,
)
}
#[test]
fn goto_incomplete_field() {
check(
r#"
struct A { a: u32 }
//^
fn foo() { A { a$0: }; }
"#,
)
}
#[test]
fn goto_proc_macro() {
check(
r#"
//- /main.rs crate:main deps:mac
use mac::fn_macro;
fn_macro$0!();
//- /mac.rs crate:mac
#![crate_type="proc-macro"]
#[proc_macro]
fn fn_macro() {}
//^^^^^^^^
"#,
)
}
#[test]
fn goto_intra_doc_links() {
check(
r#"
pub mod theitem {
/// This is the item. Cool!
pub struct TheItem;
//^^^^^^^
}
/// Gives you a [`TheItem$0`].
///
/// [`TheItem`]: theitem::TheItem
pub fn gimme() -> theitem::TheItem {
theitem::TheItem
}
2021-04-10 16:12:02 -05:00
"#,
);
}
#[test]
fn goto_ident_from_pat_macro() {
check(
r#"
macro_rules! pat {
($name:ident) => { Enum::Variant1($name) }
}
enum Enum {
Variant1(u8),
Variant2,
}
fn f(e: Enum) {
match e {
pat!(bind) => {
//^^^^
bind$0
}
Enum::Variant2 => {}
}
}
"#,
);
}
#[test]
fn goto_include() {
check(
r#"
//- /main.rs
2022-10-06 01:10:28 -05:00
#[rustc_builtin_macro]
macro_rules! include_str {}
fn main() {
let str = include_str!("foo.txt$0");
}
//- /foo.txt
// empty
//^file
"#,
);
}
2022-10-06 01:10:28 -05:00
#[test]
fn goto_doc_include_str() {
check(
r#"
//- /main.rs
#[rustc_builtin_macro]
macro_rules! include_str {}
#[doc = include_str!("docs.md$0")]
struct Item;
//- /docs.md
// docs
//^file
"#,
);
}
2022-10-06 01:10:28 -05:00
#[test]
fn goto_shadow_include() {
check(
r#"
//- /main.rs
macro_rules! include {
("included.rs") => {}
}
include!("included.rs$0");
//- /included.rs
// empty
"#,
);
}
2022-06-15 10:13:15 -05:00
mod goto_impl_of_trait_fn {
use super::check;
#[test]
fn cursor_on_impl() {
check(
r#"
trait Twait {
fn a();
}
struct Stwuct;
impl Twait for Stwuct {
fn a$0();
2022-06-15 10:13:15 -05:00
//^
}
2022-06-15 10:13:15 -05:00
"#,
);
}
#[test]
fn method_call() {
check(
r#"
trait Twait {
fn a(&self);
}
struct Stwuct;
impl Twait for Stwuct {
fn a(&self){};
//^
}
fn f() {
let s = Stwuct;
s.a$0();
}
"#,
);
}
#[test]
fn path_call() {
check(
r#"
trait Twait {
fn a(&self);
}
struct Stwuct;
impl Twait for Stwuct {
fn a(&self){};
//^
}
fn f() {
let s = Stwuct;
Stwuct::a$0(&s);
}
"#,
);
}
#[test]
fn where_clause_can_work() {
check(
r#"
trait G {
fn g(&self);
}
trait Bound{}
trait EA{}
struct Gen<T>(T);
impl <T:EA> G for Gen<T> {
fn g(&self) {
}
}
impl <T> G for Gen<T>
where T : Bound
{
fn g(&self){
//^
}
}
struct A;
impl Bound for A{}
fn f() {
let gen = Gen::<A>(A);
gen.g$0();
}
"#,
);
}
2022-06-26 10:09:06 -05:00
#[test]
fn wc_case_is_ok() {
check(
r#"
trait G {
fn g(&self);
}
trait BParent{}
trait Bound: BParent{}
struct Gen<T>(T);
impl <T> G for Gen<T>
where T : Bound
{
fn g(&self){
//^
}
}
struct A;
impl Bound for A{}
fn f() {
let gen = Gen::<A>(A);
gen.g$0();
}
"#,
);
}
2022-06-23 07:49:05 -05:00
#[test]
fn method_call_defaulted() {
check(
r#"
trait Twait {
fn a(&self) {}
//^
}
struct Stwuct;
impl Twait for Stwuct {
}
fn f() {
let s = Stwuct;
s.a$0();
}
"#,
);
}
#[test]
fn method_call_on_generic() {
check(
r#"
trait Twait {
fn a(&self) {}
//^
}
fn f<T: Twait>(s: T) {
s.a$0();
}
"#,
);
}
}
#[test]
fn goto_def_of_trait_impl_const() {
check(
r#"
trait Twait {
const NOMS: bool;
// ^^^^
}
struct Stwuct;
impl Twait for Stwuct {
const NOMS$0: bool = true;
}
"#,
);
}
#[test]
fn goto_def_of_trait_impl_type_alias() {
check(
r#"
trait Twait {
type IsBad;
// ^^^^^
}
struct Stwuct;
impl Twait for Stwuct {
type IsBad$0 = !;
}
"#,
);
}
#[test]
fn goto_def_derive_input() {
check(
r#"
//- minicore:derive
#[rustc_builtin_macro]
pub macro Copy {}
// ^^^^
#[derive(Copy$0)]
struct Foo;
"#,
);
check(
r#"
//- minicore:derive
#[rustc_builtin_macro]
pub macro Copy {}
// ^^^^
#[cfg_attr(feature = "false", derive)]
#[derive(Copy$0)]
struct Foo;
"#,
);
check(
r#"
//- minicore:derive
mod foo {
#[rustc_builtin_macro]
pub macro Copy {}
// ^^^^
}
#[derive(foo::Copy$0)]
struct Foo;
"#,
);
check(
r#"
//- minicore:derive
mod foo {
// ^^^
#[rustc_builtin_macro]
pub macro Copy {}
}
#[derive(foo$0::Copy)]
struct Foo;
"#,
);
}
#[test]
fn goto_def_in_macro_multi() {
check(
r#"
struct Foo {
foo: ()
//^^^
}
macro_rules! foo {
($ident:ident) => {
fn $ident(Foo { $ident }: Foo) {}
}
}
foo!(foo$0);
//^^^
//^^^
"#,
);
check(
r#"
fn bar() {}
//^^^
struct bar;
//^^^
macro_rules! foo {
($ident:ident) => {
fn foo() {
let _: $ident = $ident;
}
}
}
foo!(bar$0);
"#,
);
}
#[test]
fn goto_await_poll() {
check(
r#"
//- minicore: future
struct MyFut;
impl core::future::Future for MyFut {
type Output = ();
fn poll(
//^^^^
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>
) -> std::task::Poll<Self::Output>
{
()
}
}
fn f() {
MyFut.await$0;
}
"#,
);
}
#[test]
fn goto_await_into_future_poll() {
check(
r#"
//- minicore: future
struct Futurable;
impl core::future::IntoFuture for Futurable {
type IntoFuture = MyFut;
}
struct MyFut;
impl core::future::Future for MyFut {
type Output = ();
fn poll(
//^^^^
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>
) -> std::task::Poll<Self::Output>
{
()
}
}
fn f() {
Futurable.await$0;
}
"#,
);
}
#[test]
fn goto_try_op() {
check(
r#"
//- minicore: try
struct Struct;
impl core::ops::Try for Struct {
fn branch(
//^^^^^^
self
) {}
}
fn f() {
Struct?$0;
}
"#,
);
}
#[test]
fn goto_index_op() {
check(
r#"
//- minicore: index
struct Struct;
impl core::ops::Index<usize> for Struct {
fn index(
//^^^^^
self
) {}
}
fn f() {
Struct[0]$0;
}
"#,
);
}
#[test]
fn goto_prefix_op() {
check(
r#"
//- minicore: deref
struct Struct;
impl core::ops::Deref for Struct {
fn deref(
//^^^^^
self
) {}
}
fn f() {
$0*Struct;
}
"#,
);
}
#[test]
fn goto_bin_op() {
check(
r#"
//- minicore: add
struct Struct;
impl core::ops::Add for Struct {
fn add(
//^^^
self
) {}
}
fn f() {
Struct +$0 Struct;
}
"#,
);
}
#[test]
fn goto_bin_op_multiple_impl() {
check(
r#"
//- minicore: add
struct S;
impl core::ops::Add for S {
fn add(
//^^^
) {}
}
impl core::ops::Add<usize> for S {
fn add(
) {}
}
fn f() {
S +$0 S
}
"#,
);
check(
r#"
//- minicore: add
struct S;
impl core::ops::Add for S {
fn add(
) {}
}
impl core::ops::Add<usize> for S {
fn add(
//^^^
) {}
}
fn f() {
S +$0 0usize
}
"#,
);
}
#[test]
fn path_call_multiple_trait_impl() {
check(
r#"
trait Trait<T> {
fn f(_: T);
}
impl Trait<i32> for usize {
fn f(_: i32) {}
//^
}
impl Trait<i64> for usize {
fn f(_: i64) {}
}
fn main() {
usize::f$0(0i32);
}
"#,
);
check(
r#"
trait Trait<T> {
fn f(_: T);
}
impl Trait<i32> for usize {
fn f(_: i32) {}
}
impl Trait<i64> for usize {
fn f(_: i64) {}
//^
}
fn main() {
usize::f$0(0i64);
}
"#,
)
}
#[test]
fn query_impls_in_nearest_block() {
check(
r#"
struct S1;
impl S1 {
fn e() -> () {}
}
fn f1() {
struct S1;
impl S1 {
fn e() -> () {}
//^
}
fn f2() {
fn f3() {
S1::e$0();
}
}
}
"#,
);
check(
r#"
struct S1;
impl S1 {
fn e() -> () {}
}
fn f1() {
struct S1;
impl S1 {
fn e() -> () {}
//^
}
fn f2() {
struct S2;
S1::e$0();
}
}
fn f12() {
struct S1;
impl S1 {
fn e() -> () {}
}
}
"#,
);
check(
r#"
struct S1;
impl S1 {
fn e() -> () {}
//^
}
fn f2() {
struct S2;
S1::e$0();
}
"#,
);
}
2019-01-08 13:33:36 -06:00
}