aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/attrs.rs5
-rw-r--r--crates/hir/src/lib.rs3
-rw-r--r--crates/hir_def/src/attr.rs25
-rw-r--r--crates/hir_def/src/docs.rs79
-rw-r--r--crates/hir_def/src/lib.rs1
-rw-r--r--crates/ide/src/hover.rs64
6 files changed, 63 insertions, 114 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index fb2631b3e..1f2ee2580 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -1,6 +1,9 @@
1//! Attributes & documentation for hir types. 1//! Attributes & documentation for hir types.
2use hir_def::{ 2use hir_def::{
3 attr::Attrs, docs::Documentation, path::ModPath, resolver::HasResolver, AttrDefId, ModuleDefId, 3 attr::{Attrs, Documentation},
4 path::ModPath,
5 resolver::HasResolver,
6 AttrDefId, ModuleDefId,
4}; 7};
5use hir_expand::hygiene::Hygiene; 8use hir_expand::hygiene::Hygiene;
6use hir_ty::db::HirDatabase; 9use hir_ty::db::HirDatabase;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 93bdb4472..c7c7377d7 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -44,10 +44,9 @@ pub use crate::{
44 44
45pub use hir_def::{ 45pub use hir_def::{
46 adt::StructKind, 46 adt::StructKind,
47 attr::Attrs, 47 attr::{Attrs, Documentation},
48 body::scope::ExprScopes, 48 body::scope::ExprScopes,
49 builtin_type::BuiltinType, 49 builtin_type::BuiltinType,
50 docs::Documentation,
51 find_path::PrefixKind, 50 find_path::PrefixKind,
52 import_map, 51 import_map,
53 item_scope::ItemInNs, 52 item_scope::ItemInNs,
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 7825290e6..98293aad3 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -15,7 +15,6 @@ use tt::Subtree;
15 15
16use crate::{ 16use crate::{
17 db::DefDatabase, 17 db::DefDatabase,
18 docs::Documentation,
19 item_tree::{ItemTreeId, ItemTreeNode}, 18 item_tree::{ItemTreeId, ItemTreeNode},
20 nameres::ModuleSource, 19 nameres::ModuleSource,
21 path::ModPath, 20 path::ModPath,
@@ -23,6 +22,22 @@ use crate::{
23 AdtId, AttrDefId, Lookup, 22 AdtId, AttrDefId, Lookup,
24}; 23};
25 24
25/// Holds documentation
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct Documentation(Arc<str>);
28
29impl Documentation {
30 pub fn as_str(&self) -> &str {
31 &self.0
32 }
33}
34
35impl Into<String> for Documentation {
36 fn into(self) -> String {
37 self.as_str().to_owned()
38 }
39}
40
26#[derive(Default, Debug, Clone, PartialEq, Eq)] 41#[derive(Default, Debug, Clone, PartialEq, Eq)]
27pub struct Attrs { 42pub struct Attrs {
28 entries: Option<Arc<[Attr]>>, 43 entries: Option<Arc<[Attr]>>,
@@ -102,7 +117,7 @@ impl Attrs {
102 }, 117 },
103 ); 118 );
104 let mut attrs = owner.attrs().peekable(); 119 let mut attrs = owner.attrs().peekable();
105 let entries = if attrs.peek().is_none() { 120 let entries = if attrs.peek().is_none() && docs.is_none() {
106 // Avoid heap allocation 121 // Avoid heap allocation
107 None 122 None
108 } else { 123 } else {
@@ -154,7 +169,11 @@ impl Attrs {
154 .intersperse(&SmolStr::new_inline("\n")) 169 .intersperse(&SmolStr::new_inline("\n"))
155 // No FromIterator<SmolStr> for String 170 // No FromIterator<SmolStr> for String
156 .for_each(|s| docs.push_str(s.as_str())); 171 .for_each(|s| docs.push_str(s.as_str()));
157 if docs.is_empty() { None } else { Some(docs) }.map(|it| Documentation::new(&it)) 172 if docs.is_empty() {
173 None
174 } else {
175 Some(Documentation(docs.into()))
176 }
158 } 177 }
159} 178}
160 179
diff --git a/crates/hir_def/src/docs.rs b/crates/hir_def/src/docs.rs
deleted file mode 100644
index 6a27effef..000000000
--- a/crates/hir_def/src/docs.rs
+++ /dev/null
@@ -1,79 +0,0 @@
1//! Defines hir documentation.
2//!
3//! This really shouldn't exist, instead, we should deshugar doc comments into attributes, see
4//! https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102
5
6use std::sync::Arc;
7
8use itertools::Itertools;
9use syntax::{ast, SmolStr};
10
11/// Holds documentation
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Documentation(Arc<str>);
14
15impl Into<String> for Documentation {
16 fn into(self) -> String {
17 self.as_str().to_owned()
18 }
19}
20
21impl Documentation {
22 pub fn new(s: &str) -> Documentation {
23 Documentation(s.into())
24 }
25
26 pub fn from_ast<N>(node: &N) -> Option<Documentation>
27 where
28 N: ast::DocCommentsOwner + ast::AttrsOwner,
29 {
30 docs_from_ast(node)
31 }
32
33 pub fn as_str(&self) -> &str {
34 &*self.0
35 }
36}
37
38pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation>
39where
40 N: ast::DocCommentsOwner + ast::AttrsOwner,
41{
42 let doc_comment_text = node.doc_comment_text();
43 let doc_attr_text = expand_doc_attrs(node);
44 let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
45 docs.map(|it| Documentation::new(&it))
46}
47
48fn merge_doc_comments_and_attrs(
49 doc_comment_text: Option<String>,
50 doc_attr_text: Option<String>,
51) -> Option<String> {
52 match (doc_comment_text, doc_attr_text) {
53 (Some(mut comment_text), Some(attr_text)) => {
54 comment_text.reserve(attr_text.len() + 1);
55 comment_text.push('\n');
56 comment_text.push_str(&attr_text);
57 Some(comment_text)
58 }
59 (Some(comment_text), None) => Some(comment_text),
60 (None, Some(attr_text)) => Some(attr_text),
61 (None, None) => None,
62 }
63}
64
65fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> {
66 let mut docs = String::new();
67 owner
68 .attrs()
69 .filter_map(|attr| attr.as_simple_key_value().filter(|(key, _)| key == "doc"))
70 .map(|(_, value)| value)
71 .intersperse(SmolStr::new_inline("\n"))
72 // No FromIterator<SmolStr> for String
73 .for_each(|s| docs.push_str(s.as_str()));
74 if docs.is_empty() {
75 None
76 } else {
77 Some(docs)
78 }
79}
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index b41c5acb2..02ed30e4d 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -31,7 +31,6 @@ pub mod adt;
31pub mod data; 31pub mod data;
32pub mod generics; 32pub mod generics;
33pub mod lang_item; 33pub mod lang_item;
34pub mod docs;
35 34
36pub mod expr; 35pub mod expr;
37pub mod body; 36pub mod body;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index dc9621f46..1b6ff6d21 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,6 +1,6 @@
1use hir::{ 1use hir::{
2 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, 2 Adt, AsAssocItem, AssocItemContainer, FieldSource, HasAttrs, HasSource, HirDisplay, Module,
3 Module, ModuleDef, ModuleSource, Semantics, 3 ModuleDef, ModuleSource, Semantics,
4}; 4};
5use ide_db::base_db::SourceDatabase; 5use ide_db::base_db::SourceDatabase;
6use ide_db::{ 6use ide_db::{
@@ -319,31 +319,27 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
319 let mod_path = definition_mod_path(db, &def); 319 let mod_path = definition_mod_path(db, &def);
320 return match def { 320 return match def {
321 Definition::Macro(it) => { 321 Definition::Macro(it) => {
322 let src = it.source(db); 322 let label = macro_label(&it.source(db).value);
323 let docs = Documentation::from_ast(&src.value).map(Into::into); 323 from_def_source_labeled(db, it, Some(label), mod_path)
324 hover_markup(docs, Some(macro_label(&src.value)), mod_path)
325 } 324 }
326 Definition::Field(it) => { 325 Definition::Field(def) => {
327 let src = it.source(db); 326 let src = def.source(db).value;
328 match src.value { 327 if let FieldSource::Named(it) = src {
329 FieldSource::Named(it) => { 328 from_def_source_labeled(db, def, it.short_label(), mod_path)
330 let docs = Documentation::from_ast(&it).map(Into::into); 329 } else {
331 hover_markup(docs, it.short_label(), mod_path) 330 None
332 }
333 _ => None,
334 } 331 }
335 } 332 }
336 Definition::ModuleDef(it) => match it { 333 Definition::ModuleDef(it) => match it {
337 ModuleDef::Module(it) => match it.definition_source(db).value { 334 ModuleDef::Module(it) => from_def_source_labeled(
338 ModuleSource::Module(it) => { 335 db,
339 let docs = Documentation::from_ast(&it).map(Into::into); 336 it,
340 hover_markup(docs, it.short_label(), mod_path) 337 match it.definition_source(db).value {
341 } 338 ModuleSource::Module(it) => it.short_label(),
342 ModuleSource::SourceFile(it) => { 339 ModuleSource::SourceFile(it) => it.short_label(),
343 let docs = Documentation::from_ast(&it).map(Into::into); 340 },
344 hover_markup(docs, it.short_label(), mod_path) 341 mod_path,
345 } 342 ),
346 },
347 ModuleDef::Function(it) => from_def_source(db, it, mod_path), 343 ModuleDef::Function(it) => from_def_source(db, it, mod_path),
348 ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), 344 ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
349 ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path), 345 ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
@@ -371,12 +367,24 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
371 367
372 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 368 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
373 where 369 where
374 D: HasSource<Ast = A>, 370 D: HasSource<Ast = A> + HasAttrs + Copy,
375 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner, 371 A: ShortLabel,
372 {
373 let short_label = def.source(db).value.short_label();
374 from_def_source_labeled(db, def, short_label, mod_path)
375 }
376
377 fn from_def_source_labeled<D>(
378 db: &RootDatabase,
379 def: D,
380 short_label: Option<String>,
381 mod_path: Option<String>,
382 ) -> Option<Markup>
383 where
384 D: HasAttrs,
376 { 385 {
377 let src = def.source(db); 386 let docs = def.attrs(db).docs().map(Into::into);
378 let docs = Documentation::from_ast(&src.value).map(Into::into); 387 hover_markup(docs, short_label, mod_path)
379 hover_markup(docs, src.value.short_label(), mod_path)
380 } 388 }
381} 389}
382 390