rubydex 0.1.0.beta4 → 0.1.0.beta6
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 +1 -1
- data/ext/rubydex/graph.c +25 -2
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/version.rb +1 -1
- data/rust/rubydex/src/indexing/rbs_indexer.rs +220 -10
- data/rust/rubydex/src/indexing/ruby_indexer.rs +109 -249
- data/rust/rubydex/src/indexing.rs +79 -12
- data/rust/rubydex/src/listing.rs +24 -1
- data/rust/rubydex/src/model/declaration.rs +5 -0
- data/rust/rubydex/src/model/graph.rs +25 -0
- data/rust/rubydex/src/model/name.rs +5 -0
- data/rust/rubydex/src/offset.rs +17 -0
- data/rust/rubydex/src/query.rs +853 -38
- data/rust/rubydex/src/resolution.rs +86 -0
- data/rust/rubydex/src/test_utils/graph_test.rs +8 -10
- data/rust/rubydex/src/test_utils/local_graph_test.rs +167 -0
- data/rust/rubydex-sys/src/graph_api.rs +37 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2c48ae779052983ff0d4f7a345b2a6ac612271cc6c015ba99486220d5617949
|
|
4
|
+
data.tar.gz: 4c81285808882e4a545ecb34bc418821d996fd4e6fe34200f89963430f8014f6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e61f0fbf4d4cf6613042b40a4e72a41d36428b72c1f21c711b9c99ea3e6bc686b87edd9d182307e29af796df7256921da6e88ffb9cf54219630b34c324d151c
|
|
7
|
+
data.tar.gz: 1bb42b0c43a1483d1610ea743320852c1bcc4d3d5ebfab043949fb18671eb5a0c2d8f7275f3795c66faa884ac40bca62279739a23e38bbef624256c3cdf1a09e
|
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ of using the Ruby API:
|
|
|
12
12
|
# Create a new graph representing the current workspace
|
|
13
13
|
graph = Rubydex::Graph.new
|
|
14
14
|
# Configuring graph LSP encoding
|
|
15
|
-
graph.
|
|
15
|
+
graph.encoding = "utf16"
|
|
16
16
|
# Index the entire workspace with all dependencies
|
|
17
17
|
graph.index_workspace
|
|
18
18
|
# Or index specific file paths
|
data/ext/rubydex/graph.c
CHANGED
|
@@ -61,6 +61,28 @@ static VALUE rdxr_graph_index_all(VALUE self, VALUE file_paths) {
|
|
|
61
61
|
return array;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Indexes a single source string in memory, dispatching to the appropriate indexer based on language_id
|
|
65
|
+
//
|
|
66
|
+
// Graph#index_source: (String uri, String source, String language_id) -> void
|
|
67
|
+
static VALUE rdxr_graph_index_source(VALUE self, VALUE uri, VALUE source, VALUE language_id) {
|
|
68
|
+
Check_Type(uri, T_STRING);
|
|
69
|
+
Check_Type(source, T_STRING);
|
|
70
|
+
Check_Type(language_id, T_STRING);
|
|
71
|
+
|
|
72
|
+
void *graph;
|
|
73
|
+
TypedData_Get_Struct(self, void *, &graph_type, graph);
|
|
74
|
+
|
|
75
|
+
const char *uri_str = StringValueCStr(uri);
|
|
76
|
+
const char *source_str = StringValueCStr(source);
|
|
77
|
+
const char *language_id_str = StringValueCStr(language_id);
|
|
78
|
+
|
|
79
|
+
if (!rdx_index_source(graph, uri_str, source_str, language_id_str)) {
|
|
80
|
+
rb_raise(rb_eArgError, "unsupported language_id `%s`", language_id_str);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return Qnil;
|
|
84
|
+
}
|
|
85
|
+
|
|
64
86
|
// Size function for the declarations enumerator
|
|
65
87
|
static VALUE graph_declarations_size(VALUE self, VALUE _args, VALUE _eobj) {
|
|
66
88
|
void *graph;
|
|
@@ -303,7 +325,7 @@ static VALUE rdxr_graph_resolve(VALUE self) {
|
|
|
303
325
|
return self;
|
|
304
326
|
}
|
|
305
327
|
|
|
306
|
-
// Graph#
|
|
328
|
+
// Graph#encoding=: (String) -> void
|
|
307
329
|
// Sets the encoding used for transforming byte offsets into LSP code unit line/column positions
|
|
308
330
|
static VALUE rdxr_graph_set_encoding(VALUE self, VALUE encoding) {
|
|
309
331
|
Check_Type(encoding, T_STRING);
|
|
@@ -449,6 +471,7 @@ void rdxi_initialize_graph(VALUE mRubydex) {
|
|
|
449
471
|
cGraph = rb_define_class_under(mRubydex, "Graph", rb_cObject);
|
|
450
472
|
rb_define_alloc_func(cGraph, rdxr_graph_alloc);
|
|
451
473
|
rb_define_method(cGraph, "index_all", rdxr_graph_index_all, 1);
|
|
474
|
+
rb_define_method(cGraph, "index_source", rdxr_graph_index_source, 3);
|
|
452
475
|
rb_define_method(cGraph, "delete_document", rdxr_graph_delete_document, 1);
|
|
453
476
|
rb_define_method(cGraph, "resolve", rdxr_graph_resolve, 0);
|
|
454
477
|
rb_define_method(cGraph, "resolve_constant", rdxr_graph_resolve_constant, 2);
|
|
@@ -459,7 +482,7 @@ void rdxi_initialize_graph(VALUE mRubydex) {
|
|
|
459
482
|
rb_define_method(cGraph, "diagnostics", rdxr_graph_diagnostics, 0);
|
|
460
483
|
rb_define_method(cGraph, "[]", rdxr_graph_aref, 1);
|
|
461
484
|
rb_define_method(cGraph, "search", rdxr_graph_search, 1);
|
|
462
|
-
rb_define_method(cGraph, "
|
|
485
|
+
rb_define_method(cGraph, "encoding=", rdxr_graph_set_encoding, 1);
|
|
463
486
|
rb_define_method(cGraph, "resolve_require_path", rdxr_graph_resolve_require_path, 2);
|
|
464
487
|
rb_define_method(cGraph, "require_paths", rdxr_graph_require_paths, 1);
|
|
465
488
|
}
|
|
Binary file
|
data/lib/rubydex/version.rb
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
//! Visit the RBS AST and create type definitions.
|
|
2
2
|
|
|
3
|
-
use
|
|
4
|
-
indexing::local_graph::LocalGraph,
|
|
5
|
-
model::{document::Document, ids::UriId},
|
|
6
|
-
};
|
|
3
|
+
use ruby_rbs::node::{self, ModuleNode, Node, TypeNameNode, Visit};
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
use crate::diagnostic::Rule;
|
|
6
|
+
use crate::indexing::local_graph::LocalGraph;
|
|
7
|
+
use crate::model::comment::Comment;
|
|
8
|
+
use crate::model::definitions::{Definition, DefinitionFlags, ModuleDefinition};
|
|
9
|
+
use crate::model::document::Document;
|
|
10
|
+
use crate::model::ids::{DefinitionId, NameId, UriId};
|
|
11
|
+
use crate::model::name::{Name, ParentScope};
|
|
12
|
+
use crate::offset::Offset;
|
|
13
|
+
|
|
14
|
+
pub struct RBSIndexer<'a> {
|
|
10
15
|
uri_id: UriId,
|
|
11
16
|
local_graph: LocalGraph,
|
|
17
|
+
source: &'a str,
|
|
18
|
+
nesting_stack: Vec<DefinitionId>,
|
|
12
19
|
}
|
|
13
20
|
|
|
14
|
-
impl RBSIndexer {
|
|
21
|
+
impl<'a> RBSIndexer<'a> {
|
|
15
22
|
#[must_use]
|
|
16
|
-
pub fn new(uri: String, source: &str) -> Self {
|
|
23
|
+
pub fn new(uri: String, source: &'a str) -> Self {
|
|
17
24
|
let uri_id = UriId::from(&uri);
|
|
18
25
|
let local_graph = LocalGraph::new(uri_id, Document::new(uri, source));
|
|
19
26
|
|
|
20
|
-
Self {
|
|
27
|
+
Self {
|
|
28
|
+
uri_id,
|
|
29
|
+
local_graph,
|
|
30
|
+
source,
|
|
31
|
+
nesting_stack: Vec::new(),
|
|
32
|
+
}
|
|
21
33
|
}
|
|
22
34
|
|
|
23
35
|
#[must_use]
|
|
@@ -25,5 +37,203 @@ impl RBSIndexer {
|
|
|
25
37
|
self.local_graph
|
|
26
38
|
}
|
|
27
39
|
|
|
28
|
-
pub fn index(&mut self) {
|
|
40
|
+
pub fn index(&mut self) {
|
|
41
|
+
let Ok(signature) = node::parse(self.source.as_bytes()) else {
|
|
42
|
+
self.local_graph.add_diagnostic(
|
|
43
|
+
Rule::ParseError,
|
|
44
|
+
Offset::new(0, 0),
|
|
45
|
+
"Failed to parse RBS document".to_string(),
|
|
46
|
+
);
|
|
47
|
+
return;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
self.visit(&signature.as_node());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn bytes_to_string(name: &[u8]) -> String {
|
|
54
|
+
String::from_utf8_lossy(name).into_owned()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Converts an RBS `TypeNameNode` into a rubydex `NameId`.
|
|
58
|
+
///
|
|
59
|
+
/// Walks the namespace path (e.g. `Foo::Bar` in `Foo::Bar::Baz`) to build
|
|
60
|
+
/// a `ParentScope` chain, then creates the final `Name` for the leaf segment.
|
|
61
|
+
fn index_type_name(&mut self, type_name: &TypeNameNode, nesting_name_id: Option<NameId>) -> NameId {
|
|
62
|
+
let namespace = type_name.namespace();
|
|
63
|
+
|
|
64
|
+
let mut parent_scope = if namespace.absolute() {
|
|
65
|
+
ParentScope::TopLevel
|
|
66
|
+
} else {
|
|
67
|
+
ParentScope::None
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
for path_node in namespace.path().iter() {
|
|
71
|
+
let Node::Symbol(symbol) = path_node else {
|
|
72
|
+
continue;
|
|
73
|
+
};
|
|
74
|
+
parent_scope = ParentScope::Some(self.intern_name(symbol.name(), parent_scope, nesting_name_id));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
self.intern_name(type_name.name().name(), parent_scope, nesting_name_id)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fn intern_name(&mut self, name_bytes: &[u8], parent_scope: ParentScope, nesting_name_id: Option<NameId>) -> NameId {
|
|
81
|
+
let string_id = self.local_graph.intern_string(Self::bytes_to_string(name_bytes));
|
|
82
|
+
self.local_graph
|
|
83
|
+
.add_name(Name::new(string_id, parent_scope, nesting_name_id))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn parent_lexical_scope_id(&self) -> Option<DefinitionId> {
|
|
87
|
+
self.nesting_stack.last().copied()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn add_member_to_current_lexical_scope(&mut self, owner_id: DefinitionId, member_id: DefinitionId) {
|
|
91
|
+
let owner = self
|
|
92
|
+
.local_graph
|
|
93
|
+
.get_definition_mut(owner_id)
|
|
94
|
+
.expect("owner definition should exist");
|
|
95
|
+
|
|
96
|
+
match owner {
|
|
97
|
+
Definition::Module(module) => module.add_member(member_id),
|
|
98
|
+
Definition::Class(class) => class.add_member(member_id),
|
|
99
|
+
_ => unreachable!("RBS nesting stack only contains modules/classes"),
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
impl Visit for RBSIndexer<'_> {
|
|
105
|
+
fn visit_module_node(&mut self, module_node: &ModuleNode) {
|
|
106
|
+
let lexical_nesting_id = self.parent_lexical_scope_id();
|
|
107
|
+
let nesting_name_id = lexical_nesting_id.map(|id| {
|
|
108
|
+
let owner = self
|
|
109
|
+
.local_graph
|
|
110
|
+
.definitions()
|
|
111
|
+
.get(&id)
|
|
112
|
+
.expect("owner definition should exist");
|
|
113
|
+
*owner.name_id().expect("nesting definition should have a name")
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
let type_name = module_node.name();
|
|
117
|
+
let name_id = self.index_type_name(&type_name, nesting_name_id);
|
|
118
|
+
let offset = Offset::from_rbs_location(&module_node.location());
|
|
119
|
+
let name_offset = Offset::from_rbs_location(&type_name.name().location());
|
|
120
|
+
|
|
121
|
+
let comments: Vec<_> = module_node
|
|
122
|
+
.comment()
|
|
123
|
+
.into_iter()
|
|
124
|
+
.map(|comment| {
|
|
125
|
+
let text = Self::bytes_to_string(comment.string().as_bytes());
|
|
126
|
+
Comment::new(Offset::from_rbs_location(&comment.location()), text)
|
|
127
|
+
})
|
|
128
|
+
.collect();
|
|
129
|
+
|
|
130
|
+
let definition = Definition::Module(Box::new(ModuleDefinition::new(
|
|
131
|
+
name_id,
|
|
132
|
+
self.uri_id,
|
|
133
|
+
offset,
|
|
134
|
+
name_offset,
|
|
135
|
+
comments,
|
|
136
|
+
DefinitionFlags::empty(),
|
|
137
|
+
lexical_nesting_id,
|
|
138
|
+
)));
|
|
139
|
+
|
|
140
|
+
let definition_id = self.local_graph.add_definition(definition);
|
|
141
|
+
if let Some(id) = lexical_nesting_id {
|
|
142
|
+
self.add_member_to_current_lexical_scope(id, definition_id);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
self.nesting_stack.push(definition_id);
|
|
146
|
+
|
|
147
|
+
for member in module_node.members().iter() {
|
|
148
|
+
self.visit(&member);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
self.nesting_stack.pop();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[cfg(test)]
|
|
156
|
+
mod tests {
|
|
157
|
+
use crate::test_utils::LocalGraphTest;
|
|
158
|
+
use crate::{
|
|
159
|
+
assert_def_name_eq, assert_def_name_offset_eq, assert_definition_at, assert_local_diagnostics_eq,
|
|
160
|
+
assert_no_local_diagnostics,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
fn index_source(source: &str) -> LocalGraphTest {
|
|
164
|
+
LocalGraphTest::new_rbs("file:///foo.rbs", source)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#[test]
|
|
168
|
+
fn index_source_with_errors() {
|
|
169
|
+
let context = index_source("module");
|
|
170
|
+
|
|
171
|
+
assert_local_diagnostics_eq!(&context, ["parse-error: Failed to parse RBS document (1:1-1:1)"]);
|
|
172
|
+
|
|
173
|
+
assert!(context.graph().definitions().is_empty());
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
#[test]
|
|
177
|
+
fn index_module_node() {
|
|
178
|
+
let context = index_source({
|
|
179
|
+
"
|
|
180
|
+
module Foo
|
|
181
|
+
module Bar
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
"
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
assert_no_local_diagnostics!(&context);
|
|
188
|
+
assert_eq!(context.graph().definitions().len(), 2);
|
|
189
|
+
|
|
190
|
+
assert_definition_at!(&context, "1:1-4:4", Module, |def| {
|
|
191
|
+
assert_def_name_eq!(&context, def, "Foo");
|
|
192
|
+
assert_def_name_offset_eq!(&context, def, "1:8-1:11");
|
|
193
|
+
assert_eq!(1, def.members().len());
|
|
194
|
+
assert!(def.lexical_nesting_id().is_none());
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
assert_definition_at!(&context, "2:3-3:6", Module, |def| {
|
|
198
|
+
assert_def_name_eq!(&context, def, "Bar");
|
|
199
|
+
assert_def_name_offset_eq!(&context, def, "2:10-2:13");
|
|
200
|
+
|
|
201
|
+
assert_definition_at!(&context, "1:1-4:4", Module, |parent_nesting| {
|
|
202
|
+
assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
|
|
203
|
+
assert_eq!(parent_nesting.members()[0], def.id());
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#[test]
|
|
209
|
+
fn index_module_node_with_qualified_name() {
|
|
210
|
+
let context = index_source({
|
|
211
|
+
"
|
|
212
|
+
module Foo
|
|
213
|
+
module Bar::Baz
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
"
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
assert_no_local_diagnostics!(&context);
|
|
220
|
+
assert_eq!(context.graph().definitions().len(), 2);
|
|
221
|
+
|
|
222
|
+
assert_definition_at!(&context, "1:1-4:4", Module, |def| {
|
|
223
|
+
assert_def_name_eq!(&context, def, "Foo");
|
|
224
|
+
assert_def_name_offset_eq!(&context, def, "1:8-1:11");
|
|
225
|
+
assert_eq!(1, def.members().len());
|
|
226
|
+
assert!(def.lexical_nesting_id().is_none());
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
assert_definition_at!(&context, "2:3-3:6", Module, |def| {
|
|
230
|
+
assert_def_name_eq!(&context, def, "Bar::Baz");
|
|
231
|
+
assert_def_name_offset_eq!(&context, def, "2:15-2:18");
|
|
232
|
+
|
|
233
|
+
assert_definition_at!(&context, "1:1-4:4", Module, |parent_nesting| {
|
|
234
|
+
assert_eq!(parent_nesting.id(), def.lexical_nesting_id().unwrap());
|
|
235
|
+
assert_eq!(parent_nesting.members()[0], def.id());
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
}
|
|
29
239
|
}
|