diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 104 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 3 |
5 files changed, 66 insertions, 56 deletions
@@ -1,7 +1,5 @@ | |||
1 | # Rust Analyzer | 1 | # Rust Analyzer |
2 | 2 | ||
3 | [![Build Status](https://travis-ci.org/rust-analyzer/rust-analyzer.svg?branch=master)](https://travis-ci.org/rust-analyzer/rust-analyzer) | ||
4 | |||
5 | Rust Analyzer is an **experimental** modular compiler frontend for the Rust | 3 | Rust Analyzer is an **experimental** modular compiler frontend for the Rust |
6 | language. It is a part of a larger rls-2.0 effort to create excellent IDE | 4 | language. It is a part of a larger rls-2.0 effort to create excellent IDE |
7 | support for Rust. If you want to get involved, check the rls-2.0 working group | 5 | support for Rust. If you want to get involved, check the rls-2.0 working group |
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 | } |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index cefc00402..761b2435c 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | ast::{self, child_opt, children, AstChildren, AstNode, AttrInput, SyntaxNode}, | 5 | ast::{self, child_opt, children, AstNode, AttrInput, SyntaxNode}, |
6 | SmolStr, SyntaxElement, | 6 | SmolStr, SyntaxElement, |
7 | SyntaxKind::*, | 7 | SyntaxKind::*, |
8 | SyntaxToken, T, | 8 | SyntaxToken, T, |
@@ -176,16 +176,6 @@ impl ast::ImplBlock { | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | impl ast::AttrsOwner for ast::ImplItem { | ||
180 | fn attrs(&self) -> AstChildren<ast::Attr> { | ||
181 | match self { | ||
182 | ast::ImplItem::FnDef(it) => it.attrs(), | ||
183 | ast::ImplItem::TypeAliasDef(it) => it.attrs(), | ||
184 | ast::ImplItem::ConstDef(it) => it.attrs(), | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | #[derive(Debug, Clone, PartialEq, Eq)] | 179 | #[derive(Debug, Clone, PartialEq, Eq)] |
190 | pub enum StructKind { | 180 | pub enum StructKind { |
191 | Tuple(ast::TupleFieldDefList), | 181 | Tuple(ast::TupleFieldDefList), |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 34b22c3e2..2b381dcdb 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1298,6 +1298,7 @@ impl AstNode for ImplItem { | |||
1298 | } | 1298 | } |
1299 | } | 1299 | } |
1300 | } | 1300 | } |
1301 | impl ast::AttrsOwner for ImplItem {} | ||
1301 | impl ImplItem {} | 1302 | impl ImplItem {} |
1302 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 1303 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
1303 | pub struct ImplTraitType { | 1304 | pub struct ImplTraitType { |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 0a8fd0612..70d85a8e6 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -401,7 +401,8 @@ Grammar( | |||
401 | traits: ["AttrsOwner"] | 401 | traits: ["AttrsOwner"] |
402 | ), | 402 | ), |
403 | "ImplItem": ( | 403 | "ImplItem": ( |
404 | enum: ["FnDef", "TypeAliasDef", "ConstDef"] | 404 | enum: ["FnDef", "TypeAliasDef", "ConstDef"], |
405 | traits: ["AttrsOwner"] | ||
405 | ), | 406 | ), |
406 | 407 | ||
407 | "TupleExpr": ( | 408 | "TupleExpr": ( |