aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-14 17:20:18 +0000
committerGitHub <[email protected]>2019-12-14 17:20:18 +0000
commit202ad1e2d9376565cb273cf085be600ed10e5a93 (patch)
tree21ef288f183f39468147972aef88617411a3fdec
parent77db6177658b32f69ad7ebfdef96c1b3b2893fdd (diff)
parentc82529a97f10b1302d2944f1946bcb3479f64e2d (diff)
Merge #2552
2552: fix goto definition when inbetween tokens r=matklad a=succcubbus fixes both goto_definition and goto_type_definition. before, when running goto between some non-trivia token and an identifier, goto would be attempted for the non-trivia token. but this does not make sense for e.g. L_PAREN or COLONCOLON only for IDENTs. this resulted in goto actions not working when running them on the first character of some identifier e.g. for `module::<|>method()` or `method(<|>parameter)`. now only IDENTs will be searched for in goto actions, though i'm not sure if this is correct or if goto should also work for some other token types. Co-authored-by: succcubbus <[email protected]>
-rw-r--r--crates/ra_ide/src/goto_definition.rs46
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs43
-rw-r--r--crates/ra_ide/src/hover.rs23
3 files changed, 106 insertions, 6 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index cfe62037f..27052d72b 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -3,7 +3,9 @@
3use hir::{db::AstDatabase, InFile}; 3use hir::{db::AstDatabase, InFile};
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, DocCommentsOwner}, 5 ast::{self, DocCommentsOwner},
6 match_ast, AstNode, SyntaxNode, 6 match_ast, AstNode,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, TokenAtOffset,
7}; 9};
8 10
9use crate::{ 11use crate::{
@@ -19,8 +21,7 @@ pub(crate) fn goto_definition(
19 position: FilePosition, 21 position: FilePosition,
20) -> Option<RangeInfo<Vec<NavigationTarget>>> { 22) -> Option<RangeInfo<Vec<NavigationTarget>>> {
21 let file = db.parse_or_expand(position.file_id.into())?; 23 let file = db.parse_or_expand(position.file_id.into())?;
22 let original_token = 24 let original_token = pick_best(file.token_at_offset(position.offset))?;
23 file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?;
24 let token = descend_into_macros(db, position.file_id, original_token.clone()); 25 let token = descend_into_macros(db, position.file_id, original_token.clone());
25 26
26 let nav_targets = match_ast! { 27 let nav_targets = match_ast! {
@@ -38,6 +39,17 @@ pub(crate) fn goto_definition(
38 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 39 Some(RangeInfo::new(original_token.text_range(), nav_targets))
39} 40}
40 41
42fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
43 return tokens.max_by_key(priority);
44 fn priority(n: &SyntaxToken) -> usize {
45 match n.kind() {
46 IDENT | INT_NUMBER => 2,
47 kind if kind.is_trivia() => 0,
48 _ => 1,
49 }
50 }
51}
52
41#[derive(Debug)] 53#[derive(Debug)]
42pub(crate) enum ReferenceResult { 54pub(crate) enum ReferenceResult {
43 Exact(NavigationTarget), 55 Exact(NavigationTarget),
@@ -235,6 +247,18 @@ mod tests {
235 } 247 }
236 248
237 #[test] 249 #[test]
250 fn goto_definition_works_at_start_of_item() {
251 check_goto(
252 "
253 //- /lib.rs
254 struct Foo;
255 enum E { X(<|>Foo) }
256 ",
257 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
258 );
259 }
260
261 #[test]
238 fn goto_definition_resolves_correct_name() { 262 fn goto_definition_resolves_correct_name() {
239 check_goto( 263 check_goto(
240 " 264 "
@@ -435,6 +459,22 @@ mod tests {
435 } 459 }
436 460
437 #[test] 461 #[test]
462 fn goto_for_tuple_fields() {
463 check_goto(
464 "
465 //- /lib.rs
466 struct Foo(u32);
467
468 fn bar() {
469 let foo = Foo(0);
470 foo.<|>0;
471 }
472 ",
473 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
474 );
475 }
476
477 #[test]
438 fn goto_definition_works_for_ufcs_inherent_methods() { 478 fn goto_definition_works_for_ufcs_inherent_methods() {
439 check_goto( 479 check_goto(
440 " 480 "
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 992a08809..ce8b6c72a 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::db::AstDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget, 7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget,
@@ -13,7 +13,7 @@ pub(crate) fn goto_type_definition(
13 position: FilePosition, 13 position: FilePosition,
14) -> Option<RangeInfo<Vec<NavigationTarget>>> { 14) -> Option<RangeInfo<Vec<NavigationTarget>>> {
15 let file = db.parse_or_expand(position.file_id.into())?; 15 let file = db.parse_or_expand(position.file_id.into())?;
16 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 16 let token = pick_best(file.token_at_offset(position.offset))?;
17 let token = descend_into_macros(db, position.file_id, token); 17 let token = descend_into_macros(db, position.file_id, token);
18 18
19 let node = token.value.ancestors().find_map(|token| { 19 let node = token.value.ancestors().find_map(|token| {
@@ -41,6 +41,17 @@ pub(crate) fn goto_type_definition(
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
44fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
45 return tokens.max_by_key(priority);
46 fn priority(n: &SyntaxToken) -> usize {
47 match n.kind() {
48 IDENT | INT_NUMBER => 2,
49 kind if kind.is_trivia() => 0,
50 _ => 1,
51 }
52 }
53}
54
44#[cfg(test)] 55#[cfg(test)]
45mod tests { 56mod tests {
46 use crate::mock_analysis::analysis_and_position; 57 use crate::mock_analysis::analysis_and_position;
@@ -102,4 +113,32 @@ mod tests {
102 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)", 113 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)",
103 ); 114 );
104 } 115 }
116
117 #[test]
118 fn goto_type_definition_for_param() {
119 check_goto(
120 "
121 //- /lib.rs
122 struct Foo;
123 fn foo(<|>f: Foo) {}
124 ",
125 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
126 );
127 }
128
129 #[test]
130 fn goto_type_definition_for_tuple_field() {
131 check_goto(
132 "
133 //- /lib.rs
134 struct Foo;
135 struct Bar(Foo);
136 fn foo() {
137 let bar = Bar(Foo);
138 bar.<|>0;
139 }
140 ",
141 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
142 );
143 }
105} 144}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index d372ca758..51e320128 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -6,6 +6,8 @@ use ra_syntax::{
6 algo::find_covering_element, 6 algo::find_covering_element,
7 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
8 match_ast, AstNode, 8 match_ast, AstNode,
9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset,
9}; 11};
10 12
11use crate::{ 13use crate::{
@@ -156,7 +158,7 @@ fn hover_text_from_name_kind(
156 158
157pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 159pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
158 let file = db.parse_or_expand(position.file_id.into())?; 160 let file = db.parse_or_expand(position.file_id.into())?;
159 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 161 let token = pick_best(file.token_at_offset(position.offset))?;
160 let token = descend_into_macros(db, position.file_id, token); 162 let token = descend_into_macros(db, position.file_id, token);
161 163
162 let mut res = HoverResult::new(); 164 let mut res = HoverResult::new();
@@ -218,6 +220,18 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
218 Some(RangeInfo::new(range, res)) 220 Some(RangeInfo::new(range, res))
219} 221}
220 222
223fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
224 return tokens.max_by_key(priority);
225 fn priority(n: &SyntaxToken) -> usize {
226 match n.kind() {
227 IDENT | INT_NUMBER => 3,
228 L_PAREN | R_PAREN => 2,
229 kind if kind.is_trivia() => 0,
230 _ => 1,
231 }
232 }
233}
234
221pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 235pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
222 let parse = db.parse(frange.file_id); 236 let parse = db.parse(frange.file_id);
223 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range); 237 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range);
@@ -505,6 +519,13 @@ fn func(foo: i32) { if true { <|>foo; }; }
505 } 519 }
506 520
507 #[test] 521 #[test]
522 fn hover_for_param_edge() {
523 let (analysis, position) = single_file_with_position("fn func(<|>foo: i32) {}");
524 let hover = analysis.hover(position).unwrap().unwrap();
525 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
526 }
527
528 #[test]
508 fn test_type_of_for_function() { 529 fn test_type_of_for_function() {
509 let (analysis, range) = single_file_with_range( 530 let (analysis, range) = single_file_with_range(
510 " 531 "