diff --git a/ast/src/testing/kotlin/mod.rs b/ast/src/testing/kotlin/mod.rs index 134252d1e..b34d60512 100644 --- a/ast/src/testing/kotlin/mod.rs +++ b/ast/src/testing/kotlin/mod.rs @@ -1,4 +1,5 @@ use crate::lang::graphs::{EdgeType, NodeType}; +use crate::utils::get_use_lsp; use crate::lang::Graph; use crate::{lang::Lang, repo::Repo}; use anyhow::Result; @@ -6,22 +7,46 @@ use std::str::FromStr; use test_log::test; pub async fn test_kotlin_generic() -> Result<(), anyhow::Error> { + let use_lsp = get_use_lsp(); let repo = Repo::new( "src/testing/kotlin", Lang::from_str("kotlin").unwrap(), - false, + use_lsp, Vec::new(), Vec::new(), ) .unwrap(); - let graph = repo.build_graph_inner::().await?; + let graph_result = repo.build_graph_inner::().await; + + let (graph, effective_lsp) = match (use_lsp, graph_result) { + (true, Ok(g)) => (g, true), + (true, Err(_)) => { + let non_lsp_repo = Repo::new( + "src/testing/kotlin", + Lang::from_str("kotlin").unwrap(), + false, + Vec::new(), + Vec::new(), + ) + .unwrap(); + (non_lsp_repo.build_graph_inner::().await?, false) + }, + (false, Ok(g)) => (g, false), + (false, Err(e)) => return Err(e), + }; let (num_nodes, num_edges) = graph.get_graph_size(); - //graph.analysis(); - assert_eq!(num_nodes, 115, "Expected 115 nodes"); - assert_eq!(num_edges, 125, "Expected 125 edges"); + if effective_lsp { + println!("Testing with LSP: found {} nodes and {} edges", num_nodes, num_edges); + assert_eq!(num_nodes, 120, "Expected 120 nodes with LSP"); + assert_eq!(num_edges, 135, "Expected 135 edges with LSP"); + } else { + println!("Testing without LSP: found {} nodes and {} edges", num_nodes, num_edges); + assert_eq!(num_nodes, 115, "Expected 115 nodes"); + assert_eq!(num_edges, 125, "Expected 125 edges"); + } fn normalize_path(path: &str) -> String { path.replace("\\", "/") @@ -40,24 +65,44 @@ pub async fn test_kotlin_generic() -> Result<(), anyhow::Error> { ); let build_gradle_files = graph.find_nodes_by_name(NodeType::File, "build.gradle.kts"); - assert_eq!( - build_gradle_files.len(), - 2, - "Expected 2 build.gradle.kts files" - ); + if effective_lsp { + assert_eq!( + build_gradle_files.len(), + 2, + "Expected 2 build.gradle.kts files with LSP" + ); + } else { + assert_eq!( + build_gradle_files.len(), + 2, + "Expected 2 build.gradle.kts files" + ); + } assert_eq!( build_gradle_files[0].name, "build.gradle.kts", "Gradle file name is incorrect" ); let libraries = graph.find_nodes_by_type(NodeType::Library); - assert_eq!(libraries.len(), 44, "Expected 44 libraries"); + if effective_lsp { + assert_eq!(libraries.len(), 48, "Expected 48 libraries with LSP"); + } else { + assert_eq!(libraries.len(), 44, "Expected 44 libraries"); + } let imports = graph.find_nodes_by_type(NodeType::Import); - assert_eq!(imports.len(), 9, "Expected 9 imports"); + if effective_lsp { + assert_eq!(imports.len(), 11, "Expected 11 imports with LSP"); + } else { + assert_eq!(imports.len(), 9, "Expected 9 imports"); + } let classes = graph.find_nodes_by_type(NodeType::Class); - assert_eq!(classes.len(), 6, "Expected 6 classes"); + if effective_lsp { + assert_eq!(classes.len(), 8, "Expected 8 classes with LSP"); + } else { + assert_eq!(classes.len(), 6, "Expected 6 classes"); + } let mut sorted_classes = classes.clone(); sorted_classes.sort_by(|a, b| a.name.cmp(&b.name)); @@ -73,7 +118,11 @@ pub async fn test_kotlin_generic() -> Result<(), anyhow::Error> { ); let functions = graph.find_nodes_by_type(NodeType::Function); - assert_eq!(functions.len(), 19, "Expected 19 functions"); + if effective_lsp { + assert_eq!(functions.len(), 23, "Expected 23 functions with LSP"); + } else { + assert_eq!(functions.len(), 19, "Expected 19 functions"); + } let data_models = graph.find_nodes_by_type(NodeType::DataModel); assert_eq!(data_models.len(), 1, "Expected 1 data model"); @@ -82,8 +131,12 @@ pub async fn test_kotlin_generic() -> Result<(), anyhow::Error> { assert_eq!(requests.len(), 2, "Expected 2 requests"); let calls_edges_count = graph.count_edges_of_type(EdgeType::Calls); - assert!(calls_edges_count > 0, "Expected at least one calls edge"); - + if effective_lsp { + assert_eq!(calls_edges_count, 12, "Expected 12 calls edges with LSP"); + } else { + assert_eq!(calls_edges_count, 13, "Expected 13 calls edges"); + } + Ok(()) } diff --git a/lsp/Dockerfile b/lsp/Dockerfile index ea6baf41e..f463e3b6d 100644 --- a/lsp/Dockerfile +++ b/lsp/Dockerfile @@ -20,6 +20,10 @@ RUN apt-get update && apt-get install -y \ gcc \ g++ \ sed \ + unzip \ + default-jdk \ + gradle \ + jq \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -51,6 +55,36 @@ RUN mkdir -p $GOPATH/bin \ # ruby RUN gem install ruby-lsp +# kotlin - LSP +RUN mkdir -p /opt/kotlin-language-server && \ + curl -L "https://github.com/fwcd/kotlin-language-server/releases/latest/download/server.zip" -o /opt/kotlin-language-server/server.zip && \ + cd /opt/kotlin-language-server && \ + unzip server.zip && \ + chmod +x server/bin/kotlin-language-server && \ + mkdir -p server/plugins && \ + curl -L "https://github.com/fwcd/kotlin-language-server/releases/latest/download/kotlin-analysis-plugin.jar" -o server/plugins/kotlin-analysis-plugin.jar 2>/dev/null || echo "Analysis plugin not found, skipping" && \ + curl -L "https://github.com/fwcd/kotlin-language-server/releases/latest/download/kotlin-structure-plugin.jar" -o server/plugins/kotlin-structure-plugin.jar 2>/dev/null || echo "Structure plugin not found, skipping" && \ + rm server.zip + +# Kotlin compiler for improved language features and more accurate AST +RUN LATEST_KOTLIN_VERSION=$(curl -s https://api.github.com/repos/JetBrains/kotlin/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \ + echo "Installing Kotlin compiler version: $LATEST_KOTLIN_VERSION" && \ + curl -L "https://github.com/JetBrains/kotlin/releases/download/v${LATEST_KOTLIN_VERSION}/kotlin-compiler-${LATEST_KOTLIN_VERSION}.zip" -o /tmp/kotlin-compiler.zip && \ + mkdir -p /opt/kotlin && \ + unzip /tmp/kotlin-compiler.zip -d /opt/kotlin && \ + rm /tmp/kotlin-compiler.zip && \ + chmod +x /opt/kotlin/kotlinc/bin/kotlin && \ + chmod +x /opt/kotlin/kotlinc/bin/kotlinc + +# SLF4J implementation to fix logging warnings +RUN curl -L "https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.36/slf4j-simple-1.7.36.jar" \ + -o /opt/kotlin-language-server/server/lib/slf4j-simple-1.7.36.jar + +# Set environment variables for enhanced Kotlin support +ENV PATH="/opt/kotlin-language-server/server/bin:/opt/kotlin/kotlinc/bin:$PATH" +ENV KOTLIN_LANGUAGE_SERVER_OPTS="-Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+UseStringDeduplication" +ENV KOTLIN_COMPILER_HOME="/opt/kotlin/kotlinc" + # rust-analyzer RUN curl -LO "https://github.com/rust-lang/rust-analyzer/releases/download/2025-01-20/rust-analyzer-x86_64-unknown-linux-gnu.gz" \ && gzip -cd rust-analyzer-x86_64-unknown-linux-gnu.gz > /bin/rust-analyzer \