rubydex 0.3.0 → 0.4.0
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 +45 -7
- data/THIRD_PARTY_LICENSES.html +238 -2
- data/exe/rdx +2 -149
- data/ext/rubydex/config.c +140 -0
- data/ext/rubydex/config.h +16 -0
- data/ext/rubydex/diagnostic.c +75 -1
- data/ext/rubydex/diagnostic.h +2 -0
- data/ext/rubydex/graph.c +13 -45
- data/ext/rubydex/graph.h +6 -0
- data/ext/rubydex/query.c +398 -16
- data/ext/rubydex/rubydex.c +2 -0
- data/ext/rubydex/utils.c +11 -4
- data/lib/ruby_lsp/rubydex/addon.rb +211 -0
- data/lib/rubydex/cli/command/console.rb +55 -0
- data/lib/rubydex/cli/command/lint/explain.rb +74 -0
- data/lib/rubydex/cli/command/lint.rb +202 -0
- data/lib/rubydex/cli/command/mcp.rb +30 -0
- data/lib/rubydex/cli/command/query.rb +70 -0
- data/lib/rubydex/cli/command/skill.rb +69 -0
- data/lib/rubydex/cli/command.rb +168 -0
- data/lib/rubydex/cli.rb +93 -0
- data/lib/rubydex/config.rb +59 -0
- data/lib/rubydex/diagnostic.rb +12 -3
- data/lib/rubydex/errors.rb +42 -1
- data/lib/rubydex/graph.rb +10 -3
- data/lib/rubydex/linter/custom_rule.rb +97 -0
- data/lib/rubydex/linter/helpers/path_helpers.rb +78 -0
- data/lib/rubydex/linter/helpers/source_access_helpers.rb +31 -0
- data/lib/rubydex/linter/rule_loader.rb +36 -0
- data/lib/rubydex/linter/rule_test_case.rb +343 -0
- data/lib/rubydex/linter/runner.rb +56 -0
- data/lib/rubydex/linter.rb +19 -0
- data/lib/rubydex/location.rb +3 -0
- data/lib/rubydex/mcp_server.rb +1 -2
- data/lib/rubydex/related_information.rb +17 -0
- data/lib/rubydex/rule.rb +33 -0
- data/lib/rubydex/severity.rb +70 -0
- data/lib/rubydex/skill.rb +88 -0
- data/lib/rubydex/skill_registry.rb +62 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +6 -0
- data/lib/rubydex_linter/rules/rule_structure.rb +125 -0
- data/rbi/rubydex.rbi +558 -17
- data/rust/Cargo.lock +2 -2
- data/rust/rubydex/Cargo.toml +1 -1
- data/rust/rubydex/benches/graph_memory.rs +3 -5
- data/rust/rubydex/src/config.rs +538 -157
- data/rust/rubydex/src/diagnostic.rs +66 -40
- data/rust/rubydex/src/errors.rs +0 -1
- data/rust/rubydex/src/indexing/local_graph.rs +6 -5
- data/rust/rubydex/src/indexing/rbs_indexer.rs +270 -6
- data/rust/rubydex/src/indexing/ruby_indexer.rs +10 -12
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +134 -81
- data/rust/rubydex/src/lib.rs +1 -0
- data/rust/rubydex/src/listing.rs +26 -1
- data/rust/rubydex/src/main.rs +7 -4
- data/rust/rubydex/src/model/declaration.rs +302 -219
- data/rust/rubydex/src/model/graph.rs +27 -40
- data/rust/rubydex/src/model/name.rs +58 -17
- data/rust/rubydex/src/operation/ruby_builder.rs +30 -45
- data/rust/rubydex/src/path_helpers.rs +77 -0
- data/rust/rubydex/src/query/cypher/schema.rs +63 -0
- data/rust/rubydex/src/query/cypher/tests.rs +26 -1
- data/rust/rubydex/src/query/cypher.rs +8 -11
- data/rust/rubydex/src/query.rs +123 -43
- data/rust/rubydex/src/resolution.rs +139 -187
- data/rust/rubydex/src/resolution_tests.rs +247 -19
- data/rust/rubydex/src/test_utils/context.rs +2 -1
- data/rust/rubydex/src/test_utils/graph_test.rs +26 -12
- data/rust/rubydex/src/test_utils/local_graph_test.rs +19 -0
- data/rust/rubydex/tests/cli.rs +4 -4
- data/rust/rubydex-sys/src/config_api.rs +205 -0
- data/rust/rubydex-sys/src/cypher_api.rs +791 -0
- data/rust/rubydex-sys/src/diagnostic_api.rs +77 -8
- data/rust/rubydex-sys/src/graph_api.rs +13 -194
- data/rust/rubydex-sys/src/lib.rs +2 -0
- data/rust/rubydex-sys/src/name_api.rs +2 -6
- data/rust/rubydex-sys/src/utils.rs +37 -0
- data/skills/send-private-method/SKILL.md +133 -0
- metadata +31 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#[cfg(any(test, feature = "test_utils"))]
|
|
2
2
|
use crate::model::document::Document;
|
|
3
|
-
use crate::{model::ids::UriId, offset::Offset};
|
|
3
|
+
use crate::{assert_mem_size, model::ids::UriId, offset::Offset};
|
|
4
4
|
|
|
5
5
|
#[derive(Debug)]
|
|
6
6
|
pub struct Diagnostic {
|
|
@@ -9,6 +9,7 @@ pub struct Diagnostic {
|
|
|
9
9
|
offset: Offset,
|
|
10
10
|
message: String,
|
|
11
11
|
}
|
|
12
|
+
assert_mem_size!(Diagnostic, 48);
|
|
12
13
|
|
|
13
14
|
impl Diagnostic {
|
|
14
15
|
#[must_use]
|
|
@@ -53,60 +54,85 @@ impl Diagnostic {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
for lc in ch.to_lowercase() {
|
|
64
|
-
snake.push(lc);
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
snake.push(ch);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
snake
|
|
57
|
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Deserialize)]
|
|
58
|
+
#[serde(rename_all = "lowercase")]
|
|
59
|
+
pub enum Severity {
|
|
60
|
+
Error,
|
|
61
|
+
Warning,
|
|
62
|
+
Information,
|
|
63
|
+
Hint,
|
|
71
64
|
}
|
|
72
65
|
|
|
73
66
|
macro_rules! rules {
|
|
74
|
-
(
|
|
75
|
-
$( $variant:ident );* $(;)?
|
|
76
|
-
) => {
|
|
67
|
+
($($(#[$attribute:meta])* $rule:ident),+ $(,)?) => {
|
|
77
68
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
78
69
|
pub enum Rule {
|
|
79
|
-
$(
|
|
80
|
-
$variant,
|
|
81
|
-
)*
|
|
70
|
+
$($(#[$attribute])* $rule,)+
|
|
82
71
|
}
|
|
83
72
|
|
|
84
|
-
impl
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
Rule::$variant => camel_to_snake(stringify!($variant)),
|
|
89
|
-
)*
|
|
90
|
-
})
|
|
73
|
+
impl Rule {
|
|
74
|
+
#[must_use]
|
|
75
|
+
pub fn all() -> &'static [Self] {
|
|
76
|
+
&[$(Self::$rule,)+]
|
|
91
77
|
}
|
|
92
78
|
}
|
|
93
|
-
}
|
|
79
|
+
};
|
|
94
80
|
}
|
|
95
81
|
|
|
96
82
|
rules! {
|
|
97
83
|
// Parsing
|
|
98
|
-
ParseError
|
|
99
|
-
ParseWarning
|
|
84
|
+
ParseError,
|
|
85
|
+
ParseWarning,
|
|
100
86
|
|
|
101
87
|
// Indexing
|
|
102
|
-
DynamicConstantReference
|
|
103
|
-
DynamicSingletonDefinition
|
|
104
|
-
DynamicAncestor
|
|
105
|
-
TopLevelMixinSelf
|
|
106
|
-
InvalidConstantVisibility
|
|
107
|
-
InvalidMethodVisibility
|
|
88
|
+
DynamicConstantReference,
|
|
89
|
+
DynamicSingletonDefinition,
|
|
90
|
+
DynamicAncestor,
|
|
91
|
+
TopLevelMixinSelf,
|
|
92
|
+
InvalidConstantVisibility,
|
|
93
|
+
InvalidMethodVisibility,
|
|
108
94
|
|
|
109
95
|
// Resolution
|
|
110
|
-
UndefinedMethodVisibilityTarget
|
|
111
|
-
UndefinedConstantVisibilityTarget
|
|
96
|
+
UndefinedMethodVisibilityTarget,
|
|
97
|
+
UndefinedConstantVisibilityTarget,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
impl Rule {
|
|
101
|
+
#[must_use]
|
|
102
|
+
pub fn name(&self) -> &'static str {
|
|
103
|
+
match self {
|
|
104
|
+
Self::ParseError => "ParseError",
|
|
105
|
+
Self::ParseWarning => "ParseWarning",
|
|
106
|
+
Self::DynamicConstantReference => "DynamicConstantReference",
|
|
107
|
+
Self::DynamicSingletonDefinition => "DynamicSingletonDefinition",
|
|
108
|
+
Self::DynamicAncestor => "DynamicAncestor",
|
|
109
|
+
Self::TopLevelMixinSelf => "TopLevelMixinSelf",
|
|
110
|
+
Self::InvalidConstantVisibility => "InvalidConstantVisibility",
|
|
111
|
+
Self::InvalidMethodVisibility => "InvalidMethodVisibility",
|
|
112
|
+
Self::UndefinedMethodVisibilityTarget => "UndefinedMethodVisibilityTarget",
|
|
113
|
+
Self::UndefinedConstantVisibilityTarget => "UndefinedConstantVisibilityTarget",
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#[must_use]
|
|
118
|
+
pub fn default_severity(&self) -> Severity {
|
|
119
|
+
match self {
|
|
120
|
+
Self::ParseError => Severity::Error,
|
|
121
|
+
Self::ParseWarning
|
|
122
|
+
| Self::InvalidConstantVisibility
|
|
123
|
+
| Self::InvalidMethodVisibility
|
|
124
|
+
| Self::UndefinedMethodVisibilityTarget
|
|
125
|
+
| Self::UndefinedConstantVisibilityTarget => Severity::Warning,
|
|
126
|
+
Self::DynamicConstantReference
|
|
127
|
+
| Self::DynamicSingletonDefinition
|
|
128
|
+
| Self::DynamicAncestor
|
|
129
|
+
| Self::TopLevelMixinSelf => Severity::Information,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
impl std::fmt::Display for Rule {
|
|
135
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
136
|
+
write!(f, "{}", self.name())
|
|
137
|
+
}
|
|
112
138
|
}
|
data/rust/rubydex/src/errors.rs
CHANGED
|
@@ -6,7 +6,7 @@ use crate::model::document::Document;
|
|
|
6
6
|
use crate::model::graph::NameDependent;
|
|
7
7
|
use crate::model::identity_maps::IdentityHashMap;
|
|
8
8
|
use crate::model::ids::{ConstantReferenceId, DefinitionId, MethodReferenceId, NameId, StringId, UriId};
|
|
9
|
-
use crate::model::name::{Name, NameRef};
|
|
9
|
+
use crate::model::name::{Name, NameRef, ParentScope};
|
|
10
10
|
use crate::model::references::{ConstantReference, MethodRef};
|
|
11
11
|
use crate::model::string_ref::StringRef;
|
|
12
12
|
use crate::offset::Offset;
|
|
@@ -119,7 +119,8 @@ impl LocalGraph {
|
|
|
119
119
|
&self.names
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
pub fn add_name(&mut self,
|
|
122
|
+
pub fn add_name(&mut self, str: StringId, parent_scope: ParentScope, nesting: Option<NameId>) -> NameId {
|
|
123
|
+
let name = Name::new(&self.names, str, parent_scope, nesting);
|
|
123
124
|
let name_id = name.id();
|
|
124
125
|
|
|
125
126
|
match self.names.entry(name_id) {
|
|
@@ -128,13 +129,13 @@ impl LocalGraph {
|
|
|
128
129
|
entry.get_mut().increment_ref_count(1);
|
|
129
130
|
}
|
|
130
131
|
Entry::Vacant(entry) => {
|
|
131
|
-
if let Some(&
|
|
132
|
+
if let Some(&parent_scope_id) = parent_scope.as_ref() {
|
|
132
133
|
self.name_dependents
|
|
133
|
-
.entry(
|
|
134
|
+
.entry(parent_scope_id)
|
|
134
135
|
.or_default()
|
|
135
136
|
.push(NameDependent::ChildName(name_id));
|
|
136
137
|
}
|
|
137
|
-
if let Some(
|
|
138
|
+
if let Some(nesting_id) = nesting {
|
|
138
139
|
self.name_dependents
|
|
139
140
|
.entry(nesting_id)
|
|
140
141
|
.or_default()
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
use core::panic;
|
|
4
4
|
|
|
5
5
|
use ruby_rbs::node::{
|
|
6
|
-
self, AliasKind,
|
|
7
|
-
|
|
6
|
+
self, AliasKind, AttrAccessorNode, AttrReaderNode, AttrWriterNode, AttributeKind, AttributeVisibility, ClassNode,
|
|
7
|
+
CommentNode, ConstantNode, ExtendNode, FunctionTypeNode, GlobalNode, IncludeNode, ModuleNode, Node, NodeList,
|
|
8
|
+
PrependNode, TypeNameNode, Visit,
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
use crate::diagnostic::Rule;
|
|
@@ -17,7 +18,7 @@ use crate::model::definitions::{
|
|
|
17
18
|
};
|
|
18
19
|
use crate::model::document::Document;
|
|
19
20
|
use crate::model::ids::{ConstantReferenceId, DefinitionId, NameId, StringId, UriId};
|
|
20
|
-
use crate::model::name::
|
|
21
|
+
use crate::model::name::ParentScope;
|
|
21
22
|
use crate::model::references::ConstantReference;
|
|
22
23
|
use crate::model::visibility::Visibility;
|
|
23
24
|
use crate::offset::Offset;
|
|
@@ -102,8 +103,7 @@ impl<'a> RBSIndexer<'a> {
|
|
|
102
103
|
nesting_name_id: Option<NameId>,
|
|
103
104
|
) -> NameId {
|
|
104
105
|
let string_id = self.local_graph.intern_string(symbol.as_str().to_owned());
|
|
105
|
-
self.local_graph
|
|
106
|
-
.add_name(Name::new(string_id, parent_scope, nesting_name_id))
|
|
106
|
+
self.local_graph.add_name(string_id, parent_scope, nesting_name_id)
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
fn parent_lexical_scope_id(&self) -> Option<DefinitionId> {
|
|
@@ -223,6 +223,133 @@ impl<'a> RBSIndexer<'a> {
|
|
|
223
223
|
definition_id
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
#[allow(clippy::too_many_arguments)]
|
|
227
|
+
fn register_attribute_methods(
|
|
228
|
+
&mut self,
|
|
229
|
+
name: &str,
|
|
230
|
+
offset: Offset,
|
|
231
|
+
name_offset: Offset,
|
|
232
|
+
comments: Box<[Comment]>,
|
|
233
|
+
flags: DefinitionFlags,
|
|
234
|
+
lexical_nesting_id: Option<DefinitionId>,
|
|
235
|
+
kind: AttributeKind,
|
|
236
|
+
attribute_visibility: AttributeVisibility,
|
|
237
|
+
reader: bool,
|
|
238
|
+
writer: bool,
|
|
239
|
+
) {
|
|
240
|
+
let (visibility, receiver) = match kind {
|
|
241
|
+
AttributeKind::Instance => {
|
|
242
|
+
let visibility = match attribute_visibility {
|
|
243
|
+
AttributeVisibility::Public => Visibility::Public,
|
|
244
|
+
AttributeVisibility::Private => Visibility::Private,
|
|
245
|
+
AttributeVisibility::Unspecified => self.current_visibility,
|
|
246
|
+
};
|
|
247
|
+
(visibility, None)
|
|
248
|
+
}
|
|
249
|
+
AttributeKind::Singleton => {
|
|
250
|
+
let visibility = match attribute_visibility {
|
|
251
|
+
AttributeVisibility::Private => Visibility::Private,
|
|
252
|
+
AttributeVisibility::Public | AttributeVisibility::Unspecified => Visibility::Public,
|
|
253
|
+
};
|
|
254
|
+
(
|
|
255
|
+
visibility,
|
|
256
|
+
Some(Receiver::SelfReceiver(
|
|
257
|
+
lexical_nesting_id.expect("Singleton attribute must have a lexical enclosing scope"),
|
|
258
|
+
)),
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
match (reader, writer) {
|
|
264
|
+
(true, true) => {
|
|
265
|
+
self.register_attribute_method(
|
|
266
|
+
name,
|
|
267
|
+
false,
|
|
268
|
+
offset.clone(),
|
|
269
|
+
name_offset.clone(),
|
|
270
|
+
comments.clone(),
|
|
271
|
+
flags.clone(),
|
|
272
|
+
lexical_nesting_id,
|
|
273
|
+
visibility,
|
|
274
|
+
receiver.clone(),
|
|
275
|
+
);
|
|
276
|
+
self.register_attribute_method(
|
|
277
|
+
name,
|
|
278
|
+
true,
|
|
279
|
+
offset,
|
|
280
|
+
name_offset,
|
|
281
|
+
comments,
|
|
282
|
+
flags,
|
|
283
|
+
lexical_nesting_id,
|
|
284
|
+
visibility,
|
|
285
|
+
receiver,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
(true, false) => self.register_attribute_method(
|
|
289
|
+
name,
|
|
290
|
+
false,
|
|
291
|
+
offset,
|
|
292
|
+
name_offset,
|
|
293
|
+
comments,
|
|
294
|
+
flags,
|
|
295
|
+
lexical_nesting_id,
|
|
296
|
+
visibility,
|
|
297
|
+
receiver,
|
|
298
|
+
),
|
|
299
|
+
(false, true) => self.register_attribute_method(
|
|
300
|
+
name,
|
|
301
|
+
true,
|
|
302
|
+
offset,
|
|
303
|
+
name_offset,
|
|
304
|
+
comments,
|
|
305
|
+
flags,
|
|
306
|
+
lexical_nesting_id,
|
|
307
|
+
visibility,
|
|
308
|
+
receiver,
|
|
309
|
+
),
|
|
310
|
+
(false, false) => unreachable!("attribute must have a reader or writer"),
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
#[allow(clippy::too_many_arguments)]
|
|
315
|
+
fn register_attribute_method(
|
|
316
|
+
&mut self,
|
|
317
|
+
name: &str,
|
|
318
|
+
writer: bool,
|
|
319
|
+
offset: Offset,
|
|
320
|
+
name_offset: Offset,
|
|
321
|
+
comments: Box<[Comment]>,
|
|
322
|
+
flags: DefinitionFlags,
|
|
323
|
+
lexical_nesting_id: Option<DefinitionId>,
|
|
324
|
+
visibility: Visibility,
|
|
325
|
+
receiver: Option<Receiver>,
|
|
326
|
+
) {
|
|
327
|
+
let str_id = self
|
|
328
|
+
.local_graph
|
|
329
|
+
.intern_string(format!("{name}{}()", if writer { "=" } else { "" }));
|
|
330
|
+
let signatures = if writer {
|
|
331
|
+
let parameter_name = self.local_graph.intern_string(name.to_owned());
|
|
332
|
+
let parameter = Parameter::RequiredPositional(ParameterStruct::new(name_offset.clone(), parameter_name));
|
|
333
|
+
Signatures::Simple(vec![parameter].into_boxed_slice())
|
|
334
|
+
} else {
|
|
335
|
+
Signatures::Simple(Box::new([]))
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
let definition = Definition::Method(Box::new(MethodDefinition::new(
|
|
339
|
+
str_id,
|
|
340
|
+
self.uri_id,
|
|
341
|
+
offset,
|
|
342
|
+
name_offset,
|
|
343
|
+
comments,
|
|
344
|
+
flags,
|
|
345
|
+
lexical_nesting_id,
|
|
346
|
+
signatures,
|
|
347
|
+
visibility,
|
|
348
|
+
receiver,
|
|
349
|
+
)));
|
|
350
|
+
self.register_definition(definition, lexical_nesting_id);
|
|
351
|
+
}
|
|
352
|
+
|
|
226
353
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
|
227
354
|
fn source_at(&self, location: &node::RBSLocationRange) -> String {
|
|
228
355
|
let start = location.start() as usize;
|
|
@@ -574,6 +701,51 @@ impl Visit for RBSIndexer<'_> {
|
|
|
574
701
|
self.register_definition(definition, lexical_nesting_id);
|
|
575
702
|
}
|
|
576
703
|
|
|
704
|
+
fn visit_attr_reader_node(&mut self, attribute_node: &AttrReaderNode) {
|
|
705
|
+
self.register_attribute_methods(
|
|
706
|
+
attribute_node.name().as_str(),
|
|
707
|
+
Offset::from_rbs_location(&attribute_node.location()),
|
|
708
|
+
Offset::from_rbs_location(&attribute_node.name_location()),
|
|
709
|
+
self.collect_comments(attribute_node.comment()),
|
|
710
|
+
Self::flags(&attribute_node.annotations()),
|
|
711
|
+
self.parent_lexical_scope_id(),
|
|
712
|
+
attribute_node.kind(),
|
|
713
|
+
attribute_node.visibility(),
|
|
714
|
+
true,
|
|
715
|
+
false,
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
fn visit_attr_writer_node(&mut self, attribute_node: &AttrWriterNode) {
|
|
720
|
+
self.register_attribute_methods(
|
|
721
|
+
attribute_node.name().as_str(),
|
|
722
|
+
Offset::from_rbs_location(&attribute_node.location()),
|
|
723
|
+
Offset::from_rbs_location(&attribute_node.name_location()),
|
|
724
|
+
self.collect_comments(attribute_node.comment()),
|
|
725
|
+
Self::flags(&attribute_node.annotations()),
|
|
726
|
+
self.parent_lexical_scope_id(),
|
|
727
|
+
attribute_node.kind(),
|
|
728
|
+
attribute_node.visibility(),
|
|
729
|
+
false,
|
|
730
|
+
true,
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
fn visit_attr_accessor_node(&mut self, attribute_node: &AttrAccessorNode) {
|
|
735
|
+
self.register_attribute_methods(
|
|
736
|
+
attribute_node.name().as_str(),
|
|
737
|
+
Offset::from_rbs_location(&attribute_node.location()),
|
|
738
|
+
Offset::from_rbs_location(&attribute_node.name_location()),
|
|
739
|
+
self.collect_comments(attribute_node.comment()),
|
|
740
|
+
Self::flags(&attribute_node.annotations()),
|
|
741
|
+
self.parent_lexical_scope_id(),
|
|
742
|
+
attribute_node.kind(),
|
|
743
|
+
attribute_node.visibility(),
|
|
744
|
+
true,
|
|
745
|
+
true,
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
577
749
|
fn visit_method_definition_node(&mut self, def_node: &node::MethodDefinitionNode) {
|
|
578
750
|
let str_id = self.local_graph.intern_string(format!("{}()", def_node.name()));
|
|
579
751
|
let offset = Offset::from_rbs_location(&def_node.location());
|
|
@@ -651,6 +823,7 @@ impl Visit for RBSIndexer<'_> {
|
|
|
651
823
|
mod tests {
|
|
652
824
|
use ruby_rbs::node::{self, Node, NodeList};
|
|
653
825
|
|
|
826
|
+
use crate::diagnostic::Severity;
|
|
654
827
|
use crate::indexing::rbs_indexer::RBSIndexer;
|
|
655
828
|
use crate::model::definitions::{Definition, DefinitionFlags, Parameter, Signatures};
|
|
656
829
|
use crate::model::visibility::Visibility;
|
|
@@ -682,7 +855,11 @@ mod tests {
|
|
|
682
855
|
fn index_source_with_errors() {
|
|
683
856
|
let context = index_source("module");
|
|
684
857
|
|
|
685
|
-
assert_local_diagnostics_eq!(
|
|
858
|
+
assert_local_diagnostics_eq!(
|
|
859
|
+
&context,
|
|
860
|
+
["ParseError: Failed to parse RBS document (1:1-1:1)"],
|
|
861
|
+
severity: Severity::Error
|
|
862
|
+
);
|
|
686
863
|
|
|
687
864
|
assert!(context.graph().definitions().is_empty());
|
|
688
865
|
}
|
|
@@ -1051,6 +1228,93 @@ mod tests {
|
|
|
1051
1228
|
});
|
|
1052
1229
|
}
|
|
1053
1230
|
|
|
1231
|
+
#[test]
|
|
1232
|
+
fn indexes_attribute_members_as_methods_without_retaining_types_or_instance_variables() {
|
|
1233
|
+
let context = index_source({
|
|
1234
|
+
"
|
|
1235
|
+
class Foo
|
|
1236
|
+
# Reader documentation
|
|
1237
|
+
%a{deprecated}
|
|
1238
|
+
attr_reader inferred: Integer
|
|
1239
|
+
attr_reader absent(): Symbol
|
|
1240
|
+
attr_writer explicit (@writer): String
|
|
1241
|
+
attr_accessor accessor: bool
|
|
1242
|
+
private
|
|
1243
|
+
attr_reader inherited_visibility: Float
|
|
1244
|
+
public
|
|
1245
|
+
private attr_accessor self.class_value (@class_value): bool
|
|
1246
|
+
end
|
|
1247
|
+
"
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
assert_no_local_diagnostics!(&context);
|
|
1251
|
+
assert_eq!(context.graph().definitions().len(), 9);
|
|
1252
|
+
|
|
1253
|
+
let method = |name: &str| {
|
|
1254
|
+
context
|
|
1255
|
+
.graph()
|
|
1256
|
+
.definitions()
|
|
1257
|
+
.values()
|
|
1258
|
+
.find_map(|definition| match definition {
|
|
1259
|
+
Definition::Method(method)
|
|
1260
|
+
if context
|
|
1261
|
+
.graph()
|
|
1262
|
+
.strings()
|
|
1263
|
+
.get(method.str_id())
|
|
1264
|
+
.is_some_and(|string| string.as_str() == name) =>
|
|
1265
|
+
{
|
|
1266
|
+
Some(method)
|
|
1267
|
+
}
|
|
1268
|
+
_ => None,
|
|
1269
|
+
})
|
|
1270
|
+
.unwrap_or_else(|| panic!("expected `{name}` method definition"))
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
for name in [
|
|
1274
|
+
"inferred()",
|
|
1275
|
+
"absent()",
|
|
1276
|
+
"explicit=()",
|
|
1277
|
+
"accessor()",
|
|
1278
|
+
"accessor=()",
|
|
1279
|
+
"inherited_visibility()",
|
|
1280
|
+
"class_value()",
|
|
1281
|
+
"class_value=()",
|
|
1282
|
+
] {
|
|
1283
|
+
assert_eq!(method(name).signatures().as_slice().len(), 1);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
for name in [
|
|
1287
|
+
"inferred()",
|
|
1288
|
+
"absent()",
|
|
1289
|
+
"accessor()",
|
|
1290
|
+
"inherited_visibility()",
|
|
1291
|
+
"class_value()",
|
|
1292
|
+
] {
|
|
1293
|
+
assert!(method(name).signatures().as_slice()[0].is_empty());
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
for (name, parameter_name) in [
|
|
1297
|
+
("explicit=()", "explicit"),
|
|
1298
|
+
("accessor=()", "accessor"),
|
|
1299
|
+
("class_value=()", "class_value"),
|
|
1300
|
+
] {
|
|
1301
|
+
let signature = &method(name).signatures().as_slice()[0];
|
|
1302
|
+
let [Parameter::RequiredPositional(parameter)] = signature.as_ref() else {
|
|
1303
|
+
panic!("expected `{name}` to have one required positional parameter");
|
|
1304
|
+
};
|
|
1305
|
+
assert_string_eq!(&context, parameter.str(), parameter_name);
|
|
1306
|
+
assert_offset_string!(&context, parameter.offset(), parameter_name);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
assert_eq!(method("class_value()").visibility(), &Visibility::Private);
|
|
1310
|
+
assert_eq!(method("class_value=()").visibility(), &Visibility::Private);
|
|
1311
|
+
assert_eq!(method("inherited_visibility()").visibility(), &Visibility::Private);
|
|
1312
|
+
assert_method_has_receiver!(&context, method("class_value()"), "Foo");
|
|
1313
|
+
assert_method_has_receiver!(&context, method("class_value=()"), "Foo");
|
|
1314
|
+
assert_def_comments_eq!(&context, method("inferred()"), ["# Reader documentation"]);
|
|
1315
|
+
assert!(method("inferred()").flags().contains(DefinitionFlags::DEPRECATED));
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1054
1318
|
#[test]
|
|
1055
1319
|
fn index_alias_node() {
|
|
1056
1320
|
let context = index_source({
|
|
@@ -12,7 +12,7 @@ use crate::model::definitions::{
|
|
|
12
12
|
};
|
|
13
13
|
use crate::model::document::Document;
|
|
14
14
|
use crate::model::ids::{DefinitionId, NameId, StringId, UriId};
|
|
15
|
-
use crate::model::name::
|
|
15
|
+
use crate::model::name::ParentScope;
|
|
16
16
|
use crate::model::references::{ConstantReference, MethodRef};
|
|
17
17
|
use crate::model::visibility::Visibility;
|
|
18
18
|
use crate::offset::Offset;
|
|
@@ -482,11 +482,9 @@ impl<'a> RubyIndexer<'a> {
|
|
|
482
482
|
let offset = Offset::from_prism_location(&location);
|
|
483
483
|
let name = Self::location_to_string(&location);
|
|
484
484
|
let string_id = self.local_graph.intern_string(name);
|
|
485
|
-
let name_id = self
|
|
486
|
-
|
|
487
|
-
parent_scope_id,
|
|
488
|
-
self.current_lexical_scope_name_id(),
|
|
489
|
-
));
|
|
485
|
+
let name_id = self
|
|
486
|
+
.local_graph
|
|
487
|
+
.add_name(string_id, parent_scope_id, self.current_lexical_scope_name_id());
|
|
490
488
|
|
|
491
489
|
if push_final_reference {
|
|
492
490
|
self.local_graph
|
|
@@ -687,7 +685,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
687
685
|
.intern_string(format!("{}:{}<anonymous>", self.uri_id, offset.start()));
|
|
688
686
|
|
|
689
687
|
(
|
|
690
|
-
Some(self.local_graph.add_name(
|
|
688
|
+
Some(self.local_graph.add_name(string_id, ParentScope::None, None)),
|
|
691
689
|
offset.clone(),
|
|
692
690
|
)
|
|
693
691
|
};
|
|
@@ -748,7 +746,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
748
746
|
.intern_string(format!("{}:{}<anonymous>", self.uri_id, offset.start()));
|
|
749
747
|
|
|
750
748
|
(
|
|
751
|
-
Some(self.local_graph.add_name(
|
|
749
|
+
Some(self.local_graph.add_name(string_id, ParentScope::None, None)),
|
|
752
750
|
offset.clone(),
|
|
753
751
|
)
|
|
754
752
|
};
|
|
@@ -969,7 +967,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
969
967
|
}
|
|
970
968
|
|
|
971
969
|
Some((
|
|
972
|
-
self.
|
|
970
|
+
self.current_owner_name_id().unwrap(),
|
|
973
971
|
Offset::from_prism_location(&arg.location()),
|
|
974
972
|
))
|
|
975
973
|
} else if let Some(name_id) = self.index_constant_reference(&arg, false) {
|
|
@@ -1125,7 +1123,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1125
1123
|
}
|
|
1126
1124
|
None => {
|
|
1127
1125
|
let str_id = self.local_graph.intern_string("Object".into());
|
|
1128
|
-
Some(self.local_graph.add_name(
|
|
1126
|
+
Some(self.local_graph.add_name(str_id, ParentScope::None, None))
|
|
1129
1127
|
}
|
|
1130
1128
|
}
|
|
1131
1129
|
}
|
|
@@ -1169,7 +1167,7 @@ impl<'a> RubyIndexer<'a> {
|
|
|
1169
1167
|
let string_id = self.local_graph.intern_string(singleton_class_name);
|
|
1170
1168
|
let new_name_id = self
|
|
1171
1169
|
.local_graph
|
|
1172
|
-
.add_name(
|
|
1170
|
+
.add_name(string_id, ParentScope::Attached(name_id), None);
|
|
1173
1171
|
|
|
1174
1172
|
let location = receiver.map_or(fallback_location, ruby_prism::Node::location);
|
|
1175
1173
|
let offset = Offset::from_prism_location(&location);
|
|
@@ -1650,7 +1648,7 @@ impl Visit<'_> for RubyIndexer<'_> {
|
|
|
1650
1648
|
let nesting = self.current_lexical_scope_name_id();
|
|
1651
1649
|
let name_id = self
|
|
1652
1650
|
.local_graph
|
|
1653
|
-
.add_name(
|
|
1651
|
+
.add_name(string_id, ParentScope::Attached(attached_target), nesting);
|
|
1654
1652
|
|
|
1655
1653
|
let definition = Definition::SingletonClass(Box::new(SingletonClassDefinition::new(
|
|
1656
1654
|
name_id,
|