diff options
author | kjeremy <[email protected]> | 2019-11-18 16:58:42 +0000 |
---|---|---|
committer | kjeremy <[email protected]> | 2019-11-18 16:58:42 +0000 |
commit | b2cc593381aa835b708dfc2df05809e7574be0d6 (patch) | |
tree | 61c352fa2ca5cdb1e2192187a9e29ac6d6e3a5ac /crates/ra_ide_api/src | |
parent | 7614439033bc8b68d3982d93595161ddfda80837 (diff) |
Support hover through macro
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 108 |
1 files changed, 66 insertions, 42 deletions
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index c6d678c0c..78210b085 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,56 @@ 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 | let mut _b: bool = true; |
199 | let mut _b: bool = true; | 201 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); |
200 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); | 202 | } |
201 | } | ||
202 | 203 | ||
203 | if !res.is_empty() { | 204 | if !res.is_empty() { |
204 | Some(name.syntax().text_range()) | 205 | Some(name.syntax().text_range()) |
205 | } else { | 206 | } else { |
206 | None | 207 | None |
208 | } | ||
209 | }, | ||
210 | _ => None, | ||
207 | } | 211 | } |
208 | } else { | ||
209 | None | ||
210 | }; | 212 | }; |
211 | 213 | ||
212 | if range.is_none() { | 214 | if range.is_none() { |
213 | let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| { | 215 | let node = token.ast.ancestors().find(|n| { |
214 | ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() | 216 | ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() |
215 | })?; | 217 | })?; |
216 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | 218 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; |
@@ -716,4 +718,26 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
716 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | 718 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); |
717 | assert_eq!(hover.info.is_exact(), true); | 719 | assert_eq!(hover.info.is_exact(), true); |
718 | } | 720 | } |
721 | |||
722 | #[test] | ||
723 | fn test_hover_through_macro() { | ||
724 | let (analysis, position) = single_file_with_position( | ||
725 | " | ||
726 | macro_rules! id { | ||
727 | ($($tt:$tt)*) => { $($tt)* } | ||
728 | } | ||
729 | |||
730 | fn foo() {} | ||
731 | |||
732 | id! { | ||
733 | fn bar() { | ||
734 | foo<|>(); | ||
735 | } | ||
736 | } | ||
737 | ", | ||
738 | ); | ||
739 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
740 | assert_eq!(trim_markup_opt(hover.info.first()), Some("fn foo()")); | ||
741 | assert_eq!(hover.info.is_exact(), true); | ||
742 | } | ||
719 | } | 743 | } |