From def7169cf252e7c03c7450513d274a0f2c8d5dbd Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Wed, 3 Apr 2024 17:13:44 +0800 Subject: [PATCH] test: add compile unit cache e2e test Signed-off-by: he1pa <18012015693@163.com> --- kclvm/tools/src/LSP/src/state.rs | 7 +- kclvm/tools/src/LSP/src/tests.rs | 124 +++++++++++++++++++++++++++++++ kclvm/tools/src/LSP/src/util.rs | 27 ++++--- 3 files changed, 144 insertions(+), 14 deletions(-) diff --git a/kclvm/tools/src/LSP/src/state.rs b/kclvm/tools/src/LSP/src/state.rs index 7b87633d4..8d9b26655 100644 --- a/kclvm/tools/src/LSP/src/state.rs +++ b/kclvm/tools/src/LSP/src/state.rs @@ -8,7 +8,7 @@ use crate::word_index::build_word_index; use anyhow::Result; use crossbeam_channel::{select, unbounded, Receiver, Sender}; use kclvm_parser::{KCLModuleCache, LoadProgramOptions}; -use kclvm_sema::resolver::scope::{CachedScope, KCLScopeCache}; +use kclvm_sema::resolver::scope::KCLScopeCache; use lsp_server::{ReqQueue, Request, Response}; use lsp_types::Url; use lsp_types::{ @@ -18,7 +18,6 @@ use lsp_types::{ use parking_lot::RwLock; use ra_ap_vfs::{ChangeKind, ChangedFile, FileId, Vfs}; use std::collections::HashMap; -use std::sync::Mutex; use std::thread; use std::time::Duration; use std::{sync::Arc, time::Instant}; @@ -149,8 +148,8 @@ impl LanguageServerState { word_index_map: Arc::new(RwLock::new(HashMap::new())), loader, module_cache: KCLModuleCache::default(), - scope_cache: Arc::new(Mutex::new(CachedScope::default())), - compile_unit_cache: Arc::new(RwLock::new(HashMap::default())), + scope_cache: KCLScopeCache::default(), + compile_unit_cache: KCLCompileUnitCache::default(), }; let word_index_map = state.word_index_map.clone(); diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index 7af033c71..cb2912c9c 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -17,6 +17,8 @@ use lsp_types::CompletionResponse; use lsp_types::CompletionTriggerKind; use lsp_types::DocumentFormattingParams; use lsp_types::DocumentSymbolParams; +use lsp_types::FileChangeType; +use lsp_types::FileEvent; use lsp_types::GotoDefinitionParams; use lsp_types::GotoDefinitionResponse; use lsp_types::Hover; @@ -45,8 +47,10 @@ use std::path::Path; use std::path::PathBuf; use std::process::Command; +use std::sync::Arc; use std::thread; use std::time::Duration; +use std::time::Instant; use kclvm_ast::ast::Program; use kclvm_error::Diagnostic as KCLDiagnostic; @@ -74,6 +78,7 @@ use crate::main_loop::main_loop; use crate::state::KCLCompileUnitCache; use crate::state::KCLVfs; use crate::to_lsp::kcl_diag_to_lsp_diags; +use crate::util::compile_unit_with_cache; use crate::util::to_json; use crate::util::{apply_document_changes, compile_with_params, Params}; @@ -882,6 +887,125 @@ fn cancel_test() { assert!(server.receive_response(id.into()).is_none()); } +#[test] +fn compile_unit_cache_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + path.push("src/test_data/compile_unit/b.k"); + + let path = path.to_str().unwrap(); + + let compile_unit_cache = KCLCompileUnitCache::default(); + let start = Instant::now(); + let _ = compile_unit_with_cache(&Some(Arc::clone(&compile_unit_cache)), &path.to_string()); + let first_compile_time = start.elapsed(); + + let start = Instant::now(); + let _ = compile_unit_with_cache(&Some(compile_unit_cache), &path.to_string()); + let second_compile_time = start.elapsed(); + + assert!(first_compile_time > second_compile_time); +} + +#[test] +fn compile_unit_cache_e2e_test() { + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut path = root.clone(); + let mut kcl_yaml = root.clone(); + path.push("src/test_data/compile_unit/b.k"); + kcl_yaml.push("src/test_data/compile_unit/kcl.yaml"); + + let path = path.to_str().unwrap(); + + let kcl_yaml = kcl_yaml.to_str().unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let server = Project {}.server(InitializeParams::default()); + + // Mock open file + server.notification::( + lsp_types::DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: "KCL".to_string(), + version: 0, + text: src, + }, + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + let r: Request = Request::new( + id.into(), + "textDocument/documentSymbol".to_string(), + DocumentSymbolParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }, + ); + + // First time send request and wait for it's response + let start = Instant::now(); + let _ = server.send_and_receive(r); + let first_compile_time = start.elapsed(); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + // Second time send request and wait for it's response + let r: Request = Request::new( + id.into(), + "textDocument/documentSymbol".to_string(), + DocumentSymbolParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }, + ); + + let start = Instant::now(); + let _ = server.send_and_receive(r); + let second_compile_time = start.elapsed(); + assert!(first_compile_time > second_compile_time); + + // Mock edit config file, clear cache + server.notification::( + lsp_types::DidChangeWatchedFilesParams { + changes: vec![FileEvent { + uri: Url::from_file_path(kcl_yaml).unwrap(), + typ: FileChangeType::CHANGED, + }], + }, + ); + + let id = server.next_request_id.get(); + server.next_request_id.set(id.wrapping_add(1)); + + // Third time send request and wait for it's response + let r: Request = Request::new( + id.into(), + "textDocument/documentSymbol".to_string(), + DocumentSymbolParams { + text_document: TextDocumentIdentifier { + uri: Url::from_file_path(path).unwrap(), + }, + work_done_progress_params: Default::default(), + partial_result_params: Default::default(), + }, + ); + + let start = Instant::now(); + let _ = server.send_and_receive(r); + let third_compile_time = start.elapsed(); + assert!(third_compile_time > second_compile_time); +} + #[test] fn goto_def_test() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/kclvm/tools/src/LSP/src/util.rs b/kclvm/tools/src/LSP/src/util.rs index ea9b51e31..f913cbdc7 100644 --- a/kclvm/tools/src/LSP/src/util.rs +++ b/kclvm/tools/src/LSP/src/util.rs @@ -10,7 +10,7 @@ use kclvm_driver::lookup_compile_unit; use kclvm_error::Diagnostic; use kclvm_error::Position as KCLPos; use kclvm_parser::entry::get_dir_files; -use kclvm_parser::{load_program, KCLModuleCache, ParseSessionRef}; +use kclvm_parser::{load_program, KCLModuleCache, LoadProgramOptions, ParseSessionRef}; use kclvm_sema::advanced_resolver::AdvancedResolver; use kclvm_sema::core::global_state::GlobalState; use kclvm_sema::namer::Namer; @@ -67,20 +67,27 @@ pub(crate) struct Params { pub compile_unit_cache: Option, } -pub(crate) fn compile_with_params( - params: Params, -) -> anyhow::Result<(Program, IndexSet, GlobalState)> { - // Lookup compile unit (kcl.mod or kcl.yaml) from the entry file. - let (mut files, opt) = match ¶ms.compile_unit_cache { +pub(crate) fn compile_unit_with_cache( + compile_unit_cache: &Option, + file: &String, +) -> (Vec, Option) { + match compile_unit_cache { Some(cache) => { let map = cache.read(); - match map.get(¶ms.file) { + match map.get(file) { Some(compile_unit) => compile_unit.clone(), - None => lookup_compile_unit(¶ms.file, true), + None => lookup_compile_unit(file, true), } } - None => lookup_compile_unit(¶ms.file, true), - }; + None => lookup_compile_unit(file, true), + } +} + +pub(crate) fn compile_with_params( + params: Params, +) -> anyhow::Result<(Program, IndexSet, GlobalState)> { + // Lookup compile unit (kcl.mod or kcl.yaml) from the entry file. + let (mut files, opt) = compile_unit_with_cache(¶ms.compile_unit_cache, ¶ms.file); if let Some(cache) = params.compile_unit_cache { cache