rubydex 0.2.0-aarch64-linux → 0.2.2-aarch64-linux

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.
data/rbi/rubydex.rbi CHANGED
@@ -152,6 +152,7 @@ class Rubydex::GlobalVariableDefinition < Rubydex::Definition; end
152
152
  class Rubydex::InstanceVariableDefinition < Rubydex::Definition; end
153
153
  class Rubydex::MethodAliasDefinition < Rubydex::Definition; end
154
154
  class Rubydex::MethodDefinition < Rubydex::Definition; end
155
+
155
156
  class Rubydex::ModuleDefinition < Rubydex::Definition
156
157
  sig { returns(T::Array[Rubydex::Mixin]) }
157
158
  def mixins; end
@@ -317,27 +318,56 @@ class Rubydex::Graph
317
318
  # Returns completion candidates for an expression context. This includes all keywords, constants, methods, instance
318
319
  # variables, class variables and global variables reachable from the current lexical scope and self type.
319
320
  #
320
- # The nesting array represents the lexical scope stack, where the last element is the self type. An empty array
321
- # defaults to `Object` as the self type (top-level context).
322
- sig { params(nesting: T::Array[String]).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword)]) }
323
- def complete_expression(nesting); end
321
+ # The nesting array represents the lexical scope stack. The optional `self_receiver` keyword argument overrides the
322
+ # self type independently of the lexical scope (e.g., `"Foo::<Foo>"` for `def Foo.bar`). This distinction is important
323
+ # because constants and class variables are always attached to the lexical scope. Meanwhile, methods and instance
324
+ # variables are attached to the type of `self` and those don't always match.
325
+ sig do
326
+ params(
327
+ nesting: T::Array[String],
328
+ self_receiver: T.nilable(String),
329
+ ).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword)])
330
+ end
331
+ def complete_expression(nesting, self_receiver: nil); end
324
332
 
325
333
  # Returns completion candidates after a namespace access operator (e.g., `Foo::`). This includes all constants and
326
334
  # singleton methods for the namespace and its ancestors.
327
- sig { params(name: String).returns(T::Array[Rubydex::Declaration]) }
328
- def complete_namespace_access(name); end
335
+ #
336
+ # The optional `self_receiver` kwarg is the caller's runtime self type. It's used to filter visibility-restricted
337
+ # singleton methods (e.g., `private_class_method`). Pass `nil` (the default) for top-level/script scope.
338
+ sig do
339
+ params(
340
+ name: String,
341
+ self_receiver: T.nilable(String),
342
+ ).returns(T::Array[Rubydex::Declaration])
343
+ end
344
+ def complete_namespace_access(name, self_receiver: nil); end
329
345
 
330
346
  # Returns completion candidates after a method call operator (e.g., `foo.`). This includes all methods that exist on
331
347
  # the type of the receiver and its ancestors.
332
- sig { params(name: String).returns(T::Array[Rubydex::Method]) }
333
- def complete_method_call(name); end
348
+ #
349
+ # The optional `self_receiver` kwarg is the caller's runtime self type. It's used for visibility checks for `private`
350
+ # and `protected` methods. Pass `nil` (the default) for top-level/script scope.
351
+ sig do
352
+ params(
353
+ name: String,
354
+ self_receiver: T.nilable(String),
355
+ ).returns(T::Array[Rubydex::Method])
356
+ end
357
+ def complete_method_call(name, self_receiver: nil); end
334
358
 
335
359
  # Returns completion candidates inside a method call's argument list (e.g., `foo.bar(|)`). This includes everything
336
360
  # that expression completion provides plus keyword argument names of the method being called.
337
361
  #
338
- # The nesting array represents the lexical scope stack, where the last element is the self type.
339
- sig { params(name: String, nesting: T::Array[String]).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword, Rubydex::KeywordParameter)]) }
340
- def complete_method_argument(name, nesting); end
362
+ # See `complete_expression` for the semantics of `nesting` and `self_receiver`.
363
+ sig do
364
+ params(
365
+ name: String,
366
+ nesting: T::Array[String],
367
+ self_receiver: T.nilable(String),
368
+ ).returns(T::Array[T.any(Rubydex::Declaration, Rubydex::Keyword, Rubydex::KeywordParameter)])
369
+ end
370
+ def complete_method_argument(name, nesting, self_receiver: nil); end
341
371
 
342
372
  private
343
373
 
@@ -108,4 +108,5 @@ rules! {
108
108
 
109
109
  // Resolution
110
110
  UndefinedMethodVisibilityTarget;
111
+ UndefinedConstantVisibilityTarget;
111
112
  }
@@ -1200,9 +1200,7 @@ impl<'a> RubyIndexer<'a> {
1200
1200
  }
1201
1201
  Some(ruby_prism::Node::SelfNode { .. }) | None => match self.nesting_stack.last() {
1202
1202
  Some(Nesting::Method(_)) => {
1203
- // Dynamic private constant (called from a method), we ignore it but don't report an error since it's valid Ruby
1204
- // if being called from a singleton method.
1205
-
1203
+ self.visit_call_node_parts(node);
1206
1204
  return;
1207
1205
  }
1208
1206
  None => {
@@ -1211,7 +1209,7 @@ impl<'a> RubyIndexer<'a> {
1211
1209
  Offset::from_prism_location(&node.location()),
1212
1210
  "Private constant called at top level".to_string(),
1213
1211
  );
1214
-
1212
+ self.visit_call_node_parts(node);
1215
1213
  return;
1216
1214
  }
1217
1215
  _ => None,
@@ -1222,7 +1220,7 @@ impl<'a> RubyIndexer<'a> {
1222
1220
  Offset::from_prism_location(&node.location()),
1223
1221
  "Dynamic receiver for private constant".to_string(),
1224
1222
  );
1225
-
1223
+ self.visit_call_node_parts(node);
1226
1224
  return;
1227
1225
  }
1228
1226
  };
@@ -1252,19 +1250,16 @@ impl<'a> RubyIndexer<'a> {
1252
1250
  Offset::from_prism_location(&argument.location()),
1253
1251
  "Private constant called with non-symbol argument".to_string(),
1254
1252
  );
1255
-
1256
- return;
1253
+ self.visit(&argument);
1254
+ continue;
1257
1255
  }
1258
1256
  };
1259
1257
 
1260
1258
  let str_id = self.local_graph.intern_string(name);
1261
1259
  let offset = Offset::from_prism_location(&location);
1262
1260
  let definition = Definition::ConstantVisibility(Box::new(ConstantVisibilityDefinition::new(
1263
- self.local_graph.add_name(Name::new(
1264
- str_id,
1265
- receiver_name_id.map_or(ParentScope::None, ParentScope::Some),
1266
- self.current_lexical_scope_name_id(),
1267
- )),
1261
+ receiver_name_id,
1262
+ str_id,
1268
1263
  visibility,
1269
1264
  self.uri_id,
1270
1265
  offset,
@@ -1279,6 +1274,60 @@ impl<'a> RubyIndexer<'a> {
1279
1274
  }
1280
1275
  }
1281
1276
 
1277
+ fn handle_singleton_method_visibility(
1278
+ &mut self,
1279
+ node: &ruby_prism::CallNode,
1280
+ visibility: Visibility,
1281
+ call_name: &str,
1282
+ ) {
1283
+ match node.receiver() {
1284
+ Some(ruby_prism::Node::SelfNode { .. }) | None => match self.nesting_stack.last() {
1285
+ Some(Nesting::Method(_)) => {
1286
+ self.visit_call_node_parts(node);
1287
+ return;
1288
+ }
1289
+ None => {
1290
+ self.local_graph.add_diagnostic(
1291
+ Rule::InvalidMethodVisibility,
1292
+ Offset::from_prism_location(&node.location()),
1293
+ format!("`{call_name}` called at top level"),
1294
+ );
1295
+ self.visit_call_node_parts(node);
1296
+ return;
1297
+ }
1298
+ _ => {}
1299
+ },
1300
+ _ => {
1301
+ self.visit_call_node_parts(node);
1302
+ return;
1303
+ }
1304
+ }
1305
+
1306
+ let Some(arguments) = node.arguments() else {
1307
+ return;
1308
+ };
1309
+
1310
+ for argument in &arguments.arguments() {
1311
+ match argument {
1312
+ ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. } => {
1313
+ self.create_method_visibility_definition(
1314
+ &argument,
1315
+ visibility,
1316
+ DefinitionFlags::SINGLETON_METHOD_VISIBILITY,
1317
+ );
1318
+ }
1319
+ _ => {
1320
+ self.local_graph.add_diagnostic(
1321
+ Rule::InvalidMethodVisibility,
1322
+ Offset::from_prism_location(&argument.location()),
1323
+ format!("`{call_name}` called with a non-literal argument"),
1324
+ );
1325
+ self.visit(&argument);
1326
+ }
1327
+ }
1328
+ }
1329
+ }
1330
+
1282
1331
  fn is_attr_call(arg: &ruby_prism::Node) -> bool {
1283
1332
  arg.as_call_node().is_some_and(|call| {
1284
1333
  let receiver = call.receiver();
@@ -1316,7 +1365,7 @@ impl<'a> RubyIndexer<'a> {
1316
1365
  arg,
1317
1366
  ruby_prism::Node::SymbolNode { .. } | ruby_prism::Node::StringNode { .. }
1318
1367
  ) {
1319
- self.create_method_visibility_definition(&arg, visibility);
1368
+ self.create_method_visibility_definition(&arg, visibility, DefinitionFlags::empty());
1320
1369
  } else {
1321
1370
  // Unsupported arg — diagnostic + visit for side effects.
1322
1371
  let arg_offset = Offset::from_prism_location(&arg.location());
@@ -1332,7 +1381,12 @@ impl<'a> RubyIndexer<'a> {
1332
1381
  }
1333
1382
  }
1334
1383
 
1335
- fn create_method_visibility_definition(&mut self, arg: &ruby_prism::Node, visibility: Visibility) {
1384
+ fn create_method_visibility_definition(
1385
+ &mut self,
1386
+ arg: &ruby_prism::Node,
1387
+ visibility: Visibility,
1388
+ flags: DefinitionFlags,
1389
+ ) {
1336
1390
  let (name, location) = match arg {
1337
1391
  ruby_prism::Node::SymbolNode { .. } => {
1338
1392
  let symbol = arg.as_symbol_node().unwrap();
@@ -1358,7 +1412,7 @@ impl<'a> RubyIndexer<'a> {
1358
1412
  self.uri_id,
1359
1413
  arg_offset,
1360
1414
  Box::default(),
1361
- DefinitionFlags::empty(),
1415
+ flags,
1362
1416
  self.current_nesting_definition_id(),
1363
1417
  )));
1364
1418
 
@@ -2052,6 +2106,12 @@ impl Visit<'_> for RubyIndexer<'_> {
2052
2106
  "public_constant" => {
2053
2107
  self.handle_constant_visibility(node, Visibility::Public);
2054
2108
  }
2109
+ "private_class_method" => {
2110
+ self.handle_singleton_method_visibility(node, Visibility::Private, "private_class_method");
2111
+ }
2112
+ "public_class_method" => {
2113
+ self.handle_singleton_method_visibility(node, Visibility::Public, "public_class_method");
2114
+ }
2055
2115
  _ => {
2056
2116
  // For method calls that we don't explicitly handle each part, we continue visiting their parts as we
2057
2117
  // may discover something inside