Skip to content

Commit 9f6b425

Browse files
committed
fix: resolve doc path if outer comments exist on module and replace from cfg_attr bit to doc_place bit
Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com>
1 parent d30deb5 commit 9f6b425

File tree

5 files changed

+99
-34
lines changed

5 files changed

+99
-34
lines changed

crates/hir-expand/src/attrs.rs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,8 @@ impl RawAttrs {
129129
.cloned()
130130
.chain(b.slice.iter().map(|it| {
131131
let mut it = it.clone();
132-
it.id.id = (it.id.ast_index() as u32 + last_ast_index)
133-
| ((it.id.cfg_attr_index().unwrap_or(0) as u32)
134-
<< AttrId::AST_INDEX_BITS);
132+
let id = it.id.ast_index() as u32 + last_ast_index;
133+
it.id = AttrId::new(id as usize, it.id.is_inner_attr());
135134
it
136135
}))
137136
.collect::<Vec<_>>();
@@ -175,25 +174,21 @@ pub struct AttrId {
175174
// FIXME: This only handles a single level of cfg_attr nesting
176175
// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
177176
impl AttrId {
178-
const CFG_ATTR_BITS: usize = 7;
179177
const AST_INDEX_MASK: usize = 0x00FF_FFFF;
180-
const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize;
181-
const CFG_ATTR_SET_BITS: u32 = 1 << 31;
178+
const INNER_ATTR_BIT: usize = 1 << 31;
182179

183-
pub fn ast_index(&self) -> usize {
184-
self.id as usize & Self::AST_INDEX_MASK
180+
pub fn new(id: usize, is_inner: bool) -> Self {
181+
let id = id & Self::AST_INDEX_MASK;
182+
let id = if is_inner { id | Self::INNER_ATTR_BIT } else { id };
183+
Self { id: id as u32 }
185184
}
186185

187-
pub fn cfg_attr_index(&self) -> Option<usize> {
188-
if self.id & Self::CFG_ATTR_SET_BITS == 0 {
189-
None
190-
} else {
191-
Some(self.id as usize >> Self::AST_INDEX_BITS)
192-
}
186+
pub fn ast_index(&self) -> usize {
187+
self.id as usize & Self::AST_INDEX_MASK
193188
}
194189

195-
pub fn with_cfg_attr(self, idx: usize) -> AttrId {
196-
AttrId { id: self.id | ((idx as u32) << Self::AST_INDEX_BITS) | Self::CFG_ATTR_SET_BITS }
190+
pub fn is_inner_attr(&self) -> bool {
191+
(self.id as usize) & Self::INNER_ATTR_BIT != 0
197192
}
198193
}
199194

@@ -333,10 +328,7 @@ impl Attr {
333328
None => return smallvec![self.clone()],
334329
};
335330
let index = self.id;
336-
let attrs = parts
337-
.enumerate()
338-
.take(1 << AttrId::CFG_ATTR_BITS)
339-
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
331+
let attrs = parts.filter_map(|attr| Attr::from_tt(db, attr, index));
340332

341333
let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
342334
let cfg = CfgExpr::parse(&cfg);
@@ -467,13 +459,18 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
467459
pub fn collect_attrs(
468460
owner: &dyn ast::HasAttrs,
469461
) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
470-
let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
471-
let outer_attrs =
472-
ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
462+
let inner_attrs =
463+
inner_attributes(owner.syntax()).into_iter().flatten().map(|attr| (attr, true));
464+
let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
465+
.filter(|el| match el {
473466
Either::Left(attr) => attr.kind().is_outer(),
474467
Either::Right(comment) => comment.is_outer(),
475-
});
476-
outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr))
468+
})
469+
.map(|attr| (attr, false));
470+
outer_attrs
471+
.chain(inner_attrs)
472+
.enumerate()
473+
.map(|(id, (attr, is_inner))| (AttrId::new(id, is_inner), attr))
477474
}
478475

479476
fn inner_attributes(

crates/hir/src/attrs.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,32 @@ impl HasAttrs for crate::Crate {
105105
/// Resolves the item `link` points to in the scope of `def`.
106106
pub fn resolve_doc_path_on(
107107
db: &dyn HirDatabase,
108-
def: impl HasAttrs,
108+
def: impl HasAttrs + Copy,
109109
link: &str,
110110
ns: Option<Namespace>,
111111
) -> Option<DocLinkDef> {
112-
resolve_doc_path_on_(db, link, def.attr_id(), ns)
112+
let is_inner =
113+
def.attrs(db).by_key(&intern::sym::doc).attrs().all(|attr| attr.id.is_inner_attr());
114+
resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner)
113115
}
114116

115117
fn resolve_doc_path_on_(
116118
db: &dyn HirDatabase,
117119
link: &str,
118120
attr_id: AttrDefId,
119121
ns: Option<Namespace>,
122+
is_inner: bool,
120123
) -> Option<DocLinkDef> {
121124
let resolver = match attr_id {
122-
AttrDefId::ModuleId(it) => it.resolver(db),
125+
AttrDefId::ModuleId(it) => {
126+
if is_inner {
127+
it.resolver(db)
128+
} else if let Some(parent) = Module::from(it).parent(db) {
129+
parent.id.resolver(db)
130+
} else {
131+
it.resolver(db)
132+
}
133+
}
123134
AttrDefId::FieldId(it) => it.parent.resolver(db),
124135
AttrDefId::AdtId(it) => it.resolver(db),
125136
AttrDefId::FunctionId(it) => it.resolver(db),

crates/ide/src/doc_links/tests.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,40 @@ struct S$0(i32);
575575
);
576576
}
577577

578+
#[test]
579+
fn doc_links_module() {
580+
check_doc_links(
581+
r#"
582+
/// [`M`]
583+
/// [`M::f`]
584+
mod M$0 {
585+
//^ M
586+
#![doc = "inner_item[`M::S`]"]
587+
588+
pub fn f() {}
589+
//^ M::f
590+
pub struct S;
591+
//^ M::S
592+
}
593+
"#,
594+
);
595+
596+
check_doc_links(
597+
r#"
598+
mod M$0 {
599+
//^ super::M
600+
//! [`super::M`]
601+
//! [`super::M::f`]
602+
//! [`super::M::S`]
603+
pub fn f() {}
604+
//^ super::M::f
605+
pub struct S;
606+
//^ super::M::S
607+
}
608+
"#,
609+
);
610+
}
611+
578612
#[test]
579613
fn rewrite_html_root_url() {
580614
check_rewrite(
@@ -690,6 +724,29 @@ fn rewrite_intra_doc_link_with_anchor() {
690724
);
691725
}
692726

727+
#[test]
728+
fn rewrite_module() {
729+
check_rewrite(
730+
r#"
731+
//- /main.rs crate:foo
732+
/// [Foo]
733+
pub mod $0Foo{
734+
};
735+
"#,
736+
expect![[r#"[Foo](https://docs.rs/foo/*/foo/Foo/index.html)"#]],
737+
);
738+
739+
check_rewrite(
740+
r#"
741+
//- /main.rs crate:foo
742+
pub mod $0Foo{
743+
//! [super::Foo]
744+
};
745+
"#,
746+
expect![[r#"[super::Foo](https://docs.rs/foo/*/foo/Foo/index.html)"#]],
747+
);
748+
}
749+
693750
#[test]
694751
fn rewrite_intra_doc_link_to_associated_item() {
695752
check_rewrite(

crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
4141
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
4242
</style>
43-
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
43+
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[foo::Struct]</span>
4444
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
45-
<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
45+
<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[foo::Struct]</span>
4646
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
4747

4848
<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>

crates/ide/src/syntax_highlighting/tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,9 +1072,9 @@ fn test_mod_hl_injection() {
10721072
check_highlighting(
10731073
r##"
10741074
//- /foo.rs
1075-
//! [Struct]
1075+
//! [foo::Struct]
10761076
//! This is an intra doc injection test for modules
1077-
//! [Struct]
1077+
//! [foo::Struct]
10781078
//! This is an intra doc injection test for modules
10791079
10801080
pub struct Struct;
@@ -1097,9 +1097,9 @@ mod foo;
10971097
/// This is an intra doc injection test for modules
10981098
mod foo;
10991099
//- /foo.rs
1100-
//! [Struct]
1100+
//! [foo::Struct]
11011101
//! This is an intra doc injection test for modules
1102-
//! [Struct]
1102+
//! [foo::Struct]
11031103
//! This is an intra doc injection test for modules
11041104
11051105
pub struct Struct;

0 commit comments

Comments
 (0)