about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-19 13:51:57 +0000
committerGitHub <noreply@github.com>2021-04-19 13:51:57 +0000
commit6991b517f2c1ba9eb75f98ca689378e8dfa1e87f (patch)
tree9da882e4925f3b21f13f539b60fee7b007211a12
parentdeb939ac918a65c8875c488d43914a1c1aa5781b (diff)
parent6142afeafda77a412b5565d91f222b8e085b0752 (diff)
downloadrust-6991b517f2c1ba9eb75f98ca689378e8dfa1e87f.tar.gz
rust-6991b517f2c1ba9eb75f98ca689378e8dfa1e87f.zip
Merge #8577
8577: Support crates/module roots in external_docs r=Veykril a=Veykril

Fixes #8575
bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/ide/src/doc_links.rs58
1 files changed, 41 insertions, 17 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index c5dc14a237a..cb5a8e19a9d 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -108,13 +108,13 @@ pub(crate) fn external_docs(
     let node = token.parent()?;
     let definition = match_ast! {
         match node {
-            ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
-            ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
-            _ => None,
+            ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db))?,
+            ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db))?,
+            _ => return None,
         }
     };
 
-    get_doc_link(db, definition?)
+    get_doc_link(db, definition)
 }
 
 /// Extracts all links from a given markdown text.
@@ -214,20 +214,20 @@ fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, Cow
 // This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented
 // https://github.com/rust-lang/rfcs/pull/2988
 fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
-    // Get the outermost definition for the moduledef. This is used to resolve the public path to the type,
+    // Get the outermost definition for the module def. This is used to resolve the public path to the type,
     // then we can join the method, field, etc onto it if required.
     let target_def: ModuleDef = match definition {
-        Definition::ModuleDef(moddef) => match moddef {
+        Definition::ModuleDef(def) => match def {
             ModuleDef::Function(f) => f
                 .as_assoc_item(db)
                 .and_then(|assoc| match assoc.container(db) {
                     AssocItemContainer::Trait(t) => Some(t.into()),
-                    AssocItemContainer::Impl(impld) => {
-                        impld.self_ty(db).as_adt().map(|adt| adt.into())
+                    AssocItemContainer::Impl(impl_) => {
+                        impl_.self_ty(db).as_adt().map(|adt| adt.into())
                     }
                 })
-                .unwrap_or_else(|| f.clone().into()),
-            moddef => moddef,
+                .unwrap_or_else(|| def),
+            def => def,
         },
         Definition::Field(f) => f.parent_def(db).into(),
         // FIXME: Handle macros
@@ -236,17 +236,28 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
 
     let ns = ItemInNs::from(target_def);
 
-    let module = definition.module(db)?;
-    let krate = module.krate();
+    let krate = match definition {
+        // Definition::module gives back the parent module, we don't want that as it fails for root modules
+        Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(),
+        _ => definition.module(db)?.krate(),
+    };
     let import_map = db.import_map(krate.into());
-    let base = once(krate.display_name(db)?.to_string())
-        .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string()))
-        .join("/")
-        + "/";
+
+    let mut base = krate.display_name(db)?.to_string();
+    let is_root_module = matches!(
+        definition,
+        Definition::ModuleDef(ModuleDef::Module(module)) if krate.root_module(db) == module
+    );
+    if !is_root_module {
+        base = once(base)
+            .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string()))
+            .join("/");
+    }
+    base += "/";
 
     let filename = get_symbol_filename(db, &target_def);
     let fragment = match definition {
-        Definition::ModuleDef(moddef) => match moddef {
+        Definition::ModuleDef(def) => match def {
             ModuleDef::Function(f) => {
                 get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f)))
             }
@@ -533,6 +544,19 @@ mod tests {
     }
 
     #[test]
+    fn test_doc_url_crate() {
+        check(
+            r#"
+//- /main.rs crate:main deps:test
+use test$0::Foo;
+//- /lib.rs crate:test
+pub struct Foo;
+"#,
+            expect![[r#"https://docs.rs/test/*/test/index.html"#]],
+        );
+    }
+
+    #[test]
     fn test_doc_url_struct() {
         check(
             r#"