Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
-rw-r--r--crates/ide/src/inlay_hints.rs83
1 files changed, 70 insertions, 13 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 565bee88f3..4fdb7d0bc3 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -19,6 +19,7 @@ pub struct InlayHintsConfig {
pub type_hints: bool,
pub parameter_hints: bool,
pub chaining_hints: bool,
+ pub reborrow_hints: bool,
pub closure_return_type_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
@@ -35,6 +36,7 @@ pub enum LifetimeElisionHints {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InlayKind {
+ ImplicitReborrow,
TypeHint,
ParameterHint,
ClosureReturnTypeHint,
@@ -65,10 +67,7 @@ pub struct InlayHint {
//
// * return types of closure expressions with blocks
// * elided lifetimes
-//
-// **Note:** VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations.
-// This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird:
-// https://github.com/rust-analyzer/rust-analyzer/issues/1623[1], https://github.com/rust-analyzer/rust-analyzer/issues/3453[2].
+// * compiler inserted reborrows
//
// |===
// | Editor | Action Name
@@ -116,17 +115,16 @@ fn hints(
if let Some(expr) = ast::Expr::cast(node.clone()) {
chaining_hints(hints, sema, &famous_defs, config, &expr);
match expr {
- ast::Expr::CallExpr(it) => {
- param_name_hints(hints, sema, config, ast::Expr::from(it));
- }
+ ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
ast::Expr::MethodCallExpr(it) => {
- param_name_hints(hints, sema, config, ast::Expr::from(it));
+ param_name_hints(hints, sema, config, ast::Expr::from(it))
}
- ast::Expr::ClosureExpr(it) => {
- closure_ret_hints(hints, sema, &famous_defs, config, it);
- }
- _ => (),
- }
+ ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, it),
+ // We could show reborrows for all expressions, but usually that is just noise to the user
+ // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
+ ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
+ _ => None,
+ };
} else if let Some(it) = ast::IdentPat::cast(node.clone()) {
bind_pat_hints(hints, sema, config, &it);
} else if let Some(it) = ast::Fn::cast(node) {
@@ -365,6 +363,28 @@ fn closure_ret_hints(
Some(())
}
+fn reborrow_hints(
+ acc: &mut Vec<InlayHint>,
+ sema: &Semantics<RootDatabase>,
+ config: &InlayHintsConfig,
+ expr: &ast::Expr,
+) -> Option<()> {
+ if !config.reborrow_hints {
+ return None;
+ }
+
+ let mutability = sema.is_implicit_reborrow(expr)?;
+ acc.push(InlayHint {
+ range: expr.syntax().text_range(),
+ kind: InlayKind::ImplicitReborrow,
+ label: match mutability {
+ hir::Mutability::Shared => SmolStr::new_inline("&*"),
+ hir::Mutability::Mut => SmolStr::new_inline("&mut *"),
+ },
+ });
+ Some(())
+}
+
fn chaining_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>,
@@ -834,6 +854,7 @@ mod tests {
lifetime_elision_hints: LifetimeElisionHints::Never,
hide_named_constructor_hints: false,
closure_return_type_hints: false,
+ reborrow_hints: false,
param_names_for_lifetime_elision_hints: false,
max_length: None,
};
@@ -841,6 +862,7 @@ mod tests {
type_hints: true,
parameter_hints: true,
chaining_hints: true,
+ reborrow_hints: true,
closure_return_type_hints: true,
lifetime_elision_hints: LifetimeElisionHints::Always,
..DISABLED_CONFIG
@@ -2118,4 +2140,39 @@ impl () {
"#,
);
}
+
+ #[test]
+ fn hints_implicit_reborrow() {
+ check_with_config(
+ InlayHintsConfig { reborrow_hints: true, ..DISABLED_CONFIG },
+ r#"
+fn __() {
+ let unique = &mut ();
+ let r_mov = unique;
+ let foo: &mut _ = unique;
+ //^^^^^^ &mut *
+ ref_mut_id(unique);
+ //^^^^^^ &mut *
+ let shared = ref_id(unique);
+ //^^^^^^ &*
+ let mov = shared;
+ let r_mov: &_ = shared;
+ ref_id(shared);
+
+ identity(unique);
+ identity(shared);
+}
+fn identity<T>(t: T) -> T {
+ t
+}
+fn ref_mut_id(x: &mut ()) -> &mut () {
+ x
+ //^ &mut *
+}
+fn ref_id(x: &()) -> &() {
+ x
+}
+"#,
+ );
+ }
}