From 8adf5cc0e364376183c0b8009b65bc9e46fa3e36 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Jan 2021 16:24:50 +0300 Subject: [PATCH] Goto for inner doc links works for module inner doc comments --- crates/ide/src/goto_definition.rs | 57 +++++++++++++++++-------------- crates/ide/src/runnables.rs | 37 ++++++++++++-------- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index c20185b164..cd4afc8041 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -6,15 +6,13 @@ use ide_db::{ symbol_index, RootDatabase, }; use syntax::{ - ast::{self, NameOwner}, - match_ast, AstNode, AstToken, - SyntaxKind::*, - SyntaxToken, TextSize, TokenAtOffset, T, + ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, }; use crate::{ display::{ToNav, TryToNav}, doc_links::extract_definitions_from_markdown, + runnables::doc_owner_to_def, FilePosition, NavigationTarget, RangeInfo, SymbolKind, }; @@ -84,31 +82,23 @@ fn def_for_doc_comment( doc_comment: &ast::Comment, ) -> Option { let parent = doc_comment.syntax().parent(); - let db = sema.db; let (link, ns) = extract_positioned_link_from_comment(position, doc_comment)?; - let link = &link; - let name = match_ast! { - match parent { - 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 { + + let def = doc_owner_to_def(sema, parent)?; + match def { Definition::ModuleDef(def) => match def { - ModuleDef::Module(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Function(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Adt(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Variant(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Const(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Static(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::Trait(it) => it.resolve_doc_path(db, link, ns), - ModuleDef::TypeAlias(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(sema.db, &link, ns), + ModuleDef::Adt(it) => it.resolve_doc_path(sema.db, &link, ns), + ModuleDef::Variant(it) => it.resolve_doc_path(sema.db, &link, ns), + ModuleDef::Const(it) => it.resolve_doc_path(sema.db, &link, ns), + ModuleDef::Static(it) => it.resolve_doc_path(sema.db, &link, ns), + ModuleDef::Trait(it) => it.resolve_doc_path(sema.db, &link, ns), + ModuleDef::TypeAlias(it) => it.resolve_doc_path(sema.db, &link, ns), ModuleDef::BuiltinType(_) => return None, }, - Definition::Macro(it) => it.resolve_doc_path(db, link, ns), - Definition::Field(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(sema.db, &link, ns), Definition::SelfType(_) | Definition::Local(_) | Definition::GenericParam(_) @@ -1212,7 +1202,7 @@ fn foo<'foo>(_: &'foo ()) { } #[test] - fn goto_def_for_intra_rustdoc_link_same_file() { + fn goto_def_for_intra_doc_link_same_file() { check( r#" /// 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`] +"#, + ) + } } diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 3a1e204db5..f5ee7de86d 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -3,7 +3,7 @@ use std::fmt; use assists::utils::test_related_attribute; use cfg::CfgExpr; use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; -use ide_db::RootDatabase; +use ide_db::{defs::Definition, RootDatabase}; use itertools::Itertools; use syntax::{ ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, @@ -110,7 +110,10 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { _ => 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() } @@ -170,20 +173,26 @@ pub(crate) fn runnable_mod( Some(Runnable { nav, kind: RunnableKind::TestMod { path }, cfg }) } -fn runnable_doctest(sema: &Semantics, item: SyntaxNode) -> Option { - match_ast! { +// FIXME: figure out a proper API here. +pub(crate) fn doc_owner_to_def( + sema: &Semantics, + item: SyntaxNode, +) -> Option { + let res: hir::ModuleDef = match_ast! { match item { - ast::Fn(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Struct(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Enum(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Union(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Trait(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Const(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::Static(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - ast::TypeAlias(it) => module_def_doctest(sema, sema.to_def(&it)?.into()), - _ => None, + ast::SourceFile(it) => sema.scope(&item).module()?.into(), + ast::Fn(it) => sema.to_def(&it)?.into(), + ast::Struct(it) => sema.to_def(&it)?.into(), + ast::Enum(it) => sema.to_def(&it)?.into(), + ast::Union(it) => sema.to_def(&it)?.into(), + ast::Trait(it) => sema.to_def(&it)?.into(), + ast::Const(it) => sema.to_def(&it)?.into(), + ast::Static(it) => sema.to_def(&it)?.into(), + ast::TypeAlias(it) => sema.to_def(&it)?.into(), + _ => return None, } - } + }; + Some(Definition::ModuleDef(res)) } fn module_def_doctest(sema: &Semantics, def: hir::ModuleDef) -> Option {