rubydex 0.4.1 → 0.4.2
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.
- checksums.yaml +4 -4
- data/README.md +11 -0
- data/THIRD_PARTY_LICENSES.html +13 -24
- data/lib/rubydex/cli/command/dead_code.rb +59 -0
- data/lib/rubydex/mcp_server/tools/codebase_stats_tool.rb +1 -1
- data/lib/rubydex/mcp_server/tools/find_constant_references_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/find_dead_code_candidates_tool.rb +33 -0
- data/lib/rubydex/mcp_server/tools/get_declaration_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/get_descendants_tool.rb +4 -4
- data/lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb +2 -2
- data/lib/rubydex/mcp_server/tools/search_declarations_tool.rb +6 -6
- data/lib/rubydex/mcp_server.rb +24 -12
- data/lib/rubydex/version.rb +1 -1
- data/rust/Cargo.lock +17 -11
- data/rust/Cargo.toml +3 -0
- data/rust/rubydex/Cargo.toml +2 -2
- data/rust/rubydex/src/compile_assertions.rs +2 -0
- data/rust/rubydex/src/config.rs +1 -1
- data/rust/rubydex/src/indexing/rbs_indexer.rs +4 -4
- data/rust/rubydex/src/indexing/ruby_indexer.rs +26 -18
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +42 -2
- data/rust/rubydex/src/indexing.rs +6 -6
- data/rust/rubydex/src/listing.rs +12 -12
- data/rust/rubydex/src/model/built_in.rs +1 -1
- data/rust/rubydex/src/model/comment.rs +4 -4
- data/rust/rubydex/src/model/declaration.rs +25 -17
- data/rust/rubydex/src/model/document.rs +11 -11
- data/rust/rubydex/src/model/graph.rs +3 -3
- data/rust/rubydex/src/offset.rs +1 -13
- data/rust/rubydex/src/operation/ruby_builder.rs +29 -19
- data/rust/rubydex/src/query.rs +3 -2
- data/rust/rubydex/src/test_utils/graph_test.rs +2 -2
- data/rust/rubydex/src/test_utils/local_graph_test.rs +13 -6
- data/rust/rubydex-sys/Cargo.toml +2 -2
- data/rust/rubydex-sys/src/definition_api.rs +1 -1
- data/rust/rubydex-sys/src/graph_api.rs +96 -49
- data/rust/rubydex-sys/src/name_api.rs +193 -58
- metadata +191 -191
|
@@ -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:
|
|
97
|
-
let uri_id = UriId::from(
|
|
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
|
|
1393
|
-
Some((Self::location_to_string(&
|
|
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().
|
|
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().
|
|
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().
|
|
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.
|
|
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
|
-
|
|
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(), &
|
|
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(), &
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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!(¶ms[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!(¶ms[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:
|
|
114
|
-
let local_graph = build_local_graph(uri
|
|
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:
|
|
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
|
-
|
|
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,
|
|
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());
|
data/rust/rubydex/src/listing.rs
CHANGED
|
@@ -211,7 +211,7 @@ mod tests {
|
|
|
211
211
|
|
|
212
212
|
let (files, errors) = collect_document_paths(&context, &["foo", "bar"]);
|
|
213
213
|
|
|
214
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|
|
7
|
+
string: Box<str>,
|
|
8
8
|
}
|
|
9
|
-
assert_mem_size!(Comment,
|
|
9
|
+
assert_mem_size!(Comment, 24);
|
|
10
10
|
|
|
11
11
|
impl Comment {
|
|
12
12
|
#[must_use]
|
|
13
|
-
pub fn new(offset: Offset, string:
|
|
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) -> &
|
|
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:
|
|
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:
|
|
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) -> &
|
|
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
|
-
|
|
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.
|
|
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<&
|
|
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) -> &
|
|
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,
|
|
685
|
+
assert_mem_size!(ClassDeclaration, 176);
|
|
678
686
|
namespace_declaration!(Module, ModuleDeclaration);
|
|
679
|
-
assert_mem_size!(ModuleDeclaration,
|
|
687
|
+
assert_mem_size!(ModuleDeclaration, 176);
|
|
680
688
|
namespace_declaration!(SingletonClass, SingletonClassDeclaration);
|
|
681
|
-
assert_mem_size!(SingletonClassDeclaration,
|
|
689
|
+
assert_mem_size!(SingletonClassDeclaration, 176);
|
|
682
690
|
namespace_declaration!(Todo, TodoDeclaration);
|
|
683
|
-
assert_mem_size!(TodoDeclaration,
|
|
691
|
+
assert_mem_size!(TodoDeclaration, 176);
|
|
684
692
|
|
|
685
693
|
pub type ConstantDeclaration = DeclarationCore<ConstantReferenceId>;
|
|
686
|
-
assert_mem_size!(ConstantDeclaration,
|
|
694
|
+
assert_mem_size!(ConstantDeclaration, 72);
|
|
687
695
|
|
|
688
696
|
pub type MethodDeclaration = DeclarationCore<MethodReferenceId>;
|
|
689
|
-
assert_mem_size!(MethodDeclaration,
|
|
697
|
+
assert_mem_size!(MethodDeclaration, 72);
|
|
690
698
|
|
|
691
699
|
pub type GlobalVariableDeclaration = DeclarationCore<GlobalVariableReferenceId>;
|
|
692
|
-
assert_mem_size!(GlobalVariableDeclaration,
|
|
700
|
+
assert_mem_size!(GlobalVariableDeclaration, 72);
|
|
693
701
|
|
|
694
702
|
pub type InstanceVariableDeclaration = DeclarationCore<InstanceVariableReferenceId>;
|
|
695
|
-
assert_mem_size!(InstanceVariableDeclaration,
|
|
703
|
+
assert_mem_size!(InstanceVariableDeclaration, 72);
|
|
696
704
|
|
|
697
705
|
pub type ClassVariableDeclaration = DeclarationCore<ClassVariableReferenceId>;
|
|
698
|
-
assert_mem_size!(ClassVariableDeclaration,
|
|
706
|
+
assert_mem_size!(ClassVariableDeclaration, 72);
|
|
699
707
|
|
|
700
708
|
pub type ConstantAliasDeclaration = DeclarationCore<ConstantReferenceId>;
|
|
701
|
-
assert_mem_size!(ConstantAliasDeclaration,
|
|
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:
|
|
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,
|
|
23
|
+
assert_mem_size!(Document, 176);
|
|
24
24
|
|
|
25
25
|
impl Document {
|
|
26
26
|
#[must_use]
|
|
27
|
-
pub fn new(uri:
|
|
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".
|
|
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".
|
|
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".
|
|
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
|
-
|
|
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<&
|
|
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<&
|
|
2100
|
+
def.comments().iter().map(Comment::string).collect::<Vec<&str>>(),
|
|
2101
2101
|
["# Module comment"]
|
|
2102
2102
|
);
|
|
2103
2103
|
|
data/rust/rubydex/src/offset.rs
CHANGED
|
@@ -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
|