mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 21:25:25 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									d30deb58fe
								
							
						
					
					
						commit
						9f6b4255c2
					
				
					 5 changed files with 99 additions and 34 deletions
				
			
		| 
						 | 
					@ -129,9 +129,8 @@ impl RawAttrs {
 | 
				
			||||||
                    .cloned()
 | 
					                    .cloned()
 | 
				
			||||||
                    .chain(b.slice.iter().map(|it| {
 | 
					                    .chain(b.slice.iter().map(|it| {
 | 
				
			||||||
                        let mut it = it.clone();
 | 
					                        let mut it = it.clone();
 | 
				
			||||||
                        it.id.id = (it.id.ast_index() as u32 + last_ast_index)
 | 
					                        let id = it.id.ast_index() as u32 + last_ast_index;
 | 
				
			||||||
                            | ((it.id.cfg_attr_index().unwrap_or(0) as u32)
 | 
					                        it.id = AttrId::new(id as usize, it.id.is_inner_attr());
 | 
				
			||||||
                                << AttrId::AST_INDEX_BITS);
 | 
					 | 
				
			||||||
                        it
 | 
					                        it
 | 
				
			||||||
                    }))
 | 
					                    }))
 | 
				
			||||||
                    .collect::<Vec<_>>();
 | 
					                    .collect::<Vec<_>>();
 | 
				
			||||||
| 
						 | 
					@ -175,25 +174,21 @@ pub struct AttrId {
 | 
				
			||||||
// FIXME: This only handles a single level of cfg_attr nesting
 | 
					// FIXME: This only handles a single level of cfg_attr nesting
 | 
				
			||||||
// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
 | 
					// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
 | 
				
			||||||
impl AttrId {
 | 
					impl AttrId {
 | 
				
			||||||
    const CFG_ATTR_BITS: usize = 7;
 | 
					 | 
				
			||||||
    const AST_INDEX_MASK: usize = 0x00FF_FFFF;
 | 
					    const AST_INDEX_MASK: usize = 0x00FF_FFFF;
 | 
				
			||||||
    const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize;
 | 
					    const INNER_ATTR_BIT: usize = 1 << 31;
 | 
				
			||||||
    const CFG_ATTR_SET_BITS: u32 = 1 << 31;
 | 
					
 | 
				
			||||||
 | 
					    pub fn new(id: usize, is_inner: bool) -> Self {
 | 
				
			||||||
 | 
					        let id = id & Self::AST_INDEX_MASK;
 | 
				
			||||||
 | 
					        let id = if is_inner { id | Self::INNER_ATTR_BIT } else { id };
 | 
				
			||||||
 | 
					        Self { id: id as u32 }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn ast_index(&self) -> usize {
 | 
					    pub fn ast_index(&self) -> usize {
 | 
				
			||||||
        self.id as usize & Self::AST_INDEX_MASK
 | 
					        self.id as usize & Self::AST_INDEX_MASK
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn cfg_attr_index(&self) -> Option<usize> {
 | 
					    pub fn is_inner_attr(&self) -> bool {
 | 
				
			||||||
        if self.id & Self::CFG_ATTR_SET_BITS == 0 {
 | 
					        (self.id as usize) & Self::INNER_ATTR_BIT != 0
 | 
				
			||||||
            None
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            Some(self.id as usize >> Self::AST_INDEX_BITS)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn with_cfg_attr(self, idx: usize) -> AttrId {
 | 
					 | 
				
			||||||
        AttrId { id: self.id | ((idx as u32) << Self::AST_INDEX_BITS) | Self::CFG_ATTR_SET_BITS }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -333,10 +328,7 @@ impl Attr {
 | 
				
			||||||
            None => return smallvec![self.clone()],
 | 
					            None => return smallvec![self.clone()],
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let index = self.id;
 | 
					        let index = self.id;
 | 
				
			||||||
        let attrs = parts
 | 
					        let attrs = parts.filter_map(|attr| Attr::from_tt(db, attr, index));
 | 
				
			||||||
            .enumerate()
 | 
					 | 
				
			||||||
            .take(1 << AttrId::CFG_ATTR_BITS)
 | 
					 | 
				
			||||||
            .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
 | 
					        let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
 | 
				
			||||||
        let cfg = CfgExpr::parse(&cfg);
 | 
					        let cfg = CfgExpr::parse(&cfg);
 | 
				
			||||||
| 
						 | 
					@ -467,13 +459,18 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
 | 
				
			||||||
pub fn collect_attrs(
 | 
					pub fn collect_attrs(
 | 
				
			||||||
    owner: &dyn ast::HasAttrs,
 | 
					    owner: &dyn ast::HasAttrs,
 | 
				
			||||||
) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
 | 
					) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
 | 
				
			||||||
    let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
 | 
					    let inner_attrs =
 | 
				
			||||||
    let outer_attrs =
 | 
					        inner_attributes(owner.syntax()).into_iter().flatten().map(|attr| (attr, true));
 | 
				
			||||||
        ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
 | 
					    let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
 | 
				
			||||||
 | 
					        .filter(|el| match el {
 | 
				
			||||||
            Either::Left(attr) => attr.kind().is_outer(),
 | 
					            Either::Left(attr) => attr.kind().is_outer(),
 | 
				
			||||||
            Either::Right(comment) => comment.is_outer(),
 | 
					            Either::Right(comment) => comment.is_outer(),
 | 
				
			||||||
        });
 | 
					        })
 | 
				
			||||||
    outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr))
 | 
					        .map(|attr| (attr, false));
 | 
				
			||||||
 | 
					    outer_attrs
 | 
				
			||||||
 | 
					        .chain(inner_attrs)
 | 
				
			||||||
 | 
					        .enumerate()
 | 
				
			||||||
 | 
					        .map(|(id, (attr, is_inner))| (AttrId::new(id, is_inner), attr))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn inner_attributes(
 | 
					fn inner_attributes(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -105,11 +105,13 @@ impl HasAttrs for crate::Crate {
 | 
				
			||||||
/// Resolves the item `link` points to in the scope of `def`.
 | 
					/// Resolves the item `link` points to in the scope of `def`.
 | 
				
			||||||
pub fn resolve_doc_path_on(
 | 
					pub fn resolve_doc_path_on(
 | 
				
			||||||
    db: &dyn HirDatabase,
 | 
					    db: &dyn HirDatabase,
 | 
				
			||||||
    def: impl HasAttrs,
 | 
					    def: impl HasAttrs + Copy,
 | 
				
			||||||
    link: &str,
 | 
					    link: &str,
 | 
				
			||||||
    ns: Option<Namespace>,
 | 
					    ns: Option<Namespace>,
 | 
				
			||||||
) -> Option<DocLinkDef> {
 | 
					) -> Option<DocLinkDef> {
 | 
				
			||||||
    resolve_doc_path_on_(db, link, def.attr_id(), ns)
 | 
					    let is_inner =
 | 
				
			||||||
 | 
					        def.attrs(db).by_key(&intern::sym::doc).attrs().all(|attr| attr.id.is_inner_attr());
 | 
				
			||||||
 | 
					    resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn resolve_doc_path_on_(
 | 
					fn resolve_doc_path_on_(
 | 
				
			||||||
| 
						 | 
					@ -117,9 +119,18 @@ fn resolve_doc_path_on_(
 | 
				
			||||||
    link: &str,
 | 
					    link: &str,
 | 
				
			||||||
    attr_id: AttrDefId,
 | 
					    attr_id: AttrDefId,
 | 
				
			||||||
    ns: Option<Namespace>,
 | 
					    ns: Option<Namespace>,
 | 
				
			||||||
 | 
					    is_inner: bool,
 | 
				
			||||||
) -> Option<DocLinkDef> {
 | 
					) -> Option<DocLinkDef> {
 | 
				
			||||||
    let resolver = match attr_id {
 | 
					    let resolver = match attr_id {
 | 
				
			||||||
        AttrDefId::ModuleId(it) => it.resolver(db),
 | 
					        AttrDefId::ModuleId(it) => {
 | 
				
			||||||
 | 
					            if is_inner {
 | 
				
			||||||
 | 
					                it.resolver(db)
 | 
				
			||||||
 | 
					            } else if let Some(parent) = Module::from(it).parent(db) {
 | 
				
			||||||
 | 
					                parent.id.resolver(db)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                it.resolver(db)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        AttrDefId::FieldId(it) => it.parent.resolver(db),
 | 
					        AttrDefId::FieldId(it) => it.parent.resolver(db),
 | 
				
			||||||
        AttrDefId::AdtId(it) => it.resolver(db),
 | 
					        AttrDefId::AdtId(it) => it.resolver(db),
 | 
				
			||||||
        AttrDefId::FunctionId(it) => it.resolver(db),
 | 
					        AttrDefId::FunctionId(it) => it.resolver(db),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -575,6 +575,40 @@ struct S$0(i32);
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn doc_links_module() {
 | 
				
			||||||
 | 
					    check_doc_links(
 | 
				
			||||||
 | 
					        r#"
 | 
				
			||||||
 | 
					/// [`M`]
 | 
				
			||||||
 | 
					/// [`M::f`]
 | 
				
			||||||
 | 
					mod M$0 {
 | 
				
			||||||
 | 
					  //^ M
 | 
				
			||||||
 | 
					  #![doc = "inner_item[`M::S`]"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn f() {}
 | 
				
			||||||
 | 
					         //^ M::f
 | 
				
			||||||
 | 
					    pub struct S;
 | 
				
			||||||
 | 
					             //^ M::S
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_doc_links(
 | 
				
			||||||
 | 
					        r#"
 | 
				
			||||||
 | 
					mod M$0 {
 | 
				
			||||||
 | 
					  //^ super::M
 | 
				
			||||||
 | 
					    //! [`super::M`]
 | 
				
			||||||
 | 
					    //! [`super::M::f`]
 | 
				
			||||||
 | 
					    //! [`super::M::S`]
 | 
				
			||||||
 | 
					    pub fn f() {}
 | 
				
			||||||
 | 
					         //^ super::M::f
 | 
				
			||||||
 | 
					    pub struct S;
 | 
				
			||||||
 | 
					             //^ super::M::S
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn rewrite_html_root_url() {
 | 
					fn rewrite_html_root_url() {
 | 
				
			||||||
    check_rewrite(
 | 
					    check_rewrite(
 | 
				
			||||||
| 
						 | 
					@ -690,6 +724,29 @@ fn rewrite_intra_doc_link_with_anchor() {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn rewrite_module() {
 | 
				
			||||||
 | 
					    check_rewrite(
 | 
				
			||||||
 | 
					        r#"
 | 
				
			||||||
 | 
					//- /main.rs crate:foo
 | 
				
			||||||
 | 
					/// [Foo]
 | 
				
			||||||
 | 
					pub mod $0Foo{
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					        expect"#]],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_rewrite(
 | 
				
			||||||
 | 
					        r#"
 | 
				
			||||||
 | 
					//- /main.rs crate:foo
 | 
				
			||||||
 | 
					pub mod $0Foo{
 | 
				
			||||||
 | 
					    //! [super::Foo]
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					        expect"#]],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn rewrite_intra_doc_link_to_associated_item() {
 | 
					fn rewrite_intra_doc_link_to_associated_item() {
 | 
				
			||||||
    check_rewrite(
 | 
					    check_rewrite(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,9 +40,9 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 | 
				
			||||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 | 
					.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 | 
				
			||||||
.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 | 
					.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
 | 
					<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[foo::Struct]</span>
 | 
				
			||||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
 | 
					<span class="comment documentation">//! This is an intra doc injection test for modules</span>
 | 
				
			||||||
<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
 | 
					<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[foo::Struct]</span>
 | 
				
			||||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
 | 
					<span class="comment documentation">//! This is an intra doc injection test for modules</span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
 | 
					<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1072,9 +1072,9 @@ fn test_mod_hl_injection() {
 | 
				
			||||||
    check_highlighting(
 | 
					    check_highlighting(
 | 
				
			||||||
        r##"
 | 
					        r##"
 | 
				
			||||||
//- /foo.rs
 | 
					//- /foo.rs
 | 
				
			||||||
//! [Struct]
 | 
					//! [foo::Struct]
 | 
				
			||||||
//! This is an intra doc injection test for modules
 | 
					//! This is an intra doc injection test for modules
 | 
				
			||||||
//! [Struct]
 | 
					//! [foo::Struct]
 | 
				
			||||||
//! This is an intra doc injection test for modules
 | 
					//! This is an intra doc injection test for modules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Struct;
 | 
					pub struct Struct;
 | 
				
			||||||
| 
						 | 
					@ -1097,9 +1097,9 @@ mod foo;
 | 
				
			||||||
/// This is an intra doc injection test for modules
 | 
					/// This is an intra doc injection test for modules
 | 
				
			||||||
mod foo;
 | 
					mod foo;
 | 
				
			||||||
//- /foo.rs
 | 
					//- /foo.rs
 | 
				
			||||||
//! [Struct]
 | 
					//! [foo::Struct]
 | 
				
			||||||
//! This is an intra doc injection test for modules
 | 
					//! This is an intra doc injection test for modules
 | 
				
			||||||
//! [Struct]
 | 
					//! [foo::Struct]
 | 
				
			||||||
//! This is an intra doc injection test for modules
 | 
					//! This is an intra doc injection test for modules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Struct;
 | 
					pub struct Struct;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue