1 use std::{collections::HashSet, ops::ControlFlow};
4 use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
6 base_db::{FileRange, SourceDatabase},
7 defs::{Definition, NameClass, NameRefClass},
9 generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
10 pick_best_token, try_resolve_derive_input_at, FamousDefs,
14 use itertools::Itertools;
17 algo, ast, display::fn_as_proc_macro_label, match_ast, AstNode, Direction, SyntaxKind::*,
18 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
22 display::{macro_label, TryToNav},
24 doc_attributes, extract_definitions_from_docs, remove_links, resolve_doc_path_for_def,
27 markdown_remove::remove_markdown,
29 runnables::{runnable_fn, runnable_mod},
30 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
33 #[derive(Clone, Debug, PartialEq, Eq)]
34 pub struct HoverConfig {
35 pub links_in_hover: bool,
36 pub documentation: Option<HoverDocFormat>,
40 fn markdown(&self) -> bool {
41 matches!(self.documentation, Some(HoverDocFormat::Markdown))
45 #[derive(Clone, Debug, PartialEq, Eq)]
46 pub enum HoverDocFormat {
51 #[derive(Debug, Clone)]
52 pub enum HoverAction {
54 Implementation(FilePosition),
55 Reference(FilePosition),
56 GoToType(Vec<HoverGotoTypeData>),
60 fn goto_type_from_targets(db: &RootDatabase, targets: Vec<hir::ModuleDef>) -> Self {
64 Some(HoverGotoTypeData {
65 mod_path: render_path(
68 it.name(db).map(|name| name.to_string()),
70 nav: it.try_to_nav(db)?,
74 HoverAction::GoToType(targets)
78 #[derive(Debug, Clone, Eq, PartialEq)]
79 pub struct HoverGotoTypeData {
81 pub nav: NavigationTarget,
84 /// Contains the results when hovering over an item
85 #[derive(Debug, Default)]
86 pub struct HoverResult {
88 pub actions: Vec<HoverAction>,
93 // Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
94 // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
96 // image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
99 FileRange { file_id, range }: FileRange,
100 config: &HoverConfig,
101 ) -> Option<RangeInfo<HoverResult>> {
102 let sema = hir::Semantics::new(db);
103 let file = sema.parse(file_id).syntax().clone();
105 if !range.is_empty() {
106 return hover_ranged(&file, range, &sema, config);
108 let offset = range.start();
110 let token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
111 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
112 T!['('] | T![')'] => 2,
113 kind if kind.is_trivia() => 0,
117 let mut seen = HashSet::default();
119 let mut fallback = None;
120 sema.descend_into_macros_many(token.clone())
122 .filter_map(|token| match token.parent() {
124 match find_hover_result(&sema, file_id, offset, config, token, &node, &mut seen) {
125 Some(res) => match res {
126 ControlFlow::Break(inner) => Some(inner),
127 ControlFlow::Continue(_) => {
128 if fallback.is_none() {
129 // FIXME we're only taking the first fallback into account that's not `None`
130 fallback = type_hover(&sema, config, &token);
140 // reduce all descends into a single `RangeInfo`
141 // that spans from the earliest start to the latest end (fishy/FIXME),
142 // concatenates all `Markup`s with `\n---\n`,
143 // and accumulates all actions into its `actions` vector.
144 .reduce(|mut acc, RangeInfo { range, mut info }| {
145 let start = acc.range.start().min(range.start());
146 let end = acc.range.end().max(range.end());
148 acc.range = TextRange::new(start, end);
149 acc.info.actions.append(&mut info.actions);
150 acc.info.markup = Markup::from(format!("{}\n---\n{}", acc.info.markup, info.markup));
156 fn find_hover_result(
157 sema: &Semantics<RootDatabase>,
160 config: &HoverConfig,
163 seen: &mut HashSet<Definition>,
164 ) -> Option<ControlFlow<RangeInfo<HoverResult>>> {
165 let mut range_override = None;
167 // intra-doc links and attributes are special cased
168 // so don't add them to the `seen` duplicate check
169 let mut add_to_seen_definitions = true;
171 let definition = match_ast! {
173 ast::Name(name) => NameClass::classify(sema, &name).map(|class| match class {
174 NameClass::Definition(it) | NameClass::ConstReference(it) => it,
175 NameClass::PatFieldShorthand { local_def, field_ref: _ } => Definition::Local(local_def),
177 ast::NameRef(name_ref) => NameRefClass::classify(sema, &name_ref).map(|class| match class {
178 NameRefClass::Definition(def) => def,
179 NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
180 Definition::Field(field_ref)
183 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime).map_or_else(
185 NameRefClass::classify_lifetime(&sema, &lifetime).and_then(|class| match class {
186 NameRefClass::Definition(it) => Some(it),
194 // FIXME: move comment + attribute special cases somewhere else to simplify control flow,
195 // hopefully simplifying the return type of this function in the process
196 // (the `Break`/`Continue` distinction is needed to decide whether to use fallback hovers)
198 // FIXME: hovering the intra doc link to `Foo` not working:
204 if token.kind() == COMMENT {
205 add_to_seen_definitions = false;
206 cov_mark::hit!(no_highlight_on_comment_hover);
207 let (attributes, def) = doc_attributes(sema, node)?;
208 let (docs, doc_mapping) = attributes.docs_with_rangemap(sema.db)?;
209 let (idl_range, link, ns) =
210 extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
211 let mapped = doc_mapping.map(range)?;
212 (mapped.file_id == file_id.into() && mapped.value.contains(offset)).then(||(mapped.value, link, ns))
214 range_override = Some(idl_range);
215 Some(match resolve_doc_path_for_def(sema.db,def, &link,ns)? {
216 Either::Left(it) => Definition::ModuleDef(it),
217 Either::Right(it) => Definition::Macro(it),
219 // attributes, require special machinery as they are mere ident tokens
220 } else if let Some(attr) = token.ancestors().find_map(ast::Attr::cast) {
221 add_to_seen_definitions = false;
223 if let Some(res) = try_hover_for_lint(&attr, &token) {
224 return Some(ControlFlow::Break(res));
227 range_override = Some(token.text_range());
228 try_resolve_derive_input_at(&sema, &attr, &token).map(Definition::Macro)
237 if let Some(definition) = definition {
239 if seen.contains(&definition) {
242 if add_to_seen_definitions {
243 seen.insert(definition);
245 let famous_defs = match &definition {
246 Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
247 Some(FamousDefs(&sema, sema.scope(&node).krate()))
251 if let Some(markup) =
252 hover_for_definition(sema.db, definition, famous_defs.as_ref(), config)
254 let mut res = HoverResult::default();
255 res.markup = process_markup(sema.db, definition, &markup, config);
256 if let Some(action) = show_implementations_action(sema.db, definition) {
257 res.actions.push(action);
260 if let Some(action) = show_fn_references_action(sema.db, definition) {
261 res.actions.push(action);
264 if let Some(action) = runnable_action(&sema, definition, file_id) {
265 res.actions.push(action);
268 if let Some(action) = goto_type_action_for_def(sema.db, definition) {
269 res.actions.push(action);
272 let range = range_override.unwrap_or_else(|| sema.original_range(&node).range);
273 return Some(ControlFlow::Break(RangeInfo::new(range, res)));
277 if let Some(res) = hover_for_keyword(&sema, config, &token) {
278 return Some(ControlFlow::Break(res));
281 Some(ControlFlow::Continue(()))
285 sema: &Semantics<RootDatabase>,
286 config: &HoverConfig,
288 ) -> Option<RangeInfo<HoverResult>> {
291 .take_while(|it| !ast::Item::can_cast(it.kind()))
292 .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
294 let expr_or_pat = match_ast! {
296 ast::Expr(it) => Either::Left(it),
297 ast::Pat(it) => Either::Right(it),
298 // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
299 // (e.g expanding a builtin macro). So we give up here.
300 ast::MacroCall(_it) => return None,
305 let res = hover_type_info(&sema, config, &expr_or_pat)?;
306 let range = sema.original_range(&node).range;
308 Some(RangeInfo::new(range, res))
313 range: syntax::TextRange,
314 sema: &Semantics<RootDatabase>,
315 config: &HoverConfig,
316 ) -> Option<RangeInfo<HoverResult>> {
317 let expr_or_pat = file.covering_element(range).ancestors().find_map(|it| {
320 ast::Expr(expr) => Some(Either::Left(expr)),
321 ast::Pat(pat) => Some(Either::Right(pat)),
326 let res = match &expr_or_pat {
327 Either::Left(ast::Expr::TryExpr(try_expr)) => hover_try_expr(sema, config, try_expr),
330 let res = res.or_else(|| hover_type_info(sema, config, &expr_or_pat));
332 let range = match expr_or_pat {
333 Either::Left(it) => it.syntax().text_range(),
334 Either::Right(it) => it.syntax().text_range(),
336 RangeInfo::new(range, it)
341 sema: &Semantics<RootDatabase>,
342 config: &HoverConfig,
343 try_expr: &ast::TryExpr,
344 ) -> Option<HoverResult> {
345 let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original;
346 let mut ancestors = try_expr.syntax().ancestors();
347 let mut body_ty = loop {
348 let next = ancestors.next()?;
351 ast::Fn(fn_) => sema.to_def(&fn_)?.ret_type(sema.db),
352 ast::Item(__) => return None,
353 ast::ClosureExpr(closure) => sema.type_of_expr(&closure.body()?)?.original,
354 ast::EffectExpr(effect) => if matches!(effect.effect(), ast::Effect::Async(_) | ast::Effect::Try(_)| ast::Effect::Const(_)) {
355 sema.type_of_expr(&effect.block_expr()?.into())?.original
364 if inner_ty == body_ty {
368 let mut inner_ty = inner_ty;
369 let mut s = "Try Target".to_owned();
371 let adts = inner_ty.as_adt().zip(body_ty.as_adt());
372 if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts {
373 let famous_defs = FamousDefs(sema, sema.scope(&try_expr.syntax()).krate());
374 // special case for two options, there is no value in showing them
375 if let Some(option_enum) = famous_defs.core_option_Option() {
376 if inner == option_enum && body == option_enum {
377 cov_mark::hit!(hover_try_expr_opt_opt);
382 // special case two results to show the error variants only
383 if let Some(result_enum) = famous_defs.core_result_Result() {
384 if inner == result_enum && body == result_enum {
385 let error_type_args =
386 inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1));
387 if let Some((inner, body)) = error_type_args {
390 s = "Try Error".to_owned();
396 let mut res = HoverResult::default();
398 let mut targets: Vec<hir::ModuleDef> = Vec::new();
399 let mut push_new_def = |item: hir::ModuleDef| {
400 if !targets.contains(&item) {
404 walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def);
405 walk_and_push_ty(sema.db, &body_ty, &mut push_new_def);
406 res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
408 let inner_ty = inner_ty.display(sema.db).to_string();
409 let body_ty = body_ty.display(sema.db).to_string();
410 let ty_len_max = inner_ty.len().max(body_ty.len());
412 let l = "Propagated as: ".len() - " Type: ".len();
413 let static_text_len_diff = l as isize - s.len() as isize;
414 let tpad = static_text_len_diff.max(0) as usize;
415 let ppad = static_text_len_diff.min(0).abs() as usize;
417 res.markup = format!(
418 "{bt_start}{} Type: {:>pad0$}\nPropagated as: {:>pad1$}\n{bt_end}",
422 pad0 = ty_len_max + tpad,
423 pad1 = ty_len_max + ppad,
424 bt_start = if config.markdown() { "```text\n" } else { "" },
425 bt_end = if config.markdown() { "```\n" } else { "" }
432 sema: &Semantics<RootDatabase>,
433 config: &HoverConfig,
434 expr_or_pat: &Either<ast::Expr, ast::Pat>,
435 ) -> Option<HoverResult> {
436 let TypeInfo { original, adjusted } = match expr_or_pat {
437 Either::Left(expr) => sema.type_of_expr(expr)?,
438 Either::Right(pat) => sema.type_of_pat(pat)?,
441 let mut res = HoverResult::default();
442 let mut targets: Vec<hir::ModuleDef> = Vec::new();
443 let mut push_new_def = |item: hir::ModuleDef| {
444 if !targets.contains(&item) {
448 walk_and_push_ty(sema.db, &original, &mut push_new_def);
450 res.markup = if let Some(adjusted_ty) = adjusted {
451 walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
452 let original = original.display(sema.db).to_string();
453 let adjusted = adjusted_ty.display(sema.db).to_string();
454 let static_text_diff_len = "Coerced to: ".len() - "Type: ".len();
456 "{bt_start}Type: {:>apad$}\nCoerced to: {:>opad$}\n{bt_end}",
459 apad = static_text_diff_len + adjusted.len().max(original.len()),
460 opad = original.len(),
461 bt_start = if config.markdown() { "```text\n" } else { "" },
462 bt_end = if config.markdown() { "```\n" } else { "" }
466 if config.markdown() {
467 Markup::fenced_block(&original.display(sema.db))
469 original.display(sema.db).to_string().into()
472 res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
476 fn try_hover_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
477 let (path, tt) = attr.as_simple_call()?;
478 if !tt.syntax().text_range().contains(token.text_range().start()) {
481 let (is_clippy, lints) = match &*path {
482 "feature" => (false, FEATURES),
483 "allow" | "deny" | "forbid" | "warn" => {
484 let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev)
485 .filter(|t| t.kind() == T![:])
486 .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
487 .filter(|t| t.kind() == T![:])
488 .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
490 t.kind() == T![ident] && t.into_token().map_or(false, |t| t.text() == "clippy")
495 (false, DEFAULT_LINTS)
502 let needle = if is_clippy {
503 tmp = format!("clippy::{}", token.text());
510 lints.binary_search_by_key(&needle, |lint| lint.label).ok().map(|idx| &lints[idx])?;
514 markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)),
520 fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
521 fn to_action(nav_target: NavigationTarget) -> HoverAction {
522 HoverAction::Implementation(FilePosition {
523 file_id: nav_target.file_id,
524 offset: nav_target.focus_or_full_range().start(),
528 let adt = match def {
529 Definition::ModuleDef(hir::ModuleDef::Trait(it)) => {
530 return it.try_to_nav(db).map(to_action)
532 Definition::ModuleDef(hir::ModuleDef::Adt(it)) => Some(it),
533 Definition::SelfType(it) => it.self_ty(db).as_adt(),
536 adt.try_to_nav(db).map(to_action)
539 fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
541 Definition::ModuleDef(hir::ModuleDef::Function(it)) => {
542 it.try_to_nav(db).map(|nav_target| {
543 HoverAction::Reference(FilePosition {
544 file_id: nav_target.file_id,
545 offset: nav_target.focus_or_full_range().start(),
554 sema: &hir::Semantics<RootDatabase>,
557 ) -> Option<HoverAction> {
559 Definition::ModuleDef(it) => match it {
560 hir::ModuleDef::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
561 hir::ModuleDef::Function(func) => {
562 let src = func.source(sema.db)?;
563 if src.file_id != file_id.into() {
564 cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
565 cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
569 runnable_fn(sema, func).map(HoverAction::Runnable)
577 fn goto_type_action_for_def(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
578 let mut targets: Vec<hir::ModuleDef> = Vec::new();
579 let mut push_new_def = |item: hir::ModuleDef| {
580 if !targets.contains(&item) {
585 if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def {
586 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
589 Definition::Local(it) => it.ty(db),
590 Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db),
591 Definition::Field(field) => field.ty(db),
595 walk_and_push_ty(db, &ty, &mut push_new_def);
598 Some(HoverAction::goto_type_from_targets(db, targets))
604 push_new_def: &mut dyn FnMut(hir::ModuleDef),
607 if let Some(adt) = t.as_adt() {
608 push_new_def(adt.into());
609 } else if let Some(trait_) = t.as_dyn_trait() {
610 push_new_def(trait_.into());
611 } else if let Some(traits) = t.as_impl_traits(db) {
612 traits.into_iter().for_each(|it| push_new_def(it.into()));
613 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
614 push_new_def(trait_.into());
619 fn hover_markup(docs: Option<String>, desc: String, mod_path: Option<String>) -> Option<Markup> {
620 let mut buf = String::new();
622 if let Some(mod_path) = mod_path {
623 if !mod_path.is_empty() {
624 format_to!(buf, "```rust\n{}\n```\n\n", mod_path);
627 format_to!(buf, "```rust\n{}\n```", desc);
629 if let Some(doc) = docs {
630 format_to!(buf, "\n___\n\n{}", doc);
639 config: &HoverConfig,
641 let markup = markup.as_str();
642 let markup = if !config.markdown() {
643 remove_markdown(markup)
644 } else if config.links_in_hover {
645 rewrite_links(db, markup, def)
652 fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String> {
654 Definition::Field(f) => Some(f.parent_def(db).name(db)),
655 Definition::Local(l) => l.parent(db).name(db),
656 Definition::ModuleDef(md) => match md {
657 hir::ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
658 hir::AssocItemContainer::Trait(t) => Some(t.name(db)),
659 hir::AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
661 hir::ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
666 .map(|name| name.to_string())
669 fn render_path(db: &RootDatabase, module: hir::Module, item_name: Option<String>) -> String {
671 db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
672 let module_path = module
676 .flat_map(|it| it.name(db).map(|name| name.to_string()));
677 crate_name.into_iter().chain(module_path).chain(item_name).join("::")
680 fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
681 if let Definition::GenericParam(_) = def {
684 def.module(db).map(|module| render_path(db, module, definition_owner_name(db, def)))
687 fn hover_for_definition(
690 famous_defs: Option<&FamousDefs>,
691 config: &HoverConfig,
692 ) -> Option<Markup> {
693 let mod_path = definition_mod_path(db, &def);
694 let (label, docs) = match def {
695 Definition::Macro(it) => (
696 match &it.source(db)?.value {
697 Either::Left(mac) => macro_label(mac),
698 Either::Right(mac_fn) => fn_as_proc_macro_label(mac_fn),
702 Definition::Field(def) => label_and_docs(db, def),
703 Definition::ModuleDef(it) => match it {
704 hir::ModuleDef::Module(it) => label_and_docs(db, it),
705 hir::ModuleDef::Function(it) => label_and_docs(db, it),
706 hir::ModuleDef::Adt(it) => label_and_docs(db, it),
707 hir::ModuleDef::Variant(it) => label_and_docs(db, it),
708 hir::ModuleDef::Const(it) => label_and_docs(db, it),
709 hir::ModuleDef::Static(it) => label_and_docs(db, it),
710 hir::ModuleDef::Trait(it) => label_and_docs(db, it),
711 hir::ModuleDef::TypeAlias(it) => label_and_docs(db, it),
712 hir::ModuleDef::BuiltinType(it) => {
714 .and_then(|fd| hover_for_builtin(fd, it))
715 .or_else(|| Some(Markup::fenced_block(&it.name())))
718 Definition::Local(it) => return hover_for_local(it, db),
719 Definition::SelfType(impl_def) => {
720 impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
722 Definition::GenericParam(it) => label_and_docs(db, it),
723 Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db))),
727 docs.filter(|_| config.documentation.is_some()).map(Into::into),
732 fn label_and_docs<D>(db: &RootDatabase, def: D) -> (String, Option<hir::Documentation>)
734 D: HasAttrs + HirDisplay,
736 let label = def.display(db).to_string();
737 let docs = def.attrs(db).docs();
742 fn hover_for_local(it: hir::Local, db: &RootDatabase) -> Option<Markup> {
744 let ty = ty.display(db);
745 let is_mut = if it.is_mut(db) { "mut " } else { "" };
746 let desc = match it.source(db).value {
747 Either::Left(ident) => {
748 let name = it.name(db).unwrap();
749 let let_kw = if ident
752 .map_or(false, |p| p.kind() == LET_STMT || p.kind() == CONDITION)
758 format!("{}{}{}: {}", let_kw, is_mut, name, ty)
760 Either::Right(_) => format!("{}self: {}", is_mut, ty),
762 hover_markup(None, desc, None)
765 fn hover_for_keyword(
766 sema: &Semantics<RootDatabase>,
767 config: &HoverConfig,
769 ) -> Option<RangeInfo<HoverResult>> {
770 if !token.kind().is_keyword() || !config.documentation.is_some() {
773 let famous_defs = FamousDefs(sema, sema.scope(&token.parent()?).krate());
774 // std exposes {}_keyword modules with docstrings on the root to document keywords
775 let keyword_mod = format!("{}_keyword", token.text());
776 let doc_owner = find_std_module(&famous_defs, &keyword_mod)?;
777 let docs = doc_owner.attrs(sema.db).docs()?;
778 let markup = process_markup(
780 Definition::ModuleDef(doc_owner.into()),
781 &hover_markup(Some(docs.into()), token.text().into(), None)?,
784 Some(RangeInfo::new(token.text_range(), HoverResult { markup, actions: Default::default() }))
787 fn hover_for_builtin(famous_defs: &FamousDefs, builtin: hir::BuiltinType) -> Option<Markup> {
788 // std exposes prim_{} modules with docstrings on the root to document the builtins
789 let primitive_mod = format!("prim_{}", builtin.name());
790 let doc_owner = find_std_module(famous_defs, &primitive_mod)?;
791 let docs = doc_owner.attrs(famous_defs.0.db).docs()?;
792 hover_markup(Some(docs.into()), builtin.name().to_string(), None)
795 fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module> {
796 let db = famous_defs.0.db;
797 let std_crate = famous_defs.std()?;
798 let std_root_module = std_crate.root_module(db);
801 .find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
806 use expect_test::{expect, Expect};
807 use ide_db::base_db::{FileLoader, FileRange};
808 use syntax::TextRange;
810 use crate::{fixture, hover::HoverDocFormat, HoverConfig};
812 fn check_hover_no_result(ra_fixture: &str) {
813 let (analysis, position) = fixture::position(ra_fixture);
817 links_in_hover: true,
818 documentation: Some(HoverDocFormat::Markdown),
820 FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
823 assert!(hover.is_none());
826 fn check(ra_fixture: &str, expect: Expect) {
827 let (analysis, position) = fixture::position(ra_fixture);
831 links_in_hover: true,
832 documentation: Some(HoverDocFormat::Markdown),
834 FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
839 let content = analysis.db.file_text(position.file_id);
840 let hovered_element = &content[hover.range];
842 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
843 expect.assert_eq(&actual)
846 fn check_hover_no_links(ra_fixture: &str, expect: Expect) {
847 let (analysis, position) = fixture::position(ra_fixture);
851 links_in_hover: false,
852 documentation: Some(HoverDocFormat::Markdown),
854 FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
859 let content = analysis.db.file_text(position.file_id);
860 let hovered_element = &content[hover.range];
862 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
863 expect.assert_eq(&actual)
866 fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) {
867 let (analysis, position) = fixture::position(ra_fixture);
871 links_in_hover: true,
872 documentation: Some(HoverDocFormat::PlainText),
874 FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
879 let content = analysis.db.file_text(position.file_id);
880 let hovered_element = &content[hover.range];
882 let actual = format!("*{}*\n{}\n", hovered_element, hover.info.markup);
883 expect.assert_eq(&actual)
886 fn check_actions(ra_fixture: &str, expect: Expect) {
887 let (analysis, file_id, position) = fixture::range_or_position(ra_fixture);
891 links_in_hover: true,
892 documentation: Some(HoverDocFormat::Markdown),
894 FileRange { file_id, range: position.range_or_empty() },
898 expect.assert_debug_eq(&hover.info.actions)
901 fn check_hover_range(ra_fixture: &str, expect: Expect) {
902 let (analysis, range) = fixture::range(ra_fixture);
906 links_in_hover: false,
907 documentation: Some(HoverDocFormat::Markdown),
913 expect.assert_eq(hover.info.markup.as_str())
916 fn check_hover_range_no_results(ra_fixture: &str) {
917 let (analysis, range) = fixture::range(ra_fixture);
921 links_in_hover: false,
922 documentation: Some(HoverDocFormat::Markdown),
927 assert!(hover.is_none());
931 fn hover_descend_macros_avoids_duplicates() {
934 macro_rules! dupe_use {
958 fn hover_shows_all_macro_descends() {
1007 fn hover_shows_type_of_an_expression() {
1010 pub fn foo() -> u32 { 1 }
1013 let foo_test = foo()$0;
1026 fn hover_remove_markdown_if_configured() {
1027 check_hover_no_markdown(
1029 pub fn foo() -> u32 { 1 }
1032 let foo_test = foo()$0;
1043 fn hover_shows_long_type_of_an_expression() {
1046 struct Scan<A, B, C> { a: A, b: B, c: C }
1047 struct Iter<I> { inner: I }
1048 enum Option<T> { Some(T), None }
1050 struct OtherStruct<T> { i: T }
1052 fn scan<A, B, C>(a: A, b: B, c: C) -> Iter<Scan<OtherStruct<A>, B, C>> {
1053 Iter { inner: Scan { a, b, c } }
1058 let closure = |memo: &mut u32, value: &u32, _another: &mut u32| -> Option<u32> {
1059 Option::Some(*memo + value)
1062 let mut iter$0 = scan(OtherStruct { i: num }, closure, number);
1069 let mut iter: Iter<Scan<OtherStruct<OtherStruct<i32>>, |&mut u32, &u32, &mut u32| -> Option<u32>, u32>>
1076 fn hover_shows_fn_signature() {
1077 // Single file with result
1080 pub fn foo() -> u32 { 1 }
1082 fn main() { let foo_test = fo$0o(); }
1097 // Multiple candidates but results are ambiguous.
1101 pub fn foo() -> u32 { 1 }
1104 pub fn foo() -> &str { "" }
1107 pub fn foo(a: u32, b: u32) {}
1114 fn main() { let foo_test = fo$0o(); }
1124 // Use literal `crate` in path
1129 fn foo() -> crate::X { X }
1131 fn main() { f$0oo(); }
1141 fn foo() -> crate::X
1146 // Check `super` in path
1151 mod m { pub fn foo() -> super::X { super::X } }
1153 fn main() { m::f$0oo(); }
1163 pub fn foo() -> super::X
1170 fn hover_shows_fn_signature_with_type_params() {
1173 pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str { }
1175 fn main() { let foo_test = fo$0o(); }
1185 pub fn foo<'a, T>(b: &'a T) -> &'a str
1194 fn hover_shows_fn_signature_on_fn_name() {
1197 pub fn foo$0(a: u32, b: u32) -> u32 {}
1209 pub fn foo(a: u32, b: u32) -> u32
1216 fn hover_shows_fn_doc() {
1221 /// # use std::path::Path;
1223 /// foo(Path::new("hello, world!"))
1225 pub fn foo$0(_: &Path) {}
1237 pub fn foo(_: &Path)
1245 # use std::path::Path;
1247 foo(Path::new("hello, world!"))
1254 fn hover_shows_fn_doc_attr_raw_string() {
1257 #[doc = r#"Raw string doc attr"#]
1258 pub fn foo$0(_: &Path) {}
1270 pub fn foo(_: &Path)
1281 fn hover_shows_struct_field_info() {
1282 // Hovering over the field when instantiating
1285 struct Foo { field_a: u32 }
1288 let foo = Foo { field_a$0: 0, };
1304 // Hovering over the field in the definition
1307 struct Foo { field_a$0: u32 }
1310 let foo = Foo { field_a: 0 };
1328 fn hover_const_static() {
1330 r#"const foo$0: u32 = 123;"#,
1344 r#"static foo$0: u32 = 456;"#,
1360 fn hover_default_generic_types() {
1363 struct Test<K, T = u8> { k: K, t: T }
1366 let zz$0 = Test { t: 23u8, k: 33 };
1372 let zz: Test<i32, u8>
1382 enum Option<T> { Some(T) }
1385 fn main() { So$0me(12); }
1402 enum Option<T> { Some(T) }
1405 fn main() { let b$0ar = Some(12); }
1411 let bar: Option<i32>
1418 fn hover_enum_variant() {
1422 /// The None variant
1446 /// The Some variant
1450 let s = Option::Som$0e(12);
1472 fn hover_for_local_variable() {
1474 r#"fn func(foo: i32) { fo$0o; }"#,
1486 fn hover_for_local_variable_pat() {
1488 r#"fn func(fo$0o: i32) {}"#,
1500 fn hover_local_var_edge() {
1502 r#"fn func(foo: i32) { if true { $0foo; }; }"#,
1514 fn hover_for_param_edge() {
1516 r#"fn func($0foo: i32) {}"#,
1528 fn hover_for_param_with_multiple_traits() {
1533 type Target: ?Sized;
1536 type Target: ?Sized;
1538 fn f(_x$0: impl Deref<Target=u8> + DerefMut<Target=u8>) {}"#,
1543 _x: impl Deref<Target = u8> + DerefMut<Target = u8>
1550 fn test_hover_infer_associated_method_result() {
1553 struct Thing { x: u32 }
1556 fn new() -> Thing { Thing { x: 0 } }
1559 fn main() { let foo_$0test = Thing::new(); }
1572 fn test_hover_infer_associated_method_exact() {
1576 struct Thing { x: u32 }
1579 fn new() -> Thing { Thing { x: 0 } }
1583 fn main() { let foo_test = wrapper::Thing::new$0(); }
1589 test::wrapper::Thing
1600 fn test_hover_infer_associated_const_in_pattern() {
1631 fn test_hover_self() {
1634 struct Thing { x: u32 }
1636 fn new() -> Self { Self$0 { x: 0 } }
1653 struct Thing { x: u32 }
1655 fn new() -> Self$0 { Self { x: 0 } }
1674 pub fn new() -> Self$0 { Thing::A }
1693 pub fn thing(a: Self$0) {}
1711 fn test_hover_shadowing_pat() {
1732 fn test_hover_macro_invocation() {
1735 macro_rules! foo { () => {} }
1737 fn f() { fo$0o!(); }
1754 fn test_hover_macro2_invocation() {
1762 fn f() { fo$0o!(); }
1785 fn test_hover_tuple_field() {
1787 r#"struct TS(String, i32$0);"#,
1799 fn test_hover_through_macro() {
1802 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1805 fn bar() { fo$0o(); }
1823 fn test_hover_through_expr_in_macro() {
1826 macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
1827 fn foo(bar:u32) { let a = id!(ba$0r); }
1840 fn test_hover_through_expr_in_macro_recursive() {
1843 macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1844 macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1845 fn foo(bar:u32) { let a = id!(ba$0r); }
1858 fn test_hover_through_func_in_macro_recursive() {
1861 macro_rules! id_deep { ($($tt:tt)*) => { $($tt)* } }
1862 macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } }
1863 fn bar() -> u32 { 0 }
1864 fn foo() { let a = id!([0u32, bar($0)] ); }
1876 fn test_hover_through_literal_string_in_macro() {
1879 macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
1881 let mastered_for_itunes = "";
1882 let _ = arr!("Tr$0acks", &mastered_for_itunes);
1895 fn test_hover_through_assert_macro() {
1898 #[rustc_builtin_macro]
1899 macro_rules! assert {}
1901 fn bar() -> bool { true }
1921 fn test_hover_through_literal_string_in_builtin_macro() {
1922 check_hover_no_result(
1924 #[rustc_builtin_macro]
1925 macro_rules! format {}
1928 format!("hel$0lo {}", 0);
1935 fn test_hover_non_ascii_space_doc() {
1938 /// <- `\u{3000}` here
1941 fn bar() { fo$0o(); }
1962 fn test_hover_function_show_qualifiers() {
1964 r#"async fn foo$0() {}"#,
1978 r#"pub const unsafe fn foo$0() {}"#,
1987 pub const unsafe fn foo()
1991 // Top level `pub(crate)` will be displayed as no visibility.
1993 r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
2002 pub(crate) async unsafe extern "C" fn foo()
2009 fn test_hover_trait_show_qualifiers() {
2011 r"unsafe trait foo$0() {}",
2028 fn test_hover_extern_crate() {
2031 //- /main.rs crate:main deps:std
2033 //- /std/lib.rs crate:std
2034 //! Standard library for this test
2048 Standard library for this test
2056 //- /main.rs crate:main deps:std
2057 extern crate std as ab$0c;
2058 //- /std/lib.rs crate:std
2059 //! Standard library for this test
2073 Standard library for this test
2082 fn test_hover_mod_with_same_name_as_function() {
2085 use self::m$0y::Bar;
2086 mod my { pub struct Bar; }
2105 fn test_hover_struct_doc_comment() {
2108 /// This is an example
2116 /// assert_eq!(6, my_crate::add_one(5));
2120 fn foo() { let bar = Ba$0r; }
2143 assert_eq!(6, my_crate::add_one(5));
2150 fn test_hover_struct_doc_attr() {
2156 fn foo() { let bar = Ba$0r; }
2177 fn test_hover_struct_doc_attr_multiple_and_mixed() {
2181 #[doc = "bar docs 1"]
2182 #[doc = "bar docs 2"]
2185 fn foo() { let bar = Ba$0r; }
2208 fn test_hover_external_url() {
2212 /// [external](https://www.google.com)
2228 [external](https://www.google.com)
2233 // Check that we don't rewrite links which we can't identify
2235 fn test_hover_unknown_target() {
2261 fn test_hover_no_links() {
2262 check_hover_no_links(
2265 /// case 1. bare URL: https://www.example.com/
2266 /// case 2. inline URL with title: [example](https://www.example.com/)
2267 /// case 3. code reference: [`Result`]
2268 /// case 4. code reference but miss footnote: [`String`]
2269 /// case 5. autolink: <http://www.example.com/>
2270 /// case 6. email address: <test@example.com>
2271 /// case 7. reference: [example][example]
2272 /// case 8. collapsed link: [example][]
2273 /// case 9. shortcut link: [example]
2274 /// case 10. inline without URL: [example]()
2275 /// case 11. reference: [foo][foo]
2276 /// case 12. reference: [foo][bar]
2277 /// case 13. collapsed link: [foo][]
2278 /// case 14. shortcut link: [foo]
2279 /// case 15. inline without URL: [foo]()
2280 /// case 16. just escaped text: \[foo]
2281 /// case 17. inline link: [Foo](foo::Foo)
2283 /// [`Result`]: ../../std/result/enum.Result.html
2284 /// [^example]: https://www.example.com/
2301 case 1. bare URL: https://www.example.com/
2302 case 2. inline URL with title: [example](https://www.example.com/)
2303 case 3. code reference: `Result`
2304 case 4. code reference but miss footnote: `String`
2305 case 5. autolink: http://www.example.com/
2306 case 6. email address: test@example.com
2307 case 7. reference: example
2308 case 8. collapsed link: example
2309 case 9. shortcut link: example
2310 case 10. inline without URL: example
2311 case 11. reference: foo
2312 case 12. reference: foo
2313 case 13. collapsed link: foo
2314 case 14. shortcut link: foo
2315 case 15. inline without URL: foo
2316 case 16. just escaped text: \[foo\]
2317 case 17. inline link: Foo
2319 [^example]: https://www.example.com/
2325 fn test_hover_macro_generated_struct_fn_doc_comment() {
2326 cov_mark::check!(hover_macro_generated_struct_fn_doc_comment);
2342 fn foo() { let bar = Bar; bar.fo$0o(); }
2363 fn test_hover_macro_generated_struct_fn_doc_attr() {
2364 cov_mark::check!(hover_macro_generated_struct_fn_doc_attr);
2372 #[doc = "Do the foo"]
2380 fn foo() { let bar = Bar; bar.fo$0o(); }
2401 fn test_hover_trait_has_impl_action() {
2403 r#"trait foo$0() {}"#,
2420 fn test_hover_struct_has_impl_action() {
2422 r"struct foo$0() {}",
2439 fn test_hover_union_has_impl_action() {
2441 r#"union foo$0() {}"#,
2458 fn test_hover_enum_has_impl_action() {
2460 r"enum foo$0() { A, B }",
2477 fn test_hover_self_has_impl_action() {
2479 r#"struct foo where Self$0:;"#,
2496 fn test_hover_test_has_action() {
2514 use_name_in_title: false,
2515 nav: NavigationTarget {
2520 focus_range: 11..19,
2541 fn test_hover_test_mod_has_action() {
2553 use_name_in_title: false,
2554 nav: NavigationTarget {
2562 description: "mod tests",
2576 fn test_hover_struct_has_goto_type_action() {
2581 fn main() { let s$0t = S{ f1:0 }; }
2588 mod_path: "test::S",
2589 nav: NavigationTarget {
2597 description: "struct S",
2608 fn test_hover_generic_struct_has_goto_type_actions() {
2612 struct S<T>{ f1: T }
2614 fn main() { let s$0t = S{ f1:Arg(0) }; }
2621 mod_path: "test::S",
2622 nav: NavigationTarget {
2627 focus_range: 24..25,
2630 description: "struct S<T>",
2634 mod_path: "test::Arg",
2635 nav: NavigationTarget {
2643 description: "struct Arg",
2654 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
2658 struct S<T>{ f1: T }
2660 fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
2667 mod_path: "test::S",
2668 nav: NavigationTarget {
2673 focus_range: 24..25,
2676 description: "struct S<T>",
2680 mod_path: "test::Arg",
2681 nav: NavigationTarget {
2689 description: "struct Arg",
2700 fn test_hover_tuple_has_goto_type_actions() {
2709 fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
2716 mod_path: "test::A",
2717 nav: NavigationTarget {
2725 description: "struct A",
2729 mod_path: "test::B",
2730 nav: NavigationTarget {
2735 focus_range: 22..23,
2738 description: "struct B",
2742 mod_path: "test::M::C",
2743 nav: NavigationTarget {
2748 focus_range: 53..54,
2751 description: "pub struct C",
2762 fn test_hover_return_impl_trait_has_goto_type_action() {
2766 fn foo() -> impl Foo {}
2768 fn main() { let s$0t = foo(); }
2775 mod_path: "test::Foo",
2776 nav: NavigationTarget {
2784 description: "trait Foo",
2795 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
2800 fn foo() -> impl Foo<S> {}
2802 fn main() { let s$0t = foo(); }
2809 mod_path: "test::Foo",
2810 nav: NavigationTarget {
2818 description: "trait Foo<T>",
2822 mod_path: "test::S",
2823 nav: NavigationTarget {
2828 focus_range: 23..24,
2831 description: "struct S",
2842 fn test_hover_return_impl_traits_has_goto_type_action() {
2847 fn foo() -> impl Foo + Bar {}
2849 fn main() { let s$0t = foo(); }
2856 mod_path: "test::Foo",
2857 nav: NavigationTarget {
2865 description: "trait Foo",
2869 mod_path: "test::Bar",
2870 nav: NavigationTarget {
2875 focus_range: 19..22,
2878 description: "trait Bar",
2889 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
2897 fn foo() -> impl Foo<S1> + Bar<S2> {}
2899 fn main() { let s$0t = foo(); }
2906 mod_path: "test::Foo",
2907 nav: NavigationTarget {
2915 description: "trait Foo<T>",
2919 mod_path: "test::Bar",
2920 nav: NavigationTarget {
2925 focus_range: 22..25,
2928 description: "trait Bar<T>",
2932 mod_path: "test::S1",
2933 nav: NavigationTarget {
2938 focus_range: 39..41,
2941 description: "struct S1",
2945 mod_path: "test::S2",
2946 nav: NavigationTarget {
2951 focus_range: 52..54,
2954 description: "struct S2",
2965 fn test_hover_arg_impl_trait_has_goto_type_action() {
2969 fn foo(ar$0g: &impl Foo) {}
2976 mod_path: "test::Foo",
2977 nav: NavigationTarget {
2985 description: "trait Foo",
2996 fn test_hover_arg_impl_traits_has_goto_type_action() {
3003 fn foo(ar$0g: &impl Foo + Bar<S>) {}
3010 mod_path: "test::Foo",
3011 nav: NavigationTarget {
3019 description: "trait Foo",
3023 mod_path: "test::Bar",
3024 nav: NavigationTarget {
3029 focus_range: 19..22,
3032 description: "trait Bar<T>",
3036 mod_path: "test::S",
3037 nav: NavigationTarget {
3042 focus_range: 36..37,
3045 description: "struct S",
3056 fn test_hover_async_block_impl_trait_has_goto_type_action() {
3059 //- minicore: future
3062 let fo$0o = async { S };
3070 mod_path: "core::future::Future",
3071 nav: NavigationTarget {
3075 full_range: 254..436,
3076 focus_range: 293..299,
3079 description: "pub trait Future",
3083 mod_path: "test::S",
3084 nav: NavigationTarget {
3092 description: "struct S",
3103 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
3108 fn foo(ar$0g: &impl Foo<S>) {}
3115 mod_path: "test::Foo",
3116 nav: NavigationTarget {
3124 description: "trait Foo<T>",
3128 mod_path: "test::S",
3129 nav: NavigationTarget {
3134 focus_range: 23..24,
3137 description: "struct S",
3148 fn test_hover_dyn_return_has_goto_type_action() {
3156 fn foo() -> B<dyn Foo> {}
3158 fn main() { let s$0t = foo(); }
3165 mod_path: "test::B",
3166 nav: NavigationTarget {
3171 focus_range: 49..50,
3174 description: "struct B<T>",
3178 mod_path: "test::Foo",
3179 nav: NavigationTarget {
3187 description: "trait Foo",
3198 fn test_hover_dyn_arg_has_goto_type_action() {
3202 fn foo(ar$0g: &dyn Foo) {}
3209 mod_path: "test::Foo",
3210 nav: NavigationTarget {
3218 description: "trait Foo",
3229 fn test_hover_generic_dyn_arg_has_goto_type_action() {
3234 fn foo(ar$0g: &dyn Foo<S>) {}
3241 mod_path: "test::Foo",
3242 nav: NavigationTarget {
3250 description: "trait Foo<T>",
3254 mod_path: "test::S",
3255 nav: NavigationTarget {
3260 focus_range: 23..24,
3263 description: "struct S",
3274 fn test_hover_goto_type_action_links_order() {
3277 trait ImplTrait<T> {}
3278 trait DynTrait<T> {}
3282 fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
3289 mod_path: "test::ImplTrait",
3290 nav: NavigationTarget {
3298 description: "trait ImplTrait<T>",
3302 mod_path: "test::B",
3303 nav: NavigationTarget {
3308 focus_range: 50..51,
3311 description: "struct B<T>",
3315 mod_path: "test::DynTrait",
3316 nav: NavigationTarget {
3321 focus_range: 28..36,
3324 description: "trait DynTrait<T>",
3328 mod_path: "test::S",
3329 nav: NavigationTarget {
3334 focus_range: 65..66,
3337 description: "struct S",
3348 fn test_hover_associated_type_has_goto_type_action() {
3353 fn get(self) -> Self::Item {}
3359 impl Foo for S { type Item = Bar; }
3361 fn test() -> impl Foo { S {} }
3363 fn main() { let s$0t = test().get(); }
3370 mod_path: "test::Foo",
3371 nav: NavigationTarget {
3379 description: "trait Foo",
3390 fn test_hover_const_param_has_goto_type_action() {
3394 struct Foo<const BAR: Bar>;
3396 impl<const BAR: Bar> Foo<BAR$0> {}
3403 mod_path: "test::Bar",
3404 nav: NavigationTarget {
3412 description: "struct Bar",
3423 fn test_hover_type_param_has_goto_type_action() {
3428 fn foo<T: Foo>(t: T$0){}
3435 mod_path: "test::Foo",
3436 nav: NavigationTarget {
3444 description: "trait Foo",
3455 fn test_hover_self_has_go_to_type() {
3468 mod_path: "test::Foo",
3469 nav: NavigationTarget {
3477 description: "struct Foo",
3488 fn hover_displays_normalized_crate_names() {
3491 //- /lib.rs crate:name-with-dashes
3493 pub struct Thing { x: u32 }
3496 pub fn new() -> Thing { Thing { x: 0 } }
3500 //- /main.rs crate:main deps:name-with-dashes
3501 fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); }
3507 name_with_dashes::wrapper::Thing
3511 pub fn new() -> Thing
3518 fn hover_field_pat_shorthand_ref_match_ergonomics() {
3541 fn hover_self_param_shows_type() {
3560 fn hover_self_param_shows_type_for_arbitrary_self_type() {
3566 fn bar(sel$0f: Arc<Foo>) {}
3580 fn hover_doc_outer_inner() {
3587 /// This comment belongs to the function
3611 fn hover_doc_outer_inner_attribue() {
3614 #[doc = "Be quick;"]
3616 #![doc = "time is mana"]
3618 #[doc = "This comment belongs to the function"]
3642 fn hover_doc_block_style_indentend() {
3676 fn hover_comments_dont_highlight_parent() {
3677 cov_mark::check!(no_highlight_on_comment_hover);
3678 check_hover_no_result(
3706 fn hover_lifetime() {
3708 r#"fn foo<'lifetime>(_: &'lifetime$0 ()) {}"#,
3720 fn hover_type_param() {
3727 impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {}
3751 // lifetimes bounds arent being tracked yet
3756 impl<T: 'static> Foo<T$0> {}
3769 fn hover_type_param_sized_bounds() {
3770 // implicit `: Sized` bound
3776 impl<T: Trait> Foo<T$0> {}
3791 impl<T: Trait + ?Sized> Foo<T$0> {}
3803 mod type_param_sized_bounds {
3807 fn single_implicit() {
3824 fn single_explicit() {
3828 fn foo<T$0: Sized>() {}
3841 fn single_relaxed() {
3845 fn foo<T$0: ?Sized>() {}
3858 fn multiple_implicit() {
3863 fn foo<T$0: Trait>() {}
3876 fn multiple_explicit() {
3881 fn foo<T$0: Trait + Sized>() {}
3894 fn multiple_relaxed() {
3899 fn foo<T$0: Trait + ?Sized>() {}
3916 fn foo<T$0: ?Sized + Sized + Sized>() {}
3930 fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
3944 fn hover_const_param() {
3947 struct Foo<const LEN: usize>;
3948 impl<const LEN: usize> Foo<LEN$0> {}
3961 fn hover_const_pat() {
3965 const FOO: usize = 3;
3992 fn hover_mod_def() {
4019 fn hover_self_in_use() {
4022 //! This should not appear
4024 /// But this should appear
4027 use foo::bar::{self$0};
4042 But this should appear
4048 fn hover_keyword() {
4051 //- /main.rs crate:main deps:std
4052 fn f() { retur$0n; }
4053 //- /libstd.rs crate:std
4054 /// Docs for return_keyword
4055 mod return_keyword {}
4066 Docs for return_keyword
4072 fn hover_builtin() {
4075 //- /main.rs crate:main deps:std
4076 cosnt _: &str$0 = ""; }
4078 //- /libstd.rs crate:std
4079 /// Docs for prim_str
4097 fn hover_macro_expanded_function() {
4100 struct S<'a, T>(&'a T);
4104 fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
4106 for<'a> T: Clone + 'a
4125 fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
4129 for<'a> T: Clone + 'a,
4136 fn hover_intra_doc_links() {
4141 /// This is the item. Cool!
4145 /// Gives you a [`TheItem$0`].
4147 /// [`TheItem`]: theitem::TheItem
4148 pub fn gimme() -> theitem::TheItem {
4165 This is the item. Cool!
4171 fn hover_generic_assoc() {
4174 fn foo<T: A>() where T::Assoc$0: {}
4194 let _: <T>::Assoc$0;
4234 fn string_shadowed_with_inner_items() {
4237 //- /main.rs crate:main deps:alloc
4239 /// Custom `String` type.
4248 //- /alloc.rs crate:alloc
4253 /// This is `alloc::String`.
4270 Custom `String` type.
4276 fn function_doesnt_shadow_crate_in_use_tree() {
4279 //- /main.rs crate:main deps:foo
4282 //- /foo.rs crate:foo
4296 fn hover_feature() {
4298 r#"#![feature(box_syntax$0)]"#,
4308 The tracking issue for this feature is: [#49733]
4310 [#49733]: https://github.com/rust-lang/rust/issues/49733
4312 See also [`box_patterns`](box-patterns.md)
4314 ------------------------
4316 Currently the only stable way to create a `Box` is via the `Box::new` method.
4317 Also it is not possible in stable Rust to destructure a `Box` in a match
4318 pattern. The unstable `box` keyword can be used to create a `Box`. An example
4322 #![feature(box_syntax)]
4336 r#"#![allow(arithmetic_overflow$0)]"#,
4338 *arithmetic_overflow*
4344 arithmetic operation overflows
4350 fn hover_clippy_lint() {
4352 r#"#![allow(clippy::almost_swapped$0)]"#,
4356 clippy::almost_swapped
4360 Checks for `foo = bar; bar = foo` sequences.
4366 fn hover_attr_path_qualifier() {
4367 cov_mark::check!(name_ref_classify_attr_path_qualifier);
4370 //- /foo.rs crate:foo
4372 //- /lib.rs crate:main.rs deps:foo
4403 use bar::{self as foo$0};
4446 fn hover_derive_input() {
4449 #[rustc_builtin_macro]
4469 #[rustc_builtin_macro]
4472 #[derive(foo::Copy$0)]
4490 fn hover_range_math() {
4493 fn f() { let expr = $01 + 2 * 3$0 }
4503 fn f() { let expr = 1 $0+ 2 * $03 }
4513 fn f() { let expr = 1 + $02 * 3$0 }
4523 fn hover_range_arrays() {
4526 fn f() { let expr = $0[1, 2, 3, 4]$0 }
4536 fn f() { let expr = [1, 2, $03, 4]$0 }
4546 fn f() { let expr = [1, 2, $03$0, 4] }
4556 fn hover_range_functions() {
4559 fn f<T>(a: &[T]) { }
4560 fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
4570 fn f<T>(a: &[T]) { }
4571 fn b() { f($0&[1, 2, 3, 4, 5]$0); }
4581 fn hover_range_shows_nothing_when_invalid() {
4582 check_hover_range_no_results(
4584 fn f<T>(a: &[T]) { }
4585 fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
4589 check_hover_range_no_results(
4591 fn f<T>$0(a: &[T]) { }
4592 fn b() { f(&[1, 2, 3,$0 4, 5]); }
4596 check_hover_range_no_results(
4598 fn $0f() { let expr = [1, 2, 3, 4]$0 }
4604 fn hover_range_shows_unit_for_statements() {
4607 fn f<T>(a: &[T]) { }
4608 fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
4618 fn f() { let expr$0 = $0[1, 2, 3, 4] }
4628 fn hover_range_for_pat() {
4655 fn hover_range_shows_coercions_if_applicable_expr() {
4659 let x: &u32 = $0&&&&&0$0;
4672 let x: *const u32 = $0&0$0;
4678 Coerced to: *const u32
4685 fn hover_range_shows_type_actions() {
4690 let x: &Foo = $0&&&&&Foo$0;
4698 mod_path: "test::Foo",
4699 nav: NavigationTarget {
4707 description: "struct Foo",
4718 fn hover_try_expr_res() {
4724 fn foo() -> Result<(), FooError> {
4725 Ok($0Result::<(), FooError>::Ok(())?$0)
4739 fn foo() -> Result<(), FooError> {
4740 Ok($0Result::<(), BarError>::Ok(())?$0)
4745 Try Error Type: BarError
4746 Propagated as: FooError
4753 fn hover_try_expr() {
4756 struct NotResult<T, U>(T, U);
4760 fn foo() -> NotResult<(), Looooong> {
4761 $0NotResult((), Short)?$0;
4766 Try Target Type: NotResult<(), Short>
4767 Propagated as: NotResult<(), Looooong>
4773 struct NotResult<T, U>(T, U);
4777 fn foo() -> NotResult<(), Short> {
4778 $0NotResult((), Looooong)?$0;
4783 Try Target Type: NotResult<(), Looooong>
4784 Propagated as: NotResult<(), Short>
4791 fn hover_try_expr_option() {
4792 cov_mark::check!(hover_try_expr_opt_opt);
4795 //- minicore: option, try
4797 fn foo() -> Option<()> {
4804 <Option<i32> as Try>::Output