gobject_linter/rules/
use_g_value_set_static_string.rs1use gobject_ast::model::{CallExpression, Expression, FileModel, FunctionDefItem};
2
3use crate::{
4 ast_context::AstContext,
5 config::Config,
6 rules::{Fix, Rule, Violation},
7};
8
9pub struct UseGValueSetStaticString;
10
11impl Rule for UseGValueSetStaticString {
12 fn name(&self) -> &'static str {
13 "use_g_value_set_static_string"
14 }
15
16 fn description(&self) -> &'static str {
17 "Use g_value_set_static_string for string literals instead of g_value_set_string"
18 }
19
20 fn category(&self) -> crate::rules::Category {
21 crate::rules::Category::Perf
22 }
23
24 fn fixable(&self) -> bool {
25 true
26 }
27
28 fn check_func_impl(
29 &self,
30 _ast_context: &AstContext,
31 config: &Config,
32 func: &FunctionDefItem,
33 file: &FileModel,
34 violations: &mut Vec<Violation>,
35 ) {
36 for call in func.find_calls(&["g_value_set_string"]) {
37 self.check_call(file, call, config, violations);
38 }
39 }
40}
41
42impl UseGValueSetStaticString {
43 fn check_call(
44 &self,
45 file: &FileModel,
46 call: &CallExpression,
47 config: &Config,
48 violations: &mut Vec<Violation>,
49 ) {
50 if call.arguments.len() < 2 {
52 return;
53 }
54
55 let Some(second_expr) = call.get_arg(1) else {
57 return;
58 };
59 if !second_expr.is_string_literal() {
60 return;
61 }
62
63 let Expression::StringLiteral(string_lit) = second_expr else {
65 unreachable!();
66 };
67
68 let args: Vec<&str> = call
70 .arguments
71 .iter()
72 .filter_map(|arg| arg.location().as_str())
73 .collect();
74 let replacement = config.style.format_call("g_value_set_static_string", &args);
75
76 let fix = Fix::new(
77 call.location.start_byte,
78 call.location.end_byte,
79 replacement,
80 );
81
82 violations.push(self.violation_with_fix_at(
83 &file.path,
84 &call.location,
85 format!(
86 "Use g_value_set_static_string instead of g_value_set_string for string literal {}",
87 string_lit.value
88 ),
89 fix,
90 ));
91 }
92}