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
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//! C API for method signature accessors
|
|
2
|
+
|
|
3
|
+
use crate::graph_api::{GraphPointer, with_graph};
|
|
4
|
+
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
5
|
+
use libc::c_char;
|
|
6
|
+
use rubydex::model::declaration::Declaration;
|
|
7
|
+
use rubydex::model::definitions::{Definition, MethodDefinition, Parameter};
|
|
8
|
+
use rubydex::model::graph::Graph;
|
|
9
|
+
use rubydex::model::ids::DefinitionId;
|
|
10
|
+
use std::ffi::CString;
|
|
11
|
+
use std::ptr;
|
|
12
|
+
|
|
13
|
+
/// C-compatible enum representing the kind of a parameter.
|
|
14
|
+
#[repr(C)]
|
|
15
|
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
16
|
+
pub enum ParameterKind {
|
|
17
|
+
RequiredPositional = 0,
|
|
18
|
+
OptionalPositional = 1,
|
|
19
|
+
RestPositional = 2,
|
|
20
|
+
Post = 3,
|
|
21
|
+
RequiredKeyword = 4,
|
|
22
|
+
OptionalKeyword = 5,
|
|
23
|
+
RestKeyword = 6,
|
|
24
|
+
Forward = 7,
|
|
25
|
+
Block = 8,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fn map_parameter_kind(param: &Parameter) -> ParameterKind {
|
|
29
|
+
match param {
|
|
30
|
+
Parameter::RequiredPositional(_) => ParameterKind::RequiredPositional,
|
|
31
|
+
Parameter::Post(_) => ParameterKind::Post,
|
|
32
|
+
Parameter::OptionalPositional(_) => ParameterKind::OptionalPositional,
|
|
33
|
+
Parameter::RestPositional(_) => ParameterKind::RestPositional,
|
|
34
|
+
Parameter::RequiredKeyword(_) => ParameterKind::RequiredKeyword,
|
|
35
|
+
Parameter::OptionalKeyword(_) => ParameterKind::OptionalKeyword,
|
|
36
|
+
Parameter::RestKeyword(_) => ParameterKind::RestKeyword,
|
|
37
|
+
Parameter::Block(_) => ParameterKind::Block,
|
|
38
|
+
Parameter::Forward(_) => ParameterKind::Forward,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// C-compatible struct representing a single parameter with its name, kind, and location.
|
|
43
|
+
#[repr(C)]
|
|
44
|
+
pub struct ParameterEntry {
|
|
45
|
+
pub name: *const c_char,
|
|
46
|
+
pub location: *mut Location,
|
|
47
|
+
pub kind: ParameterKind,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// C-compatible struct representing a single method signature (a list of parameters).
|
|
51
|
+
#[repr(C)]
|
|
52
|
+
pub struct SignatureEntry {
|
|
53
|
+
pub parameters: *mut ParameterEntry,
|
|
54
|
+
pub parameters_len: usize,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// C-compatible array of signatures.
|
|
58
|
+
#[repr(C)]
|
|
59
|
+
pub struct SignatureArray {
|
|
60
|
+
pub items: *mut SignatureEntry,
|
|
61
|
+
pub len: usize,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Returns a newly allocated array of signatures for the given method definition id.
|
|
65
|
+
/// Caller must free the returned pointer with `rdx_definition_signatures_free`.
|
|
66
|
+
///
|
|
67
|
+
/// # Safety
|
|
68
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
69
|
+
/// - `definition_id` must be a valid definition id.
|
|
70
|
+
///
|
|
71
|
+
/// # Panics
|
|
72
|
+
/// Panics if `definition_id` does not exist or is not a `MethodDefinition`.
|
|
73
|
+
#[unsafe(no_mangle)]
|
|
74
|
+
pub unsafe extern "C" fn rdx_definition_signatures(pointer: GraphPointer, definition_id: u64) -> *mut SignatureArray {
|
|
75
|
+
with_graph(pointer, |graph| {
|
|
76
|
+
let def_id = DefinitionId::new(definition_id);
|
|
77
|
+
let Definition::Method(method_def) = graph.definitions().get(&def_id).expect("definition should exist") else {
|
|
78
|
+
panic!("expected a method definition");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
let sig_entries = collect_method_signatures(graph, method_def);
|
|
82
|
+
|
|
83
|
+
let len = sig_entries.len();
|
|
84
|
+
let items_ptr = Box::into_raw(sig_entries.into_boxed_slice()).cast::<SignatureEntry>();
|
|
85
|
+
|
|
86
|
+
Box::into_raw(Box::new(SignatureArray { items: items_ptr, len }))
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Helper: build signature entries from a `MethodDefinition`.
|
|
91
|
+
fn collect_method_signatures(graph: &Graph, method_def: &MethodDefinition) -> Vec<SignatureEntry> {
|
|
92
|
+
let uri_id = *method_def.uri_id();
|
|
93
|
+
let document = graph.documents().get(&uri_id).expect("document should exist");
|
|
94
|
+
|
|
95
|
+
method_def
|
|
96
|
+
.signatures()
|
|
97
|
+
.as_slice()
|
|
98
|
+
.iter()
|
|
99
|
+
.map(|sig| {
|
|
100
|
+
let param_entries: Vec<ParameterEntry> = sig
|
|
101
|
+
.iter()
|
|
102
|
+
.map(|param| {
|
|
103
|
+
let param_struct = param.inner();
|
|
104
|
+
let name = graph
|
|
105
|
+
.strings()
|
|
106
|
+
.get(param_struct.str())
|
|
107
|
+
.expect("parameter name string should exist");
|
|
108
|
+
let name_str = CString::new(name.as_str()).unwrap().into_raw().cast_const();
|
|
109
|
+
|
|
110
|
+
ParameterEntry {
|
|
111
|
+
name: name_str,
|
|
112
|
+
kind: map_parameter_kind(param),
|
|
113
|
+
location: create_location_for_uri_and_offset(graph, document, param_struct.offset()),
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
.collect();
|
|
117
|
+
|
|
118
|
+
let parameters_len = param_entries.len();
|
|
119
|
+
let parameters_ptr = Box::into_raw(param_entries.into_boxed_slice()).cast::<ParameterEntry>();
|
|
120
|
+
|
|
121
|
+
SignatureEntry {
|
|
122
|
+
parameters: parameters_ptr,
|
|
123
|
+
parameters_len,
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
.collect()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Returns signatures for a `MethodAliasDefinition` by following the alias chain.
|
|
130
|
+
/// Always returns a valid `SignatureArray` pointer (possibly with `len == 0`).
|
|
131
|
+
/// Errors during alias resolution (unresolved receivers, circular chains, etc.)
|
|
132
|
+
/// are silently ignored.
|
|
133
|
+
///
|
|
134
|
+
/// # Safety
|
|
135
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
136
|
+
/// - `definition_id` must be a valid definition id.
|
|
137
|
+
///
|
|
138
|
+
/// # Panics
|
|
139
|
+
/// Panics if `definition_id` does not exist or is not a `MethodAliasDefinition`.
|
|
140
|
+
#[unsafe(no_mangle)]
|
|
141
|
+
pub unsafe extern "C" fn rdx_method_alias_definition_signatures(
|
|
142
|
+
pointer: GraphPointer,
|
|
143
|
+
definition_id: u64,
|
|
144
|
+
) -> *mut SignatureArray {
|
|
145
|
+
with_graph(pointer, |graph| {
|
|
146
|
+
let def_id = DefinitionId::new(definition_id);
|
|
147
|
+
let resolved = rubydex::query::follow_method_alias(graph, def_id);
|
|
148
|
+
|
|
149
|
+
let mut sig_entries: Vec<SignatureEntry> = Vec::new();
|
|
150
|
+
|
|
151
|
+
if let Ok(declaration_id) = resolved {
|
|
152
|
+
if let Some(Declaration::Method(method_def)) = graph.declarations().get(&declaration_id) {
|
|
153
|
+
for definition_id in method_def.definitions() {
|
|
154
|
+
if let Some(Definition::Method(method_definition)) = graph.definitions().get(definition_id) {
|
|
155
|
+
sig_entries.extend(collect_method_signatures(graph, method_definition));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
panic!("expected a method declaration");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let mut boxed = sig_entries.into_boxed_slice();
|
|
164
|
+
let len = boxed.len();
|
|
165
|
+
let items_ptr = boxed.as_mut_ptr();
|
|
166
|
+
std::mem::forget(boxed);
|
|
167
|
+
|
|
168
|
+
Box::into_raw(Box::new(SignatureArray { items: items_ptr, len }))
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// Frees a `SignatureArray` previously returned by `rdx_definition_signatures`.
|
|
173
|
+
///
|
|
174
|
+
/// # Safety
|
|
175
|
+
/// - `ptr` must be a valid pointer previously returned by `rdx_definition_signatures`.
|
|
176
|
+
/// - `ptr` must not be used after being freed.
|
|
177
|
+
#[unsafe(no_mangle)]
|
|
178
|
+
pub unsafe extern "C" fn rdx_definition_signatures_free(ptr: *mut SignatureArray) {
|
|
179
|
+
if ptr.is_null() {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
let arr = unsafe { Box::from_raw(ptr) };
|
|
184
|
+
|
|
185
|
+
if arr.items.is_null() || arr.len == 0 {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
let slice_ptr = ptr::slice_from_raw_parts_mut(arr.items, arr.len);
|
|
190
|
+
let sig_slice: Box<[SignatureEntry]> = unsafe { Box::from_raw(slice_ptr) };
|
|
191
|
+
|
|
192
|
+
for sig_entry in &*sig_slice {
|
|
193
|
+
if sig_entry.parameters.is_null() || sig_entry.parameters_len == 0 {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
let param_slice_ptr = ptr::slice_from_raw_parts_mut(sig_entry.parameters, sig_entry.parameters_len);
|
|
198
|
+
let param_slice: Box<[ParameterEntry]> = unsafe { Box::from_raw(param_slice_ptr) };
|
|
199
|
+
|
|
200
|
+
for param_entry in &*param_slice {
|
|
201
|
+
if !param_entry.name.is_null() {
|
|
202
|
+
drop(unsafe { CString::from_raw(param_entry.name.cast_mut()) });
|
|
203
|
+
}
|
|
204
|
+
if !param_entry.location.is_null() {
|
|
205
|
+
unsafe { crate::location_api::rdx_location_free(param_entry.location) };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubydex
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A high-performance static analysis suite for Ruby, built in Rust with
|
|
14
14
|
Ruby APIs
|
|
@@ -41,6 +41,8 @@ files:
|
|
|
41
41
|
- ext/rubydex/reference.c
|
|
42
42
|
- ext/rubydex/reference.h
|
|
43
43
|
- ext/rubydex/rubydex.c
|
|
44
|
+
- ext/rubydex/signature.c
|
|
45
|
+
- ext/rubydex/signature.h
|
|
44
46
|
- ext/rubydex/utils.c
|
|
45
47
|
- ext/rubydex/utils.h
|
|
46
48
|
- lib/rubydex.rb
|
|
@@ -53,6 +55,7 @@ files:
|
|
|
53
55
|
- lib/rubydex/keyword_parameter.rb
|
|
54
56
|
- lib/rubydex/location.rb
|
|
55
57
|
- lib/rubydex/mixin.rb
|
|
58
|
+
- lib/rubydex/signature.rb
|
|
56
59
|
- lib/rubydex/version.rb
|
|
57
60
|
- rbi/rubydex.rbi
|
|
58
61
|
- rust/Cargo.lock
|
|
@@ -77,6 +80,7 @@ files:
|
|
|
77
80
|
- rust/rubydex-sys/src/location_api.rs
|
|
78
81
|
- rust/rubydex-sys/src/name_api.rs
|
|
79
82
|
- rust/rubydex-sys/src/reference_api.rs
|
|
83
|
+
- rust/rubydex-sys/src/signature_api.rs
|
|
80
84
|
- rust/rubydex-sys/src/utils.rs
|
|
81
85
|
- rust/rubydex/Cargo.toml
|
|
82
86
|
- rust/rubydex/src/compile_assertions.rs
|