Repository: rust-lang/rust-analyzer
Pull request #12519 (2022-06-13 09:57:48)

feat: On assoc item name hover, render trait decl docs


Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 193ef904de..3f62a2cd33 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -628,42 +628,35 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
         }
 
         DefDiagnosticKind::UnresolvedProcMacro { ast } => {
-            let (node, precise_location, macro_name) = match ast {
+            let mut precise_location = None;
+            let (node, macro_name) = match ast {
                 MacroCallKind::FnLike { ast_id, .. } => {
                     let node = ast_id.to_node(db.upcast());
-                    (
-                        ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
-                        node.path().map(|it| it.syntax().text_range()),
-                        node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
-                    )
+                    (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
                 }
                 MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
                     let node = ast_id.to_node(db.upcast());
+
                     // Compute the precise location of the macro name's token in the derive
                     // list.
                     let token = (|| {
-                        let derive_attr = node
-                            .doc_comments_and_attrs()
-                            .nth(*derive_attr_index as usize)
-                            .and_then(Either::left)?;
-                        let token_tree = derive_attr.meta()?.token_tree()?;
-                        let group_by = token_tree
+                        let derive_attr = node.attrs().nth(*derive_attr_index as usize)?;
+                        derive_attr
                             .syntax()
                             .children_with_tokens()
                             .filter_map(|elem| match elem {
                                 syntax::NodeOrToken::Token(tok) => Some(tok),
                                 _ => None,
                             })
-                            .group_by(|t| t.kind() == T![,]);
-                        let (_, mut group) = group_by
+                            .group_by(|t| t.kind() == T![,])
                             .into_iter()
                             .filter(|&(comma, _)| !comma)
-                            .nth(*derive_index as usize)?;
-                        group.find(|t| t.kind() == T![ident])
+                            .nth(*derive_index as usize)
+                            .and_then(|(_, mut g)| g.find(|t| t.kind() == T![ident]))
                     })();
+                    precise_location = token.as_ref().map(|tok| tok.text_range());
                     (
                         ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
-                        token.as_ref().map(|tok| tok.text_range()),
                         token.as_ref().map(ToString::to_string),
                     )
                 }
@@ -674,10 +667,8 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
                         .nth((*invoc_attr_index) as usize)
                         .and_then(Either::left)
                         .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
-
                     (
                         ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
-                        Some(attr.syntax().text_range()),
                         attr.path()
                             .and_then(|path| path.segment())
                             .and_then(|seg| seg.name_ref())
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
index fea3a0e832..fde1d1323f 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
@@ -8,25 +8,20 @@ use crate::{Diagnostic, DiagnosticsContext, Severity};
 //
 // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
 // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
-// enable support for procedural macros (see `rust-analyzer.procMacro.attributes.enable`).
+// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
 pub(crate) fn unresolved_proc_macro(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::UnresolvedProcMacro,
-    attr_proc_macros_enabled: bool,
 ) -> Diagnostic {
     // Use more accurate position if available.
     let display_range = d
         .precise_location
         .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range);
+    // FIXME: it would be nice to tell the user whether proc macros are currently disabled
     let message = match &d.macro_name {
         Some(name) => format!("proc macro `{}` not expanded", name),
         None => "proc macro not expanded".to_string(),
     };
-    let message = format!(
-        "{message}{}",
-        if attr_proc_macros_enabled { "" } else { " (attribute macro expansion is disabled)" }
-    );
 
-    Diagnostic::new("unresolved-proc-macro", message, display_range)
-        .severity(if attr_proc_macros_enabled { Severity::Error } else { Severity::WeakWarning })
+    Diagnostic::new("unresolved-proc-macro", message, display_range).severity(Severity::WeakWarning)
 }
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 1cbe8ad72b..1d4ea461d0 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -139,7 +139,6 @@ impl Default for ExprFillDefaultMode {
 
 #[derive(Default, Debug, Clone)]
 pub struct DiagnosticsConfig {
-    pub attr_proc_macros_enabled: bool,
     pub disable_experimental: bool,
     pub disabled: FxHashSet<String>,
     pub expr_fill_default: ExprFillDefaultMode,
@@ -205,7 +204,7 @@ pub fn diagnostics(
             AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
             AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
             AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
-            AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.attr_proc_macros_enabled),
+            AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
             AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
 
             AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 0676220272..1cb67c6657 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -372,7 +372,20 @@ pub(super) fn definition(
         Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))),
     };
 
-    markup(docs.filter(|_| config.documentation.is_some()).map(Into::into), label, mod_path)
+    let docs = match config.documentation {
+        Some(_) => docs.or_else(|| {
+            // docs are missing, for assoc items of trait impls try to fall back to the docs of the
+            // original item of the trait
+            let assoc = def.as_assoc_item(db)?;
+            let trait_ = assoc.containing_trait_impl(db)?;
+            let name = Some(assoc.name(db)?);
+            let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
+            item.docs(db)
+        }),
+        None => None,
+    };
+    let docs = docs.filter(|_| config.documentation.is_some()).map(Into::into);
+    markup(docs, label, mod_path)
 }
 
 fn render_builtin_attr(db: &RootDatabase, attr: hir::BuiltinAttr) -> Option<Markup> {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index fcc4cbebc5..9fd1958999 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -856,7 +856,6 @@ impl Config {
 
     pub fn diagnostics(&self) -> DiagnosticsConfig {
         DiagnosticsConfig {
-            attr_proc_macros_enabled: self.expand_proc_attr_macros(),
             disable_experimental: !self.data.diagnostics_experimental_enable,
             disabled: self.data.diagnostics_disabled.clone(),
             expr_fill_default: match self.data.assist_expressionFillDefault {
@@ -894,7 +893,7 @@ impl Config {
     }
 
     pub fn expand_proc_attr_macros(&self) -> bool {
-        self.data.procMacro_enable && self.data.procMacro_attributes_enable
+        self.data.procMacro_attributes_enable
     }
 
     pub fn files(&self) -> FilesConfig {


Test patch:
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index c95a0e4005..8eb16aab29 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4888,3 +4888,33 @@ enum Enum {
         "#]],
     );
 }
+
+#[test]
+fn hover_trait_impl_assoc_item_def_doc_forwarding() {
+    check(
+        r#"
+trait T {
+    /// Trait docs
+    fn func() {}
+}
+impl T for () {
+    fn func$0() {}
+}
+"#,
+        expect![[r#"
+            *func*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            fn func()
+            ```
+
+            ---
+
+            Trait docs
+        "#]],
+    );
+}