Use classify_name_ref in hover

This commit is contained in:
Edwin Cheng 2019-06-11 00:34:43 +08:00
parent cbafae6fa8
commit 34322ea9a3
3 changed files with 130 additions and 13 deletions

View File

@ -13,6 +13,7 @@ pub use structure::{StructureNode, file_structure};
pub use function_signature::FunctionSignature;
pub(crate) use short_label::ShortLabel;
pub(crate) use navigation_target::{docs_from_symbol, description_from_symbol};
pub(crate) fn function_label(node: &ast::FnDef) -> String {
FunctionSignature::from(node).to_string()

View File

@ -413,7 +413,7 @@ impl NavigationTarget {
}
}
fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
let file = db.parse(symbol.file_id).tree;
let node = symbol.ptr.to_node(file.syntax()).to_owned();
@ -439,7 +439,7 @@ fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
/// Get a description of a symbol.
///
/// e.g. `struct Name`, `enum Name`, `fn Name`
fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
let file = db.parse(symbol.file_id).tree;
let node = symbol.ptr.to_node(file.syntax()).to_owned();

View File

@ -1,6 +1,6 @@
use ra_db::SourceDatabase;
use ra_syntax::{
AstNode, ast,
AstNode, ast::{self, DocCommentsOwner},
algo::{find_covering_element, find_node_at_offset, ancestors_at_offset},
};
use hir::HirDisplay;
@ -8,7 +8,8 @@ use hir::HirDisplay;
use crate::{
db::RootDatabase,
RangeInfo, FilePosition, FileRange,
display::{rust_code_markup, doc_text_for},
display::{rust_code_markup, doc_text_for, rust_code_markup_with_doc, ShortLabel, docs_from_symbol, description_from_symbol},
name_ref_kind::{NameRefKind::*, classify_name_ref},
};
/// Contains the results when hovering over an item
@ -77,25 +78,140 @@ impl HoverResult {
}
}
fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
match (desc, docs) {
(Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
(None, Some(docs)) => Some(docs.to_string()),
_ => None,
}
}
pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
let file = db.parse(position.file_id).tree;
let mut res = HoverResult::new();
let mut range = None;
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
use crate::goto_definition::{ReferenceResult::*, reference_definition};
let ref_result = reference_definition(db, position.file_id, name_ref);
match ref_result {
Exact(nav) => res.extend(doc_text_for(nav)),
Approximate(navs) => {
// We are no longer exact
res.exact = false;
let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
for nav in navs {
res.extend(doc_text_for(nav))
match classify_name_ref(db, &analyzer, name_ref) {
Some(Method(it)) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()));
}
Some(Macro(it)) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), None));
}
Some(FieldAccess(it)) => {
let it = it.source(db).1;
if let hir::FieldSource::Named(it) = it {
res.extend(hover_text(it.doc_comment_text(), it.short_label()));
}
}
Some(AssocItem(it)) => match it {
hir::ImplItem::Method(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ImplItem::Const(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ImplItem::TypeAlias(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
},
Some(Def(it)) => {
match it {
hir::ModuleDef::Module(it) => {
let it = it.definition_source(db).1;
if let hir::ModuleSource::Module(it) = it {
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
}
hir::ModuleDef::Function(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Struct(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Union(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Enum(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::EnumVariant(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Const(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Static(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::Trait(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::TypeAlias(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::ModuleDef::BuiltinType(_) => {
// FIXME: hover for builtin Type ?
}
}
}
Some(SelfType(ty)) => {
if let Some((adt_def, _)) = ty.as_adt() {
match adt_def {
hir::AdtDef::Struct(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::AdtDef::Union(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
hir::AdtDef::Enum(it) => {
let it = it.source(db).1;
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
}
}
}
}
Some(Pat(_)) => {
res.extend(None);
}
Some(SelfParam(_)) => {
res.extend(None);
}
Some(GenericParam(_)) => {
// FIXME: Hover for generic param
}
None => {}
}
if res.is_empty() {
// Fallback index based approach:
let symbols = crate::symbol_index::index_resolve(db, name_ref);
for sym in symbols {
let docs = docs_from_symbol(db, &sym);
let desc = description_from_symbol(db, &sym);
res.extend(hover_text(docs, desc));
}
}
if !res.is_empty() {
range = Some(name_ref.syntax().range())
}