From b5efd62729ae551ca51b77a8f5dab270c7eec228 Mon Sep 17 00:00:00 2001 From: "deepak.nailwal" Date: Sun, 9 Nov 2025 17:09:13 +0530 Subject: [PATCH 1/2] feature: kotlin support for AST arsing --- refact-agent/engine/Cargo.toml | 1 + .../engine/src/ast/treesitter/language_id.rs | 1 + .../engine/src/ast/treesitter/parsers.rs | 6 + .../src/ast/treesitter/parsers/kotlin.rs | 1007 +++++++++++++++++ .../src/ast/treesitter/parsers/tests.rs | 1 + .../parsers/tests/cases/kotlin/main.kt | 35 + .../parsers/tests/cases/kotlin/main.kt.json | 1 + .../parsers/tests/cases/kotlin/person.kt | 56 + .../tests/cases/kotlin/person.kt.decl_json | 1 + .../parsers/tests/cases/kotlin/person.kt.json | 1 + .../tests/cases/kotlin/person.kt.skeleton | 1 + .../ast/treesitter/parsers/tests/kotlin.rs | 82 ++ 12 files changed, 1193 insertions(+) create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/kotlin.rs create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton create mode 100644 refact-agent/engine/src/ast/treesitter/parsers/tests/kotlin.rs diff --git a/refact-agent/engine/Cargo.toml b/refact-agent/engine/Cargo.toml index 759cab845..aa3f3a5f0 100644 --- a/refact-agent/engine/Cargo.toml +++ b/refact-agent/engine/Cargo.toml @@ -92,6 +92,7 @@ tree-sitter = "0.25" tree-sitter-cpp = "0.23" tree-sitter-java = "0.23" tree-sitter-javascript = "0.23" +tree-sitter-kotlin-ng = "1.1.0" tree-sitter-python = "0.23" tree-sitter-rust = "0.23" tree-sitter-typescript = "0.23" diff --git a/refact-agent/engine/src/ast/treesitter/language_id.rs b/refact-agent/engine/src/ast/treesitter/language_id.rs index 716a8fda4..cf0e1e266 100644 --- a/refact-agent/engine/src/ast/treesitter/language_id.rs +++ b/refact-agent/engine/src/ast/treesitter/language_id.rs @@ -135,6 +135,7 @@ impl From for LanguageId { lang if lang == tree_sitter_cpp::LANGUAGE.into() => Self::Cpp, lang if lang == tree_sitter_python::LANGUAGE.into() => Self::Python, lang if lang == tree_sitter_java::LANGUAGE.into() => Self::Java, + lang if lang == tree_sitter_kotlin_ng::LANGUAGE.into() => Self::Kotlin, lang if lang == tree_sitter_javascript::LANGUAGE.into() => Self::JavaScript, lang if lang == tree_sitter_rust::LANGUAGE.into() => Self::Rust, lang if lang == tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into() => Self::TypeScript, diff --git a/refact-agent/engine/src/ast/treesitter/parsers.rs b/refact-agent/engine/src/ast/treesitter/parsers.rs index 342db3e2c..8804a88eb 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers.rs +++ b/refact-agent/engine/src/ast/treesitter/parsers.rs @@ -13,6 +13,7 @@ pub(crate) mod rust; mod tests; mod utils; mod java; +mod kotlin; mod cpp; mod ts; mod js; @@ -49,6 +50,10 @@ pub(crate) fn get_ast_parser(language_id: LanguageId) -> Result { + let parser = kotlin::KotlinParser::new()?; + Ok(Box::new(parser)) + } LanguageId::Cpp => { let parser = cpp::CppParser::new()?; Ok(Box::new(parser)) @@ -91,6 +96,7 @@ pub fn get_language_id_by_filename(filename: &PathBuf) -> Option { "inl" | "inc" | "tpp" | "tpl" => Some(LanguageId::Cpp), "py" | "py3" | "pyx" => Some(LanguageId::Python), "java" => Some(LanguageId::Java), + "kt" | "kts" => Some(LanguageId::Kotlin), "js" | "jsx" => Some(LanguageId::JavaScript), "rs" => Some(LanguageId::Rust), "ts" => Some(LanguageId::TypeScript), diff --git a/refact-agent/engine/src/ast/treesitter/parsers/kotlin.rs b/refact-agent/engine/src/ast/treesitter/parsers/kotlin.rs new file mode 100644 index 000000000..b29752c92 --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/kotlin.rs @@ -0,0 +1,1007 @@ +use std::collections::{HashMap, VecDeque}; +use std::path::PathBuf; +use std::string::ToString; +use std::sync::Arc; + +#[cfg(test)] +use itertools::Itertools; + +use parking_lot::RwLock; +use similar::DiffableStr; +use tree_sitter::{Node, Parser, Range}; +use uuid::Uuid; + +use crate::ast::treesitter::ast_instance_structs::{AstSymbolFields, AstSymbolInstanceArc, ClassFieldDeclaration, CommentDefinition, FunctionArg, FunctionCall, FunctionDeclaration, ImportDeclaration, ImportType, StructDeclaration, TypeDef, VariableDefinition, VariableUsage}; +use crate::ast::treesitter::language_id::LanguageId; +use crate::ast::treesitter::parsers::{AstLanguageParser, internal_error, ParserError}; +use crate::ast::treesitter::parsers::utils::{CandidateInfo, get_guid}; + +pub(crate) struct KotlinParser { + pub parser: Parser, +} + +static KOTLIN_KEYWORDS: [&str; 64] = [ + "abstract", "actual", "annotation", "as", "break", "by", "catch", "class", "companion", "const", + "constructor", "continue", "crossinline", "data", "do", "dynamic", "else", "enum", "expect", "external", + "final", "finally", "for", "fun", "get", "if", "import", "in", "infix", "init", "inline", "inner", + "interface", "internal", "is", "lateinit", "noinline", "object", "open", "operator", "out", "override", + "package", "private", "protected", "public", "reified", "return", "sealed", "set", "super", "suspend", + "tailrec", "this", "throw", "try", "typealias", "typeof", "val", "var", "vararg", "when", "where", "while" +]; + +static SYSTEM_MODULES: [&str; 2] = [ + "kotlin", "java", +]; + +pub fn parse_type(parent: &Node, code: &str) -> Option { + let kind = parent.kind(); + let text = code.slice(parent.byte_range()).to_string(); + + match kind { + "type_identifier" | "identifier" | "user_type" => { + return Some(TypeDef { + name: Some(text), + inference_info: None, + inference_info_guid: None, + is_pod: false, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }); + } + "void_type" | "integral_type" | "floating_point_type" | "boolean_type" => { + return Some(TypeDef { + name: None, + inference_info: Some(text), + inference_info_guid: None, + is_pod: true, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }); + } + "nullable_type" => { + if let Some(non_null_type) = parent.child_by_field_name("type") { + if let Some(mut dtype) = parse_type(&non_null_type, code) { + dtype.name = Some(format!("{}?", dtype.name.unwrap_or_default())); + return Some(dtype); + } + } + } + "generic_type" => { + let mut decl = TypeDef { + name: None, + inference_info: None, + inference_info_guid: None, + is_pod: false, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }; + for i in 0..parent.child_count() { + let child = parent.child(i).unwrap(); + match child.kind() { + "type_identifier" => { + decl.name = Some(code.slice(child.byte_range()).to_string()); + } + "type_arguments" => { + for i in 0..child.child_count() { + let child = child.child(i).unwrap(); + if let Some(t) = parse_type(&child, code) { + decl.nested_types.push(t); + } + } + } + _ => {} + } + } + return Some(decl); + } + "array_type" => { + let mut decl = TypeDef { + name: Some("[]".to_string()), + inference_info: None, + inference_info_guid: None, + is_pod: false, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }; + if let Some(element) = parent.child_by_field_name("element") { + if let Some(dtype) = parse_type(&element, code) { + decl.nested_types.push(dtype); + } + } + return Some(decl); + } + "scoped_type_identifier" => { + let mut decl = TypeDef { + name: None, + inference_info: None, + inference_info_guid: None, + is_pod: false, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }; + + let mut parts = Vec::new(); + for i in 0..parent.child_count() { + let child = parent.child(i).unwrap(); + if child.kind() == "type_identifier" { + parts.push(code.slice(child.byte_range()).to_string()); + } + } + + if !parts.is_empty() { + decl.name = Some(parts.join(".")); + } + return Some(decl); + } + "function_type" => { + let mut decl = TypeDef { + name: Some("Function".to_string()), + inference_info: None, + inference_info_guid: None, + is_pod: false, + namespace: "".to_string(), + guid: None, + nested_types: vec![], + }; + + if let Some(parameters) = parent.child_by_field_name("parameters") { + for i in 0..parameters.child_count() { + let child = parameters.child(i).unwrap(); + if let Some(t) = parse_type(&child, code) { + decl.nested_types.push(t); + } + } + } + + if let Some(return_type) = parent.child_by_field_name("return_type") { + if let Some(t) = parse_type(&return_type, code) { + decl.nested_types.push(t); + } + } + + return Some(decl); + } + _ => {} + } + None +} + +fn parse_function_arg(parent: &Node, code: &str) -> FunctionArg { + let mut arg = FunctionArg::default(); + + if let Some(name) = parent.child_by_field_name("name") { + arg.name = code.slice(name.byte_range()).to_string(); + } + + if let Some(type_node) = parent.child_by_field_name("type") { + if let Some(dtype) = parse_type(&type_node, code) { + arg.type_ = Some(dtype); + } + } + + arg +} + +impl KotlinParser { + pub fn new() -> Result { + let mut parser = Parser::new(); + parser + .set_language(&tree_sitter_kotlin_ng::LANGUAGE.into()) + .map_err(internal_error)?; + Ok(KotlinParser { parser }) + } + + fn parse_class_declaration<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let mut decl = StructDeclaration::default(); + + decl.ast_fields.language = info.ast_fields.language; + decl.ast_fields.full_range = info.node.range(); + decl.ast_fields.declaration_range = info.node.range(); + decl.ast_fields.definition_range = info.node.range(); + decl.ast_fields.file_path = info.ast_fields.file_path.clone(); + decl.ast_fields.parent_guid = Some(info.parent_guid.clone()); + decl.ast_fields.guid = get_guid(); + decl.ast_fields.is_error = info.ast_fields.is_error; + + symbols.extend(self.find_error_usages(&info.node, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + + if let Some(name_node) = info.node.child_by_field_name("name") { + decl.ast_fields.name = code.slice(name_node.byte_range()).to_string(); + } else { + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + if child.kind() == "identifier" { + decl.ast_fields.name = code.slice(child.byte_range()).to_string(); + break; + } + } + } + + if let Some(node) = info.node.child_by_field_name("supertype") { + symbols.extend(self.find_error_usages(&node, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + for i in 0..node.child_count() { + let child = node.child(i).unwrap(); + if let Some(dtype) = parse_type(&child, code) { + decl.inherited_types.push(dtype); + } + } + } + + if let Some(node) = info.node.child_by_field_name("delegation_specifiers") { + symbols.extend(self.find_error_usages(&node, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + for i in 0..node.child_count() { + let child = node.child(i).unwrap(); + symbols.extend(self.find_error_usages(&child, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + match child.kind() { + "type_list" => { + for i in 0..child.child_count() { + let child = child.child(i).unwrap(); + if let Some(dtype) = parse_type(&child, code) { + decl.inherited_types.push(dtype); + } + } + } + _ => {} + } + } + } + + if let Some(_) = info.node.child_by_field_name("type_parameters") {} + + if let Some(body) = info.node.child_by_field_name("body") { + decl.ast_fields.definition_range = body.range(); + decl.ast_fields.declaration_range = Range { + start_byte: decl.ast_fields.full_range.start_byte, + end_byte: decl.ast_fields.definition_range.start_byte, + start_point: decl.ast_fields.full_range.start_point, + end_point: decl.ast_fields.definition_range.start_point, + }; + candidates.push_back(CandidateInfo { + ast_fields: decl.ast_fields.clone(), + node: body, + parent_guid: decl.ast_fields.guid.clone(), + }); + } else if let Some(body) = info.node.child_by_field_name("class_body") { + decl.ast_fields.definition_range = body.range(); + decl.ast_fields.declaration_range = Range { + start_byte: decl.ast_fields.full_range.start_byte, + end_byte: decl.ast_fields.definition_range.start_byte, + start_point: decl.ast_fields.full_range.start_point, + end_point: decl.ast_fields.definition_range.start_point, + }; + candidates.push_back(CandidateInfo { + ast_fields: decl.ast_fields.clone(), + node: body, + parent_guid: decl.ast_fields.guid.clone(), + }); + } else if let Some(body) = info.node.child_by_field_name("members") { + decl.ast_fields.definition_range = body.range(); + decl.ast_fields.declaration_range = Range { + start_byte: decl.ast_fields.full_range.start_byte, + end_byte: decl.ast_fields.definition_range.start_byte, + start_point: decl.ast_fields.full_range.start_point, + end_point: decl.ast_fields.definition_range.start_point, + }; + candidates.push_back(CandidateInfo { + ast_fields: decl.ast_fields.clone(), + node: body, + parent_guid: decl.ast_fields.guid.clone(), + }); + } else { + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + if child.kind() == "class_body" || child.kind() == "body" || child.kind() == "members" || + child.kind() == "{" || child.kind().contains("body") { + candidates.push_back(CandidateInfo { + ast_fields: decl.ast_fields.clone(), + node: child, + parent_guid: decl.ast_fields.guid.clone(), + }); + } + } + } + + symbols.push(Arc::new(RwLock::new(Box::new(decl)))); + symbols + } + + fn parse_function_declaration<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let mut decl = FunctionDeclaration::default(); + + decl.ast_fields.language = info.ast_fields.language; + decl.ast_fields.full_range = info.node.range(); + decl.ast_fields.declaration_range = info.node.range(); + decl.ast_fields.definition_range = info.node.range(); + decl.ast_fields.file_path = info.ast_fields.file_path.clone(); + decl.ast_fields.parent_guid = Some(info.parent_guid.clone()); + decl.ast_fields.guid = get_guid(); + decl.ast_fields.is_error = info.ast_fields.is_error; + + symbols.extend(self.find_error_usages(&info.node, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + + if let Some(name_node) = info.node.child_by_field_name("name") { + decl.ast_fields.name = code.slice(name_node.byte_range()).to_string(); + } else { + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + if child.kind() == "identifier" { + decl.ast_fields.name = code.slice(child.byte_range()).to_string(); + break; + } + } + } + + if let Some(parameters_node) = info.node.child_by_field_name("parameters") { + symbols.extend(self.find_error_usages(¶meters_node, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + decl.ast_fields.declaration_range = Range { + start_byte: decl.ast_fields.full_range.start_byte, + end_byte: parameters_node.end_byte(), + start_point: decl.ast_fields.full_range.start_point, + end_point: parameters_node.end_position(), + }; + + let mut function_args = vec![]; + for i in 0..parameters_node.child_count() { + let child = parameters_node.child(i).unwrap(); + symbols.extend(self.find_error_usages(&child, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + if child.kind() == "parameter" { + function_args.push(parse_function_arg(&child, code)); + } + } + decl.args = function_args; + } + + if let Some(return_type) = info.node.child_by_field_name("type") { + decl.return_type = parse_type(&return_type, code); + symbols.extend(self.find_error_usages(&return_type, code, &info.ast_fields.file_path, &decl.ast_fields.guid)); + } + + if let Some(body_node) = info.node.child_by_field_name("body") { + decl.ast_fields.definition_range = body_node.range(); + decl.ast_fields.declaration_range = Range { + start_byte: decl.ast_fields.full_range.start_byte, + end_byte: decl.ast_fields.definition_range.start_byte, + start_point: decl.ast_fields.full_range.start_point, + end_point: decl.ast_fields.definition_range.start_point, + }; + + for i in 0..body_node.child_count() { + let child = body_node.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(decl.ast_fields.guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: decl.ast_fields.guid.clone(), + }); + } + } else { + decl.ast_fields.declaration_range = decl.ast_fields.full_range; + } + + symbols.push(Arc::new(RwLock::new(Box::new(decl)))); + symbols + } + + fn parse_property_declaration<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + + let mut decl = ClassFieldDeclaration::default(); + + decl.ast_fields.language = info.ast_fields.language; + decl.ast_fields.full_range = info.node.range(); + decl.ast_fields.declaration_range = info.node.range(); + decl.ast_fields.file_path = info.ast_fields.file_path.clone(); + decl.ast_fields.parent_guid = Some(info.parent_guid.clone()); + decl.ast_fields.guid = get_guid(); + decl.ast_fields.is_error = info.ast_fields.is_error; + + if let Some(name) = info.node.child_by_field_name("name") { + decl.ast_fields.name = code.slice(name.byte_range()).to_string(); + } else { + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + + if child.kind() == "variable_declaration" { + for j in 0..child.child_count() { + let subchild = child.child(j).unwrap(); + if subchild.kind() == "identifier" { + decl.ast_fields.name = code.slice(subchild.byte_range()).to_string(); + break; + } + } + if !decl.ast_fields.name.is_empty() { + break; + } + } else if child.kind() == "identifier" { + decl.ast_fields.name = code.slice(child.byte_range()).to_string(); + break; + } + } + } + + if let Some(type_node) = info.node.child_by_field_name("type") { + if let Some(dtype) = parse_type(&type_node, code) { + decl.type_ = dtype; + } + } else { + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + + if child.kind() == "variable_declaration" { + for j in 0..child.child_count() { + let subchild = child.child(j).unwrap(); + if subchild.kind() == "function_type" || subchild.kind() == "type_identifier" || + subchild.kind() == "nullable_type" || subchild.kind() == "generic_type" || + subchild.kind() == "user_type" { + if let Some(dtype) = parse_type(&subchild, code) { + decl.type_ = dtype; + break; + } + } + } + if decl.type_.name.is_some() { + break; + } + } else if child.kind() == "function_type" || child.kind() == "type_identifier" || + child.kind() == "nullable_type" || child.kind() == "generic_type" || + child.kind() == "user_type" { + if let Some(dtype) = parse_type(&child, code) { + decl.type_ = dtype; + break; + } + } + } + } + + if let Some(initializer) = info.node.child_by_field_name("initializer") { + decl.type_.inference_info = Some(code.slice(initializer.byte_range()).to_string()); + + for i in 0..initializer.child_count() { + let child = initializer.child(i).unwrap(); + if child.kind() == "lambda_literal" || child.kind() == "lambda_expression" { + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(decl.ast_fields.guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: decl.ast_fields.guid.clone(), + }); + } + } + } + + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + match child.kind() { + "getter" | "setter" => { + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(decl.ast_fields.guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: decl.ast_fields.guid.clone(), + }); + } + _ => {} + } + } + + symbols.push(Arc::new(RwLock::new(Box::new(decl)))); + symbols + } + + fn parse_variable_declaration<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, _candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let mut type_ = TypeDef::default(); + + if let Some(type_node) = info.node.child_by_field_name("type") { + if let Some(dtype) = parse_type(&type_node, code) { + type_ = dtype; + } + } + + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + match child.kind() { + "variable_declarator" => { + let mut decl = VariableDefinition::default(); + decl.ast_fields.language = info.ast_fields.language; + decl.ast_fields.full_range = info.node.range(); + decl.ast_fields.file_path = info.ast_fields.file_path.clone(); + decl.ast_fields.parent_guid = Some(info.parent_guid.clone()); + decl.ast_fields.guid = get_guid(); + decl.ast_fields.is_error = info.ast_fields.is_error; + decl.type_ = type_.clone(); + + if let Some(name) = child.child_by_field_name("name") { + decl.ast_fields.name = code.slice(name.byte_range()).to_string(); + } + + if let Some(value) = child.child_by_field_name("value") { + decl.type_.inference_info = Some(code.slice(value.byte_range()).to_string()); + } + + symbols.push(Arc::new(RwLock::new(Box::new(decl)))); + } + _ => {} + } + } + + symbols + } + + fn parse_identifier<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, _candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let name = code.slice(info.node.byte_range()).to_string(); + + if KOTLIN_KEYWORDS.contains(&name.as_str()) { + return symbols; + } + + let mut usage = VariableUsage::default(); + usage.ast_fields.name = name; + usage.ast_fields.language = info.ast_fields.language; + usage.ast_fields.full_range = info.node.range(); + usage.ast_fields.file_path = info.ast_fields.file_path.clone(); + usage.ast_fields.parent_guid = Some(info.parent_guid.clone()); + usage.ast_fields.guid = get_guid(); + usage.ast_fields.is_error = info.ast_fields.is_error; + if let Some(caller_guid) = info.ast_fields.caller_guid.clone() { + usage.ast_fields.guid = caller_guid; + } + + symbols.push(Arc::new(RwLock::new(Box::new(usage)))); + symbols + } + + fn parse_call_expression<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let mut decl = FunctionCall::default(); + + decl.ast_fields.language = info.ast_fields.language; + decl.ast_fields.full_range = info.node.range(); + decl.ast_fields.file_path = info.ast_fields.file_path.clone(); + decl.ast_fields.parent_guid = Some(info.parent_guid.clone()); + decl.ast_fields.guid = get_guid(); + decl.ast_fields.is_error = info.ast_fields.is_error; + if let Some(caller_guid) = info.ast_fields.caller_guid.clone() { + decl.ast_fields.guid = caller_guid; + } + decl.ast_fields.caller_guid = Some(get_guid()); + + symbols.extend(self.find_error_usages(&info.node, code, &info.ast_fields.file_path, &info.parent_guid)); + + if let Some(name) = info.node.child_by_field_name("name") { + decl.ast_fields.name = code.slice(name.byte_range()).to_string(); + } + if let Some(type_) = info.node.child_by_field_name("type") { + symbols.extend(self.find_error_usages(&type_, code, &info.ast_fields.file_path, &info.parent_guid)); + if let Some(dtype) = parse_type(&type_, code) { + if let Some(name) = dtype.name { + decl.ast_fields.name = name; + } else { + decl.ast_fields.name = code.slice(type_.byte_range()).to_string(); + } + } else { + decl.ast_fields.name = code.slice(type_.byte_range()).to_string(); + } + } + if let Some(arguments) = info.node.child_by_field_name("arguments") { + symbols.extend(self.find_error_usages(&arguments, code, &info.ast_fields.file_path, &info.parent_guid)); + let mut new_ast_fields = info.ast_fields.clone(); + new_ast_fields.caller_guid = None; + for i in 0..arguments.child_count() { + let child = arguments.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: new_ast_fields.clone(), + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + } + if let Some(object) = info.node.child_by_field_name("receiver") { + candidates.push_back(CandidateInfo { + ast_fields: decl.ast_fields.clone(), + node: object, + parent_guid: info.parent_guid.clone(), + }); + } + + symbols.push(Arc::new(RwLock::new(Box::new(decl)))); + symbols + } + + fn parse_annotation<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, _candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + let mut usage = VariableUsage::default(); + + usage.ast_fields.name = code.slice(info.node.byte_range()).to_string(); + usage.ast_fields.language = info.ast_fields.language; + usage.ast_fields.full_range = info.node.range(); + usage.ast_fields.file_path = info.ast_fields.file_path.clone(); + usage.ast_fields.parent_guid = Some(info.parent_guid.clone()); + usage.ast_fields.guid = get_guid(); + usage.ast_fields.is_error = info.ast_fields.is_error; + + if usage.ast_fields.name.starts_with('@') { + usage.ast_fields.name = usage.ast_fields.name[1..].to_string(); + } + + symbols.push(Arc::new(RwLock::new(Box::new(usage)))); + symbols + } + + fn parse_field_access<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let mut symbols: Vec = vec![]; + + if let (Some(object), Some(field)) = (info.node.child_by_field_name("receiver"), info.node.child_by_field_name("field")) { + let mut usage = VariableUsage::default(); + usage.ast_fields.name = code.slice(field.byte_range()).to_string(); + usage.ast_fields.language = info.ast_fields.language; + usage.ast_fields.full_range = info.node.range(); + usage.ast_fields.file_path = info.ast_fields.file_path.clone(); + usage.ast_fields.guid = get_guid(); + usage.ast_fields.parent_guid = Some(info.parent_guid.clone()); + usage.ast_fields.caller_guid = Some(get_guid()); + if let Some(caller_guid) = info.ast_fields.caller_guid.clone() { + usage.ast_fields.guid = caller_guid; + } + candidates.push_back(CandidateInfo { + ast_fields: usage.ast_fields.clone(), + node: object, + parent_guid: info.parent_guid.clone(), + }); + symbols.push(Arc::new(RwLock::new(Box::new(usage)))); + } + + symbols + } + + fn parse_lambda_expression<'a>(&mut self, info: &CandidateInfo<'a>, _code: &str, candidates: &mut VecDeque>) -> Vec { + let symbols: Vec = vec![]; + + if let Some(parameters) = info.node.child_by_field_name("parameters") { + for i in 0..parameters.child_count() { + let child = parameters.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(info.parent_guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + } + + if let Some(body) = info.node.child_by_field_name("body") { + for i in 0..body.child_count() { + let child = body.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(info.parent_guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + } + + symbols + } + + fn find_error_usages(&mut self, parent: &Node, code: &str, path: &PathBuf, parent_guid: &Uuid) -> Vec { + let mut symbols: Vec = vec![]; + for i in 0..parent.child_count() { + let child = parent.child(i).unwrap(); + if child.kind() == "ERROR" { + symbols.extend(self.parse_error_usages(&child, code, path, parent_guid)); + } + } + symbols + } + + fn parse_error_usages(&mut self, parent: &Node, code: &str, path: &PathBuf, parent_guid: &Uuid) -> Vec { + let mut symbols: Vec = vec![]; + match parent.kind() { + "identifier" => { + let name = code.slice(parent.byte_range()).to_string(); + if KOTLIN_KEYWORDS.contains(&name.as_str()) { + return symbols; + } + + let mut usage = VariableUsage::default(); + usage.ast_fields.name = name; + usage.ast_fields.language = LanguageId::Kotlin; + usage.ast_fields.full_range = parent.range(); + usage.ast_fields.file_path = path.clone(); + usage.ast_fields.parent_guid = Some(parent_guid.clone()); + usage.ast_fields.guid = get_guid(); + usage.ast_fields.is_error = true; + symbols.push(Arc::new(RwLock::new(Box::new(usage)))); + } + "field_access" | "navigation_expression" => { + if let (Some(object), Some(field)) = (parent.child_by_field_name("receiver"), parent.child_by_field_name("field")) { + let usages = self.parse_error_usages(&object, code, path, parent_guid); + let mut usage = VariableUsage::default(); + usage.ast_fields.name = code.slice(field.byte_range()).to_string(); + usage.ast_fields.language = LanguageId::Kotlin; + usage.ast_fields.full_range = parent.range(); + usage.ast_fields.file_path = path.clone(); + usage.ast_fields.guid = get_guid(); + usage.ast_fields.parent_guid = Some(parent_guid.clone()); + if let Some(last) = usages.last() { + usage.ast_fields.caller_guid = last.read().fields().parent_guid.clone(); + } + symbols.extend(usages); + if !KOTLIN_KEYWORDS.contains(&usage.ast_fields.name.as_str()) { + symbols.push(Arc::new(RwLock::new(Box::new(usage)))); + } + } + } + _ => { + for i in 0..parent.child_count() { + let child = parent.child(i).unwrap(); + symbols.extend(self.parse_error_usages(&child, code, path, parent_guid)); + } + } + } + symbols + } + + fn parse_usages_<'a>(&mut self, info: &CandidateInfo<'a>, code: &str, candidates: &mut VecDeque>) -> Vec { + let kind = info.node.kind(); + + + match kind { + "class_declaration" | "interface_declaration" | "enum_declaration" | "object_declaration" => { + self.parse_class_declaration(info, code, candidates) + } + "function_declaration" | "fun" | "method_declaration" | "method" | "constructor" | "init" | "getter" | "setter" | + "function" | "member_function" | "class_function" | "method_definition" | "function_definition" => { + self.parse_function_declaration(info, code, candidates) + } + "property_declaration" | "val" | "var" | "property" | "mutable_property" | "immutable_property" | "lateinit" | + "val_declaration" | "var_declaration" | "const_declaration" | "member_property" | "class_property" => { + self.parse_property_declaration(info, code, candidates) + } + "companion_object" => { + let symbols: Vec = vec![]; + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(info.parent_guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + symbols + } + "local_variable_declaration" | "variable_declaration" => { + self.parse_variable_declaration(info, code, candidates) + } + "call_expression" | "function_call" => { + self.parse_call_expression(info, code, candidates) + } + "lambda_literal" | "lambda_expression" => { + self.parse_lambda_expression(info, code, candidates) + } + "identifier" => { + self.parse_identifier(info, code, candidates) + } + "field_access" | "navigation_expression" => { + self.parse_field_access(info, code, candidates) + } + "annotation" => { + self.parse_annotation(info, code, candidates) + } + "import_declaration" => { + let mut symbols: Vec = vec![]; + let mut def = ImportDeclaration::default(); + def.ast_fields.language = info.ast_fields.language; + def.ast_fields.full_range = info.node.range(); + def.ast_fields.file_path = info.ast_fields.file_path.clone(); + def.ast_fields.parent_guid = Some(info.parent_guid.clone()); + def.ast_fields.guid = get_guid(); + + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + if ["scoped_identifier", "identifier"].contains(&child.kind()) { + let path = code.slice(child.byte_range()).to_string(); + def.path_components = path.split(".").map(|x| x.to_string()).collect(); + if let Some(first) = def.path_components.first() { + if SYSTEM_MODULES.contains(&first.as_str()) { + def.import_type = ImportType::System; + } + } + } + } + + symbols.push(Arc::new(RwLock::new(Box::new(def)))); + symbols + } + "block_comment" | "line_comment" => { + let mut symbols: Vec = vec![]; + let mut def = CommentDefinition::default(); + def.ast_fields.language = info.ast_fields.language; + def.ast_fields.full_range = info.node.range(); + def.ast_fields.file_path = info.ast_fields.file_path.clone(); + def.ast_fields.parent_guid = Some(info.parent_guid.clone()); + def.ast_fields.guid = get_guid(); + def.ast_fields.is_error = info.ast_fields.is_error; + symbols.push(Arc::new(RwLock::new(Box::new(def)))); + symbols + } + "ERROR" => { + let symbols: Vec = vec![]; + let mut ast = info.ast_fields.clone(); + ast.is_error = true; + + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: ast.clone(), + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + symbols + } + "package_declaration" => { + vec![] + } + "class_body" | "members" | "body" => { + let symbols: Vec = vec![]; + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(info.parent_guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + symbols + } + _ => { + let symbols: Vec = vec![]; + for i in 0..info.node.child_count() { + let child = info.node.child(i).unwrap(); + candidates.push_back(CandidateInfo { + ast_fields: { + let mut ast_fields = AstSymbolFields::default(); + ast_fields.language = info.ast_fields.language; + ast_fields.full_range = child.range(); + ast_fields.file_path = info.ast_fields.file_path.clone(); + ast_fields.parent_guid = Some(info.parent_guid.clone()); + ast_fields.guid = get_guid(); + ast_fields.is_error = false; + ast_fields.caller_guid = None; + ast_fields + }, + node: child, + parent_guid: info.parent_guid.clone(), + }); + } + symbols + } + } + } + + fn parse_(&mut self, parent: &Node, code: &str, path: &PathBuf) -> Vec { + let mut symbols: Vec = vec![]; + let mut ast_fields = AstSymbolFields::default(); + ast_fields.file_path = path.clone(); + ast_fields.is_error = false; + ast_fields.language = LanguageId::Kotlin; + + let mut candidates = VecDeque::from(vec![CandidateInfo { + ast_fields, + node: parent.clone(), + parent_guid: get_guid(), + }]); + + while let Some(candidate) = candidates.pop_front() { + let symbols_l = self.parse_usages_(&candidate, code, &mut candidates); + symbols.extend(symbols_l); + } + + let guid_to_symbol_map: HashMap = symbols.iter() + .map(|s| (s.read().guid().clone(), s.clone())) + .collect(); + + for symbol in symbols.iter_mut() { + let guid = symbol.read().guid().clone(); + if let Some(parent_guid) = symbol.read().parent_guid() { + if let Some(parent) = guid_to_symbol_map.get(parent_guid) { + parent.write().fields_mut().childs_guid.push(guid); + } + } + } + + #[cfg(test)] + for symbol in symbols.iter_mut() { + let mut sym = symbol.write(); + sym.fields_mut().childs_guid = sym.fields_mut().childs_guid.iter() + .sorted_by_key(|x| { + guid_to_symbol_map.get(*x).unwrap().read().full_range().start_byte + }).map(|x| x.clone()).collect(); + } + + symbols + } +} + +impl AstLanguageParser for KotlinParser { + fn parse(&mut self, code: &str, path: &PathBuf) -> Vec { + let tree = self.parser.parse(code, None).unwrap(); + let symbols = self.parse_(&tree.root_node(), code, path); + symbols + } +} \ No newline at end of file diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests.rs b/refact-agent/engine/src/ast/treesitter/parsers/tests.rs index 134fb646e..6781027b2 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers/tests.rs +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests.rs @@ -19,6 +19,7 @@ use crate::files_in_workspace::Document; mod rust; mod python; mod java; +mod kotlin; mod cpp; mod ts; mod js; diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt new file mode 100644 index 000000000..358570d0c --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt @@ -0,0 +1,35 @@ +package com.example + +import kotlin.math.PI +import java.util.* + +fun main() { + val name = "Kotlin" + val version = 1.8 + println("Hello, $name version $version!") + + val numbers = listOf(1, 2, 3, 4, 5) + val doubled = numbers.map { it * 2 } + + val person = Person("Alice", 30) + person.greet() + + val calculator = Calculator() + val result = calculator.add(10, 20) + println("Result: $result") +} + +class Person(val name: String, val age: Int) { + fun greet() { + println("Hello, I'm $name and I'm $age years old") + } + + fun isAdult(): Boolean = age >= 18 +} + +class Calculator { + fun add(a: Int, b: Int): Int = a + b + fun subtract(a: Int, b: Int): Int = a - b + fun multiply(a: Int, b: Int): Int = a * b + fun divide(a: Int, b: Int): Double = a.toDouble() / b.toDouble() +} diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json @@ -0,0 +1 @@ +[] diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt new file mode 100644 index 000000000..5dcc1577e --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt @@ -0,0 +1,56 @@ +package com.example.model + +import java.time.LocalDate + +data class Person( + val name: String, + val age: Int, + val email: String? = null, + val birthDate: LocalDate? = null +) { + fun isAdult(): Boolean = age >= 18 + + fun getDisplayName(): String = name.uppercase() + + companion object { + fun create(name: String, age: Int): Person { + return Person(name, age) + } + } +} + +interface Greetable { + fun greet(): String +} + +class Employee( + name: String, + age: Int, + val department: String, + val salary: Double +) : Person(name, age), Greetable { + + override fun greet(): String { + return "Hello, I'm $name from $department department" + } + + fun getAnnualSalary(): Double = salary * 12 +} + +enum class Department { + ENGINEERING, + MARKETING, + SALES, + HR +} + +object Company { + val name = "TechCorp" + val employees = mutableListOf() + + fun addEmployee(employee: Employee) { + employees.add(employee) + } + + fun getEmployeeCount(): Int = employees.size +} diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json @@ -0,0 +1 @@ +[] diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json @@ -0,0 +1 @@ +[] diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton @@ -0,0 +1 @@ +[] diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/kotlin.rs b/refact-agent/engine/src/ast/treesitter/parsers/tests/kotlin.rs new file mode 100644 index 000000000..22eca8d6a --- /dev/null +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/kotlin.rs @@ -0,0 +1,82 @@ +use std::path::PathBuf; + +use crate::ast::treesitter::language_id::LanguageId; +use crate::ast::treesitter::parsers::kotlin::KotlinParser; +use crate::ast::treesitter::parsers::tests::{base_parser_test, base_skeletonizer_test, base_declaration_formatter_test}; + +#[test] +fn test_kotlin_main() { + let parser = KotlinParser::new().unwrap(); + let mut boxed_parser: Box = Box::new(parser); + let path = PathBuf::from("main.kt"); + let code = include_str!("cases/kotlin/main.kt"); + let symbols_str = include_str!("cases/kotlin/main.kt.json"); + base_parser_test(&mut boxed_parser, &path, code, symbols_str); +} + +#[test] +fn test_kotlin_person() { + let parser = KotlinParser::new().unwrap(); + let mut boxed_parser: Box = Box::new(parser); + let path = PathBuf::from("person.kt"); + let code = include_str!("cases/kotlin/person.kt"); + let symbols_str = include_str!("cases/kotlin/person.kt.json"); + base_parser_test(&mut boxed_parser, &path, code, symbols_str); +} + +#[test] +fn test_kotlin_skeletonizer() { + let parser = KotlinParser::new().unwrap(); + let mut boxed_parser: Box = Box::new(parser); + let path = PathBuf::from("person.kt"); + let code = include_str!("cases/kotlin/person.kt"); + let skeleton_ref_str = include_str!("cases/kotlin/person.kt.skeleton"); + base_skeletonizer_test(&LanguageId::Kotlin, &mut boxed_parser, &path, code, skeleton_ref_str); +} + +#[test] +fn test_kotlin_declaration_formatter() { + let parser = KotlinParser::new().unwrap(); + let mut boxed_parser: Box = Box::new(parser); + let path = PathBuf::from("person.kt"); + let code = include_str!("cases/kotlin/person.kt"); + let decls_ref_str = include_str!("cases/kotlin/person.kt.decl_json"); + base_declaration_formatter_test(&LanguageId::Kotlin, &mut boxed_parser, &path, code, decls_ref_str); +} + +#[test] +fn test_kotlin_lambda_properties() { + let parser = KotlinParser::new().unwrap(); + let mut boxed_parser: Box = Box::new(parser); + let path = PathBuf::from("lambda_test.kt"); + let code = r#" +class TestClass { + val realtimeCleaner: () -> String = { + "test" + } + + val regularProperty: String = "test" + + companion object { + private val logger: String = "test" + } +} +"#; + let symbols = boxed_parser.parse(code, &path); + + println!("Total symbols found: {}", symbols.len()); + + for (i, symbol) in symbols.iter().enumerate() { + let sym = symbol.read(); + println!("Symbol {}: {} - '{}'", i, sym.symbol_type(), sym.name()); + + if let Some(prop) = sym.as_any().downcast_ref::() { + println!(" -> Property type: {:?}", prop.type_); + if let Some(inference) = &prop.type_.inference_info { + println!(" -> Inference info: {}", inference); + } + } + } + + assert!(symbols.len() > 0, "Expected some symbols to be parsed"); +} From 3234fe421c49c81c56b83bf616f786c0cbaecc9e Mon Sep 17 00:00:00 2001 From: "deepak.nailwal" Date: Mon, 10 Nov 2025 13:07:03 +0530 Subject: [PATCH 2/2] feat: test json added --- .../parsers/tests/cases/kotlin/main.kt.json | 900 ++++++++++- .../tests/cases/kotlin/person.kt.decl_json | 43 +- .../parsers/tests/cases/kotlin/person.kt.json | 1424 ++++++++++++++++- .../tests/cases/kotlin/person.kt.skeleton | 18 +- 4 files changed, 2381 insertions(+), 4 deletions(-) diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json index fe51488c7..9003bae73 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/main.kt.json @@ -1 +1,899 @@ -[] +[ + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "3ca687ac-1dca-45c5-887a-b4edd6b38db3", + "name": "main", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 63, + "end_byte": 426, + "start_point": { + "row": 5, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 63, + "end_byte": 426, + "start_point": { + "row": 5, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "definition_range": { + "start_byte": 63, + "end_byte": 426, + "start_point": { + "row": 5, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "ae021215-49a0-4c2e-a7ee-f20af7c8787b", + "name": "Person", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [ + "4130233b-dee9-4215-9802-beaccd9435a8", + "b4dfc11c-caa0-40f2-819c-608826cdd434" + ], + "full_range": { + "start_byte": 428, + "end_byte": 603, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 27, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 428, + "end_byte": 603, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 27, + "column": 1 + } + }, + "definition_range": { + "start_byte": 428, + "end_byte": 603, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 27, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "192ada66-03ff-4d7b-93f4-7e2abab4a3bc", + "name": "Calculator", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [ + "26a0303a-d702-4720-bc05-a6a807923438", + "3b9fd2f9-b545-45ab-89bc-b76c07a31f3a", + "b3733e75-8b9f-4343-822a-4db86840b51a", + "6c937f13-e717-4c4f-a7b2-51acf018e616" + ], + "full_range": { + "start_byte": 605, + "end_byte": 827, + "start_point": { + "row": 29, + "column": 0 + }, + "end_point": { + "row": 34, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 605, + "end_byte": 827, + "start_point": { + "row": 29, + "column": 0 + }, + "end_point": { + "row": 34, + "column": 1 + } + }, + "definition_range": { + "start_byte": 605, + "end_byte": 827, + "start_point": { + "row": 29, + "column": 0 + }, + "end_point": { + "row": 34, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "68098471-1305-4bcd-82a5-7933d10d330c", + "name": "com", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 8, + "end_byte": 11, + "start_point": { + "row": 0, + "column": 8 + }, + "end_point": { + "row": 0, + "column": 11 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "e98adeb5-c5c8-4aab-9347-80762539278c", + "name": "example", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 12, + "end_byte": 19, + "start_point": { + "row": 0, + "column": 12 + }, + "end_point": { + "row": 0, + "column": 19 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "93ea07b0-d871-433f-8c56-5f70a69a3d07", + "name": "kotlin", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 28, + "end_byte": 34, + "start_point": { + "row": 2, + "column": 7 + }, + "end_point": { + "row": 2, + "column": 13 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "302c1b4c-32a8-4abc-aa64-cbd3212ef180", + "name": "math", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 35, + "end_byte": 39, + "start_point": { + "row": 2, + "column": 14 + }, + "end_point": { + "row": 2, + "column": 18 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "dd141487-8970-4323-b3a5-32189bb02157", + "name": "PI", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 40, + "end_byte": 42, + "start_point": { + "row": 2, + "column": 19 + }, + "end_point": { + "row": 2, + "column": 21 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "337ba28d-5667-425a-a1c7-b69834effe1d", + "name": "java", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 50, + "end_byte": 54, + "start_point": { + "row": 3, + "column": 7 + }, + "end_point": { + "row": 3, + "column": 11 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "aec23a5a-f2e6-4da0-afdf-57c30e8e83c1", + "name": "util", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "d9d6df2b-ea2e-4836-b762-bf5cbddd70fa", + "childs_guid": [], + "full_range": { + "start_byte": 55, + "end_byte": 59, + "start_point": { + "row": 3, + "column": 12 + }, + "end_point": { + "row": 3, + "column": 16 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "4130233b-dee9-4215-9802-beaccd9435a8", + "name": "greet", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "ae021215-49a0-4c2e-a7ee-f20af7c8787b", + "childs_guid": [], + "full_range": { + "start_byte": 479, + "end_byte": 557, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 24, + "column": 5 + } + }, + "declaration_range": { + "start_byte": 479, + "end_byte": 557, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 24, + "column": 5 + } + }, + "definition_range": { + "start_byte": 479, + "end_byte": 557, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 24, + "column": 5 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "b4dfc11c-caa0-40f2-819c-608826cdd434", + "name": "isAdult", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "ae021215-49a0-4c2e-a7ee-f20af7c8787b", + "childs_guid": [], + "full_range": { + "start_byte": 567, + "end_byte": 601, + "start_point": { + "row": 26, + "column": 4 + }, + "end_point": { + "row": 26, + "column": 38 + } + }, + "declaration_range": { + "start_byte": 567, + "end_byte": 601, + "start_point": { + "row": 26, + "column": 4 + }, + "end_point": { + "row": 26, + "column": 38 + } + }, + "definition_range": { + "start_byte": 567, + "end_byte": 601, + "start_point": { + "row": 26, + "column": 4 + }, + "end_point": { + "row": 26, + "column": 38 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "26a0303a-d702-4720-bc05-a6a807923438", + "name": "add", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "192ada66-03ff-4d7b-93f4-7e2abab4a3bc", + "childs_guid": [], + "full_range": { + "start_byte": 628, + "end_byte": 664, + "start_point": { + "row": 30, + "column": 4 + }, + "end_point": { + "row": 30, + "column": 40 + } + }, + "declaration_range": { + "start_byte": 628, + "end_byte": 664, + "start_point": { + "row": 30, + "column": 4 + }, + "end_point": { + "row": 30, + "column": 40 + } + }, + "definition_range": { + "start_byte": 628, + "end_byte": 664, + "start_point": { + "row": 30, + "column": 4 + }, + "end_point": { + "row": 30, + "column": 40 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "3b9fd2f9-b545-45ab-89bc-b76c07a31f3a", + "name": "subtract", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "192ada66-03ff-4d7b-93f4-7e2abab4a3bc", + "childs_guid": [], + "full_range": { + "start_byte": 669, + "end_byte": 710, + "start_point": { + "row": 31, + "column": 4 + }, + "end_point": { + "row": 31, + "column": 45 + } + }, + "declaration_range": { + "start_byte": 669, + "end_byte": 710, + "start_point": { + "row": 31, + "column": 4 + }, + "end_point": { + "row": 31, + "column": 45 + } + }, + "definition_range": { + "start_byte": 669, + "end_byte": 710, + "start_point": { + "row": 31, + "column": 4 + }, + "end_point": { + "row": 31, + "column": 45 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "b3733e75-8b9f-4343-822a-4db86840b51a", + "name": "multiply", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "192ada66-03ff-4d7b-93f4-7e2abab4a3bc", + "childs_guid": [], + "full_range": { + "start_byte": 715, + "end_byte": 756, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 32, + "column": 45 + } + }, + "declaration_range": { + "start_byte": 715, + "end_byte": 756, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 32, + "column": 45 + } + }, + "definition_range": { + "start_byte": 715, + "end_byte": 756, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 32, + "column": 45 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "6c937f13-e717-4c4f-a7b2-51acf018e616", + "name": "divide", + "language": "Kotlin", + "file_path": "main.kt", + "namespace": "", + "parent_guid": "192ada66-03ff-4d7b-93f4-7e2abab4a3bc", + "childs_guid": [], + "full_range": { + "start_byte": 761, + "end_byte": 825, + "start_point": { + "row": 33, + "column": 4 + }, + "end_point": { + "row": 33, + "column": 68 + } + }, + "declaration_range": { + "start_byte": 761, + "end_byte": 825, + "start_point": { + "row": 33, + "column": 4 + }, + "end_point": { + "row": 33, + "column": 68 + } + }, + "definition_range": { + "start_byte": 761, + "end_byte": 825, + "start_point": { + "row": 33, + "column": 4 + }, + "end_point": { + "row": 33, + "column": 68 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + } + ] \ No newline at end of file diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json index fe51488c7..be2afc63f 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.decl_json @@ -1 +1,42 @@ -[] +[ + { + "top_row": 12, + "bottom_row": 12, + "line": "fun getDisplayName(): String = name.uppercase()" + }, + { + "top_row": 10, + "bottom_row": 10, + "line": "fun isAdult(): Boolean = age >= 18" + }, + { + "top_row": 50, + "bottom_row": 52, + "line": "fun addEmployee(employee: Employee) {\n employees.add(employee)\n}" + }, + { + "top_row": 15, + "bottom_row": 17, + "line": "fun create(name: String, age: Int): Person {\n return Person(name, age)\n}" + }, + { + "top_row": 36, + "bottom_row": 36, + "line": "fun getAnnualSalary(): Double = salary * 12" + }, + { + "top_row": 54, + "bottom_row": 54, + "line": "fun getEmployeeCount(): Int = employees.size" + }, + { + "top_row": 32, + "bottom_row": 34, + "line": "override fun greet(): String {\n return \"Hello, I'm $name from $department department\"\n}" + }, + { + "top_row": 22, + "bottom_row": 22, + "line": "fun greet(): String" + } +] \ No newline at end of file diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json index fe51488c7..1c1c285c9 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.json @@ -1 +1,1423 @@ -[] +[ + { + "StructDeclaration": { + "ast_fields": { + "guid": "31acc62f-0cc5-4d5e-ae1f-0ddb737c87b2", + "name": "Person", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [ + "8233bc21-9074-4629-8de3-e663e47b23f9", + "756f7162-ce6f-4dda-b973-e519b5264aff", + "a6d41d5b-3b38-4381-9214-bbaf02bd6c34" + ], + "full_range": { + "start_byte": 55, + "end_byte": 417, + "start_point": { + "row": 4, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 55, + "end_byte": 417, + "start_point": { + "row": 4, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "definition_range": { + "start_byte": 55, + "end_byte": 417, + "start_point": { + "row": 4, + "column": 0 + }, + "end_point": { + "row": 19, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "d1908f8c-9be8-41ad-ac50-8ad91202f61b", + "name": "Greetable", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [ + "f2f419ff-98d7-4628-be47-807a1a5ffccc" + ], + "full_range": { + "start_byte": 419, + "end_byte": 466, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 23, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 419, + "end_byte": 466, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 23, + "column": 1 + } + }, + "definition_range": { + "start_byte": 419, + "end_byte": 466, + "start_point": { + "row": 21, + "column": 0 + }, + "end_point": { + "row": 23, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "1a2b4eec-e058-4115-b8e2-68e1c1967155", + "name": "Employee", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [ + "018d645d-4c13-431f-b40a-3e63a3a07d03", + "ffd8fbf3-55b6-4fdb-b396-afbc4bf0102a" + ], + "full_range": { + "start_byte": 468, + "end_byte": 764, + "start_point": { + "row": 25, + "column": 0 + }, + "end_point": { + "row": 37, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 468, + "end_byte": 764, + "start_point": { + "row": 25, + "column": 0 + }, + "end_point": { + "row": 37, + "column": 1 + } + }, + "definition_range": { + "start_byte": 468, + "end_byte": 764, + "start_point": { + "row": 25, + "column": 0 + }, + "end_point": { + "row": 37, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "1b78cdc4-f6a7-487c-a719-f22869d44781", + "name": "Department", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [ + "4535069e-01d4-4e4b-8a9b-1fb9155b0505", + "b12622ea-0d11-4ad0-9e73-debec5356a61", + "19046035-0077-411c-9b0d-cef08f6e552d", + "d8ec955b-587f-4863-8517-2ba80030e16b" + ], + "full_range": { + "start_byte": 766, + "end_byte": 841, + "start_point": { + "row": 39, + "column": 0 + }, + "end_point": { + "row": 44, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 766, + "end_byte": 841, + "start_point": { + "row": 39, + "column": 0 + }, + "end_point": { + "row": 44, + "column": 1 + } + }, + "definition_range": { + "start_byte": 766, + "end_byte": 841, + "start_point": { + "row": 39, + "column": 0 + }, + "end_point": { + "row": 44, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "StructDeclaration": { + "ast_fields": { + "guid": "7e4eeafb-a1bf-4662-b27a-1e9e5af1d528", + "name": "Company", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [ + "856c96db-e2f4-40a6-ad8a-536e06bfe489", + "1c5ac737-2e77-49d2-ba80-c3072d6c2875", + "ca3eceb2-85c9-4f16-aeab-f44b53ad3560", + "f6b75eda-8c85-4337-8aba-73bb2fe8cb2d" + ], + "full_range": { + "start_byte": 843, + "end_byte": 1072, + "start_point": { + "row": 46, + "column": 0 + }, + "end_point": { + "row": 55, + "column": 1 + } + }, + "declaration_range": { + "start_byte": 843, + "end_byte": 1072, + "start_point": { + "row": 46, + "column": 0 + }, + "end_point": { + "row": 55, + "column": 1 + } + }, + "definition_range": { + "start_byte": 843, + "end_byte": 1072, + "start_point": { + "row": 46, + "column": 0 + }, + "end_point": { + "row": 55, + "column": 1 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "inherited_types": [] + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "cd57f33d-e0bf-46eb-9463-5666ce5b8027", + "name": "com", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 8, + "end_byte": 11, + "start_point": { + "row": 0, + "column": 8 + }, + "end_point": { + "row": 0, + "column": 11 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "2d1ad4d2-4e8a-4402-a6cb-1343ff0c5256", + "name": "example", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 12, + "end_byte": 19, + "start_point": { + "row": 0, + "column": 12 + }, + "end_point": { + "row": 0, + "column": 19 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "79d536b1-438b-45a5-ac9d-50063d543d7c", + "name": "model", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 20, + "end_byte": 25, + "start_point": { + "row": 0, + "column": 20 + }, + "end_point": { + "row": 0, + "column": 25 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "7a82f118-3d7e-4c07-8c6f-48d4214fbb53", + "name": "java", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 34, + "end_byte": 38, + "start_point": { + "row": 2, + "column": 7 + }, + "end_point": { + "row": 2, + "column": 11 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "4b312423-d758-4058-a170-8b5eb3d9f893", + "name": "time", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 39, + "end_byte": 43, + "start_point": { + "row": 2, + "column": 12 + }, + "end_point": { + "row": 2, + "column": 16 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "e96f3f75-3b29-4e57-a28e-9d29bbbaaceb", + "name": "LocalDate", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "ddd672da-20e1-4dfb-adbd-62bf8665d4a0", + "childs_guid": [], + "full_range": { + "start_byte": 44, + "end_byte": 53, + "start_point": { + "row": 2, + "column": 17 + }, + "end_point": { + "row": 2, + "column": 26 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "8233bc21-9074-4629-8de3-e663e47b23f9", + "name": "isAdult", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "31acc62f-0cc5-4d5e-ae1f-0ddb737c87b2", + "childs_guid": [], + "full_range": { + "start_byte": 190, + "end_byte": 224, + "start_point": { + "row": 10, + "column": 4 + }, + "end_point": { + "row": 10, + "column": 38 + } + }, + "declaration_range": { + "start_byte": 190, + "end_byte": 224, + "start_point": { + "row": 10, + "column": 4 + }, + "end_point": { + "row": 10, + "column": 38 + } + }, + "definition_range": { + "start_byte": 190, + "end_byte": 224, + "start_point": { + "row": 10, + "column": 4 + }, + "end_point": { + "row": 10, + "column": 38 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "756f7162-ce6f-4dda-b973-e519b5264aff", + "name": "getDisplayName", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "31acc62f-0cc5-4d5e-ae1f-0ddb737c87b2", + "childs_guid": [], + "full_range": { + "start_byte": 234, + "end_byte": 281, + "start_point": { + "row": 12, + "column": 4 + }, + "end_point": { + "row": 12, + "column": 51 + } + }, + "declaration_range": { + "start_byte": 234, + "end_byte": 281, + "start_point": { + "row": 12, + "column": 4 + }, + "end_point": { + "row": 12, + "column": 51 + } + }, + "definition_range": { + "start_byte": 234, + "end_byte": 281, + "start_point": { + "row": 12, + "column": 4 + }, + "end_point": { + "row": 12, + "column": 51 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "f2f419ff-98d7-4628-be47-807a1a5ffccc", + "name": "greet", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "d1908f8c-9be8-41ad-ac50-8ad91202f61b", + "childs_guid": [], + "full_range": { + "start_byte": 445, + "end_byte": 464, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 22, + "column": 23 + } + }, + "declaration_range": { + "start_byte": 445, + "end_byte": 464, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 22, + "column": 23 + } + }, + "definition_range": { + "start_byte": 445, + "end_byte": 464, + "start_point": { + "row": 22, + "column": 4 + }, + "end_point": { + "row": 22, + "column": 23 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "018d645d-4c13-431f-b40a-3e63a3a07d03", + "name": "greet", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1a2b4eec-e058-4115-b8e2-68e1c1967155", + "childs_guid": [], + "full_range": { + "start_byte": 611, + "end_byte": 709, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 34, + "column": 5 + } + }, + "declaration_range": { + "start_byte": 611, + "end_byte": 709, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 34, + "column": 5 + } + }, + "definition_range": { + "start_byte": 611, + "end_byte": 709, + "start_point": { + "row": 32, + "column": 4 + }, + "end_point": { + "row": 34, + "column": 5 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "ffd8fbf3-55b6-4fdb-b396-afbc4bf0102a", + "name": "getAnnualSalary", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1a2b4eec-e058-4115-b8e2-68e1c1967155", + "childs_guid": [], + "full_range": { + "start_byte": 719, + "end_byte": 762, + "start_point": { + "row": 36, + "column": 4 + }, + "end_point": { + "row": 36, + "column": 47 + } + }, + "declaration_range": { + "start_byte": 719, + "end_byte": 762, + "start_point": { + "row": 36, + "column": 4 + }, + "end_point": { + "row": 36, + "column": 47 + } + }, + "definition_range": { + "start_byte": 719, + "end_byte": 762, + "start_point": { + "row": 36, + "column": 4 + }, + "end_point": { + "row": 36, + "column": 47 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "ClassFieldDeclaration": { + "ast_fields": { + "guid": "856c96db-e2f4-40a6-ad8a-536e06bfe489", + "name": "name", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "7e4eeafb-a1bf-4662-b27a-1e9e5af1d528", + "childs_guid": [], + "full_range": { + "start_byte": 864, + "end_byte": 885, + "start_point": { + "row": 47, + "column": 4 + }, + "end_point": { + "row": 47, + "column": 25 + } + }, + "declaration_range": { + "start_byte": 864, + "end_byte": 885, + "start_point": { + "row": 47, + "column": 4 + }, + "end_point": { + "row": 47, + "column": 25 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "type_": { + "name": null, + "inference_info": null, + "inference_info_guid": null, + "is_pod": false, + "namespace": "", + "guid": null, + "nested_types": [] + } + } + }, + { + "ClassFieldDeclaration": { + "ast_fields": { + "guid": "1c5ac737-2e77-49d2-ba80-c3072d6c2875", + "name": "employees", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "7e4eeafb-a1bf-4662-b27a-1e9e5af1d528", + "childs_guid": [], + "full_range": { + "start_byte": 890, + "end_byte": 931, + "start_point": { + "row": 48, + "column": 4 + }, + "end_point": { + "row": 48, + "column": 45 + } + }, + "declaration_range": { + "start_byte": 890, + "end_byte": 931, + "start_point": { + "row": 48, + "column": 4 + }, + "end_point": { + "row": 48, + "column": 45 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "type_": { + "name": null, + "inference_info": null, + "inference_info_guid": null, + "is_pod": false, + "namespace": "", + "guid": null, + "nested_types": [] + } + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "ca3eceb2-85c9-4f16-aeab-f44b53ad3560", + "name": "addEmployee", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "7e4eeafb-a1bf-4662-b27a-1e9e5af1d528", + "childs_guid": [], + "full_range": { + "start_byte": 941, + "end_byte": 1016, + "start_point": { + "row": 50, + "column": 4 + }, + "end_point": { + "row": 52, + "column": 5 + } + }, + "declaration_range": { + "start_byte": 941, + "end_byte": 1016, + "start_point": { + "row": 50, + "column": 4 + }, + "end_point": { + "row": 52, + "column": 5 + } + }, + "definition_range": { + "start_byte": 941, + "end_byte": 1016, + "start_point": { + "row": 50, + "column": 4 + }, + "end_point": { + "row": 52, + "column": 5 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "f6b75eda-8c85-4337-8aba-73bb2fe8cb2d", + "name": "getEmployeeCount", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "7e4eeafb-a1bf-4662-b27a-1e9e5af1d528", + "childs_guid": [], + "full_range": { + "start_byte": 1026, + "end_byte": 1070, + "start_point": { + "row": 54, + "column": 4 + }, + "end_point": { + "row": 54, + "column": 48 + } + }, + "declaration_range": { + "start_byte": 1026, + "end_byte": 1070, + "start_point": { + "row": 54, + "column": 4 + }, + "end_point": { + "row": 54, + "column": 48 + } + }, + "definition_range": { + "start_byte": 1026, + "end_byte": 1070, + "start_point": { + "row": 54, + "column": 4 + }, + "end_point": { + "row": 54, + "column": 48 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "4535069e-01d4-4e4b-8a9b-1fb9155b0505", + "name": "ENGINEERING", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1b78cdc4-f6a7-487c-a719-f22869d44781", + "childs_guid": [], + "full_range": { + "start_byte": 794, + "end_byte": 805, + "start_point": { + "row": 40, + "column": 4 + }, + "end_point": { + "row": 40, + "column": 15 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "b12622ea-0d11-4ad0-9e73-debec5356a61", + "name": "MARKETING", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1b78cdc4-f6a7-487c-a719-f22869d44781", + "childs_guid": [], + "full_range": { + "start_byte": 811, + "end_byte": 820, + "start_point": { + "row": 41, + "column": 4 + }, + "end_point": { + "row": 41, + "column": 13 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "19046035-0077-411c-9b0d-cef08f6e552d", + "name": "SALES", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1b78cdc4-f6a7-487c-a719-f22869d44781", + "childs_guid": [], + "full_range": { + "start_byte": 826, + "end_byte": 831, + "start_point": { + "row": 42, + "column": 4 + }, + "end_point": { + "row": 42, + "column": 9 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "VariableUsage": { + "ast_fields": { + "guid": "d8ec955b-587f-4863-8517-2ba80030e16b", + "name": "HR", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "1b78cdc4-f6a7-487c-a719-f22869d44781", + "childs_guid": [], + "full_range": { + "start_byte": 837, + "end_byte": 839, + "start_point": { + "row": 43, + "column": 4 + }, + "end_point": { + "row": 43, + "column": 6 + } + }, + "declaration_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "definition_range": { + "start_byte": 0, + "end_byte": 0, + "start_point": { + "row": 0, + "column": 0 + }, + "end_point": { + "row": 0, + "column": 0 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + } + } + }, + { + "FunctionDeclaration": { + "ast_fields": { + "guid": "a6d41d5b-3b38-4381-9214-bbaf02bd6c34", + "name": "create", + "language": "Kotlin", + "file_path": "person.kt", + "namespace": "", + "parent_guid": "31acc62f-0cc5-4d5e-ae1f-0ddb737c87b2", + "childs_guid": [], + "full_range": { + "start_byte": 318, + "end_byte": 409, + "start_point": { + "row": 15, + "column": 8 + }, + "end_point": { + "row": 17, + "column": 9 + } + }, + "declaration_range": { + "start_byte": 318, + "end_byte": 409, + "start_point": { + "row": 15, + "column": 8 + }, + "end_point": { + "row": 17, + "column": 9 + } + }, + "definition_range": { + "start_byte": 318, + "end_byte": 409, + "start_point": { + "row": 15, + "column": 8 + }, + "end_point": { + "row": 17, + "column": 9 + } + }, + "linked_decl_guid": null, + "linked_decl_type": null, + "caller_guid": null, + "is_error": false, + "caller_depth": null + }, + "template_types": [], + "args": [], + "return_type": null + } + } + ] \ No newline at end of file diff --git a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton index fe51488c7..98c45b569 100644 --- a/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton +++ b/refact-agent/engine/src/ast/treesitter/parsers/tests/cases/kotlin/person.kt.skeleton @@ -1 +1,17 @@ -[] +[ + { + "line": "data class Person(\nval name: String,\nval age: Int,\nval email: String? = null,\nval birthDate: LocalDate? = null\n) {\nfun isAdult(): Boolean = age >= 18\n\nfun getDisplayName(): String = name.uppercase()\n\ncompanion object {\nfun create(name: String, age: Int): Person {\nreturn Person(name, age)\n}\n}\n} {\n fun isAdult(): Boolean = age >= 18 { ... }\n fun getDisplayName(): String = name.uppercase() { ... }\n fun create(name: String, age: Int): Person {\n return Person(name, age)\n }\n}" + }, + { + "line": "class Employee(\nname: String,\nage: Int,\nval department: String,\nval salary: Double\n) : Person(name, age), Greetable {\n\noverride fun greet(): String {\nreturn \"Hello, I'm $name from $department department\"\n}\n\nfun getAnnualSalary(): Double = salary * 12\n} {\n override fun greet(): String {\n return \"Hello, I'm $name from $department department\"\n }\n fun getAnnualSalary(): Double = salary * 12 { ... }\n}" + }, + { + "line": "enum class Department {\nENGINEERING,\nMARKETING,\nSALES,\nHR\n} {\n}" + }, + { + "line": "interface Greetable {\nfun greet(): String\n} {\n fun greet(): String { ... }\n}" + }, + { + "line": "object Company {\nval name = \"TechCorp\"\nval employees = mutableListOf()\n\nfun addEmployee(employee: Employee) {\nemployees.add(employee)\n}\n\nfun getEmployeeCount(): Int = employees.size\n} {\n val name = \"TechCorp\",\n val employees = mutableListOf(),\n fun addEmployee(employee: Employee) {\n employees.add(employee)\n }\n fun getEmployeeCount(): Int = employees.size { ... }\n}" + } +] \ No newline at end of file