rubydex 0.4.3 → 0.4.4
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/THIRD_PARTY_LICENSES.html +2 -2
- data/ext/rubydex/declaration.c +2 -6
- data/ext/rubydex/definition.c +2 -3
- data/ext/rubydex/graph.c +2 -1
- data/ext/rubydex/query.c +3 -1
- data/ext/rubydex/reference.c +3 -3
- data/ext/rubydex/utils.c +13 -0
- data/ext/rubydex/utils.h +5 -0
- data/lib/rubydex/version.rb +1 -1
- data/rust/Cargo.lock +2 -2
- data/rust/Cargo.toml +3 -2
- data/rust/rubydex/Cargo.toml +1 -1
- data/rust/rubydex-sys/Cargo.toml +2 -2
- data/rust/rubydex-sys/src/cypher_api.rs +8 -8
- data/rust/rubydex-sys/src/declaration_api.rs +11 -19
- data/rust/rubydex-sys/src/definition_api.rs +10 -17
- data/rust/rubydex-sys/src/diagnostic_api.rs +5 -7
- data/rust/rubydex-sys/src/reference_api.rs +7 -10
- data/rust/rubydex-sys/src/utils.rs +49 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 196878527af0452d4afb518e0520ed26ccf7370fc6755954d70038afa6e0f66e
|
|
4
|
+
data.tar.gz: 864a4ac367601c64a465946115b732da341971b2a7c9d06f96ce8b3fae983354
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30ef223c97026abc1cb3f1a8c84048f87889dbb96aa01fc81fe37a9db52109cbb774ba492635ec09067050ab7a33dbd2b7f40aac5512dc81367d7f0009c036ee
|
|
7
|
+
data.tar.gz: 20e4b61e4790603a8589419404d85011ef0f9342b4e0cc65f056b19fdadc5a6d881a37f3e49cd9328c072bc64cc6e988350e0372da32243632d5ae2a1de2fcbf
|
data/THIRD_PARTY_LICENSES.html
CHANGED
|
@@ -2848,10 +2848,10 @@ SOFTWARE.
|
|
|
2848
2848
|
<ul class="license-used-by">
|
|
2849
2849
|
<li><a
|
|
2850
2850
|
href=" https://github.com/Shopify/rubydex ">rubydex
|
|
2851
|
-
0.4.
|
|
2851
|
+
0.4.4</a></li>
|
|
2852
2852
|
<li><a
|
|
2853
2853
|
href=" https://github.com/Shopify/rubydex ">rubydex-sys
|
|
2854
|
-
0.4.
|
|
2854
|
+
0.4.4</a></li>
|
|
2855
2855
|
<li><a
|
|
2856
2856
|
href=" https://github.com/DimaKudosh/difflib ">difflib
|
|
2857
2857
|
0.4.0</a></li>
|
data/ext/rubydex/declaration.c
CHANGED
|
@@ -60,9 +60,7 @@ VALUE rdxi_declaration_class_for_kind(CDeclarationKind kind) {
|
|
|
60
60
|
static VALUE rdxr_declaration_name(VALUE self) {
|
|
61
61
|
HandleData *data;
|
|
62
62
|
void *graph = rdxi_graph_from_handle(self, &data);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return rdxi_owned_c_string_to_ruby(name);
|
|
63
|
+
return rdxi_owned_string_to_ruby(rdx_declaration_name(graph, data->id));
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
/*
|
|
@@ -74,9 +72,7 @@ static VALUE rdxr_declaration_name(VALUE self) {
|
|
|
74
72
|
static VALUE rdxr_declaration_unqualified_name(VALUE self) {
|
|
75
73
|
HandleData *data;
|
|
76
74
|
void *graph = rdxi_graph_from_handle(self, &data);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return rdxi_owned_c_string_to_ruby(name);
|
|
75
|
+
return rdxi_owned_string_to_ruby(rdx_declaration_unqualified_name(graph, data->id));
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
// Body function for rb_ensure in Declaration#definitions
|
data/ext/rubydex/definition.c
CHANGED
|
@@ -132,7 +132,7 @@ static VALUE rdxr_definition_comments(VALUE self) {
|
|
|
132
132
|
for (size_t i = 0; i < arr->len; i++) {
|
|
133
133
|
CommentEntry entry = arr->items[i];
|
|
134
134
|
|
|
135
|
-
VALUE string =
|
|
135
|
+
VALUE string = rb_utf8_str_new(entry.string.data, (long)entry.string.length);
|
|
136
136
|
|
|
137
137
|
Location *loc = entry.location;
|
|
138
138
|
VALUE location = rdxi_build_location_value(loc);
|
|
@@ -160,8 +160,7 @@ static VALUE rdxr_definition_name(VALUE self) {
|
|
|
160
160
|
HandleData *data;
|
|
161
161
|
void *graph = rdxi_graph_from_handle(self, &data);
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
return rdxi_owned_c_string_to_ruby(name);
|
|
163
|
+
return rdxi_owned_string_to_ruby(rdx_definition_name(graph, data->id));
|
|
165
164
|
}
|
|
166
165
|
|
|
167
166
|
/*
|
data/ext/rubydex/graph.c
CHANGED
|
@@ -679,7 +679,8 @@ static VALUE rdxr_graph_diagnostics(VALUE self) {
|
|
|
679
679
|
VALUE diagnostics = rb_ary_new_capa((long)array->len);
|
|
680
680
|
for (size_t i = 0; i < array->len; i++) {
|
|
681
681
|
DiagnosticEntry entry = array->items[i];
|
|
682
|
-
VALUE message =
|
|
682
|
+
VALUE message =
|
|
683
|
+
entry.message.data == NULL ? Qnil : rb_utf8_str_new(entry.message.data, (long)entry.message.length);
|
|
683
684
|
VALUE rule = rdxi_rule_class_from_name(entry.rule.name, entry.rule.name_length);
|
|
684
685
|
VALUE location = rdxi_build_location_value(entry.location);
|
|
685
686
|
|
data/ext/rubydex/query.c
CHANGED
|
@@ -188,7 +188,9 @@ static VALUE cypher_cell_to_value(VALUE graph_obj, const struct CCell *cell) {
|
|
|
188
188
|
case CCellTag_Int:
|
|
189
189
|
return LL2NUM(cell->payload.int_val);
|
|
190
190
|
case CCellTag_Str:
|
|
191
|
-
return cell->payload.str_val == NULL
|
|
191
|
+
return cell->payload.str_val.data == NULL
|
|
192
|
+
? Qnil
|
|
193
|
+
: rb_utf8_str_new(cell->payload.str_val.data, (long)cell->payload.str_val.length);
|
|
192
194
|
case CCellTag_List: {
|
|
193
195
|
VALUE array = rb_ary_new_capa((long)cell->payload.list.len);
|
|
194
196
|
for (size_t i = 0; i < cell->payload.list.len; i++) {
|
data/ext/rubydex/reference.c
CHANGED
|
@@ -86,11 +86,11 @@ static VALUE rdxr_method_reference_name(VALUE self) {
|
|
|
86
86
|
HandleData *data;
|
|
87
87
|
void *graph = rdxi_graph_from_handle(self, &data);
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
if (name == NULL) {
|
|
89
|
+
OwnedString name = rdx_method_reference_name(graph, data->id);
|
|
90
|
+
if (name.data == NULL) {
|
|
91
91
|
rb_raise(rb_eRuntimeError, "Method reference must exist for a valid id");
|
|
92
92
|
}
|
|
93
|
-
return
|
|
93
|
+
return rdxi_owned_string_to_ruby(name);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/*
|
data/ext/rubydex/utils.c
CHANGED
|
@@ -59,6 +59,19 @@ VALUE rdxi_owned_c_string_to_ruby(const char *string) {
|
|
|
59
59
|
return value;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
// Convert a Rust-owned string with an explicit length to a Ruby string and release it with free_owned_string.
|
|
63
|
+
// Returns nil when the Rust side returned a null string.
|
|
64
|
+
VALUE rdxi_owned_string_to_ruby(OwnedString string) {
|
|
65
|
+
if (string.data == NULL) {
|
|
66
|
+
return Qnil;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
VALUE value = rb_utf8_str_new(string.data, (long)string.length);
|
|
70
|
+
free_owned_string(string);
|
|
71
|
+
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
62
75
|
// Coerce an optional String, Symbol, or nil to a C string, defaulting to `default_value` for nil.
|
|
63
76
|
const char *rdxi_symbol_or_string_cstr(VALUE value, const char *default_value) {
|
|
64
77
|
if (NIL_P(value)) {
|
data/ext/rubydex/utils.h
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#define RUBYDEX_UTILS_H
|
|
3
3
|
|
|
4
4
|
#include "ruby.h"
|
|
5
|
+
#include "rustbindings.h"
|
|
5
6
|
|
|
6
7
|
// Convert a Ruby array of strings into a double char pointer so that we can pass that to Rust.
|
|
7
8
|
// This copies the data so it must be freed with rdxi_free_str_array
|
|
@@ -17,6 +18,10 @@ void rdxi_check_array_of_strings(VALUE array);
|
|
|
17
18
|
// Returns nil when the Rust side returned NULL.
|
|
18
19
|
VALUE rdxi_owned_c_string_to_ruby(const char *string);
|
|
19
20
|
|
|
21
|
+
// Convert a Rust-owned string with an explicit length to a Ruby string and release it with free_owned_string. Unlike
|
|
22
|
+
// a C string, it may contain NUL bytes. Returns nil when the Rust side returned a null string.
|
|
23
|
+
VALUE rdxi_owned_string_to_ruby(OwnedString string);
|
|
24
|
+
|
|
20
25
|
// Coerce an optional String, Symbol, or nil to a C string, returning `default_value` when the value
|
|
21
26
|
// is nil. A non-nil value must be a String or Symbol, otherwise a `TypeError` is raised. The
|
|
22
27
|
// returned pointer is owned by the Ruby VALUE and is only valid while it stays live.
|
data/lib/rubydex/version.rb
CHANGED
data/rust/Cargo.lock
CHANGED
|
@@ -760,7 +760,7 @@ dependencies = [
|
|
|
760
760
|
|
|
761
761
|
[[package]]
|
|
762
762
|
name = "rubydex"
|
|
763
|
-
version = "0.4.
|
|
763
|
+
version = "0.4.4"
|
|
764
764
|
dependencies = [
|
|
765
765
|
"assert_cmd",
|
|
766
766
|
"bitflags",
|
|
@@ -789,7 +789,7 @@ dependencies = [
|
|
|
789
789
|
|
|
790
790
|
[[package]]
|
|
791
791
|
name = "rubydex-sys"
|
|
792
|
-
version = "0.4.
|
|
792
|
+
version = "0.4.4"
|
|
793
793
|
dependencies = [
|
|
794
794
|
"cbindgen",
|
|
795
795
|
"libc",
|
data/rust/Cargo.toml
CHANGED
|
@@ -7,7 +7,8 @@ members = [
|
|
|
7
7
|
resolver = "3"
|
|
8
8
|
|
|
9
9
|
[workspace.package]
|
|
10
|
-
version = "0.4.
|
|
10
|
+
version = "0.4.4"
|
|
11
|
+
rust-version = "1.99.1"
|
|
11
12
|
|
|
12
13
|
[profile.release]
|
|
13
14
|
lto = true
|
|
@@ -28,4 +29,4 @@ complexity = "deny"
|
|
|
28
29
|
style = "deny"
|
|
29
30
|
pedantic = "warn"
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
ptr_as_ptr = { level = "deny", priority = 1 }
|
data/rust/rubydex/Cargo.toml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name = "rubydex"
|
|
3
3
|
version.workspace = true
|
|
4
4
|
edition = "2024"
|
|
5
|
-
rust-version =
|
|
5
|
+
rust-version.workspace = true
|
|
6
6
|
license = "MIT"
|
|
7
7
|
description = "High-performance Ruby code indexing and static analysis library."
|
|
8
8
|
homepage = "https://github.com/Shopify/rubydex"
|
data/rust/rubydex-sys/Cargo.toml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name = "rubydex-sys"
|
|
3
3
|
version.workspace = true
|
|
4
4
|
edition = "2024"
|
|
5
|
-
rust-version =
|
|
5
|
+
rust-version.workspace = true
|
|
6
6
|
license = "MIT"
|
|
7
7
|
description = "C FFI bindings for the Rubydex Ruby code indexing engine."
|
|
8
8
|
homepage = "https://github.com/Shopify/rubydex"
|
|
@@ -15,7 +15,7 @@ categories = ["development-tools", "external-ffi-bindings"]
|
|
|
15
15
|
crate-type = ["cdylib", "staticlib"]
|
|
16
16
|
|
|
17
17
|
[dependencies]
|
|
18
|
-
rubydex = { version = "=0.4.
|
|
18
|
+
rubydex = { version = "=0.4.4", path = "../rubydex" }
|
|
19
19
|
libc = "0.2.174"
|
|
20
20
|
url = "2.5.4"
|
|
21
21
|
line-index = "0.1.2"
|
|
@@ -5,11 +5,13 @@ use crate::declaration_api::CDeclaration;
|
|
|
5
5
|
use crate::definition_api::map_definition_to_kind;
|
|
6
6
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
7
7
|
use crate::utils;
|
|
8
|
+
use crate::utils::OwnedString;
|
|
8
9
|
use libc::{c_char, c_void};
|
|
9
10
|
use rubydex::model::graph::Graph;
|
|
10
11
|
use rubydex::query::cypher::schema::NodeRef;
|
|
11
12
|
use rubydex::query::cypher::{self, CypherValue, OutputFormat};
|
|
12
13
|
use std::ffi::CString;
|
|
14
|
+
use std::mem::ManuallyDrop;
|
|
13
15
|
use std::ptr;
|
|
14
16
|
|
|
15
17
|
/// Which layer of the Cypher pipeline rejected a call, so callers can raise a matching error class.
|
|
@@ -201,14 +203,13 @@ pub struct CMap {
|
|
|
201
203
|
/// Payload of a `CCell`. The active field is selected by the cell's `tag`; reading any other field
|
|
202
204
|
/// is undefined. `Null` carries no payload.
|
|
203
205
|
#[repr(C)]
|
|
204
|
-
#[derive(Clone, Copy)]
|
|
205
206
|
pub union CCellPayload {
|
|
206
207
|
/// `Bool`.
|
|
207
208
|
pub bool_val: bool,
|
|
208
209
|
/// `Int`.
|
|
209
210
|
pub int_val: i64,
|
|
210
|
-
/// `Str`: owned
|
|
211
|
-
pub str_val:
|
|
211
|
+
/// `Str`: owned string (freed by `rdx_rows_iter_free`). A union never drops its fields, so `free_cell` drops it.
|
|
212
|
+
pub str_val: ManuallyDrop<OwnedString>,
|
|
212
213
|
/// `Node`.
|
|
213
214
|
pub node: CNode,
|
|
214
215
|
/// `List`.
|
|
@@ -306,7 +307,7 @@ fn build_cell(graph: &Graph, value: &CypherValue) -> Result<CCell, String> {
|
|
|
306
307
|
CypherValue::Str(s) => Ok(CCell::new(
|
|
307
308
|
CCellTag::Str,
|
|
308
309
|
CCellPayload {
|
|
309
|
-
str_val:
|
|
310
|
+
str_val: ManuallyDrop::new(OwnedString::new(s)),
|
|
310
311
|
},
|
|
311
312
|
)),
|
|
312
313
|
CypherValue::List(items) => {
|
|
@@ -715,10 +716,9 @@ unsafe fn free_cell(cell: &CCell) {
|
|
|
715
716
|
match cell.tag {
|
|
716
717
|
// SAFETY: the tag selects the active union field.
|
|
717
718
|
CCellTag::Str => {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
719
|
+
// The cell is not used after this, so moving the string out of it is sound
|
|
720
|
+
let string = unsafe { ptr::read(&raw const cell.payload.str_val) };
|
|
721
|
+
drop(ManuallyDrop::into_inner(string));
|
|
722
722
|
}
|
|
723
723
|
// SAFETY: the tag selects the active union field.
|
|
724
724
|
CCellTag::List => {
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
use libc::c_char;
|
|
4
4
|
use rubydex::model::declaration::{Ancestor, Declaration, Namespace};
|
|
5
|
-
use std::ffi::CString;
|
|
6
5
|
use std::ptr;
|
|
7
6
|
|
|
8
7
|
use crate::definition_api::{DefinitionsIter, rdx_definitions_iter_new_from_ids};
|
|
9
8
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
10
9
|
use crate::reference_api::{CConstantReference, CMethodReference, ConstantReferencesIter, MethodReferencesIter};
|
|
11
10
|
use crate::utils;
|
|
11
|
+
use crate::utils::OwnedString;
|
|
12
12
|
use rubydex::model::ids::{DeclarationId, StringId, declaration_id_from_lookup_name};
|
|
13
13
|
|
|
14
14
|
#[repr(C)]
|
|
@@ -119,24 +119,20 @@ pub unsafe extern "C" fn rdx_graph_declarations_iter_free(iter: *mut Declaration
|
|
|
119
119
|
unsafe { DeclarationsIter::free(iter) }
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
/// Returns the UTF-8 name string for a declaration id.
|
|
123
|
-
/// Caller must free with `
|
|
122
|
+
/// Returns the UTF-8 name string for a declaration id, or a null string if the declaration cannot be found.
|
|
123
|
+
/// Caller must free with `free_owned_string`.
|
|
124
124
|
///
|
|
125
125
|
/// # Safety
|
|
126
126
|
///
|
|
127
127
|
/// Assumes pointer is valid.
|
|
128
|
-
///
|
|
129
|
-
/// # Panics
|
|
130
|
-
///
|
|
131
|
-
/// This function will panic if the name pointer is invalid.
|
|
132
128
|
#[unsafe(no_mangle)]
|
|
133
|
-
pub unsafe extern "C" fn rdx_declaration_name(pointer: GraphPointer, name_id: u64) ->
|
|
129
|
+
pub unsafe extern "C" fn rdx_declaration_name(pointer: GraphPointer, name_id: u64) -> OwnedString {
|
|
134
130
|
with_graph(pointer, |graph| {
|
|
135
131
|
let name_id = DeclarationId::new(name_id);
|
|
136
132
|
if let Some(decl) = graph.declarations().get(&name_id) {
|
|
137
|
-
|
|
133
|
+
OwnedString::new(decl.name())
|
|
138
134
|
} else {
|
|
139
|
-
|
|
135
|
+
OwnedString::null()
|
|
140
136
|
}
|
|
141
137
|
})
|
|
142
138
|
}
|
|
@@ -213,24 +209,20 @@ pub unsafe extern "C" fn rdx_declaration_find_member(
|
|
|
213
209
|
})
|
|
214
210
|
}
|
|
215
211
|
|
|
216
|
-
/// Returns the UTF-8 unqualified name string for a declaration id
|
|
217
|
-
/// Caller must free with `
|
|
212
|
+
/// Returns the UTF-8 unqualified name string for a declaration id, or a null string if the declaration cannot be
|
|
213
|
+
/// found. Caller must free with `free_owned_string`.
|
|
218
214
|
///
|
|
219
215
|
/// # Safety
|
|
220
216
|
///
|
|
221
217
|
/// Assumes pointer is valid.
|
|
222
|
-
///
|
|
223
|
-
/// # Panics
|
|
224
|
-
///
|
|
225
|
-
/// This function will panic if the name pointer is invalid.
|
|
226
218
|
#[unsafe(no_mangle)]
|
|
227
|
-
pub unsafe extern "C" fn rdx_declaration_unqualified_name(pointer: GraphPointer, name_id: u64) ->
|
|
219
|
+
pub unsafe extern "C" fn rdx_declaration_unqualified_name(pointer: GraphPointer, name_id: u64) -> OwnedString {
|
|
228
220
|
with_graph(pointer, |graph| {
|
|
229
221
|
let name_id = DeclarationId::new(name_id);
|
|
230
222
|
if let Some(decl) = graph.declarations().get(&name_id) {
|
|
231
|
-
|
|
223
|
+
OwnedString::new(&decl.unqualified_name())
|
|
232
224
|
} else {
|
|
233
|
-
|
|
225
|
+
OwnedString::null()
|
|
234
226
|
}
|
|
235
227
|
})
|
|
236
228
|
}
|
|
@@ -4,6 +4,7 @@ use crate::declaration_api::CDeclaration;
|
|
|
4
4
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
5
5
|
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
6
6
|
use crate::reference_api::CConstantReference;
|
|
7
|
+
use crate::utils::OwnedString;
|
|
7
8
|
use libc::c_char;
|
|
8
9
|
use rubydex::model::definitions::{Definition, Mixin};
|
|
9
10
|
use rubydex::model::graph::Graph;
|
|
@@ -84,30 +85,26 @@ pub unsafe extern "C" fn rdx_definition_kind(pointer: GraphPointer, definition_i
|
|
|
84
85
|
})
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
/// Returns the UTF-8 unqualified name string for a definition id.
|
|
88
|
-
/// Caller must free with `
|
|
88
|
+
/// Returns the UTF-8 unqualified name string for a definition id, or a null string if the definition cannot be found.
|
|
89
|
+
/// Caller must free with `free_owned_string`.
|
|
89
90
|
///
|
|
90
91
|
/// # Safety
|
|
91
92
|
///
|
|
92
93
|
/// Assumes pointer is valid.
|
|
93
|
-
///
|
|
94
|
-
/// # Panics
|
|
95
|
-
///
|
|
96
|
-
/// This function will panic if the definition cannot be found.
|
|
97
94
|
#[unsafe(no_mangle)]
|
|
98
|
-
pub unsafe extern "C" fn rdx_definition_name(pointer: GraphPointer, definition_id: u64) ->
|
|
95
|
+
pub unsafe extern "C" fn rdx_definition_name(pointer: GraphPointer, definition_id: u64) -> OwnedString {
|
|
99
96
|
with_graph(pointer, |graph| {
|
|
100
97
|
let def_id = DefinitionId::new(definition_id);
|
|
101
98
|
if let Some(defn) = graph.definitions().get(&def_id) {
|
|
102
99
|
let string_id = graph.definition_string_id(defn);
|
|
103
100
|
|
|
104
101
|
if let Some(name) = graph.strings().get(&string_id) {
|
|
105
|
-
|
|
102
|
+
OwnedString::new(name.as_str())
|
|
106
103
|
} else {
|
|
107
|
-
|
|
104
|
+
OwnedString::null()
|
|
108
105
|
}
|
|
109
106
|
} else {
|
|
110
|
-
|
|
107
|
+
OwnedString::null()
|
|
111
108
|
}
|
|
112
109
|
})
|
|
113
110
|
}
|
|
@@ -212,7 +209,7 @@ pub unsafe extern "C" fn rdx_definitions_iter_free(iter: *mut DefinitionsIter) {
|
|
|
212
209
|
/// C-compatible struct representing a single comment with its string and location
|
|
213
210
|
#[repr(C)]
|
|
214
211
|
pub struct CommentEntry {
|
|
215
|
-
pub string:
|
|
212
|
+
pub string: OwnedString,
|
|
216
213
|
pub location: *mut Location,
|
|
217
214
|
}
|
|
218
215
|
|
|
@@ -248,7 +245,7 @@ pub unsafe extern "C" fn rdx_definition_comments(pointer: GraphPointer, definiti
|
|
|
248
245
|
.comments()
|
|
249
246
|
.iter()
|
|
250
247
|
.map(|c| CommentEntry {
|
|
251
|
-
string:
|
|
248
|
+
string: OwnedString::new(c.string()),
|
|
252
249
|
location: create_location_for_uri_and_offset(graph, document, c.offset()),
|
|
253
250
|
})
|
|
254
251
|
.collect::<Vec<CommentEntry>>()
|
|
@@ -282,17 +279,13 @@ pub unsafe extern "C" fn rdx_definition_comments_free(ptr: *mut CommentArray) {
|
|
|
282
279
|
let mut boxed_slice: Box<[CommentEntry]> = unsafe { Box::from_raw(slice_ptr) };
|
|
283
280
|
|
|
284
281
|
for item in &mut boxed_slice {
|
|
285
|
-
if !item.string.is_null() {
|
|
286
|
-
// Free the CString allocated for the comment string
|
|
287
|
-
let _ = unsafe { CString::from_raw(item.string.cast_mut()) };
|
|
288
|
-
}
|
|
289
282
|
if !item.location.is_null() {
|
|
290
283
|
unsafe { crate::location_api::rdx_location_free(item.location) };
|
|
291
284
|
item.location = ptr::null_mut();
|
|
292
285
|
}
|
|
293
286
|
}
|
|
294
287
|
|
|
295
|
-
// boxed_slice is dropped here, freeing the items buffer
|
|
288
|
+
// boxed_slice is dropped here, freeing the items buffer and each item's string
|
|
296
289
|
}
|
|
297
290
|
// arr is dropped here
|
|
298
291
|
}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
4
4
|
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
5
|
+
use crate::utils::OwnedString;
|
|
5
6
|
use libc::c_char;
|
|
6
7
|
use rubydex::diagnostic::{Rule, Severity};
|
|
7
|
-
use std::{
|
|
8
|
+
use std::{mem, ptr};
|
|
8
9
|
|
|
9
10
|
/// C-compatible enum representing diagnostic severity levels.
|
|
10
11
|
#[repr(C)]
|
|
@@ -49,7 +50,7 @@ impl From<Rule> for CRule {
|
|
|
49
50
|
#[repr(C)]
|
|
50
51
|
pub struct DiagnosticEntry {
|
|
51
52
|
pub rule: CRule,
|
|
52
|
-
pub message:
|
|
53
|
+
pub message: OwnedString,
|
|
53
54
|
pub location: *mut Location,
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -91,7 +92,7 @@ pub unsafe extern "C" fn rdx_graph_diagnostics(pointer: GraphPointer) -> *mut Di
|
|
|
91
92
|
|
|
92
93
|
DiagnosticEntry {
|
|
93
94
|
rule: CRule::from(*diagnostic.rule()),
|
|
94
|
-
message:
|
|
95
|
+
message: OwnedString::new(diagnostic.message()),
|
|
95
96
|
location,
|
|
96
97
|
}
|
|
97
98
|
})
|
|
@@ -119,15 +120,12 @@ pub unsafe extern "C" fn rdx_diagnostics_free(ptr: *mut DiagnosticArray) {
|
|
|
119
120
|
let mut boxed_slice: Box<[DiagnosticEntry]> = unsafe { Box::from_raw(slice_ptr) };
|
|
120
121
|
|
|
121
122
|
for entry in &mut *boxed_slice {
|
|
122
|
-
if !entry.message.is_null() {
|
|
123
|
-
let _ = unsafe { CString::from_raw(entry.message.cast_mut()) };
|
|
124
|
-
}
|
|
125
123
|
if !entry.location.is_null() {
|
|
126
124
|
unsafe { crate::location_api::rdx_location_free(entry.location) };
|
|
127
125
|
entry.location = ptr::null_mut();
|
|
128
126
|
}
|
|
129
127
|
}
|
|
130
|
-
// boxed_slice drops here, releasing the buffer
|
|
128
|
+
// boxed_slice drops here, releasing the buffer and each entry's message
|
|
131
129
|
}
|
|
132
130
|
// array drops here
|
|
133
131
|
}
|
|
@@ -6,6 +6,7 @@ use std::ptr;
|
|
|
6
6
|
use crate::declaration_api::CDeclaration;
|
|
7
7
|
use crate::graph_api::{GraphPointer, with_graph};
|
|
8
8
|
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
9
|
+
use crate::utils::OwnedString;
|
|
9
10
|
use libc::c_char;
|
|
10
11
|
use rubydex::model::graph::Graph;
|
|
11
12
|
use rubydex::model::ids::{ConstantReferenceId, MethodReferenceId};
|
|
@@ -148,8 +149,8 @@ pub unsafe extern "C" fn rdx_constant_reference_name(pointer: GraphPointer, refe
|
|
|
148
149
|
})
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
/// Returns the UTF-8 name string for a method reference id, or
|
|
152
|
-
/// Caller must free with `
|
|
152
|
+
/// Returns the UTF-8 name string for a method reference id, or a null string if the reference cannot be found.
|
|
153
|
+
/// Caller must free with `free_owned_string`.
|
|
153
154
|
///
|
|
154
155
|
/// # Safety
|
|
155
156
|
///
|
|
@@ -159,18 +160,14 @@ pub unsafe extern "C" fn rdx_constant_reference_name(pointer: GraphPointer, refe
|
|
|
159
160
|
///
|
|
160
161
|
/// This function will panic if the reference's name cannot be found.
|
|
161
162
|
#[unsafe(no_mangle)]
|
|
162
|
-
pub unsafe extern "C" fn rdx_method_reference_name(pointer: GraphPointer, reference_id: u64) ->
|
|
163
|
+
pub unsafe extern "C" fn rdx_method_reference_name(pointer: GraphPointer, reference_id: u64) -> OwnedString {
|
|
163
164
|
with_graph(pointer, |graph| {
|
|
164
165
|
let ref_id = MethodReferenceId::new(reference_id);
|
|
165
166
|
let Some(reference) = graph.method_references().get(&ref_id) else {
|
|
166
|
-
return
|
|
167
|
+
return OwnedString::null();
|
|
167
168
|
};
|
|
168
|
-
let name = graph
|
|
169
|
-
|
|
170
|
-
.get(reference.str())
|
|
171
|
-
.expect("Name ID should exist")
|
|
172
|
-
.to_string();
|
|
173
|
-
CString::new(name).unwrap().into_raw().cast_const()
|
|
169
|
+
let name = graph.strings().get(reference.str()).expect("Name ID should exist");
|
|
170
|
+
OwnedString::new(name.as_str())
|
|
174
171
|
})
|
|
175
172
|
}
|
|
176
173
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use libc::{c_char, size_t};
|
|
2
2
|
use std::ffi::{CStr, CString};
|
|
3
3
|
use std::path::Path;
|
|
4
|
+
use std::ptr;
|
|
4
5
|
use std::slice;
|
|
5
6
|
use std::str::Utf8Error;
|
|
6
7
|
|
|
@@ -42,6 +43,54 @@ pub extern "C" fn free_c_string(ptr: *const c_char) {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/// C-compatible owned UTF-8 string with an explicit length. Unlike a C string, it is not NUL-terminated and may
|
|
47
|
+
/// contain NUL bytes, which source code can put into names, comments and diagnostic messages. A null `data` means
|
|
48
|
+
/// there is no string. Dropping it frees the bytes
|
|
49
|
+
#[repr(C)]
|
|
50
|
+
pub struct OwnedString {
|
|
51
|
+
pub data: *const c_char,
|
|
52
|
+
pub length: usize,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
impl OwnedString {
|
|
56
|
+
#[must_use]
|
|
57
|
+
pub fn new(value: &str) -> Self {
|
|
58
|
+
let bytes: Box<[u8]> = value.as_bytes().into();
|
|
59
|
+
Self {
|
|
60
|
+
length: bytes.len(),
|
|
61
|
+
data: Box::into_raw(bytes).cast::<c_char>().cast_const(),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[must_use]
|
|
66
|
+
pub fn null() -> Self {
|
|
67
|
+
Self {
|
|
68
|
+
data: ptr::null(),
|
|
69
|
+
length: 0,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
impl Drop for OwnedString {
|
|
75
|
+
fn drop(&mut self) {
|
|
76
|
+
if !self.data.is_null() {
|
|
77
|
+
let bytes = ptr::slice_from_raw_parts_mut(self.data.cast_mut().cast::<u8>(), self.length);
|
|
78
|
+
// SAFETY: a non-null `data` always comes from `Box::into_raw` in `OwnedString::new`, with `length` bytes
|
|
79
|
+
let _ = unsafe { Box::from_raw(bytes) };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Frees an `OwnedString` allocated on the Rust side
|
|
85
|
+
///
|
|
86
|
+
/// # Safety
|
|
87
|
+
///
|
|
88
|
+
/// - `string` must have been returned by a rubydex function and must not be used after being freed
|
|
89
|
+
#[unsafe(no_mangle)]
|
|
90
|
+
pub unsafe extern "C" fn free_owned_string(string: OwnedString) {
|
|
91
|
+
drop(string);
|
|
92
|
+
}
|
|
93
|
+
|
|
45
94
|
/// Frees a boxed u64 allocated on the Rust side
|
|
46
95
|
#[unsafe(no_mangle)]
|
|
47
96
|
pub extern "C" fn free_u64(ptr: *const u64) {
|