rubydex 0.4.1-aarch64-linux → 0.4.2-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -0
  3. data/THIRD_PARTY_LICENSES.html +13 -24
  4. data/lib/rubydex/cli/command/dead_code.rb +59 -0
  5. data/lib/rubydex/librubydex_sys.so +0 -0
  6. data/lib/rubydex/mcp_server/tools/codebase_stats_tool.rb +1 -1
  7. data/lib/rubydex/mcp_server/tools/find_constant_references_tool.rb +4 -4
  8. data/lib/rubydex/mcp_server/tools/find_dead_code_candidates_tool.rb +33 -0
  9. data/lib/rubydex/mcp_server/tools/get_declaration_tool.rb +2 -2
  10. data/lib/rubydex/mcp_server/tools/get_descendants_tool.rb +4 -4
  11. data/lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb +2 -2
  12. data/lib/rubydex/mcp_server/tools/search_declarations_tool.rb +6 -6
  13. data/lib/rubydex/mcp_server.rb +24 -12
  14. data/lib/rubydex/version.rb +1 -1
  15. data/rust/Cargo.lock +17 -11
  16. data/rust/Cargo.toml +3 -0
  17. data/rust/rubydex/Cargo.toml +2 -2
  18. data/rust/rubydex/src/compile_assertions.rs +2 -0
  19. data/rust/rubydex/src/config.rs +1 -1
  20. data/rust/rubydex/src/indexing/rbs_indexer.rs +4 -4
  21. data/rust/rubydex/src/indexing/ruby_indexer.rs +26 -18
  22. data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +42 -2
  23. data/rust/rubydex/src/indexing.rs +6 -6
  24. data/rust/rubydex/src/listing.rs +12 -12
  25. data/rust/rubydex/src/model/built_in.rs +1 -1
  26. data/rust/rubydex/src/model/comment.rs +4 -4
  27. data/rust/rubydex/src/model/declaration.rs +25 -17
  28. data/rust/rubydex/src/model/document.rs +11 -11
  29. data/rust/rubydex/src/model/graph.rs +3 -3
  30. data/rust/rubydex/src/offset.rs +1 -13
  31. data/rust/rubydex/src/operation/ruby_builder.rs +29 -19
  32. data/rust/rubydex/src/query.rs +3 -2
  33. data/rust/rubydex/src/test_utils/graph_test.rs +2 -2
  34. data/rust/rubydex/src/test_utils/local_graph_test.rs +13 -6
  35. data/rust/rubydex-sys/Cargo.toml +2 -2
  36. data/rust/rubydex-sys/src/definition_api.rs +1 -1
  37. data/rust/rubydex-sys/src/graph_api.rs +96 -49
  38. data/rust/rubydex-sys/src/name_api.rs +193 -58
  39. metadata +199 -198
@@ -93,8 +93,8 @@ pub struct RubyIndexer<'a> {
93
93
 
94
94
  impl<'a> RubyIndexer<'a> {
95
95
  #[must_use]
96
- pub fn new(uri: String, source: &'a str) -> Self {
97
- let uri_id = UriId::from(&uri);
96
+ pub fn new(uri: Box<str>, source: &'a str) -> Self {
97
+ let uri_id = UriId::from(&*uri);
98
98
  let local_graph = LocalGraph::new(uri_id, Document::new(uri, source));
99
99
 
100
100
  Self {
@@ -120,7 +120,7 @@ impl<'a> RubyIndexer<'a> {
120
120
  self.local_graph.add_diagnostic(
121
121
  Rule::ParseError,
122
122
  Offset::from_prism_location(&error.location()),
123
- error.message().to_string(),
123
+ String::from_utf8_lossy(error.message()).to_string(),
124
124
  );
125
125
  }
126
126
 
@@ -128,7 +128,7 @@ impl<'a> RubyIndexer<'a> {
128
128
  self.local_graph.add_diagnostic(
129
129
  Rule::ParseWarning,
130
130
  Offset::from_prism_location(&warning.location()),
131
- warning.message().to_string(),
131
+ String::from_utf8_lossy(warning.message()).to_string(),
132
132
  );
133
133
  }
134
134
 
@@ -313,7 +313,9 @@ impl<'a> RubyIndexer<'a> {
313
313
  }
314
314
  }
315
315
 
316
- if let Some(block) = parameters_list.block() {
316
+ if let Some(block) = parameters_list.block()
317
+ && let Some(block) = block.as_block_parameter_node()
318
+ {
317
319
  let location = block.name_loc().unwrap_or_else(|| block.location());
318
320
  let str_id = self.local_graph.intern_string(Self::location_to_string(&location));
319
321
 
@@ -1389,8 +1391,8 @@ impl<'a> RubyIndexer<'a> {
1389
1391
  match arg {
1390
1392
  ruby_prism::Node::SymbolNode { .. } => {
1391
1393
  let symbol = arg.as_symbol_node().unwrap();
1392
- let value_loc = symbol.value_loc()?;
1393
- Some((Self::location_to_string(&value_loc), value_loc))
1394
+ let content_loc = symbol.content_loc();
1395
+ Some((Self::location_to_string(&content_loc), content_loc))
1394
1396
  }
1395
1397
  ruby_prism::Node::StringNode { .. } => {
1396
1398
  let string = arg.as_string_node().unwrap();
@@ -1522,7 +1524,7 @@ impl CommentGroup {
1522
1524
  // Accepts the next line if it is continuous
1523
1525
  fn accepts(&self, next: &ruby_prism::Comment, source: &str) -> bool {
1524
1526
  let current_end_offset = self.end_offset;
1525
- let next_line_start_offset = next.location().start_offset();
1527
+ let next_line_start_offset = next.location().start() as usize;
1526
1528
 
1527
1529
  let between = &source.as_bytes()[current_end_offset..next_line_start_offset];
1528
1530
  if !between.iter().all(|&b| b.is_ascii_whitespace()) {
@@ -1538,7 +1540,7 @@ impl CommentGroup {
1538
1540
  // 1. still move the group end offset to the end of the magic comment
1539
1541
  // 2. not add the comment to the comments array
1540
1542
  fn add_comment(&mut self, comment: &ruby_prism::Comment) {
1541
- self.end_offset = comment.location().end_offset();
1543
+ self.end_offset = comment.location().end() as usize;
1542
1544
  let text = String::from_utf8_lossy(comment.location().as_slice()).to_string();
1543
1545
 
1544
1546
  if text.lines().any(|line| line.starts_with("# @deprecated")) {
@@ -1547,7 +1549,7 @@ impl CommentGroup {
1547
1549
 
1548
1550
  self.comments.push(Comment::new(
1549
1551
  Offset::from_prism_location(&comment.location()),
1550
- text.trim().to_string(),
1552
+ text.trim().into(),
1551
1553
  ));
1552
1554
  }
1553
1555
 
@@ -1984,12 +1986,18 @@ impl Visit<'_> for RubyIndexer<'_> {
1984
1986
  });
1985
1987
  };
1986
1988
 
1987
- let message_loc = node.message_loc();
1989
+ let message_loc = if node.name().as_slice().is_empty() {
1990
+ // Incomplete calls like `Foo.` have no message. We still index them using the call operator location, so
1991
+ // that the receiver's singleton class gets created, which completion depends on
1992
+ node.call_operator_loc()
1993
+ } else {
1994
+ node.message_loc()
1995
+ };
1988
1996
 
1989
- if message_loc.is_none() {
1997
+ let Some(message_loc) = message_loc else {
1990
1998
  // No message, we can't index this node
1991
1999
  return;
1992
- }
2000
+ };
1993
2001
 
1994
2002
  let message = String::from_utf8_lossy(node.name().as_slice()).to_string();
1995
2003
 
@@ -2217,11 +2225,11 @@ impl Visit<'_> for RubyIndexer<'_> {
2217
2225
  self.visit(&receiver);
2218
2226
  }
2219
2227
 
2220
- self.index_method_reference(message.clone(), &node.message_loc().unwrap(), method_receiver);
2228
+ self.index_method_reference(message.clone(), &message_loc, method_receiver);
2221
2229
 
2222
2230
  match message.as_str() {
2223
2231
  ">" | "<" | ">=" | "<=" => {
2224
- self.index_method_reference("<=>".to_string(), &node.message_loc().unwrap(), method_receiver);
2232
+ self.index_method_reference("<=>".to_string(), &message_loc, method_receiver);
2225
2233
  }
2226
2234
  _ => {}
2227
2235
  }
@@ -2382,7 +2390,7 @@ impl Visit<'_> for RubyIndexer<'_> {
2382
2390
  match expression {
2383
2391
  ruby_prism::Node::SymbolNode { .. } => {
2384
2392
  let symbol = expression.as_symbol_node().unwrap();
2385
- let name = Self::location_to_string(&symbol.value_loc().unwrap());
2393
+ let name = Self::location_to_string(&symbol.content_loc());
2386
2394
  self.index_method_reference(name, &node.location(), None);
2387
2395
  }
2388
2396
  _ => {
@@ -2394,13 +2402,13 @@ impl Visit<'_> for RubyIndexer<'_> {
2394
2402
 
2395
2403
  fn visit_alias_method_node(&mut self, node: &ruby_prism::AliasMethodNode<'_>) {
2396
2404
  let mut new_name = if let Some(symbol_node) = node.new_name().as_symbol_node() {
2397
- Self::location_to_string(&symbol_node.value_loc().unwrap())
2405
+ Self::location_to_string(&symbol_node.content_loc())
2398
2406
  } else {
2399
2407
  Self::location_to_string(&node.new_name().location())
2400
2408
  };
2401
2409
 
2402
2410
  let mut old_name = if let Some(symbol_node) = node.old_name().as_symbol_node() {
2403
- Self::location_to_string(&symbol_node.value_loc().unwrap())
2411
+ Self::location_to_string(&symbol_node.content_loc())
2404
2412
  } else {
2405
2413
  Self::location_to_string(&node.old_name().location())
2406
2414
  };
@@ -900,7 +900,7 @@ mod class_and_module_tests {
900
900
  assert_def_name_eq!(&context, def, "Baz");
901
901
  assert_def_name_offset_eq!(&context, def, "3:11-3:14");
902
902
  assert!(def.superclass_ref().is_none());
903
- assert!(def.members().is_empty());
903
+ assert_eq!(def.members(), []);
904
904
 
905
905
  assert_definition_at!(&context, "2:3-4:6", Class, |parent_nesting| {
906
906
  assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
@@ -948,7 +948,7 @@ mod class_and_module_tests {
948
948
  assert_def_name_eq!(&context, def, "Quuux");
949
949
  assert_def_name_offset_eq!(&context, def, "3:13-3:18");
950
950
  assert!(def.superclass_ref().is_none());
951
- assert!(def.members().is_empty());
951
+ assert_eq!(def.members(), []);
952
952
 
953
953
  assert_definition_at!(&context, "2:3-4:6", Class, |parent_nesting| {
954
954
  assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
@@ -1250,6 +1250,46 @@ mod method_tests {
1250
1250
  });
1251
1251
  }
1252
1252
 
1253
+ #[test]
1254
+ fn index_def_node_with_no_block_parameter() {
1255
+ let context = index_source({
1256
+ "
1257
+ def foo(a, &nil); end
1258
+ "
1259
+ });
1260
+
1261
+ assert_no_local_diagnostics!(&context);
1262
+
1263
+ assert_definition_at!(&context, "1:1-1:22", Method, |def| {
1264
+ assert_simple_signature!(def, |params| {
1265
+ assert_eq!(params.len(), 1);
1266
+ assert_parameter!(&params[0], RequiredPositional, |param| {
1267
+ assert_string_eq!(context, param.str(), "a");
1268
+ });
1269
+ });
1270
+ });
1271
+ }
1272
+
1273
+ #[test]
1274
+ fn index_def_node_with_trailing_comma_in_parameters() {
1275
+ let context = index_source({
1276
+ "
1277
+ def foo(a,); end
1278
+ "
1279
+ });
1280
+
1281
+ assert_no_local_diagnostics!(&context);
1282
+
1283
+ assert_definition_at!(&context, "1:1-1:17", Method, |def| {
1284
+ assert_simple_signature!(def, |params| {
1285
+ assert_eq!(params.len(), 1);
1286
+ assert_parameter!(&params[0], RequiredPositional, |param| {
1287
+ assert_string_eq!(context, param.str(), "a");
1288
+ });
1289
+ });
1290
+ });
1291
+ }
1292
+
1253
1293
  #[test]
1254
1294
  fn index_nested_method_definitions() {
1255
1295
  let context = index_source({
@@ -101,7 +101,7 @@ impl Job for IndexingJob {
101
101
  };
102
102
 
103
103
  let language = self.path.extension().map_or(LanguageId::Ruby, LanguageId::from);
104
- let local_graph = build_local_graph(url.to_string(), &source, &language, self.backend);
104
+ let local_graph = build_local_graph(url.to_string().into(), &source, &language, self.backend);
105
105
 
106
106
  self.local_graph_tx
107
107
  .send(local_graph)
@@ -110,8 +110,8 @@ impl Job for IndexingJob {
110
110
  }
111
111
 
112
112
  /// Indexes a single source string in memory, dispatching to the appropriate indexer based on `language_id`.
113
- pub fn index_source(graph: &mut Graph, uri: &str, source: &str, language_id: &LanguageId) {
114
- let local_graph = build_local_graph(uri.to_string(), source, language_id, IndexerBackend::RubyIndexer);
113
+ pub fn index_source(graph: &mut Graph, uri: Box<str>, source: &str, language_id: &LanguageId) {
114
+ let local_graph = build_local_graph(uri, source, language_id, IndexerBackend::RubyIndexer);
115
115
  graph.consume_document_changes(local_graph);
116
116
  }
117
117
 
@@ -153,7 +153,7 @@ pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>, backend: IndexerBacke
153
153
 
154
154
  /// Indexes a source string using the appropriate indexer for the given language.
155
155
  #[must_use]
156
- pub fn build_local_graph(uri: String, source: &str, language: &LanguageId, backend: IndexerBackend) -> LocalGraph {
156
+ pub fn build_local_graph(uri: Box<str>, source: &str, language: &LanguageId, backend: IndexerBackend) -> LocalGraph {
157
157
  match language {
158
158
  LanguageId::Ruby => match backend {
159
159
  IndexerBackend::RubyIndexer => {
@@ -203,7 +203,7 @@ mod tests {
203
203
  let mut graph = Graph::new();
204
204
  let errors = index_files(&mut graph, vec![relative_to_pwd.clone()], IndexerBackend::RubyIndexer);
205
205
 
206
- assert!(errors.is_empty());
206
+ assert_eq!(errors.as_slice(), []);
207
207
  assert_eq!(graph.documents().len(), 2);
208
208
  }
209
209
 
@@ -228,7 +228,7 @@ mod tests {
228
228
  assert_eq!(6, graph.definitions().len());
229
229
  assert_eq!(2, graph.documents().len());
230
230
 
231
- index_source(&mut graph, &uri, "", &LanguageId::Ruby);
231
+ index_source(&mut graph, uri.into(), "", &LanguageId::Ruby);
232
232
 
233
233
  assert_eq!(5, graph.definitions().len());
234
234
  assert_eq!(2, graph.documents().len());
@@ -211,7 +211,7 @@ mod tests {
211
211
 
212
212
  let (files, errors) = collect_document_paths(&context, &["foo", "bar"]);
213
213
 
214
- assert!(errors.is_empty());
214
+ assert_eq!(errors.as_slice(), []);
215
215
 
216
216
  assert_eq!(
217
217
  files,
@@ -236,7 +236,7 @@ mod tests {
236
236
 
237
237
  let (files, errors) = collect_document_paths(&context, &["bar"]);
238
238
 
239
- assert!(errors.is_empty());
239
+ assert_eq!(errors.as_slice(), []);
240
240
 
241
241
  assert_eq!(
242
242
  files,
@@ -260,7 +260,7 @@ mod tests {
260
260
 
261
261
  let (files, errors) = collect_document_paths(&context, &["lib", "sig", "config.ru"]);
262
262
 
263
- assert!(errors.is_empty());
263
+ assert_eq!(errors.as_slice(), []);
264
264
 
265
265
  assert_eq!(
266
266
  [
@@ -287,7 +287,7 @@ mod tests {
287
287
  &HashSet::new(),
288
288
  );
289
289
 
290
- assert!(files.is_empty());
290
+ assert_eq!(files, [] as [std::path::PathBuf; 0]);
291
291
 
292
292
  assert_eq!(
293
293
  errors,
@@ -315,8 +315,8 @@ mod tests {
315
315
 
316
316
  let (files, errors) = collect_file_paths(vec![relative_root.to_string_lossy().into_owned()], &HashSet::new());
317
317
 
318
- assert!(errors.is_empty());
319
- assert!(!files.is_empty());
318
+ assert_eq!(errors.as_slice(), []);
319
+ assert_ne!(files, [] as [std::path::PathBuf; 0]);
320
320
  assert!(
321
321
  files.iter().all(|path| path.is_absolute()),
322
322
  "expected only absolute paths, got {files:?}"
@@ -336,7 +336,7 @@ mod tests {
336
336
 
337
337
  let (files, errors) = collect_document_paths_with_exclusions(&context, &["included", "excluded"], &excluded);
338
338
 
339
- assert!(errors.is_empty());
339
+ assert_eq!(errors.as_slice(), []);
340
340
  assert_eq!(files, [included.to_str().unwrap().to_string()]);
341
341
  }
342
342
 
@@ -353,7 +353,7 @@ mod tests {
353
353
 
354
354
  let (files, errors) = collect_document_paths_with_exclusions(&context, &["root"], &excluded);
355
355
 
356
- assert!(errors.is_empty());
356
+ assert_eq!(errors.as_slice(), []);
357
357
  assert_eq!(files, [kept.to_str().unwrap().to_string()]);
358
358
  }
359
359
 
@@ -374,7 +374,7 @@ mod tests {
374
374
 
375
375
  let (files, errors) = collect_document_paths(&context, &["project"]);
376
376
 
377
- assert!(errors.is_empty());
377
+ assert_eq!(errors.as_slice(), []);
378
378
  // The symlink is indexed at its own path, not resolved to the target.
379
379
  let alias = PathBuf::from("project").join("alias.rb");
380
380
  assert_eq!(files, [alias.to_str().unwrap().to_string()]);
@@ -398,7 +398,7 @@ mod tests {
398
398
 
399
399
  let (files, errors) = collect_document_paths(&context, &["project"]);
400
400
 
401
- assert!(errors.is_empty());
401
+ assert_eq!(errors.as_slice(), []);
402
402
  // The symlinked directory is not followed, so `outside/bar.rb` is never reached.
403
403
  assert_eq!(files, [kept.to_str().unwrap().to_string()]);
404
404
  }
@@ -415,7 +415,7 @@ mod tests {
415
415
 
416
416
  let (files, errors) = collect_document_paths(&context, &["link"]);
417
417
 
418
- assert!(errors.is_empty());
418
+ assert_eq!(errors.as_slice(), []);
419
419
  // The requested root is traversed; files are indexed under the requested (symlink) path.
420
420
  let foo = PathBuf::from("link").join("foo.rb");
421
421
  assert_eq!(files, [foo.to_str().unwrap().to_string()]);
@@ -458,7 +458,7 @@ mod tests {
458
458
 
459
459
  let (files, errors) = collect_document_paths_with_exclusions(&context, &["lib"], &excluded);
460
460
 
461
- assert!(errors.is_empty());
461
+ assert_eq!(errors.as_slice(), []);
462
462
  assert_eq!(files, [kept.to_str().unwrap().to_string()]);
463
463
  }
464
464
  }
@@ -48,7 +48,7 @@ pub fn add_built_in_data(graph: &mut Graph) {
48
48
  class Class < Module
49
49
  end
50
50
  ";
51
- indexing::index_source(graph, uri.as_ref(), source, &LanguageId::Rbs);
51
+ indexing::index_source(graph, uri.to_string().into(), source, &LanguageId::Rbs);
52
52
 
53
53
  // Creating declarations eagerly is still necessary because we need to associate correct ownership data no matter in
54
54
  // what order we discover classes and modules
@@ -4,13 +4,13 @@ use crate::offset::Offset;
4
4
  #[derive(Debug, Clone)]
5
5
  pub struct Comment {
6
6
  offset: Offset,
7
- string: String,
7
+ string: Box<str>,
8
8
  }
9
- assert_mem_size!(Comment, 32);
9
+ assert_mem_size!(Comment, 24);
10
10
 
11
11
  impl Comment {
12
12
  #[must_use]
13
- pub fn new(offset: Offset, string: String) -> Self {
13
+ pub fn new(offset: Offset, string: Box<str>) -> Self {
14
14
  Self { offset, string }
15
15
  }
16
16
 
@@ -20,7 +20,7 @@ impl Comment {
20
20
  }
21
21
 
22
22
  #[must_use]
23
- pub fn string(&self) -> &String {
23
+ pub fn string(&self) -> &str {
24
24
  &self.string
25
25
  }
26
26
  }
@@ -119,7 +119,7 @@ pub struct DeclarationCore<T> {
119
119
  /// The list of definition IDs that compose this declaration
120
120
  definition_ids: Vec<DefinitionId>,
121
121
  /// The set of references that are made to this declaration
122
- references: IdentityHashSet<T>,
122
+ references: Vec<T>,
123
123
  /// The ID of the owner of this declaration
124
124
  owner_id: DeclarationId,
125
125
  }
@@ -130,7 +130,7 @@ impl<T: Eq + Hash> DeclarationCore<T> {
130
130
  Self {
131
131
  name: name.into_boxed_str(),
132
132
  definition_ids: Vec::new(),
133
- references: IdentityHashSet::default(),
133
+ references: Vec::new(),
134
134
  owner_id,
135
135
  }
136
136
  }
@@ -152,16 +152,24 @@ impl<T: Eq + Hash> DeclarationCore<T> {
152
152
  }
153
153
 
154
154
  #[must_use]
155
- pub fn references(&self) -> &IdentityHashSet<T> {
155
+ pub fn references(&self) -> &[T] {
156
156
  &self.references
157
157
  }
158
158
 
159
159
  pub fn add_reference(&mut self, reference_id: T) {
160
- self.references.insert(reference_id);
160
+ debug_assert!(
161
+ !self.references.contains(&reference_id),
162
+ "Cannot add the same exact reference to a declaration twice. Duplicate reference IDs"
163
+ );
164
+
165
+ self.references.push(reference_id);
161
166
  }
162
167
 
163
168
  pub fn remove_reference(&mut self, reference_id: &T) {
164
- self.references.remove(reference_id);
169
+ if let Some(pos) = self.references.iter().position(|id| id == reference_id) {
170
+ self.references.swap_remove(pos);
171
+ self.references.shrink_to_fit();
172
+ }
165
173
  }
166
174
 
167
175
  #[must_use]
@@ -493,7 +501,7 @@ impl Declaration {
493
501
  /// Returns the constant reference IDs for declarations that track constant references (`Namespace`, `Constant`,
494
502
  /// `ConstantAlias`). Returns `None` for other declaration types.
495
503
  #[must_use]
496
- pub fn constant_references(&self) -> Option<&IdentityHashSet<ConstantReferenceId>> {
504
+ pub fn constant_references(&self) -> Option<&[ConstantReferenceId]> {
497
505
  match self {
498
506
  Declaration::Namespace(it) => Some(it.references()),
499
507
  Declaration::Constant(it) | Declaration::ConstantAlias(it) => Some(it.references()),
@@ -559,7 +567,7 @@ impl Namespace {
559
567
  }
560
568
 
561
569
  #[must_use]
562
- pub fn references(&self) -> &IdentityHashSet<ConstantReferenceId> {
570
+ pub fn references(&self) -> &[ConstantReferenceId] {
563
571
  all_namespaces!(self, it => &it.core.references)
564
572
  }
565
573
 
@@ -674,31 +682,31 @@ impl Namespace {
674
682
  }
675
683
 
676
684
  namespace_declaration!(Class, ClassDeclaration);
677
- assert_mem_size!(ClassDeclaration, 184);
685
+ assert_mem_size!(ClassDeclaration, 176);
678
686
  namespace_declaration!(Module, ModuleDeclaration);
679
- assert_mem_size!(ModuleDeclaration, 184);
687
+ assert_mem_size!(ModuleDeclaration, 176);
680
688
  namespace_declaration!(SingletonClass, SingletonClassDeclaration);
681
- assert_mem_size!(SingletonClassDeclaration, 184);
689
+ assert_mem_size!(SingletonClassDeclaration, 176);
682
690
  namespace_declaration!(Todo, TodoDeclaration);
683
- assert_mem_size!(TodoDeclaration, 184);
691
+ assert_mem_size!(TodoDeclaration, 176);
684
692
 
685
693
  pub type ConstantDeclaration = DeclarationCore<ConstantReferenceId>;
686
- assert_mem_size!(ConstantDeclaration, 80);
694
+ assert_mem_size!(ConstantDeclaration, 72);
687
695
 
688
696
  pub type MethodDeclaration = DeclarationCore<MethodReferenceId>;
689
- assert_mem_size!(MethodDeclaration, 80);
697
+ assert_mem_size!(MethodDeclaration, 72);
690
698
 
691
699
  pub type GlobalVariableDeclaration = DeclarationCore<GlobalVariableReferenceId>;
692
- assert_mem_size!(GlobalVariableDeclaration, 80);
700
+ assert_mem_size!(GlobalVariableDeclaration, 72);
693
701
 
694
702
  pub type InstanceVariableDeclaration = DeclarationCore<InstanceVariableReferenceId>;
695
- assert_mem_size!(InstanceVariableDeclaration, 80);
703
+ assert_mem_size!(InstanceVariableDeclaration, 72);
696
704
 
697
705
  pub type ClassVariableDeclaration = DeclarationCore<ClassVariableReferenceId>;
698
- assert_mem_size!(ClassVariableDeclaration, 80);
706
+ assert_mem_size!(ClassVariableDeclaration, 72);
699
707
 
700
708
  pub type ConstantAliasDeclaration = DeclarationCore<ConstantReferenceId>;
701
- assert_mem_size!(ConstantAliasDeclaration, 80);
709
+ assert_mem_size!(ConstantAliasDeclaration, 72);
702
710
 
703
711
  #[cfg(test)]
704
712
  mod tests {
@@ -12,7 +12,7 @@ use crate::model::ids::{ConstantReferenceId, DefinitionId, MethodReferenceId};
12
12
  // definitions and references discovered in it
13
13
  #[derive(Debug)]
14
14
  pub struct Document {
15
- uri: String,
15
+ uri: Box<str>,
16
16
  line_index: LineIndex,
17
17
  definition_ids: Vec<DefinitionId>,
18
18
  method_reference_ids: Vec<MethodReferenceId>,
@@ -20,11 +20,11 @@ pub struct Document {
20
20
  diagnostics: Vec<Diagnostic>,
21
21
  content_hash: u64,
22
22
  }
23
- assert_mem_size!(Document, 184);
23
+ assert_mem_size!(Document, 176);
24
24
 
25
25
  impl Document {
26
26
  #[must_use]
27
- pub fn new(uri: String, source: &str) -> Self {
27
+ pub fn new(uri: Box<str>, source: &str) -> Self {
28
28
  Self {
29
29
  uri,
30
30
  line_index: LineIndex::new(source),
@@ -176,7 +176,7 @@ mod tests {
176
176
  #[test]
177
177
  #[should_panic(expected = "Cannot add the same exact definition to a document twice. Duplicate definition IDs")]
178
178
  fn inserting_duplicate_definitions() {
179
- let mut document = Document::new("file:///foo.rb".to_string(), "class Foo; end");
179
+ let mut document = Document::new("file:///foo.rb".into(), "class Foo; end");
180
180
  let def_id = DefinitionId::new(123);
181
181
 
182
182
  document.add_definition(def_id);
@@ -187,7 +187,7 @@ mod tests {
187
187
 
188
188
  #[test]
189
189
  fn tracking_references() {
190
- let mut document = Document::new("file:///foo.rb".to_string(), "class Foo; end");
190
+ let mut document = Document::new("file:///foo.rb".into(), "class Foo; end");
191
191
  let method_ref = MethodReferenceId::new(1);
192
192
  let constant_ref = ConstantReferenceId::new(2);
193
193
 
@@ -202,7 +202,7 @@ mod tests {
202
202
  fn require_path() {
203
203
  let root = test_root();
204
204
  let path = root.join("lib").join("foo").join("bar.rb");
205
- let uri = Url::from_file_path(path).unwrap().to_string();
205
+ let uri = Url::from_file_path(path).unwrap().to_string().into();
206
206
  let load_paths = [root.join("lib")];
207
207
 
208
208
  let document = Document::new(uri, "");
@@ -213,7 +213,7 @@ mod tests {
213
213
  fn require_path_first_load_path_wins() {
214
214
  let root = test_root();
215
215
  let path = root.join("a").join("b").join("foo.rb");
216
- let uri = Url::from_file_path(path).unwrap().to_string();
216
+ let uri = Url::from_file_path(path).unwrap().to_string().into();
217
217
  let load_path_a = root.join("a");
218
218
  let load_path_ab = root.join("a").join("b");
219
219
  let load_paths = [load_path_a, load_path_ab];
@@ -228,18 +228,18 @@ mod tests {
228
228
  let load_paths = [root.join("lib")];
229
229
 
230
230
  // non-file URI
231
- let document = Document::new("untitled:Untitled-1".to_string(), "");
231
+ let document = Document::new("untitled:Untitled-1".into(), "");
232
232
  assert!(document.require_path(&load_paths).is_none());
233
233
 
234
234
  // non-.rb extension
235
235
  let path = root.join("lib").join("foo.so");
236
- let uri = Url::from_file_path(path).unwrap().to_string();
236
+ let uri = Url::from_file_path(path).unwrap().to_string().into();
237
237
  let document = Document::new(uri, "");
238
238
  assert!(document.require_path(&load_paths).is_none());
239
239
 
240
240
  // /libfoo is not under /lib - should not match due to partial directory name
241
241
  let path = root.join("libfoo").join("bar.rb");
242
- let uri = Url::from_file_path(path).unwrap().to_string();
242
+ let uri = Url::from_file_path(path).unwrap().to_string().into();
243
243
  let document = Document::new(uri, "");
244
244
  assert!(document.require_path(&load_paths).is_none());
245
245
  }
@@ -248,7 +248,7 @@ mod tests {
248
248
  fn require_path_with_spaces() {
249
249
  let root = test_root();
250
250
  let path = root.join("lib").join("space foo").join("bar.rb");
251
- let uri = Url::from_file_path(path).unwrap().to_string();
251
+ let uri = Url::from_file_path(path).unwrap().to_string().into();
252
252
  let load_paths = [root.join("lib")];
253
253
 
254
254
  let document = Document::new(uri, "");
@@ -1759,7 +1759,7 @@ mod tests {
1759
1759
  assert_eq!(context.graph().constant_references.len(), 4);
1760
1760
  {
1761
1761
  let declaration = context.graph().declarations().get(&DeclarationId::from("Foo")).unwrap();
1762
- assert!(declaration.as_namespace().unwrap().references().is_empty());
1762
+ assert_eq!(declaration.as_namespace().unwrap().references(), []);
1763
1763
  }
1764
1764
  }
1765
1765
 
@@ -2090,14 +2090,14 @@ mod tests {
2090
2090
  let definitions = context.graph().get("CommentedClass").unwrap();
2091
2091
  let def = definitions.first().unwrap();
2092
2092
  assert_eq!(
2093
- def.comments().iter().map(Comment::string).collect::<Vec<&String>>(),
2093
+ def.comments().iter().map(Comment::string).collect::<Vec<&str>>(),
2094
2094
  ["# This is a class comment", "# Multi-line comment"]
2095
2095
  );
2096
2096
 
2097
2097
  let definitions = context.graph().get("CommentedModule").unwrap();
2098
2098
  let def = definitions.first().unwrap();
2099
2099
  assert_eq!(
2100
- def.comments().iter().map(Comment::string).collect::<Vec<&String>>(),
2100
+ def.comments().iter().map(Comment::string).collect::<Vec<&str>>(),
2101
2101
  ["# Module comment"]
2102
2102
  );
2103
2103
 
@@ -30,21 +30,9 @@ impl Offset {
30
30
  Self { start, end }
31
31
  }
32
32
 
33
- /// # Panics
34
- ///
35
- /// This function can panic if the Prism location offsets do not fit into a u32
36
33
  #[must_use]
37
34
  pub fn from_prism_location(location: &ruby_prism::Location) -> Self {
38
- Self::new(
39
- location
40
- .start_offset()
41
- .try_into()
42
- .expect("Expected usize `start` to fit in `u32`"),
43
- location
44
- .end_offset()
45
- .try_into()
46
- .expect("Expected usize `end` to fit in `u32`"),
47
- )
35
+ Self::new(location.start(), location.end())
48
36
  }
49
37
 
50
38
  /// # Panics