Skip to content

Commit daaa83d

Browse files
committed
Implement m_oneof, m_allof and m_noneof combine matchers functions
1 parent a0d4abd commit daaa83d

File tree

6 files changed

+193
-2
lines changed

6 files changed

+193
-2
lines changed

.github/workflows/ci.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,15 @@ jobs:
1818
steps:
1919
- uses: actions/checkout@v4
2020
- uses: dtolnay/rust-toolchain@stable
21-
- run: cargo fmt --all -- --check
21+
- run: cargo fmt --all -- --check
22+
23+
clippy:
24+
name: Clippy
25+
runs-on: ubuntu-latest
26+
steps:
27+
- run: wget https://apt.llvm.org/llvm.sh
28+
- run: chmod +x llvm.sh
29+
- run: sudo ./llvm.sh 18
30+
- uses: actions/checkout@v4
31+
- uses: dtolnay/rust-toolchain@stable
32+
- run: cargo clippy -- -D warnings

docs/MatcherFunctions.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,12 @@
1616
| m_destructor | () | FunctionMatcher | Create Matcher to match function is destructor |
1717
| m_public | () | FunctionMatcher | Create Matcher to match public function |
1818
| m_protected | () | FunctionMatcher | Create Matcher to match protected function |
19-
| m_private | () | FunctionMatcher | Create Matcher to match private function |
19+
| m_private | () | FunctionMatcher | Create Matcher to match private function |
20+
21+
### Combine matchers functions
22+
23+
| Function | Parameters | Return | Description |
24+
| :------: | :----------------------: | :-------------: | :----------------------------------------------------------------: |
25+
| m_oneof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if any sub matcher is true |
26+
| m_allof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if all of sub matcher are true |
27+
| m_noneof | (n : ...FunctionMatcher) | FunctionMatcher | Create a matcher that returns true if none of sub matcher are true |
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use std::collections::HashMap;
2+
3+
use gitql_ast::types::dynamic::DynamicType;
4+
use gitql_ast::types::varargs::VarargsType;
5+
use gitql_ast::types::variant::VariantType;
6+
use gitql_core::signature::Signature;
7+
use gitql_core::signature::StandardFunction;
8+
use gitql_core::values::base::Value;
9+
use gitql_std::meta_types::first_element_type;
10+
11+
use crate::clang_ql::matchers::CombineMatcher;
12+
use crate::clang_ql::matchers::Matcher;
13+
use crate::clang_ql::types::FunctionMatcherType;
14+
use crate::clang_ql::values::FunctionMatcherValue;
15+
use crate::clang_ql::values::FunctionNode;
16+
17+
#[inline(always)]
18+
pub(crate) fn register_combine_matchers_functions(
19+
map: &mut HashMap<&'static str, StandardFunction>,
20+
) {
21+
map.insert("m_oneof", matcher_combine_oneof);
22+
map.insert("m_allof", matcher_combine_allof);
23+
map.insert("m_noneof", matcher_combine_noneof);
24+
}
25+
26+
#[inline(always)]
27+
pub(crate) fn register_combine_matchers_signatures(map: &mut HashMap<&'static str, Signature>) {
28+
map.insert(
29+
"m_oneof",
30+
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
31+
.add_parameter(Box::new(VariantType::new(vec![Box::new(
32+
FunctionMatcherType,
33+
)])))
34+
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
35+
first_element_type,
36+
))))),
37+
);
38+
39+
map.insert(
40+
"m_allof",
41+
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
42+
.add_parameter(Box::new(VariantType::new(vec![Box::new(
43+
FunctionMatcherType,
44+
)])))
45+
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
46+
first_element_type,
47+
))))),
48+
);
49+
50+
map.insert(
51+
"m_noneof",
52+
Signature::with_return(Box::new(DynamicType::new(first_element_type)))
53+
.add_parameter(Box::new(VariantType::new(vec![Box::new(
54+
FunctionMatcherType,
55+
)])))
56+
.add_parameter(Box::new(VarargsType::new(Box::new(DynamicType::new(
57+
first_element_type,
58+
))))),
59+
);
60+
}
61+
62+
fn matcher_combine_oneof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
63+
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
64+
for value in values.iter() {
65+
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
66+
matchers.push(matcher_value.matcher.to_owned());
67+
}
68+
}
69+
70+
let combine_matcher = Box::new(CombineMatcher::create_one_of(matchers));
71+
Box::new(FunctionMatcherValue::new(combine_matcher))
72+
}
73+
74+
fn matcher_combine_allof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
75+
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
76+
for value in values.iter() {
77+
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
78+
matchers.push(matcher_value.matcher.to_owned());
79+
}
80+
}
81+
82+
let combine_matcher = Box::new(CombineMatcher::create_all_of(matchers));
83+
Box::new(FunctionMatcherValue::new(combine_matcher))
84+
}
85+
86+
fn matcher_combine_noneof(values: &[Box<dyn Value>]) -> Box<dyn Value> {
87+
let mut matchers: Vec<Box<dyn Matcher<FunctionNode>>> = vec![];
88+
for value in values.iter() {
89+
if let Some(matcher_value) = value.as_any().downcast_ref::<FunctionMatcherValue>() {
90+
matchers.push(matcher_value.matcher.to_owned());
91+
}
92+
}
93+
94+
let combine_matcher = Box::new(CombineMatcher::create_none_of(matchers));
95+
Box::new(FunctionMatcherValue::new(combine_matcher))
96+
}

src/clang_ql/functions/matchers/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ use std::collections::HashMap;
33
use gitql_core::signature::Signature;
44
use gitql_core::signature::StandardFunction;
55

6+
mod combine;
67
mod function;
78

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

1315
#[inline(always)]
1416
pub(crate) fn register_matchers_signatures(map: &mut HashMap<&'static str, Signature>) {
1517
function::register_function_matchers_signatures(map);
18+
combine::register_combine_matchers_signatures(map);
1619
}

src/clang_ql/matchers/combine.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,77 @@
11
use super::Matcher;
22

3+
#[allow(clippy::enum_variant_names)]
4+
#[derive(PartialEq, Clone)]
5+
enum CombineMatcherKind {
6+
OneOf,
7+
AllOf,
8+
NoneOf,
9+
}
10+
11+
#[derive(Clone)]
12+
pub struct CombineMatcher<T> {
13+
matchers: Vec<Box<dyn Matcher<T>>>,
14+
kind: CombineMatcherKind,
15+
}
16+
17+
impl<T: Clone> CombineMatcher<T> {
18+
pub fn create_one_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
19+
CombineMatcher {
20+
matchers,
21+
kind: CombineMatcherKind::OneOf,
22+
}
23+
}
24+
25+
pub fn create_all_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
26+
CombineMatcher {
27+
matchers,
28+
kind: CombineMatcherKind::AllOf,
29+
}
30+
}
31+
32+
pub fn create_none_of(matchers: Vec<Box<dyn Matcher<T>>>) -> Self {
33+
CombineMatcher {
34+
matchers,
35+
kind: CombineMatcherKind::AllOf,
36+
}
37+
}
38+
}
39+
40+
impl<T: Clone> Matcher<T> for CombineMatcher<T> {
41+
fn is_match(&self, node: &T) -> bool {
42+
let mut matches_count = 0;
43+
let matcher_kind = &self.kind;
44+
for matcher in self.matchers.iter() {
45+
let is_matches = matcher.is_match(node);
46+
47+
// If kind is `oneOf` and one if matches, return true
48+
if is_matches && CombineMatcherKind::OneOf.eq(matcher_kind) {
49+
return true;
50+
}
51+
52+
// If kind is `allOf` and one is not matches, return false
53+
if !is_matches && CombineMatcherKind::AllOf.eq(matcher_kind) {
54+
return false;
55+
}
56+
57+
// If kind is `noneOf` and one is matches, return false
58+
if is_matches && CombineMatcherKind::NoneOf.eq(matcher_kind) {
59+
return false;
60+
}
61+
62+
if is_matches {
63+
matches_count += 1;
64+
}
65+
}
66+
67+
match self.kind {
68+
CombineMatcherKind::OneOf => matches_count > 1,
69+
CombineMatcherKind::AllOf => matches_count == self.matchers.len(),
70+
CombineMatcherKind::NoneOf => matches_count == 0,
71+
}
72+
}
73+
}
74+
375
#[derive(Clone)]
476
enum CombineUnaryMatcherKind {
577
Not,

src/clang_ql/matchers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub use function::IsStaticMethodMatcher;
1616
pub use function::IsVirtualMatcher;
1717

1818
mod combine;
19+
pub use combine::CombineMatcher;
1920
pub use combine::UnaryCombineMatcher;
2021

2122
dyn_clone::clone_trait_object!(<T> Matcher<T>);

0 commit comments

Comments
 (0)