diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-10 13:47:23 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-10 13:47:23 +0100 |
commit | 0f7770ae43dd0d97686eb85fccb38801ff30117b (patch) | |
tree | 754d726b02595db4dcc4594712e30ca97a336988 | |
parent | 5fa8f8e3761363098c80e11842682dffcee171d8 (diff) | |
parent | 075380dd56439cdaf1967b7298e10b96b995fc07 (diff) |
Merge #5292
5292: Goto type definition improvements r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_type_definition.rs | 132 |
5 files changed, 105 insertions, 71 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 3d78f71c1..0d877e44e 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, |
27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, |
28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, |
29 | }; | 29 | }; |
30 | use resolver::TypeNs; | 30 | use resolver::TypeNs; |
31 | 31 | ||
@@ -192,6 +192,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
192 | self.imp.type_of_pat(pat) | 192 | self.imp.type_of_pat(pat) |
193 | } | 193 | } |
194 | 194 | ||
195 | pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { | ||
196 | self.imp.type_of_self(param) | ||
197 | } | ||
198 | |||
195 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 199 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
196 | self.imp.resolve_method_call(call) | 200 | self.imp.resolve_method_call(call) |
197 | } | 201 | } |
@@ -216,8 +220,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
216 | self.imp.resolve_path(path) | 220 | self.imp.resolve_path(path) |
217 | } | 221 | } |
218 | 222 | ||
219 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { | 223 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantDef> { |
220 | self.imp.resolve_variant(record_lit) | 224 | self.imp.resolve_variant(record_lit).map(VariantDef::from) |
221 | } | 225 | } |
222 | 226 | ||
223 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | 227 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { |
@@ -370,13 +374,17 @@ impl<'db> SemanticsImpl<'db> { | |||
370 | } | 374 | } |
371 | 375 | ||
372 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 376 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
373 | self.analyze(expr.syntax()).type_of(self.db, &expr) | 377 | self.analyze(expr.syntax()).type_of_expr(self.db, &expr) |
374 | } | 378 | } |
375 | 379 | ||
376 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { | 380 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { |
377 | self.analyze(pat.syntax()).type_of_pat(self.db, &pat) | 381 | self.analyze(pat.syntax()).type_of_pat(self.db, &pat) |
378 | } | 382 | } |
379 | 383 | ||
384 | pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> { | ||
385 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) | ||
386 | } | ||
387 | |||
380 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 388 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
381 | self.analyze(call.syntax()).resolve_method_call(self.db, call) | 389 | self.analyze(call.syntax()).resolve_method_call(self.db, call) |
382 | } | 390 | } |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 1d6c47103..f74b78b23 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -115,7 +115,7 @@ impl SourceAnalyzer { | |||
115 | Some(res) | 115 | Some(res) |
116 | } | 116 | } |
117 | 117 | ||
118 | pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { | 118 | pub(crate) fn type_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { |
119 | let expr_id = self.expr_id(db, expr)?; | 119 | let expr_id = self.expr_id(db, expr)?; |
120 | let ty = self.infer.as_ref()?[expr_id].clone(); | 120 | let ty = self.infer.as_ref()?[expr_id].clone(); |
121 | Type::new_with_resolver(db, &self.resolver, ty) | 121 | Type::new_with_resolver(db, &self.resolver, ty) |
@@ -127,6 +127,17 @@ impl SourceAnalyzer { | |||
127 | Type::new_with_resolver(db, &self.resolver, ty) | 127 | Type::new_with_resolver(db, &self.resolver, ty) |
128 | } | 128 | } |
129 | 129 | ||
130 | pub(crate) fn type_of_self( | ||
131 | &self, | ||
132 | db: &dyn HirDatabase, | ||
133 | param: &ast::SelfParam, | ||
134 | ) -> Option<Type> { | ||
135 | let src = InFile { file_id: self.file_id, value: param }; | ||
136 | let pat_id = self.body_source_map.as_ref()?.node_self_param(src)?; | ||
137 | let ty = self.infer.as_ref()?[pat_id].clone(); | ||
138 | Type::new_with_resolver(db, &self.resolver, ty) | ||
139 | } | ||
140 | |||
130 | pub(crate) fn resolve_method_call( | 141 | pub(crate) fn resolve_method_call( |
131 | &self, | 142 | &self, |
132 | db: &dyn HirDatabase, | 143 | db: &dyn HirDatabase, |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 4f2350915..031ffe13f 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -302,6 +302,11 @@ impl BodySourceMap { | |||
302 | self.pat_map.get(&src).cloned() | 302 | self.pat_map.get(&src).cloned() |
303 | } | 303 | } |
304 | 304 | ||
305 | pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { | ||
306 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
307 | self.pat_map.get(&src).cloned() | ||
308 | } | ||
309 | |||
305 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { | 310 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { |
306 | self.field_map[&(expr, field)].clone() | 311 | self.field_map[&(expr, field)].clone() |
307 | } | 312 | } |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 4c78fa214..8fc33d031 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | ast::{self}, | 7 | ast::{self}, |
8 | match_ast, AstNode, | 8 | match_ast, AstNode, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, TokenAtOffset, | 10 | SyntaxToken, TokenAtOffset, T, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
@@ -32,9 +32,10 @@ pub(crate) fn goto_definition( | |||
32 | let file = sema.parse(position.file_id).syntax().clone(); | 32 | let file = sema.parse(position.file_id).syntax().clone(); |
33 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 33 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
34 | let token = sema.descend_into_macros(original_token.clone()); | 34 | let token = sema.descend_into_macros(original_token.clone()); |
35 | let parent = token.parent(); | ||
35 | 36 | ||
36 | let nav_targets = match_ast! { | 37 | let nav_targets = match_ast! { |
37 | match (token.parent()) { | 38 | match parent { |
38 | ast::NameRef(name_ref) => { | 39 | ast::NameRef(name_ref) => { |
39 | reference_definition(&sema, &name_ref).to_vec() | 40 | reference_definition(&sema, &name_ref).to_vec() |
40 | }, | 41 | }, |
@@ -57,7 +58,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
57 | return tokens.max_by_key(priority); | 58 | return tokens.max_by_key(priority); |
58 | fn priority(n: &SyntaxToken) -> usize { | 59 | fn priority(n: &SyntaxToken) -> usize { |
59 | match n.kind() { | 60 | match n.kind() { |
60 | IDENT | INT_NUMBER => 2, | 61 | IDENT | INT_NUMBER | T![self] => 2, |
61 | kind if kind.is_trivia() => 0, | 62 | kind if kind.is_trivia() => 0, |
62 | _ => 1, | 63 | _ => 1, |
63 | } | 64 | } |
@@ -121,7 +122,8 @@ mod tests { | |||
121 | data => panic!("bad data: {}", data), | 122 | data => panic!("bad data: {}", data), |
122 | } | 123 | } |
123 | 124 | ||
124 | let mut navs = analysis.goto_definition(position).unwrap().unwrap().info; | 125 | let mut navs = |
126 | analysis.goto_definition(position).unwrap().expect("no definition found").info; | ||
125 | if navs.len() == 0 { | 127 | if navs.len() == 0 { |
126 | panic!("unresolved reference") | 128 | panic!("unresolved reference") |
127 | } | 129 | } |
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs index 7eb40d637..069cb283e 100644 --- a/crates/ra_ide/src/goto_type_definition.rs +++ b/crates/ra_ide/src/goto_type_definition.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use ra_ide_db::RootDatabase; | 1 | use ra_ide_db::RootDatabase; |
2 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; | 2 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 3 | ||
4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 4 | use 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)] |
55 | mod tests { | 56 | mod tests { |
56 | use crate::mock_analysis::analysis_and_position; | 57 | use ra_db::FileRange; |
57 | 58 | ||
58 | fn check_goto(ra_fixture: &str, expected: &str) { | 59 | use crate::mock_analysis::MockAnalysis; |
59 | let (analysis, pos) = analysis_and_position(ra_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 | r" | 76 | r#" |
71 | //- /lib.rs | 77 | struct Foo; |
72 | struct Foo; | 78 | //^^^ |
73 | fn foo() { | 79 | fn 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 | r" | 89 | r#" |
86 | //- /lib.rs | 90 | struct Foo; |
87 | struct Foo; | 91 | //^^^ |
88 | fn foo() { | 92 | fn 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 | r" | 102 | r#" |
101 | //- /lib.rs | 103 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
102 | macro_rules! id { | 104 | struct Foo {} |
103 | ($($tt:tt)*) => { $($tt)* } | 105 | //^^^ |
104 | } | 106 | id! { |
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 | r" | 116 | r#" |
120 | //- /lib.rs | 117 | struct Foo; |
121 | struct Foo; | 118 | //^^^ |
122 | fn foo(<|>f: Foo) {} | 119 | fn 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 | r" | 127 | r#" |
132 | //- /lib.rs | 128 | struct Foo; |
133 | struct Foo; | 129 | //^^^ |
134 | struct Bar(Foo); | 130 | struct Bar(Foo); |
135 | fn foo() { | 131 | fn 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#" | ||
143 | struct Foo; | ||
144 | //^^^ | ||
145 | impl Foo { | ||
146 | fn f(&self<|>) {} | ||
147 | } | ||
148 | "#, | ||
149 | ) | ||
150 | } | ||
143 | } | 151 | } |