rust/crates/ra_ide/src/hover.rs

3099 lines
88 KiB
Rust
Raw Normal View History

use std::iter::once;
2020-03-05 23:02:14 +00:00
use hir::{
2020-06-15 02:47:33 +00:00
db::DefDatabase, Adt, AsAssocItem, AsName, AssocItemContainer, AttrDef, Crate, Documentation,
2020-06-30 09:16:12 +00:00
FieldSource, HasSource, HirDisplay, Hygiene, ItemInNs, ModPath, Module, ModuleDef,
ModuleSource, Semantics,
2020-03-05 23:02:14 +00:00
};
use itertools::Itertools;
2020-06-15 02:47:33 +00:00
use pulldown_cmark::{CowStr, Event, Options, Parser, Tag};
use pulldown_cmark_to_cmark::cmark;
2020-03-08 13:26:57 +00:00
use ra_db::SourceDatabase;
use ra_ide_db::{
2020-03-03 17:54:39 +00:00
defs::{classify_name, classify_name_ref, Definition},
RootDatabase,
};
use ra_syntax::{ast, ast::Path, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
use ra_tt::{Ident, Leaf, Literal, TokenTree};
2020-07-09 08:19:37 +00:00
use stdx::format_to;
use test_utils::mark;
2020-06-09 08:06:53 +00:00
use url::Url;
2019-01-08 19:33:36 +00:00
2019-05-30 17:46:43 +00:00
use crate::{
2020-07-09 08:19:37 +00:00
display::{macro_label, ShortLabel, ToNav, TryToNav},
2020-07-08 20:37:35 +00:00
markup::Markup,
2020-06-06 11:30:29 +00:00
runnables::runnable,
FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
2019-05-30 17:46:43 +00:00
};
2019-01-08 19:33:36 +00:00
2020-06-03 11:15:54 +00:00
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HoverConfig {
pub implementations: bool,
2020-06-06 11:30:29 +00:00
pub run: bool,
pub debug: bool,
pub goto_type_def: bool,
2020-06-03 11:15:54 +00:00
}
impl Default for HoverConfig {
fn default() -> Self {
Self { implementations: true, run: true, debug: true, goto_type_def: true }
2020-06-03 11:15:54 +00:00
}
}
impl HoverConfig {
pub const NO_ACTIONS: Self =
Self { implementations: false, run: false, debug: false, goto_type_def: false };
2020-06-03 11:15:54 +00:00
pub fn any(&self) -> bool {
self.implementations || self.runnable() || self.goto_type_def
2020-06-03 11:15:54 +00:00
}
pub fn none(&self) -> bool {
!self.any()
}
2020-06-06 11:30:29 +00:00
pub fn runnable(&self) -> bool {
self.run || self.debug
}
2020-06-03 11:15:54 +00:00
}
#[derive(Debug, Clone)]
pub enum HoverAction {
2020-06-06 11:30:29 +00:00
Runnable(Runnable),
2020-06-03 11:15:54 +00:00
Implementaion(FilePosition),
GoToType(Vec<HoverGotoTypeData>),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct HoverGotoTypeData {
pub mod_path: String,
pub nav: NavigationTarget,
2020-06-03 11:15:54 +00:00
}
/// Contains the results when hovering over an item
#[derive(Debug, Default)]
pub struct HoverResult {
2020-07-08 20:37:35 +00:00
pub markup: Markup,
pub actions: Vec<HoverAction>,
}
// Feature: Hover
//
// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
let sema = Semantics::new(db);
let file = sema.parse(position.file_id).syntax().clone();
let token = pick_best(file.token_at_offset(position.offset))?;
let token = sema.descend_into_macros(token);
2020-07-09 07:42:01 +00:00
let mut res = HoverResult::default();
2020-07-08 18:26:20 +00:00
let node = token.parent();
let definition = match_ast! {
match node {
2020-07-09 07:39:53 +00:00
ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()),
ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()),
_ => None,
}
2020-07-08 18:26:20 +00:00
};
if let Some(definition) = definition {
2020-07-09 08:19:37 +00:00
if let Some(markup) = hover_for_definition(db, definition) {
let markup = rewrite_links(db, &markup.as_str(), &definition);
res.markup = Markup::from(markup);
2020-07-08 18:26:20 +00:00
if let Some(action) = show_implementations_action(db, definition) {
2020-07-09 07:42:01 +00:00
res.actions.push(action);
2020-06-03 11:15:54 +00:00
}
2020-07-08 18:26:20 +00:00
if let Some(action) = runnable_action(&sema, definition, position.file_id) {
2020-07-09 07:42:01 +00:00
res.actions.push(action);
2020-06-06 11:30:29 +00:00
}
2020-07-08 18:26:20 +00:00
if let Some(action) = goto_type_action(db, definition) {
2020-07-09 07:42:01 +00:00
res.actions.push(action);
}
2020-07-09 07:39:53 +00:00
let range = sema.original_range(&node).range;
return Some(RangeInfo::new(range, res));
}
}
let node = token
.ancestors()
.find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
let ty = match_ast! {
match node {
2020-07-09 07:39:53 +00:00
ast::Expr(it) => sema.type_of_expr(&it)?,
ast::Pat(it) => sema.type_of_pat(&it)?,
// If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
// (e.g expanding a builtin macro). So we give up here.
ast::MacroCall(_it) => return None,
_ => return None,
}
2020-07-09 07:39:53 +00:00
};
2020-07-09 08:19:37 +00:00
res.markup = Markup::fenced_block(&ty.display(db));
let range = sema.original_range(&node).range;
Some(RangeInfo::new(range, res))
}
2020-06-03 11:15:54 +00:00
fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
fn to_action(nav_target: NavigationTarget) -> HoverAction {
HoverAction::Implementaion(FilePosition {
2020-07-17 10:42:48 +00:00
file_id: nav_target.file_id,
offset: nav_target.focus_or_full_range().start(),
2020-06-03 11:15:54 +00:00
})
}
match def {
Definition::ModuleDef(it) => match it {
ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))),
ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))),
ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))),
ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))),
_ => None,
},
_ => None,
}
}
2020-06-06 11:30:29 +00:00
fn runnable_action(
sema: &Semantics<RootDatabase>,
def: Definition,
file_id: FileId,
) -> Option<HoverAction> {
match def {
Definition::ModuleDef(it) => match it {
ModuleDef::Module(it) => match it.definition_source(sema.db).value {
ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id)
.map(|it| HoverAction::Runnable(it)),
_ => None,
},
ModuleDef::Function(it) => {
let src = it.source(sema.db);
if src.file_id != file_id.into() {
2020-06-08 10:56:31 +00:00
mark::hit!(hover_macro_generated_struct_fn_doc_comment);
mark::hit!(hover_macro_generated_struct_fn_doc_attr);
return None;
}
runnable(&sema, src.value.syntax().clone(), file_id)
2020-06-06 11:30:29 +00:00
.map(|it| HoverAction::Runnable(it))
}
_ => None,
},
_ => None,
}
}
fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
match def {
Definition::Local(it) => {
2020-06-11 17:17:32 +00:00
let mut targets: Vec<ModuleDef> = Vec::new();
let mut push_new_def = |item: ModuleDef| {
if !targets.contains(&item) {
targets.push(item);
}
};
it.ty(db).walk(db, |t| {
if let Some(adt) = t.as_adt() {
push_new_def(adt.into());
} else if let Some(trait_) = t.as_dyn_trait() {
push_new_def(trait_.into());
2020-06-11 20:06:58 +00:00
} else if let Some(traits) = t.as_impl_traits(db) {
traits.into_iter().for_each(|it| push_new_def(it.into()));
2020-06-11 17:17:32 +00:00
} else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
push_new_def(trait_.into());
}
});
let targets = targets
2020-06-10 19:56:49 +00:00
.into_iter()
2020-06-11 11:41:42 +00:00
.filter_map(|it| {
Some(HoverGotoTypeData {
2020-07-09 07:56:15 +00:00
mod_path: render_path(
db,
it.module(db)?,
it.name(db).map(|name| name.to_string()),
),
2020-06-11 11:41:42 +00:00
nav: it.try_to_nav(db)?,
})
})
2020-06-11 17:17:32 +00:00
.collect();
Some(HoverAction::GoToType(targets))
}
_ => None,
}
}
2020-07-09 08:19:37 +00:00
fn hover_markup(
2020-03-05 23:02:14 +00:00
docs: Option<String>,
desc: Option<String>,
mod_path: Option<String>,
2020-07-09 08:19:37 +00:00
) -> Option<Markup> {
match desc {
Some(desc) => {
let mut buf = String::new();
if let Some(mod_path) = mod_path {
if !mod_path.is_empty() {
format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
}
}
format_to!(buf, "```rust\n{}\n```", desc);
if let Some(doc) = docs {
format_to!(buf, "\n___\n\n{}", doc);
}
Some(buf.into())
}
None => docs.map(Markup::from),
2019-06-10 16:34:43 +00:00
}
}
2020-03-05 23:02:14 +00:00
fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
match def {
2020-04-25 12:23:34 +00:00
Definition::Field(f) => Some(f.parent_def(db).name(db)),
2020-03-05 23:02:14 +00:00
Definition::Local(l) => l.parent(db).name(db),
Definition::ModuleDef(md) => match md {
ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
AssocItemContainer::Trait(t) => Some(t.name(db)),
AssocItemContainer::ImplDef(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
},
ModuleDef::EnumVariant(e) => Some(e.parent_enum(db).name(db)),
_ => None,
},
Definition::SelfType(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)),
_ => None,
}
.map(|name| name.to_string())
}
2020-07-09 07:56:15 +00:00
fn render_path(db: &RootDatabase, module: Module, item_name: Option<String>) -> String {
let crate_name =
db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string);
let module_path = module
.path_to_root(db)
.into_iter()
.rev()
.flat_map(|it| it.name(db).map(|name| name.to_string()));
crate_name.into_iter().chain(module_path).chain(item_name).join("::")
}
fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
2020-07-09 07:56:15 +00:00
def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
2020-03-05 23:02:14 +00:00
}
2020-07-09 08:19:37 +00:00
fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
let mod_path = definition_mod_path(db, &def);
2020-02-19 13:56:22 +00:00
return match def {
2020-03-03 17:36:39 +00:00
Definition::Macro(it) => {
let src = it.source(db);
let docs = Documentation::from_ast(&src.value).map(Into::into);
2020-07-09 08:19:37 +00:00
hover_markup(docs, Some(macro_label(&src.value)), mod_path)
}
2020-04-25 12:23:34 +00:00
Definition::Field(it) => {
let src = it.source(db);
2019-11-20 06:40:36 +00:00
match src.value {
2020-03-08 13:26:57 +00:00
FieldSource::Named(it) => {
let docs = Documentation::from_ast(&it).map(Into::into);
2020-07-09 08:19:37 +00:00
hover_markup(docs, it.short_label(), mod_path)
2020-03-05 23:02:14 +00:00
}
_ => None,
}
}
2020-03-03 17:36:39 +00:00
Definition::ModuleDef(it) => match it {
2020-03-05 23:02:14 +00:00
ModuleDef::Module(it) => match it.definition_source(db).value {
ModuleSource::Module(it) => {
let docs = Documentation::from_ast(&it).map(Into::into);
2020-07-09 08:19:37 +00:00
hover_markup(docs, it.short_label(), mod_path)
}
_ => None,
},
2020-03-05 23:02:14 +00:00
ModuleDef::Function(it) => from_def_source(db, it, mod_path),
ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
ModuleDef::EnumVariant(it) => from_def_source(db, it, mod_path),
ModuleDef::Const(it) => from_def_source(db, it, mod_path),
ModuleDef::Static(it) => from_def_source(db, it, mod_path),
ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
2020-07-09 08:19:37 +00:00
ModuleDef::BuiltinType(it) => return Some(it.to_string().into()),
},
2020-07-09 08:19:37 +00:00
Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))),
2020-03-03 17:36:39 +00:00
Definition::TypeParam(_) | Definition::SelfType(_) => {
// FIXME: Hover for generic param
None
}
};
2020-07-09 08:19:37 +00:00
fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
where
D: HasSource<Ast = A>,
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner,
{
let src = def.source(db);
let docs = Documentation::from_ast(&src.value).map(Into::into);
2020-07-09 08:19:37 +00:00
hover_markup(docs, src.value.short_label(), mod_path)
}
}
2020-06-15 02:47:33 +00:00
// Rewrites a markdown document, resolving links using `callback` and additionally striping prefixes/suffixes on link titles.
fn map_links<'e>(
events: impl Iterator<Item = Event<'e>>,
2020-06-30 07:52:25 +00:00
callback: impl Fn(&str, &str) -> (String, String),
2020-06-15 02:47:33 +00:00
) -> impl Iterator<Item = Event<'e>> {
let mut in_link = false;
2020-06-30 07:52:25 +00:00
let mut link_target: Option<CowStr> = None;
2020-06-15 02:47:33 +00:00
events.map(move |evt| match evt {
2020-06-30 07:52:25 +00:00
Event::Start(Tag::Link(_link_type, ref target, _)) => {
2020-06-15 02:47:33 +00:00
in_link = true;
2020-06-30 07:52:25 +00:00
link_target = Some(target.clone());
2020-06-15 02:47:33 +00:00
evt
}
2020-06-30 07:52:25 +00:00
Event::End(Tag::Link(link_type, _target, _)) => {
2020-06-15 02:47:33 +00:00
in_link = false;
2020-06-30 07:52:25 +00:00
Event::End(Tag::Link(link_type, link_target.take().unwrap(), CowStr::Borrowed("")))
2020-06-15 02:47:33 +00:00
}
Event::Text(s) if in_link => {
2020-06-30 07:52:25 +00:00
let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
link_target = Some(CowStr::Boxed(link_target_s.into()));
Event::Text(CowStr::Boxed(link_name.into()))
2020-06-15 02:47:33 +00:00
}
Event::Code(s) if in_link => {
2020-06-30 07:52:25 +00:00
let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
link_target = Some(CowStr::Boxed(link_target_s.into()));
Event::Code(CowStr::Boxed(link_name.into()))
2020-06-15 02:47:33 +00:00
}
_ => evt,
})
}
2020-06-30 07:52:25 +00:00
/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
2020-06-15 02:47:33 +00:00
let doc = Parser::new_with_broken_link_callback(
markdown,
Options::empty(),
Some(&|label, _| Some((/*url*/ label.to_string(), /*title*/ label.to_string()))),
);
let doc = map_links(doc, |target, title: &str| {
2020-06-30 07:52:25 +00:00
// This check is imperfect, there's some overlap between valid intra-doc links
// and valid URLs so we choose to be too eager to try to resolve what might be
// a URL.
if target.contains("://") {
(target.to_string(), title.to_string())
} else {
// Two posibilities:
// * path-based links: `../../module/struct.MyStruct.html`
// * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
2020-06-30 09:16:12 +00:00
let resolved = try_resolve_intra(db, definition, title, &target).or_else(|| {
try_resolve_path(db, definition, &target).map(|target| (target, title.to_string()))
});
2020-06-30 07:52:25 +00:00
match resolved {
Some((target, title)) => (target, title),
None => (target.to_string(), title.to_string()),
2020-06-15 02:47:33 +00:00
}
2020-06-09 08:06:53 +00:00
}
});
2020-06-15 02:47:33 +00:00
let mut out = String::new();
cmark(doc, &mut out, None).ok();
out
2020-06-09 03:43:57 +00:00
}
2020-06-12 03:02:48 +00:00
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
enum Namespace {
Types,
Values,
2020-06-15 02:47:33 +00:00
Macros,
2020-06-12 03:02:48 +00:00
}
static TYPES: ([&str; 7], [&str; 0]) =
(["type", "struct", "enum", "mod", "trait", "union", "module"], []);
static VALUES: ([&str; 8], [&str; 1]) =
(["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]);
static MACROS: ([&str; 1], [&str; 1]) = (["macro"], ["!"]);
2020-06-15 02:47:33 +00:00
2020-06-12 03:02:48 +00:00
impl Namespace {
/// Extract the specified namespace from an intra-doc-link if one exists.
2020-08-01 00:39:07 +00:00
///
/// # Examples
///
/// * `struct MyStruct` -> `Namespace::Types`
/// * `panic!` -> `Namespace::Macros`
/// * `fn@from_intra_spec` -> `Namespace::Values`
2020-06-12 03:02:48 +00:00
fn from_intra_spec(s: &str) -> Option<Self> {
[
(Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())),
(Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
(Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
]
.iter()
.filter(|(_ns, (prefixes, suffixes))| {
prefixes
.clone()
.map(|prefix| {
s.starts_with(*prefix)
&& s.chars()
.nth(prefix.len() + 1)
.map(|c| c == '@' || c == ' ')
.unwrap_or(false)
})
.any(|cond| cond)
|| suffixes
.clone()
.map(|suffix| {
s.starts_with(*suffix)
2020-06-15 02:47:33 +00:00
&& s.chars()
.nth(suffix.len() + 1)
2020-06-15 02:47:33 +00:00
.map(|c| c == '@' || c == ' ')
.unwrap_or(false)
})
.any(|cond| cond)
})
.map(|(ns, (_, _))| *ns)
.next()
2020-06-12 03:02:48 +00:00
}
}
2020-06-15 02:47:33 +00:00
// Strip prefixes, suffixes, and inline code marks from the given string.
fn strip_prefixes_suffixes(mut s: &str) -> &str {
s = s.trim_matches('`');
[
(TYPES.0.iter(), TYPES.1.iter()),
(VALUES.0.iter(), VALUES.1.iter()),
(MACROS.0.iter(), MACROS.1.iter()),
]
.iter()
.for_each(|(prefixes, suffixes)| {
prefixes.clone().for_each(|prefix| s = s.trim_start_matches(*prefix));
suffixes.clone().for_each(|suffix| s = s.trim_end_matches(*suffix));
2020-06-15 02:47:33 +00:00
});
s.trim_start_matches("@").trim()
}
/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`).
///
/// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md).
2020-06-15 02:47:33 +00:00
fn try_resolve_intra(
db: &RootDatabase,
definition: &Definition,
link_text: &str,
link_target: &str,
2020-06-30 07:52:25 +00:00
) -> Option<(String, String)> {
eprintln!("resolving intra");
2020-06-12 03:02:48 +00:00
// Set link_target for implied shortlinks
2020-06-15 02:47:33 +00:00
let link_target =
if link_target.is_empty() { link_text.trim_matches('`') } else { link_target };
// Namespace disambiguation
let namespace = Namespace::from_intra_spec(link_target);
// Strip prefixes/suffixes
let link_target = strip_prefixes_suffixes(link_target);
2020-06-12 03:02:48 +00:00
// Parse link as a module path
2020-06-30 08:23:06 +00:00
let path = Path::parse(link_target).ok()?;
2020-06-12 03:02:48 +00:00
let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
// Resolve it relative to symbol's location (according to the RFC this should consider small scopes
let resolver = definition.resolver(db)?;
2020-06-12 03:02:48 +00:00
let resolved = resolver.resolve_module_path_in_items(db, &modpath);
let (defid, namespace) = match namespace {
2020-06-16 04:52:40 +00:00
// FIXME: .or(resolved.macros)
2020-06-15 02:47:33 +00:00
None => resolved
.types
.map(|t| (t.0, Namespace::Types))
.or(resolved.values.map(|t| (t.0, Namespace::Values)))?,
2020-06-12 03:02:48 +00:00
Some(ns @ Namespace::Types) => (resolved.types?.0, ns),
Some(ns @ Namespace::Values) => (resolved.values?.0, ns),
2020-06-16 04:52:40 +00:00
// FIXME:
2020-06-15 02:47:33 +00:00
Some(Namespace::Macros) => None?,
2020-06-12 03:02:48 +00:00
};
// Get the filepath of the final symbol
let def: ModuleDef = defid.into();
let module = def.module(db)?;
let krate = module.krate();
let ns = match namespace {
Namespace::Types => ItemInNs::Types(defid),
Namespace::Values => ItemInNs::Values(defid),
2020-06-16 04:52:40 +00:00
// FIXME:
2020-06-15 02:47:33 +00:00
Namespace::Macros => None?,
2020-06-12 03:02:48 +00:00
};
let import_map = db.import_map(krate.into());
let path = import_map.path_of(ns)?;
2020-06-30 07:52:25 +00:00
Some((
2020-06-12 03:02:48 +00:00
get_doc_url(db, &krate)?
2020-06-15 02:47:33 +00:00
.join(&format!("{}/", krate.display_name(db)?))
.ok()?
2020-08-01 00:39:07 +00:00
.join(&path.segments.iter().map(|name| name.to_string()).join("/"))
2020-06-15 02:47:33 +00:00
.ok()?
.join(&get_symbol_filename(db, &Definition::ModuleDef(def))?)
.ok()?
.into_string(),
2020-06-30 09:16:12 +00:00
strip_prefixes_suffixes(link_text).to_string(),
))
2020-06-09 03:43:57 +00:00
}
/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
fn try_resolve_path(db: &RootDatabase, definition: &Definition, link: &str) -> Option<String> {
eprintln!("resolving path");
2020-06-15 02:47:33 +00:00
if !link.contains("#") && !link.contains(".html") {
return None;
}
2020-06-09 03:43:57 +00:00
let ns = if let Definition::ModuleDef(moddef) = definition {
ItemInNs::Types(moddef.clone().into())
} else {
return None;
};
2020-06-09 07:53:09 +00:00
let module = definition.module(db)?;
let krate = module.krate();
2020-06-09 03:43:57 +00:00
let import_map = db.import_map(krate.into());
2020-06-15 02:47:33 +00:00
let base = once(format!("{}", krate.display_name(db)?))
.chain(import_map.path_of(ns)?.segments.iter().map(|name| format!("{}", name)))
2020-06-15 02:47:33 +00:00
.join("/");
get_doc_url(db, &krate)
.and_then(|url| url.join(&base).ok())
2020-06-15 02:47:33 +00:00
.and_then(|url| {
get_symbol_filename(db, definition).as_deref().map(|f| url.join(f).ok()).flatten()
})
.and_then(|url| url.join(link).ok())
.map(|url| url.into_string())
2020-06-09 07:53:09 +00:00
}
/// Try to get the root URL of the documentation of a crate.
fn get_doc_url(db: &RootDatabase, krate: &Crate) -> Option<Url> {
2020-06-09 08:06:53 +00:00
// Look for #![doc(html_root_url = "...")]
2020-06-09 07:53:09 +00:00
let attrs = db.attrs(AttrDef::from(krate.root_module(db)?).into());
let doc_attr_q = attrs.by_key("doc");
2020-06-09 07:53:09 +00:00
let doc_url = if doc_attr_q.exists() {
doc_attr_q.tt_values().map(|tt| {
let name = tt.token_trees.iter()
.skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url"))
.skip(2)
.next();
match name {
Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
_ => None
2020-06-09 07:53:09 +00:00
}
}).flat_map(|t| t).next().map(|s| s.to_string())
2020-06-09 07:53:09 +00:00
} else {
2020-06-09 08:06:53 +00:00
// Fallback to docs.rs
2020-06-16 04:52:40 +00:00
// FIXME: Specify an exact version here (from Cargo.lock)
2020-06-09 08:06:53 +00:00
Some(format!("https://docs.rs/{}/*", krate.display_name(db)?))
2020-06-09 07:53:09 +00:00
};
doc_url
.map(|s| s.trim_matches('"').trim_end_matches("/").to_owned() + "/")
.and_then(|s| Url::parse(&s).ok())
2020-06-09 03:43:57 +00:00
}
/// Get the filename and extension generated for a symbol by rustdoc.
///
/// Example: `struct.Shard.html`
fn get_symbol_filename(db: &RootDatabase, definition: &Definition) -> Option<String> {
Some(match definition {
Definition::ModuleDef(def) => match def {
ModuleDef::Adt(adt) => match adt {
Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
2020-06-15 02:47:33 +00:00
Adt::Union(u) => format!("union.{}.html", u.name(db)),
},
ModuleDef::Module(_) => "index.html".to_string(),
ModuleDef::Trait(t) => format!("trait.{}.html", t.name(db)),
ModuleDef::TypeAlias(t) => format!("type.{}.html", t.name(db)),
ModuleDef::BuiltinType(t) => format!("primitive.{}.html", t.as_name()),
ModuleDef::Function(f) => format!("fn.{}.html", f.name(db)),
2020-06-15 02:47:33 +00:00
ModuleDef::EnumVariant(ev) => {
format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db))
}
ModuleDef::Const(c) => format!("const.{}.html", c.name(db)?),
2020-06-15 02:47:33 +00:00
ModuleDef::Static(s) => format!("static.{}.html", s.name(db)?),
},
Definition::Macro(m) => format!("macro.{}.html", m.name(db)?),
2020-06-15 02:47:33 +00:00
_ => None?,
})
}
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
return tokens.max_by_key(priority);
fn priority(n: &SyntaxToken) -> usize {
match n.kind() {
IDENT | INT_NUMBER => 3,
2020-07-08 22:07:32 +00:00
T!['('] | T![')'] => 2,
kind if kind.is_trivia() => 0,
_ => 1,
}
}
}
2019-01-08 19:33:36 +00:00
#[cfg(test)]
mod tests {
2020-07-08 22:07:32 +00:00
use expect::{expect, Expect};
use ra_db::FileLoader;
2020-06-24 09:31:30 +00:00
use crate::mock_analysis::analysis_and_position;
2020-07-08 22:07:32 +00:00
use super::*;
2020-07-08 22:07:32 +00:00
fn check_hover_no_result(ra_fixture: &str) {
let (analysis, position) = analysis_and_position(ra_fixture);
assert!(analysis.hover(position).unwrap().is_none());
2020-06-03 11:15:54 +00:00
}
2020-07-08 22:07:32 +00:00
fn check(ra_fixture: &str, expect: Expect) {
2020-07-01 15:08:45 +00:00
let (analysis, position) = analysis_and_position(ra_fixture);
let hover = analysis.hover(position).unwrap().unwrap();
let content = analysis.db.file_text(position.file_id);
2020-07-08 22:07:32 +00:00
let hovered_element = &content[hover.range];
2020-07-09 08:30:47 +00:00
let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
2020-07-08 22:07:32 +00:00
expect.assert_eq(&actual)
}
2019-01-08 19:33:36 +00:00
2020-07-08 22:07:32 +00:00
fn check_actions(ra_fixture: &str, expect: Expect) {
2020-07-01 15:08:45 +00:00
let (analysis, position) = analysis_and_position(ra_fixture);
2020-07-08 22:07:32 +00:00
let hover = analysis.hover(position).unwrap().unwrap();
expect.assert_debug_eq(&hover.info.actions)
2020-02-26 16:12:26 +00:00
}
2019-01-08 19:33:36 +00:00
#[test]
fn hover_shows_type_of_an_expression() {
2020-07-08 22:07:32 +00:00
check(
2020-06-24 09:29:43 +00:00
r#"
pub fn foo() -> u32 { 1 }
2019-01-08 19:33:36 +00:00
2020-06-24 09:29:43 +00:00
fn main() {
let foo_test = foo()<|>;
}
"#,
2020-07-08 22:07:32 +00:00
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo()*
2020-07-08 22:07:32 +00:00
```rust
u32
```
"#]],
2019-01-08 19:33:36 +00:00
);
}
#[test]
fn hover_shows_long_type_of_an_expression() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
struct Scan<A, B, C> { a: A, b: B, c: C }
struct Iter<I> { inner: I }
enum Option<T> { Some(T), None }
2020-07-08 22:07:32 +00:00
struct OtherStruct<T> { i: T }
2020-07-08 22:07:32 +00:00
fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
Iter { inner: Scan { a, b, c } }
}
2020-07-08 22:07:32 +00:00
fn main() {
let num: i32 = 55;
let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
Option::Some(*memo + value)
};
let number = 5u32;
let mut iter<|> = scan(OtherStruct { i: num }, closure, number);
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*iter*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_shows_fn_signature() {
// Single file with result
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
pub fn foo() -> u32 { 1 }
2020-07-08 22:07:32 +00:00
fn main() { let foo_test = fo<|>o(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
pub fn foo() -> u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
// Multiple candidates but results are ambiguous.
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
//- /a.rs
pub fn foo() -> u32 { 1 }
2020-07-08 22:07:32 +00:00
//- /b.rs
pub fn foo() -> &str { "" }
2020-07-08 22:07:32 +00:00
//- /c.rs
pub fn foo(a: u32, b: u32) {}
2020-07-08 22:07:32 +00:00
//- /main.rs
mod a;
mod b;
mod c;
2020-07-08 22:07:32 +00:00
fn main() { let foo_test = fo<|>o(); }
"#,
2020-07-08 22:07:32 +00:00
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-08 22:07:32 +00:00
```rust
{unknown}
```
"#]],
);
}
#[test]
fn hover_shows_fn_signature_with_type_params() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
2020-07-08 22:07:32 +00:00
fn main() { let foo_test = fo<|>o(); }
"#,
2020-07-08 22:07:32 +00:00
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
2019-01-08 19:33:36 +00:00
}
#[test]
fn hover_shows_fn_signature_on_fn_name() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
pub fn foo<|>(a: u32, b: u32) -> u32 {}
2020-07-08 22:07:32 +00:00
fn main() { }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
pub fn foo(a: u32, b: u32) -> u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_shows_struct_field_info() {
// Hovering over the field when instantiating
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
struct Foo { field_a: u32 }
2020-07-08 22:07:32 +00:00
fn main() {
let foo = Foo { field_a<|>: 0, };
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*field_a*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::Foo
````
````rust
2020-07-08 22:07:32 +00:00
field_a: u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
// Hovering over the field in the definition
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
struct Foo { field_a<|>: u32 }
2020-07-08 22:07:32 +00:00
fn main() {
let foo = Foo { field_a: 0 };
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*field_a*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::Foo
````
````rust
2020-07-08 22:07:32 +00:00
field_a: u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_const_static() {
2020-07-08 22:07:32 +00:00
check(
r#"const foo<|>: u32 = 0;"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
const foo: u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
2020-07-08 22:07:32 +00:00
check(
r#"static foo<|>: u32 = 0;"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
static foo: u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_default_generic_types() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
struct Test<K, T = u8> { k: K, t: T }
fn main() {
let zz<|> = Test { t: 23u8, k: 33 };
}"#,
2020-07-08 22:07:32 +00:00
expect![[r#"
2020-07-09 08:30:47 +00:00
*zz*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
Test<i32, u8>
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_some() {
2020-07-08 22:07:32 +00:00
check(
r#"
enum Option<T> { Some(T) }
use Option::Some;
2020-07-08 22:07:32 +00:00
fn main() { So<|>me(12); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Some*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::Option
````
````rust
2020-07-08 22:07:32 +00:00
Some
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
2020-06-15 02:47:33 +00:00
);
2020-07-08 22:07:32 +00:00
check(
r#"
enum Option<T> { Some(T) }
use Option::Some;
2020-07-08 22:07:32 +00:00
fn main() { let b<|>ar = Some(12); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*bar*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
Option<i32>
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn hover_enum_variant() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
enum Option<T> {
/// The None variant
Non<|>e
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*None*
2020-07-31 02:34:49 +00:00
````rust
test::Option
````
````rust
2020-07-08 22:07:32 +00:00
None
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
The None variant
"#]],
);
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
enum Option<T> {
/// The Some variant
Some(T)
}
fn main() {
let s = Option::Som<|>e(12);
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Some*
2020-07-31 02:34:49 +00:00
````rust
test::Option
````
````rust
2020-07-08 22:07:32 +00:00
Some
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
The Some variant
"#]],
);
}
2019-01-08 19:33:36 +00:00
#[test]
fn hover_for_local_variable() {
2020-07-08 22:07:32 +00:00
check(
r#"fn func(foo: i32) { fo<|>o; }"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
i32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-01-08 19:33:36 +00:00
}
#[test]
fn hover_for_local_variable_pat() {
2020-07-08 22:07:32 +00:00
check(
r#"fn func(fo<|>o: i32) {}"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
i32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-01-08 19:33:36 +00:00
}
#[test]
fn hover_local_var_edge() {
2020-07-08 22:07:32 +00:00
check(
r#"fn func(foo: i32) { if true { <|>foo; }; }"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
i32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
}
2019-12-13 18:54:07 +00:00
#[test]
fn hover_for_param_edge() {
2020-07-08 22:07:32 +00:00
check(
r#"fn func(<|>foo: i32) {}"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
i32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-12-13 18:54:07 +00:00
}
#[test]
fn test_hover_infer_associated_method_result() {
2020-07-08 22:07:32 +00:00
check(
r#"
struct Thing { x: u32 }
2020-07-08 22:07:32 +00:00
impl Thing {
fn new() -> Thing { Thing { x: 0 } }
}
2020-07-08 22:07:32 +00:00
fn main() { let foo_<|>test = Thing::new(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo_test*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
Thing
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
}
#[test]
fn test_hover_infer_associated_method_exact() {
2020-07-08 22:07:32 +00:00
check(
r#"
mod wrapper {
struct Thing { x: u32 }
2020-07-08 22:07:32 +00:00
impl Thing {
fn new() -> Thing { Thing { x: 0 } }
}
}
2020-07-08 22:07:32 +00:00
fn main() { let foo_test = wrapper::Thing::new<|>(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*new*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::wrapper::Thing
````
````rust
2020-07-08 22:07:32 +00:00
fn new() -> Thing
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
}
2019-03-06 16:39:11 +00:00
#[test]
fn test_hover_infer_associated_const_in_pattern() {
2020-07-08 22:07:32 +00:00
check(
r#"
struct X;
impl X {
const C: u32 = 1;
}
2019-03-06 16:39:11 +00:00
2020-07-08 22:07:32 +00:00
fn main() {
match 1 {
X::C<|> => {},
2 => {},
_ => {}
};
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*C*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
const C: u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-03-06 16:39:11 +00:00
}
#[test]
fn test_hover_self() {
2020-07-08 22:07:32 +00:00
check(
r#"
struct Thing { x: u32 }
impl Thing {
fn new() -> Self { Self<|> { x: 0 } }
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Self { x: 0 }*
2020-07-08 22:07:32 +00:00
```rust
Thing
```
"#]],
)
} /* FIXME: revive these tests
let (analysis, position) = analysis_and_position(
"
struct Thing { x: u32 }
impl Thing {
fn new() -> Self<|> {
Self { x: 0 }
}
}
",
);
let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("Thing"));
let (analysis, position) = analysis_and_position(
"
enum Thing { A }
impl Thing {
pub fn new() -> Self<|> {
Thing::A
}
}
",
);
let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
let (analysis, position) = analysis_and_position(
"
enum Thing { A }
impl Thing {
pub fn thing(a: Self<|>) {
}
}
",
);
let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(trim_markup(&hover.info.markup.as_str()), ("enum Thing"));
*/
2019-06-11 14:32:33 +00:00
#[test]
fn test_hover_shadowing_pat() {
2020-07-08 22:07:32 +00:00
check(
r#"
fn x() {}
2019-06-11 14:32:33 +00:00
2020-07-08 22:07:32 +00:00
fn y() {
let x = 0i32;
x<|>;
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*x*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
i32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-06-11 14:32:33 +00:00
}
2019-09-10 05:33:02 +00:00
#[test]
fn test_hover_macro_invocation() {
2020-07-08 22:07:32 +00:00
check(
r#"
macro_rules! foo { () => {} }
2019-09-10 05:33:02 +00:00
2020-07-08 22:07:32 +00:00
fn f() { fo<|>o!(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
macro_rules! foo
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
)
2019-09-10 05:33:02 +00:00
}
2019-11-10 18:59:39 +00:00
#[test]
fn test_hover_tuple_field() {
2020-07-08 22:07:32 +00:00
check(
r#"struct TS(String, i32<|>);"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*i32*
2020-07-08 22:07:32 +00:00
i32
"#]],
)
2019-11-10 18:59:39 +00:00
}
2019-11-18 16:58:42 +00:00
#[test]
fn test_hover_through_macro() {
2020-07-08 22:07:32 +00:00
check(
r#"
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
fn foo() {}
id! {
fn bar() { fo<|>o(); }
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
fn foo()
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
2019-11-18 16:58:42 +00:00
);
}
2020-01-10 17:51:08 +00:00
#[test]
fn test_hover_through_expr_in_macro() {
2020-07-08 22:07:32 +00:00
check(
r#"
macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
fn foo(bar:u32) { let a = id!(ba<|>r); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*bar*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
2020-01-10 17:51:08 +00:00
);
}
#[test]
fn test_hover_through_expr_in_macro_recursive() {
2020-07-08 22:07:32 +00:00
check(
r#"
macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
fn foo(bar:u32) { let a = id!(ba<|>r); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*bar*
2020-07-31 02:34:49 +00:00
````rust
2020-07-08 22:07:32 +00:00
u32
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
2020-02-28 14:53:59 +00:00
#[test]
fn test_hover_through_func_in_macro_recursive() {
2020-07-08 22:07:32 +00:00
check(
r#"
macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
fn bar() -> u32 { 0 }
fn foo() { let a = id!([0u32, bar(<|>)] ); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*bar()*
2020-07-08 22:07:32 +00:00
```rust
u32
```
"#]],
2020-02-28 14:53:59 +00:00
);
}
2020-02-26 16:12:26 +00:00
#[test]
fn test_hover_through_literal_string_in_macro() {
2020-07-08 22:07:32 +00:00
check(
2020-02-26 16:12:26 +00:00
r#"
2020-07-08 22:07:32 +00:00
macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
fn foo() {
let mastered_for_itunes = "";
let _ = arr!("Tr<|>acks", &mastered_for_itunes);
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*"Tracks"*
2020-07-08 22:07:32 +00:00
```rust
&str
```
"#]],
2020-02-26 16:12:26 +00:00
);
}
2020-03-11 15:14:15 +00:00
#[test]
fn test_hover_through_assert_macro() {
2020-07-08 22:07:32 +00:00
check(
2020-03-11 15:14:15 +00:00
r#"
2020-07-08 22:07:32 +00:00
#[rustc_builtin_macro]
macro_rules! assert {}
2020-03-11 15:14:15 +00:00
2020-07-08 22:07:32 +00:00
fn bar() -> bool { true }
fn foo() {
assert!(ba<|>r());
}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*bar*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
fn bar() -> bool
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
2020-03-11 15:14:15 +00:00
);
}
2020-02-27 15:03:18 +00:00
#[test]
fn test_hover_through_literal_string_in_builtin_macro() {
check_hover_no_result(
r#"
#[rustc_builtin_macro]
2020-03-11 15:08:12 +00:00
macro_rules! format {}
2020-02-27 15:03:18 +00:00
fn foo() {
2020-03-11 15:08:12 +00:00
format!("hel<|>lo {}", 0);
2020-02-27 15:03:18 +00:00
}
"#,
);
}
#[test]
fn test_hover_non_ascii_space_doc() {
2020-07-08 22:07:32 +00:00
check(
"
2020-07-08 22:07:32 +00:00
/// <- `\u{3000}` here
fn foo() { }
2020-07-08 22:07:32 +00:00
fn bar() { fo<|>o(); }
",
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
fn foo()
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
\<- ` ` here
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn test_hover_function_show_qualifiers() {
2020-07-08 22:07:32 +00:00
check(
r#"async fn foo<|>() {}"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
async fn foo()
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
2020-07-08 22:07:32 +00:00
check(
r#"pub const unsafe fn foo<|>() {}"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
pub const unsafe fn foo()
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
2020-07-08 22:07:32 +00:00
check(
r#"pub(crate) async unsafe extern "C" fn foo<|>() {}"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
pub(crate) async unsafe extern "C" fn foo()
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
2020-05-01 15:49:51 +00:00
#[test]
fn test_hover_trait_show_qualifiers() {
2020-07-08 22:07:32 +00:00
check_actions(
r"unsafe trait foo<|>() {}",
expect![[r#"
[
Implementaion(
FilePosition {
file_id: FileId(
1,
),
offset: 13,
},
),
]
"#]],
2020-05-01 15:49:51 +00:00
);
}
#[test]
fn test_hover_mod_with_same_name_as_function() {
2020-07-08 22:07:32 +00:00
check(
r#"
use self::m<|>y::Bar;
mod my { pub struct Bar; }
2020-07-08 22:07:32 +00:00
fn my() {}
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*my*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
mod my
2020-07-31 02:34:49 +00:00
````
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn test_hover_struct_doc_comment() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
/// bar docs
struct Bar;
2020-07-08 22:07:32 +00:00
fn foo() { let bar = Ba<|>r; }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Bar*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
struct Bar
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
bar docs
"#]],
);
}
#[test]
fn test_hover_struct_doc_attr() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
#[doc = "bar docs"]
struct Bar;
2020-07-08 22:07:32 +00:00
fn foo() { let bar = Ba<|>r; }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Bar*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
struct Bar
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
bar docs
"#]],
);
}
#[test]
fn test_hover_struct_doc_attr_multiple_and_mixed() {
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
/// bar docs 0
#[doc = "bar docs 1"]
#[doc = "bar docs 2"]
struct Bar;
2020-07-08 22:07:32 +00:00
fn foo() { let bar = Ba<|>r; }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*Bar*
2020-07-31 02:34:49 +00:00
````rust
test
````
````rust
2020-07-08 22:07:32 +00:00
struct Bar
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
bar docs 0
bar docs 1
bar docs 2
"#]],
);
}
#[test]
fn test_hover_path_link() {
2020-07-31 02:28:33 +00:00
check(
r"
//- /lib.rs
pub struct Foo;
/// [Foo](struct.Foo.html)
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[Foo](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
);
}
#[test]
2020-06-30 07:52:25 +00:00
fn test_hover_path_link_no_strip() {
2020-07-31 02:28:33 +00:00
check(
r"
//- /lib.rs
pub struct Foo;
2020-06-30 07:52:25 +00:00
/// [struct Foo](struct.Foo.html)
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[struct Foo](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-30 07:52:25 +00:00
);
}
#[test]
fn test_hover_intra_link() {
2020-07-31 02:28:33 +00:00
check(
2020-06-30 07:52:25 +00:00
r"
//- /lib.rs
pub mod foo {
pub struct Foo;
}
/// [Foo](foo::Foo)
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[Foo](https://docs.rs/test/*/test/foo/struct.Foo.html)
"#]],
);
}
#[test]
fn test_hover_intra_link_shortlink() {
2020-07-31 02:28:33 +00:00
check(
r"
//- /lib.rs
pub struct Foo;
/// [Foo]
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[Foo](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-15 02:47:33 +00:00
);
}
#[test]
fn test_hover_intra_link_shortlink_code() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [`Foo`]
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
);
}
#[test]
fn test_hover_intra_link_namespaced() {
2020-07-31 02:28:33 +00:00
check(
r"
//- /lib.rs
pub struct Foo;
fn Foo() {}
/// [Foo()]
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[Foo](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-15 02:47:33 +00:00
);
}
#[test]
fn test_hover_intra_link_shortlink_namspaced_code() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [`struct Foo`]
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-15 02:47:33 +00:00
);
}
#[test]
fn test_hover_intra_link_shortlink_namspaced_code_with_at() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [`struct@Foo`]
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-15 02:47:33 +00:00
);
}
#[test]
fn test_hover_intra_link_reference() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [my Foo][foo]
///
/// [foo]: Foo
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[my Foo](https://docs.rs/test/*/test/struct.Foo.html)
"#]],
2020-06-15 02:47:33 +00:00
);
}
#[test]
fn test_hover_external_url() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [external](https://www.google.com)
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[external](https://www.google.com)
"#]],
2020-06-15 02:47:33 +00:00
);
}
// Check that we don't rewrite links which we can't identify
#[test]
fn test_hover_unknown_target() {
2020-07-31 02:28:33 +00:00
check(
2020-06-15 02:47:33 +00:00
r"
//- /lib.rs
pub struct Foo;
/// [baz](Baz)
pub struct B<|>ar
",
2020-07-31 02:34:49 +00:00
expect![[r#"
*Bar*
````rust
test
````
````rust
pub struct Bar
````
---
[baz](Baz)
"#]],
);
}
#[test]
fn test_hover_macro_generated_struct_fn_doc_comment() {
2020-06-08 10:56:31 +00:00
mark::check!(hover_macro_generated_struct_fn_doc_comment);
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
macro_rules! bar {
() => {
struct Bar;
impl Bar {
/// Do the foo
fn foo(&self) {}
}
}
}
2020-07-08 22:07:32 +00:00
bar!();
2020-07-08 22:07:32 +00:00
fn foo() { let bar = Bar; bar.fo<|>o(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::Bar
````
````rust
2020-07-08 22:07:32 +00:00
fn foo(&self)
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
Do the foo
2020-07-08 22:07:32 +00:00
"#]],
);
}
#[test]
fn test_hover_macro_generated_struct_fn_doc_attr() {
2020-06-08 10:56:31 +00:00
mark::check!(hover_macro_generated_struct_fn_doc_attr);
2020-07-08 22:07:32 +00:00
check(
r#"
2020-07-08 22:07:32 +00:00
macro_rules! bar {
() => {
struct Bar;
impl Bar {
#[doc = "Do the foo"]
fn foo(&self) {}
}
}
}
2020-07-08 22:07:32 +00:00
bar!();
2020-07-08 22:07:32 +00:00
fn foo() { let bar = Bar; bar.fo<|>o(); }
"#,
expect![[r#"
2020-07-09 08:30:47 +00:00
*foo*
2020-07-08 22:07:32 +00:00
2020-07-31 02:34:49 +00:00
````rust
test::Bar
````
````rust
2020-07-08 22:07:32 +00:00
fn foo(&self)
2020-07-31 02:34:49 +00:00
````
---
2020-07-08 22:07:32 +00:00
Do the foo
"#]],
);
}
2020-06-03 11:15:54 +00:00
#[test]
2020-06-03 12:13:26 +00:00
fn test_hover_trait_has_impl_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"trait foo<|>() {}"#,
expect![[r#"
[
Implementaion(
FilePosition {
file_id: FileId(
1,
),
offset: 6,
},
),
]
"#]],
2020-06-03 11:15:54 +00:00
);
}
#[test]
2020-06-03 12:13:26 +00:00
fn test_hover_struct_has_impl_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r"struct foo<|>() {}",
expect![[r#"
[
Implementaion(
FilePosition {
file_id: FileId(
1,
),
offset: 7,
},
),
]
"#]],
2020-06-03 11:15:54 +00:00
);
}
#[test]
2020-06-03 12:13:26 +00:00
fn test_hover_union_has_impl_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"union foo<|>() {}"#,
expect![[r#"
[
Implementaion(
FilePosition {
2020-06-06 11:30:29 +00:00
file_id: FileId(
1,
),
2020-07-08 22:07:32 +00:00
offset: 6,
2020-06-06 11:30:29 +00:00
},
2020-07-08 22:07:32 +00:00
),
]
"#]],
2020-06-03 11:15:54 +00:00
);
}
2020-06-03 12:29:03 +00:00
#[test]
fn test_hover_enum_has_impl_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r"enum foo<|>() { A, B }",
expect![[r#"
[
Implementaion(
FilePosition {
2020-06-06 11:30:29 +00:00
file_id: FileId(
1,
),
2020-07-08 22:07:32 +00:00
offset: 5,
2020-06-06 11:30:29 +00:00
},
2020-07-08 22:07:32 +00:00
),
]
"#]],
2020-06-03 12:29:03 +00:00
);
}
2020-06-06 11:30:29 +00:00
#[test]
fn test_hover_test_has_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
#[test]
fn foo_<|>test() {}
"#,
expect![[r#"
[
Runnable(
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
),
2020-07-08 22:07:32 +00:00
full_range: 0..24,
focus_range: Some(
2020-07-08 22:07:32 +00:00
11..19,
),
2020-07-17 10:42:48 +00:00
name: "foo_test",
2020-07-30 12:51:08 +00:00
kind: FN,
container_name: None,
2020-07-08 22:07:32 +00:00
description: None,
docs: None,
},
2020-07-08 22:07:32 +00:00
kind: Test {
test_id: Path(
"foo_test",
),
attr: TestAttr {
ignore: false,
},
2020-06-06 11:30:29 +00:00
},
2020-07-08 22:07:32 +00:00
cfg_exprs: [],
2020-06-06 11:30:29 +00:00
},
2020-07-08 22:07:32 +00:00
),
]
"#]],
);
2020-06-06 11:30:29 +00:00
}
#[test]
fn test_hover_test_mod_has_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
mod tests<|> {
#[test]
fn foo_test() {}
}
"#,
expect![[r#"
[
Runnable(
Runnable {
nav: NavigationTarget {
file_id: FileId(
1,
),
2020-07-08 22:07:32 +00:00
full_range: 0..46,
focus_range: Some(
2020-07-08 22:07:32 +00:00
4..9,
),
2020-07-17 10:42:48 +00:00
name: "tests",
kind: MODULE,
container_name: None,
2020-07-08 22:07:32 +00:00
description: None,
docs: None,
},
2020-07-08 22:07:32 +00:00
kind: TestMod {
path: "tests",
},
2020-07-08 22:07:32 +00:00
cfg_exprs: [],
2020-06-06 11:30:29 +00:00
},
2020-07-08 22:07:32 +00:00
),
]
"#]],
);
2020-06-06 11:30:29 +00:00
}
#[test]
fn test_hover_struct_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
struct S{ f1: u32 }
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = S{ f1:0 }; }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..19,
focus_range: Some(
7..8,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
],
),
]
"#]],
);
}
#[test]
fn test_hover_generic_struct_has_goto_type_actions() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
struct Arg(u32);
struct S<T>{ f1: T }
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = S{ f1:Arg(0) }; }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 17..37,
focus_range: Some(
24..25,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Arg",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..16,
focus_range: Some(
7..10,
),
2020-07-17 10:42:48 +00:00
name: "Arg",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct Arg",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
fn test_hover_generic_struct_has_flattened_goto_type_actions() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
struct Arg(u32);
struct S<T>{ f1: T }
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 17..37,
focus_range: Some(
24..25,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Arg",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..16,
focus_range: Some(
7..10,
),
2020-07-17 10:42:48 +00:00
name: "Arg",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct Arg",
),
docs: None,
},
},
],
),
]
"#]],
);
}
#[test]
fn test_hover_tuple_has_goto_type_actions() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
struct A(u32);
struct B(u32);
mod M {
pub struct C(u32);
}
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = (A(1), B(2), M::C(3) ); }
"#,
expect![[r#"
[
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::A",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..14,
focus_range: Some(
7..8,
),
2020-07-17 10:42:48 +00:00
name: "A",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct A",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::B",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 15..29,
focus_range: Some(
22..23,
),
2020-07-17 10:42:48 +00:00
name: "B",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct B",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::M::C",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 42..60,
focus_range: Some(
53..54,
),
2020-07-17 10:42:48 +00:00
name: "C",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"pub struct C",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
fn test_hover_return_impl_trait_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
fn foo() -> impl Foo {}
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = foo(); }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
fn test_hover_generic_return_impl_trait_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo<T> {}
struct S;
fn foo() -> impl Foo<S> {}
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = foo(); }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..15,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 16..25,
focus_range: Some(
23..24,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
2020-06-11 20:06:58 +00:00
#[test]
fn test_hover_return_impl_traits_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
trait Bar {}
fn foo() -> impl Foo + Bar {}
2020-06-11 20:06:58 +00:00
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = foo(); }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Bar",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 13..25,
focus_range: Some(
19..22,
),
2020-07-17 10:42:48 +00:00
name: "Bar",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Bar",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
2020-06-11 20:06:58 +00:00
}
#[test]
fn test_hover_generic_return_impl_traits_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo<T> {}
trait Bar<T> {}
struct S1 {}
struct S2 {}
2020-06-11 20:06:58 +00:00
2020-07-08 22:07:32 +00:00
fn foo() -> impl Foo<S1> + Bar<S2> {}
2020-06-11 20:06:58 +00:00
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = foo(); }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..15,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Bar",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 16..31,
focus_range: Some(
22..25,
),
2020-07-17 10:42:48 +00:00
name: "Bar",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Bar",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S1",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 32..44,
focus_range: Some(
39..41,
),
2020-07-17 10:42:48 +00:00
name: "S1",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S1",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S2",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 45..57,
focus_range: Some(
52..54,
),
2020-07-17 10:42:48 +00:00
name: "S2",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S2",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
2020-06-11 20:06:58 +00:00
}
#[test]
fn test_hover_arg_impl_trait_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
fn foo(ar<|>g: &impl Foo) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
2020-06-11 20:06:58 +00:00
#[test]
fn test_hover_arg_impl_traits_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
trait Bar<T> {}
struct S{}
2020-06-11 20:06:58 +00:00
2020-07-08 22:07:32 +00:00
fn foo(ar<|>g: &impl Foo + Bar<S>) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Bar",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 13..28,
focus_range: Some(
19..22,
),
2020-07-17 10:42:48 +00:00
name: "Bar",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Bar",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 29..39,
focus_range: Some(
36..37,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
2020-06-11 20:06:58 +00:00
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
2020-06-11 20:06:58 +00:00
}
#[test]
fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo<T> {}
struct S {}
fn foo(ar<|>g: &impl Foo<S>) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..15,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 16..27,
focus_range: Some(
23..24,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
fn test_hover_dyn_return_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
struct S;
impl Foo for S {}
2020-07-08 22:07:32 +00:00
struct B<T>{}
fn foo() -> B<dyn Foo> {}
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = foo(); }
"#,
expect![[r#"
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::B",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 42..55,
focus_range: Some(
49..50,
),
2020-07-17 10:42:48 +00:00
name: "B",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct B",
),
docs: None,
},
},
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
],
),
]
"#]],
);
}
#[test]
fn test_hover_dyn_arg_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {}
fn foo(ar<|>g: &dyn Foo) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..12,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
fn test_hover_generic_dyn_arg_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo<T> {}
struct S {}
fn foo(ar<|>g: &dyn Foo<S>) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..15,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 16..27,
focus_range: Some(
23..24,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
#[test]
2020-06-10 19:56:49 +00:00
fn test_hover_goto_type_action_links_order() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait ImplTrait<T> {}
trait DynTrait<T> {}
struct B<T> {}
struct S {}
2020-06-10 19:56:49 +00:00
2020-07-08 22:07:32 +00:00
fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::ImplTrait",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..21,
focus_range: Some(
6..15,
),
2020-07-17 10:42:48 +00:00
name: "ImplTrait",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait ImplTrait",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::B",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 43..57,
focus_range: Some(
50..51,
),
2020-07-17 10:42:48 +00:00
name: "B",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct B",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::DynTrait",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 22..42,
focus_range: Some(
28..36,
),
2020-07-17 10:42:48 +00:00
name: "DynTrait",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait DynTrait",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::S",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 58..69,
focus_range: Some(
65..66,
),
2020-07-17 10:42:48 +00:00
name: "S",
2020-07-30 15:50:40 +00:00
kind: STRUCT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"struct S",
),
docs: None,
},
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
}
2020-06-10 19:58:25 +00:00
#[test]
fn test_hover_associated_type_has_goto_type_action() {
2020-07-08 22:07:32 +00:00
check_actions(
r#"
trait Foo {
type Item;
fn get(self) -> Self::Item {}
}
2020-06-10 19:58:25 +00:00
2020-07-08 22:07:32 +00:00
struct Bar{}
struct S{}
2020-06-10 19:58:25 +00:00
2020-07-08 22:07:32 +00:00
impl Foo for S { type Item = Bar; }
2020-06-10 19:58:25 +00:00
2020-07-08 22:07:32 +00:00
fn test() -> impl Foo { S {} }
2020-06-10 19:58:25 +00:00
2020-07-08 22:07:32 +00:00
fn main() { let s<|>t = test().get(); }
"#,
expect![[r#"
2020-06-30 08:23:06 +00:00
[
2020-07-08 22:07:32 +00:00
GoToType(
[
HoverGotoTypeData {
2020-07-31 02:34:49 +00:00
mod_path: "test::Foo",
2020-07-08 22:07:32 +00:00
nav: NavigationTarget {
file_id: FileId(
1,
),
full_range: 0..62,
focus_range: Some(
6..9,
),
2020-07-17 10:42:48 +00:00
name: "Foo",
2020-07-30 16:17:28 +00:00
kind: TRAIT,
2020-07-08 22:07:32 +00:00
container_name: None,
description: Some(
"trait Foo",
),
docs: None,
},
2020-06-10 19:58:25 +00:00
},
2020-07-08 22:07:32 +00:00
],
),
]
"#]],
);
2020-06-10 19:58:25 +00:00
}
2019-01-08 19:33:36 +00:00
}