Goto for inner doc links works for module inner doc comments

This commit is contained in:
Aleksey Kladov 2021-01-11 16:24:50 +03:00
parent 8c33ffecc1
commit 8adf5cc0e3
2 changed files with 54 additions and 40 deletions

View file

@ -6,15 +6,13 @@ use ide_db::{
symbol_index, RootDatabase, symbol_index, RootDatabase,
}; };
use syntax::{ use syntax::{
ast::{self, NameOwner}, ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
match_ast, AstNode, AstToken,
SyntaxKind::*,
SyntaxToken, TextSize, TokenAtOffset, T,
}; };
use crate::{ use crate::{
display::{ToNav, TryToNav}, display::{ToNav, TryToNav},
doc_links::extract_definitions_from_markdown, doc_links::extract_definitions_from_markdown,
runnables::doc_owner_to_def,
FilePosition, NavigationTarget, RangeInfo, SymbolKind, FilePosition, NavigationTarget, RangeInfo, SymbolKind,
}; };
@ -84,31 +82,23 @@ fn def_for_doc_comment(
doc_comment: &ast::Comment, doc_comment: &ast::Comment,
) -> Option<hir::ModuleDef> { ) -> Option<hir::ModuleDef> {
let parent = doc_comment.syntax().parent(); let parent = doc_comment.syntax().parent();
let db = sema.db;
let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?;
let link = &link;
let name = match_ast! { let def = doc_owner_to_def(sema, parent)?;
match parent { match def {
ast::Name(name) => Some(name),
ast::Fn(func) => func.name(),
_ => None,
}
}?;
let definition = NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db))?;
match definition {
Definition::ModuleDef(def) => match def { Definition::ModuleDef(def) => match def {
ModuleDef::Module(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Module(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Function(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Function(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Adt(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Variant(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Const(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Static(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::Trait(it) => it.resolve_doc_path(db, link, ns), ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, link, ns), ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns),
ModuleDef::BuiltinType(_) => return None, ModuleDef::BuiltinType(_) => return None,
}, },
Definition::Macro(it) => it.resolve_doc_path(db, link, ns), Definition::Macro(it) => it.resolve_doc_path(sema.db, &link, ns),
Definition::Field(it) => it.resolve_doc_path(db, link, ns), Definition::Field(it) => it.resolve_doc_path(sema.db, &link, ns),
Definition::SelfType(_) Definition::SelfType(_)
| Definition::Local(_) | Definition::Local(_)
| Definition::GenericParam(_) | Definition::GenericParam(_)
@ -1212,7 +1202,7 @@ fn foo<'foo>(_: &'foo ()) {
} }
#[test] #[test]
fn goto_def_for_intra_rustdoc_link_same_file() { fn goto_def_for_intra_doc_link_same_file() {
check( check(
r#" r#"
/// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar) /// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar)
@ -1225,4 +1215,19 @@ pub fn foo() { }
}"#, }"#,
) )
} }
#[test]
fn goto_def_for_intra_doc_link_inner() {
check(
r#"
//- /main.rs
mod m;
struct S;
//^
//- /m.rs
//! [`super::S$0`]
"#,
)
}
} }

View file

@ -3,7 +3,7 @@ use std::fmt;
use assists::utils::test_related_attribute; use assists::utils::test_related_attribute;
use cfg::CfgExpr; use cfg::CfgExpr;
use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; use hir::{AsAssocItem, HasAttrs, HasSource, Semantics};
use ide_db::RootDatabase; use ide_db::{defs::Definition, RootDatabase};
use itertools::Itertools; use itertools::Itertools;
use syntax::{ use syntax::{
ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, ast::{self, AstNode, AttrsOwner, ModuleItemOwner},
@ -110,7 +110,10 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
_ => None, _ => None,
} }
}; };
runnable.or_else(|| runnable_doctest(&sema, item)) runnable.or_else(|| match doc_owner_to_def(&sema, item)? {
Definition::ModuleDef(def) => module_def_doctest(&sema, def),
_ => None,
})
}) })
.collect() .collect()
} }
@ -170,20 +173,26 @@ pub(crate) fn runnable_mod(
Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg })
} }
fn runnable_doctest(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { // FIXME: figure out a proper API here.
match_ast! { pub(crate) fn doc_owner_to_def(
sema: &Semantics<RootDatabase>,
item: SyntaxNode,
) -> Option<Definition> {
let res: hir::ModuleDef = match_ast! {
match item { match item {
ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::SourceFile(it) => sema.scope(&item).module()?.into(),
ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Fn(it) => sema.to_def(&it)?.into(),
ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Struct(it) => sema.to_def(&it)?.into(),
ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Enum(it) => sema.to_def(&it)?.into(),
ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Union(it) => sema.to_def(&it)?.into(),
ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Trait(it) => sema.to_def(&it)?.into(),
ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Const(it) => sema.to_def(&it)?.into(),
ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), ast::Static(it) => sema.to_def(&it)?.into(),
_ => None, ast::TypeAlias(it) => sema.to_def(&it)?.into(),
} _ => return None,
} }
};
Some(Definition::ModuleDef(res))
} }
fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> { fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Option<Runnable> {