rubydex 0.2.0 → 0.2.2
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/ext/rubydex/declaration.c +38 -0
- data/ext/rubydex/definition.c +27 -0
- data/ext/rubydex/graph.c +70 -17
- data/ext/rubydex/rubydex.c +2 -0
- data/ext/rubydex/signature.c +83 -0
- data/ext/rubydex/signature.h +23 -0
- data/lib/rubydex/declaration.rb +31 -0
- data/lib/rubydex/signature.rb +130 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +1 -0
- data/rbi/rubydex.rbi +41 -11
- data/rust/rubydex/src/diagnostic.rs +1 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +75 -15
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +2832 -2663
- data/rust/rubydex/src/model/declaration.rs +48 -0
- data/rust/rubydex/src/model/definitions.rs +41 -9
- data/rust/rubydex/src/model/graph.rs +276 -46
- data/rust/rubydex/src/query.rs +2073 -160
- data/rust/rubydex/src/resolution.rs +202 -71
- data/rust/rubydex/src/resolution_tests.rs +333 -1
- data/rust/rubydex-sys/src/declaration_api.rs +29 -33
- data/rust/rubydex-sys/src/graph_api.rs +89 -5
- data/rust/rubydex-sys/src/lib.rs +1 -0
- data/rust/rubydex-sys/src/signature_api.rs +209 -0
- metadata +6 -2
|
@@ -4926,6 +4926,25 @@ mod visibility_resolution_tests {
|
|
|
4926
4926
|
};
|
|
4927
4927
|
}
|
|
4928
4928
|
|
|
4929
|
+
#[test]
|
|
4930
|
+
fn retroactive_visibility_override_applies_in_source_order() {
|
|
4931
|
+
let mut context = GraphTest::new();
|
|
4932
|
+
context.index_uri(
|
|
4933
|
+
"file:///foo.rb",
|
|
4934
|
+
r"
|
|
4935
|
+
class Foo
|
|
4936
|
+
def bar; end
|
|
4937
|
+
private :bar
|
|
4938
|
+
public :bar
|
|
4939
|
+
end
|
|
4940
|
+
",
|
|
4941
|
+
);
|
|
4942
|
+
context.resolve();
|
|
4943
|
+
|
|
4944
|
+
assert_no_diagnostics!(&context);
|
|
4945
|
+
assert_visibility_eq!(context, "Foo#bar()", Visibility::Public);
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4929
4948
|
#[test]
|
|
4930
4949
|
fn retroactive_visibility_on_direct_method() {
|
|
4931
4950
|
let mut context = GraphTest::new();
|
|
@@ -5066,7 +5085,7 @@ mod visibility_resolution_tests {
|
|
|
5066
5085
|
assert_diagnostics_eq!(
|
|
5067
5086
|
context,
|
|
5068
5087
|
&[
|
|
5069
|
-
"undefined-method-visibility-target: undefined method `nonexistent()` for visibility change
|
|
5088
|
+
"undefined-method-visibility-target: undefined method `Foo#nonexistent()` for visibility change (2:12-2:23)"
|
|
5070
5089
|
]
|
|
5071
5090
|
);
|
|
5072
5091
|
}
|
|
@@ -5128,4 +5147,317 @@ mod visibility_resolution_tests {
|
|
|
5128
5147
|
assert_owner_eq!(context, "Child#foo()", "Child");
|
|
5129
5148
|
assert_visibility_eq!(context, "Child#foo()", Visibility::Private);
|
|
5130
5149
|
}
|
|
5150
|
+
|
|
5151
|
+
#[test]
|
|
5152
|
+
fn retroactive_constant_visibility_on_direct_member() {
|
|
5153
|
+
let mut context = GraphTest::new();
|
|
5154
|
+
context.index_uri(
|
|
5155
|
+
"file:///foo.rb",
|
|
5156
|
+
r"
|
|
5157
|
+
class Foo
|
|
5158
|
+
BAR = 1
|
|
5159
|
+
private_constant :BAR
|
|
5160
|
+
|
|
5161
|
+
BAZ = 2
|
|
5162
|
+
public_constant :BAZ
|
|
5163
|
+
|
|
5164
|
+
QUX = 3
|
|
5165
|
+
|
|
5166
|
+
class Inner; end
|
|
5167
|
+
private_constant :Inner
|
|
5168
|
+
|
|
5169
|
+
module InnerMod; end
|
|
5170
|
+
private_constant :InnerMod
|
|
5171
|
+
end
|
|
5172
|
+
",
|
|
5173
|
+
);
|
|
5174
|
+
context.resolve();
|
|
5175
|
+
|
|
5176
|
+
assert_no_diagnostics!(&context);
|
|
5177
|
+
assert_visibility_eq!(context, "Foo::BAR", Visibility::Private);
|
|
5178
|
+
assert_visibility_eq!(context, "Foo::BAZ", Visibility::Public);
|
|
5179
|
+
assert_visibility_eq!(context, "Foo::QUX", Visibility::Public);
|
|
5180
|
+
assert_visibility_eq!(context, "Foo::Inner", Visibility::Private);
|
|
5181
|
+
assert_visibility_eq!(context, "Foo::InnerMod", Visibility::Private);
|
|
5182
|
+
}
|
|
5183
|
+
|
|
5184
|
+
#[test]
|
|
5185
|
+
fn retroactive_constant_visibility_via_qualified_receiver() {
|
|
5186
|
+
let mut context = GraphTest::new();
|
|
5187
|
+
context.index_uri(
|
|
5188
|
+
"file:///foo.rb",
|
|
5189
|
+
r"
|
|
5190
|
+
class Foo
|
|
5191
|
+
BAR = 1
|
|
5192
|
+
BAZ = 2
|
|
5193
|
+
end
|
|
5194
|
+
|
|
5195
|
+
ALIAS = Foo
|
|
5196
|
+
Foo.private_constant :BAR
|
|
5197
|
+
ALIAS.private_constant :BAZ
|
|
5198
|
+
",
|
|
5199
|
+
);
|
|
5200
|
+
context.resolve();
|
|
5201
|
+
|
|
5202
|
+
assert_no_diagnostics!(&context);
|
|
5203
|
+
assert_visibility_eq!(context, "Foo::BAR", Visibility::Private);
|
|
5204
|
+
assert_visibility_eq!(context, "Foo::BAZ", Visibility::Private);
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
#[test]
|
|
5208
|
+
fn retroactive_constant_visibility_multi_arg_undefined_emits_per_name_diagnostic() {
|
|
5209
|
+
let mut context = GraphTest::new();
|
|
5210
|
+
context.index_uri(
|
|
5211
|
+
"file:///foo.rb",
|
|
5212
|
+
r"
|
|
5213
|
+
class Foo
|
|
5214
|
+
private_constant :NOPE_ONE, :NOPE_TWO
|
|
5215
|
+
end
|
|
5216
|
+
",
|
|
5217
|
+
);
|
|
5218
|
+
context.resolve();
|
|
5219
|
+
|
|
5220
|
+
assert_diagnostics_eq!(
|
|
5221
|
+
context,
|
|
5222
|
+
&[
|
|
5223
|
+
"undefined-constant-visibility-target: undefined constant `NOPE_ONE` for visibility change in `Foo` (2:21-2:29)",
|
|
5224
|
+
"undefined-constant-visibility-target: undefined constant `NOPE_TWO` for visibility change in `Foo` (2:32-2:40)",
|
|
5225
|
+
]
|
|
5226
|
+
);
|
|
5227
|
+
}
|
|
5228
|
+
|
|
5229
|
+
#[test]
|
|
5230
|
+
fn retroactive_constant_visibility_inherited_constant_emits_diagnostic() {
|
|
5231
|
+
let mut context = GraphTest::new();
|
|
5232
|
+
context.index_uri(
|
|
5233
|
+
"file:///foo.rb",
|
|
5234
|
+
r"
|
|
5235
|
+
class Parent
|
|
5236
|
+
CONST = 1
|
|
5237
|
+
end
|
|
5238
|
+
|
|
5239
|
+
class Child < Parent
|
|
5240
|
+
private_constant :CONST
|
|
5241
|
+
end
|
|
5242
|
+
",
|
|
5243
|
+
);
|
|
5244
|
+
context.resolve();
|
|
5245
|
+
|
|
5246
|
+
assert_diagnostics_eq!(
|
|
5247
|
+
context,
|
|
5248
|
+
&[
|
|
5249
|
+
"undefined-constant-visibility-target: undefined constant `CONST` for visibility change in `Child` (6:21-6:26)"
|
|
5250
|
+
]
|
|
5251
|
+
);
|
|
5252
|
+
assert_visibility_eq!(context, "Parent::CONST", Visibility::Public);
|
|
5253
|
+
}
|
|
5254
|
+
|
|
5255
|
+
#[test]
|
|
5256
|
+
fn retroactive_constant_visibility_clears_when_call_removed() {
|
|
5257
|
+
let mut context = GraphTest::new();
|
|
5258
|
+
context.index_uri(
|
|
5259
|
+
"file:///foo.rb",
|
|
5260
|
+
r"
|
|
5261
|
+
class Foo
|
|
5262
|
+
BAR = 1
|
|
5263
|
+
end
|
|
5264
|
+
",
|
|
5265
|
+
);
|
|
5266
|
+
context.index_uri(
|
|
5267
|
+
"file:///vis.rb",
|
|
5268
|
+
r"
|
|
5269
|
+
Foo.private_constant :BAR
|
|
5270
|
+
",
|
|
5271
|
+
);
|
|
5272
|
+
context.resolve();
|
|
5273
|
+
|
|
5274
|
+
assert_no_diagnostics!(&context);
|
|
5275
|
+
assert_visibility_eq!(context, "Foo::BAR", Visibility::Private);
|
|
5276
|
+
|
|
5277
|
+
context.delete_uri("file:///vis.rb");
|
|
5278
|
+
context.resolve();
|
|
5279
|
+
|
|
5280
|
+
assert_no_diagnostics!(&context);
|
|
5281
|
+
assert_visibility_eq!(context, "Foo::BAR", Visibility::Public);
|
|
5282
|
+
}
|
|
5283
|
+
|
|
5284
|
+
#[test]
|
|
5285
|
+
fn retroactive_constant_visibility_inside_singleton_class_body() {
|
|
5286
|
+
let mut context = GraphTest::new();
|
|
5287
|
+
context.index_uri(
|
|
5288
|
+
"file:///foo.rb",
|
|
5289
|
+
r"
|
|
5290
|
+
class Foo
|
|
5291
|
+
class << self
|
|
5292
|
+
BAR = 1
|
|
5293
|
+
private_constant :BAR
|
|
5294
|
+
end
|
|
5295
|
+
end
|
|
5296
|
+
",
|
|
5297
|
+
);
|
|
5298
|
+
context.resolve();
|
|
5299
|
+
|
|
5300
|
+
assert_no_diagnostics!(&context);
|
|
5301
|
+
assert_visibility_eq!(context, "Foo::<Foo>::BAR", Visibility::Private);
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5304
|
+
#[test]
|
|
5305
|
+
fn retroactive_constant_visibility_persists_across_reopened_class() {
|
|
5306
|
+
let mut context = GraphTest::new();
|
|
5307
|
+
context.index_uri(
|
|
5308
|
+
"file:///a.rb",
|
|
5309
|
+
r"
|
|
5310
|
+
class Foo
|
|
5311
|
+
BAR = 1
|
|
5312
|
+
private_constant :BAR
|
|
5313
|
+
end
|
|
5314
|
+
",
|
|
5315
|
+
);
|
|
5316
|
+
context.index_uri(
|
|
5317
|
+
"file:///b.rb",
|
|
5318
|
+
r"
|
|
5319
|
+
class Foo
|
|
5320
|
+
BAR = 2
|
|
5321
|
+
end
|
|
5322
|
+
",
|
|
5323
|
+
);
|
|
5324
|
+
context.resolve();
|
|
5325
|
+
|
|
5326
|
+
assert_visibility_eq!(context, "Foo::BAR", Visibility::Private);
|
|
5327
|
+
}
|
|
5328
|
+
|
|
5329
|
+
#[test]
|
|
5330
|
+
fn retroactive_singleton_method_visibility_on_direct_member() {
|
|
5331
|
+
let mut context = GraphTest::new();
|
|
5332
|
+
context.index_uri(
|
|
5333
|
+
"file:///foo.rb",
|
|
5334
|
+
r"
|
|
5335
|
+
class Foo
|
|
5336
|
+
def self.bar; end
|
|
5337
|
+
def self.baz; end
|
|
5338
|
+
|
|
5339
|
+
private_class_method :bar
|
|
5340
|
+
private_class_method :baz
|
|
5341
|
+
public_class_method :baz
|
|
5342
|
+
end
|
|
5343
|
+
",
|
|
5344
|
+
);
|
|
5345
|
+
context.resolve();
|
|
5346
|
+
|
|
5347
|
+
assert_no_diagnostics!(&context);
|
|
5348
|
+
assert_visibility_eq!(context, "Foo::<Foo>#bar()", Visibility::Private);
|
|
5349
|
+
assert_visibility_eq!(context, "Foo::<Foo>#baz()", Visibility::Public);
|
|
5350
|
+
}
|
|
5351
|
+
|
|
5352
|
+
#[test]
|
|
5353
|
+
fn retroactive_singleton_method_visibility_on_inherited_method() {
|
|
5354
|
+
let mut context = GraphTest::new();
|
|
5355
|
+
context.index_uri(
|
|
5356
|
+
"file:///foo.rb",
|
|
5357
|
+
r"
|
|
5358
|
+
class Parent
|
|
5359
|
+
def self.foo; end
|
|
5360
|
+
end
|
|
5361
|
+
|
|
5362
|
+
class Child < Parent
|
|
5363
|
+
private_class_method :foo
|
|
5364
|
+
end
|
|
5365
|
+
",
|
|
5366
|
+
);
|
|
5367
|
+
context.resolve();
|
|
5368
|
+
|
|
5369
|
+
assert_no_diagnostics!(&context);
|
|
5370
|
+
assert_declaration_exists!(context, "Child::<Child>#foo()");
|
|
5371
|
+
assert_visibility_eq!(context, "Child::<Child>#foo()", Visibility::Private);
|
|
5372
|
+
assert_visibility_eq!(context, "Parent::<Parent>#foo()", Visibility::Public);
|
|
5373
|
+
}
|
|
5374
|
+
|
|
5375
|
+
#[test]
|
|
5376
|
+
fn retroactive_singleton_method_visibility_on_undefined_method_emits_diagnostic() {
|
|
5377
|
+
let mut context = GraphTest::new();
|
|
5378
|
+
context.index_uri(
|
|
5379
|
+
"file:///foo.rb",
|
|
5380
|
+
r"
|
|
5381
|
+
class Foo
|
|
5382
|
+
private_class_method :nonexistent
|
|
5383
|
+
end
|
|
5384
|
+
",
|
|
5385
|
+
);
|
|
5386
|
+
context.resolve();
|
|
5387
|
+
|
|
5388
|
+
assert_diagnostics_eq!(
|
|
5389
|
+
context,
|
|
5390
|
+
&[
|
|
5391
|
+
"undefined-method-visibility-target: undefined method `Foo::<Foo>#nonexistent()` for visibility change (2:25-2:36)"
|
|
5392
|
+
]
|
|
5393
|
+
);
|
|
5394
|
+
}
|
|
5395
|
+
|
|
5396
|
+
#[test]
|
|
5397
|
+
fn retroactive_singleton_method_visibility_undefined_target_diagnostic_clears_when_file_deleted() {
|
|
5398
|
+
let mut context = GraphTest::new();
|
|
5399
|
+
context.index_uri(
|
|
5400
|
+
"file:///foo.rb",
|
|
5401
|
+
r"
|
|
5402
|
+
class Foo
|
|
5403
|
+
end
|
|
5404
|
+
",
|
|
5405
|
+
);
|
|
5406
|
+
context.index_uri(
|
|
5407
|
+
"file:///bad.rb",
|
|
5408
|
+
r"
|
|
5409
|
+
class Foo
|
|
5410
|
+
private_class_method :missing
|
|
5411
|
+
end
|
|
5412
|
+
",
|
|
5413
|
+
);
|
|
5414
|
+
context.resolve();
|
|
5415
|
+
|
|
5416
|
+
assert_diagnostics_eq!(
|
|
5417
|
+
context,
|
|
5418
|
+
&[
|
|
5419
|
+
"undefined-method-visibility-target: undefined method `Foo::<Foo>#missing()` for visibility change (2:25-2:32)"
|
|
5420
|
+
]
|
|
5421
|
+
);
|
|
5422
|
+
|
|
5423
|
+
context.delete_uri("file:///bad.rb");
|
|
5424
|
+
context.resolve();
|
|
5425
|
+
|
|
5426
|
+
assert_no_diagnostics!(&context);
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
#[test]
|
|
5430
|
+
fn retroactive_singleton_method_visibility_undefined_target_diagnostic_clears_when_target_added() {
|
|
5431
|
+
let mut context = GraphTest::new();
|
|
5432
|
+
context.index_uri(
|
|
5433
|
+
"file:///foo.rb",
|
|
5434
|
+
r"
|
|
5435
|
+
class Foo
|
|
5436
|
+
private_class_method :missing
|
|
5437
|
+
end
|
|
5438
|
+
",
|
|
5439
|
+
);
|
|
5440
|
+
context.resolve();
|
|
5441
|
+
|
|
5442
|
+
assert_diagnostics_eq!(
|
|
5443
|
+
context,
|
|
5444
|
+
&[
|
|
5445
|
+
"undefined-method-visibility-target: undefined method `Foo::<Foo>#missing()` for visibility change (2:25-2:32)"
|
|
5446
|
+
]
|
|
5447
|
+
);
|
|
5448
|
+
|
|
5449
|
+
context.index_uri(
|
|
5450
|
+
"file:///foo.rb",
|
|
5451
|
+
r"
|
|
5452
|
+
class Foo
|
|
5453
|
+
def self.missing; end
|
|
5454
|
+
private_class_method :missing
|
|
5455
|
+
end
|
|
5456
|
+
",
|
|
5457
|
+
);
|
|
5458
|
+
context.resolve();
|
|
5459
|
+
|
|
5460
|
+
assert_no_diagnostics!(&context);
|
|
5461
|
+
assert_visibility_eq!(context, "Foo::<Foo>#missing()", Visibility::Private);
|
|
5462
|
+
}
|
|
5131
5463
|
}
|
|
@@ -64,6 +64,25 @@ impl CDeclaration {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/// Convert a nullable C string to `Option<DeclarationId>`.
|
|
68
|
+
/// Null, empty, or non-UTF-8 input yields `None`.
|
|
69
|
+
///
|
|
70
|
+
/// # Safety
|
|
71
|
+
///
|
|
72
|
+
/// If non-null, `ptr` must point to a valid, NUL-terminated C string that remains valid for the
|
|
73
|
+
/// duration of the call. The contents do not need to be UTF-8 — non-UTF-8 input is handled by returning
|
|
74
|
+
/// `None`.
|
|
75
|
+
pub(crate) unsafe fn decl_id_from_char_ptr(ptr: *const c_char) -> Option<DeclarationId> {
|
|
76
|
+
if ptr.is_null() {
|
|
77
|
+
return None;
|
|
78
|
+
}
|
|
79
|
+
let s = unsafe { utils::convert_char_ptr_to_string(ptr) }.ok()?;
|
|
80
|
+
if s.is_empty() {
|
|
81
|
+
return None;
|
|
82
|
+
}
|
|
83
|
+
Some(DeclarationId::from(s.as_str()))
|
|
84
|
+
}
|
|
85
|
+
|
|
67
86
|
/// An iterator over declaration IDs
|
|
68
87
|
///
|
|
69
88
|
/// We snapshot the IDs at iterator creation so if the graph is modified, the iterator will not see the changes
|
|
@@ -178,42 +197,19 @@ pub unsafe extern "C" fn rdx_declaration_find_member(
|
|
|
178
197
|
|
|
179
198
|
with_graph(pointer, |graph| {
|
|
180
199
|
let id = DeclarationId::new(declaration_id);
|
|
200
|
+
let member_id = StringId::from(member_str.as_str());
|
|
181
201
|
|
|
182
|
-
let
|
|
183
|
-
|
|
202
|
+
let member_decl_id = match rubydex::query::find_member_in_ancestors(graph, id, member_id, only_inherited) {
|
|
203
|
+
Ok(decl_id) => decl_id,
|
|
204
|
+
Err(rubydex::query::FindMemberError::MemberNotFound) => return ptr::null(),
|
|
205
|
+
Err(err) => unreachable!(
|
|
206
|
+
"Namespace#find_member is only exposed on namespace declarations, so the declaration must exist and be \
|
|
207
|
+
a namespace, got {err:?}"
|
|
208
|
+
),
|
|
184
209
|
};
|
|
185
210
|
|
|
186
|
-
let
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
decl.ancestors()
|
|
190
|
-
.iter()
|
|
191
|
-
.find_map(|ancestor| match ancestor {
|
|
192
|
-
Ancestor::Complete(ancestor_id) => {
|
|
193
|
-
// When only_inherited, skip self and prepended modules
|
|
194
|
-
if only_inherited {
|
|
195
|
-
let is_self = *ancestor_id == id;
|
|
196
|
-
if is_self {
|
|
197
|
-
found_main_namespace = true;
|
|
198
|
-
}
|
|
199
|
-
if is_self || !found_main_namespace {
|
|
200
|
-
return None;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
let ancestor_decl = graph.declarations().get(ancestor_id).unwrap().as_namespace().unwrap();
|
|
205
|
-
|
|
206
|
-
if let Some(member_decl_id) = ancestor_decl.member(&member_id) {
|
|
207
|
-
return Some((member_decl_id, graph.declarations().get(member_decl_id).unwrap()));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
None
|
|
211
|
-
}
|
|
212
|
-
Ancestor::Partial(_) => None,
|
|
213
|
-
})
|
|
214
|
-
.map_or(ptr::null(), |(member_decl_id, member_decl)| {
|
|
215
|
-
Box::into_raw(Box::new(CDeclaration::from_declaration(*member_decl_id, member_decl))).cast_const()
|
|
216
|
-
})
|
|
211
|
+
let member_decl = graph.declarations().get(&member_decl_id).unwrap();
|
|
212
|
+
Box::into_raw(Box::new(CDeclaration::from_declaration(member_decl_id, member_decl))).cast_const()
|
|
217
213
|
})
|
|
218
214
|
}
|
|
219
215
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
use crate::declaration_api::CDeclaration;
|
|
4
4
|
use crate::declaration_api::DeclarationsIter;
|
|
5
|
+
use crate::declaration_api::decl_id_from_char_ptr;
|
|
5
6
|
use crate::document_api::DocumentsIter;
|
|
6
7
|
use crate::reference_api::{CConstantReference, CMethodReference, ConstantReferencesIter, MethodReferencesIter};
|
|
7
8
|
use crate::{name_api, utils};
|
|
@@ -12,6 +13,7 @@ use rubydex::model::graph::Graph;
|
|
|
12
13
|
use rubydex::model::ids::{DeclarationId, NameId, UriId};
|
|
13
14
|
use rubydex::model::keywords;
|
|
14
15
|
use rubydex::model::name::NameRef;
|
|
16
|
+
use rubydex::model::visibility::Visibility;
|
|
15
17
|
use rubydex::query::{CompletionCandidate, CompletionContext, CompletionReceiver};
|
|
16
18
|
use rubydex::resolution::Resolver;
|
|
17
19
|
use rubydex::{indexing, integrity, listing, query};
|
|
@@ -791,11 +793,15 @@ fn run_and_finalize_completion(
|
|
|
791
793
|
///
|
|
792
794
|
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
793
795
|
/// - `nesting` must point to `nesting_count` valid, null-terminated UTF-8 strings.
|
|
796
|
+
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
|
|
797
|
+
/// overrides the self-type (e.g., `"Foo::<Foo>"` for completion inside `def Foo.bar`), while
|
|
798
|
+
/// the lexical nesting still comes from `nesting`.
|
|
794
799
|
#[unsafe(no_mangle)]
|
|
795
800
|
pub unsafe extern "C" fn rdx_graph_complete_expression(
|
|
796
801
|
pointer: GraphPointer,
|
|
797
802
|
nesting: *const *const c_char,
|
|
798
803
|
nesting_count: usize,
|
|
804
|
+
self_receiver: *const c_char,
|
|
799
805
|
) -> CompletionResult {
|
|
800
806
|
with_mut_graph(pointer, |graph| {
|
|
801
807
|
let Some((name_id, names_to_untrack)) = (unsafe { completion_nesting_name_id(graph, nesting, nesting_count) })
|
|
@@ -803,7 +809,16 @@ pub unsafe extern "C" fn rdx_graph_complete_expression(
|
|
|
803
809
|
return CompletionResult::success(ptr::null_mut());
|
|
804
810
|
};
|
|
805
811
|
|
|
806
|
-
|
|
812
|
+
let self_decl_id = unsafe { decl_id_from_char_ptr(self_receiver) };
|
|
813
|
+
|
|
814
|
+
run_and_finalize_completion(
|
|
815
|
+
graph,
|
|
816
|
+
CompletionReceiver::Expression {
|
|
817
|
+
self_decl_id,
|
|
818
|
+
nesting_name_id: name_id,
|
|
819
|
+
},
|
|
820
|
+
names_to_untrack,
|
|
821
|
+
)
|
|
807
822
|
})
|
|
808
823
|
}
|
|
809
824
|
|
|
@@ -815,19 +830,27 @@ pub unsafe extern "C" fn rdx_graph_complete_expression(
|
|
|
815
830
|
///
|
|
816
831
|
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
817
832
|
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the namespace).
|
|
833
|
+
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
|
|
834
|
+
/// is the caller's runtime self type (e.g., for filtering `private_class_method` visibility).
|
|
818
835
|
#[unsafe(no_mangle)]
|
|
819
836
|
pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
|
|
820
837
|
pointer: GraphPointer,
|
|
821
838
|
name: *const c_char,
|
|
839
|
+
self_receiver: *const c_char,
|
|
822
840
|
) -> CompletionResult {
|
|
823
841
|
let Ok(name_str) = (unsafe { utils::convert_char_ptr_to_string(name) }) else {
|
|
824
842
|
return CompletionResult::success(ptr::null_mut());
|
|
825
843
|
};
|
|
826
844
|
|
|
827
845
|
with_mut_graph(pointer, |graph| {
|
|
846
|
+
let self_decl_id = unsafe { decl_id_from_char_ptr(self_receiver) };
|
|
847
|
+
|
|
828
848
|
run_and_finalize_completion(
|
|
829
849
|
graph,
|
|
830
|
-
CompletionReceiver::NamespaceAccess
|
|
850
|
+
CompletionReceiver::NamespaceAccess {
|
|
851
|
+
self_decl_id,
|
|
852
|
+
namespace_decl_id: DeclarationId::from(name_str.as_str()),
|
|
853
|
+
},
|
|
831
854
|
Vec::new(),
|
|
832
855
|
)
|
|
833
856
|
})
|
|
@@ -841,19 +864,27 @@ pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
|
|
|
841
864
|
///
|
|
842
865
|
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
843
866
|
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the receiver).
|
|
867
|
+
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. When non-null, it
|
|
868
|
+
/// is the caller's runtime self type, used for MRI-style visibility checks.
|
|
844
869
|
#[unsafe(no_mangle)]
|
|
845
870
|
pub unsafe extern "C" fn rdx_graph_complete_method_call(
|
|
846
871
|
pointer: GraphPointer,
|
|
847
872
|
name: *const c_char,
|
|
873
|
+
self_receiver: *const c_char,
|
|
848
874
|
) -> CompletionResult {
|
|
849
875
|
let Ok(name_str) = (unsafe { utils::convert_char_ptr_to_string(name) }) else {
|
|
850
876
|
return CompletionResult::success(ptr::null_mut());
|
|
851
877
|
};
|
|
852
878
|
|
|
853
879
|
with_mut_graph(pointer, |graph| {
|
|
880
|
+
let self_decl_id = unsafe { decl_id_from_char_ptr(self_receiver) };
|
|
881
|
+
|
|
854
882
|
run_and_finalize_completion(
|
|
855
883
|
graph,
|
|
856
|
-
CompletionReceiver::MethodCall
|
|
884
|
+
CompletionReceiver::MethodCall {
|
|
885
|
+
self_decl_id,
|
|
886
|
+
receiver_decl_id: DeclarationId::from(name_str.as_str()),
|
|
887
|
+
},
|
|
857
888
|
Vec::new(),
|
|
858
889
|
)
|
|
859
890
|
})
|
|
@@ -868,28 +899,34 @@ pub unsafe extern "C" fn rdx_graph_complete_method_call(
|
|
|
868
899
|
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
869
900
|
/// - `name` must be a valid, null-terminated UTF-8 string (FQN of the method).
|
|
870
901
|
/// - `nesting` must point to `nesting_count` valid, null-terminated UTF-8 strings.
|
|
902
|
+
/// - `self_receiver` must be null or a valid, null-terminated UTF-8 string. See
|
|
903
|
+
/// `rdx_graph_complete_expression` for semantics.
|
|
871
904
|
#[unsafe(no_mangle)]
|
|
872
905
|
pub unsafe extern "C" fn rdx_graph_complete_method_argument(
|
|
873
906
|
pointer: GraphPointer,
|
|
874
907
|
name: *const c_char,
|
|
875
908
|
nesting: *const *const c_char,
|
|
876
909
|
nesting_count: usize,
|
|
910
|
+
self_receiver: *const c_char,
|
|
877
911
|
) -> CompletionResult {
|
|
878
912
|
let Ok(name_str) = (unsafe { utils::convert_char_ptr_to_string(name) }) else {
|
|
879
913
|
return CompletionResult::success(ptr::null_mut());
|
|
880
914
|
};
|
|
881
915
|
|
|
882
916
|
with_mut_graph(pointer, |graph| {
|
|
883
|
-
let Some((
|
|
917
|
+
let Some((nesting_name_id, names_to_untrack)) =
|
|
884
918
|
(unsafe { completion_nesting_name_id(graph, nesting, nesting_count) })
|
|
885
919
|
else {
|
|
886
920
|
return CompletionResult::success(ptr::null_mut());
|
|
887
921
|
};
|
|
888
922
|
|
|
923
|
+
let self_decl_id = unsafe { decl_id_from_char_ptr(self_receiver) };
|
|
924
|
+
|
|
889
925
|
run_and_finalize_completion(
|
|
890
926
|
graph,
|
|
891
927
|
CompletionReceiver::MethodArgument {
|
|
892
|
-
|
|
928
|
+
self_decl_id,
|
|
929
|
+
nesting_name_id,
|
|
893
930
|
method_decl_id: DeclarationId::from(name_str.as_str()),
|
|
894
931
|
},
|
|
895
932
|
names_to_untrack,
|
|
@@ -942,6 +979,53 @@ pub unsafe extern "C" fn rdx_keyword_get(name: *const c_char) -> *const CKeyword
|
|
|
942
979
|
}
|
|
943
980
|
}
|
|
944
981
|
|
|
982
|
+
#[repr(u8)]
|
|
983
|
+
#[derive(Debug, Clone, Copy)]
|
|
984
|
+
pub enum CVisibility {
|
|
985
|
+
Public = 0,
|
|
986
|
+
Protected = 1,
|
|
987
|
+
Private = 2,
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
/// Returns the visibility of a declaration (method, constant, class, or module) as a heap-allocated
|
|
991
|
+
/// `CVisibility`, or NULL when the declaration carries no visibility (e.g. variables, singleton
|
|
992
|
+
/// classes, todos). Caller must free the returned pointer with `free_c_visibility`.
|
|
993
|
+
///
|
|
994
|
+
/// # Safety
|
|
995
|
+
///
|
|
996
|
+
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
997
|
+
#[unsafe(no_mangle)]
|
|
998
|
+
pub unsafe extern "C" fn rdx_graph_visibility(pointer: GraphPointer, declaration_id: u64) -> *const CVisibility {
|
|
999
|
+
with_graph(pointer, |graph| {
|
|
1000
|
+
let Some(visibility) = graph.visibility(&DeclarationId::new(declaration_id)) else {
|
|
1001
|
+
return ptr::null();
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
let c_visibility = match visibility {
|
|
1005
|
+
Visibility::Public => CVisibility::Public,
|
|
1006
|
+
Visibility::Protected => CVisibility::Protected,
|
|
1007
|
+
Visibility::Private => CVisibility::Private,
|
|
1008
|
+
Visibility::ModuleFunction => {
|
|
1009
|
+
unimplemented!("module_function visibility translation is not implemented yet")
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
Box::into_raw(Box::new(c_visibility)).cast_const()
|
|
1014
|
+
})
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/// Frees a `CVisibility` previously returned by `rdx_graph_visibility`.
|
|
1018
|
+
///
|
|
1019
|
+
/// # Safety
|
|
1020
|
+
///
|
|
1021
|
+
/// - `ptr` must be a valid pointer previously returned by `rdx_graph_visibility`.
|
|
1022
|
+
#[unsafe(no_mangle)]
|
|
1023
|
+
pub unsafe extern "C" fn free_c_visibility(ptr: *const CVisibility) {
|
|
1024
|
+
unsafe {
|
|
1025
|
+
let _ = Box::from_raw(ptr.cast_mut());
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
945
1029
|
/// Frees a `CKeyword` previously returned by `rdx_keyword_get`.
|
|
946
1030
|
///
|
|
947
1031
|
/// # Safety
|