Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/hover.rs7
-rw-r--r--crates/ide/src/hover/render.rs54
2 files changed, 58 insertions, 3 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 838fb18c3d..966daad135 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -87,7 +87,7 @@ pub struct HoverResult {
// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
//
-// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
+// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif
pub(crate) fn hover(
db: &RootDatabase,
FileRange { file_id, range }: FileRange,
@@ -268,7 +268,10 @@ fn hover_type_fallback(
}
};
- let res = render::type_info(sema, config, &expr_or_pat)?;
+ let res =
+ render::type_info(sema, config, &expr_or_pat)
+ .or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?;
+
let range = sema
.original_range_opt(&node)
.map(|frange| frange.range)
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index d109c07691..3b561f65da 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -14,7 +14,7 @@ use ide_db::{
use itertools::Itertools;
use stdx::format_to;
use syntax::{
- algo, ast, match_ast, AstNode, Direction,
+ algo, ast::{self, RecordPat}, match_ast, AstNode, Direction,
SyntaxKind::{LET_EXPR, LET_STMT},
SyntaxToken, T,
};
@@ -250,6 +250,58 @@ pub(super) fn keyword(
Some(HoverResult { markup, actions })
}
+pub(super) fn struct_rest_pat(
+ sema: &Semantics<'_, RootDatabase>,
+ config: &HoverConfig,
+ expr_or_pat: &Either<ast::Expr, ast::Pat>,
+) -> Option<HoverResult> {
+ let pat = expr_or_pat.as_ref().right()?;
+
+ let mut ancestors = sema.ancestors_with_macros(pat.syntax().clone());
+ let _record_pat_field_list = ancestors.next()?;
+ let record_pat = ancestors.next()?;
+ let pattern = sema
+ .find_nodes_at_offset_with_descend::<RecordPat>(
+ &record_pat,
+ record_pat.text_range().start())
+ .next()?;
+
+ let missing_fields = sema.record_pattern_missing_fields(&pattern);
+
+ // if there are no missing fields, the end result is a hover that shows ".."
+ // should be left in to indicate that there are no more fields in the pattern
+ // example, S {a: 1, b: 2, ..} when struct S {a: u32, b: u32}
+
+ let mut res = HoverResult::default();
+ let mut targets: Vec<hir::ModuleDef> = Vec::new();
+ let mut push_new_def = |item: hir::ModuleDef| {
+ if !targets.contains(&item) {
+ targets.push(item);
+ }
+ };
+ for (_, t) in &missing_fields {
+ walk_and_push_ty(sema.db, &t, &mut push_new_def);
+ }
+
+ res.markup = {
+ let mut s = String::from(".., ");
+ for (f, _) in &missing_fields {
+ s += f.display(sema.db).to_string().as_ref();
+ s += ", ";
+ }
+ // get rid of trailing comma
+ if s.len() > 0 {s.truncate(s.len() - 2);}
+
+ if config.markdown() {
+ Markup::fenced_block(&s)
+ } else {
+ s.into()
+ }
+ };
+ res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
+ Some(res)
+}
+
pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> {
let (path, tt) = attr.as_simple_call()?;
if !tt.syntax().text_range().contains(token.text_range().start()) {