aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/hover.rs')
-rw-r--r--crates/ra_ide/src/hover.rs45
1 files changed, 22 insertions, 23 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 1c6ca36df..ace33c079 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -1,8 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{db::AstDatabase, Adt, HasSource, HirDisplay, SourceBinder}; 3use hir::{Adt, HasSource, HirDisplay, Semantics};
4use ra_db::SourceDatabase; 4use ra_ide_db::{
5use ra_ide_db::{defs::NameDefinition, RootDatabase}; 5 defs::{classify_name, NameDefinition},
6 RootDatabase,
7};
6use ra_syntax::{ 8use ra_syntax::{
7 algo::find_covering_element, 9 algo::find_covering_element,
8 ast::{self, DocCommentsOwner}, 10 ast::{self, DocCommentsOwner},
@@ -13,8 +15,7 @@ use ra_syntax::{
13 15
14use crate::{ 16use crate::{
15 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, 17 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
16 expand::{descend_into_macros, original_range}, 18 references::classify_name_ref,
17 references::{classify_name, classify_name_ref},
18 FilePosition, FileRange, RangeInfo, 19 FilePosition, FileRange, RangeInfo,
19}; 20};
20 21
@@ -143,25 +144,25 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: NameDefinition) -> Option<S
143} 144}
144 145
145pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 146pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
146 let file = db.parse_or_expand(position.file_id.into())?; 147 let sema = Semantics::new(db);
148 let file = sema.parse(position.file_id).syntax().clone();
147 let token = pick_best(file.token_at_offset(position.offset))?; 149 let token = pick_best(file.token_at_offset(position.offset))?;
148 let token = descend_into_macros(db, position.file_id, token); 150 let token = sema.descend_into_macros(token);
149 151
150 let mut res = HoverResult::new(); 152 let mut res = HoverResult::new();
151 153
152 let mut sb = SourceBinder::new(db);
153 if let Some((node, name_kind)) = match_ast! { 154 if let Some((node, name_kind)) = match_ast! {
154 match (token.value.parent()) { 155 match (token.parent()) {
155 ast::NameRef(name_ref) => { 156 ast::NameRef(name_ref) => {
156 classify_name_ref(&mut sb, token.with_value(&name_ref)).map(|d| (name_ref.syntax().clone(), d)) 157 classify_name_ref(&sema, &name_ref).map(|d| (name_ref.syntax().clone(), d))
157 }, 158 },
158 ast::Name(name) => { 159 ast::Name(name) => {
159 classify_name(&mut sb, token.with_value(&name)).map(|d| (name.syntax().clone(), d)) 160 classify_name(&sema, &name).map(|d| (name.syntax().clone(), d))
160 }, 161 },
161 _ => None, 162 _ => None,
162 } 163 }
163 } { 164 } {
164 let range = original_range(db, token.with_value(&node)).range; 165 let range = sema.original_range(&node).range;
165 res.extend(hover_text_from_name_kind(db, name_kind)); 166 res.extend(hover_text_from_name_kind(db, name_kind));
166 167
167 if !res.is_empty() { 168 if !res.is_empty() {
@@ -170,11 +171,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
170 } 171 }
171 172
172 let node = token 173 let node = token
173 .value
174 .ancestors() 174 .ancestors()
175 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; 175 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
176 176
177 let frange = original_range(db, token.with_value(&node)); 177 let frange = sema.original_range(&node);
178 res.extend(type_of(db, frange).map(rust_code_markup)); 178 res.extend(type_of(db, frange).map(rust_code_markup));
179 if res.is_empty() { 179 if res.is_empty() {
180 return None; 180 return None;
@@ -197,19 +197,17 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
197} 197}
198 198
199pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 199pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
200 let parse = db.parse(frange.file_id); 200 let sema = Semantics::new(db);
201 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range); 201 let source_file = sema.parse(frange.file_id);
202 let leaf_node = find_covering_element(source_file.syntax(), frange.range);
202 // if we picked identifier, expand to pattern/expression 203 // if we picked identifier, expand to pattern/expression
203 let node = leaf_node 204 let node = leaf_node
204 .ancestors() 205 .ancestors()
205 .take_while(|it| it.text_range() == leaf_node.text_range()) 206 .take_while(|it| it.text_range() == leaf_node.text_range())
206 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; 207 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?;
207 let analyzer = 208 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| sema.type_of_expr(&e)) {
208 hir::SourceAnalyzer::new(db, hir::InFile::new(frange.file_id.into(), &node), None);
209 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e))
210 {
211 ty 209 ty
212 } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| analyzer.type_of_pat(db, &p)) { 210 } else if let Some(ty) = ast::Pat::cast(node).and_then(|p| sema.type_of_pat(&p)) {
213 ty 211 ty
214 } else { 212 } else {
215 return None; 213 return None;
@@ -219,11 +217,12 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
219 217
220#[cfg(test)] 218#[cfg(test)]
221mod tests { 219mod tests {
220 use ra_db::FileLoader;
221 use ra_syntax::TextRange;
222
222 use crate::mock_analysis::{ 223 use crate::mock_analysis::{
223 analysis_and_position, single_file_with_position, single_file_with_range, 224 analysis_and_position, single_file_with_position, single_file_with_range,
224 }; 225 };
225 use ra_db::FileLoader;
226 use ra_syntax::TextRange;
227 226
228 fn trim_markup(s: &str) -> &str { 227 fn trim_markup(s: &str) -> &str {
229 s.trim_start_matches("```rust\n").trim_end_matches("\n```") 228 s.trim_start_matches("```rust\n").trim_end_matches("\n```")