Skip to content

Commit a6d0806

Browse files
bors[bot]kjeremy
andauthored
Merge #2249
2249: Cleanup hover r=matklad a=kjeremy Take advantage of classify_name to consolidate multiple hover paths. This isn't quite as clean as I want it to be (`no_fallback` bool is wonky). There's a relationship between `HoverResult` being empty and the range that is a little warty. Also I noticed that HoverResults are always marked as exact and have been for quite a while... maybe that should be removed in another PR. Co-authored-by: Jeremy Kolb <[email protected]>
2 parents ae6a803 + 89647f9 commit a6d0806

File tree

1 file changed

+93
-111
lines changed

1 file changed

+93
-111
lines changed

crates/ra_ide_api/src/hover.rs

Lines changed: 93 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase;
55
use ra_syntax::{
66
algo::{ancestors_at_offset, find_covering_element, find_node_at_offset},
77
ast::{self, DocCommentsOwner},
8-
match_ast, AstNode,
8+
AstNode,
99
};
1010

1111
use crate::{
@@ -14,7 +14,7 @@ use crate::{
1414
description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
1515
rust_code_markup_with_doc, ShortLabel,
1616
},
17-
references::{classify_name_ref, NameKind::*},
17+
references::{classify_name, classify_name_ref, NameKind, NameKind::*},
1818
FilePosition, FileRange, RangeInfo,
1919
};
2020

@@ -92,65 +92,88 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
9292
}
9393
}
9494

95+
fn hover_text_from_name_kind(
96+
db: &RootDatabase,
97+
name_kind: NameKind,
98+
no_fallback: &mut bool,
99+
) -> Option<String> {
100+
return match name_kind {
101+
Macro(it) => {
102+
let src = it.source(db);
103+
hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))
104+
}
105+
Field(it) => {
106+
let src = it.source(db);
107+
match src.ast {
108+
hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()),
109+
_ => None,
110+
}
111+
}
112+
AssocItem(it) => match it {
113+
hir::AssocItem::Function(it) => from_def_source(db, it),
114+
hir::AssocItem::Const(it) => from_def_source(db, it),
115+
hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
116+
},
117+
Def(it) => match it {
118+
hir::ModuleDef::Module(it) => match it.definition_source(db).ast {
119+
hir::ModuleSource::Module(it) => {
120+
hover_text(it.doc_comment_text(), it.short_label())
121+
}
122+
_ => None,
123+
},
124+
hir::ModuleDef::Function(it) => from_def_source(db, it),
125+
hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it),
126+
hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it),
127+
hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it),
128+
hir::ModuleDef::EnumVariant(it) => from_def_source(db, it),
129+
hir::ModuleDef::Const(it) => from_def_source(db, it),
130+
hir::ModuleDef::Static(it) => from_def_source(db, it),
131+
hir::ModuleDef::Trait(it) => from_def_source(db, it),
132+
hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
133+
hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
134+
},
135+
SelfType(ty) => match ty.as_adt() {
136+
Some((adt_def, _)) => match adt_def {
137+
hir::Adt::Struct(it) => from_def_source(db, it),
138+
hir::Adt::Union(it) => from_def_source(db, it),
139+
hir::Adt::Enum(it) => from_def_source(db, it),
140+
},
141+
_ => None,
142+
},
143+
Local(_) => {
144+
// Hover for these shows type names
145+
*no_fallback = true;
146+
None
147+
}
148+
GenericParam(_) => {
149+
// FIXME: Hover for generic param
150+
None
151+
}
152+
};
153+
154+
fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String>
155+
where
156+
D: HasSource<Ast = A>,
157+
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
158+
{
159+
let src = def.source(db);
160+
hover_text(src.ast.doc_comment_text(), src.ast.short_label())
161+
}
162+
}
163+
95164
pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
96165
let parse = db.parse(position.file_id);
97166
let file = parse.tree();
167+
98168
let mut res = HoverResult::new();
99169

100-
let mut range = None;
101-
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
170+
let mut range = if let Some(name_ref) =
171+
find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)
172+
{
102173
let mut no_fallback = false;
103-
let name_kind = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind);
104-
match name_kind {
105-
Some(Macro(it)) => {
106-
let src = it.source(db);
107-
res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast))));
108-
}
109-
Some(Field(it)) => {
110-
let src = it.source(db);
111-
if let hir::FieldSource::Named(it) = src.ast {
112-
res.extend(hover_text(it.doc_comment_text(), it.short_label()));
113-
}
114-
}
115-
Some(AssocItem(it)) => res.extend(match it {
116-
hir::AssocItem::Function(it) => from_def_source(db, it),
117-
hir::AssocItem::Const(it) => from_def_source(db, it),
118-
hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
119-
}),
120-
Some(Def(it)) => match it {
121-
hir::ModuleDef::Module(it) => {
122-
if let hir::ModuleSource::Module(it) = it.definition_source(db).ast {
123-
res.extend(hover_text(it.doc_comment_text(), it.short_label()))
124-
}
125-
}
126-
hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
127-
hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
128-
hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
129-
hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
130-
hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
131-
hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
132-
hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
133-
hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
134-
hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
135-
hir::ModuleDef::BuiltinType(it) => res.extend(Some(it.to_string())),
136-
},
137-
Some(SelfType(ty)) => {
138-
if let Some((adt_def, _)) = ty.as_adt() {
139-
res.extend(match adt_def {
140-
hir::Adt::Struct(it) => from_def_source(db, it),
141-
hir::Adt::Union(it) => from_def_source(db, it),
142-
hir::Adt::Enum(it) => from_def_source(db, it),
143-
})
144-
}
145-
}
146-
Some(Local(_)) => {
147-
// Hover for these shows type names
148-
no_fallback = true;
149-
}
150-
Some(GenericParam(_)) => {
151-
// FIXME: Hover for generic param
152-
}
153-
None => {}
174+
if let Some(name_kind) = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind)
175+
{
176+
res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
154177
}
155178

156179
if res.is_empty() && !no_fallback {
@@ -164,55 +187,24 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
164187
}
165188

166189
if !res.is_empty() {
167-
range = Some(name_ref.syntax().text_range())
190+
Some(name_ref.syntax().text_range())
191+
} else {
192+
None
168193
}
169194
} else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
170-
if let Some(parent) = name.syntax().parent() {
171-
let text = match_ast! {
172-
match parent {
173-
ast::StructDef(it) => {
174-
hover_text(it.doc_comment_text(), it.short_label())
175-
},
176-
ast::EnumDef(it) => {
177-
hover_text(it.doc_comment_text(), it.short_label())
178-
},
179-
ast::EnumVariant(it) => {
180-
hover_text(it.doc_comment_text(), it.short_label())
181-
},
182-
ast::FnDef(it) => {
183-
hover_text(it.doc_comment_text(), it.short_label())
184-
},
185-
ast::TypeAliasDef(it) => {
186-
hover_text(it.doc_comment_text(), it.short_label())
187-
},
188-
ast::ConstDef(it) => {
189-
hover_text(it.doc_comment_text(), it.short_label())
190-
},
191-
ast::StaticDef(it) => {
192-
hover_text(it.doc_comment_text(), it.short_label())
193-
},
194-
ast::TraitDef(it) => {
195-
hover_text(it.doc_comment_text(), it.short_label())
196-
},
197-
ast::RecordFieldDef(it) => {
198-
hover_text(it.doc_comment_text(), it.short_label())
199-
},
200-
ast::Module(it) => {
201-
hover_text(it.doc_comment_text(), it.short_label())
202-
},
203-
ast::MacroCall(it) => {
204-
hover_text(it.doc_comment_text(), None)
205-
},
206-
_ => None,
207-
}
208-
};
209-
res.extend(text);
195+
if let Some(name_kind) = classify_name(db, position.file_id, &name).map(|d| d.kind) {
196+
let mut _b: bool = true;
197+
res.extend(hover_text_from_name_kind(db, name_kind, &mut _b));
210198
}
211199

212-
if !res.is_empty() && range.is_none() {
213-
range = Some(name.syntax().text_range());
200+
if !res.is_empty() {
201+
Some(name.syntax().text_range())
202+
} else {
203+
None
214204
}
215-
}
205+
} else {
206+
None
207+
};
216208

217209
if range.is_none() {
218210
let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| {
@@ -221,23 +213,13 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
221213
let frange = FileRange { file_id: position.file_id, range: node.text_range() };
222214
res.extend(type_of(db, frange).map(rust_code_markup));
223215
range = Some(node.text_range());
224-
}
216+
};
225217

226218
let range = range?;
227219
if res.is_empty() {
228220
return None;
229221
}
230-
let res = RangeInfo::new(range, res);
231-
return Some(res);
232-
233-
fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String>
234-
where
235-
D: HasSource<Ast = A>,
236-
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
237-
{
238-
let src = def.source(db);
239-
hover_text(src.ast.doc_comment_text(), src.ast.short_label())
240-
}
222+
Some(RangeInfo::new(range, res))
241223
}
242224

243225
pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {

0 commit comments

Comments
 (0)