rubydex 0.1.0.beta12-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.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +125 -0
- data/THIRD_PARTY_LICENSES.html +4562 -0
- data/exe/rdx +47 -0
- data/ext/rubydex/declaration.c +453 -0
- data/ext/rubydex/declaration.h +23 -0
- data/ext/rubydex/definition.c +284 -0
- data/ext/rubydex/definition.h +28 -0
- data/ext/rubydex/diagnostic.c +6 -0
- data/ext/rubydex/diagnostic.h +11 -0
- data/ext/rubydex/document.c +97 -0
- data/ext/rubydex/document.h +10 -0
- data/ext/rubydex/extconf.rb +138 -0
- data/ext/rubydex/graph.c +681 -0
- data/ext/rubydex/graph.h +10 -0
- data/ext/rubydex/handle.h +44 -0
- data/ext/rubydex/location.c +22 -0
- data/ext/rubydex/location.h +15 -0
- data/ext/rubydex/reference.c +123 -0
- data/ext/rubydex/reference.h +15 -0
- data/ext/rubydex/rubydex.c +22 -0
- data/ext/rubydex/utils.c +108 -0
- data/ext/rubydex/utils.h +34 -0
- data/lib/rubydex/3.2/rubydex.so +0 -0
- data/lib/rubydex/3.3/rubydex.so +0 -0
- data/lib/rubydex/3.4/rubydex.so +0 -0
- data/lib/rubydex/4.0/rubydex.so +0 -0
- data/lib/rubydex/comment.rb +17 -0
- data/lib/rubydex/diagnostic.rb +21 -0
- data/lib/rubydex/failures.rb +15 -0
- data/lib/rubydex/graph.rb +98 -0
- data/lib/rubydex/keyword.rb +17 -0
- data/lib/rubydex/keyword_parameter.rb +13 -0
- data/lib/rubydex/librubydex_sys.so +0 -0
- data/lib/rubydex/location.rb +90 -0
- data/lib/rubydex/mixin.rb +22 -0
- data/lib/rubydex/version.rb +5 -0
- data/lib/rubydex.rb +23 -0
- data/rbi/rubydex.rbi +422 -0
- data/rust/Cargo.lock +1851 -0
- data/rust/Cargo.toml +29 -0
- data/rust/about.hbs +78 -0
- data/rust/about.toml +10 -0
- data/rust/rubydex/Cargo.toml +42 -0
- data/rust/rubydex/src/compile_assertions.rs +13 -0
- data/rust/rubydex/src/diagnostic.rs +110 -0
- data/rust/rubydex/src/errors.rs +28 -0
- data/rust/rubydex/src/indexing/local_graph.rs +224 -0
- data/rust/rubydex/src/indexing/rbs_indexer.rs +1551 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +2329 -0
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +4962 -0
- data/rust/rubydex/src/indexing.rs +210 -0
- data/rust/rubydex/src/integrity.rs +279 -0
- data/rust/rubydex/src/job_queue.rs +205 -0
- data/rust/rubydex/src/lib.rs +17 -0
- data/rust/rubydex/src/listing.rs +371 -0
- data/rust/rubydex/src/main.rs +160 -0
- data/rust/rubydex/src/model/built_in.rs +83 -0
- data/rust/rubydex/src/model/comment.rs +24 -0
- data/rust/rubydex/src/model/declaration.rs +671 -0
- data/rust/rubydex/src/model/definitions.rs +1682 -0
- data/rust/rubydex/src/model/document.rs +222 -0
- data/rust/rubydex/src/model/encoding.rs +22 -0
- data/rust/rubydex/src/model/graph.rs +3754 -0
- data/rust/rubydex/src/model/id.rs +110 -0
- data/rust/rubydex/src/model/identity_maps.rs +58 -0
- data/rust/rubydex/src/model/ids.rs +60 -0
- data/rust/rubydex/src/model/keywords.rs +256 -0
- data/rust/rubydex/src/model/name.rs +298 -0
- data/rust/rubydex/src/model/references.rs +111 -0
- data/rust/rubydex/src/model/string_ref.rs +50 -0
- data/rust/rubydex/src/model/visibility.rs +41 -0
- data/rust/rubydex/src/model.rs +15 -0
- data/rust/rubydex/src/offset.rs +147 -0
- data/rust/rubydex/src/position.rs +6 -0
- data/rust/rubydex/src/query.rs +1841 -0
- data/rust/rubydex/src/resolution.rs +6517 -0
- data/rust/rubydex/src/stats/memory.rs +71 -0
- data/rust/rubydex/src/stats/orphan_report.rs +264 -0
- data/rust/rubydex/src/stats/timer.rs +127 -0
- data/rust/rubydex/src/stats.rs +11 -0
- data/rust/rubydex/src/test_utils/context.rs +226 -0
- data/rust/rubydex/src/test_utils/graph_test.rs +730 -0
- data/rust/rubydex/src/test_utils/local_graph_test.rs +602 -0
- data/rust/rubydex/src/test_utils.rs +52 -0
- data/rust/rubydex/src/visualization/dot.rs +192 -0
- data/rust/rubydex/src/visualization.rs +6 -0
- data/rust/rubydex/tests/cli.rs +185 -0
- data/rust/rubydex-mcp/Cargo.toml +28 -0
- data/rust/rubydex-mcp/src/main.rs +48 -0
- data/rust/rubydex-mcp/src/server.rs +1145 -0
- data/rust/rubydex-mcp/src/tools.rs +49 -0
- data/rust/rubydex-mcp/tests/mcp.rs +302 -0
- data/rust/rubydex-sys/Cargo.toml +20 -0
- data/rust/rubydex-sys/build.rs +14 -0
- data/rust/rubydex-sys/cbindgen.toml +12 -0
- data/rust/rubydex-sys/src/declaration_api.rs +485 -0
- data/rust/rubydex-sys/src/definition_api.rs +443 -0
- data/rust/rubydex-sys/src/diagnostic_api.rs +99 -0
- data/rust/rubydex-sys/src/document_api.rs +85 -0
- data/rust/rubydex-sys/src/graph_api.rs +948 -0
- data/rust/rubydex-sys/src/lib.rs +79 -0
- data/rust/rubydex-sys/src/location_api.rs +79 -0
- data/rust/rubydex-sys/src/name_api.rs +135 -0
- data/rust/rubydex-sys/src/reference_api.rs +267 -0
- data/rust/rubydex-sys/src/utils.rs +70 -0
- data/rust/rustfmt.toml +2 -0
- metadata +159 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
//! This file provides the C API for Definition accessors
|
|
2
|
+
|
|
3
|
+
use crate::graph_api::{GraphPointer, with_graph};
|
|
4
|
+
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
5
|
+
use crate::reference_api::CConstantReference;
|
|
6
|
+
use libc::c_char;
|
|
7
|
+
use rubydex::model::definitions::{Definition, Mixin};
|
|
8
|
+
use rubydex::model::ids::DefinitionId;
|
|
9
|
+
use std::ffi::CString;
|
|
10
|
+
use std::ptr;
|
|
11
|
+
|
|
12
|
+
/// C-compatible enum representing the kind of a definition.
|
|
13
|
+
#[repr(C)]
|
|
14
|
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
15
|
+
pub enum DefinitionKind {
|
|
16
|
+
Class = 0,
|
|
17
|
+
SingletonClass = 1,
|
|
18
|
+
Module = 2,
|
|
19
|
+
Constant = 3,
|
|
20
|
+
ConstantAlias = 4,
|
|
21
|
+
ConstantVisibility = 5,
|
|
22
|
+
MethodVisibility = 6,
|
|
23
|
+
Method = 7,
|
|
24
|
+
AttrAccessor = 8,
|
|
25
|
+
AttrReader = 9,
|
|
26
|
+
AttrWriter = 10,
|
|
27
|
+
GlobalVariable = 11,
|
|
28
|
+
InstanceVariable = 12,
|
|
29
|
+
ClassVariable = 13,
|
|
30
|
+
MethodAlias = 14,
|
|
31
|
+
GlobalVariableAlias = 15,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[repr(C)]
|
|
35
|
+
#[derive(Debug, Clone, Copy)]
|
|
36
|
+
pub struct CDefinition {
|
|
37
|
+
pub id: u64,
|
|
38
|
+
pub kind: DefinitionKind,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub(crate) fn map_definition_to_kind(defn: &Definition) -> DefinitionKind {
|
|
42
|
+
match defn {
|
|
43
|
+
Definition::Class(_) => DefinitionKind::Class,
|
|
44
|
+
Definition::SingletonClass(_) => DefinitionKind::SingletonClass,
|
|
45
|
+
Definition::Module(_) => DefinitionKind::Module,
|
|
46
|
+
Definition::Constant(_) => DefinitionKind::Constant,
|
|
47
|
+
Definition::ConstantAlias(_) => DefinitionKind::ConstantAlias,
|
|
48
|
+
Definition::ConstantVisibility(_) => DefinitionKind::ConstantVisibility,
|
|
49
|
+
Definition::MethodVisibility(_) => DefinitionKind::MethodVisibility,
|
|
50
|
+
Definition::Method(_) => DefinitionKind::Method,
|
|
51
|
+
Definition::AttrAccessor(_) => DefinitionKind::AttrAccessor,
|
|
52
|
+
Definition::AttrReader(_) => DefinitionKind::AttrReader,
|
|
53
|
+
Definition::AttrWriter(_) => DefinitionKind::AttrWriter,
|
|
54
|
+
Definition::GlobalVariable(_) => DefinitionKind::GlobalVariable,
|
|
55
|
+
Definition::InstanceVariable(_) => DefinitionKind::InstanceVariable,
|
|
56
|
+
Definition::ClassVariable(_) => DefinitionKind::ClassVariable,
|
|
57
|
+
Definition::MethodAlias(_) => DefinitionKind::MethodAlias,
|
|
58
|
+
Definition::GlobalVariableAlias(_) => DefinitionKind::GlobalVariableAlias,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// Returns the enum kind for a definition id (e.g. Class, Module).
|
|
63
|
+
///
|
|
64
|
+
/// # Safety
|
|
65
|
+
///
|
|
66
|
+
/// Assumes pointer is valid.
|
|
67
|
+
///
|
|
68
|
+
/// # Panics
|
|
69
|
+
///
|
|
70
|
+
/// This function will panic if the definition cannot be found.
|
|
71
|
+
#[unsafe(no_mangle)]
|
|
72
|
+
pub unsafe extern "C" fn rdx_definition_kind(pointer: GraphPointer, definition_id: u64) -> DefinitionKind {
|
|
73
|
+
with_graph(pointer, |graph| {
|
|
74
|
+
let definition_id = DefinitionId::new(definition_id);
|
|
75
|
+
if let Some(defn) = graph.definitions().get(&definition_id) {
|
|
76
|
+
map_definition_to_kind(defn)
|
|
77
|
+
} else {
|
|
78
|
+
panic!("Definition not found: {definition_id:?}");
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Returns the UTF-8 unqualified name string for a definition id.
|
|
84
|
+
/// Caller must free with `free_c_string`.
|
|
85
|
+
///
|
|
86
|
+
/// # Safety
|
|
87
|
+
///
|
|
88
|
+
/// Assumes pointer is valid.
|
|
89
|
+
///
|
|
90
|
+
/// # Panics
|
|
91
|
+
///
|
|
92
|
+
/// This function will panic if the definition cannot be found.
|
|
93
|
+
#[unsafe(no_mangle)]
|
|
94
|
+
pub unsafe extern "C" fn rdx_definition_name(pointer: GraphPointer, definition_id: u64) -> *const c_char {
|
|
95
|
+
with_graph(pointer, |graph| {
|
|
96
|
+
let def_id = DefinitionId::new(definition_id);
|
|
97
|
+
if let Some(defn) = graph.definitions().get(&def_id) {
|
|
98
|
+
let string_id = graph.definition_string_id(defn);
|
|
99
|
+
|
|
100
|
+
if let Some(name) = graph.strings().get(&string_id) {
|
|
101
|
+
CString::new(name.as_str()).unwrap().into_raw().cast_const()
|
|
102
|
+
} else {
|
|
103
|
+
ptr::null()
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
ptr::null()
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// Shared iterator over definition (id, kind) pairs
|
|
112
|
+
#[derive(Debug)]
|
|
113
|
+
pub struct DefinitionsIter {
|
|
114
|
+
entries: Box<[CDefinition]>,
|
|
115
|
+
index: usize,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
iterator!(DefinitionsIter, entries: CDefinition);
|
|
119
|
+
|
|
120
|
+
/// # Safety
|
|
121
|
+
/// `iter` must be a valid pointer previously returned by `DefinitionsIter::new`.
|
|
122
|
+
#[unsafe(no_mangle)]
|
|
123
|
+
pub unsafe extern "C" fn rdx_definitions_iter_len(iter: *const DefinitionsIter) -> usize {
|
|
124
|
+
unsafe { DefinitionsIter::len(iter) }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// # Safety
|
|
128
|
+
/// - `iter` must be a valid pointer previously returned by `DefinitionsIter::new`.
|
|
129
|
+
/// - `out` must be a valid, writable pointer.
|
|
130
|
+
#[unsafe(no_mangle)]
|
|
131
|
+
pub unsafe extern "C" fn rdx_definitions_iter_next(iter: *mut DefinitionsIter, out: *mut CDefinition) -> bool {
|
|
132
|
+
unsafe { DefinitionsIter::next(iter, out) }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/// # Safety
|
|
136
|
+
/// - `iter` must be a pointer previously returned by `DefinitionsIter::new`.
|
|
137
|
+
/// - `iter` must not be used after being freed.
|
|
138
|
+
#[unsafe(no_mangle)]
|
|
139
|
+
pub unsafe extern "C" fn rdx_definitions_iter_free(iter: *mut DefinitionsIter) {
|
|
140
|
+
unsafe { DefinitionsIter::free(iter) }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// C-compatible struct representing a single comment with its string and location
|
|
144
|
+
#[repr(C)]
|
|
145
|
+
pub struct CommentEntry {
|
|
146
|
+
pub string: *const c_char,
|
|
147
|
+
pub location: *mut Location,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/// C-compatible array of comments
|
|
151
|
+
#[repr(C)]
|
|
152
|
+
pub struct CommentArray {
|
|
153
|
+
pub items: *mut CommentEntry,
|
|
154
|
+
pub len: usize,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/// Returns a newly allocated array of comments (string and location) for the given definition id.
|
|
158
|
+
/// Caller must free the returned pointer with `rdx_definition_comments_free` and each inner string with `free_c_string` if needed.
|
|
159
|
+
///
|
|
160
|
+
/// # Safety
|
|
161
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
162
|
+
/// - `definition_id` must be a valid definition id.
|
|
163
|
+
///
|
|
164
|
+
/// # Panics
|
|
165
|
+
/// This function will panic if a definition or document cannot be found.
|
|
166
|
+
#[unsafe(no_mangle)]
|
|
167
|
+
pub unsafe extern "C" fn rdx_definition_comments(pointer: GraphPointer, definition_id: u64) -> *mut CommentArray {
|
|
168
|
+
with_graph(pointer, |graph| {
|
|
169
|
+
let def_id = DefinitionId::new(definition_id);
|
|
170
|
+
let Some(defn) = graph.definitions().get(&def_id) else {
|
|
171
|
+
panic!("Definition not found: {definition_id:?}");
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
let uri_id = *defn.uri_id();
|
|
175
|
+
let document = graph.documents().get(&uri_id).expect("document should exist");
|
|
176
|
+
|
|
177
|
+
let mut entries = defn
|
|
178
|
+
.comments()
|
|
179
|
+
.iter()
|
|
180
|
+
.map(|c| CommentEntry {
|
|
181
|
+
string: CString::new(c.string().as_str()).unwrap().into_raw().cast_const(),
|
|
182
|
+
location: create_location_for_uri_and_offset(graph, document, c.offset()),
|
|
183
|
+
})
|
|
184
|
+
.collect::<Vec<CommentEntry>>()
|
|
185
|
+
.into_boxed_slice();
|
|
186
|
+
|
|
187
|
+
let len = entries.len();
|
|
188
|
+
let items_ptr = entries.as_mut_ptr();
|
|
189
|
+
std::mem::forget(entries);
|
|
190
|
+
|
|
191
|
+
Box::into_raw(Box::new(CommentArray { items: items_ptr, len }))
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/// Frees a `CommentArray` previously returned by `rdx_definition_comments`.
|
|
196
|
+
///
|
|
197
|
+
/// # Safety
|
|
198
|
+
/// - `ptr` must be a valid pointer previously returned by `rdx_definition_comments`.
|
|
199
|
+
/// - `ptr` must not be used after being freed.
|
|
200
|
+
#[unsafe(no_mangle)]
|
|
201
|
+
pub unsafe extern "C" fn rdx_definition_comments_free(ptr: *mut CommentArray) {
|
|
202
|
+
if ptr.is_null() {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Take ownership of the CommentArray
|
|
207
|
+
let arr = unsafe { Box::from_raw(ptr) };
|
|
208
|
+
|
|
209
|
+
if !arr.items.is_null() && arr.len > 0 {
|
|
210
|
+
// Reconstruct the boxed slice so we can drop it after freeing inner allocations
|
|
211
|
+
let slice_ptr = ptr::slice_from_raw_parts_mut(arr.items, arr.len);
|
|
212
|
+
let mut boxed_slice: Box<[CommentEntry]> = unsafe { Box::from_raw(slice_ptr) };
|
|
213
|
+
|
|
214
|
+
for item in &mut boxed_slice {
|
|
215
|
+
if !item.string.is_null() {
|
|
216
|
+
// Free the CString allocated for the comment string
|
|
217
|
+
let _ = unsafe { CString::from_raw(item.string.cast_mut()) };
|
|
218
|
+
}
|
|
219
|
+
if !item.location.is_null() {
|
|
220
|
+
unsafe { crate::location_api::rdx_location_free(item.location) };
|
|
221
|
+
item.location = ptr::null_mut();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// boxed_slice is dropped here, freeing the items buffer
|
|
226
|
+
}
|
|
227
|
+
// arr is dropped here
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/// Returns a newly allocated `Location` for the given definition id.
|
|
231
|
+
/// Caller must free the returned pointer with `rdx_location_free`.
|
|
232
|
+
///
|
|
233
|
+
/// # Safety
|
|
234
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
235
|
+
/// - `definition_id` must be a valid definition id.
|
|
236
|
+
///
|
|
237
|
+
/// # Panics
|
|
238
|
+
///
|
|
239
|
+
/// This function will panic if a definition or document cannot be found.
|
|
240
|
+
#[unsafe(no_mangle)]
|
|
241
|
+
pub unsafe extern "C" fn rdx_definition_location(pointer: GraphPointer, definition_id: u64) -> *mut Location {
|
|
242
|
+
with_graph(pointer, |graph| {
|
|
243
|
+
let def_id = DefinitionId::new(definition_id);
|
|
244
|
+
let Some(defn) = graph.definitions().get(&def_id) else {
|
|
245
|
+
panic!("Definition not found: {definition_id:?}");
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
let document = graph.documents().get(defn.uri_id()).expect("document should exist");
|
|
249
|
+
create_location_for_uri_and_offset(graph, document, defn.offset())
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// Creates a new iterator over definition IDs for a given declaration by snapshotting the current set of IDs.
|
|
254
|
+
///
|
|
255
|
+
/// # Panics
|
|
256
|
+
///
|
|
257
|
+
/// This function will panic if a definition cannot be found.
|
|
258
|
+
pub(crate) fn rdx_definitions_iter_new_from_ids<'a, I>(
|
|
259
|
+
graph: &rubydex::model::graph::Graph,
|
|
260
|
+
ids: I,
|
|
261
|
+
) -> *mut DefinitionsIter
|
|
262
|
+
where
|
|
263
|
+
I: IntoIterator<Item = &'a DefinitionId>,
|
|
264
|
+
{
|
|
265
|
+
let entries = ids
|
|
266
|
+
.into_iter()
|
|
267
|
+
.map(|def_id| {
|
|
268
|
+
let id = **def_id;
|
|
269
|
+
let kind = graph
|
|
270
|
+
.definitions()
|
|
271
|
+
.get(&DefinitionId::new(id))
|
|
272
|
+
.map_or_else(|| panic!("Definition not found: {id:?}"), map_definition_to_kind);
|
|
273
|
+
CDefinition { id, kind }
|
|
274
|
+
})
|
|
275
|
+
.collect::<Vec<_>>()
|
|
276
|
+
.into_boxed_slice();
|
|
277
|
+
|
|
278
|
+
DefinitionsIter::new(entries)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/// Returns true if the definition is deprecated.
|
|
282
|
+
///
|
|
283
|
+
/// # Safety
|
|
284
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
285
|
+
/// - `definition_id` must be a valid definition id.
|
|
286
|
+
///
|
|
287
|
+
/// # Panics
|
|
288
|
+
/// This function will panic if a definition cannot be found.
|
|
289
|
+
#[unsafe(no_mangle)]
|
|
290
|
+
pub unsafe extern "C" fn rdx_definition_is_deprecated(pointer: GraphPointer, definition_id: u64) -> bool {
|
|
291
|
+
with_graph(pointer, |graph| {
|
|
292
|
+
let def_id = DefinitionId::new(definition_id);
|
|
293
|
+
let defn = graph.definitions().get(&def_id).expect("definition not found");
|
|
294
|
+
defn.is_deprecated()
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// Returns a newly allocated `Location` for the name portion of a definition id.
|
|
299
|
+
/// For class, module, and singleton class definitions, this returns the location of just
|
|
300
|
+
/// the name (e.g., "Bar" in `class Foo::Bar`).
|
|
301
|
+
/// For other definition types, returns NULL.
|
|
302
|
+
/// Caller must free the returned pointer with `rdx_location_free`.
|
|
303
|
+
///
|
|
304
|
+
/// # Safety
|
|
305
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
306
|
+
/// - `definition_id` must be a valid definition id.
|
|
307
|
+
///
|
|
308
|
+
/// # Panics
|
|
309
|
+
/// Panics if the definition's document does not exist in the graph.
|
|
310
|
+
#[unsafe(no_mangle)]
|
|
311
|
+
pub unsafe extern "C" fn rdx_definition_name_location(pointer: GraphPointer, definition_id: u64) -> *mut Location {
|
|
312
|
+
with_graph(pointer, |graph| {
|
|
313
|
+
let def_id = DefinitionId::new(definition_id);
|
|
314
|
+
let Some(defn) = graph.definitions().get(&def_id) else {
|
|
315
|
+
return ptr::null_mut();
|
|
316
|
+
};
|
|
317
|
+
let Some(name_offset) = defn.name_offset() else {
|
|
318
|
+
return ptr::null_mut();
|
|
319
|
+
};
|
|
320
|
+
let document = graph.documents().get(defn.uri_id()).expect("document should exist");
|
|
321
|
+
create_location_for_uri_and_offset(graph, document, name_offset)
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/// Returns the superclass constant reference for a class definition, or NULL if the class has no superclass. Caller
|
|
326
|
+
/// must free with `free_c_constant_reference`.
|
|
327
|
+
///
|
|
328
|
+
/// # Safety
|
|
329
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
330
|
+
/// - `definition_id` must be a valid definition id for a class definition.
|
|
331
|
+
///
|
|
332
|
+
/// # Panics
|
|
333
|
+
/// This function will panic if the definition cannot be found or is not a class definition.
|
|
334
|
+
#[unsafe(no_mangle)]
|
|
335
|
+
pub unsafe extern "C" fn rdx_class_definition_superclass(
|
|
336
|
+
pointer: GraphPointer,
|
|
337
|
+
definition_id: u64,
|
|
338
|
+
) -> *const CConstantReference {
|
|
339
|
+
with_graph(pointer, |graph| {
|
|
340
|
+
let def_id = DefinitionId::new(definition_id);
|
|
341
|
+
let defn = graph.definitions().get(&def_id).expect("Definition not found");
|
|
342
|
+
|
|
343
|
+
let Definition::Class(class_def) = defn else {
|
|
344
|
+
panic!("Definition is not a class: {definition_id}");
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
let Some(ref_id) = class_def.superclass_ref() else {
|
|
348
|
+
return ptr::null();
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
Box::into_raw(Box::new(CConstantReference::from_id(graph, *ref_id))).cast_const()
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/// C-compatible enum representing the kind of a mixin.
|
|
356
|
+
#[repr(C)]
|
|
357
|
+
#[derive(Debug, Clone, Copy)]
|
|
358
|
+
pub enum MixinKind {
|
|
359
|
+
Include = 0,
|
|
360
|
+
Prepend = 1,
|
|
361
|
+
Extend = 2,
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/// C-compatible struct representing a mixin (kind + constant reference).
|
|
365
|
+
#[repr(C)]
|
|
366
|
+
#[derive(Debug, Clone, Copy)]
|
|
367
|
+
pub struct CMixin {
|
|
368
|
+
pub kind: MixinKind,
|
|
369
|
+
pub constant_reference: CConstantReference,
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#[derive(Debug)]
|
|
373
|
+
pub struct MixinsIter {
|
|
374
|
+
entries: Box<[CMixin]>,
|
|
375
|
+
index: usize,
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
iterator!(MixinsIter, entries: CMixin);
|
|
379
|
+
|
|
380
|
+
/// # Safety
|
|
381
|
+
/// `iter` must be a valid pointer previously returned by `rdx_definition_mixins`.
|
|
382
|
+
#[unsafe(no_mangle)]
|
|
383
|
+
pub unsafe extern "C" fn rdx_mixins_iter_len(iter: *const MixinsIter) -> usize {
|
|
384
|
+
unsafe { MixinsIter::len(iter) }
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/// # Safety
|
|
388
|
+
/// - `iter` must be a valid pointer previously returned by `rdx_definition_mixins`.
|
|
389
|
+
/// - `out` must be a valid, writable pointer.
|
|
390
|
+
#[unsafe(no_mangle)]
|
|
391
|
+
pub unsafe extern "C" fn rdx_mixins_iter_next(iter: *mut MixinsIter, out: *mut CMixin) -> bool {
|
|
392
|
+
unsafe { MixinsIter::next(iter, out) }
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/// # Safety
|
|
396
|
+
/// - `iter` must be a pointer previously returned by `rdx_definition_mixins`.
|
|
397
|
+
/// - `iter` must not be used after being freed.
|
|
398
|
+
#[unsafe(no_mangle)]
|
|
399
|
+
pub unsafe extern "C" fn rdx_mixins_iter_free(iter: *mut MixinsIter) {
|
|
400
|
+
unsafe { MixinsIter::free(iter) }
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
fn map_mixin_kind(mixin: &Mixin) -> MixinKind {
|
|
404
|
+
match mixin {
|
|
405
|
+
Mixin::Include(_) => MixinKind::Include,
|
|
406
|
+
Mixin::Prepend(_) => MixinKind::Prepend,
|
|
407
|
+
Mixin::Extend(_) => MixinKind::Extend,
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/// Returns an iterator over the mixins for a definition (class, module, or singleton class).
|
|
412
|
+
/// Returns NULL for definition types that do not support mixins.
|
|
413
|
+
///
|
|
414
|
+
/// # Safety
|
|
415
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
416
|
+
/// - `definition_id` must be a valid definition id.
|
|
417
|
+
///
|
|
418
|
+
/// # Panics
|
|
419
|
+
/// This function will panic if the definition cannot be found.
|
|
420
|
+
#[unsafe(no_mangle)]
|
|
421
|
+
pub unsafe extern "C" fn rdx_definition_mixins(pointer: GraphPointer, definition_id: u64) -> *mut MixinsIter {
|
|
422
|
+
with_graph(pointer, |graph| {
|
|
423
|
+
let def_id = DefinitionId::new(definition_id);
|
|
424
|
+
let defn = graph.definitions().get(&def_id).expect("Definition not found");
|
|
425
|
+
|
|
426
|
+
let mixins = match defn {
|
|
427
|
+
Definition::Class(class_def) => class_def.mixins(),
|
|
428
|
+
Definition::Module(mod_def) => mod_def.mixins(),
|
|
429
|
+
Definition::SingletonClass(singleton_def) => singleton_def.mixins(),
|
|
430
|
+
_ => return ptr::null_mut(),
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
let entries: Vec<CMixin> = mixins
|
|
434
|
+
.iter()
|
|
435
|
+
.map(|mixin| CMixin {
|
|
436
|
+
kind: map_mixin_kind(mixin),
|
|
437
|
+
constant_reference: CConstantReference::from_id(graph, *mixin.constant_reference_id()),
|
|
438
|
+
})
|
|
439
|
+
.collect();
|
|
440
|
+
|
|
441
|
+
MixinsIter::new(entries.into_boxed_slice())
|
|
442
|
+
})
|
|
443
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//! Diagnostics-related FFI helpers
|
|
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 std::{ffi::CString, mem, ptr};
|
|
7
|
+
|
|
8
|
+
/// C-compatible struct representing a diagnostic entry.
|
|
9
|
+
#[repr(C)]
|
|
10
|
+
pub struct DiagnosticEntry {
|
|
11
|
+
pub rule: *const c_char,
|
|
12
|
+
pub message: *const c_char,
|
|
13
|
+
pub location: *mut Location,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// C-compatible array wrapper for diagnostics.
|
|
17
|
+
#[repr(C)]
|
|
18
|
+
pub struct DiagnosticArray {
|
|
19
|
+
pub items: *mut DiagnosticEntry,
|
|
20
|
+
pub len: usize,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
impl DiagnosticArray {
|
|
24
|
+
fn from_vec(mut entries: Vec<DiagnosticEntry>) -> *mut DiagnosticArray {
|
|
25
|
+
let len = entries.len();
|
|
26
|
+
let ptr = entries.as_mut_ptr();
|
|
27
|
+
mem::forget(entries);
|
|
28
|
+
Box::into_raw(Box::new(DiagnosticArray { items: ptr, len }))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Returns all diagnostics currently recorded in the global graph.
|
|
33
|
+
///
|
|
34
|
+
/// # Safety
|
|
35
|
+
///
|
|
36
|
+
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
37
|
+
/// - The pointed graph must remain alive for the duration of the call.
|
|
38
|
+
///
|
|
39
|
+
/// # Panics
|
|
40
|
+
///
|
|
41
|
+
/// - If a diagnostic references a URI whose file cannot be read to build a location.
|
|
42
|
+
#[unsafe(no_mangle)]
|
|
43
|
+
pub unsafe extern "C" fn rdx_graph_diagnostics(pointer: GraphPointer) -> *mut DiagnosticArray {
|
|
44
|
+
with_graph(pointer, |graph| {
|
|
45
|
+
let entries = graph
|
|
46
|
+
.all_diagnostics()
|
|
47
|
+
.iter()
|
|
48
|
+
.map(|diagnostic| {
|
|
49
|
+
let document = graph.documents().get(diagnostic.uri_id()).unwrap();
|
|
50
|
+
let location = create_location_for_uri_and_offset(graph, document, diagnostic.offset());
|
|
51
|
+
|
|
52
|
+
DiagnosticEntry {
|
|
53
|
+
rule: CString::new(diagnostic.rule().to_string())
|
|
54
|
+
.unwrap()
|
|
55
|
+
.into_raw()
|
|
56
|
+
.cast_const(),
|
|
57
|
+
message: CString::new(diagnostic.message()).unwrap().into_raw().cast_const(),
|
|
58
|
+
location,
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
.collect::<Vec<DiagnosticEntry>>();
|
|
62
|
+
|
|
63
|
+
DiagnosticArray::from_vec(entries)
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Frees a diagnostic array previously returned by `rdx_graph_diagnostics`.
|
|
68
|
+
///
|
|
69
|
+
/// # Safety
|
|
70
|
+
///
|
|
71
|
+
/// - `ptr` must be a valid pointer previously returned by `rdx_graph_diagnostics`.
|
|
72
|
+
/// - `ptr` must not be used after being freed.
|
|
73
|
+
#[unsafe(no_mangle)]
|
|
74
|
+
pub unsafe extern "C" fn rdx_diagnostics_free(ptr: *mut DiagnosticArray) {
|
|
75
|
+
if ptr.is_null() {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let array = unsafe { Box::from_raw(ptr) };
|
|
80
|
+
if !array.items.is_null() && array.len > 0 {
|
|
81
|
+
let slice_ptr = ptr::slice_from_raw_parts_mut(array.items, array.len);
|
|
82
|
+
let mut boxed_slice: Box<[DiagnosticEntry]> = unsafe { Box::from_raw(slice_ptr) };
|
|
83
|
+
|
|
84
|
+
for entry in &mut *boxed_slice {
|
|
85
|
+
if !entry.rule.is_null() {
|
|
86
|
+
let _ = unsafe { CString::from_raw(entry.rule.cast_mut()) };
|
|
87
|
+
}
|
|
88
|
+
if !entry.message.is_null() {
|
|
89
|
+
let _ = unsafe { CString::from_raw(entry.message.cast_mut()) };
|
|
90
|
+
}
|
|
91
|
+
if !entry.location.is_null() {
|
|
92
|
+
unsafe { crate::location_api::rdx_location_free(entry.location) };
|
|
93
|
+
entry.location = ptr::null_mut();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// boxed_slice drops here, releasing the buffer
|
|
97
|
+
}
|
|
98
|
+
// array drops here
|
|
99
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//! This file provides the C API for Document accessors
|
|
2
|
+
|
|
3
|
+
use libc::c_char;
|
|
4
|
+
use std::ffi::CString;
|
|
5
|
+
use std::ptr;
|
|
6
|
+
|
|
7
|
+
use crate::definition_api::{DefinitionsIter, rdx_definitions_iter_new_from_ids};
|
|
8
|
+
use crate::graph_api::{GraphPointer, with_graph};
|
|
9
|
+
use rubydex::model::ids::UriId;
|
|
10
|
+
|
|
11
|
+
#[derive(Debug)]
|
|
12
|
+
pub struct DocumentsIter {
|
|
13
|
+
entries: Box<[u64]>,
|
|
14
|
+
index: usize,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
iterator!(DocumentsIter, entries: u64);
|
|
18
|
+
|
|
19
|
+
/// # Safety
|
|
20
|
+
/// `iter` must be a valid pointer previously returned by `DocumentsIter::new`.
|
|
21
|
+
#[unsafe(no_mangle)]
|
|
22
|
+
pub unsafe extern "C" fn rdx_graph_documents_iter_len(iter: *const DocumentsIter) -> usize {
|
|
23
|
+
unsafe { DocumentsIter::len(iter) }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// # Safety
|
|
27
|
+
/// - `iter` must be a valid pointer previously returned by `DocumentsIter::new`.
|
|
28
|
+
/// - `out` must be a valid, writable pointer.
|
|
29
|
+
#[unsafe(no_mangle)]
|
|
30
|
+
pub unsafe extern "C" fn rdx_graph_documents_iter_next(iter: *mut DocumentsIter, out: *mut u64) -> bool {
|
|
31
|
+
unsafe { DocumentsIter::next(iter, out) }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// # Safety
|
|
35
|
+
/// - `iter` must be a pointer previously returned by `DocumentsIter::new`.
|
|
36
|
+
/// - `iter` must not be used after being freed.
|
|
37
|
+
#[unsafe(no_mangle)]
|
|
38
|
+
pub unsafe extern "C" fn rdx_graph_documents_iter_free(iter: *mut DocumentsIter) {
|
|
39
|
+
unsafe { DocumentsIter::free(iter) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Returns the UTF-8 URI string for a document id.
|
|
43
|
+
/// Caller must free with `free_c_string`.
|
|
44
|
+
///
|
|
45
|
+
/// # Safety
|
|
46
|
+
///
|
|
47
|
+
/// Assumes pointer is valid.
|
|
48
|
+
///
|
|
49
|
+
/// # Panics
|
|
50
|
+
///
|
|
51
|
+
/// This function will panic if the URI pointer is invalid.
|
|
52
|
+
#[unsafe(no_mangle)]
|
|
53
|
+
pub unsafe extern "C" fn rdx_document_uri(pointer: GraphPointer, uri_id: u64) -> *const c_char {
|
|
54
|
+
with_graph(pointer, |graph| {
|
|
55
|
+
let uri_id = UriId::new(uri_id);
|
|
56
|
+
if let Some(doc) = graph.documents().get(&uri_id) {
|
|
57
|
+
CString::new(doc.uri()).unwrap().into_raw().cast_const()
|
|
58
|
+
} else {
|
|
59
|
+
ptr::null()
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// An iterator over definition IDs and kinds for a given document (URI)
|
|
65
|
+
///
|
|
66
|
+
/// We snapshot the IDs at iterator creation so if the graph is modified, the iterator will not see the changes
|
|
67
|
+
// Use shared DefinitionsIter directly in signatures
|
|
68
|
+
/// Creates a new iterator over definition IDs for a given document by snapshotting the current set of IDs.
|
|
69
|
+
///
|
|
70
|
+
/// # Safety
|
|
71
|
+
///
|
|
72
|
+
/// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
|
|
73
|
+
/// - The returned pointer must be freed with `rdx_document_definitions_iter_free`.
|
|
74
|
+
#[unsafe(no_mangle)]
|
|
75
|
+
pub unsafe extern "C" fn rdx_document_definitions_iter_new(pointer: GraphPointer, uri_id: u64) -> *mut DefinitionsIter {
|
|
76
|
+
// Snapshot the IDs and kinds at iterator creation to avoid borrowing across FFI calls
|
|
77
|
+
with_graph(pointer, |graph| {
|
|
78
|
+
let uri_id = UriId::new(uri_id);
|
|
79
|
+
if let Some(doc) = graph.documents().get(&uri_id) {
|
|
80
|
+
rdx_definitions_iter_new_from_ids(graph, doc.definitions())
|
|
81
|
+
} else {
|
|
82
|
+
DefinitionsIter::new(Vec::<_>::new().into_boxed_slice())
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
}
|