From 6cc712e113bf7d3cdb4b2ba0b44d73cbd2ca55fc Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Thu, 16 May 2024 19:30:24 +0800 Subject: [PATCH 1/2] fix: fix inherit schema attrs hover Signed-off-by: he1pa <18012015693@163.com> --- kclvm/sema/src/core/symbol.rs | 16 ++- kclvm/sema/src/namer/node.rs | 2 +- kclvm/tools/src/LSP/src/hover.rs | 105 ++++++++++++------ .../LSP/src/test_data/hover_test/inherit.k | 7 ++ 4 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs index 772b2bc65..a4171cf11 100644 --- a/kclvm/sema/src/core/symbol.rs +++ b/kclvm/sema/src/core/symbol.rs @@ -130,6 +130,14 @@ impl SymbolData { } } + pub fn get_attr_symbol(&self, id: SymbolRef) -> Option<&AttributeSymbol> { + if matches!(id.get_kind(), SymbolKind::Attribute) { + self.attributes.get(id.get_id()) + } else { + None + } + } + pub fn get_symbol(&self, id: SymbolRef) -> Option<&KCLSymbol> { match id.get_kind() { SymbolKind::Schema => self @@ -1095,6 +1103,7 @@ pub struct AttributeSymbol { pub(crate) end: Position, pub(crate) owner: SymbolRef, pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) is_optional: bool, } impl Symbol for AttributeSymbol { @@ -1198,7 +1207,7 @@ impl Symbol for AttributeSymbol { } impl AttributeSymbol { - pub fn new(name: String, start: Position, end: Position, owner: SymbolRef) -> Self { + pub fn new(name: String, start: Position, end: Position, owner: SymbolRef, is_optional: bool) -> Self { Self { id: None, name, @@ -1206,8 +1215,13 @@ impl AttributeSymbol { end, sema_info: KCLSymbolSemanticInfo::default(), owner, + is_optional, } } + + pub fn is_optional(&self) -> bool { + self.is_optional + } } #[allow(unused)] #[derive(Debug, Clone)] diff --git a/kclvm/sema/src/namer/node.rs b/kclvm/sema/src/namer/node.rs index 71e0cb1bf..b472e2e9b 100644 --- a/kclvm/sema/src/namer/node.rs +++ b/kclvm/sema/src/namer/node.rs @@ -226,7 +226,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Namer<'ctx> { let (start_pos, end_pos): Range = schema_attr.name.get_span_pos(); let owner = self.ctx.owner_symbols.last().unwrap().clone(); let attribute_ref = self.gs.get_symbols_mut().alloc_attribute_symbol( - AttributeSymbol::new(schema_attr.name.node.clone(), start_pos, end_pos, owner), + AttributeSymbol::new(schema_attr.name.node.clone(), start_pos, end_pos, owner, schema_attr.is_optional), self.ctx.get_node_key(&schema_attr.name.id), ); Some(vec![attribute_ref]) diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs index a87f75ef2..c26af559a 100644 --- a/kclvm/tools/src/LSP/src/hover.rs +++ b/kclvm/tools/src/LSP/src/hover.rs @@ -3,7 +3,7 @@ use kclvm_error::Position as KCLPos; use kclvm_sema::{ builtin::BUILTIN_DECORATORS, core::global_state::GlobalState, - ty::{FunctionType, SchemaType}, + ty::{FunctionType, SchemaType, ANY_TYPE_STR}, }; use lsp_types::{Hover, HoverContents, MarkedString}; @@ -22,8 +22,51 @@ pub(crate) fn hover( Some(def_ref) => match gs.get_symbols().get_symbol(def_ref) { Some(obj) => match def_ref.get_kind() { kclvm_sema::core::symbol::SymbolKind::Schema => match &obj.get_sema_info().ty { - Some(schema_ty) => { - docs.extend(build_schema_hover_content(&schema_ty.into_schema_type())); + Some(ty) => { + // Build hover content for schema definition + // Schema Definition hover + // ``` + // pkg + // schema Foo(Base)[param: type] + // ----------------- + // doc + // ----------------- + // Attributes: + // attr1: type + // attr2? type + // ``` + let schema_ty = ty.into_schema_type(); + docs.push(schema_ty.schema_ty_signature_str()); + if !schema_ty.doc.is_empty() { + docs.push(schema_ty.doc.clone()); + } + + // The attr of schema_ty does not contain the attrs from inherited base schema. + // Use the api provided by GlobalState to get all attrs + let module_info = gs.get_packages().get_module_info(&kcl_pos.filename); + let schema_attrs = obj.get_all_attributes(gs.get_symbols(), module_info); + let mut attrs = vec!["Attributes:".to_string()]; + for schema_attr in schema_attrs { + if let kclvm_sema::core::symbol::SymbolKind::Attribute = + schema_attr.get_kind() + { + let attr = gs.get_symbols().get_symbol(schema_attr).unwrap(); + let name = attr.get_name(); + let attr_symbol = + gs.get_symbols().get_attr_symbol(schema_attr).unwrap(); + let attr_ty_str = match &attr.get_sema_info().ty { + Some(ty) => ty.ty_str(), + None => ANY_TYPE_STR.to_string(), + }; + attrs.push(format!( + "{}{}: {}", + name, + if attr_symbol.is_optional() { "?" } else { "" }, + attr_ty_str, + )); + } + } + docs.push(attrs.join("\n\n")); } _ => {} }, @@ -100,37 +143,6 @@ fn docs_to_hover(docs: Vec) -> Option { } } -// Build hover content for schema definition -// Schema Definition hover -// ``` -// pkg -// schema Foo(Base)[param: type] -// ----------------- -// doc -// ----------------- -// Attributes: -// attr1: type -// attr2? type -// ``` -fn build_schema_hover_content(schema_ty: &SchemaType) -> Vec { - let mut docs = vec![]; - docs.push(schema_ty.schema_ty_signature_str()); - if !schema_ty.doc.is_empty() { - docs.push(schema_ty.doc.clone()); - } - let mut attrs = vec!["Attributes:".to_string()]; - for (name, attr) in &schema_ty.attrs { - attrs.push(format!( - "{}{}: {}", - name, - if attr.is_optional { "?" } else { "" }, - attr.ty.ty_str(), - )); - } - docs.push(attrs.join("\n\n")); - docs -} - // Build hover content for function call // ``` // pkg @@ -574,4 +586,29 @@ mod tests { _ => unreachable!("test error"), } } + + #[test] + #[bench_test] + fn inherit_schema_attr_hover() { + let (file, program, _, gs) = compile_test_file("src/test_data/hover_test/inherit.k"); + let pos = KCLPos { + filename: file.clone(), + line: 5, + column: Some(9), + }; + let got = hover(&program, &pos, &gs).unwrap(); + + let expect_content = vec![MarkedString::String( + "__main__\n\nschema Data1\\[m: {str:str}](Data)".to_string(), + ), MarkedString::String( + "Attributes:\n\nname: str\n\nage: int".to_string(), + )]; + + match got.contents { + lsp_types::HoverContents::Array(vec) => { + assert_eq!(vec, expect_content); + } + _ => unreachable!("test error"), + } + } } diff --git a/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k b/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k new file mode 100644 index 000000000..0e8c08f5b --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/hover_test/inherit.k @@ -0,0 +1,7 @@ +schema Data: + name: str = "1" + age: int + +schema Data1[m: {str:str}](Data): + name = m.name + \ No newline at end of file From f35abff8edc1b622bacdfc2b532a906d94a4235e Mon Sep 17 00:00:00 2001 From: he1pa <18012015693@163.com> Date: Thu, 16 May 2024 19:44:33 +0800 Subject: [PATCH 2/2] fmt: fmt code Signed-off-by: he1pa <18012015693@163.com> --- kclvm/sema/src/core/symbol.rs | 8 +++++++- kclvm/sema/src/namer/node.rs | 8 +++++++- kclvm/tools/src/LSP/src/hover.rs | 9 ++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs index a4171cf11..37ace5323 100644 --- a/kclvm/sema/src/core/symbol.rs +++ b/kclvm/sema/src/core/symbol.rs @@ -1207,7 +1207,13 @@ impl Symbol for AttributeSymbol { } impl AttributeSymbol { - pub fn new(name: String, start: Position, end: Position, owner: SymbolRef, is_optional: bool) -> Self { + pub fn new( + name: String, + start: Position, + end: Position, + owner: SymbolRef, + is_optional: bool, + ) -> Self { Self { id: None, name, diff --git a/kclvm/sema/src/namer/node.rs b/kclvm/sema/src/namer/node.rs index b472e2e9b..ab923cef7 100644 --- a/kclvm/sema/src/namer/node.rs +++ b/kclvm/sema/src/namer/node.rs @@ -226,7 +226,13 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Namer<'ctx> { let (start_pos, end_pos): Range = schema_attr.name.get_span_pos(); let owner = self.ctx.owner_symbols.last().unwrap().clone(); let attribute_ref = self.gs.get_symbols_mut().alloc_attribute_symbol( - AttributeSymbol::new(schema_attr.name.node.clone(), start_pos, end_pos, owner, schema_attr.is_optional), + AttributeSymbol::new( + schema_attr.name.node.clone(), + start_pos, + end_pos, + owner, + schema_attr.is_optional, + ), self.ctx.get_node_key(&schema_attr.name.id), ); Some(vec![attribute_ref]) diff --git a/kclvm/tools/src/LSP/src/hover.rs b/kclvm/tools/src/LSP/src/hover.rs index c26af559a..371c72a4d 100644 --- a/kclvm/tools/src/LSP/src/hover.rs +++ b/kclvm/tools/src/LSP/src/hover.rs @@ -598,11 +598,10 @@ mod tests { }; let got = hover(&program, &pos, &gs).unwrap(); - let expect_content = vec![MarkedString::String( - "__main__\n\nschema Data1\\[m: {str:str}](Data)".to_string(), - ), MarkedString::String( - "Attributes:\n\nname: str\n\nage: int".to_string(), - )]; + let expect_content = vec![ + MarkedString::String("__main__\n\nschema Data1\\[m: {str:str}](Data)".to_string()), + MarkedString::String("Attributes:\n\nname: str\n\nage: int".to_string()), + ]; match got.contents { lsp_types::HoverContents::Array(vec) => {