about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-03-19 18:11:56 +0100
committerLukas Wirth <lukastw97@gmail.com>2022-03-19 18:11:56 +0100
commit45756c823fdf12ff8eca8c4350b93c833633d4db (patch)
tree91868e310261ac7c1140ea2b9a3ce5c1579c1489
parentc22fed895e1debfa820f366ee21cdeaddfebb015 (diff)
downloadrust-45756c823fdf12ff8eca8c4350b93c833633d4db.tar.gz
rust-45756c823fdf12ff8eca8c4350b93c833633d4db.zip
Use numbers for lifetimes by default, add setting to prefer using parameter names
-rw-r--r--crates/ide/src/inlay_hints.rs131
-rw-r--r--crates/ide/src/static_index.rs1
-rw-r--r--crates/rust-analyzer/src/config.rs21
3 files changed, 94 insertions, 59 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index b908895a6b0..ebafdf8052b 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,7 +1,10 @@
 use either::Either;
 use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
-use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
+use ide_db::{
+    base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, RootDatabase,
+};
 use itertools::Itertools;
+use rustc_hash::FxHashSet;
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
@@ -19,6 +22,7 @@ pub struct InlayHintsConfig {
     pub closure_return_type_hints: bool,
     // FIXME: ternary option here, on off non-noisy
     pub lifetime_elision_hints: bool,
+    pub param_names_for_lifetime_elision_hints: bool,
     pub hide_named_constructor_hints: bool,
     pub max_length: Option<usize>,
 }
@@ -136,31 +140,37 @@ fn lifetime_hints(
     let ret_type = func.ret_type();
     let self_param = param_list.self_param().filter(|it| it.amp_token().is_some());
 
-    // FIXME: don't use already used lifetimenames
+    let used_names: FxHashSet<SmolStr> = generic_param_list
+        .iter()
+        .filter(|_| !config.param_names_for_lifetime_elision_hints)
+        .flat_map(|gpl| gpl.lifetime_params())
+        .filter_map(|param| param.lifetime())
+        .map(|lt| SmolStr::from(lt.text().as_str()))
+        .collect();
 
     let mut allocated_lifetimes = vec![];
     let mut gen_name = {
-        let mut gen = ('a'..).map(|it| SmolStr::from_iter(['\'', it]));
-        move || gen.next().unwrap_or_else(SmolStr::default)
+        let mut gen = (0u8..).map(|idx| match idx {
+            idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
+            idx => format!("'{idx}").into(),
+        });
+        move || gen.next().unwrap_or_default()
     };
 
-    let potential_lt_refs: Vec<_> = param_list
-        .params()
-        .filter_map(|it| {
-            let ty = it.ty()?;
-            // FIXME: look into the nested types here and check path types
-            match ty {
-                ast::Type::RefType(r) => Some((
-                    it.pat().and_then(|it| match it {
-                        ast::Pat::IdentPat(p) => p.name(),
-                        _ => None,
-                    }),
-                    r,
-                )),
-                _ => None,
-            }
+    let mut potential_lt_refs: Vec<_> = vec![];
+    param_list.params().filter_map(|it| Some((it.pat(), it.ty()?))).for_each(|(pat, ty)| {
+        // FIXME: check path types
+        walk_ty(&ty, &mut |ty| match ty {
+            ast::Type::RefType(r) => potential_lt_refs.push((
+                pat.as_ref().and_then(|it| match it {
+                    ast::Pat::IdentPat(p) => p.name(),
+                    _ => None,
+                }),
+                r,
+            )),
+            _ => (),
         })
-        .collect();
+    });
 
     enum LifetimeKind {
         Elided,
@@ -184,15 +194,25 @@ fn lifetime_hints(
     // allocate names
     if let Some(self_param) = &self_param {
         if is_elided(self_param.lifetime()) {
-            allocated_lifetimes.push(SmolStr::new_inline("'self"));
+            allocated_lifetimes.push(if config.param_names_for_lifetime_elision_hints {
+                "'self".into()
+            } else {
+                gen_name()
+            });
         }
     }
     potential_lt_refs.iter().for_each(|(name, it)| {
-        // FIXME: look into the nested types here and check path types
         if is_elided(it.lifetime()) {
             allocated_lifetimes.push(
                 name.as_ref()
-                    .map_or_else(|| gen_name(), |it| SmolStr::from_iter(["'", it.text().as_str()])),
+                    .filter(|it| {
+                        config.param_names_for_lifetime_elision_hints
+                            && !used_names.contains(it.text().as_str())
+                    })
+                    .map_or_else(
+                        || gen_name(),
+                        |it| SmolStr::from_iter(["\'", it.text().as_str()]),
+                    ),
             );
         }
     });
@@ -221,22 +241,26 @@ fn lifetime_hints(
     // apply output if required
     match (&output, ret_type) {
         (Some(output_lt), Some(r)) => {
-            if let Some(ast::Type::RefType(t)) = r.ty() {
-                if t.lifetime().is_none() {
-                    let amp = t.amp_token()?;
-                    acc.push(InlayHint {
-                        range: amp.text_range(),
-                        kind: InlayKind::LifetimeHint,
-                        label: output_lt.clone(),
-                    });
-                }
+            if let Some(ty) = r.ty() {
+                walk_ty(&ty, &mut |ty| match ty {
+                    ast::Type::RefType(ty) if ty.lifetime().is_none() => {
+                        if let Some(amp) = ty.amp_token() {
+                            acc.push(InlayHint {
+                                range: amp.text_range(),
+                                kind: InlayKind::LifetimeHint,
+                                label: output_lt.clone(),
+                            });
+                        }
+                    }
+                    _ => (),
+                })
             }
         }
         _ => (),
     }
 
-    let mut idx = if let Some(self_param) = &self_param {
-        if is_elided(self_param.lifetime()) {
+    let mut idx = match &self_param {
+        Some(self_param) if is_elided(self_param.lifetime()) => {
             if let Some(amp) = self_param.amp_token() {
                 let lt = allocated_lifetimes[0].clone();
                 acc.push(InlayHint {
@@ -246,11 +270,8 @@ fn lifetime_hints(
                 });
             }
             1
-        } else {
-            0
         }
-    } else {
-        0
+        _ => 0,
     };
 
     for (_, p) in potential_lt_refs.iter() {
@@ -789,6 +810,7 @@ mod tests {
         lifetime_elision_hints: false,
         hide_named_constructor_hints: false,
         closure_return_type_hints: false,
+        param_names_for_lifetime_elision_hints: false,
         max_length: None,
     };
     const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
@@ -1981,32 +2003,39 @@ fn main() {
 fn empty() {}
 
 fn no_gpl(a: &()) {}
- //^^^^^^<'a>
-          // ^'a
+ //^^^^^^<'0>
+          // ^'0
 fn empty_gpl<>(a: &()) {}
-      //    ^'a   ^'a
+      //    ^'0   ^'0
 fn partial<'b>(a: &(), b: &'b ()) {}
-//        ^'a, $  ^'a
+//        ^'0, $  ^'0
 fn partial<'a>(a: &'a (), b: &()) {}
-//        ^'b, $             ^'b
+//        ^'0, $             ^'0
 
 fn single_ret(a: &()) -> &() {}
-// ^^^^^^^^^^<'a>
-              // ^'a     ^'a
+// ^^^^^^^^^^<'0>
+              // ^'0     ^'0
 fn full_mul(a: &(), b: &()) {}
-// ^^^^^^^^<'a, 'b>
-            // ^'a     ^'b
+// ^^^^^^^^<'0, '1>
+            // ^'0     ^'1
 
 fn foo<'c>(a: &'c ()) -> &() {}
                       // ^'c
 
+fn nested_in(a: &   &X< &()>) {}
+// ^^^^^^^^^<'0, '1, '2>
+              //^'0 ^'1 ^'2
+fn nested_out(a: &()) -> &   &X< &()>{}
+// ^^^^^^^^^^<'0>
+               //^'0     ^'0 ^'0 ^'0
+
 impl () {
     fn foo(&self) -> &() {}
-    // ^^^<'self>
-        // ^'self    ^'self
+    // ^^^<'0>
+        // ^'0       ^'0
     fn foo(&self, a: &()) -> &() {}
-    // ^^^<'self, 'a>
-        // ^'self    ^'a     ^'self$
+    // ^^^<'0, '1>
+        // ^'0       ^'1     ^'0
 }
 "#,
         );
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 7b3fa016a26..0ae330be47b 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -112,6 +112,7 @@ impl StaticIndex<'_> {
                     closure_return_type_hints: true,
                     lifetime_elision_hints: false,
                     hide_named_constructor_hints: false,
+                    param_names_for_lifetime_elision_hints: false,
                     max_length: Some(25),
                 },
                 file_id,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index d2b089bb1b4..75d8733e915 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -243,22 +243,24 @@ config_data! {
         hoverActions_run: bool             = "true",
 
         /// Whether to render trailing colons for parameter hints, and trailing colons for parameter hints.
-        inlayHints_renderColons: bool               = "true",
+        inlayHints_renderColons: bool                      = "true",
         /// Maximum length for inlay hints. Set to null to have an unlimited length.
-        inlayHints_maxLength: Option<usize>         = "25",
+        inlayHints_maxLength: Option<usize>                = "25",
         /// Whether to show function parameter name inlay hints at the call
         /// site.
-        inlayHints_parameterHints: bool             = "true",
+        inlayHints_parameterHints: bool                    = "true",
         /// Whether to show inlay type hints for variables.
-        inlayHints_typeHints: bool                  = "true",
+        inlayHints_typeHints: bool                         = "true",
         /// Whether to show inlay type hints for method chains.
-        inlayHints_chainingHints: bool              = "true",
+        inlayHints_chainingHints: bool                     = "true",
         /// Whether to show inlay type hints for return types of closures with blocks.
-        inlayHints_closureReturnTypeHints: bool     = "false",
+        inlayHints_closureReturnTypeHints: bool            = "false",
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
-        inlayHints_lifetimeElisionHints: bool       = "false",
+        inlayHints_lifetimeElisionHints: bool              = "false",
+        /// Whether to show prefer using parameter names as the name for elided lifetime hints.
+        inlayHints_paramNamesForLifetimeElisionHints: bool = "false",
         /// Whether to hide inlay hints for constructors.
-        inlayHints_hideNamedConstructorHints: bool  = "false",
+        inlayHints_hideNamedConstructorHints: bool         = "false",
 
         /// Join lines inserts else between consecutive ifs.
         joinLines_joinElseIf: bool = "true",
@@ -859,6 +861,9 @@ impl Config {
             closure_return_type_hints: self.data.inlayHints_closureReturnTypeHints,
             lifetime_elision_hints: self.data.inlayHints_lifetimeElisionHints,
             hide_named_constructor_hints: self.data.inlayHints_hideNamedConstructorHints,
+            param_names_for_lifetime_elision_hints: self
+                .data
+                .inlayHints_paramNamesForLifetimeElisionHints,
             max_length: self.data.inlayHints_maxLength,
         }
     }