use gobject_ast::{Expression, Statement};
use crate::{
ast_context::AstContext,
config::Config,
rules::{Fix, Rule, Violation},
};
pub struct UseGStrcmp0;
impl Rule for UseGStrcmp0 {
fn name(&self) -> &'static str {
"use_g_strcmp0"
}
fn description(&self) -> &'static str {
"Suggest g_strcmp0 instead of strcmp if arguments can be NULL (NULL-safe)"
}
fn category(&self) -> crate::rules::Category {
crate::rules::Category::Style
}
fn fixable(&self) -> bool {
true
}
fn check_func_impl(
&self,
_ast_context: &AstContext,
_config: &Config,
func: &gobject_ast::top_level::FunctionDefItem,
file: &gobject_ast::FileModel,
violations: &mut Vec<Violation>,
) {
self.check_statements(&func.body_statements, file, violations);
}
}
impl UseGStrcmp0 {
fn check_statements(
&self,
statements: &[Statement],
file: &gobject_ast::FileModel,
violations: &mut Vec<Violation>,
) {
for stmt in statements {
stmt.walk_expressions(&mut |expr| {
expr.walk(&mut |e| {
self.check_expression(e, file, violations);
});
});
}
}
fn check_expression(
&self,
expr: &Expression,
file: &gobject_ast::FileModel,
violations: &mut Vec<Violation>,
) {
if expr.is_call_to("strcmp") {
let Expression::Call(call) = expr else {
return;
};
let fix = Fix::new(
call.location.start_byte,
call.location.start_byte + "strcmp".len(),
"g_strcmp0".to_string(),
);
violations.push(self.violation_with_fix(
&file.path,
call.location.line,
call.location.column,
"Consider g_strcmp0 instead of strcmp if arguments can be NULL (g_strcmp0 is NULL-safe)".to_string(),
fix,
));
}
}
}