From e2a2db9adcf4abde4e2869cc52e97fb9e4309012 Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Wed, 26 Jun 2024 11:59:23 +0800 Subject: [PATCH 1/2] feat: add advanced resolver api to get definition within scope. fix nested scehma config completion Signed-off-by: he1pa <18012015693@163.com> --- kclvm/sema/src/core/global_state.rs | 31 ++++++- kclvm/sema/src/core/scope.rs | 50 +++++++++++ kclvm/tools/src/LSP/src/completion.rs | 86 +++++++++---------- ...e_server__completion__tests__lambda_1.snap | 4 +- ...sts__schema_attr_newline_completion_0.snap | 5 ++ ...s__schema_attr_newline_completion_0_1.snap | 5 ++ ...sts__schema_attr_newline_completion_1.snap | 5 ++ .../{newline.k => schema/schema_0/schema_0.k} | 2 +- .../newline/schema/schema_1/schema_1.k | 13 +++ 9 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap create mode 100644 kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap create mode 100644 kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap rename kclvm/tools/src/LSP/src/test_data/completion_test/newline/{newline.k => schema/schema_0/schema_0.k} (94%) create mode 100644 kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k diff --git a/kclvm/sema/src/core/global_state.rs b/kclvm/sema/src/core/global_state.rs index 9c92df40a..b2181195d 100644 --- a/kclvm/sema/src/core/global_state.rs +++ b/kclvm/sema/src/core/global_state.rs @@ -167,7 +167,7 @@ impl GlobalState { } } - /// get all definition symbols within specific scope + /// get all definition symbols within specific scope and parent scope /// /// # Parameters /// @@ -196,6 +196,35 @@ impl GlobalState { Some(all_defs) } + /// get all definition symbols within specific scope + /// + /// # Parameters + /// + /// `scope`: [ScopeRef] + /// the reference of scope which was allocated by [ScopeData] + /// + /// + /// # Returns + /// + /// result: [Option>] + /// all definition symbols in the scope + pub fn get_defs_within_scope(&self, scope: ScopeRef) -> Option> { + let scopes = &self.scopes; + let scope = scopes.get_scope(&scope)?; + let all_defs: Vec = scope + .get_defs_within_scope( + scopes, + &self.symbols, + self.packages.get_module_info(scope.get_filename()), + false, + ) + .values() + .into_iter() + .cloned() + .collect(); + Some(all_defs) + } + /// look up closest symbol by specific position, which means /// the specified position is located after the starting position of the returned symbol /// and before the starting position of the next symbol diff --git a/kclvm/sema/src/core/scope.rs b/kclvm/sema/src/core/scope.rs index b1baf688b..dbb7cda61 100644 --- a/kclvm/sema/src/core/scope.rs +++ b/kclvm/sema/src/core/scope.rs @@ -27,6 +27,7 @@ pub trait Scope { local: bool, ) -> Option; + /// Get all defs within current scope and parent scope fn get_all_defs( &self, scope_data: &ScopeData, @@ -35,6 +36,15 @@ pub trait Scope { recursive: bool, ) -> HashMap; + /// Get all defs within current scope + fn get_defs_within_scope( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + recursive: bool, + ) -> HashMap; + fn dump(&self, scope_data: &ScopeData, symbol_data: &Self::SymbolData) -> Option; } @@ -328,6 +338,17 @@ impl Scope for RootSymbolScope { fn get_range(&self) -> Option<(Position, Position)> { None } + + fn get_defs_within_scope( + &self, + scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + recursive: bool, + ) -> HashMap { + // get defs within root scope equal to get all defs + self.get_all_defs(scope_data, symbol_data, module_info, recursive) + } } impl RootSymbolScope { @@ -553,6 +574,35 @@ impl Scope for LocalSymbolScope { fn get_range(&self) -> Option<(Position, Position)> { Some((self.start.clone(), self.end.clone())) } + + fn get_defs_within_scope( + &self, + _scope_data: &ScopeData, + symbol_data: &Self::SymbolData, + module_info: Option<&ModuleInfo>, + _recursive: bool, + ) -> HashMap { + let mut all_defs_map = HashMap::new(); + if let Some(owner) = self.owner { + if let Some(owner) = symbol_data.get_symbol(owner) { + for def_ref in owner.get_all_attributes(symbol_data, module_info) { + if let Some(def) = symbol_data.get_symbol(def_ref) { + let name = def.get_name(); + if !all_defs_map.contains_key(&name) { + all_defs_map.insert(name, def_ref); + } + } + } + } + } + + for def_ref in self.defs.values() { + if let Some(def) = symbol_data.get_symbol(*def_ref) { + all_defs_map.insert(def.get_name(), *def_ref); + } + } + all_defs_map + } } impl LocalSymbolScope { diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 0e6939892..599fe31d1 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -396,7 +396,7 @@ fn completion_newline( if let ScopeKind::Local = scope.get_kind() { if let Some(locol_scope) = gs.get_scopes().try_get_local_scope(&scope) { if let LocalSymbolScopeKind::SchemaConfig = locol_scope.get_kind() { - if let Some(defs) = gs.get_all_defs_in_scope(scope) { + if let Some(defs) = gs.get_defs_within_scope(scope) { for symbol_ref in defs { match gs.get_symbols().get_symbol(symbol_ref) { Some(def) => { @@ -1341,50 +1341,7 @@ mod tests { } } - #[test] - fn schema_attr_newline_completion() { - let (file, program, _, gs) = - compile_test_file("src/test_data/completion_test/newline/newline.k"); - let pos = KCLPos { - filename: file.to_owned(), - line: 8, - column: Some(4), - }; - - let tool = toolchain::default(); - let mut got = completion(Some('\n'), &program, &pos, &gs, &tool).unwrap(); - match &mut got { - CompletionResponse::Array(arr) => { - arr.sort_by(|a, b| a.label.cmp(&b.label)); - assert_eq!( - arr[1], - CompletionItem { - label: "c".to_string(), - kind: Some(CompletionItemKind::FIELD), - detail: Some("c: int".to_string()), - documentation: None, - ..Default::default() - } - ) - } - CompletionResponse::List(_) => panic!("test failed"), - } - - // not complete in schema stmt - let pos = KCLPos { - filename: file.to_owned(), - line: 5, - column: Some(4), - }; - let got = completion(Some('\n'), &program, &pos, &gs, &tool).unwrap(); - match got { - CompletionResponse::Array(arr) => { - assert!(arr.is_empty()) - } - CompletionResponse::List(_) => panic!("test failed"), - } - } #[test] fn schema_docstring_newline_completion() { @@ -1826,7 +1783,7 @@ mod tests { } #[macro_export] - macro_rules! completion_label_test_snapshot { + macro_rules! completion_label_without_builtin_func_test_snapshot { ($name:ident, $file:expr, $line:expr, $column: expr, $trigger: expr) => { #[test] fn $name() { @@ -1847,6 +1804,18 @@ mod tests { let mut labels: Vec = arr.iter().map(|item| item.label.clone()).collect(); labels.sort(); + let builtin_func_lables: Vec = BUILTIN_FUNCTIONS + .iter() + .map(|(name, func)| { + func_ty_complete_label(name, &func.into_func_type()) + }) + .collect(); + let labels: Vec = labels + .iter() + .filter(|label| !builtin_func_lables.contains(label)) + .map(|label| label.clone()) + .collect(); + labels } CompletionResponse::List(_) => panic!("test failed"), @@ -1856,11 +1825,36 @@ mod tests { }; } - completion_label_test_snapshot!( + completion_label_without_builtin_func_test_snapshot!( lambda_1, "src/test_data/completion_test/lambda/lambda_1/lambda_1.k", 8, 5, None ); + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_0, + "src/test_data/completion_test/newline/schema/schema_0/schema_0.k", + 8, + 4, + Some('\n') + ); + + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_0_1, + "src/test_data/completion_test/newline/schema/schema_0/schema_0.k", + 5, + 4, + Some('\n') + ); + + completion_label_without_builtin_func_test_snapshot!( + schema_attr_newline_completion_1, + "src/test_data/completion_test/newline/schema/schema_1/schema_1.k", + 10, + 4, + Some('\n') + ); } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap index 31b3c212e..653bfc01c 100644 --- a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__lambda_1.snap @@ -1,5 +1,5 @@ --- source: tools/src/LSP/src/completion.rs -expression: "format!(\"{:?}\", labels)" +expression: "format!(\"{:?}\",\n {\n let(file, program, _, gs) =\n compile_test_file(\"src/test_data/completion_test/lambda/lambda_1/lambda_1.k\")\n ; let pos = KCLPos\n { filename : file.clone(), line : 8, column : Some(5), } ; let tool =\n toolchain :: default() ; let mut got =\n completion(None, & program, & pos, & gs, & tool).unwrap() ; match &\n mut got\n {\n CompletionResponse :: Array(arr) =>\n {\n let mut labels : Vec < String > =\n arr.iter().map(| item | item.label.clone()).collect() ;\n labels.sort() ; let builtin_func_lables : Vec < String > =\n BUILTIN_FUNCTIONS.iter().map(| (name, func) |\n {\n func_ty_complete_label(name, & func.into_func_type())\n }).collect() ; println! (\"{:?}\", builtin_func_lables) ; let\n labels : Vec < String > =\n labels.iter().filter(| label |!\n builtin_func_lables.contains(label)).map(| label |\n label.clone()).collect() ; println! (\"{:?}\", labels) ; labels\n } CompletionResponse :: List(_) => panic! (\"test failed\"),\n }\n })" --- -["abs(…)", "all_true(…)", "any_true(…)", "bin(…)", "bool(…)", "case", "cases", "dict(…)", "float(…)", "func1", "hex(…)", "int(…)", "isunique(…)", "len(…)", "list(…)", "max(…)", "min(…)", "multiplyof(…)", "oct(…)", "option(…)", "ord(…)", "pow(…)", "print(…)", "range(…)", "round(…)", "sorted(…)", "str(…)", "sum(…)", "typeof(…)", "zip(…)"] +["case", "cases", "func1"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap new file mode 100644 index 000000000..de5146ec5 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\",\n {\n let(file, program, _, gs) =\n compile_test_file(\"src/test_data/completion_test/newline/schema/schema_0/schema_0.k\")\n ; let pos = KCLPos\n { filename : file.clone(), line : 8, column : Some(4), } ; let tool =\n toolchain :: default() ; let mut got =\n completion(Some('\\n'), & program, & pos, & gs, & tool).unwrap() ;\n match & mut got\n {\n CompletionResponse :: Array(arr) =>\n {\n let mut labels : Vec < String > =\n arr.iter().map(| item | item.label.clone()).collect() ;\n labels.sort() ; let builtin_func_lables : Vec < String > =\n BUILTIN_FUNCTIONS.iter().map(| (name, func) |\n {\n func_ty_complete_label(name, & func.into_func_type())\n }).collect() ; let labels : Vec < String > =\n labels.iter().filter(| label |!\n builtin_func_lables.contains(label)).map(| label |\n label.clone()).collect() ; labels\n } CompletionResponse :: List(_) => panic! (\"test failed\"),\n }\n })" +--- +["a", "c"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap new file mode 100644 index 000000000..ca8d5037c --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_0_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\",\n {\n let(file, program, _, gs) =\n compile_test_file(\"src/test_data/completion_test/newline/schema/schema_0/schema_0.k\")\n ; let pos = KCLPos\n { filename : file.clone(), line : 5, column : Some(4), } ; let tool =\n toolchain :: default() ; let mut got =\n completion(Some('\\n'), & program, & pos, & gs, & tool).unwrap() ;\n match & mut got\n {\n CompletionResponse :: Array(arr) =>\n {\n let mut labels : Vec < String > =\n arr.iter().map(| item | item.label.clone()).collect() ;\n labels.sort() ; let builtin_func_lables : Vec < String > =\n BUILTIN_FUNCTIONS.iter().map(| (name, func) |\n {\n func_ty_complete_label(name, & func.into_func_type())\n }).collect() ; let labels : Vec < String > =\n labels.iter().filter(| label |!\n builtin_func_lables.contains(label)).map(| label |\n label.clone()).collect() ; labels\n } CompletionResponse :: List(_) => panic! (\"test failed\"),\n }\n })" +--- +[] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap new file mode 100644 index 000000000..d0c609114 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_attr_newline_completion_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\",\n {\n let(file, program, _, gs) =\n compile_test_file(\"src/test_data/completion_test/newline/schema/schema_1/schema_1.k\")\n ; let pos = KCLPos\n { filename : file.clone(), line : 10, column : Some(4), } ; let tool =\n toolchain :: default() ; let mut got =\n completion(None, & program, & pos, & gs, & tool).unwrap() ; match &\n mut got\n {\n CompletionResponse :: Array(arr) =>\n {\n let mut labels : Vec < String > =\n arr.iter().map(| item | item.label.clone()).collect() ;\n labels.sort() ; let builtin_func_lables : Vec < String > =\n BUILTIN_FUNCTIONS.iter().map(| (name, func) |\n {\n func_ty_complete_label(name, & func.into_func_type())\n }).collect() ; println! (\"{:?}\", builtin_func_lables) ; let\n labels : Vec < String > =\n labels.iter().filter(| label |!\n builtin_func_lables.contains(label)).map(| label |\n label.clone()).collect() ; println! (\"{:?}\", labels) ; labels\n } CompletionResponse :: List(_) => panic! (\"test failed\"),\n }\n })" +--- +["name"] diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k similarity index 94% rename from kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline.k rename to kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k index 263155647..0abb2a503 100644 --- a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/newline.k +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_0/schema_0.k @@ -5,5 +5,5 @@ schema Person[b: int](Base): c: int p1= Person(b){ - + } diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k new file mode 100644 index 000000000..e91d1c571 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/newline/schema/schema_1/schema_1.k @@ -0,0 +1,13 @@ +schema Name: + name: str + +schema Person: + name: Name + age: int + +p = Person{ + name: Name{ + + } +} + \ No newline at end of file From 7cba7bb7213b205a23914a79d867749db56dd7ef Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Wed, 26 Jun 2024 17:42:08 +0800 Subject: [PATCH 2/2] fmt code Signed-off-by: he1pa <18012015693@163.com> --- kclvm/sema/src/core/scope.rs | 2 +- kclvm/tools/src/LSP/src/completion.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/kclvm/sema/src/core/scope.rs b/kclvm/sema/src/core/scope.rs index dbb7cda61..a8d70e587 100644 --- a/kclvm/sema/src/core/scope.rs +++ b/kclvm/sema/src/core/scope.rs @@ -574,7 +574,7 @@ impl Scope for LocalSymbolScope { fn get_range(&self) -> Option<(Position, Position)> { Some((self.start.clone(), self.end.clone())) } - + fn get_defs_within_scope( &self, _scope_data: &ScopeData, diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 599fe31d1..9d68060b9 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -1341,8 +1341,6 @@ mod tests { } } - - #[test] fn schema_docstring_newline_completion() { let (file, program, _, gs) = @@ -1841,7 +1839,6 @@ mod tests { Some('\n') ); - completion_label_without_builtin_func_test_snapshot!( schema_attr_newline_completion_0_1, "src/test_data/completion_test/newline/schema/schema_0/schema_0.k",