about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-05-30 13:51:48 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-05-30 13:59:58 +0200
commitaced76d0ffd8319c553f52f276f7971cfaea5cd8 (patch)
treed4a9c97dd88c710ffadca54931acd803ab1473f4
parent9ceaff91d31ea16e38d6fb415d3a7d52703a7499 (diff)
downloadrust-aced76d0ffd8319c553f52f276f7971cfaea5cd8.tar.gz
rust-aced76d0ffd8319c553f52f276f7971cfaea5cd8.zip
Add implicit static lifetime hints
-rw-r--r--crates/ide/src/inlay_hints.rs105
1 files changed, 85 insertions, 20 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 910aee7b05c..116c1c480a1 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -117,33 +117,32 @@ pub(crate) fn inlay_hints(
 
     let mut acc = Vec::new();
 
-    let hints = |node| hints(&mut acc, &sema, config, file_id, node);
-    match range_limit {
-        Some(FileRange { range, .. }) => match file.covering_element(range) {
-            NodeOrToken::Token(_) => return acc,
-            NodeOrToken::Node(n) => n
-                .descendants()
-                .filter(|descendant| range.intersect(descendant.text_range()).is_some())
-                .for_each(hints),
-        },
-        None => file.descendants().for_each(hints),
-    };
+    if let Some(scope) = sema.scope(&file) {
+        let famous_defs = FamousDefs(&sema, scope.krate());
+
+        let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
+        match range_limit {
+            Some(FileRange { range, .. }) => match file.covering_element(range) {
+                NodeOrToken::Token(_) => return acc,
+                NodeOrToken::Node(n) => n
+                    .descendants()
+                    .filter(|descendant| range.intersect(descendant.text_range()).is_some())
+                    .for_each(hints),
+            },
+            None => file.descendants().for_each(hints),
+        };
+    }
 
     acc
 }
 
 fn hints(
     hints: &mut Vec<InlayHint>,
-    sema: &Semantics<RootDatabase>,
+    famous_defs @ FamousDefs(sema, _): &FamousDefs,
     config: &InlayHintsConfig,
     file_id: FileId,
     node: SyntaxNode,
 ) {
-    let famous_defs = match sema.scope(&node) {
-        Some(it) => FamousDefs(sema, it.krate()),
-        None => return,
-    };
-
     closing_brace_hints(hints, sema, config, file_id, node.clone());
     match_ast! {
         match node {
@@ -168,8 +167,18 @@ fn hints(
                 }
                 Some(())
             },
-            ast::Fn(it) => lifetime_fn_hints(hints, config, it),
-            _ => Some(()),
+            ast::Item(it) => match it {
+                // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
+                ast::Item::Impl(_) => None,
+                ast::Item::Fn(it) => fn_lifetime_fn_hints(hints, config, it),
+                // static type elisions
+                ast::Item::Static(it) => implicit_static_hints(hints, config, Either::Left(it)),
+                ast::Item::Const(it) => implicit_static_hints(hints, config, Either::Right(it)),
+                _ => None,
+            },
+            // FIXME: fn-ptr type, dyn fn type, and trait object type elisions
+            ast::Type(_) => None,
+            _ => None,
         }
     };
 }
@@ -279,7 +288,39 @@ fn closing_brace_hints(
     None
 }
 
-fn lifetime_fn_hints(
+fn implicit_static_hints(
+    acc: &mut Vec<InlayHint>,
+    config: &InlayHintsConfig,
+    statik_or_const: Either<ast::Static, ast::Const>,
+) -> Option<()> {
+    if config.lifetime_elision_hints != LifetimeElisionHints::Always {
+        return None;
+    }
+
+    if let Either::Right(it) = &statik_or_const {
+        if ast::AssocItemList::can_cast(
+            it.syntax().parent().map_or(SyntaxKind::EOF, |it| it.kind()),
+        ) {
+            return None;
+        }
+    }
+
+    if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) {
+        if ty.lifetime().is_none() {
+            let t = ty.amp_token()?;
+            acc.push(InlayHint {
+                range: t.text_range(),
+                kind: InlayKind::LifetimeHint,
+                label: "'static".to_owned(),
+                tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
+            });
+        }
+    }
+
+    Some(())
+}
+
+fn fn_lifetime_fn_hints(
     acc: &mut Vec<InlayHint>,
     config: &InlayHintsConfig,
     func: ast::Fn,
@@ -2594,6 +2635,30 @@ impl () {
     }
 
     #[test]
+    fn hints_lifetimes_static() {
+        check_with_config(
+            InlayHintsConfig {
+                lifetime_elision_hints: LifetimeElisionHints::Always,
+                ..TEST_CONFIG
+            },
+            r#"
+trait Trait {}
+static S: &str = "";
+//        ^'static
+const C: &str = "";
+//       ^'static
+const C: &dyn Trait = panic!();
+//       ^'static
+
+impl () {
+    const C: &str = "";
+    const C: &dyn Trait = panic!();
+}
+"#,
+        );
+    }
+
+    #[test]
     fn hints_implicit_reborrow() {
         check_with_config(
             InlayHintsConfig {