#[cfg(feature = "kotlin-ast")]
pub struct KotlinAstStrategy;
#[cfg(feature = "kotlin-ast")]
impl KotlinAstStrategy {
fn extract_name_from_node(
node: &crate::models::unified_ast::UnifiedAstNode,
content: &str,
) -> Option<String> {
let start = node.source_range.start as usize;
let end = node.source_range.end as usize;
if start >= content.len() || end > content.len() || start >= end {
return None;
}
let source_text = &content[start..end];
match &node.kind {
crate::models::unified_ast::AstKind::Function(_) => {
Self::extract_function_name(source_text)
}
crate::models::unified_ast::AstKind::Type(_) => Self::extract_class_name(source_text),
_ => None,
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub(crate) fn extract_function_name(source_text: &str) -> Option<String> {
if let Some(fun_pos) = source_text.find("fun ") {
let after_fun = &source_text[fun_pos + 4..];
if let Some(paren_pos) = after_fun.find('(') {
let name_part = &after_fun[..paren_pos];
return name_part
.split_whitespace()
.next()
.map(std::string::ToString::to_string);
}
}
None
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub(crate) fn extract_class_name(source_text: &str) -> Option<String> {
let lines = source_text.lines().next()?; let words: Vec<&str> = lines.split_whitespace().collect();
if words.len() >= 3 && words[0] == "enum" && words[1] == "class" {
let name_with_extras = words[2];
let name = name_with_extras
.split(['(', ':', '<', '{'])
.next()
.unwrap_or(name_with_extras)
.trim();
return Some(name.to_string());
}
if words.len() >= 3 && words[0] == "data" && words[1] == "class" {
let name_with_extras = words[2];
let name = name_with_extras
.split(['(', ':', '<'])
.next()
.unwrap_or(name_with_extras);
return Some(name.to_string());
}
for i in 0..words.len() {
if matches!(words[i], "class" | "interface" | "object") && i + 1 < words.len() {
let name_with_extras = words[i + 1];
let name = name_with_extras
.split(['(', ':', '<'])
.next()
.unwrap_or(name_with_extras);
return Some(name.to_string());
}
}
None
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub(crate) fn byte_pos_to_line(byte_pos: usize, content_lines: &[&str]) -> usize {
let mut current_pos = 0;
for (line_idx, line) in content_lines.iter().enumerate() {
if current_pos + line.len() >= byte_pos {
return line_idx + 1; }
current_pos += line.len() + 1; }
content_lines.len() }
}
#[cfg(feature = "kotlin-ast")]
#[async_trait]
impl AstStrategy for KotlinAstStrategy {
async fn analyze(&self, path: &Path, classifier: &FileClassifier) -> Result<FileContext> {
use crate::services::ast::languages::kotlin_strategy::KotlinStrategy;
use crate::services::ast::AstStrategy as UnifiedAstStrategy;
let kotlin_strategy = KotlinStrategy;
UnifiedAstStrategy::analyze(&kotlin_strategy, path, classifier).await
}
fn supports_extension(&self, ext: &str) -> bool {
matches!(ext, "kt" | "kts")
}
}