Skip to content

Commit

Permalink
Implement m_oneof, m_allof and m_noneof combine matchers functions
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrDeveloper committed Jan 12, 2025
1 parent a0d4abd commit daaa83d
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 2 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,15 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo fmt --all -- --check
- run: cargo fmt --all -- --check

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- run: wget https://apt.llvm.org/llvm.sh
- run: chmod +x llvm.sh
- run: sudo ./llvm.sh 18
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo clippy -- -D warnings
10 changes: 9 additions & 1 deletion docs/MatcherFunctions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@
| m_destructor | () | FunctionMatcher | Create Matcher to match function is destructor |
| m_public | () | FunctionMatcher | Create Matcher to match public function |
| m_protected | () | FunctionMatcher | Create Matcher to match protected function |
| m_private | () | FunctionMatcher | Create Matcher to match private function |
| m_private | () | FunctionMatcher | Create Matcher to match private function |

### Combine matchers functions

| Function | Parameters | Return | Description |
| :------: | :----------------------: | :-------------: | :----------------------------------------------------------------: |
| m_oneof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if any sub matcher is true |
| m_allof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if all of sub matcher are true |
| m_noneof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if none of sub matcher are true |
96 changes: 96 additions & 0 deletions src/clang_ql/functions/matchers/combine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use std::collections::HashMap;

use gitql_ast::types::dynamic::DynamicType;
use gitql_ast::types::varargs::VarargsType;
use gitql_ast::types::variant::VariantType;
use gitql_core::signature::Signature;
use gitql_core::signature::StandardFunction;
use gitql_core::values::base::Value;
use gitql_std::meta_types::first_element_type;

use crate::clang_ql::matchers::CombineMatcher;
use crate::clang_ql::matchers::Matcher;
use crate::clang_ql::types::FunctionMatcherType;
use crate::clang_ql::values::FunctionMatcherValue;
use crate::clang_ql::values::FunctionNode;

#[inline(always)]
pub(crate) fn register_combine_matchers_functions(
map: &mut HashMap<&'static str, StandardFunction>,
) {
map.insert("m_oneof", matcher_combine_oneof);
map.insert("m_allof", matcher_combine_allof);
map.insert("m_noneof", matcher_combine_noneof);
}

#[inline(always)]
pub(crate) fn register_combine_matchers_signatures(map: &mut HashMap<&'static str, Signature>) {
map.insert(
"m_oneof",
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
.add_parameter(Box::new(VariantType::new(vec![Box::new(
FunctionMatcherType,
)])))
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
first_element_type,
))))),
);

map.insert(
"m_allof",
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
.add_parameter(Box::new(VariantType::new(vec![Box::new(
FunctionMatcherType,
)])))
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
first_element_type,
))))),
);

map.insert(
"m_noneof",
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
.add_parameter(Box::new(VariantType::new(vec![Box::new(
FunctionMatcherType,
)])))
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
first_element_type,
))))),
);
}

fn matcher_combine_oneof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
for value in values.iter() {
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
matchers.push(matcher_value.matcher.to_owned());
}
}

let combine_matcher = Box::new(CombineMatcher::create_one_of(matchers));
Box::new(FunctionMatcherValue::new(combine_matcher))
}

fn matcher_combine_allof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
for value in values.iter() {
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
matchers.push(matcher_value.matcher.to_owned());
}
}

let combine_matcher = Box::new(CombineMatcher::create_all_of(matchers));
Box::new(FunctionMatcherValue::new(combine_matcher))
}

fn matcher_combine_noneof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
for value in values.iter() {
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
matchers.push(matcher_value.matcher.to_owned());
}
}

let combine_matcher = Box::new(CombineMatcher::create_none_of(matchers));
Box::new(FunctionMatcherValue::new(combine_matcher))
}
3 changes: 3 additions & 0 deletions src/clang_ql/functions/matchers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ use std::collections::HashMap;
use gitql_core::signature::Signature;
use gitql_core::signature::StandardFunction;

mod combine;
mod function;

#[inline(always)]
pub(crate) fn register_matchers_functions(map: &mut HashMap<&'static str, StandardFunction>) {
function::register_function_matchers_functions(map);
combine::register_combine_matchers_functions(map);
}

#[inline(always)]
pub(crate) fn register_matchers_signatures(map: &mut HashMap<&'static str, Signature>) {
function::register_function_matchers_signatures(map);
combine::register_combine_matchers_signatures(map);
}
72 changes: 72 additions & 0 deletions src/clang_ql/matchers/combine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,77 @@
use super::Matcher;

#[allow(clippy::enum_variant_names)]
#[derive(PartialEq, Clone)]
enum CombineMatcherKind {
OneOf,
AllOf,
NoneOf,
}

#[derive(Clone)]
pub struct CombineMatcher<T> {
matchers: Vec<Box<dyn Matcher<T>>>,
kind: CombineMatcherKind,
}

impl<T: Clone> CombineMatcher<T> {
pub fn create_one_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
CombineMatcher {
matchers,
kind: CombineMatcherKind::OneOf,
}
}

pub fn create_all_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
CombineMatcher {
matchers,
kind: CombineMatcherKind::AllOf,
}
}

pub fn create_none_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
CombineMatcher {
matchers,
kind: CombineMatcherKind::AllOf,
}
}
}

impl<T: Clone> Matcher<T> for CombineMatcher<T> {
fn is_match(&self, node: &T) -> bool {
let mut matches_count = 0;
let matcher_kind = &self.kind;
for matcher in self.matchers.iter() {
let is_matches = matcher.is_match(node);

// If kind is `oneOf` and one if matches, return true
if is_matches && CombineMatcherKind::OneOf.eq(matcher_kind) {
return true;
}

// If kind is `allOf` and one is not matches, return false
if !is_matches && CombineMatcherKind::AllOf.eq(matcher_kind) {
return false;
}

// If kind is `noneOf` and one is matches, return false
if is_matches && CombineMatcherKind::NoneOf.eq(matcher_kind) {
return false;
}

if is_matches {
matches_count += 1;
}
}

match self.kind {
CombineMatcherKind::OneOf => matches_count > 1,
CombineMatcherKind::AllOf => matches_count == self.matchers.len(),
CombineMatcherKind::NoneOf => matches_count == 0,
}
}
}

#[derive(Clone)]
enum CombineUnaryMatcherKind {
Not,
Expand Down
1 change: 1 addition & 0 deletions src/clang_ql/matchers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub use function::IsStaticMethodMatcher;
pub use function::IsVirtualMatcher;

mod combine;
pub use combine::CombineMatcher;
pub use combine::UnaryCombineMatcher;

dyn_clone::clone_trait_object!(<T> Matcher<T>);
Expand Down

0 comments on commit daaa83d

Please sign in to comment.