diff --git a/lib/binding_rust/build.rs b/lib/binding_rust/build.rs index c560149a..caf5fa8e 100644 --- a/lib/binding_rust/build.rs +++ b/lib/binding_rust/build.rs @@ -1,7 +1,7 @@ extern crate cc; -use std::{env, fs}; use std::path::{Path, PathBuf}; +use std::{env, fs}; fn main() { println!("cargo:rerun-if-env-changed=TREE_SITTER_STATIC_ANALYSIS"); @@ -21,13 +21,12 @@ fn main() { let mut config = cc::Build::new(); - println!("cargo:rerun-if-env-changed=TREE_SITTER_TEST"); - if env::var("TREE_SITTER_TEST").is_ok() { + println!("cargo:rerun-if-env-changed=DEBUG"); + if env::var("DEBUG").map(|s| s == "true").unwrap_or(false) { config.define("TREE_SITTER_TEST", ""); } let src_path = Path::new("src"); - for entry in fs::read_dir(&src_path).unwrap() { let entry = entry.unwrap(); let path = src_path.join(entry.file_name()); @@ -40,7 +39,6 @@ fn main() { .include(src_path) .include("include") .file(src_path.join("lib.c")) - .file(Path::new("binding_rust").join("helper.c")) .compile("tree-sitter"); } diff --git a/lib/binding_rust/helper.c b/lib/binding_rust/helper.c deleted file mode 100644 index 4275e445..00000000 --- a/lib/binding_rust/helper.c +++ /dev/null @@ -1,17 +0,0 @@ -#if defined(TREE_SITTER_TEST) - -void ts_record_free(void *); - -void rust_tree_sitter_free(void *p) { - ts_record_free(p); -} - -#else - -void free(void *); - -void rust_tree_sitter_free(void *p) { - free(p); -} - -#endif diff --git a/lib/binding_rust/util.rs b/lib/binding_rust/util.rs index e62e371f..3480c02d 100644 --- a/lib/binding_rust/util.rs +++ b/lib/binding_rust/util.rs @@ -1,8 +1,69 @@ use std::os::raw::c_void; extern "C" { - #[link_name = "rust_tree_sitter_free"] + /// In *Release* builds, the C library links directly against `malloc` and `free`. + /// + /// When freeing memory that was allocated by C code, use `free` directly. + #[cfg(not(test))] + #[link_name = "free"] pub fn free_ptr(ptr: *mut c_void); + + /// In *Test* builds, the C library is compiled with the `TREE_SITTER_TEST` macro, + /// so all calls to `malloc`, `free`, etc are linked against wrapper functions + /// called `ts_record_malloc`, `ts_record_free`, etc. These symbols are defined + /// in the `tree_sitter_cli::tests::helpers::allocations` module. + /// + /// When freeing memory that was allocated by C code, use the `free` function + /// from that module. + #[cfg(test)] + #[link_name = "ts_record_free"] + pub fn free_ptr(ptr: *mut c_void); + + /// In *Debug* builds, the C library is compiled the same as in test builds: using + /// the wrapper functions. This prevents the C library from having to be recompiled + /// constantly when switching between running tests and compiling with RLS. + /// + /// But we don't want to actually record allocations when running the library in + /// debug mode, so we define symbols like `ts_record_malloc` to just delegate to + /// the normal `malloc` functions. + #[cfg(all(debug_assertions, not(test)))] + fn malloc(size: usize) -> *mut c_void; + #[cfg(all(debug_assertions, not(test)))] + fn calloc(count: usize, size: usize) -> *mut c_void; + #[cfg(all(debug_assertions, not(test)))] + fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void; + #[cfg(all(debug_assertions, not(test)))] + fn free(ptr: *mut c_void); +} + +#[cfg(all(debug_assertions, not(test)))] +#[no_mangle] +unsafe extern "C" fn ts_record_malloc(size: usize) -> *const c_void { + malloc(size) +} + +#[cfg(all(debug_assertions, not(test)))] +#[no_mangle] +unsafe extern "C" fn ts_record_calloc(count: usize, size: usize) -> *const c_void { + calloc(count, size) +} + +#[cfg(all(debug_assertions, not(test)))] +#[no_mangle] +unsafe extern "C" fn ts_record_realloc(ptr: *mut c_void, size: usize) -> *const c_void { + realloc(ptr, size) +} + +#[cfg(all(debug_assertions, not(test)))] +#[no_mangle] +unsafe extern "C" fn ts_record_free(ptr: *mut c_void) { + free(ptr) +} + +#[cfg(all(debug_assertions, not(test)))] +#[no_mangle] +extern "C" fn ts_toggle_allocation_recording(_: bool) -> bool { + false } pub struct CBufferIter { @@ -40,6 +101,8 @@ impl ExactSizeIterator for CBufferIter {} impl Drop for CBufferIter { fn drop(&mut self) { - unsafe { free_ptr(self.ptr as *mut c_void); } + unsafe { + free_ptr(self.ptr as *mut c_void); + } } } diff --git a/lib/src/subtree.c b/lib/src/subtree.c index e95733eb..c6c11223 100644 --- a/lib/src/subtree.c +++ b/lib/src/subtree.c @@ -18,18 +18,9 @@ typedef struct { Length new_end; } Edit; -#ifdef TREE_SITTER_TEST - -#define TS_MAX_INLINE_TREE_LENGTH 2 -#define TS_MAX_TREE_POOL_SIZE 0 - -#else - #define TS_MAX_INLINE_TREE_LENGTH UINT8_MAX #define TS_MAX_TREE_POOL_SIZE 32 -#endif - static const ExternalScannerState empty_state = {.length = 0, .short_data = {0}}; // ExternalScannerState