From 85cb18be32d807dc53d733230cc9b88aa47461e1 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Sat, 11 Jan 2025 15:08:18 +0100 Subject: [PATCH] Restructure the tables to allow more customizations --- Cargo.lock | 1 + Cargo.toml | 1 + docs/ASTFunctions.md | 6 +++ src/clang_ql/data_provider.rs | 50 ++------------------- src/clang_ql/functions/ast/functions.rs | 43 ++++++++++++++++++ src/clang_ql/functions/ast/mod.rs | 18 ++++++++ src/clang_ql/functions/mod.rs | 26 +++++++++++ src/clang_ql/matchers/mod.rs | 9 ++++ src/clang_ql/mod.rs | 2 + src/clang_ql/schema.rs | 32 +++----------- src/clang_ql/types/function.rs | 24 ++++++++++ src/clang_ql/types/mod.rs | 3 ++ src/clang_ql/values/function.rs | 55 +++++++++++++++++++++++ src/clang_ql/values/mod.rs | 4 ++ src/clang_ql/visitors/function.rs | 58 ++----------------------- 15 files changed, 205 insertions(+), 127 deletions(-) create mode 100644 docs/ASTFunctions.md create mode 100644 src/clang_ql/functions/ast/functions.rs create mode 100644 src/clang_ql/functions/ast/mod.rs create mode 100644 src/clang_ql/functions/mod.rs create mode 100644 src/clang_ql/matchers/mod.rs create mode 100644 src/clang_ql/types/function.rs create mode 100644 src/clang_ql/values/function.rs diff --git a/Cargo.lock b/Cargo.lock index 50bd014..3992ff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,6 +91,7 @@ name = "clangql" version = "0.8.0" dependencies = [ "clang-sys", + "dyn-clone", "gitql-ast", "gitql-cli", "gitql-core", diff --git a/Cargo.toml b/Cargo.toml index f6f0b4d..25df3d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ gitql-ast = "0.31.0" gitql-parser = "0.34.0" gitql-engine = "0.35.0" clang-sys = "1.8.1" +dyn-clone = "1.0.17" diff --git a/docs/ASTFunctions.md b/docs/ASTFunctions.md new file mode 100644 index 0000000..2f1df8a --- /dev/null +++ b/docs/ASTFunctions.md @@ -0,0 +1,6 @@ +### AST function node functions + +| Function | Parameters | Return | Description | +| :-------------: | :----------------: | :----: | :----------------------------------: | +| is_virtual | (n : FunctionType) | Bool | True if the function is virtual | +| is_pure_virtual | (n : FunctionType) | Bool | True if the function is pure virtual | \ No newline at end of file diff --git a/src/clang_ql/data_provider.rs b/src/clang_ql/data_provider.rs index 94600ae..8208dae 100644 --- a/src/clang_ql/data_provider.rs +++ b/src/clang_ql/data_provider.rs @@ -17,6 +17,7 @@ use crate::clang_ql::visitors::function; use crate::clang_ql::visitors::global; use crate::clang_ql::visitors::unions; +use super::values::FunctionValue; use super::values::SourceLocValue; pub struct ClangDataProvider { @@ -238,58 +239,13 @@ fn select_functions( continue; } - if column_name == "args_count" { - values.push(Box::new(IntValue::new(function.arguments_count as i64))); - continue; - } - - if column_name == "class_name" { - values.push(Box::new(TextValue::new(function.class_name.to_owned()))); - continue; - } - if column_name == "return_type" { values.push(Box::new(TextValue::new(function.return_type.to_owned()))); continue; } - if column_name == "is_method" { - values.push(Box::new(BoolValue::new(function.is_method))); - continue; - } - - if column_name == "is_virtual" { - values.push(Box::new(BoolValue::new(function.is_virtual))); - continue; - } - - if column_name == "is_pure_virtual" { - values.push(Box::new(BoolValue::new(function.is_pure_virtual))); - continue; - } - - if column_name == "is_static" { - values.push(Box::new(BoolValue::new(function.is_static))); - continue; - } - - if column_name == "is_const" { - values.push(Box::new(BoolValue::new(function.is_const))); - continue; - } - - if column_name == "has_template" { - values.push(Box::new(BoolValue::new(function.has_template))); - continue; - } - - if column_name == "access_modifier" { - values.push(Box::new(IntValue::new(function.access_modifier as i64))); - continue; - } - - if column_name == "is_variadic" { - values.push(Box::new(BoolValue::new(function.is_variadic))); + if column_name == "ast_function" { + values.push(Box::new(FunctionValue::new(function.clone()))); continue; } diff --git a/src/clang_ql/functions/ast/functions.rs b/src/clang_ql/functions/ast/functions.rs new file mode 100644 index 0000000..11d4d18 --- /dev/null +++ b/src/clang_ql/functions/ast/functions.rs @@ -0,0 +1,43 @@ +use std::collections::HashMap; + +use clang_sys::clang_CXXMethod_isPureVirtual; +use clang_sys::clang_CXXMethod_isVirtual; +use gitql_ast::types::boolean::BoolType; +use gitql_core::signature::Signature; +use gitql_core::signature::StandardFunction; +use gitql_core::values::base::Value; +use gitql_core::values::boolean::BoolValue; + +use crate::clang_ql::types::FunctionType; +use crate::clang_ql::values::FunctionValue; + +#[inline(always)] +pub fn register_ast_function_functions(map: &mut HashMap<&'static str, StandardFunction>) { + map.insert("is_virtual", function_is_virtual); + map.insert("is_pure_virtual", is_pure_virtual); +} + +#[inline(always)] +pub fn register_ast_function_signatures(map: &mut HashMap<&'static str, Signature>) { + map.insert( + "is_virtual", + Signature::with_return(Box::new(BoolType)).add_parameter(Box::new(FunctionType)), + ); + + map.insert( + "is_pure_virtual", + Signature::with_return(Box::new(BoolType)).add_parameter(Box::new(FunctionType)), + ); +} + +fn function_is_virtual(values: &[Box]) -> Box { + let ast_node = values[0].as_any().downcast_ref::().unwrap(); + let is_virtual = unsafe { clang_CXXMethod_isVirtual(ast_node.node.cursor) != 0 }; + Box::new(BoolValue::new(is_virtual)) +} + +fn is_pure_virtual(values: &[Box]) -> Box { + let ast_node = values[0].as_any().downcast_ref::().unwrap(); + let is_virtual = unsafe { clang_CXXMethod_isPureVirtual(ast_node.node.cursor) != 0 }; + Box::new(BoolValue::new(is_virtual)) +} diff --git a/src/clang_ql/functions/ast/mod.rs b/src/clang_ql/functions/ast/mod.rs new file mode 100644 index 0000000..756962f --- /dev/null +++ b/src/clang_ql/functions/ast/mod.rs @@ -0,0 +1,18 @@ +mod functions; +use functions::register_ast_function_functions; +use functions::register_ast_function_signatures; + +use std::collections::HashMap; + +use gitql_core::signature::Signature; +use gitql_core::signature::StandardFunction; + +#[inline(always)] +pub fn register_ast_functions(map: &mut HashMap<&'static str, StandardFunction>) { + register_ast_function_functions(map); +} + +#[inline(always)] +pub fn register_ast_signatures(map: &mut HashMap<&'static str, Signature>) { + register_ast_function_signatures(map); +} diff --git a/src/clang_ql/functions/mod.rs b/src/clang_ql/functions/mod.rs new file mode 100644 index 0000000..622950c --- /dev/null +++ b/src/clang_ql/functions/mod.rs @@ -0,0 +1,26 @@ +use std::collections::HashMap; +use std::sync::OnceLock; + +use gitql_core::signature::Signature; +use gitql_core::signature::StandardFunction; +use gitql_std::standard::standard_function_signatures; +use gitql_std::standard::standard_functions; + +mod ast; + +#[inline(always)] +pub fn clang_ql_functions() -> &'static HashMap<&'static str, StandardFunction> { + static HASHMAP: OnceLock> = OnceLock::new(); + HASHMAP.get_or_init(|| { + let mut map = standard_functions().to_owned(); + ast::register_ast_functions(&mut map); + map + }) +} + +#[inline(always)] +pub fn clang_ql_functions_signatures() -> HashMap<&'static str, Signature> { + let mut map = standard_function_signatures().to_owned(); + ast::register_ast_signatures(&mut map); + map +} diff --git a/src/clang_ql/matchers/mod.rs b/src/clang_ql/matchers/mod.rs new file mode 100644 index 0000000..006eb07 --- /dev/null +++ b/src/clang_ql/matchers/mod.rs @@ -0,0 +1,9 @@ +use dyn_clone::DynClone; + +use super::values::FunctionNode; + +dyn_clone::clone_trait_object!(FunctionMatcher); + +pub trait FunctionMatcher: DynClone { + fn is_match(&self, function: FunctionNode) -> bool; +} diff --git a/src/clang_ql/mod.rs b/src/clang_ql/mod.rs index ac944dc..5637096 100644 --- a/src/clang_ql/mod.rs +++ b/src/clang_ql/mod.rs @@ -1,5 +1,7 @@ pub mod clang_parser; pub mod data_provider; +pub mod functions; +pub mod matchers; pub mod schema; pub mod types; pub mod values; diff --git a/src/clang_ql/schema.rs b/src/clang_ql/schema.rs index 2b8b2c7..1a2aa00 100644 --- a/src/clang_ql/schema.rs +++ b/src/clang_ql/schema.rs @@ -9,11 +9,12 @@ use gitql_core::environment::Environment; use gitql_core::schema::Schema; use gitql_std::aggregation::aggregation_function_signatures; use gitql_std::aggregation::aggregation_functions; -use gitql_std::standard::standard_function_signatures; -use gitql_std::standard::standard_functions; use gitql_std::window::window_function_signatures; use gitql_std::window::window_functions; +use super::functions::clang_ql_functions; +use super::functions::clang_ql_functions_signatures; +use super::types::FunctionType; use super::types::SourceLocType; fn tables_fields_types() -> HashMap<&'static str, Box> { @@ -21,19 +22,10 @@ fn tables_fields_types() -> HashMap<&'static str, Box> { map.insert("name", Box::new(TextType)); map.insert("type", Box::new(TextType)); map.insert("signature", Box::new(TextType)); - map.insert("class_name", Box::new(TextType)); + map.insert("ast_function", Box::new(FunctionType)); - map.insert("access_modifier", Box::new(IntType)); - - map.insert("is_method", Box::new(BoolType)); - map.insert("is_virtual", Box::new(BoolType)); - map.insert("is_pure_virtual", Box::new(BoolType)); - map.insert("is_static", Box::new(BoolType)); - map.insert("is_const", Box::new(BoolType)); - map.insert("is_variadic", Box::new(BoolType)); map.insert("is_volatile", Box::new(BoolType)); map.insert("is_struct", Box::new(BoolType)); - map.insert("has_template", Box::new(BoolType)); map.insert("return_type", Box::new(TextType)); map.insert("type_literal", Box::new(TextType)); @@ -47,7 +39,6 @@ fn tables_fields_types() -> HashMap<&'static str, Box> { map.insert("size", Box::new(IntType)); map.insert("align", Box::new(IntType)); - // Source code location columns map.insert("source_loc", Box::new(SourceLocType)); map } @@ -79,17 +70,8 @@ fn tables_fields_names() -> &'static HashMap<&'static str, Vec<&'static str>> { vec![ "name", "signature", - "args_count", "return_type", - "class_name", - "is_method", - "is_virtual", - "is_pure_virtual", - "is_static", - "is_const", - "has_template", - "access_modifier", - "is_variadic", + "ast_function", "source_loc", ], ); @@ -104,8 +86,8 @@ pub fn create_clang_ql_environment() -> Environment { tables_fields_types: tables_fields_types().to_owned(), }; - let std_signatures = standard_function_signatures(); - let std_functions = standard_functions(); + let std_signatures = clang_ql_functions_signatures(); + let std_functions = clang_ql_functions(); let aggregation_signatures = aggregation_function_signatures(); let aggregation_functions = aggregation_functions(); diff --git a/src/clang_ql/types/function.rs b/src/clang_ql/types/function.rs new file mode 100644 index 0000000..9b58982 --- /dev/null +++ b/src/clang_ql/types/function.rs @@ -0,0 +1,24 @@ +use std::any::Any; + +use gitql_ast::types::base::DataType; + +#[derive(Clone)] +pub struct FunctionType; + +impl DataType for FunctionType { + fn literal(&self) -> String { + "Function".to_string() + } + + #[allow(clippy::borrowed_box)] + fn equals(&self, other: &Box) -> bool { + let self_type: Box = Box::new(FunctionType); + other.is_any() + || other.is_variant_contains(&self_type) + || other.as_any().downcast_ref::().is_some() + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/clang_ql/types/mod.rs b/src/clang_ql/types/mod.rs index 85f3222..9517d1b 100644 --- a/src/clang_ql/types/mod.rs +++ b/src/clang_ql/types/mod.rs @@ -1,2 +1,5 @@ mod source_location; pub use source_location::SourceLocType; + +mod function; +pub use function::FunctionType; diff --git a/src/clang_ql/values/function.rs b/src/clang_ql/values/function.rs new file mode 100644 index 0000000..4da7f57 --- /dev/null +++ b/src/clang_ql/values/function.rs @@ -0,0 +1,55 @@ +use clang_sys::CXCursor; +use gitql_core::values::base::Value; + +use crate::clang_ql::types::FunctionType; + +use super::FileLocation; + +#[derive(Clone)] +pub struct FunctionNode { + pub name: String, + pub cursor: CXCursor, + pub parent: CXCursor, + pub signature: String, + pub return_type: String, + pub location: FileLocation, +} + +#[derive(Clone)] +pub struct FunctionValue { + pub node: FunctionNode, +} + +impl FunctionValue { + pub fn new(node: FunctionNode) -> Self { + FunctionValue { node } + } +} + +impl Value for FunctionValue { + fn literal(&self) -> String { + self.node.signature.to_string() + } + + fn equals(&self, other: &Box) -> bool { + if let Some(other_fun) = other.as_any().downcast_ref::() { + return self.node.name.eq(&other_fun.node.name) + && self.node.signature.eq(&other_fun.node.signature) + && self.node.return_type.eq(&other_fun.node.return_type) + && self.node.location.eq(&other_fun.node.location); + } + false + } + + fn compare(&self, _other: &Box) -> Option { + None + } + + fn data_type(&self) -> Box { + Box::new(FunctionType) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} diff --git a/src/clang_ql/values/mod.rs b/src/clang_ql/values/mod.rs index b791b85..c83848b 100644 --- a/src/clang_ql/values/mod.rs +++ b/src/clang_ql/values/mod.rs @@ -1,3 +1,7 @@ mod source_location; pub use source_location::FileLocation; pub use source_location::SourceLocValue; + +mod function; +pub use function::FunctionNode; +pub use function::FunctionValue; diff --git a/src/clang_ql/visitors/function.rs b/src/clang_ql/visitors/function.rs index e489dd6..9e04635 100644 --- a/src/clang_ql/visitors/function.rs +++ b/src/clang_ql/visitors/function.rs @@ -5,26 +5,9 @@ use std::ffi::c_void; use std::ffi::CStr; use crate::clang_ql::clang_parser::CompilationUnit; -use crate::clang_ql::values::FileLocation; +use crate::clang_ql::values::FunctionNode; use crate::clang_ql::visitors::location; -pub struct FunctionNode { - pub name: String, - pub signature: String, - pub return_type: String, - pub arguments_count: i32, - pub class_name: String, - pub is_method: bool, - pub is_virtual: bool, - pub is_pure_virtual: bool, - pub is_static: bool, - pub is_const: bool, - pub has_template: bool, - pub access_modifier: i32, - pub is_variadic: bool, - pub location: FileLocation, -} - pub fn select_clang_functions(compilation_unit: &CompilationUnit) -> Vec { let mut functions: Vec = Vec::new(); let data = &mut functions as *mut Vec as *mut c_void; @@ -67,49 +50,14 @@ extern "C" fn visit_children( let return_type = CStr::from_ptr(clang_getCString(result_type_spelling)).to_string_lossy(); - let arguments_count = clang_getNumArgTypes(function_type); - - let mut is_method = false; - let mut has_template = false; - let mut class_name = String::from("None"); - let mut is_virtual = false; - let mut is_pure_virtual = false; - let mut is_static = false; - let mut is_const = false; - - if cursor_kind == CXCursor_CXXMethod { - is_method = true; - has_template = cursor_kind == CXCursor_FunctionTemplate; - - let parent_spelling = clang_getCursorSpelling(parent); - let parent_name = - CStr::from_ptr(clang_getCString(parent_spelling)).to_string_lossy(); - class_name = parent_name.to_string(); - - is_virtual = clang_CXXMethod_isVirtual(cursor) != 0; - is_pure_virtual = clang_CXXMethod_isPureVirtual(cursor) != 0; - is_static = clang_CXXMethod_isStatic(cursor) != 0; - is_const = clang_CXXMethod_isConst(cursor) != 0; - } - - let access_modifier = clang_getCXXAccessSpecifier(cursor); - let is_variadic = clang_isFunctionTypeVariadic(function_type) != 0; let location = location::visit_source_location(cursor); functions.push(FunctionNode { name: name.to_string(), + cursor, + parent, signature: signature.to_string(), return_type: return_type.to_string(), - arguments_count, - class_name, - is_method, - is_virtual, - is_pure_virtual, - is_static, - is_const, - has_template, - access_modifier, - is_variadic, location, });