rubydex 0.1.0.beta10 → 0.1.0.beta11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13a3cb3d4cbe536ab21b25d16a2ec0903b600dd2ffe90b062657c38cefc3dfbd
4
- data.tar.gz: 43664af48f34fe8ca7cf006cc5a77548fad873df329b5f45c344aea0f34fff14
3
+ metadata.gz: d26e66bf7f1eac1c1bffa154b2a5e2c0621ce59883ae0367202cc82b6f85e64d
4
+ data.tar.gz: 3ea90f481e9717834e2be5e2a7dc1140810f842e738132496c211b5a19b6837b
5
5
  SHA512:
6
- metadata.gz: 3e8f31a47de5aa62df61a57c9545a3b93155617e96fb4064ef95201c38c43949b524688e3ad8204471240dacc62f0f2e34b02fd49e2257fd181b1b9d69b0924a
7
- data.tar.gz: c7ebeb6983652dfd86591054a954ee1ecb3b5bc55c00a43581014344c337f46e5ccc5b6539fe50e9861bd30ef7e88ba596e7734570575ed3dee3d3437c707519
6
+ metadata.gz: 24f8c2aa31a6d1ad76dd76486d005f3ee1e9143e0624b91db920c33e39da5b1bf248c431d0efc97996019f24f02ed8673912d4731509fcaaa59b1075c84378f9
7
+ data.tar.gz: 22b831aa47e08e9f3be4390054b645376e3e6d6974eeb2071e7e76499e1f9f056cdf0f0091eb1c28604047c2f0acea68a8e8f15a41ce939fa3acba13956e791f
@@ -13,6 +13,7 @@ VALUE cSingletonClassDefinition;
13
13
  VALUE cModuleDefinition;
14
14
  VALUE cConstantDefinition;
15
15
  VALUE cConstantAliasDefinition;
16
+ VALUE cConstantVisibilityDefinition;
16
17
  VALUE cMethodDefinition;
17
18
  VALUE cAttrAccessorDefinition;
18
19
  VALUE cAttrReaderDefinition;
@@ -36,6 +37,8 @@ VALUE rdxi_definition_class_for_kind(DefinitionKind kind) {
36
37
  return cConstantDefinition;
37
38
  case DefinitionKind_ConstantAlias:
38
39
  return cConstantAliasDefinition;
40
+ case DefinitionKind_ConstantVisibility:
41
+ return cConstantVisibilityDefinition;
39
42
  case DefinitionKind_Method:
40
43
  return cMethodDefinition;
41
44
  case DefinitionKind_AttrAccessor:
@@ -181,6 +184,7 @@ void rdxi_initialize_definition(VALUE mod) {
181
184
  cModuleDefinition = rb_define_class_under(mRubydex, "ModuleDefinition", cDefinition);
182
185
  cConstantDefinition = rb_define_class_under(mRubydex, "ConstantDefinition", cDefinition);
183
186
  cConstantAliasDefinition = rb_define_class_under(mRubydex, "ConstantAliasDefinition", cDefinition);
187
+ cConstantVisibilityDefinition = rb_define_class_under(mRubydex, "ConstantVisibilityDefinition", cDefinition);
184
188
  cMethodDefinition = rb_define_class_under(mRubydex, "MethodDefinition", cDefinition);
185
189
  cAttrAccessorDefinition = rb_define_class_under(mRubydex, "AttrAccessorDefinition", cDefinition);
186
190
  cAttrReaderDefinition = rb_define_class_under(mRubydex, "AttrReaderDefinition", cDefinition);
Binary file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubydex
4
- VERSION = "0.1.0.beta10"
4
+ VERSION = "0.1.0.beta11"
5
5
  end
@@ -103,6 +103,7 @@ rules! {
103
103
  DynamicSingletonDefinition;
104
104
  DynamicAncestor;
105
105
  TopLevelMixinSelf;
106
+ InvalidPrivateConstant;
106
107
 
107
108
  // Resolution
108
109
  }
@@ -5,10 +5,10 @@ use crate::indexing::local_graph::LocalGraph;
5
5
  use crate::model::comment::Comment;
6
6
  use crate::model::definitions::{
7
7
  AttrAccessorDefinition, AttrReaderDefinition, AttrWriterDefinition, ClassDefinition, ClassVariableDefinition,
8
- ConstantAliasDefinition, ConstantDefinition, Definition, DefinitionFlags, ExtendDefinition,
9
- GlobalVariableAliasDefinition, GlobalVariableDefinition, IncludeDefinition, InstanceVariableDefinition,
10
- MethodAliasDefinition, MethodDefinition, Mixin, ModuleDefinition, Parameter, ParameterStruct, PrependDefinition,
11
- Receiver, Signatures, SingletonClassDefinition,
8
+ ConstantAliasDefinition, ConstantDefinition, ConstantVisibilityDefinition, Definition, DefinitionFlags,
9
+ ExtendDefinition, GlobalVariableAliasDefinition, GlobalVariableDefinition, IncludeDefinition,
10
+ InstanceVariableDefinition, MethodAliasDefinition, MethodDefinition, Mixin, ModuleDefinition, Parameter,
11
+ ParameterStruct, PrependDefinition, Receiver, Signatures, SingletonClassDefinition,
12
12
  };
13
13
  use crate::model::document::Document;
14
14
  use crate::model::ids::{DefinitionId, NameId, StringId, UriId};
@@ -1164,6 +1164,94 @@ impl<'a> RubyIndexer<'a> {
1164
1164
  .add_constant_reference(ConstantReference::new(new_name_id, self.uri_id, offset));
1165
1165
  Some(new_name_id)
1166
1166
  }
1167
+
1168
+ fn handle_constant_visibility(&mut self, node: &ruby_prism::CallNode, visibility: Visibility) {
1169
+ let receiver = node.receiver();
1170
+
1171
+ let receiver_name_id = match receiver {
1172
+ Some(ruby_prism::Node::ConstantPathNode { .. } | ruby_prism::Node::ConstantReadNode { .. }) => {
1173
+ self.index_constant_reference(&receiver.unwrap(), true)
1174
+ }
1175
+ Some(ruby_prism::Node::SelfNode { .. }) | None => match self.nesting_stack.last() {
1176
+ Some(Nesting::Method(_)) => {
1177
+ // Dynamic private constant (called from a method), we ignore it but don't report an error since it's valid Ruby
1178
+ // if being called from a singleton method.
1179
+
1180
+ return;
1181
+ }
1182
+ None => {
1183
+ self.local_graph.add_diagnostic(
1184
+ Rule::InvalidPrivateConstant,
1185
+ Offset::from_prism_location(&node.location()),
1186
+ "Private constant called at top level".to_string(),
1187
+ );
1188
+
1189
+ return;
1190
+ }
1191
+ _ => None,
1192
+ },
1193
+ _ => {
1194
+ self.local_graph.add_diagnostic(
1195
+ Rule::InvalidPrivateConstant,
1196
+ Offset::from_prism_location(&node.location()),
1197
+ "Dynamic receiver for private constant".to_string(),
1198
+ );
1199
+
1200
+ return;
1201
+ }
1202
+ };
1203
+
1204
+ let Some(arguments) = node.arguments() else {
1205
+ return;
1206
+ };
1207
+
1208
+ for argument in &arguments.arguments() {
1209
+ let (name, location) = match argument {
1210
+ ruby_prism::Node::SymbolNode { .. } => {
1211
+ let symbol = argument.as_symbol_node().unwrap();
1212
+ if let Some(value_loc) = symbol.value_loc() {
1213
+ (Self::location_to_string(&value_loc), value_loc)
1214
+ } else {
1215
+ continue;
1216
+ }
1217
+ }
1218
+ ruby_prism::Node::StringNode { .. } => {
1219
+ let string = argument.as_string_node().unwrap();
1220
+ let name = String::from_utf8_lossy(string.unescaped()).to_string();
1221
+ (name, argument.location())
1222
+ }
1223
+ _ => {
1224
+ self.local_graph.add_diagnostic(
1225
+ Rule::InvalidPrivateConstant,
1226
+ Offset::from_prism_location(&argument.location()),
1227
+ "Private constant called with non-symbol argument".to_string(),
1228
+ );
1229
+
1230
+ return;
1231
+ }
1232
+ };
1233
+
1234
+ let str_id = self.local_graph.intern_string(name);
1235
+ let offset = Offset::from_prism_location(&location);
1236
+ let definition = Definition::ConstantVisibility(Box::new(ConstantVisibilityDefinition::new(
1237
+ self.local_graph.add_name(Name::new(
1238
+ str_id,
1239
+ receiver_name_id.map_or(ParentScope::None, ParentScope::Some),
1240
+ self.current_lexical_scope_name_id(),
1241
+ )),
1242
+ visibility,
1243
+ self.uri_id,
1244
+ offset,
1245
+ Vec::new(),
1246
+ DefinitionFlags::empty(),
1247
+ self.current_nesting_definition_id(),
1248
+ )));
1249
+
1250
+ let definition_id = self.local_graph.add_definition(definition);
1251
+
1252
+ self.add_member_to_current_owner(definition_id);
1253
+ }
1254
+ }
1167
1255
  }
1168
1256
 
1169
1257
  struct CommentGroup {
@@ -1845,6 +1933,12 @@ impl Visit<'_> for RubyIndexer<'_> {
1845
1933
 
1846
1934
  self.index_method_reference_for_call(node);
1847
1935
  }
1936
+ "private_constant" => {
1937
+ self.handle_constant_visibility(node, Visibility::Private);
1938
+ }
1939
+ "public_constant" => {
1940
+ self.handle_constant_visibility(node, Visibility::Public);
1941
+ }
1848
1942
  _ => {
1849
1943
  // For method calls that we don't explicitly handle each part, we continue visiting their parts as we
1850
1944
  // may discover something inside
@@ -2229,22 +2323,35 @@ mod tests {
2229
2323
  }};
2230
2324
  }
2231
2325
 
2232
- /// Asserts that a method reference has the expected receiver.
2326
+ /// Asserts that exactly one method reference with the given name has the expected receiver.
2233
2327
  ///
2234
- /// Finds a `MethodRef` by name and checks its receiver's string representation.
2328
+ /// Panics if there isn't exactly one `MethodRef` with that name.
2235
2329
  ///
2236
2330
  /// Usage:
2237
2331
  /// - `assert_method_ref_receiver!(context, "bar", "<Foo>")`
2238
2332
  macro_rules! assert_method_ref_receiver {
2239
2333
  ($context:expr, $method_name:expr, $expected_receiver:expr) => {{
2240
- let method_ref = $context
2334
+ let target = StringId::from($method_name);
2335
+ let matches: Vec<_> = $context
2241
2336
  .graph()
2242
2337
  .method_references()
2243
2338
  .values()
2244
- .find(|method_ref| *method_ref.str() == StringId::from($method_name))
2245
- .unwrap_or_else(|| panic!("should have a method reference for {}", $method_name));
2339
+ .filter(|method_ref| *method_ref.str() == target)
2340
+ .collect();
2341
+
2342
+ assert_eq!(
2343
+ matches.len(),
2344
+ 1,
2345
+ "expected exactly one method reference for `{}`, found {}",
2346
+ $method_name,
2347
+ matches.len()
2348
+ );
2246
2349
 
2247
- let receiver = $context.graph().names().get(&method_ref.receiver().unwrap()).unwrap();
2350
+ let method_ref = matches[0];
2351
+ let receiver_id = method_ref
2352
+ .receiver()
2353
+ .unwrap_or_else(|| panic!("method reference for `{}` has no receiver", $method_name));
2354
+ let receiver = $context.graph().names().get(&receiver_id).unwrap();
2248
2355
 
2249
2356
  assert_eq!(
2250
2357
  StringId::from($expected_receiver),
@@ -6469,6 +6576,101 @@ mod tests {
6469
6576
  assert_promotable!(def);
6470
6577
  });
6471
6578
  }
6579
+
6580
+ #[test]
6581
+ fn index_private_constant_calls() {
6582
+ let context = index_source({
6583
+ r#"
6584
+ module Foo
6585
+ BAR = 42
6586
+ BAZ = 43
6587
+ FOO = 44
6588
+
6589
+ private_constant :BAR, :BAZ
6590
+ private_constant "FOO"
6591
+
6592
+ class Qux
6593
+ BAR = 42
6594
+ BAZ = 43
6595
+
6596
+ Foo.public_constant :BAR
6597
+ Foo.public_constant "BAZ"
6598
+ end
6599
+
6600
+ self.private_constant :Qux
6601
+ end
6602
+
6603
+ Foo.public_constant :BAR
6604
+ "#
6605
+ });
6606
+
6607
+ assert_no_local_diagnostics!(&context);
6608
+
6609
+ assert_definition_at!(&context, "6:21-6:24", ConstantVisibility, |def| {
6610
+ assert_def_name_eq!(&context, def, "BAR");
6611
+ assert_eq!(def.visibility(), &Visibility::Private);
6612
+ });
6613
+ assert_definition_at!(&context, "6:27-6:30", ConstantVisibility, |def| {
6614
+ assert_def_name_eq!(&context, def, "BAZ");
6615
+ assert_eq!(def.visibility(), &Visibility::Private);
6616
+ });
6617
+ assert_definition_at!(&context, "7:20-7:25", ConstantVisibility, |def| {
6618
+ assert_def_name_eq!(&context, def, "FOO");
6619
+ assert_eq!(def.visibility(), &Visibility::Private);
6620
+ });
6621
+ assert_definition_at!(&context, "13:26-13:29", ConstantVisibility, |def| {
6622
+ assert_def_name_eq!(&context, def, "Foo::BAR");
6623
+ assert_eq!(def.visibility(), &Visibility::Public);
6624
+ });
6625
+ assert_definition_at!(&context, "14:25-14:30", ConstantVisibility, |def| {
6626
+ assert_def_name_eq!(&context, def, "Foo::BAZ");
6627
+ assert_eq!(def.visibility(), &Visibility::Public);
6628
+ });
6629
+ assert_definition_at!(&context, "17:26-17:29", ConstantVisibility, |def| {
6630
+ assert_def_name_eq!(&context, def, "Qux");
6631
+ assert_eq!(def.visibility(), &Visibility::Private);
6632
+ });
6633
+ assert_definition_at!(&context, "20:22-20:25", ConstantVisibility, |def| {
6634
+ assert_def_name_eq!(&context, def, "Foo::BAR");
6635
+ assert_eq!(def.visibility(), &Visibility::Public);
6636
+ });
6637
+ }
6638
+
6639
+ #[test]
6640
+ fn index_private_constant_calls_diagnostics() {
6641
+ let context = index_source({
6642
+ "
6643
+ private_constant :NOT_INDEXED
6644
+ self.private_constant :NOT_INDEXED
6645
+ foo.private_constant :NOT_INDEXED # not indexed, dynamic receiver
6646
+
6647
+ module Foo
6648
+ private_constant NOT_INDEXED, not_indexed # not indexed, not a symbol
6649
+ private_constant # not indexed, no arguments
6650
+
6651
+ def self.qux
6652
+ private_constant :Bar # not indexed, dynamic
6653
+ end
6654
+
6655
+ def foo
6656
+ private_constant :Bar # not indexed, dynamic
6657
+ end
6658
+ end
6659
+ "
6660
+ });
6661
+
6662
+ assert_local_diagnostics_eq!(
6663
+ &context,
6664
+ vec![
6665
+ "invalid-private-constant: Private constant called at top level (1:1-1:30)",
6666
+ "invalid-private-constant: Private constant called at top level (2:1-2:35)",
6667
+ "invalid-private-constant: Dynamic receiver for private constant (3:1-3:34)",
6668
+ "invalid-private-constant: Private constant called with non-symbol argument (6:20-6:31)",
6669
+ ]
6670
+ );
6671
+
6672
+ assert_eq!(context.graph().definitions().len(), 3); // Foo, Foo::Qux, Foo#foo
6673
+ }
6472
6674
  }
6473
6675
 
6474
6676
  #[cfg(test)]
@@ -95,7 +95,7 @@ impl Job for IndexingJob {
95
95
  /// Indexes a single source string in memory, dispatching to the appropriate indexer based on `language_id`.
96
96
  pub fn index_source(graph: &mut Graph, uri: &str, source: &str, language_id: &LanguageId) {
97
97
  let local_graph = build_local_graph(uri.to_string(), source, language_id);
98
- graph.update(local_graph);
98
+ graph.consume_document_changes(local_graph);
99
99
  }
100
100
 
101
101
  /// Indexes the given paths, reading the content from disk and populating the given `Graph` instance.
@@ -123,7 +123,7 @@ pub fn index_files(graph: &mut Graph, paths: Vec<PathBuf>) -> Vec<Errors> {
123
123
 
124
124
  // Merge graphs as they arrive, overlapping with indexing work on other threads.
125
125
  while let Ok(local_graph) = local_graphs_rx.recv() {
126
- graph.update(local_graph);
126
+ graph.consume_document_changes(local_graph);
127
127
  }
128
128
 
129
129
  for handle in handles {
@@ -94,7 +94,7 @@ fn main() {
94
94
 
95
95
  time_it!(resolution, {
96
96
  let mut resolver = Resolver::new(&mut graph);
97
- resolver.resolve_all();
97
+ resolver.resolve();
98
98
  });
99
99
 
100
100
  if let Some(StopAfter::Resolution) = args.stop_after {
@@ -482,6 +482,10 @@ impl Namespace {
482
482
  all_namespaces!(self, it => it.member(str_id))
483
483
  }
484
484
 
485
+ pub fn remove_member(&mut self, str_id: &StringId) -> Option<DeclarationId> {
486
+ all_namespaces!(self, it => it.remove_member(str_id))
487
+ }
488
+
485
489
  #[must_use]
486
490
  pub fn singleton_class(&self) -> Option<&DeclarationId> {
487
491
  all_namespaces!(self, it => it.singleton_class_id())
@@ -62,6 +62,7 @@ pub enum Definition {
62
62
  Module(Box<ModuleDefinition>),
63
63
  Constant(Box<ConstantDefinition>),
64
64
  ConstantAlias(Box<ConstantAliasDefinition>),
65
+ ConstantVisibility(Box<ConstantVisibilityDefinition>),
65
66
  Method(Box<MethodDefinition>),
66
67
  AttrAccessor(Box<AttrAccessorDefinition>),
67
68
  AttrReader(Box<AttrReaderDefinition>),
@@ -82,6 +83,7 @@ macro_rules! all_definitions {
82
83
  Definition::Module($var) => $expr,
83
84
  Definition::Constant($var) => $expr,
84
85
  Definition::ConstantAlias($var) => $expr,
86
+ Definition::ConstantVisibility($var) => $expr,
85
87
  Definition::GlobalVariable($var) => $expr,
86
88
  Definition::InstanceVariable($var) => $expr,
87
89
  Definition::ClassVariable($var) => $expr,
@@ -129,6 +131,7 @@ impl Definition {
129
131
  Definition::Module(_) => "Module",
130
132
  Definition::Constant(_) => "Constant",
131
133
  Definition::ConstantAlias(_) => "ConstantAlias",
134
+ Definition::ConstantVisibility(_) => "ConstantVisibility",
132
135
  Definition::Method(_) => "Method",
133
136
  Definition::AttrAccessor(_) => "AttrAccessor",
134
137
  Definition::AttrReader(_) => "AttrReader",
@@ -149,6 +152,7 @@ impl Definition {
149
152
  Definition::Module(d) => Some(d.name_id()),
150
153
  Definition::Constant(d) => Some(d.name_id()),
151
154
  Definition::ConstantAlias(d) => Some(d.name_id()),
155
+ Definition::ConstantVisibility(d) => Some(d.name_id()),
152
156
  Definition::GlobalVariable(_)
153
157
  | Definition::InstanceVariable(_)
154
158
  | Definition::ClassVariable(_)
@@ -701,6 +705,80 @@ impl ConstantAliasDefinition {
701
705
  }
702
706
  }
703
707
 
708
+ #[derive(Debug)]
709
+ pub struct ConstantVisibilityDefinition {
710
+ name_id: NameId,
711
+ visibility: Visibility,
712
+ uri_id: UriId,
713
+ offset: Offset,
714
+ flags: DefinitionFlags,
715
+ comments: Vec<Comment>,
716
+ lexical_nesting_id: Option<DefinitionId>,
717
+ }
718
+
719
+ impl ConstantVisibilityDefinition {
720
+ #[must_use]
721
+ pub const fn new(
722
+ name_id: NameId,
723
+ visibility: Visibility,
724
+ uri_id: UriId,
725
+ offset: Offset,
726
+ comments: Vec<Comment>,
727
+ flags: DefinitionFlags,
728
+ lexical_nesting_id: Option<DefinitionId>,
729
+ ) -> Self {
730
+ Self {
731
+ name_id,
732
+ visibility,
733
+ uri_id,
734
+ offset,
735
+ flags,
736
+ comments,
737
+ lexical_nesting_id,
738
+ }
739
+ }
740
+
741
+ #[must_use]
742
+ pub fn id(&self) -> DefinitionId {
743
+ DefinitionId::from(&format!("{}{}{}", *self.uri_id, self.offset.start(), *self.name_id))
744
+ }
745
+
746
+ #[must_use]
747
+ pub fn name_id(&self) -> &NameId {
748
+ &self.name_id
749
+ }
750
+
751
+ #[must_use]
752
+ pub fn visibility(&self) -> &Visibility {
753
+ &self.visibility
754
+ }
755
+
756
+ #[must_use]
757
+ pub fn uri_id(&self) -> &UriId {
758
+ &self.uri_id
759
+ }
760
+
761
+ #[must_use]
762
+ pub fn offset(&self) -> &Offset {
763
+ &self.offset
764
+ }
765
+
766
+ #[must_use]
767
+ pub fn comments(&self) -> &[Comment] {
768
+ &self.comments
769
+ }
770
+
771
+ #[must_use]
772
+ pub fn lexical_nesting_id(&self) -> &Option<DefinitionId> {
773
+ &self.lexical_nesting_id
774
+ }
775
+
776
+ #[must_use]
777
+ pub fn flags(&self) -> &DefinitionFlags {
778
+ &self.flags
779
+ }
780
+ }
781
+
704
782
  /// The signature of a method
705
783
  ///
706
784
  /// Currently only supports the parameter names and kinds.