codesearch 0.1.15

A fast, intelligent CLI tool with multiple search modes (regex, fuzzy, semantic), code analysis, and dead code detection for popular programming languages
Documentation
//! Declaration Detection for Structural Search
//!
//! Provides lightweight heuristic detection of whether a line of code
//! is a symbol declaration (function, class, variable, etc.) or a usage.
//!
//! This enables `--only-declarations` and `--only-usages` filters.

use crate::types::DeclarationFilter;
use regex::RegexSet;
use std::sync::LazyLock;

/// Pre-compiled patterns that match common declaration syntax across languages.
static DECLARATION_PATTERNS: LazyLock<RegexSet> = LazyLock::new(|| {
    RegexSet::new([
        // Rust
        r"^\s*pub\s+(fn|struct|enum|type|trait|use|mod|const|static|unsafe\s+fn)\b",
        r"^\s*(fn|struct|enum|type|trait|impl|mod|const|static|unsafe\s+fn|macro)\b",
        r"^\s*(let|mut)\s+",
        // Python / Ruby / Shell
        r"^\s*(def|class)\s+",
        // JavaScript / TypeScript
        r"^\s*(function|class|const|let|var|interface|type|enum)\s+",
        r"^\s*(export|public|private|protected)\s+(function|class|const|let|var|interface|type)\b",
        // Go / C / C++ / Java / C#
        r"^\s*(func|struct|class|interface|typedef|enum|const|var|using)\s+",
        r"^\s*(public|private|protected|static|final|abstract)\s+.*\b(class|interface|enum|void|int|float|double|bool|string|char|byte|long|short)\b",
        // General type declarations
        r"^\s*(typedef|struct|union|enum)\b",
    ])
    .expect("declaration patterns are valid")
});

/// Check if a line is a symbol declaration.
///
/// Uses a lightweight regex heuristic that covers common declaration
/// syntax across Rust, Python, JavaScript, TypeScript, Go, C, C++, Java, and C#.
pub fn is_declaration_line(line: &str) -> bool {
    DECLARATION_PATTERNS.is_match(line)
}

/// Determine whether a search result should be included based on declaration filter.
pub fn should_include_declaration(line: &str, filter: Option<&DeclarationFilter>) -> bool {
    match filter {
        None => true,
        Some(DeclarationFilter::Declarations) => is_declaration_line(line),
        Some(DeclarationFilter::Usages) => !is_declaration_line(line),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_rust_function_declaration() {
        assert!(is_declaration_line("fn main() {}"));
        assert!(is_declaration_line("pub fn helper() {}"));
        assert!(is_declaration_line("  pub fn indented() {}"));
    }

    #[test]
    fn test_rust_struct_declaration() {
        assert!(is_declaration_line("struct Point { x: i32, y: i32 }"));
        assert!(is_declaration_line("pub struct Config;"));
    }

    #[test]
    fn test_python_declaration() {
        assert!(is_declaration_line("def helper():"));
        assert!(is_declaration_line("class MyClass:"));
    }

    #[test]
    fn test_js_declaration() {
        assert!(is_declaration_line("function helper() {}"));
        assert!(is_declaration_line("const x = 42;"));
        assert!(is_declaration_line("class Helper {}"));
    }

    #[test]
    fn test_usage_not_declaration() {
        assert!(!is_declaration_line("    helper();"));
        assert!(!is_declaration_line("println!(\"hello\");"));
        assert!(!is_declaration_line("result = helper();"));
        assert!(!is_declaration_line("do_something(helper);"));
    }

    #[test]
    fn test_should_include_filter() {
        assert!(should_include_declaration("fn main() {}", None));
        assert!(should_include_declaration(
            "fn main() {}",
            Some(&DeclarationFilter::Declarations)
        ));
        assert!(!should_include_declaration(
            "helper();",
            Some(&DeclarationFilter::Declarations)
        ));
        assert!(should_include_declaration(
            "helper();",
            Some(&DeclarationFilter::Usages)
        ));
        assert!(!should_include_declaration(
            "fn main() {}",
            Some(&DeclarationFilter::Usages)
        ));
    }
}