sqruff_lib_core/
segments.rs

1use crate::edit_type::EditType;
2use crate::lint_fix::LintFix;
3use crate::parser::segments::fix::SourceFix;
4
5type LintFixIdx = usize;
6
7/// For a given fix anchor, count of the fix edit types and fixes for it."""
8#[derive(Debug, Default)]
9pub struct AnchorEditInfo {
10    pub delete: usize,
11    pub replace: usize,
12    pub create_before: usize,
13    pub create_after: usize,
14    pub fixes: Vec<LintFix>,
15    pub source_fixes: Vec<SourceFix>,
16    // First fix of edit_type "replace" in "fixes"
17    pub first_replace: Option<LintFixIdx>,
18}
19
20impl AnchorEditInfo {
21    /// Returns total count of fixes.
22    #[allow(dead_code)]
23    fn total(&self) -> usize {
24        self.delete + self.replace + self.create_before + self.create_after
25    }
26
27    /// Returns True if valid combination of fixes for anchor.
28    ///
29    /// Cases:
30    /// * 0-1 fixes of any type: Valid
31    /// * 2 fixes: Valid if and only if types are create_before and create_after
32    #[allow(dead_code)]
33    fn is_valid(&self) -> bool {
34        let total = self.total();
35        if total <= 1 {
36            // Definitely valid (i.e. no conflict) if 0 or 1. In practice, this
37            // function probably won't be called if there are 0 fixes, but 0 is
38            // valid; it simply means "no fixes to apply".
39            true
40        } else if total == 2 {
41            // This is only OK for this special case. We allow this because
42            // the intent is clear (i.e. no conflict): Insert something *before*
43            // the segment and something else *after* the segment.
44            self.create_before == 1 && self.create_after == 1
45        } else {
46            // Definitely bad if > 2.
47            false
48        }
49    }
50
51    /// Adds the fix and updates stats.
52    ///
53    /// We also allow potentially multiple source fixes on the same anchor by
54    /// condensing them together here.
55    pub fn add(&mut self, fix: LintFix) {
56        if self.fixes.contains(&fix) {
57            // Deduplicate fixes in case it's already in there.
58            return;
59        };
60
61        if fix.is_just_source_edit() {
62            self.source_fixes.extend(fix.edit[0].get_source_fixes());
63
64            if let Some(_first_replace) = &self.first_replace {
65                unimplemented!();
66            }
67        }
68
69        if fix.edit_type == EditType::Replace && self.first_replace.is_none() {
70            self.first_replace = Some(self.fixes.len());
71        }
72
73        match fix.edit_type {
74            EditType::CreateBefore => self.create_before += 1,
75            EditType::CreateAfter => self.create_after += 1,
76            EditType::Replace => self.replace += 1,
77            EditType::Delete => self.delete += 1,
78        };
79
80        self.fixes.push(fix);
81    }
82}