Skip to main content

gobject_linter/rules/
property_enum_coverage.rs

1use gobject_ast::model::{EnumInfo, FileModel};
2
3use crate::{
4    ast_context::AstContext,
5    config::Config,
6    rules::{Rule, Violation},
7};
8
9pub struct PropertyEnumCoverage;
10
11impl Rule for PropertyEnumCoverage {
12    fn name(&self) -> &'static str {
13        "property_enum_coverage"
14    }
15
16    fn description(&self) -> &'static str {
17        "Ensure all property enum values have corresponding g_param_spec or g_object_class_override_property"
18    }
19
20    fn category(&self) -> crate::rules::Category {
21        crate::rules::Category::Correctness
22    }
23
24    fn check_enum(
25        &self,
26        _ast_context: &AstContext,
27        _config: &Config,
28        enum_info: &EnumInfo,
29        file: &FileModel,
30        violations: &mut Vec<Violation>,
31    ) {
32        if !enum_info.is_property_enum() {
33            return;
34        }
35
36        let property_values: Vec<&str> = enum_info
37            .values
38            .iter()
39            .filter(|v| !v.is_prop_0() && !v.is_prop_last())
40            .map(|v| v.name.as_str())
41            .collect();
42
43        if property_values.is_empty() {
44            return;
45        }
46
47        let Some(gobject_type) = file.find_gobject_type_for_property_enum(enum_info) else {
48            return;
49        };
50
51        let installed_properties: Vec<_> = gobject_type
52            .properties
53            .iter()
54            .filter_map(|assignment| assignment.get_installed_enum_value())
55            .collect();
56
57        for prop_name in property_values {
58            if !installed_properties.iter().any(|p| p == &prop_name) {
59                violations.push(self.violation(
60                    &file.path,
61                    enum_info.location.line,
62                    1,
63                    format!(
64                        "Property enum value '{}' is declared but never installed in {}",
65                        prop_name,
66                        gobject_type.class_init_function_name()
67                    ),
68                ));
69            }
70        }
71    }
72}