aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/goto_type_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/goto_type_definition.rs')
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs132
1 files changed, 70 insertions, 62 deletions
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 91a3097fb..069cb283e 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,5 +1,5 @@
1use ra_ide_db::RootDatabase; 1use ra_ide_db::RootDatabase;
2use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 2use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
3 3
4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo};
5 5
@@ -25,8 +25,9 @@ pub(crate) fn goto_type_definition(
25 let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| { 25 let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| {
26 let ty = match_ast! { 26 let ty = match_ast! {
27 match node { 27 match node {
28 ast::Expr(expr) => sema.type_of_expr(&expr)?, 28 ast::Expr(it) => sema.type_of_expr(&it)?,
29 ast::Pat(pat) => sema.type_of_pat(&pat)?, 29 ast::Pat(it) => sema.type_of_pat(&it)?,
30 ast::SelfParam(it) => sema.type_of_self(&it)?,
30 _ => return None, 31 _ => return None,
31 } 32 }
32 }; 33 };
@@ -34,7 +35,7 @@ pub(crate) fn goto_type_definition(
34 Some((ty, node)) 35 Some((ty, node))
35 })?; 36 })?;
36 37
37 let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?; 38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
38 39
39 let nav = adt_def.to_nav(db); 40 let nav = adt_def.to_nav(db);
40 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
@@ -44,7 +45,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
44 return tokens.max_by_key(priority); 45 return tokens.max_by_key(priority);
45 fn priority(n: &SyntaxToken) -> usize { 46 fn priority(n: &SyntaxToken) -> usize {
46 match n.kind() { 47 match n.kind() {
47 IDENT | INT_NUMBER => 2, 48 IDENT | INT_NUMBER | T![self] => 2,
48 kind if kind.is_trivia() => 0, 49 kind if kind.is_trivia() => 0,
49 _ => 1, 50 _ => 1,
50 } 51 }
@@ -53,91 +54,98 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
53 54
54#[cfg(test)] 55#[cfg(test)]
55mod tests { 56mod tests {
56 use crate::mock_analysis::analysis_and_position; 57 use ra_db::FileRange;
57 58
58 fn check_goto(fixture: &str, expected: &str) { 59 use crate::mock_analysis::MockAnalysis;
59 let (analysis, pos) = analysis_and_position(fixture);
60 60
61 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info; 61 fn check(ra_fixture: &str) {
62 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
63 let (expected, data) = mock.annotation();
64 assert!(data.is_empty());
65 let analysis = mock.analysis();
66
67 let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info;
62 assert_eq!(navs.len(), 1); 68 assert_eq!(navs.len(), 1);
63 let nav = navs.pop().unwrap(); 69 let nav = navs.pop().unwrap();
64 nav.assert_match(expected); 70 assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() });
65 } 71 }
66 72
67 #[test] 73 #[test]
68 fn goto_type_definition_works_simple() { 74 fn goto_type_definition_works_simple() {
69 check_goto( 75 check(
70 " 76 r#"
71 //- /lib.rs 77struct Foo;
72 struct Foo; 78 //^^^
73 fn foo() { 79fn foo() {
74 let f: Foo; 80 let f: Foo; f<|>
75 f<|> 81}
76 } 82"#,
77 ",
78 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
79 ); 83 );
80 } 84 }
81 85
82 #[test] 86 #[test]
83 fn goto_type_definition_works_simple_ref() { 87 fn goto_type_definition_works_simple_ref() {
84 check_goto( 88 check(
85 " 89 r#"
86 //- /lib.rs 90struct Foo;
87 struct Foo; 91 //^^^
88 fn foo() { 92fn foo() {
89 let f: &Foo; 93 let f: &Foo; f<|>
90 f<|> 94}
91 } 95"#,
92 ",
93 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
94 ); 96 );
95 } 97 }
96 98
97 #[test] 99 #[test]
98 fn goto_type_definition_works_through_macro() { 100 fn goto_type_definition_works_through_macro() {
99 check_goto( 101 check(
100 " 102 r#"
101 //- /lib.rs 103macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
102 macro_rules! id { 104struct Foo {}
103 ($($tt:tt)*) => { $($tt)* } 105 //^^^
104 } 106id! {
105 struct Foo {} 107 fn bar() { let f<|> = Foo {}; }
106 id! { 108}
107 fn bar() { 109"#,
108 let f<|> = Foo {};
109 }
110 }
111 ",
112 "Foo STRUCT_DEF FileId(1) 52..65 59..62",
113 ); 110 );
114 } 111 }
115 112
116 #[test] 113 #[test]
117 fn goto_type_definition_for_param() { 114 fn goto_type_definition_for_param() {
118 check_goto( 115 check(
119 " 116 r#"
120 //- /lib.rs 117struct Foo;
121 struct Foo; 118 //^^^
122 fn foo(<|>f: Foo) {} 119fn foo(<|>f: Foo) {}
123 ", 120"#,
124 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
125 ); 121 );
126 } 122 }
127 123
128 #[test] 124 #[test]
129 fn goto_type_definition_for_tuple_field() { 125 fn goto_type_definition_for_tuple_field() {
130 check_goto( 126 check(
131 " 127 r#"
132 //- /lib.rs 128struct Foo;
133 struct Foo; 129 //^^^
134 struct Bar(Foo); 130struct Bar(Foo);
135 fn foo() { 131fn foo() {
136 let bar = Bar(Foo); 132 let bar = Bar(Foo);
137 bar.<|>0; 133 bar.<|>0;
138 } 134}
139 ", 135"#,
140 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
141 ); 136 );
142 } 137 }
138
139 #[test]
140 fn goto_def_for_self_param() {
141 check(
142 r#"
143struct Foo;
144 //^^^
145impl Foo {
146 fn f(&self<|>) {}
147}
148"#,
149 )
150 }
143} 151}