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,79 @@
|
|
|
1
|
+
/// Helper macro to generate all required functions for an iterator. We use iterators to go over any collection of data
|
|
2
|
+
/// that exists on the Rust side (e.g.: definitions, documents, declarations, references). The goal is to avoid eager
|
|
3
|
+
/// allocation of large collections when possible.
|
|
4
|
+
///
|
|
5
|
+
/// Note: structs must be defined manually so that the cbindgen can see them. The actual methods are not extern "C" and
|
|
6
|
+
/// so they can be expanded from the macro.
|
|
7
|
+
///
|
|
8
|
+
/// # Example
|
|
9
|
+
///
|
|
10
|
+
/// ```ignore
|
|
11
|
+
/// pub struct FoosIter {
|
|
12
|
+
/// entries: Box<[Foo]>,
|
|
13
|
+
/// index: usize,
|
|
14
|
+
/// }
|
|
15
|
+
///
|
|
16
|
+
/// iterator!(FoosIter, entries: Foo);
|
|
17
|
+
/// ```
|
|
18
|
+
macro_rules! iterator {
|
|
19
|
+
($name:ident, $field:ident : $entry:ty) => {
|
|
20
|
+
impl $name {
|
|
21
|
+
#[must_use]
|
|
22
|
+
pub fn new($field: Box<[$entry]>) -> *mut $name {
|
|
23
|
+
Box::into_raw(Box::new($name { $field, index: 0 }))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// # Safety
|
|
27
|
+
/// `iter` must be a valid pointer returned by `new`, or null.
|
|
28
|
+
pub unsafe fn len(iter: *const Self) -> usize {
|
|
29
|
+
if iter.is_null() {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
unsafe { (&*iter).$field.len() }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// # Safety
|
|
36
|
+
/// - `iter` must be a valid pointer returned by `new`, or null.
|
|
37
|
+
/// - `out` must be a valid, writable pointer, or null.
|
|
38
|
+
pub unsafe fn next(iter: *mut Self, out: *mut $entry) -> bool {
|
|
39
|
+
if iter.is_null() || out.is_null() {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let it = unsafe { &mut *iter };
|
|
44
|
+
if it.index >= it.$field.len() {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let entry = it.$field[it.index];
|
|
49
|
+
it.index += 1;
|
|
50
|
+
unsafe {
|
|
51
|
+
*out = entry;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// # Safety
|
|
58
|
+
/// `iter` must be a pointer returned by `new` (or null). Must not be used after.
|
|
59
|
+
pub unsafe fn free(iter: *mut Self) {
|
|
60
|
+
if iter.is_null() {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
unsafe {
|
|
64
|
+
let _ = Box::from_raw(iter);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub mod declaration_api;
|
|
72
|
+
pub mod definition_api;
|
|
73
|
+
pub mod diagnostic_api;
|
|
74
|
+
pub mod document_api;
|
|
75
|
+
pub mod graph_api;
|
|
76
|
+
pub mod location_api;
|
|
77
|
+
pub mod name_api;
|
|
78
|
+
pub mod reference_api;
|
|
79
|
+
pub mod utils;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//! Location-related C API and structs
|
|
2
|
+
|
|
3
|
+
use libc::c_char;
|
|
4
|
+
use rubydex::model::document::Document;
|
|
5
|
+
use rubydex::model::graph::Graph;
|
|
6
|
+
use rubydex::offset::Offset;
|
|
7
|
+
use std::ffi::CString;
|
|
8
|
+
|
|
9
|
+
/// C-compatible struct representing a definition location with offsets and line/column positions.
|
|
10
|
+
#[repr(C)]
|
|
11
|
+
#[derive(Debug, Clone)]
|
|
12
|
+
pub struct Location {
|
|
13
|
+
pub uri: *const c_char,
|
|
14
|
+
pub start_line: u32,
|
|
15
|
+
pub end_line: u32,
|
|
16
|
+
pub start_column: u32,
|
|
17
|
+
pub end_column: u32,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// Helper to create a location for a given URI and byte-offset range.
|
|
21
|
+
/// Allocates and returns a pointer to `Location`. Caller must free with `rdx_location_free`.
|
|
22
|
+
///
|
|
23
|
+
/// # Panics
|
|
24
|
+
///
|
|
25
|
+
/// - If the URI cannot be converted to a file path.
|
|
26
|
+
/// - If the file cannot be read.
|
|
27
|
+
/// - If the offset cannot be converted to a position.
|
|
28
|
+
#[must_use]
|
|
29
|
+
pub(crate) fn create_location_for_uri_and_offset(graph: &Graph, document: &Document, offset: &Offset) -> *mut Location {
|
|
30
|
+
let line_index = document.line_index();
|
|
31
|
+
let start_pos = line_index.line_col(offset.start().into());
|
|
32
|
+
let end_pos = line_index.line_col(offset.end().into());
|
|
33
|
+
|
|
34
|
+
let loc = if let Some(wide_encoding) = graph.encoding().to_wide() {
|
|
35
|
+
let wide_start_pos = line_index.to_wide(wide_encoding, start_pos).unwrap();
|
|
36
|
+
let wide_end_pos = line_index.to_wide(wide_encoding, end_pos).unwrap();
|
|
37
|
+
|
|
38
|
+
Location {
|
|
39
|
+
uri: CString::new(document.uri()).unwrap().into_raw().cast_const(),
|
|
40
|
+
start_line: wide_start_pos.line,
|
|
41
|
+
end_line: wide_end_pos.line,
|
|
42
|
+
start_column: wide_start_pos.col,
|
|
43
|
+
end_column: wide_end_pos.col,
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
Location {
|
|
47
|
+
uri: CString::new(document.uri()).unwrap().into_raw().cast_const(),
|
|
48
|
+
start_line: start_pos.line,
|
|
49
|
+
end_line: end_pos.line,
|
|
50
|
+
start_column: start_pos.col,
|
|
51
|
+
end_column: end_pos.col,
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
Box::into_raw(Box::new(loc))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Frees a `Location` struct and its owned inner strings.
|
|
59
|
+
///
|
|
60
|
+
/// # Safety
|
|
61
|
+
///
|
|
62
|
+
/// - `ptr` must be a valid pointer previously returned by `create_location_for_uri_and_offset`.
|
|
63
|
+
/// - `ptr` must not be used after being freed.
|
|
64
|
+
#[unsafe(no_mangle)]
|
|
65
|
+
pub unsafe extern "C" fn rdx_location_free(ptr: *mut Location) {
|
|
66
|
+
if ptr.is_null() {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
unsafe {
|
|
70
|
+
// Take ownership of the box so we can free inner allocations first
|
|
71
|
+
let boxed = Box::from_raw(ptr);
|
|
72
|
+
|
|
73
|
+
if !boxed.uri.is_null() {
|
|
74
|
+
let _ = CString::from_raw(boxed.uri.cast_mut());
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Box drops here, freeing the struct memory
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
use rubydex::model::{
|
|
2
|
+
graph::Graph,
|
|
3
|
+
ids::NameId,
|
|
4
|
+
name::{Name, ParentScope},
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/// Takes a constant name and a nesting stack (e.g.: `["Foo", "Bar::Baz", "Qux"]`) and transforms it into a `NameId`,
|
|
8
|
+
/// registering each required part in the graph. Returns the `NameId` and a list of name ids that need to be untracked
|
|
9
|
+
/// afterwards
|
|
10
|
+
///
|
|
11
|
+
/// # Panics
|
|
12
|
+
///
|
|
13
|
+
/// Should not panic because `const_name` will always be turned into a name
|
|
14
|
+
pub fn nesting_stack_to_name_id(graph: &mut Graph, const_name: &str, nesting: Vec<String>) -> (NameId, Vec<NameId>) {
|
|
15
|
+
let mut current_nesting = None;
|
|
16
|
+
let mut current_name = ParentScope::None;
|
|
17
|
+
let mut names_to_untrack = Vec::new();
|
|
18
|
+
|
|
19
|
+
for entry in nesting {
|
|
20
|
+
for part in entry.split("::").map(String::from) {
|
|
21
|
+
if part.is_empty() {
|
|
22
|
+
current_name = ParentScope::TopLevel;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let str_id = graph.intern_string(part);
|
|
27
|
+
let name_id = graph.add_name(Name::new(str_id, current_name, current_nesting));
|
|
28
|
+
names_to_untrack.push(name_id);
|
|
29
|
+
current_name = ParentScope::Some(name_id);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
current_nesting = current_name.map_or(None, |id| Some(*id));
|
|
33
|
+
current_name = ParentScope::None;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for part in const_name.split("::").map(String::from) {
|
|
37
|
+
if part.is_empty() {
|
|
38
|
+
current_name = ParentScope::TopLevel;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let str_id = graph.intern_string(part);
|
|
43
|
+
let name_id = graph.add_name(Name::new(str_id, current_name, current_nesting));
|
|
44
|
+
names_to_untrack.push(name_id);
|
|
45
|
+
current_name = ParentScope::Some(name_id);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
(
|
|
49
|
+
current_name.expect("The NameId cannot be None since it contains at least `const_name`"),
|
|
50
|
+
names_to_untrack,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[cfg(test)]
|
|
55
|
+
mod tests {
|
|
56
|
+
use rubydex::model::ids::StringId;
|
|
57
|
+
|
|
58
|
+
use super::*;
|
|
59
|
+
|
|
60
|
+
#[test]
|
|
61
|
+
fn nesting_is_converted_to_name_id() {
|
|
62
|
+
let mut graph = Graph::new();
|
|
63
|
+
|
|
64
|
+
let (name_id, _) = nesting_stack_to_name_id(
|
|
65
|
+
&mut graph,
|
|
66
|
+
"Some::CONST",
|
|
67
|
+
vec!["Foo".into(), "Bar::Zip".into(), "Qux".into()],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
let const_name = graph.names().get(&name_id).unwrap();
|
|
71
|
+
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
72
|
+
|
|
73
|
+
let some_name = graph
|
|
74
|
+
.names()
|
|
75
|
+
.get(&const_name.parent_scope().expect("Parent scope should exist"))
|
|
76
|
+
.unwrap();
|
|
77
|
+
assert_eq!(StringId::from("Some"), *some_name.str());
|
|
78
|
+
assert_eq!(const_name.nesting(), some_name.nesting());
|
|
79
|
+
|
|
80
|
+
let qux_name = graph.names().get(&some_name.nesting().unwrap()).unwrap();
|
|
81
|
+
assert_eq!(StringId::from("Qux"), *qux_name.str());
|
|
82
|
+
assert!(qux_name.parent_scope().is_none());
|
|
83
|
+
|
|
84
|
+
let zip_name = graph.names().get(&qux_name.nesting().unwrap()).unwrap();
|
|
85
|
+
assert_eq!(StringId::from("Zip"), *zip_name.str());
|
|
86
|
+
|
|
87
|
+
let bar_name = graph
|
|
88
|
+
.names()
|
|
89
|
+
.get(&zip_name.parent_scope().expect("Parent scope should exist"))
|
|
90
|
+
.unwrap();
|
|
91
|
+
assert_eq!(StringId::from("Bar"), *bar_name.str());
|
|
92
|
+
assert_eq!(zip_name.nesting(), bar_name.nesting());
|
|
93
|
+
|
|
94
|
+
let foo_name = graph.names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
95
|
+
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
96
|
+
assert!(foo_name.parent_scope().is_none());
|
|
97
|
+
assert!(foo_name.nesting().is_none());
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#[test]
|
|
101
|
+
fn top_level_reference_is_converted_to_name_id() {
|
|
102
|
+
let mut graph = Graph::new();
|
|
103
|
+
|
|
104
|
+
let (name_id, _) = nesting_stack_to_name_id(&mut graph, "::CONST", vec!["Foo".into()]);
|
|
105
|
+
|
|
106
|
+
let const_name = graph.names().get(&name_id).unwrap();
|
|
107
|
+
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
108
|
+
assert!(const_name.parent_scope().is_top_level());
|
|
109
|
+
|
|
110
|
+
let foo_name = graph.names().get(&const_name.nesting().unwrap()).unwrap();
|
|
111
|
+
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
112
|
+
assert!(foo_name.nesting().is_none());
|
|
113
|
+
assert!(foo_name.parent_scope().is_none());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#[test]
|
|
117
|
+
fn top_level_nesting_is_converted_to_name_id() {
|
|
118
|
+
let mut graph = Graph::new();
|
|
119
|
+
|
|
120
|
+
let (name_id, _) = nesting_stack_to_name_id(&mut graph, "CONST", vec!["Foo".into(), "::Bar".into()]);
|
|
121
|
+
|
|
122
|
+
let const_name = graph.names().get(&name_id).unwrap();
|
|
123
|
+
assert_eq!(StringId::from("CONST"), *const_name.str());
|
|
124
|
+
assert!(const_name.parent_scope().is_none());
|
|
125
|
+
|
|
126
|
+
let bar_name = graph.names().get(&const_name.nesting().unwrap()).unwrap();
|
|
127
|
+
assert_eq!(StringId::from("Bar"), *bar_name.str());
|
|
128
|
+
assert!(bar_name.parent_scope().is_top_level());
|
|
129
|
+
|
|
130
|
+
let foo_name = graph.names().get(&bar_name.nesting().unwrap()).unwrap();
|
|
131
|
+
assert_eq!(StringId::from("Foo"), *foo_name.str());
|
|
132
|
+
assert!(foo_name.parent_scope().is_none());
|
|
133
|
+
assert!(foo_name.nesting().is_none());
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
//! C API for exposing references through ID handles (like definitions)
|
|
2
|
+
|
|
3
|
+
use std::ffi::CString;
|
|
4
|
+
use std::ptr;
|
|
5
|
+
|
|
6
|
+
use crate::declaration_api::CDeclaration;
|
|
7
|
+
use crate::graph_api::{GraphPointer, with_graph};
|
|
8
|
+
use crate::location_api::{Location, create_location_for_uri_and_offset};
|
|
9
|
+
use libc::c_char;
|
|
10
|
+
use rubydex::model::graph::Graph;
|
|
11
|
+
use rubydex::model::ids::{ConstantReferenceId, MethodReferenceId};
|
|
12
|
+
use rubydex::model::name::NameRef;
|
|
13
|
+
|
|
14
|
+
#[repr(C)]
|
|
15
|
+
#[derive(Debug, Clone, Copy)]
|
|
16
|
+
pub struct CConstantReference {
|
|
17
|
+
pub id: u64,
|
|
18
|
+
pub declaration_id: u64,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl CConstantReference {
|
|
22
|
+
/// Build a `CConstantReference` from a graph and reference ID. Sets `declaration_id` to 0 when the reference is
|
|
23
|
+
/// unresolved.
|
|
24
|
+
///
|
|
25
|
+
/// # Panics
|
|
26
|
+
///
|
|
27
|
+
/// This function will panic if there's inconsistent data in the graph
|
|
28
|
+
#[must_use]
|
|
29
|
+
pub fn from_id(graph: &Graph, ref_id: ConstantReferenceId) -> Self {
|
|
30
|
+
let reference = graph
|
|
31
|
+
.constant_references()
|
|
32
|
+
.get(&ref_id)
|
|
33
|
+
.expect("Constant reference not found");
|
|
34
|
+
|
|
35
|
+
let name_ref = graph.names().get(reference.name_id()).expect("Name ID should exist");
|
|
36
|
+
|
|
37
|
+
let declaration_id = match name_ref {
|
|
38
|
+
NameRef::Resolved(resolved) => **resolved.declaration_id(),
|
|
39
|
+
NameRef::Unresolved(_) => 0,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Self {
|
|
43
|
+
id: *ref_id,
|
|
44
|
+
declaration_id,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#[derive(Debug)]
|
|
50
|
+
pub struct ConstantReferencesIter {
|
|
51
|
+
entries: Box<[CConstantReference]>,
|
|
52
|
+
index: usize,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
iterator!(ConstantReferencesIter, entries: CConstantReference);
|
|
56
|
+
|
|
57
|
+
/// # Safety
|
|
58
|
+
/// `iter` must be a valid pointer previously returned by `ConstantReferencesIter::new`.
|
|
59
|
+
#[unsafe(no_mangle)]
|
|
60
|
+
pub unsafe extern "C" fn rdx_constant_references_iter_len(iter: *const ConstantReferencesIter) -> usize {
|
|
61
|
+
unsafe { ConstantReferencesIter::len(iter) }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// # Safety
|
|
65
|
+
/// - `iter` must be a valid pointer previously returned by `ConstantReferencesIter::new`.
|
|
66
|
+
/// - `out` must be a valid, writable pointer.
|
|
67
|
+
#[unsafe(no_mangle)]
|
|
68
|
+
pub unsafe extern "C" fn rdx_constant_references_iter_next(
|
|
69
|
+
iter: *mut ConstantReferencesIter,
|
|
70
|
+
out: *mut CConstantReference,
|
|
71
|
+
) -> bool {
|
|
72
|
+
unsafe { ConstantReferencesIter::next(iter, out) }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// # Safety
|
|
76
|
+
/// - `iter` must be a pointer previously returned by `ConstantReferencesIter::new`.
|
|
77
|
+
/// - `iter` must not be used after being freed.
|
|
78
|
+
#[unsafe(no_mangle)]
|
|
79
|
+
pub unsafe extern "C" fn rdx_constant_references_iter_free(iter: *mut ConstantReferencesIter) {
|
|
80
|
+
unsafe { ConstantReferencesIter::free(iter) }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#[repr(C)]
|
|
84
|
+
#[derive(Debug, Clone, Copy)]
|
|
85
|
+
pub struct CMethodReference {
|
|
86
|
+
pub id: u64,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#[derive(Debug)]
|
|
90
|
+
pub struct MethodReferencesIter {
|
|
91
|
+
entries: Box<[CMethodReference]>,
|
|
92
|
+
index: usize,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
iterator!(MethodReferencesIter, entries: CMethodReference);
|
|
96
|
+
|
|
97
|
+
/// # Safety
|
|
98
|
+
/// `iter` must be a valid pointer previously returned by `MethodReferencesIter::new`.
|
|
99
|
+
#[unsafe(no_mangle)]
|
|
100
|
+
pub unsafe extern "C" fn rdx_method_references_iter_len(iter: *const MethodReferencesIter) -> usize {
|
|
101
|
+
unsafe { MethodReferencesIter::len(iter) }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// # Safety
|
|
105
|
+
/// - `iter` must be a valid pointer previously returned by `MethodReferencesIter::new`.
|
|
106
|
+
/// - `out` must be a valid, writable pointer.
|
|
107
|
+
#[unsafe(no_mangle)]
|
|
108
|
+
pub unsafe extern "C" fn rdx_method_references_iter_next(
|
|
109
|
+
iter: *mut MethodReferencesIter,
|
|
110
|
+
out: *mut CMethodReference,
|
|
111
|
+
) -> bool {
|
|
112
|
+
unsafe { MethodReferencesIter::next(iter, out) }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/// # Safety
|
|
116
|
+
/// - `iter` must be a pointer previously returned by `MethodReferencesIter::new`.
|
|
117
|
+
/// - `iter` must not be used after being freed.
|
|
118
|
+
#[unsafe(no_mangle)]
|
|
119
|
+
pub unsafe extern "C" fn rdx_method_references_iter_free(iter: *mut MethodReferencesIter) {
|
|
120
|
+
unsafe { MethodReferencesIter::free(iter) }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Returns the UTF-8 name string for a constant reference id.
|
|
124
|
+
/// Caller must free with `free_c_string`.
|
|
125
|
+
///
|
|
126
|
+
/// # Safety
|
|
127
|
+
///
|
|
128
|
+
/// Assumes pointer is valid.
|
|
129
|
+
///
|
|
130
|
+
/// # Panics
|
|
131
|
+
///
|
|
132
|
+
/// This function will panic if the reference cannot be found.
|
|
133
|
+
#[unsafe(no_mangle)]
|
|
134
|
+
pub unsafe extern "C" fn rdx_constant_reference_name(pointer: GraphPointer, reference_id: u64) -> *const c_char {
|
|
135
|
+
with_graph(pointer, |graph| {
|
|
136
|
+
let ref_id = ConstantReferenceId::new(reference_id);
|
|
137
|
+
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
|
|
138
|
+
let name = graph.names().get(reference.name_id()).expect("Name ID should exist");
|
|
139
|
+
|
|
140
|
+
let name_string = graph
|
|
141
|
+
.strings()
|
|
142
|
+
.get(name.str())
|
|
143
|
+
.expect("String ID should exist")
|
|
144
|
+
.to_string();
|
|
145
|
+
CString::new(name_string).unwrap().into_raw().cast_const()
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// Returns the UTF-8 name string for a method reference id.
|
|
150
|
+
/// Caller must free with `free_c_string`.
|
|
151
|
+
///
|
|
152
|
+
/// # Safety
|
|
153
|
+
///
|
|
154
|
+
/// Assumes pointer is valid.
|
|
155
|
+
///
|
|
156
|
+
/// # Panics
|
|
157
|
+
///
|
|
158
|
+
/// This function will panic if the reference cannot be found.
|
|
159
|
+
#[unsafe(no_mangle)]
|
|
160
|
+
pub unsafe extern "C" fn rdx_method_reference_name(pointer: GraphPointer, reference_id: u64) -> *const c_char {
|
|
161
|
+
with_graph(pointer, |graph| {
|
|
162
|
+
let ref_id = MethodReferenceId::new(reference_id);
|
|
163
|
+
let reference = graph.method_references().get(&ref_id).expect("Reference not found");
|
|
164
|
+
let name = graph
|
|
165
|
+
.strings()
|
|
166
|
+
.get(reference.str())
|
|
167
|
+
.expect("Name ID should exist")
|
|
168
|
+
.to_string();
|
|
169
|
+
CString::new(name).unwrap().into_raw().cast_const()
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// Returns a newly allocated `Location` for the given constant reference id.
|
|
174
|
+
/// Caller must free the returned pointer with `rdx_location_free`.
|
|
175
|
+
///
|
|
176
|
+
/// # Safety
|
|
177
|
+
///
|
|
178
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
179
|
+
/// - `reference_id` must be a valid reference id.
|
|
180
|
+
///
|
|
181
|
+
/// # Panics
|
|
182
|
+
///
|
|
183
|
+
/// This function will panic if a reference or document cannot be found.
|
|
184
|
+
#[unsafe(no_mangle)]
|
|
185
|
+
pub unsafe extern "C" fn rdx_constant_reference_location(pointer: GraphPointer, reference_id: u64) -> *mut Location {
|
|
186
|
+
with_graph(pointer, |graph| {
|
|
187
|
+
let ref_id = ConstantReferenceId::new(reference_id);
|
|
188
|
+
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
|
|
189
|
+
let document = graph
|
|
190
|
+
.documents()
|
|
191
|
+
.get(&reference.uri_id())
|
|
192
|
+
.expect("Document should exist");
|
|
193
|
+
|
|
194
|
+
create_location_for_uri_and_offset(graph, document, reference.offset())
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Returns the declaration that the given resolved constant reference points to. Returns NULL if the reference is
|
|
199
|
+
/// unresolved. Caller must free with `free_c_declaration`.
|
|
200
|
+
///
|
|
201
|
+
/// # Safety
|
|
202
|
+
///
|
|
203
|
+
/// Assumes pointer is valid.
|
|
204
|
+
///
|
|
205
|
+
/// # Panics
|
|
206
|
+
///
|
|
207
|
+
/// This function will panic if the reference cannot be found.
|
|
208
|
+
#[unsafe(no_mangle)]
|
|
209
|
+
pub unsafe extern "C" fn rdx_resolved_constant_reference_declaration(
|
|
210
|
+
pointer: GraphPointer,
|
|
211
|
+
reference_id: u64,
|
|
212
|
+
) -> *const CDeclaration {
|
|
213
|
+
with_graph(pointer, |graph| {
|
|
214
|
+
let ref_id = ConstantReferenceId::new(reference_id);
|
|
215
|
+
let reference = graph.constant_references().get(&ref_id).expect("Reference not found");
|
|
216
|
+
let name_ref = graph.names().get(reference.name_id()).expect("Name ID should exist");
|
|
217
|
+
|
|
218
|
+
match name_ref {
|
|
219
|
+
NameRef::Resolved(resolved) => {
|
|
220
|
+
let decl_id = *resolved.declaration_id();
|
|
221
|
+
let decl = graph.declarations().get(&decl_id).expect("Declaration not found");
|
|
222
|
+
Box::into_raw(Box::new(CDeclaration::from_declaration(decl_id, decl))).cast_const()
|
|
223
|
+
}
|
|
224
|
+
NameRef::Unresolved(_) => ptr::null(),
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/// Returns a newly allocated `Location` for the given method reference id.
|
|
230
|
+
/// Caller must free the returned pointer with `rdx_location_free`.
|
|
231
|
+
///
|
|
232
|
+
/// # Safety
|
|
233
|
+
///
|
|
234
|
+
/// - `pointer` must be a valid pointer previously returned by `rdx_graph_new`.
|
|
235
|
+
/// - `reference_id` must be a valid reference id.
|
|
236
|
+
///
|
|
237
|
+
/// # Panics
|
|
238
|
+
///
|
|
239
|
+
/// This function will panic if a reference or document cannot be found.
|
|
240
|
+
#[unsafe(no_mangle)]
|
|
241
|
+
pub unsafe extern "C" fn rdx_method_reference_location(pointer: GraphPointer, reference_id: u64) -> *mut Location {
|
|
242
|
+
with_graph(pointer, |graph| {
|
|
243
|
+
let ref_id = MethodReferenceId::new(reference_id);
|
|
244
|
+
let reference = graph.method_references().get(&ref_id).expect("Reference not found");
|
|
245
|
+
let document = graph
|
|
246
|
+
.documents()
|
|
247
|
+
.get(&reference.uri_id())
|
|
248
|
+
.expect("Document should exist");
|
|
249
|
+
|
|
250
|
+
create_location_for_uri_and_offset(graph, document, reference.offset())
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/// Frees a `CConstantReference` previously returned by an FFI function.
|
|
255
|
+
///
|
|
256
|
+
/// # Safety
|
|
257
|
+
/// - `ptr` must be a valid pointer previously returned by an FFI function that allocates a `CConstantReference`, or
|
|
258
|
+
/// NULL.
|
|
259
|
+
/// - `ptr` must not be used after being freed.
|
|
260
|
+
#[unsafe(no_mangle)]
|
|
261
|
+
pub unsafe extern "C" fn free_c_constant_reference(ptr: *const CConstantReference) {
|
|
262
|
+
if !ptr.is_null() {
|
|
263
|
+
unsafe {
|
|
264
|
+
let _ = Box::from_raw(ptr.cast_mut());
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
use libc::{c_char, size_t};
|
|
2
|
+
use std::ffi::{CStr, CString};
|
|
3
|
+
use std::slice;
|
|
4
|
+
use std::str::Utf8Error;
|
|
5
|
+
|
|
6
|
+
/// Converts a C array of strings into a Vec<String>
|
|
7
|
+
///
|
|
8
|
+
/// # Safety
|
|
9
|
+
///
|
|
10
|
+
/// This function is unsafe because it attempts to instantiate a Vec<String> from a raw char** pointer
|
|
11
|
+
///
|
|
12
|
+
/// # Errors
|
|
13
|
+
///
|
|
14
|
+
/// This function errors if any of the strings inside the array contain invalid UTF-8 data
|
|
15
|
+
pub unsafe fn convert_double_pointer_to_vec(data: *const *const c_char, len: size_t) -> Result<Vec<String>, Utf8Error> {
|
|
16
|
+
unsafe {
|
|
17
|
+
slice::from_raw_parts(data, len)
|
|
18
|
+
.iter()
|
|
19
|
+
.map(|arg| CStr::from_ptr(*arg).to_str().map(ToString::to_string))
|
|
20
|
+
.collect()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// # Safety
|
|
25
|
+
///
|
|
26
|
+
/// This function is unsafe because it dereferences the char pointer, which needs to be valid for the duration of the
|
|
27
|
+
/// function
|
|
28
|
+
///
|
|
29
|
+
/// # Errors
|
|
30
|
+
///
|
|
31
|
+
/// This function errors if any of the strings inside the array contain invalid UTF-8 data
|
|
32
|
+
pub unsafe fn convert_char_ptr_to_string(data: *const c_char) -> Result<String, Utf8Error> {
|
|
33
|
+
unsafe { CStr::from_ptr(data).to_str().map(ToString::to_string) }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Frees a `CString` allocated on the Rust side
|
|
37
|
+
#[unsafe(no_mangle)]
|
|
38
|
+
pub extern "C" fn free_c_string(ptr: *const c_char) {
|
|
39
|
+
unsafe {
|
|
40
|
+
let _ = CString::from_raw(ptr.cast_mut());
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Frees a boxed u64 allocated on the Rust side
|
|
45
|
+
#[unsafe(no_mangle)]
|
|
46
|
+
pub extern "C" fn free_u64(ptr: *const u64) {
|
|
47
|
+
unsafe {
|
|
48
|
+
let _ = Box::from_raw(ptr.cast_mut());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Frees an array of C strings allocated by Rust.
|
|
53
|
+
///
|
|
54
|
+
/// # Safety
|
|
55
|
+
/// - `ptr` must be a pointer to a boxed slice of C strings previously allocated by this crate.
|
|
56
|
+
/// - `count` must be the length of the array.
|
|
57
|
+
/// - `ptr` must not be used after being freed.
|
|
58
|
+
#[unsafe(no_mangle)]
|
|
59
|
+
pub unsafe extern "C" fn free_c_string_array(ptr: *const *const c_char, count: usize) {
|
|
60
|
+
if ptr.is_null() {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let slice = unsafe { Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr.cast_mut(), count)) };
|
|
65
|
+
let _: Vec<_> = slice
|
|
66
|
+
.iter()
|
|
67
|
+
.filter(|p| !p.is_null())
|
|
68
|
+
.map(|arg| unsafe { CString::from_raw((*arg).cast_mut()) })
|
|
69
|
+
.collect();
|
|
70
|
+
}
|
data/rust/rustfmt.toml
ADDED