mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Auto merge of #16702 - Veykril:intra-doc-links-generic, r=Veykril
fix: Ignore generic arguments in intra doc link path resolution Fixes https://github.com/rust-lang/rust-analyzer/issues/16699
This commit is contained in:
		
						commit
						4ef6a49b44
					
				@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 | 
			
		||||
resolver = "2"
 | 
			
		||||
 | 
			
		||||
[workspace.package]
 | 
			
		||||
rust-version = "1.74"
 | 
			
		||||
rust-version = "1.76"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
license = "MIT OR Apache-2.0"
 | 
			
		||||
authors = ["rust-analyzer team"]
 | 
			
		||||
 | 
			
		||||
@ -124,7 +124,7 @@ fn resolve_doc_path_on_(
 | 
			
		||||
        AttrDefId::GenericParamId(_) => return None,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut modpath = modpath_from_str(link)?;
 | 
			
		||||
    let mut modpath = doc_modpath_from_str(link)?;
 | 
			
		||||
 | 
			
		||||
    let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
 | 
			
		||||
    if resolved.is_none() {
 | 
			
		||||
@ -299,7 +299,7 @@ fn as_module_def_if_namespace_matches(
 | 
			
		||||
    (ns.unwrap_or(expected_ns) == expected_ns).then_some(DocLinkDef::ModuleDef(def))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn modpath_from_str(link: &str) -> Option<ModPath> {
 | 
			
		||||
fn doc_modpath_from_str(link: &str) -> Option<ModPath> {
 | 
			
		||||
    // FIXME: this is not how we should get a mod path here.
 | 
			
		||||
    let try_get_modpath = |link: &str| {
 | 
			
		||||
        let mut parts = link.split("::");
 | 
			
		||||
@ -327,7 +327,9 @@ fn modpath_from_str(link: &str) -> Option<ModPath> {
 | 
			
		||||
        };
 | 
			
		||||
        let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() {
 | 
			
		||||
            Ok(idx) => Name::new_tuple_field(idx),
 | 
			
		||||
            Err(_) => Name::new_text_dont_use(segment.into()),
 | 
			
		||||
            Err(_) => {
 | 
			
		||||
                Name::new_text_dont_use(segment.split_once('<').map_or(segment, |it| it.0).into())
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        Some(ModPath::from_segments(kind, parts))
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -721,7 +721,7 @@ impl NameRefClass {
 | 
			
		||||
 | 
			
		||||
impl_from!(
 | 
			
		||||
    Field, Module, Function, Adt, Variant, Const, Static, Trait, TraitAlias, TypeAlias, BuiltinType, Local,
 | 
			
		||||
    GenericParam, Label, Macro
 | 
			
		||||
    GenericParam, Label, Macro, ExternCrateDecl
 | 
			
		||||
    for Definition
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -233,21 +233,22 @@ pub(crate) fn doc_attributes(
 | 
			
		||||
) -> Option<(hir::AttrsWithOwner, Definition)> {
 | 
			
		||||
    match_ast! {
 | 
			
		||||
        match node {
 | 
			
		||||
            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))),
 | 
			
		||||
            ast::Module(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Module(def))),
 | 
			
		||||
            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Function(def))),
 | 
			
		||||
            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Struct(def)))),
 | 
			
		||||
            ast::Union(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Union(def)))),
 | 
			
		||||
            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Adt(hir::Adt::Enum(def)))),
 | 
			
		||||
            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Variant(def))),
 | 
			
		||||
            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Trait(def))),
 | 
			
		||||
            ast::Static(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Static(def))),
 | 
			
		||||
            ast::Const(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Const(def))),
 | 
			
		||||
            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::TypeAlias(def))),
 | 
			
		||||
            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
 | 
			
		||||
            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
 | 
			
		||||
            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
 | 
			
		||||
            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
 | 
			
		||||
            ast::SourceFile(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Module(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Fn(it)          => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Struct(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(hir::Adt::Struct(def)))),
 | 
			
		||||
            ast::Union(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(hir::Adt::Union(def)))),
 | 
			
		||||
            ast::Enum(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(hir::Adt::Enum(def)))),
 | 
			
		||||
            ast::Variant(it)     => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Trait(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Static(it)      => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Const(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::TypeAlias(it)   => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Impl(it)        => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::TupleField(it)  => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::Macro(it)       => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            ast::ExternCrate(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))),
 | 
			
		||||
            // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
 | 
			
		||||
            _ => None
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
//! Helper tools for intra doc links.
 | 
			
		||||
 | 
			
		||||
const TYPES: ([&str; 9], [&str; 0]) =
 | 
			
		||||
    (["type", "struct", "enum", "mod", "trait", "union", "module", "prim", "primitive"], []);
 | 
			
		||||
const VALUES: ([&str; 8], [&str; 1]) =
 | 
			
		||||
    (["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]);
 | 
			
		||||
const MACROS: ([&str; 2], [&str; 1]) = (["macro", "derive"], ["!"]);
 | 
			
		||||
const TYPES: (&[&str], &[&str]) =
 | 
			
		||||
    (&["type", "struct", "enum", "mod", "trait", "union", "module", "prim", "primitive"], &[]);
 | 
			
		||||
const VALUES: (&[&str], &[&str]) =
 | 
			
		||||
    (&["value", "function", "fn", "method", "const", "static", "mod", "module"], &["()"]);
 | 
			
		||||
const MACROS: (&[&str], &[&str]) = (&["macro", "derive"], &["!"]);
 | 
			
		||||
 | 
			
		||||
/// Extract the specified namespace from an intra-doc-link if one exists.
 | 
			
		||||
///
 | 
			
		||||
@ -17,39 +17,35 @@ pub(super) fn parse_intra_doc_link(s: &str) -> (&str, Option<hir::Namespace>) {
 | 
			
		||||
    let s = s.trim_matches('`');
 | 
			
		||||
 | 
			
		||||
    [
 | 
			
		||||
        (hir::Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())),
 | 
			
		||||
        (hir::Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
 | 
			
		||||
        (hir::Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
 | 
			
		||||
        (hir::Namespace::Types, TYPES),
 | 
			
		||||
        (hir::Namespace::Values, VALUES),
 | 
			
		||||
        (hir::Namespace::Macros, MACROS),
 | 
			
		||||
    ]
 | 
			
		||||
    .into_iter()
 | 
			
		||||
    .find_map(|(ns, (mut prefixes, mut suffixes))| {
 | 
			
		||||
        if let Some(prefix) = prefixes.find(|&&prefix| {
 | 
			
		||||
    .find_map(|(ns, (prefixes, suffixes))| {
 | 
			
		||||
        if let Some(prefix) = prefixes.iter().find(|&&prefix| {
 | 
			
		||||
            s.starts_with(prefix)
 | 
			
		||||
                && s.chars().nth(prefix.len()).map_or(false, |c| c == '@' || c == ' ')
 | 
			
		||||
        }) {
 | 
			
		||||
            Some((&s[prefix.len() + 1..], ns))
 | 
			
		||||
        } else {
 | 
			
		||||
            suffixes.find_map(|&suffix| s.strip_suffix(suffix).zip(Some(ns)))
 | 
			
		||||
            suffixes.iter().find_map(|&suffix| s.strip_suffix(suffix).zip(Some(ns)))
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    .map_or((s, None), |(s, ns)| (s, Some(ns)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(super) fn strip_prefixes_suffixes(s: &str) -> &str {
 | 
			
		||||
    [
 | 
			
		||||
        (TYPES.0.iter(), TYPES.1.iter()),
 | 
			
		||||
        (VALUES.0.iter(), VALUES.1.iter()),
 | 
			
		||||
        (MACROS.0.iter(), MACROS.1.iter()),
 | 
			
		||||
    ]
 | 
			
		||||
    [TYPES, VALUES, MACROS]
 | 
			
		||||
        .into_iter()
 | 
			
		||||
    .find_map(|(mut prefixes, mut suffixes)| {
 | 
			
		||||
        if let Some(prefix) = prefixes.find(|&&prefix| {
 | 
			
		||||
        .find_map(|(prefixes, suffixes)| {
 | 
			
		||||
            if let Some(prefix) = prefixes.iter().find(|&&prefix| {
 | 
			
		||||
                s.starts_with(prefix)
 | 
			
		||||
                    && s.chars().nth(prefix.len()).map_or(false, |c| c == '@' || c == ' ')
 | 
			
		||||
            }) {
 | 
			
		||||
                Some(&s[prefix.len() + 1..])
 | 
			
		||||
            } else {
 | 
			
		||||
            suffixes.find_map(|&suffix| s.strip_suffix(suffix))
 | 
			
		||||
                suffixes.iter().find_map(|&suffix| s.strip_suffix(suffix))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        .unwrap_or(s)
 | 
			
		||||
 | 
			
		||||
@ -6103,6 +6103,31 @@ pub struct Foo(i32);
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn hover_intra_generics() {
 | 
			
		||||
    check(
 | 
			
		||||
        r#"
 | 
			
		||||
/// Doc comment for [`Foo$0<T>`]
 | 
			
		||||
pub struct Foo<T>(T);
 | 
			
		||||
"#,
 | 
			
		||||
        expect![[r#"
 | 
			
		||||
            *[`Foo<T>`]*
 | 
			
		||||
 | 
			
		||||
            ```rust
 | 
			
		||||
            test
 | 
			
		||||
            ```
 | 
			
		||||
 | 
			
		||||
            ```rust
 | 
			
		||||
            pub struct Foo<T>(T);
 | 
			
		||||
            ```
 | 
			
		||||
 | 
			
		||||
            ---
 | 
			
		||||
 | 
			
		||||
            Doc comment for [`Foo<T>`](https://docs.rs/test/*/test/struct.Foo.html)
 | 
			
		||||
        "#]],
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn hover_inert_attr() {
 | 
			
		||||
    check(
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ name = "syntax-fuzz"
 | 
			
		||||
version = "0.0.1"
 | 
			
		||||
publish = false
 | 
			
		||||
edition = "2021"
 | 
			
		||||
rust-version = "1.66.1"
 | 
			
		||||
rust-version = "1.76"
 | 
			
		||||
 | 
			
		||||
[package.metadata]
 | 
			
		||||
cargo-fuzz = true
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user