diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-18 19:57:06 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-18 19:57:06 +0000 |
commit | c8fb5b491a172efed308ba1f15843fbc93815fc5 (patch) | |
tree | 0c6d2ea15471a4be005546df7065fb55948d7d23 | |
parent | a4f21801c54c65eafa337edc5e86de2c46b37544 (diff) | |
parent | 90f6f6080ea5f3f8588ed4a10056820e418e78d0 (diff) |
Merge #2307
2307: Support hover through macro r=matklad a=kjeremy
Allows hover to work through macros like `match_ast!`.
Co-authored-by: kjeremy <[email protected]>
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index c6d678c0c..787b714b3 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Adt, HasSource, HirDisplay, Source}; | 3 | use hir::{db::AstDatabase, Adt, HasSource, HirDisplay}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, | 6 | algo::find_covering_element, |
7 | ast::{self, DocCommentsOwner}, | 7 | ast::{self, DocCommentsOwner}, |
8 | AstNode, | 8 | match_ast, AstNode, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
@@ -14,6 +14,7 @@ use crate::{ | |||
14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, | 14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, |
15 | rust_code_markup_with_doc, ShortLabel, | 15 | rust_code_markup_with_doc, ShortLabel, |
16 | }, | 16 | }, |
17 | expand::descend_into_macros, | ||
17 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, | 18 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, |
18 | FilePosition, FileRange, RangeInfo, | 19 | FilePosition, FileRange, RangeInfo, |
19 | }; | 20 | }; |
@@ -162,55 +163,55 @@ fn hover_text_from_name_kind( | |||
162 | } | 163 | } |
163 | 164 | ||
164 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { | 165 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { |
165 | let parse = db.parse(position.file_id); | 166 | let file = db.parse_or_expand(position.file_id.into())?; |
166 | let file = parse.tree(); | 167 | let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; |
168 | let token = descend_into_macros(db, position.file_id, token); | ||
167 | 169 | ||
168 | let mut res = HoverResult::new(); | 170 | let mut res = HoverResult::new(); |
169 | 171 | ||
170 | let mut range = if let Some(name_ref) = | 172 | let mut range = match_ast! { |
171 | find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) | 173 | match (token.ast.parent()) { |
172 | { | 174 | ast::NameRef(name_ref) => { |
173 | let mut no_fallback = false; | 175 | let mut no_fallback = false; |
174 | if let Some(name_kind) = | 176 | if let Some(name_kind) = |
175 | classify_name_ref(db, Source::new(position.file_id.into(), &name_ref)).map(|d| d.kind) | 177 | classify_name_ref(db, token.with_ast(&name_ref)).map(|d| d.kind) |
176 | { | 178 | { |
177 | res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback)) | 179 | res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback)) |
178 | } | 180 | } |
179 | 181 | ||
180 | if res.is_empty() && !no_fallback { | 182 | if res.is_empty() && !no_fallback { |
181 | // Fallback index based approach: | 183 | // Fallback index based approach: |
182 | let symbols = crate::symbol_index::index_resolve(db, &name_ref); | 184 | let symbols = crate::symbol_index::index_resolve(db, &name_ref); |
183 | for sym in symbols { | 185 | for sym in symbols { |
184 | let docs = docs_from_symbol(db, &sym); | 186 | let docs = docs_from_symbol(db, &sym); |
185 | let desc = description_from_symbol(db, &sym); | 187 | let desc = description_from_symbol(db, &sym); |
186 | res.extend(hover_text(docs, desc)); | 188 | res.extend(hover_text(docs, desc)); |
187 | } | 189 | } |
188 | } | 190 | } |
189 | 191 | ||
190 | if !res.is_empty() { | 192 | if !res.is_empty() { |
191 | Some(name_ref.syntax().text_range()) | 193 | Some(name_ref.syntax().text_range()) |
192 | } else { | 194 | } else { |
193 | None | 195 | None |
194 | } | 196 | } |
195 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { | 197 | }, |
196 | if let Some(name_kind) = | 198 | ast::Name(name) => { |
197 | classify_name(db, Source::new(position.file_id.into(), &name)).map(|d| d.kind) | 199 | if let Some(name_kind) = classify_name(db, token.with_ast(&name)).map(|d| d.kind) { |
198 | { | 200 | res.extend(hover_text_from_name_kind(db, name_kind, &mut true)); |
199 | let mut _b: bool = true; | 201 | } |
200 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); | ||
201 | } | ||
202 | 202 | ||
203 | if !res.is_empty() { | 203 | if !res.is_empty() { |
204 | Some(name.syntax().text_range()) | 204 | Some(name.syntax().text_range()) |
205 | } else { | 205 | } else { |
206 | None | 206 | None |
207 | } | ||
208 | }, | ||
209 | _ => None, | ||
207 | } | 210 | } |
208 | } else { | ||
209 | None | ||
210 | }; | 211 | }; |
211 | 212 | ||
212 | if range.is_none() { | 213 | if range.is_none() { |
213 | let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| { | 214 | let node = token.ast.ancestors().find(|n| { |
214 | ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() | 215 | ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() |
215 | })?; | 216 | })?; |
216 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | 217 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; |
@@ -716,4 +717,23 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
716 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 717 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); |
717 | assert_eq!(hover.info.is_exact(), true); | 718 | assert_eq!(hover.info.is_exact(), true); |
718 | } | 719 | } |
720 | |||
721 | #[test] | ||
722 | fn test_hover_through_macro() { | ||
723 | check_hover_result( | ||
724 | " | ||
725 | //- /lib.rs | ||
726 | macro_rules! id { | ||
727 | ($($tt:tt)*) => { $($tt)* } | ||
728 | } | ||
729 | fn foo() {} | ||
730 | id! { | ||
731 | fn bar() { | ||
732 | fo<|>o(); | ||
733 | } | ||
734 | } | ||
735 | ", | ||
736 | &["fn foo()"], | ||
737 | ); | ||
738 | } | ||
719 | } | 739 | } |