Merge pull request #21141 from Wilfred/scip_enclosing_range

feature: Set enclosing_range field on SCIP output
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 052de0f..52b201d 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -44,7 +44,15 @@
 pub struct TokenStaticData {
     pub documentation: Option<Documentation>,
     pub hover: Option<HoverResult>,
+    /// The position of the token itself.
+    ///
+    /// For example, in `fn foo() {}` this is the position of `foo`.
     pub definition: Option<FileRange>,
+    /// The position of the entire definition that this token belongs to.
+    ///
+    /// For example, in `fn foo() {}` this is the position from `fn`
+    /// to the closing brace.
+    pub definition_body: Option<FileRange>,
     pub references: Vec<ReferenceData>,
     pub moniker: Option<MonikerResult>,
     pub display_name: Option<String>,
@@ -248,6 +256,10 @@
                     definition: def.try_to_nav(&sema).map(UpmappingResult::call_site).map(|it| {
                         FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
                     }),
+                    definition_body: def
+                        .try_to_nav(&sema)
+                        .map(UpmappingResult::call_site)
+                        .map(|it| FileRange { file_id: it.file_id, range: it.full_range }),
                     references: vec![],
                     moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
                     display_name: def
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index 37f83f6..f822efb 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -189,6 +189,13 @@
                     symbol_roles |= scip_types::SymbolRole::Definition as i32;
                 }
 
+                let enclosing_range = match token.definition_body {
+                    Some(def_body) if def_body.file_id == file_id => {
+                        text_range_to_scip_range(&line_index, def_body.range)
+                    }
+                    _ => Vec::new(),
+                };
+
                 occurrences.push(scip_types::Occurrence {
                     range: text_range_to_scip_range(&line_index, text_range),
                     symbol,
@@ -197,7 +204,7 @@
                     syntax_kind: Default::default(),
                     diagnostics: Vec::new(),
                     special_fields: Default::default(),
-                    enclosing_range: Vec::new(),
+                    enclosing_range,
                 });
             }
 
@@ -508,6 +515,7 @@
 #[cfg(test)]
 mod test {
     use super::*;
+    use hir::FileRangeWrapper;
     use ide::{FilePosition, TextSize};
     use test_fixture::ChangeFixture;
     use vfs::VfsPath;
@@ -887,4 +895,32 @@
 
         assert_eq!(token.documentation.as_ref().map(|d| d.as_str()), Some("foo"));
     }
+
+    #[test]
+    fn function_has_enclosing_range() {
+        let s = "fn foo() {}";
+
+        let mut host = AnalysisHost::default();
+        let change_fixture = ChangeFixture::parse(host.raw_database(), s);
+        host.raw_database_mut().apply_change(change_fixture.change);
+
+        let analysis = host.analysis();
+        let si = StaticIndex::compute(
+            &analysis,
+            VendoredLibrariesConfig::Included {
+                workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()),
+            },
+        );
+
+        let file = si.files.first().unwrap();
+        let (_, token_id) = file.tokens.get(1).unwrap(); // first token is file module, second is `foo`
+        let token = si.tokens.get(*token_id).unwrap();
+
+        let expected_range = FileRangeWrapper {
+            file_id: FileId::from_raw(0),
+            range: TextRange::new(0.into(), 11.into()),
+        };
+
+        assert_eq!(token.definition_body, Some(expected_range));
+    }
 }