Unnamed repository; edit this file 'description' to name the repository.
align with rustc behavior
| -rw-r--r-- | crates/hir-def/src/attrs.rs | 11 | ||||
| -rw-r--r-- | crates/hir-def/src/attrs/docs.rs | 68 | ||||
| -rw-r--r-- | crates/ide/src/hover/tests.rs | 54 |
3 files changed, 43 insertions, 90 deletions
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs index 3dbbafdd51..aa7dad8bf1 100644 --- a/crates/hir-def/src/attrs.rs +++ b/crates/hir-def/src/attrs.rs @@ -965,20 +965,13 @@ impl AttrFlags { pub fn docs(db: &dyn DefDatabase, owner: AttrDefId) -> Option<Box<Docs>> { let (source, outer_mod_decl, _extra_crate_attrs, krate) = attrs_source(db, owner); let inner_attrs_node = source.value.inner_attributes_node(); - let parent = if outer_mod_decl.is_some() - && let AttrDefId::ModuleId(module_id) = owner - { - module_id.containing_module(db) - } else { - None - }; // Note: we don't have to pass down `_extra_crate_attrs` here, since `extract_docs` // does not handle crate-level attributes related to docs. // See: https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html#at-the-crate-level self::docs::extract_docs( db, krate, - &|| (parent.map(|it| it.resolver(db)), resolver_for_attr_def_id(db, owner)), + &|| resolver_for_attr_def_id(db, owner), &|| krate.cfg_options(db), source, outer_mod_decl, @@ -1001,7 +994,7 @@ impl AttrFlags { self::docs::extract_docs( db, krate, - &|| (None, variant.resolver(db)), + &|| variant.resolver(db), &|| cfg_options, field, None, diff --git a/crates/hir-def/src/attrs/docs.rs b/crates/hir-def/src/attrs/docs.rs index 16e813bc5f..a0665dfecd 100644 --- a/crates/hir-def/src/attrs/docs.rs +++ b/crates/hir-def/src/attrs/docs.rs @@ -418,10 +418,10 @@ fn extend_with_attrs<'a, 'db>( indent: &mut usize, get_cfg_options: &dyn Fn() -> &'a CfgOptions, cfg_options: &mut Option<&'a CfgOptions>, - make_resolver: &dyn Fn() -> Option<Resolver<'db>>, + make_resolver: &dyn Fn() -> Resolver<'db>, ) { // Lazily initialised when we first encounter a `#[doc = macro!()]`. - let mut expander: Option<Option<(DocMacroExpander<'db>, DocExprSourceCtx<'db>)>> = None; + let mut expander: Option<(DocMacroExpander<'db>, DocExprSourceCtx<'db>)> = None; // FIXME: `#[cfg_attr(..., doc = macro!())]` skips macro expansion because // `top_attr` points to the `cfg_attr` node, not the inner `doc = macro!()`. @@ -457,32 +457,31 @@ fn extend_with_attrs<'a, 'db>( top_attr.as_simple_call().is_some_and(|(name, _)| name == "cfg_attr"); if !is_from_cfg_attr && let Some(expr) = top_attr.expr() - && let Some((exp, ctx)) = expander - .get_or_insert_with(|| { - make_resolver().map(|resolver| { - let def_map = resolver.top_level_def_map(); - let recursion_limit = def_map.recursion_limit() as usize; - ( - DocMacroExpander { - db, - krate, - recursion_depth: 0, - recursion_limit, - }, - DocExprSourceCtx { - resolver, - file_id, - ast_id_map: db.ast_id_map(file_id), - span_map: db.span_map(file_id), - }, - ) - }) - }) - .as_mut() - && let Some(expanded) = - expand_doc_expr_via_macro_pipeline(exp, ctx, expr) { - result.extend_with_unmapped_doc_str(&expanded, indent); + let (exp, ctx) = expander.get_or_insert_with(|| { + let resolver = make_resolver(); + let def_map = resolver.top_level_def_map(); + let recursion_limit = def_map.recursion_limit() as usize; + ( + DocMacroExpander { + db, + krate, + recursion_depth: 0, + recursion_limit, + }, + DocExprSourceCtx { + resolver, + file_id, + ast_id_map: db.ast_id_map(file_id), + span_map: db.span_map(file_id), + }, + ) + }); + if let Some(expanded) = + expand_doc_expr_via_macro_pipeline(exp, ctx, expr) + { + result.extend_with_unmapped_doc_str(&expanded, indent); + } } } _ => {} @@ -496,10 +495,7 @@ fn extend_with_attrs<'a, 'db>( pub(crate) fn extract_docs<'a, 'db>( db: &'db dyn DefDatabase, krate: Crate, - // Returns (outer_resolver, inline_resolver). - // `outer_resolver` is `Some` only for outlined modules (`mod foo;`) where outer docs - // should be resolved in the parent module's scope. - resolvers: &dyn Fn() -> (Option<Resolver<'db>>, Resolver<'db>), + resolver: &dyn Fn() -> Resolver<'db>, get_cfg_options: &dyn Fn() -> &'a CfgOptions, source: InFile<ast::AnyHasAttrs>, outer_mod_decl: Option<InFile<ast::Module>>, @@ -519,8 +515,7 @@ pub(crate) fn extract_docs<'a, 'db>( if let Some(outer_mod_decl) = outer_mod_decl { let mut indent = usize::MAX; - // For outer docs (the `mod foo;` declaration), use the parent module's resolver - // so that macros are resolved in the parent's scope. + // For outer docs (the `mod foo;` declaration), use the module's own resolver. extend_with_attrs( &mut result, db, @@ -531,7 +526,7 @@ pub(crate) fn extract_docs<'a, 'db>( &mut indent, get_cfg_options, &mut cfg_options, - &|| resolvers().0, + resolver, ); result.remove_indent(indent, 0); result.outline_mod = Some((outer_mod_decl.file_id, result.docs_source_map.len())); @@ -539,7 +534,6 @@ pub(crate) fn extract_docs<'a, 'db>( let inline_source_map_start = result.docs_source_map.len(); let mut indent = usize::MAX; - let inline_resolver = &|| Some(resolvers().1); // For inline docs, use the item's own resolver. extend_with_attrs( &mut result, @@ -551,7 +545,7 @@ pub(crate) fn extract_docs<'a, 'db>( &mut indent, get_cfg_options, &mut cfg_options, - inline_resolver, + resolver, ); if let Some(inner_attrs_node) = &inner_attrs_node { result.inline_inner_docs_start = Some(TextSize::of(&result.docs)); @@ -565,7 +559,7 @@ pub(crate) fn extract_docs<'a, 'db>( &mut indent, get_cfg_options, &mut cfg_options, - inline_resolver, + resolver, ); } result.remove_indent(indent, inline_source_map_start); diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 2ca43096dd..882aa041ce 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -11660,18 +11660,21 @@ struct Bar { } #[test] -fn test_hover_doc_attr_macro_on_outlined_mod_resolves_from_parent() { - // Outer doc-macro on `mod foo;` should resolve from the parent module, - // and combine with inner `//!` docs from the module file. +fn test_hover_doc_attr_macro_on_outlined_mod() { + // Outer doc-macro on `mod foo;` resolves from inside the module's scope + // (matching rustc behavior), and combines with inner `//!` docs from the module file. check( r#" //- /main.rs -macro_rules! doc_str { - () => { "expanded from parent" }; +mod mac { + macro_rules! doc_str { + () => { "expanded from macro" }; + } + pub(crate) use doc_str; } /// plain outer doc -#[doc = doc_str!()] +#[doc = super::mac::doc_str!()] mod foo$0; //- /foo.rs @@ -11692,45 +11695,8 @@ pub struct Bar; --- plain outer doc - expanded from parent + expanded from macro inner module docs "#]], ); } - -#[test] -fn test_hover_doc_attr_inner_doc_macro() { - // Inner doc attribute with macro expansion (`#![doc = macro!()]`) - check( - r#" -macro_rules! doc_str { - () => { "inner doc from macro" }; -} - -/// outer doc -/// -mod foo$0 { - #![doc = doc_str!()] - - pub struct Bar; -} -"#, - expect![[r#" - *foo* - - ```rust - ra_test_fixture - ``` - - ```rust - mod foo - ``` - - --- - - outer doc - - inner doc from macro - "#]], - ); -} |