code-buster 0.11.0

Repository-aware static analysis for AI-assisted development
Documentation
pub(crate) mod analyzer_config;
pub(crate) mod core;
pub(crate) mod flutter_build;
pub(crate) mod index;
pub(crate) mod lifecycle;
pub(crate) mod model_contracts;
pub(crate) mod model_duplication;
pub(crate) mod mvvm;
pub(crate) mod null_assertion;
pub(crate) mod oop;
pub(crate) mod package_cycle;
pub(crate) mod performance;
pub(crate) mod reliability;
pub(crate) mod security;

pub(crate) fn attached_declaration_line(source: &str, declaration_line: usize) -> usize {
    attached_line(
        source,
        declaration_line,
        is_attachable_declaration_prefix,
        is_documentation_start,
    )
}

pub(crate) fn attached_documentation_line(source: &str, declaration_line: usize) -> usize {
    attached_line(
        source,
        declaration_line,
        is_documentation_prefix,
        is_documentation_prefix,
    )
}

fn attached_line(
    source: &str,
    declaration_line: usize,
    is_attachable: impl Fn(&str) -> bool,
    marks_attachment: impl Fn(&str) -> bool,
) -> usize {
    let lines = source.split('\n').collect::<Vec<_>>();
    let mut index = declaration_line.saturating_sub(1);
    let mut attached = false;
    while index > 0 {
        let previous = lines[index - 1].trim();
        if !is_attachable(previous) {
            break;
        }
        attached |= marks_attachment(previous);
        index -= 1;
    }
    if attached {
        index + 1
    } else {
        declaration_line
    }
}

fn is_attachable_declaration_prefix(line: &str) -> bool {
    ["//", "/*", "*", "@"]
        .iter()
        .any(|prefix| line.starts_with(prefix))
        || line == "*/"
}

fn is_documentation_prefix(line: &str) -> bool {
    ["///", "/**", "*", "@"]
        .iter()
        .any(|prefix| line.starts_with(prefix))
}

fn is_documentation_start(line: &str) -> bool {
    ["///", "/**", "@"]
        .iter()
        .any(|prefix| line.starts_with(prefix))
}

struct QuoteAwareCodeBytes<'a> {
    bytes: &'a [u8],
    index: usize,
    quote: Option<u8>,
}

impl<'a> QuoteAwareCodeBytes<'a> {
    fn new(source: &'a str, start: usize) -> Self {
        Self {
            bytes: source.as_bytes(),
            index: start,
            quote: None,
        }
    }

    fn advance_quoted(&mut self, byte: u8, quote: u8) {
        if byte == b'\\' && self.index < self.bytes.len() {
            self.index += 1;
        } else if byte == quote {
            self.quote = None;
        }
    }
}

impl Iterator for QuoteAwareCodeBytes<'_> {
    type Item = (usize, u8);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let index = self.index;
            let &byte = self.bytes.get(index)?;
            self.index += 1;
            match self.quote {
                Some(quote) => self.advance_quoted(byte, quote),
                None if matches!(byte, b'\'' | b'"') => self.quote = Some(byte),
                None => return Some((index, byte)),
            }
        }
    }
}

fn matching_delimiter_in(
    code_bytes: impl Iterator<Item = (usize, u8)>,
    opening: u8,
    closing: u8,
) -> Option<usize> {
    let mut depth = 0usize;
    for (index, byte) in code_bytes {
        if byte == opening {
            depth += 1;
            continue;
        }
        if byte != closing {
            continue;
        }
        depth = depth.checked_sub(1)?;
        if depth == 0 {
            return Some(index);
        }
    }
    None
}

pub(crate) fn matching_delimiter(
    source: &str,
    open: usize,
    opening: u8,
    closing: u8,
) -> Option<usize> {
    let code_bytes = source.as_bytes().iter().copied().enumerate().skip(open);
    matching_delimiter_in(code_bytes, opening, closing)
}

pub(crate) fn quote_aware_matching_delimiter(
    source: &str,
    open: usize,
    opening: u8,
    closing: u8,
) -> Option<usize> {
    matching_delimiter_in(QuoteAwareCodeBytes::new(source, open), opening, closing)
}

pub(crate) fn top_level_arrow(source: &str) -> Option<usize> {
    let bytes = source.as_bytes();
    let mut depths = [0usize; 3];
    let mut quote = None;
    let mut index = 0usize;
    while index + 1 < bytes.len() {
        if let Some(current_quote) = quote {
            if bytes[index] == b'\\' {
                index += 2;
                continue;
            }
            if bytes[index] == current_quote {
                quote = None;
            }
        } else {
            match bytes[index] {
                b'\'' | b'"' => quote = Some(bytes[index]),
                b'(' => depths[0] += 1,
                b')' => depths[0] = depths[0].saturating_sub(1),
                b'[' => depths[1] += 1,
                b']' => depths[1] = depths[1].saturating_sub(1),
                b'{' => depths[2] += 1,
                b'}' => depths[2] = depths[2].saturating_sub(1),
                b'=' if depths == [0, 0, 0] && bytes[index + 1] == b'>' => {
                    return Some(index);
                }
                _ => {}
            }
        }
        index += 1;
    }
    None
}

fn split_code_bytes<const TRACK_ANGLES: bool>(
    source: &str,
    separator: u8,
    code_bytes: impl Iterator<Item = (usize, u8)>,
) -> Vec<&str> {
    let mut result = Vec::new();
    let mut start = 0usize;
    let mut depths = [0usize; 4];
    for (index, byte) in code_bytes {
        match byte {
            b'(' => depths[0] += 1,
            b')' => depths[0] = depths[0].saturating_sub(1),
            b'[' => depths[1] += 1,
            b']' => depths[1] = depths[1].saturating_sub(1),
            b'{' => depths[2] += 1,
            b'}' => depths[2] = depths[2].saturating_sub(1),
            b'<' if TRACK_ANGLES => depths[3] += 1,
            b'>' if TRACK_ANGLES => depths[3] = depths[3].saturating_sub(1),
            value if value == separator && depths == [0, 0, 0, 0] => {
                result.push(&source[start..index]);
                start = index + 1;
            }
            _ => {}
        }
    }
    result.push(&source[start..]);
    result
}

pub(crate) fn split_top_level(source: &str, separator: u8) -> Vec<&str> {
    let code_bytes = source.as_bytes().iter().copied().enumerate();
    split_code_bytes::<false>(source, separator, code_bytes)
}

pub(crate) fn quote_aware_split_top_level(source: &str, separator: u8) -> Vec<&str> {
    split_code_bytes::<false>(source, separator, QuoteAwareCodeBytes::new(source, 0))
}

pub(crate) fn quote_aware_split_top_level_with_angles(source: &str, separator: u8) -> Vec<&str> {
    split_code_bytes::<true>(source, separator, QuoteAwareCodeBytes::new(source, 0))
}