rubydex 0.2.9 → 0.3.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 +69 -3
- data/THIRD_PARTY_LICENSES.html +34 -1
- data/exe/rdx +131 -55
- data/ext/rubydex/declaration.c +1 -1
- data/ext/rubydex/definition.c +32 -4
- data/ext/rubydex/graph.c +14 -3
- data/ext/rubydex/query.c +105 -0
- data/ext/rubydex/query.h +8 -0
- data/ext/rubydex/reference.c +60 -0
- data/ext/rubydex/rubydex.c +2 -0
- data/ext/rubydex/utils.c +12 -0
- data/ext/rubydex/utils.h +5 -0
- data/lib/rubydex/version.rb +1 -1
- data/rbi/rubydex.rbi +22 -0
- data/rust/Cargo.lock +7 -0
- data/rust/rubydex/Cargo.toml +1 -0
- data/rust/rubydex/benches/graph_memory.rs +22 -4
- data/rust/rubydex/src/compile_assertions.rs +15 -0
- data/rust/rubydex/src/diagnostic.rs +1 -1
- data/rust/rubydex/src/indexing/rbs_indexer.rs +14 -2
- data/rust/rubydex/src/indexing/ruby_indexer.rs +49 -58
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +72 -16
- data/rust/rubydex/src/main.rs +2 -124
- data/rust/rubydex/src/model/declaration.rs +0 -11
- data/rust/rubydex/src/model/definitions.rs +27 -26
- data/rust/rubydex/src/model/document.rs +43 -7
- data/rust/rubydex/src/model/graph.rs +40 -28
- data/rust/rubydex/src/model/id.rs +55 -0
- data/rust/rubydex/src/model/ids.rs +21 -9
- data/rust/rubydex/src/model/name.rs +35 -7
- data/rust/rubydex/src/model/references.rs +16 -13
- data/rust/rubydex/src/operation/ruby_builder.rs +48 -59
- data/rust/rubydex/src/query/cypher/schema.rs +790 -0
- data/rust/rubydex/src/query/cypher/schema_info.rs +161 -0
- data/rust/rubydex/src/query/cypher/tests.rs +228 -0
- data/rust/rubydex/src/query/cypher.rs +57 -0
- data/rust/rubydex/src/query.rs +2 -0
- data/rust/rubydex/src/resolution.rs +248 -227
- data/rust/rubydex/src/resolution_tests.rs +263 -65
- data/rust/rubydex-sys/src/declaration_api.rs +6 -3
- data/rust/rubydex-sys/src/definition_api.rs +27 -7
- data/rust/rubydex-sys/src/graph_api.rs +158 -14
- data/rust/rubydex-sys/src/reference_api.rs +58 -12
- metadata +8 -2
|
@@ -2,7 +2,10 @@ use std::fmt::Display;
|
|
|
2
2
|
|
|
3
3
|
use crate::{
|
|
4
4
|
assert_mem_size,
|
|
5
|
-
model::
|
|
5
|
+
model::{
|
|
6
|
+
id::id_from_parts,
|
|
7
|
+
ids::{DeclarationId, NameId, StringId},
|
|
8
|
+
},
|
|
6
9
|
};
|
|
7
10
|
|
|
8
11
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
@@ -127,12 +130,19 @@ impl Name {
|
|
|
127
130
|
|
|
128
131
|
#[must_use]
|
|
129
132
|
pub fn id(&self) -> NameId {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
// We need to include both the variant and the bytes of the parent scope when present
|
|
134
|
+
let (parent_tag, parent_id): (u8, u64) = match self.parent_scope {
|
|
135
|
+
ParentScope::None => (0, 0),
|
|
136
|
+
ParentScope::TopLevel => (1, 0),
|
|
137
|
+
ParentScope::Some(id) => (2, id.get()),
|
|
138
|
+
ParentScope::Attached(id) => (3, id.get()),
|
|
139
|
+
};
|
|
140
|
+
let (nesting_tag, nesting_id): (u8, u64) = match self.nesting {
|
|
141
|
+
None => (0, 0),
|
|
142
|
+
Some(id) => (1, id.get()),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
id_from_parts!(NameId; self.str.get(), parent_tag, parent_id, nesting_tag, nesting_id)
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
148
|
|
|
@@ -297,4 +307,22 @@ mod tests {
|
|
|
297
307
|
);
|
|
298
308
|
assert_eq!(name_7.id(), name_8.id());
|
|
299
309
|
}
|
|
310
|
+
|
|
311
|
+
#[test]
|
|
312
|
+
fn parent_scope_variants_are_distinct() {
|
|
313
|
+
let inner = Name::new(StringId::from("Foo"), ParentScope::None, None).id();
|
|
314
|
+
|
|
315
|
+
let ids = [
|
|
316
|
+
Name::new(StringId::from("Foo"), ParentScope::None, None).id(),
|
|
317
|
+
Name::new(StringId::from("Foo"), ParentScope::TopLevel, None).id(),
|
|
318
|
+
Name::new(StringId::from("Foo"), ParentScope::Some(inner), None).id(),
|
|
319
|
+
Name::new(StringId::from("Foo"), ParentScope::Attached(inner), None).id(),
|
|
320
|
+
];
|
|
321
|
+
|
|
322
|
+
for (i, a) in ids.iter().enumerate() {
|
|
323
|
+
for b in &ids[i + 1..] {
|
|
324
|
+
assert_ne!(a, b);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
300
328
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
assert_mem_size,
|
|
3
|
-
model::
|
|
3
|
+
model::{
|
|
4
|
+
id::id_from_parts,
|
|
5
|
+
ids::{ConstantReferenceId, MethodReferenceId, NameId, StringId, UriId},
|
|
6
|
+
},
|
|
4
7
|
offset::Offset,
|
|
5
8
|
};
|
|
6
9
|
|
|
@@ -43,13 +46,13 @@ impl ConstantReference {
|
|
|
43
46
|
|
|
44
47
|
#[must_use]
|
|
45
48
|
pub fn id(&self) -> ConstantReferenceId {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
self.name_id,
|
|
49
|
-
self.uri_id,
|
|
49
|
+
id_from_parts!(
|
|
50
|
+
ConstantReferenceId;
|
|
51
|
+
self.name_id.get(),
|
|
52
|
+
self.uri_id.get(),
|
|
50
53
|
self.offset.start(),
|
|
51
|
-
self.offset.end()
|
|
52
|
-
)
|
|
54
|
+
self.offset.end(),
|
|
55
|
+
)
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -100,12 +103,12 @@ impl MethodRef {
|
|
|
100
103
|
|
|
101
104
|
#[must_use]
|
|
102
105
|
pub fn id(&self) -> MethodReferenceId {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
self.str,
|
|
106
|
-
self.uri_id,
|
|
106
|
+
id_from_parts!(
|
|
107
|
+
MethodReferenceId;
|
|
108
|
+
self.str.get(),
|
|
109
|
+
self.uri_id.get(),
|
|
107
110
|
self.offset.start(),
|
|
108
|
-
self.offset.end()
|
|
109
|
-
)
|
|
111
|
+
self.offset.end(),
|
|
112
|
+
)
|
|
110
113
|
}
|
|
111
114
|
}
|
|
@@ -611,20 +611,8 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
611
611
|
{
|
|
612
612
|
if let Some(arguments) = node.arguments() {
|
|
613
613
|
for argument in &arguments.arguments() {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
let symbol = argument.as_symbol_node().unwrap();
|
|
617
|
-
if let Some(value_loc) = symbol.value_loc() {
|
|
618
|
-
let name = Self::location_to_string(&value_loc);
|
|
619
|
-
f(name, value_loc);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
623
|
-
let string = argument.as_string_node().unwrap();
|
|
624
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
625
|
-
f(name, argument.location());
|
|
626
|
-
}
|
|
627
|
-
_ => {}
|
|
614
|
+
if let Some((name, location)) = Self::extract_literal_name(&argument) {
|
|
615
|
+
f(name, location);
|
|
628
616
|
}
|
|
629
617
|
}
|
|
630
618
|
}
|
|
@@ -899,28 +887,29 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
899
887
|
|
|
900
888
|
fn handle_constant_visibility(&mut self, node: &ruby_prism::CallNode, visibility: Visibility) {
|
|
901
889
|
let receiver = node.receiver();
|
|
890
|
+
let call_name = String::from_utf8_lossy(node.name().as_slice());
|
|
902
891
|
|
|
903
|
-
let receiver_name_id = match receiver {
|
|
892
|
+
let receiver_name_id = match &receiver {
|
|
904
893
|
Some(ruby_prism::Node::ConstantPathNode { .. } | ruby_prism::Node::ConstantReadNode { .. }) => {
|
|
905
|
-
self.index_constant_reference(
|
|
894
|
+
self.index_constant_reference(receiver.as_ref().unwrap(), true)
|
|
906
895
|
}
|
|
907
896
|
Some(ruby_prism::Node::SelfNode { .. }) | None => match self.nesting_stack.last() {
|
|
908
897
|
Some(Nesting::Method { .. }) => return,
|
|
909
898
|
None => {
|
|
910
899
|
self.add_diagnostic(
|
|
911
|
-
Rule::
|
|
900
|
+
Rule::InvalidConstantVisibility,
|
|
912
901
|
Offset::from_prism_location(&node.location()),
|
|
913
|
-
"
|
|
902
|
+
format!("`{call_name}` called at top level"),
|
|
914
903
|
);
|
|
915
904
|
return;
|
|
916
905
|
}
|
|
917
906
|
_ => None,
|
|
918
907
|
},
|
|
919
|
-
|
|
908
|
+
Some(other) => {
|
|
920
909
|
self.add_diagnostic(
|
|
921
|
-
Rule::
|
|
922
|
-
Offset::from_prism_location(&
|
|
923
|
-
"Dynamic receiver for
|
|
910
|
+
Rule::InvalidConstantVisibility,
|
|
911
|
+
Offset::from_prism_location(&other.location()),
|
|
912
|
+
format!("Dynamic receiver for `{call_name}`"),
|
|
924
913
|
);
|
|
925
914
|
return;
|
|
926
915
|
}
|
|
@@ -931,28 +920,13 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
931
920
|
};
|
|
932
921
|
|
|
933
922
|
for argument in &arguments.arguments() {
|
|
934
|
-
let (name, location) =
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
944
|
-
let string = argument.as_string_node().unwrap();
|
|
945
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
946
|
-
(name, argument.location())
|
|
947
|
-
}
|
|
948
|
-
_ => {
|
|
949
|
-
self.add_diagnostic(
|
|
950
|
-
Rule::InvalidPrivateConstant,
|
|
951
|
-
Offset::from_prism_location(&argument.location()),
|
|
952
|
-
"Private constant called with non-symbol argument".to_string(),
|
|
953
|
-
);
|
|
954
|
-
continue;
|
|
955
|
-
}
|
|
923
|
+
let Some((name, location)) = Self::extract_literal_name(&argument) else {
|
|
924
|
+
self.add_diagnostic(
|
|
925
|
+
Rule::InvalidConstantVisibility,
|
|
926
|
+
Offset::from_prism_location(&argument.location()),
|
|
927
|
+
format!("`{call_name}` called with a non-literal argument"),
|
|
928
|
+
);
|
|
929
|
+
continue;
|
|
956
930
|
};
|
|
957
931
|
|
|
958
932
|
let str_id = self.intern_string(name);
|
|
@@ -1067,6 +1041,22 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
1067
1041
|
Some(())
|
|
1068
1042
|
}
|
|
1069
1043
|
|
|
1044
|
+
fn extract_literal_name<'b>(arg: &ruby_prism::Node<'b>) -> Option<(String, ruby_prism::Location<'b>)> {
|
|
1045
|
+
match arg {
|
|
1046
|
+
ruby_prism::Node::SymbolNode { .. } => {
|
|
1047
|
+
let symbol = arg.as_symbol_node().unwrap();
|
|
1048
|
+
let value_loc = symbol.value_loc()?;
|
|
1049
|
+
Some((Self::location_to_string(&value_loc), value_loc))
|
|
1050
|
+
}
|
|
1051
|
+
ruby_prism::Node::StringNode { .. } => {
|
|
1052
|
+
let string = arg.as_string_node().unwrap();
|
|
1053
|
+
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
1054
|
+
Some((name, arg.location()))
|
|
1055
|
+
}
|
|
1056
|
+
_ => None,
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1070
1060
|
fn is_attr_call(arg: &ruby_prism::Node) -> bool {
|
|
1071
1061
|
arg.as_call_node().is_some_and(|call| {
|
|
1072
1062
|
let receiver = call.receiver();
|
|
@@ -1116,6 +1106,18 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
1116
1106
|
ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. }
|
|
1117
1107
|
) {
|
|
1118
1108
|
self.create_method_visibility_operation(&arg, visibility, DefinitionFlags::empty());
|
|
1109
|
+
if visibility == Visibility::ModuleFunction {
|
|
1110
|
+
// `module_function` also creates a public singleton method, so we emit a
|
|
1111
|
+
// second def for the singleton side. The two defs stay separate (rather than
|
|
1112
|
+
// shared) so reverse-lookup invalidation can detach `Foo#bar` and
|
|
1113
|
+
// `Foo::<Foo>#bar` independently. The `SINGLETON_METHOD_VISIBILITY` flag
|
|
1114
|
+
// routes this one to the singleton class.
|
|
1115
|
+
self.create_method_visibility_operation(
|
|
1116
|
+
&arg,
|
|
1117
|
+
visibility,
|
|
1118
|
+
DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1119
1121
|
} else {
|
|
1120
1122
|
let arg_offset = Offset::from_prism_location(&arg.location());
|
|
1121
1123
|
let message = if Self::is_attr_call(&arg) {
|
|
@@ -1135,21 +1137,8 @@ impl<'a> RubyOperationBuilder<'a> {
|
|
|
1135
1137
|
visibility: Visibility,
|
|
1136
1138
|
flags: DefinitionFlags,
|
|
1137
1139
|
) {
|
|
1138
|
-
let (name, location) =
|
|
1139
|
-
|
|
1140
|
-
let symbol = arg.as_symbol_node().unwrap();
|
|
1141
|
-
if let Some(value_loc) = symbol.value_loc() {
|
|
1142
|
-
(Self::location_to_string(&value_loc), value_loc)
|
|
1143
|
-
} else {
|
|
1144
|
-
return;
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
ruby_prism::Node::StringNode { .. } => {
|
|
1148
|
-
let string = arg.as_string_node().unwrap();
|
|
1149
|
-
let name = String::from_utf8_lossy(string.unescaped()).to_string();
|
|
1150
|
-
(name, arg.location())
|
|
1151
|
-
}
|
|
1152
|
-
_ => return,
|
|
1140
|
+
let Some((name, location)) = Self::extract_literal_name(arg) else {
|
|
1141
|
+
return;
|
|
1153
1142
|
};
|
|
1154
1143
|
|
|
1155
1144
|
let str_id = self.intern_string(format!("{name}()"));
|