rubydex 0.1.0.beta8 → 0.1.0.beta9
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/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/version.rb +1 -1
- data/rust/Cargo.toml +5 -0
- data/rust/rubydex/src/indexing/local_graph.rs +35 -0
- data/rust/rubydex/src/indexing/rbs_indexer.rs +240 -19
- data/rust/rubydex/src/indexing/ruby_indexer.rs +510 -124
- data/rust/rubydex/src/indexing.rs +6 -1
- data/rust/rubydex/src/job_queue.rs +23 -4
- data/rust/rubydex/src/model/definitions.rs +83 -45
- data/rust/rubydex/src/model/graph.rs +128 -12
- data/rust/rubydex/src/query.rs +7 -5
- data/rust/rubydex/src/resolution.rs +556 -146
- data/rust/rubydex/src/test_utils/graph_test.rs +80 -1
- data/rust/rubydex/src/test_utils/local_graph_test.rs +156 -1
- data/rust/rubydex-mcp/src/server.rs +675 -74
- data/rust/rubydex-mcp/src/tools.rs +9 -1
- data/rust/rubydex-mcp/tests/mcp.rs +7 -4
- 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: d9838707935ff868fb005a0d85254747ea6e3a5b5871c0626f5ec6641e0878e2
|
|
4
|
+
data.tar.gz: 87f4157545d244bfb3bb7e869914dc355d1d2b3dd0e181e439ce81ce1073cdc5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a69359f6261bb54eb0f576fbb9c31b85eb209c45fdb60d81d5f965abed05ac535409191b8a87376bcabe8278149ef1f87c8097162204d583f1ed2670bea7d5e
|
|
7
|
+
data.tar.gz: 862070c2cd67d83aae2da083987235017610d9637d6b90b49b8270a6ab8d3c4a1914333e30152f025f3e24e317fd3b3d0a74f3f20e64ffcf25752503c40baa7f
|
|
Binary file
|
data/lib/rubydex/version.rb
CHANGED
data/rust/Cargo.toml
CHANGED
|
@@ -3,6 +3,7 @@ use std::collections::hash_map::Entry;
|
|
|
3
3
|
use crate::diagnostic::{Diagnostic, Rule};
|
|
4
4
|
use crate::model::definitions::Definition;
|
|
5
5
|
use crate::model::document::Document;
|
|
6
|
+
use crate::model::graph::NameDependent;
|
|
6
7
|
use crate::model::identity_maps::IdentityHashMap;
|
|
7
8
|
use crate::model::ids::{DefinitionId, NameId, ReferenceId, StringId, UriId};
|
|
8
9
|
use crate::model::name::{Name, NameRef};
|
|
@@ -18,6 +19,7 @@ type LocalGraphParts = (
|
|
|
18
19
|
IdentityHashMap<NameId, NameRef>,
|
|
19
20
|
IdentityHashMap<ReferenceId, ConstantReference>,
|
|
20
21
|
IdentityHashMap<ReferenceId, MethodRef>,
|
|
22
|
+
IdentityHashMap<NameId, Vec<NameDependent>>,
|
|
21
23
|
);
|
|
22
24
|
|
|
23
25
|
#[derive(Debug)]
|
|
@@ -29,6 +31,7 @@ pub struct LocalGraph {
|
|
|
29
31
|
names: IdentityHashMap<NameId, NameRef>,
|
|
30
32
|
constant_references: IdentityHashMap<ReferenceId, ConstantReference>,
|
|
31
33
|
method_references: IdentityHashMap<ReferenceId, MethodRef>,
|
|
34
|
+
name_dependents: IdentityHashMap<NameId, Vec<NameDependent>>,
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
impl LocalGraph {
|
|
@@ -42,6 +45,7 @@ impl LocalGraph {
|
|
|
42
45
|
names: IdentityHashMap::default(),
|
|
43
46
|
constant_references: IdentityHashMap::default(),
|
|
44
47
|
method_references: IdentityHashMap::default(),
|
|
48
|
+
name_dependents: IdentityHashMap::default(),
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
51
|
|
|
@@ -70,6 +74,13 @@ impl LocalGraph {
|
|
|
70
74
|
pub fn add_definition(&mut self, definition: Definition) -> DefinitionId {
|
|
71
75
|
let definition_id = definition.id();
|
|
72
76
|
|
|
77
|
+
if let Some(name_id) = definition.name_id() {
|
|
78
|
+
self.name_dependents
|
|
79
|
+
.entry(*name_id)
|
|
80
|
+
.or_default()
|
|
81
|
+
.push(NameDependent::Definition(definition_id));
|
|
82
|
+
}
|
|
83
|
+
|
|
73
84
|
if self.definitions.insert(definition_id, definition).is_some() {
|
|
74
85
|
debug_assert!(false, "DefinitionId collision in local graph");
|
|
75
86
|
}
|
|
@@ -117,6 +128,18 @@ impl LocalGraph {
|
|
|
117
128
|
entry.get_mut().increment_ref_count(1);
|
|
118
129
|
}
|
|
119
130
|
Entry::Vacant(entry) => {
|
|
131
|
+
if let Some(&parent_scope) = name.parent_scope().as_ref() {
|
|
132
|
+
self.name_dependents
|
|
133
|
+
.entry(parent_scope)
|
|
134
|
+
.or_default()
|
|
135
|
+
.push(NameDependent::ChildName(name_id));
|
|
136
|
+
}
|
|
137
|
+
if let Some(&nesting_id) = name.nesting().as_ref() {
|
|
138
|
+
self.name_dependents
|
|
139
|
+
.entry(nesting_id)
|
|
140
|
+
.or_default()
|
|
141
|
+
.push(NameDependent::NestedName(name_id));
|
|
142
|
+
}
|
|
120
143
|
entry.insert(NameRef::Unresolved(Box::new(name)));
|
|
121
144
|
}
|
|
122
145
|
}
|
|
@@ -133,6 +156,10 @@ impl LocalGraph {
|
|
|
133
156
|
|
|
134
157
|
pub fn add_constant_reference(&mut self, reference: ConstantReference) -> ReferenceId {
|
|
135
158
|
let reference_id = reference.id();
|
|
159
|
+
self.name_dependents
|
|
160
|
+
.entry(*reference.name_id())
|
|
161
|
+
.or_default()
|
|
162
|
+
.push(NameDependent::Reference(reference_id));
|
|
136
163
|
|
|
137
164
|
if self.constant_references.insert(reference_id, reference).is_some() {
|
|
138
165
|
debug_assert!(false, "ReferenceId collision in local graph");
|
|
@@ -172,6 +199,13 @@ impl LocalGraph {
|
|
|
172
199
|
self.document.add_diagnostic(diagnostic);
|
|
173
200
|
}
|
|
174
201
|
|
|
202
|
+
// Name dependents
|
|
203
|
+
|
|
204
|
+
#[must_use]
|
|
205
|
+
pub fn name_dependents(&self) -> &IdentityHashMap<NameId, Vec<NameDependent>> {
|
|
206
|
+
&self.name_dependents
|
|
207
|
+
}
|
|
208
|
+
|
|
175
209
|
// Into parts
|
|
176
210
|
|
|
177
211
|
#[must_use]
|
|
@@ -184,6 +218,7 @@ impl LocalGraph {
|
|
|
184
218
|
self.names,
|
|
185
219
|
self.constant_references,
|
|
186
220
|
self.method_references,
|
|
221
|
+
self.name_dependents,
|
|
187
222
|
)
|
|
188
223
|
}
|
|
189
224
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//! Visit the RBS AST and create type definitions.
|
|
2
2
|
|
|
3
3
|
use ruby_rbs::node::{
|
|
4
|
-
self, ClassNode, CommentNode, ConstantNode, ExtendNode, GlobalNode, IncludeNode, ModuleNode, Node,
|
|
5
|
-
PrependNode, TypeNameNode, Visit,
|
|
4
|
+
self, AliasKind, ClassNode, CommentNode, ConstantNode, ExtendNode, GlobalNode, IncludeNode, ModuleNode, Node,
|
|
5
|
+
NodeList, PrependNode, TypeNameNode, Visit,
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
use crate::diagnostic::Rule;
|
|
@@ -10,7 +10,7 @@ use crate::indexing::local_graph::LocalGraph;
|
|
|
10
10
|
use crate::model::comment::Comment;
|
|
11
11
|
use crate::model::definitions::{
|
|
12
12
|
ClassDefinition, ConstantDefinition, Definition, DefinitionFlags, ExtendDefinition, GlobalVariableDefinition,
|
|
13
|
-
IncludeDefinition, Mixin, ModuleDefinition, PrependDefinition,
|
|
13
|
+
IncludeDefinition, MethodAliasDefinition, Mixin, ModuleDefinition, PrependDefinition, Receiver,
|
|
14
14
|
};
|
|
15
15
|
use crate::model::document::Document;
|
|
16
16
|
use crate::model::ids::{DefinitionId, NameId, ReferenceId, UriId};
|
|
@@ -147,14 +147,52 @@ impl<'a> RBSIndexer<'a> {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
#[allow(clippy::cast_possible_truncation)]
|
|
151
|
+
fn collect_comments(&self, comment_node: Option<CommentNode>) -> Box<[Comment]> {
|
|
152
|
+
let Some(comment_node) = comment_node else {
|
|
153
|
+
return Box::new([]);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
let location = comment_node.location();
|
|
157
|
+
let start = location.start().cast_unsigned() as usize;
|
|
158
|
+
let end = location.end().cast_unsigned() as usize;
|
|
159
|
+
|
|
160
|
+
let comment_block = &self.source[start..end];
|
|
161
|
+
let lines: Vec<&str> = comment_block.split('\n').collect();
|
|
162
|
+
|
|
163
|
+
let mut comments = Vec::with_capacity(lines.len());
|
|
164
|
+
let mut current_offset = start as u32;
|
|
165
|
+
|
|
166
|
+
for (i, line) in lines.iter().enumerate() {
|
|
167
|
+
let mut size = 1;
|
|
168
|
+
let mut line = *line;
|
|
169
|
+
|
|
170
|
+
if line.ends_with('\r') {
|
|
171
|
+
line = line.trim_end_matches('\r');
|
|
172
|
+
size += 1;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let line_indent = if i == 0 {
|
|
176
|
+
0
|
|
177
|
+
} else {
|
|
178
|
+
line.len() - line.trim_start().len()
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Skip past indentation to the comment text
|
|
182
|
+
current_offset += line_indent as u32;
|
|
183
|
+
|
|
184
|
+
let line_text = line[line_indent..].to_string();
|
|
185
|
+
let line_bytes = line_text.len() as u32;
|
|
186
|
+
let offset = Offset::new(current_offset, current_offset + line_bytes);
|
|
187
|
+
comments.push(Comment::new(offset, line_text));
|
|
188
|
+
|
|
189
|
+
// Advance past current line text + \r (if present) + \n for the next line
|
|
190
|
+
if i < lines.len() - 1 {
|
|
191
|
+
current_offset += line_bytes + size;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
comments.into_boxed_slice()
|
|
158
196
|
}
|
|
159
197
|
|
|
160
198
|
fn register_definition(
|
|
@@ -201,7 +239,7 @@ impl Visit for RBSIndexer<'_> {
|
|
|
201
239
|
let offset = Offset::from_rbs_location(&class_node.location());
|
|
202
240
|
let name_offset = Offset::from_rbs_location(&type_name.name().location());
|
|
203
241
|
|
|
204
|
-
let comments =
|
|
242
|
+
let comments = self.collect_comments(class_node.comment());
|
|
205
243
|
|
|
206
244
|
let superclass_ref = class_node.super_class().as_ref().map(|super_node| {
|
|
207
245
|
let type_name = super_node.name();
|
|
@@ -241,7 +279,7 @@ impl Visit for RBSIndexer<'_> {
|
|
|
241
279
|
let offset = Offset::from_rbs_location(&module_node.location());
|
|
242
280
|
let name_offset = Offset::from_rbs_location(&type_name.name().location());
|
|
243
281
|
|
|
244
|
-
let comments =
|
|
282
|
+
let comments = self.collect_comments(module_node.comment());
|
|
245
283
|
|
|
246
284
|
let definition = Definition::Module(Box::new(ModuleDefinition::new(
|
|
247
285
|
name_id,
|
|
@@ -271,7 +309,7 @@ impl Visit for RBSIndexer<'_> {
|
|
|
271
309
|
let name_id = self.index_type_name(&type_name, nesting_name_id);
|
|
272
310
|
let offset = Offset::from_rbs_location(&constant_node.location());
|
|
273
311
|
|
|
274
|
-
let comments =
|
|
312
|
+
let comments = self.collect_comments(constant_node.comment());
|
|
275
313
|
|
|
276
314
|
let definition = Definition::Constant(Box::new(ConstantDefinition::new(
|
|
277
315
|
name_id,
|
|
@@ -293,7 +331,7 @@ impl Visit for RBSIndexer<'_> {
|
|
|
293
331
|
.intern_string(Self::bytes_to_string(global_node.name().name()));
|
|
294
332
|
let offset = Offset::from_rbs_location(&global_node.location());
|
|
295
333
|
|
|
296
|
-
let comments =
|
|
334
|
+
let comments = self.collect_comments(global_node.comment());
|
|
297
335
|
|
|
298
336
|
let definition = Definition::GlobalVariable(Box::new(GlobalVariableDefinition::new(
|
|
299
337
|
str_id,
|
|
@@ -324,6 +362,37 @@ impl Visit for RBSIndexer<'_> {
|
|
|
324
362
|
Mixin::Extend(ExtendDefinition::new(ref_id))
|
|
325
363
|
});
|
|
326
364
|
}
|
|
365
|
+
|
|
366
|
+
fn visit_alias_node(&mut self, alias_node: &node::AliasNode) {
|
|
367
|
+
let lexical_nesting_id = self.parent_lexical_scope_id();
|
|
368
|
+
|
|
369
|
+
let receiver = match alias_node.kind() {
|
|
370
|
+
AliasKind::Instance => None,
|
|
371
|
+
AliasKind::Singleton => lexical_nesting_id.map(Receiver::SelfReceiver),
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
let new_name = Self::bytes_to_string(alias_node.new_name().name());
|
|
375
|
+
let old_name = Self::bytes_to_string(alias_node.old_name().name());
|
|
376
|
+
|
|
377
|
+
let new_name_str_id = self.local_graph.intern_string(format!("{new_name}()"));
|
|
378
|
+
let old_name_str_id = self.local_graph.intern_string(format!("{old_name}()"));
|
|
379
|
+
|
|
380
|
+
let offset = Offset::from_rbs_location(&alias_node.location());
|
|
381
|
+
let comments = self.collect_comments(alias_node.comment());
|
|
382
|
+
|
|
383
|
+
let definition = Definition::MethodAlias(Box::new(MethodAliasDefinition::new(
|
|
384
|
+
new_name_str_id,
|
|
385
|
+
old_name_str_id,
|
|
386
|
+
self.uri_id,
|
|
387
|
+
offset,
|
|
388
|
+
comments,
|
|
389
|
+
Self::flags(&alias_node.annotations()),
|
|
390
|
+
lexical_nesting_id,
|
|
391
|
+
receiver,
|
|
392
|
+
)));
|
|
393
|
+
|
|
394
|
+
self.register_definition(definition, lexical_nesting_id);
|
|
395
|
+
}
|
|
327
396
|
}
|
|
328
397
|
|
|
329
398
|
#[cfg(test)]
|
|
@@ -331,11 +400,12 @@ mod tests {
|
|
|
331
400
|
use ruby_rbs::node::{self, Node, NodeList};
|
|
332
401
|
|
|
333
402
|
use crate::indexing::rbs_indexer::RBSIndexer;
|
|
334
|
-
use crate::model::definitions::DefinitionFlags;
|
|
403
|
+
use crate::model::definitions::{Definition, DefinitionFlags};
|
|
335
404
|
use crate::test_utils::LocalGraphTest;
|
|
336
405
|
use crate::{
|
|
337
406
|
assert_def_comments_eq, assert_def_mixins_eq, assert_def_name_eq, assert_def_name_offset_eq, assert_def_str_eq,
|
|
338
|
-
assert_def_superclass_ref_eq, assert_definition_at, assert_local_diagnostics_eq,
|
|
407
|
+
assert_def_superclass_ref_eq, assert_definition_at, assert_local_diagnostics_eq, assert_method_has_receiver,
|
|
408
|
+
assert_no_local_diagnostics, assert_string_eq,
|
|
339
409
|
};
|
|
340
410
|
|
|
341
411
|
fn index_source(source: &str) -> LocalGraphTest {
|
|
@@ -526,7 +596,7 @@ mod tests {
|
|
|
526
596
|
|
|
527
597
|
assert_definition_at!(&context, "2:1-2:12", Constant, |def| {
|
|
528
598
|
assert_def_name_eq!(&context, def, "FOO");
|
|
529
|
-
assert_def_comments_eq!(&context, def, ["Some documentation
|
|
599
|
+
assert_def_comments_eq!(&context, def, ["# Some documentation"]);
|
|
530
600
|
});
|
|
531
601
|
}
|
|
532
602
|
|
|
@@ -551,7 +621,7 @@ mod tests {
|
|
|
551
621
|
|
|
552
622
|
assert_definition_at!(&context, "4:1-4:14", GlobalVariable, |def| {
|
|
553
623
|
assert_def_str_eq!(&context, def, "$bar");
|
|
554
|
-
assert_def_comments_eq!(&context, def, ["A global variable
|
|
624
|
+
assert_def_comments_eq!(&context, def, ["# A global variable"]);
|
|
555
625
|
});
|
|
556
626
|
}
|
|
557
627
|
|
|
@@ -714,4 +784,155 @@ mod tests {
|
|
|
714
784
|
assert!(def.flags().contains(DefinitionFlags::DEPRECATED));
|
|
715
785
|
});
|
|
716
786
|
}
|
|
787
|
+
|
|
788
|
+
#[test]
|
|
789
|
+
fn index_alias_node() {
|
|
790
|
+
let context = index_source({
|
|
791
|
+
"
|
|
792
|
+
class Foo
|
|
793
|
+
# Some documentation
|
|
794
|
+
alias bar baz
|
|
795
|
+
end
|
|
796
|
+
"
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
assert_no_local_diagnostics!(&context);
|
|
800
|
+
|
|
801
|
+
assert_definition_at!(&context, "1:1-4:4", Class, |class_def| {
|
|
802
|
+
assert_eq!(1, class_def.members().len());
|
|
803
|
+
|
|
804
|
+
assert_definition_at!(&context, "3:3-3:16", MethodAlias, |def| {
|
|
805
|
+
assert_string_eq!(&context, def.new_name_str_id(), "bar()");
|
|
806
|
+
assert_string_eq!(&context, def.old_name_str_id(), "baz()");
|
|
807
|
+
assert_def_comments_eq!(&context, def, ["# Some documentation"]);
|
|
808
|
+
assert_eq!(class_def.id(), def.lexical_nesting_id().unwrap());
|
|
809
|
+
});
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
#[test]
|
|
814
|
+
fn index_alias_node_with_deprecation() {
|
|
815
|
+
let context = index_source({
|
|
816
|
+
"
|
|
817
|
+
class Foo
|
|
818
|
+
%a{deprecated}
|
|
819
|
+
alias bar baz
|
|
820
|
+
end
|
|
821
|
+
"
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
assert_no_local_diagnostics!(&context);
|
|
825
|
+
|
|
826
|
+
assert_definition_at!(&context, "3:3-3:16", MethodAlias, |def| {
|
|
827
|
+
assert!(def.flags().contains(DefinitionFlags::DEPRECATED));
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
#[test]
|
|
832
|
+
fn index_alias_node_singleton() {
|
|
833
|
+
let context = index_source({
|
|
834
|
+
"
|
|
835
|
+
class Foo
|
|
836
|
+
alias self.bar self.baz
|
|
837
|
+
end
|
|
838
|
+
"
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
assert_no_local_diagnostics!(&context);
|
|
842
|
+
assert_eq!(context.graph().definitions().len(), 2);
|
|
843
|
+
|
|
844
|
+
assert_definition_at!(&context, "2:3-2:26", MethodAlias, |def| {
|
|
845
|
+
assert_string_eq!(&context, def.new_name_str_id(), "bar()");
|
|
846
|
+
assert_string_eq!(&context, def.old_name_str_id(), "baz()");
|
|
847
|
+
assert_method_has_receiver!(&context, def, "Foo");
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
#[test]
|
|
852
|
+
fn mixed_singleton_instance_alias_is_not_indexed() {
|
|
853
|
+
// Mixed aliases (`alias self.x y` and `alias x self.y`) are not valid RBS.
|
|
854
|
+
// Verify that no alias definitions are produced for these inputs.
|
|
855
|
+
for source in [
|
|
856
|
+
"
|
|
857
|
+
class Foo
|
|
858
|
+
alias self.bar baz
|
|
859
|
+
end
|
|
860
|
+
",
|
|
861
|
+
"
|
|
862
|
+
class Foo
|
|
863
|
+
alias bar self.baz
|
|
864
|
+
end
|
|
865
|
+
",
|
|
866
|
+
] {
|
|
867
|
+
let context = index_source(source);
|
|
868
|
+
let has_alias = context
|
|
869
|
+
.graph()
|
|
870
|
+
.definitions()
|
|
871
|
+
.values()
|
|
872
|
+
.any(|d| matches!(d, Definition::MethodAlias(_)));
|
|
873
|
+
assert!(!has_alias, "Expected no alias definitions for: {source}");
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
#[test]
|
|
878
|
+
fn split_multiline_comments() {
|
|
879
|
+
let context = index_source({
|
|
880
|
+
"
|
|
881
|
+
# First line
|
|
882
|
+
# Second line
|
|
883
|
+
# Third line
|
|
884
|
+
class Foo
|
|
885
|
+
# A comment for Bar
|
|
886
|
+
# Another line for Bar
|
|
887
|
+
# One more line for Bar
|
|
888
|
+
module Bar
|
|
889
|
+
end
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# splits strings at the \\n char
|
|
893
|
+
BAZ: Integer
|
|
894
|
+
"
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
assert_no_local_diagnostics!(&context);
|
|
898
|
+
|
|
899
|
+
assert_definition_at!(&context, "4:1-10:4", Class, |def| {
|
|
900
|
+
assert_def_name_eq!(&context, def, "Foo");
|
|
901
|
+
assert_def_comments_eq!(&context, def, ["# First line", "# Second line", "# Third line"]);
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
assert_definition_at!(&context, "8:3-9:6", Module, |def| {
|
|
905
|
+
assert_def_name_eq!(&context, def, "Bar");
|
|
906
|
+
assert_def_comments_eq!(
|
|
907
|
+
&context,
|
|
908
|
+
def,
|
|
909
|
+
[
|
|
910
|
+
"# A comment for Bar",
|
|
911
|
+
"# Another line for Bar",
|
|
912
|
+
"# One more line for Bar"
|
|
913
|
+
]
|
|
914
|
+
);
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
assert_definition_at!(&context, "13:1-13:13", Constant, |def| {
|
|
918
|
+
assert_def_name_eq!(&context, def, "BAZ");
|
|
919
|
+
assert_def_comments_eq!(&context, def, ["# splits strings at the \\n char"]);
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
#[test]
|
|
924
|
+
fn split_multiline_comments_crlf() {
|
|
925
|
+
// Build the indexer directly to bypass normalize_indentation, which strips \r
|
|
926
|
+
let source = "# First line\r\n# Second line\r\nclass Foo\r\nend\r\n";
|
|
927
|
+
let mut indexer = RBSIndexer::new("file:///foo.rbs".to_string(), source);
|
|
928
|
+
indexer.index();
|
|
929
|
+
let context = LocalGraphTest::from_local_graph("file:///foo.rbs", indexer.local_graph());
|
|
930
|
+
|
|
931
|
+
assert_no_local_diagnostics!(&context);
|
|
932
|
+
|
|
933
|
+
assert_definition_at!(&context, "3:1-4:4", Class, |def| {
|
|
934
|
+
assert_def_name_eq!(&context, def, "Foo");
|
|
935
|
+
assert_def_comments_eq!(&context, def, ["# First line", "# Second line"]);
|
|
936
|
+
});
|
|
937
|
+
}
|
|
717
938
|
}
|