]> git.lizzy.rs Git - rust.git/commitdiff
Enable hover and autocomplete docs on macro generated items
authorAaron Loucks <aloucks@cofront.net>
Sat, 30 May 2020 18:21:06 +0000 (14:21 -0400)
committerAaron Loucks <aloucks@cofront.net>
Wed, 3 Jun 2020 10:46:07 +0000 (06:46 -0400)
crates/ra_hir_def/src/attr.rs
crates/ra_hir_def/src/docs.rs
crates/ra_hir_expand/src/name.rs
crates/ra_ide/src/hover.rs
crates/ra_syntax/src/ast/traits.rs

index 8b6c0bedee78bc8daf2ffb90af73bbaeca3fe6a9..2eeba057299185a1b1ad308052308740de4645e9 100644 (file)
@@ -87,12 +87,18 @@ pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) ->
     }
 
     pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
+        let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map(
+            |docs_text| Attr {
+                input: Some(AttrInput::Literal(SmolStr::new(docs_text))),
+                path: ModPath::from(hir_expand::name!(doc)),
+            },
+        );
         let mut attrs = owner.attrs().peekable();
         let entries = if attrs.peek().is_none() {
             // Avoid heap allocation
             None
         } else {
-            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
+            Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect())
         };
         Attrs { entries }
     }
index b221ae1cece3fc9a44163382c302263d5ac2d408..74b9f8199c1081dd8328ee9d6e846e4805249526 100644 (file)
@@ -70,6 +70,45 @@ pub(crate) fn documentation_query(
     }
 }
 
-pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
-    node.doc_comment_text().map(|it| Documentation::new(&it))
+pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation>
+where
+    N: ast::DocCommentsOwner + ast::AttrsOwner,
+{
+    let doc_comment_text = node.doc_comment_text();
+    let doc_attr_text = expand_doc_attrs(node);
+    let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
+    docs.map(|it| Documentation::new(&it))
+}
+
+fn merge_doc_comments_and_attrs(
+    doc_comment_text: Option<String>,
+    doc_attr_text: Option<String>,
+) -> Option<String> {
+    match (doc_comment_text, doc_attr_text) {
+        (Some(mut comment_text), Some(attr_text)) => {
+            comment_text.push_str("\n\n");
+            comment_text.push_str(&attr_text);
+            Some(comment_text)
+        }
+        (Some(comment_text), None) => Some(comment_text),
+        (None, Some(attr_text)) => Some(attr_text),
+        (None, None) => None,
+    }
+}
+
+fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> {
+    let mut docs = String::new();
+    for attr in owner.attrs() {
+        if let Some(("doc", value)) =
+            attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str()))
+        {
+            docs.push_str(value);
+            docs.push_str("\n\n");
+        }
+    }
+    if docs.is_empty() {
+        None
+    } else {
+        Some(docs)
+    }
 }
index ea495cb11a2ba736e759a054fd79112bbf20deb6..660bdfe3365b2f20182ede8f1c4abd356e049669 100644 (file)
@@ -153,6 +153,7 @@ macro_rules! known_names {
         str,
         // Special names
         macro_rules,
+        doc,
         // Components of known path (value or mod name)
         std,
         core,
index d96cb55969180c582b76c36ebce2ae6eafb049fc..e25a7dacf01bda13f7262181309bb9c70f5e14cd 100644 (file)
@@ -169,13 +169,19 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
     return match def {
         Definition::Macro(it) => {
             let src = it.source(db);
-            hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path)
+            let doc_comment_text = src.value.doc_comment_text();
+            let doc_attr_text = expand_doc_attrs(&src.value);
+            let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
+            hover_text(docs, Some(macro_label(&src.value)), mod_path)
         }
         Definition::Field(it) => {
             let src = it.source(db);
             match src.value {
                 FieldSource::Named(it) => {
-                    hover_text(it.doc_comment_text(), it.short_label(), mod_path)
+                    let doc_comment_text = it.doc_comment_text();
+                    let doc_attr_text = expand_doc_attrs(&it);
+                    let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
+                    hover_text(docs, it.short_label(), mod_path)
                 }
                 _ => None,
             }
@@ -183,7 +189,10 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
         Definition::ModuleDef(it) => match it {
             ModuleDef::Module(it) => match it.definition_source(db).value {
                 ModuleSource::Module(it) => {
-                    hover_text(it.doc_comment_text(), it.short_label(), mod_path)
+                    let doc_comment_text = it.doc_comment_text();
+                    let doc_attr_text = expand_doc_attrs(&it);
+                    let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
+                    hover_text(docs, it.short_label(), mod_path)
                 }
                 _ => None,
             },
@@ -208,10 +217,46 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
     fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String>
     where
         D: HasSource<Ast = A>,
-        A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
+        A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner,
     {
         let src = def.source(db);
-        hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path)
+        let doc_comment_text = src.value.doc_comment_text();
+        let doc_attr_text = expand_doc_attrs(&src.value);
+        let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
+        hover_text(docs, src.value.short_label(), mod_path)
+    }
+}
+
+fn merge_doc_comments_and_attrs(
+    doc_comment_text: Option<String>,
+    doc_attr_text: Option<String>,
+) -> Option<String> {
+    match (doc_comment_text, doc_attr_text) {
+        (Some(mut comment_text), Some(attr_text)) => {
+            comment_text.push_str("\n\n");
+            comment_text.push_str(&attr_text);
+            Some(comment_text)
+        }
+        (Some(comment_text), None) => Some(comment_text),
+        (None, Some(attr_text)) => Some(attr_text),
+        (None, None) => None,
+    }
+}
+
+fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> {
+    let mut docs = String::new();
+    for attr in owner.attrs() {
+        if let Some(("doc", value)) =
+            attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str()))
+        {
+            docs.push_str(value);
+            docs.push_str("\n\n");
+        }
+    }
+    if docs.is_empty() {
+        None
+    } else {
+        Some(docs)
     }
 }
 
index bfc05e08bf2438f37e08573c9de7767099f4108a..a8f2454fd96e861209a9345911cef983ce41ace4 100644 (file)
@@ -83,13 +83,22 @@ fn doc_comments(&self) -> CommentIter {
         CommentIter { iter: self.syntax().children_with_tokens() }
     }
 
+    fn doc_comment_text(&self) -> Option<String> {
+        self.doc_comments().doc_comment_text()
+    }
+}
+
+impl CommentIter {
+    pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> CommentIter {
+        CommentIter { iter: syntax_node.children_with_tokens() }
+    }
+
     /// Returns the textual content of a doc comment block as a single string.
     /// That is, strips leading `///` (+ optional 1 character of whitespace),
     /// trailing `*/`, trailing whitespace and then joins the lines.
-    fn doc_comment_text(&self) -> Option<String> {
+    pub fn doc_comment_text(self) -> Option<String> {
         let mut has_comments = false;
         let docs = self
-            .doc_comments()
             .filter(|comment| comment.kind().doc.is_some())
             .map(|comment| {
                 has_comments = true;