Skip to content

Commit 0689fa8

Browse files
committed
Improve using libclang and fix memory issue
1 parent ac10013 commit 0689fa8

File tree

8 files changed

+133
-138
lines changed

8 files changed

+133
-138
lines changed

src/clang_parser.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use std::ffi::CString;
2+
use std::ptr;
3+
4+
use clang_sys::clang_createIndex;
5+
use clang_sys::clang_parseTranslationUnit;
6+
use clang_sys::CXIndex;
7+
use clang_sys::CXTranslationUnit;
8+
9+
pub struct CompilationUnit {
10+
#[allow(dead_code)]
11+
pub path: String,
12+
13+
pub index: CXIndex,
14+
pub translation_unit: CXTranslationUnit,
15+
}
16+
17+
pub fn parse_files(files: &[String]) -> Vec<CompilationUnit> {
18+
let mut translation_units: Vec<CompilationUnit> = vec![];
19+
20+
for file in files {
21+
unsafe {
22+
let fname: CString = CString::new(file.as_str()).unwrap();
23+
let index: CXIndex = clang_createIndex(0, 0);
24+
let translation_unit: CXTranslationUnit = clang_parseTranslationUnit(
25+
index,
26+
fname.as_ptr(),
27+
ptr::null_mut(),
28+
0,
29+
ptr::null_mut(),
30+
0,
31+
0,
32+
);
33+
34+
if translation_unit.is_null() {
35+
continue;
36+
}
37+
38+
let compilation_unit = CompilationUnit {
39+
path: file.to_string(),
40+
index,
41+
translation_unit,
42+
};
43+
44+
translation_units.push(compilation_unit);
45+
}
46+
}
47+
48+
translation_units
49+
}

src/data_provider.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::vec;
22

3+
use clang_sys::clang_disposeIndex;
4+
use clang_sys::clang_disposeTranslationUnit;
35
use gitql_core::object::Row;
46
use gitql_core::values::base::Value;
57
use gitql_core::values::boolean::BoolValue;
@@ -8,54 +10,71 @@ use gitql_core::values::null::NullValue;
810
use gitql_core::values::text::TextValue;
911
use gitql_engine::data_provider::DataProvider;
1012

13+
use crate::clang_parser::CompilationUnit;
1114
use crate::visitor::class;
1215
use crate::visitor::enumeration;
1316
use crate::visitor::function;
1417
use crate::visitor::global;
1518
use crate::visitor::unions;
1619

17-
pub struct ClangAstDataProvider {
18-
pub paths: Vec<String>,
20+
pub struct ClangDataProvider {
21+
pub compilation_units: Vec<CompilationUnit>,
1922
}
2023

21-
impl ClangAstDataProvider {
22-
pub fn new(paths: Vec<String>) -> Self {
23-
Self { paths }
24+
impl ClangDataProvider {
25+
pub fn new(compilation_units: Vec<CompilationUnit>) -> Self {
26+
Self { compilation_units }
2427
}
2528
}
2629

27-
impl DataProvider for ClangAstDataProvider {
30+
impl DataProvider for ClangDataProvider {
2831
fn provide(&self, table: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
2932
let mut rows: Vec<Row> = vec![];
30-
31-
for path in &self.paths {
32-
let mut selected_rows = select_clang_ast_objects(path, table, selected_columns)?;
33+
for compilation_unit in &self.compilation_units {
34+
let mut selected_rows =
35+
select_clang_ast_objects(compilation_unit, table, selected_columns)?;
3336
rows.append(&mut selected_rows);
3437
}
35-
3638
Ok(rows)
3739
}
3840
}
3941

42+
impl Drop for ClangDataProvider {
43+
fn drop(&mut self) {
44+
for compilation_unit in self.compilation_units.iter() {
45+
unsafe {
46+
// Dispose the translation unit
47+
clang_disposeTranslationUnit(compilation_unit.translation_unit);
48+
49+
// Dispose the index
50+
clang_disposeIndex(compilation_unit.index);
51+
}
52+
}
53+
}
54+
}
55+
4056
fn select_clang_ast_objects(
41-
path: &str,
57+
compilation_unit: &CompilationUnit,
4258
table: &str,
4359
selected_columns: &[String],
4460
) -> Result<Vec<Row>, String> {
4561
let rows = match table {
46-
"classes" => select_classes(path, selected_columns)?,
47-
"enums" => select_enums(path, selected_columns)?,
48-
"unions" => select_unions(path, selected_columns)?,
49-
"functions" => select_functions(path, selected_columns)?,
50-
"globals" => select_variables(path, selected_columns)?,
62+
"classes" => select_classes(compilation_unit, selected_columns)?,
63+
"enums" => select_enums(compilation_unit, selected_columns)?,
64+
"unions" => select_unions(compilation_unit, selected_columns)?,
65+
"functions" => select_functions(compilation_unit, selected_columns)?,
66+
"globals" => select_variables(compilation_unit, selected_columns)?,
5167
_ => vec![Row { values: vec![] }],
5268
};
5369
Ok(rows)
5470
}
5571

56-
fn select_classes(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
72+
fn select_classes(
73+
compilation_unit: &CompilationUnit,
74+
selected_columns: &[String],
75+
) -> Result<Vec<Row>, String> {
5776
let mut rows: Vec<Row> = vec![];
58-
let ast_classes = class::select_clang_classes(path);
77+
let ast_classes = class::select_clang_classes(compilation_unit);
5978
for class in ast_classes.iter() {
6079
let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(selected_columns.len());
6180

@@ -129,9 +148,12 @@ fn select_classes(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, S
129148
Ok(rows)
130149
}
131150

132-
fn select_enums(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
151+
fn select_enums(
152+
compilation_unit: &CompilationUnit,
153+
selected_columns: &[String],
154+
) -> Result<Vec<Row>, String> {
133155
let mut rows: Vec<Row> = vec![];
134-
let ast_enums = enumeration::select_clang_enums(path);
156+
let ast_enums = enumeration::select_clang_enums(compilation_unit);
135157
for enumeration in ast_enums.iter() {
136158
let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(selected_columns.len());
137159

@@ -184,9 +206,12 @@ fn select_enums(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, Str
184206
Ok(rows)
185207
}
186208

187-
fn select_unions(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
209+
fn select_unions(
210+
compilation_unit: &CompilationUnit,
211+
selected_columns: &[String],
212+
) -> Result<Vec<Row>, String> {
188213
let mut rows: Vec<Row> = vec![];
189-
let ast_unions = unions::select_clang_unions(path);
214+
let ast_unions = unions::select_clang_unions(compilation_unit);
190215
for union_node in ast_unions.iter() {
191216
let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(selected_columns.len());
192217

@@ -238,9 +263,12 @@ fn select_unions(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, St
238263
Ok(rows)
239264
}
240265

241-
fn select_functions(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
266+
fn select_functions(
267+
compilation_unit: &CompilationUnit,
268+
selected_columns: &[String],
269+
) -> Result<Vec<Row>, String> {
242270
let mut rows: Vec<Row> = vec![];
243-
let ast_functions = function::select_clang_functions(path);
271+
let ast_functions = function::select_clang_functions(compilation_unit);
244272
for function in ast_functions.iter() {
245273
let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(selected_columns.len());
246274

@@ -340,9 +368,12 @@ fn select_functions(path: &str, selected_columns: &[String]) -> Result<Vec<Row>,
340368
Ok(rows)
341369
}
342370

343-
fn select_variables(path: &str, selected_columns: &[String]) -> Result<Vec<Row>, String> {
371+
fn select_variables(
372+
compilation_unit: &CompilationUnit,
373+
selected_columns: &[String],
374+
) -> Result<Vec<Row>, String> {
344375
let mut rows: Vec<Row> = vec![];
345-
let ast_variables = global::select_clang_variables(path);
376+
let ast_variables = global::select_clang_variables(compilation_unit);
346377
for variable in ast_variables.iter() {
347378
let mut values: Vec<Box<dyn Value>> = Vec::with_capacity(selected_columns.len());
348379
for field_name in selected_columns {

src/main.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use std::path::Path;
44
use crate::engine::EvaluationResult::SelectedGroups;
55
use arguments::Arguments;
66
use arguments::Command;
7-
use data_provider::ClangAstDataProvider;
7+
use clang_parser::parse_files;
8+
use data_provider::ClangDataProvider;
89
use gitql_cli::arguments::OutputFormat;
910
use gitql_cli::diagnostic_reporter;
1011
use gitql_cli::diagnostic_reporter::DiagnosticReporter;
@@ -29,6 +30,7 @@ use schema::tables_fields_names;
2930
use schema::tables_fields_types;
3031

3132
mod arguments;
33+
mod clang_parser;
3234
mod data_provider;
3335
mod schema;
3436
mod visitor;
@@ -70,7 +72,10 @@ fn main() {
7072
env.with_aggregation_functions(&aggregation_signatures, aggregation_functions);
7173
env.with_window_functions(&window_signatures, window_function);
7274

73-
execute_clangql_query(query, &arguments, files, &mut env, &mut reporter);
75+
let compilation_units = parse_files(files);
76+
let provider: Box<dyn DataProvider> =
77+
Box::new(ClangDataProvider::new(compilation_units));
78+
execute_clangql_query(query, &arguments, &mut env, &provider, &mut reporter);
7479
}
7580
Command::Help => {
7681
arguments::print_help_list();
@@ -111,6 +116,9 @@ fn launch_clangql_repl(arguments: Arguments) {
111116
global_env.with_aggregation_functions(&aggregation_signatures, aggregation_functions);
112117
global_env.with_window_functions(&window_signatures, window_function);
113118

119+
let compilation_units = parse_files(files);
120+
let provider: Box<dyn DataProvider> = Box::new(ClangDataProvider::new(compilation_units));
121+
114122
let mut input = String::new();
115123

116124
loop {
@@ -145,8 +153,8 @@ fn launch_clangql_repl(arguments: Arguments) {
145153
execute_clangql_query(
146154
stdin_input.to_owned(),
147155
&arguments,
148-
files,
149156
&mut global_env,
157+
&provider,
150158
&mut reporter,
151159
);
152160

@@ -158,8 +166,8 @@ fn launch_clangql_repl(arguments: Arguments) {
158166
fn execute_clangql_query(
159167
query: String,
160168
arguments: &Arguments,
161-
files: &[String],
162169
env: &mut Environment,
170+
provider: &Box<dyn DataProvider>,
163171
reporter: &mut DiagnosticReporter,
164172
) {
165173
let front_start = std::time::Instant::now();
@@ -186,9 +194,6 @@ fn execute_clangql_query(
186194
let front_duration = front_start.elapsed();
187195

188196
let engine_start = std::time::Instant::now();
189-
let files = files.to_vec();
190-
let file_provider = ClangAstDataProvider::new(files);
191-
let provider: Box<dyn DataProvider> = Box::new(file_provider);
192197
let evaluation_result = engine::evaluate(env, &provider, query_node);
193198

194199
// Report Runtime exceptions if they exists

src/visitor/class.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
extern crate clang_sys;
22

33
use clang_sys::*;
4-
use std::ffi::c_char;
54
use std::ffi::c_void;
65
use std::ffi::CStr;
7-
use std::ptr;
86

7+
use crate::clang_parser::CompilationUnit;
98
use crate::visitor::location;
109

1110
pub struct ClassNode {
@@ -24,30 +23,13 @@ pub struct ClassAttributes {
2423
pub fields_count: u32,
2524
}
2625

27-
pub fn select_clang_classes(path: &str) -> Vec<ClassNode> {
26+
pub fn select_clang_classes(compilation_unit: &CompilationUnit) -> Vec<ClassNode> {
2827
let mut classes: Vec<ClassNode> = Vec::new();
2928
let data = &mut classes as *mut Vec<ClassNode> as *mut c_void;
3029

3130
unsafe {
32-
let index = clang_createIndex(0, 0);
33-
let translation_unit: CXTranslationUnit = clang_parseTranslationUnit(
34-
index,
35-
path.as_ptr() as *const c_char,
36-
ptr::null_mut(),
37-
0,
38-
ptr::null_mut(),
39-
0,
40-
0,
41-
);
42-
43-
let cursor = clang_getTranslationUnitCursor(translation_unit);
31+
let cursor = clang_getTranslationUnitCursor(compilation_unit.translation_unit);
4432
clang_visitChildren(cursor, visit_class_or_struct_declaration, data);
45-
46-
// Dispose the translation unit
47-
clang_disposeTranslationUnit(translation_unit);
48-
49-
// Dispose the index
50-
clang_disposeIndex(index);
5133
}
5234

5335
classes

src/visitor/enumeration.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
extern crate clang_sys;
22

33
use clang_sys::*;
4-
use std::ffi::c_char;
54
use std::ffi::c_void;
65
use std::ffi::CStr;
7-
use std::ptr;
86

7+
use crate::clang_parser::CompilationUnit;
98
use crate::visitor::location;
109

1110
pub struct EnumNode {
@@ -20,30 +19,13 @@ pub struct EnumAttributes {
2019
pub constants_count: u32,
2120
}
2221

23-
pub fn select_clang_enums(path: &str) -> Vec<EnumNode> {
22+
pub fn select_clang_enums(compilation_unit: &CompilationUnit) -> Vec<EnumNode> {
2423
let mut enums: Vec<EnumNode> = Vec::new();
2524
let data = &mut enums as *mut Vec<EnumNode> as *mut c_void;
2625

2726
unsafe {
28-
let index = clang_createIndex(0, 0);
29-
let translation_unit: CXTranslationUnit = clang_parseTranslationUnit(
30-
index,
31-
path.as_ptr() as *const c_char,
32-
ptr::null_mut(),
33-
0,
34-
ptr::null_mut(),
35-
0,
36-
0,
37-
);
38-
39-
let cursor = clang_getTranslationUnitCursor(translation_unit);
27+
let cursor = clang_getTranslationUnitCursor(compilation_unit.translation_unit);
4028
clang_visitChildren(cursor, visit_enum_declaration, data);
41-
42-
// Dispose the translation unit
43-
clang_disposeTranslationUnit(translation_unit);
44-
45-
// Dispose the index
46-
clang_disposeIndex(index);
4729
}
4830

4931
enums

0 commit comments

Comments
 (0)