about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKirill Bulatov <mail4score@gmail.com>2022-02-12 00:48:01 +0200
committerLaurențiu Nicola <lnicola@dend.ro>2022-03-04 07:45:51 +0200
commitb1d8dae930deb73a0d11c310f11785e4c1fbb3c9 (patch)
tree8b334246fc915ad774cf1aee6b937e4ccaff65ab
parent9c0c199e962ef90fe3bf152bc87ff96d5c2a9093 (diff)
downloadrust-b1d8dae930deb73a0d11c310f11785e4c1fbb3c9.tar.gz
rust-b1d8dae930deb73a0d11c310f11785e4c1fbb3c9.zip
Load hints for part of the file only
-rw-r--r--crates/ide/src/inlay_hints.rs113
-rw-r--r--crates/ide/src/lib.rs3
-rw-r--r--crates/ide/src/static_index.rs1
-rw-r--r--crates/rust-analyzer/src/handlers.rs11
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs1
5 files changed, 108 insertions, 21 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 2ca756cbe04..3dc72731cb9 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -5,7 +5,7 @@ use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{self, AstNode, HasArgList, HasName, UnaryOp},
-    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
+    match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, TextRange, T,
 };
 
 use crate::FileId;
@@ -58,6 +58,7 @@ pub struct InlayHint {
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
     file_id: FileId,
+    range_limit: Option<FileRange>,
     config: &InlayHintsConfig,
 ) -> Vec<InlayHint> {
     let _p = profile::span("inlay_hints");
@@ -65,25 +66,50 @@ pub(crate) fn inlay_hints(
     let file = sema.parse(file_id);
     let file = file.syntax();
 
-    let mut res = Vec::new();
-
-    for node in file.descendants() {
-        if let Some(expr) = ast::Expr::cast(node.clone()) {
-            get_chaining_hints(&mut res, &sema, config, &expr);
-            match expr {
-                ast::Expr::CallExpr(it) => {
-                    get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
-                }
-                ast::Expr::MethodCallExpr(it) => {
-                    get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it));
+    let mut hints = Vec::new();
+
+    if let Some(range_limit) = range_limit {
+        let range_limit = range_limit.range;
+        match file.covering_element(range_limit) {
+            NodeOrToken::Token(_) => return hints,
+            NodeOrToken::Node(n) => {
+                for node in n
+                    .descendants()
+                    .filter(|descendant| range_limit.contains_range(descendant.text_range()))
+                {
+                    get_hints(&mut hints, &sema, config, node);
                 }
-                _ => (),
             }
-        } else if let Some(it) = ast::IdentPat::cast(node.clone()) {
-            get_bind_pat_hints(&mut res, &sema, config, &it);
         }
+    } else {
+        for node in file.descendants() {
+            get_hints(&mut hints, &sema, config, node);
+        }
+    }
+
+    hints
+}
+
+fn get_hints(
+    hints: &mut Vec<InlayHint>,
+    sema: &Semantics<RootDatabase>,
+    config: &InlayHintsConfig,
+    node: SyntaxNode,
+) {
+    if let Some(expr) = ast::Expr::cast(node.clone()) {
+        get_chaining_hints(hints, sema, config, &expr);
+        match expr {
+            ast::Expr::CallExpr(it) => {
+                get_param_name_hints(hints, sema, config, ast::Expr::from(it));
+            }
+            ast::Expr::MethodCallExpr(it) => {
+                get_param_name_hints(hints, sema, config, ast::Expr::from(it));
+            }
+            _ => (),
+        }
+    } else if let Some(it) = ast::IdentPat::cast(node) {
+        get_bind_pat_hints(hints, sema, config, &it);
     }
-    res
 }
 
 fn get_chaining_hints(
@@ -541,6 +567,8 @@ fn get_callable(
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
+    use ide_db::base_db::FileRange;
+    use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
     use crate::{fixture, inlay_hints::InlayHintsConfig};
@@ -604,7 +632,7 @@ mod tests {
     fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
-        let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
+        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         let actual =
             inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
         assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
@@ -613,7 +641,7 @@ mod tests {
     #[track_caller]
     fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
         let (analysis, file_id) = fixture::file(ra_fixture);
-        let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
+        let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         expect.assert_debug_eq(&inlay_hints)
     }
 
@@ -1046,6 +1074,55 @@ fn main() {
     }
 
     #[test]
+    fn check_hint_range_limit() {
+        let fixture = r#"
+        //- minicore: fn, sized
+        fn foo() -> impl Fn() { loop {} }
+        fn foo1() -> impl Fn(f64) { loop {} }
+        fn foo2() -> impl Fn(f64, f64) { loop {} }
+        fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
+        fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
+        fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
+        fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
+        fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
+
+        fn main() {
+            let foo = foo();
+            let foo = foo1();
+            let foo = foo2();
+            let foo = foo3();
+             // ^^^ impl Fn(f64, f64) -> u32
+            let foo = foo4();
+             // ^^^ &dyn Fn(f64, f64) -> u32
+            let foo = foo5();
+            let foo = foo6();
+            let foo = foo7();
+        }
+        "#;
+        let (analysis, file_id) = fixture::file(fixture);
+        let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
+        let inlay_hints = analysis
+            .inlay_hints(
+                &InlayHintsConfig {
+                    parameter_hints: false,
+                    type_hints: true,
+                    chaining_hints: false,
+                    hide_named_constructor_hints: false,
+                    max_length: None,
+                },
+                file_id,
+                Some(FileRange {
+                    file_id,
+                    range: TextRange::new(TextSize::from(500), TextSize::from(600)),
+                }),
+            )
+            .unwrap();
+        let actual =
+            inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
+        assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
+    }
+
+    #[test]
     fn fn_hints_ptr_rpit_fn_parentheses() {
         check_types(
             r#"
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 4028b0bc725..1acaaaccf0d 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -358,8 +358,9 @@ impl Analysis {
         &self,
         config: &InlayHintsConfig,
         file_id: FileId,
+        range: Option<FileRange>,
     ) -> Cancellable<Vec<InlayHint>> {
-        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config))
+        self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
     }
 
     /// Returns the set of folding ranges.
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index d5bfbd18941..64f2bc44233 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -112,6 +112,7 @@ impl StaticIndex<'_> {
                     max_length: Some(25),
                 },
                 file_id,
+                None,
             )
             .unwrap();
         // hovers
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index b45fbe698c9..70ffec7ed27 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1318,11 +1318,18 @@ pub(crate) fn handle_inlay_hints(
     params: InlayHintsParams,
 ) -> Result<Vec<InlayHint>> {
     let _p = profile::span("handle_inlay_hints");
-    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let document_uri = &params.text_document.uri;
+    let file_id = from_proto::file_id(&snap, document_uri)?;
     let line_index = snap.file_line_index(file_id)?;
+    let range = params
+        .range
+        .map(|range| {
+            from_proto::file_range(&snap, TextDocumentIdentifier::new(document_uri.to_owned()), range)
+        })
+        .transpose()?;
     Ok(snap
         .analysis
-        .inlay_hints(&snap.config.inlay_hints(), file_id)?
+        .inlay_hints(&snap.config.inlay_hints(), file_id, range)?
         .into_iter()
         .map(|it| to_proto::inlay_hint(&line_index, it))
         .collect())
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index f57080542c1..973769a7207 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -240,6 +240,7 @@ impl Request for InlayHints {
 #[serde(rename_all = "camelCase")]
 pub struct InlayHintsParams {
     pub text_document: TextDocumentIdentifier,
+    pub range: Option<lsp_types::Range>,
 }
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize)]