about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Barsky <me@davidbarsky.com>2025-03-15 11:19:25 -0400
committerDavid Barsky <me@davidbarsky.com>2025-03-24 09:59:51 -0700
commitfe192932a9bdc77dd56e5b3d989e223b565eca51 (patch)
tree359ff1052e931601f19af867ffdd7646bc1054b4
parent12dc311eb83d20e3241bdf7817eb4d11b03f4aee (diff)
downloadrust-fe192932a9bdc77dd56e5b3d989e223b565eca51.tar.gz
rust-fe192932a9bdc77dd56e5b3d989e223b565eca51.zip
analysis-stats: expose and print some limited statistics from `hir-def`
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs25
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs68
2 files changed, 90 insertions, 3 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index ea87b0f7000..2debbb1ee4e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -218,6 +218,22 @@ impl ItemTree {
         Attrs::filter(db, krate, self.raw_attrs(of).clone())
     }
 
+    /// Returns a count of a few, expensive items.
+    ///
+    /// For more detail, see [`ItemTreeDataStats`].
+    pub fn item_tree_stats(&self) -> ItemTreeDataStats {
+        match self.data {
+            Some(ref data) => ItemTreeDataStats {
+                traits: data.traits.len(),
+                impls: data.impls.len(),
+                mods: data.mods.len(),
+                macro_calls: data.macro_calls.len(),
+                macro_rules: data.macro_rules.len(),
+            },
+            None => ItemTreeDataStats::default(),
+        }
+    }
+
     pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String {
         pretty::print_item_tree(db, self, edition)
     }
@@ -329,6 +345,15 @@ struct ItemTreeData {
 }
 
 #[derive(Default, Debug, Eq, PartialEq)]
+pub struct ItemTreeDataStats {
+    pub traits: usize,
+    pub impls: usize,
+    pub mods: usize,
+    pub macro_calls: usize,
+    pub macro_rules: usize,
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
 pub struct ItemTreeSourceMaps {
     all_concatenated: Box<[TypesSourceMap]>,
     structs_offset: u32,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index bca44f95886..ec232d8e85c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -3,6 +3,7 @@
 
 use std::{
     env, fmt,
+    ops::AddAssign,
     time::{SystemTime, UNIX_EPOCH},
 };
 
@@ -129,6 +130,9 @@ impl flags::AnalysisStats {
         let mut dep_item_trees = 0;
         let mut workspace_item_trees = 0;
 
+        let mut workspace_item_stats = PrettyItemStats::default();
+        let mut dep_item_stats = PrettyItemStats::default();
+
         for source_root_id in source_roots {
             let source_root = db.source_root(source_root_id).source_root(db);
             for file_id in source_root.iter() {
@@ -137,16 +141,24 @@ impl flags::AnalysisStats {
                         // measure workspace/project code
                         if !source_root.is_library || self.with_deps {
                             let length = db.file_text(file_id).text(db).lines().count();
-                            db.file_item_tree(EditionedFileId::current_edition(file_id).into());
+                            let item_stats = db
+                                .file_item_tree(EditionedFileId::current_edition(file_id).into())
+                                .item_tree_stats()
+                                .into();
 
                             workspace_loc += length;
                             workspace_item_trees += 1;
+                            workspace_item_stats += item_stats;
                         } else {
                             let length = db.file_text(file_id).text(db).lines().count();
-                            db.file_item_tree(EditionedFileId::current_edition(file_id).into());
+                            let item_stats = db
+                                .file_item_tree(EditionedFileId::current_edition(file_id).into())
+                                .item_tree_stats()
+                                .into();
 
                             dep_loc += length;
-                            dep_item_trees += 1
+                            dep_item_trees += 1;
+                            dep_item_stats += item_stats;
                         }
                     }
                 }
@@ -161,11 +173,13 @@ impl flags::AnalysisStats {
             UsizeWithUnderscore(dep_loc),
             UsizeWithUnderscore(dep_item_trees),
         );
+        eprintln!("  dependency item stats: {}", dep_item_stats);
         eprintln!(
             "  workspace lines of code: {}, item trees: {}",
             UsizeWithUnderscore(workspace_loc),
             UsizeWithUnderscore(workspace_item_trees),
         );
+        eprintln!("  workspace stats: {}", workspace_item_stats);
 
         // FIXME(salsa-transition): bring back stats for ParseQuery (file size)
         // and ParseMacroExpansionQuery (macro expansion "file") size whenever we implement
@@ -1258,6 +1272,7 @@ fn percentage(n: u64, total: u64) -> u64 {
     (n * 100).checked_div(total).unwrap_or(100)
 }
 
+#[derive(Default, Debug, Eq, PartialEq)]
 struct UsizeWithUnderscore(usize);
 
 impl fmt::Display for UsizeWithUnderscore {
@@ -1282,6 +1297,53 @@ impl fmt::Display for UsizeWithUnderscore {
     }
 }
 
+impl std::ops::AddAssign for UsizeWithUnderscore {
+    fn add_assign(&mut self, other: UsizeWithUnderscore) {
+        self.0 += other.0;
+    }
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+struct PrettyItemStats {
+    traits: UsizeWithUnderscore,
+    impls: UsizeWithUnderscore,
+    mods: UsizeWithUnderscore,
+    macro_calls: UsizeWithUnderscore,
+    macro_rules: UsizeWithUnderscore,
+}
+
+impl From<hir_def::item_tree::ItemTreeDataStats> for PrettyItemStats {
+    fn from(value: hir_def::item_tree::ItemTreeDataStats) -> Self {
+        Self {
+            traits: UsizeWithUnderscore(value.traits),
+            impls: UsizeWithUnderscore(value.impls),
+            mods: UsizeWithUnderscore(value.mods),
+            macro_calls: UsizeWithUnderscore(value.macro_calls),
+            macro_rules: UsizeWithUnderscore(value.macro_rules),
+        }
+    }
+}
+
+impl AddAssign for PrettyItemStats {
+    fn add_assign(&mut self, rhs: Self) {
+        self.traits += rhs.traits;
+        self.impls += rhs.impls;
+        self.mods += rhs.mods;
+        self.macro_calls += rhs.macro_calls;
+        self.macro_rules += rhs.macro_rules;
+    }
+}
+
+impl fmt::Display for PrettyItemStats {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "traits: {}, impl: {}, mods: {}, macro calls: {}, macro rules: {}",
+            self.traits, self.impls, self.mods, self.macro_calls, self.macro_rules
+        )
+    }
+}
+
 // FIXME(salsa-transition): bring this back whenever we implement
 // Salsa's memory usage tracking to work with tracked functions.
 // fn syntax_len(node: SyntaxNode) -> usize {