From b6e0c0bd541c65136abd3b173b51c54b85b7e77f Mon Sep 17 00:00:00 2001 From: Peefy Date: Wed, 3 Jul 2024 16:22:40 +0800 Subject: [PATCH] add hint API for the semantic model (#1468) add hint API for the sematic model Signed-off-by: peefy --- kclvm/sema/src/advanced_resolver/node.rs | 68 ++-- kclvm/sema/src/core/symbol.rs | 166 +++++++--- kclvm/tools/src/LSP/src/inlay_hints.rs | 128 ++++---- kclvm/tools/src/LSP/src/request.rs | 2 +- ...y_hints__tests__assign_stmt_type_hint.snap | 294 ++++++++++++++++++ .../main_pkg/kcl.mod.lock | 4 +- .../goto_import_def_test/kcl.mod.lock | 3 +- .../assign_stmt_type_hint.k | 22 ++ 8 files changed, 535 insertions(+), 152 deletions(-) create mode 100644 kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap create mode 100644 kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k diff --git a/kclvm/sema/src/advanced_resolver/node.rs b/kclvm/sema/src/advanced_resolver/node.rs index 6df4640a1..0d263bfd2 100644 --- a/kclvm/sema/src/advanced_resolver/node.rs +++ b/kclvm/sema/src/advanced_resolver/node.rs @@ -11,8 +11,8 @@ use crate::{ core::{ scope::LocalSymbolScopeKind, symbol::{ - CommentSymbol, DecoratorSymbol, ExpressionSymbol, KCLSymbolSemanticInfo, SymbolRef, - UnresolvedSymbol, ValueSymbol, + CommentSymbol, DecoratorSymbol, ExpressionSymbol, SymbolHint, SymbolRef, + SymbolSemanticInfo, UnresolvedSymbol, ValueSymbol, }, }, ty::{Type, TypeKind, SCHEMA_MEMBER_FUNCTIONS}, @@ -73,7 +73,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { .type_aliases .get_mut(alias_symbol.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -93,7 +93,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { continue; } self.ctx.maybe_def = true; - self.walk_identifier_expr(target)?; + self.walk_identifier_expr_with_hint(target, assign_stmt.ty.is_none())?; self.ctx.maybe_def = false; } self.walk_type_expr(assign_stmt.ty.as_ref().map(|ty| ty.as_ref()))?; @@ -222,7 +222,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { .schemas .get_mut(schema_symbol.get_id()) .ok_or(anyhow!("schema_symbol not found"))? - .sema_info = KCLSymbolSemanticInfo { + .sema_info = SymbolSemanticInfo { ty: Some(schema_ty.clone()), doc: schema_stmt.doc.as_ref().map(|doc| doc.node.clone()), }; @@ -285,7 +285,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { self.ctx.current_pkgpath.clone().unwrap(), ); if let Some(symbol) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -368,7 +368,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { .rules .get_mut(rule_symbol.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -434,15 +434,14 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { .get_scopes_mut() .add_def_to_scope(cur_scope, name, value); if let Some(symbol) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { - ty: self - .ctx - .node_ty_map - .borrow() - .get(&self.ctx.get_node_key(ast_id)) - .map(|ty| ty.clone()), - doc: None, - }; + let ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(ast_id)) + .map(|ty| ty.clone()); + symbol.hint = ty.as_ref().map(|ty| SymbolHint::TypeHint(ty.ty_str())); + symbol.sema_info = SymbolSemanticInfo { ty, doc: None }; } } @@ -485,7 +484,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { .attributes .get_mut(attr_symbol.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -688,7 +687,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { self.expr(&comp_clause.iter)?; for target in comp_clause.targets.iter() { self.ctx.maybe_def = true; - self.walk_identifier_expr(target)?; + self.walk_identifier_expr_with_hint(target, true)?; self.ctx.maybe_def = false; } for if_expr in comp_clause.ifs.iter() { @@ -1065,7 +1064,7 @@ impl<'ctx> AdvancedResolver<'ctx> { .values .get_mut(first_value.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -1095,7 +1094,7 @@ impl<'ctx> AdvancedResolver<'ctx> { if let Some(symbol) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { - symbol.sema_info = KCLSymbolSemanticInfo { + symbol.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map @@ -1119,6 +1118,14 @@ impl<'ctx> AdvancedResolver<'ctx> { pub fn walk_identifier_expr( &mut self, identifier: &'ctx ast::NodeRef, + ) -> ResolvedResult { + self.walk_identifier_expr_with_hint(identifier, false) + } + + pub fn walk_identifier_expr_with_hint( + &mut self, + identifier: &'ctx ast::NodeRef, + with_hint: bool, ) -> ResolvedResult { let symbol_ref = if let Some(identifier_symbol) = self .gs @@ -1139,15 +1146,16 @@ impl<'ctx> AdvancedResolver<'ctx> { } else { &identifier.node.names.last().unwrap().id }; - symbol.sema_info = KCLSymbolSemanticInfo { - ty: self - .ctx - .node_ty_map - .borrow() - .get(&self.ctx.get_node_key(id)) - .map(|ty| ty.clone()), - doc: None, - }; + let ty = self + .ctx + .node_ty_map + .borrow() + .get(&self.ctx.get_node_key(id)) + .map(|ty| ty.clone()); + if with_hint { + symbol.hint = ty.as_ref().map(|ty| SymbolHint::TypeHint(ty.ty_str())); + } + symbol.sema_info = SymbolSemanticInfo { ty, doc: None }; } if self.ctx.maybe_def && identifier.node.names.len() > 0 { @@ -1233,7 +1241,7 @@ impl<'ctx> AdvancedResolver<'ctx> { ); if let Some(value) = self.gs.get_symbols_mut().values.get_mut(value.get_id()) { - value.sema_info = KCLSymbolSemanticInfo { + value.sema_info = SymbolSemanticInfo { ty: self .ctx .node_ty_map diff --git a/kclvm/sema/src/core/symbol.rs b/kclvm/sema/src/core/symbol.rs index bc4a70172..57596aa02 100644 --- a/kclvm/sema/src/core/symbol.rs +++ b/kclvm/sema/src/core/symbol.rs @@ -15,6 +15,8 @@ use crate::{ pub trait Symbol { type SymbolData; type SemanticInfo; + type SymbolHint; + fn get_sema_info(&self) -> &Self::SemanticInfo; fn is_global(&self) -> bool; fn get_range(&self) -> Range; @@ -41,14 +43,17 @@ pub trait Symbol { module_info: Option<&ModuleInfo>, ) -> Vec; + fn get_hint(&self) -> Option<&Self::SymbolHint>; + fn simple_dump(&self) -> String; fn full_dump(&self, data: &Self::SymbolData) -> Option; } -pub type KCLSymbol = dyn Symbol; +pub type KCLSymbol = + dyn Symbol; #[derive(Debug, Clone, Default)] -pub struct KCLSymbolSemanticInfo { +pub struct SymbolSemanticInfo { pub ty: Option>, pub doc: Option, } @@ -84,6 +89,12 @@ pub struct SymbolDB { pub(crate) pkg_symbol_map: IndexMap>, } +#[derive(Debug, Clone)] +pub enum SymbolHint { + TypeHint(String), + VarHint(String), +} + impl SymbolData { pub fn get_package_symbol(&self, id: SymbolRef) -> Option<&PackageSymbol> { if matches!(id.get_kind(), SymbolKind::Package) { @@ -936,7 +947,7 @@ pub struct SchemaSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: SymbolRef, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, pub(crate) parent_schema: Option, pub(crate) for_host: Option, @@ -946,7 +957,8 @@ pub struct SchemaSymbol { impl Symbol for SchemaSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { true @@ -1049,6 +1061,10 @@ impl Symbol for SchemaSymbol { self.get_attribute(name, data, module_info).is_some() } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"SchemaSymbol\",\n"); @@ -1121,7 +1137,7 @@ impl SchemaSymbol { owner, parent_schema: None, for_host: None, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), mixins: Vec::default(), attributes: IndexMap::default(), } @@ -1136,18 +1152,21 @@ pub struct ValueSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: Option, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, + pub(crate) hint: Option, pub(crate) is_global: bool, } impl Symbol for ValueSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { self.is_global } + fn get_range(&self) -> Range { (self.start.clone(), self.end.clone()) } @@ -1202,6 +1221,11 @@ impl Symbol for ValueSymbol { ) -> bool { self.get_attribute(name, data, module_info).is_some() } + + fn get_hint(&self) -> Option<&Self::SymbolHint> { + self.hint.as_ref() + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"ValueSymbol\",\n"); @@ -1252,8 +1276,9 @@ impl ValueSymbol { start, end, owner, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), is_global, + hint: None, } } } @@ -1266,13 +1291,14 @@ pub struct AttributeSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: SymbolRef, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, pub(crate) is_optional: bool, } impl Symbol for AttributeSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { true @@ -1336,6 +1362,10 @@ impl Symbol for AttributeSymbol { self.get_attribute(name, data, module_info).is_some() } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"AttributeSymbol\",\n"); @@ -1383,7 +1413,7 @@ impl AttributeSymbol { name, start, end, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), owner, is_optional, } @@ -1401,12 +1431,13 @@ pub struct PackageSymbol { pub(crate) members: IndexMap, pub(crate) start: Position, pub(crate) end: Position, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for PackageSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { true @@ -1461,6 +1492,10 @@ impl Symbol for PackageSymbol { self.members.contains_key(name) } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"PackageSymbol\",\n"); @@ -1508,7 +1543,7 @@ impl PackageSymbol { name, start, end, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), members: IndexMap::default(), } } @@ -1521,12 +1556,13 @@ pub struct TypeAliasSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: SymbolRef, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for TypeAliasSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { true @@ -1586,6 +1622,10 @@ impl Symbol for TypeAliasSymbol { self.get_attribute(name, data, module_info).is_some() } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"TypeAliasSymbol\",\n"); @@ -1629,7 +1669,7 @@ impl TypeAliasSymbol { name, start, end, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), owner, } } @@ -1642,7 +1682,7 @@ pub struct RuleSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: SymbolRef, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, pub(crate) parent_rules: Vec, pub(crate) for_host: Option, @@ -1650,7 +1690,8 @@ pub struct RuleSymbol { impl Symbol for RuleSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { true @@ -1701,6 +1742,10 @@ impl Symbol for RuleSymbol { false } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"RuleSymbol\",\n"); @@ -1757,7 +1802,7 @@ impl RuleSymbol { start, end, owner, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), parent_rules: vec![], for_host: None, } @@ -1772,12 +1817,13 @@ pub struct UnresolvedSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: Option, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for UnresolvedSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { false @@ -1834,6 +1880,14 @@ impl Symbol for UnresolvedSymbol { self.get_attribute(name, data, module_info).is_some() } + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"UnresolvedSymbol\",\n"); @@ -1853,6 +1907,7 @@ impl Symbol for UnresolvedSymbol { output.push_str("\"\n}"); output } + fn full_dump(&self, data: &Self::SymbolData) -> Option { let mut output = format!("{{\n\"simple_info\": {},\n", self.simple_dump()); output.push_str("\"additional_info\": {\n"); @@ -1863,10 +1918,6 @@ impl Symbol for UnresolvedSymbol { output.push_str("\n}\n}"); Some(output) } - - fn get_sema_info(&self) -> &Self::SemanticInfo { - &self.sema_info - } } impl UnresolvedSymbol { @@ -1877,7 +1928,7 @@ impl UnresolvedSymbol { name, start, end, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), owner, } } @@ -1907,12 +1958,13 @@ pub struct ExpressionSymbol { pub(crate) owner: Option, pub(crate) name: String, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for ExpressionSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { false @@ -1971,6 +2023,15 @@ impl Symbol for ExpressionSymbol { ) -> bool { self.get_attribute(name, data, module_info).is_some() } + + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"ExpressionSymbol\",\n"); @@ -2000,10 +2061,6 @@ impl Symbol for ExpressionSymbol { output.push_str("\n}\n}"); Some(output) } - - fn get_sema_info(&self) -> &Self::SemanticInfo { - &self.sema_info - } } impl ExpressionSymbol { @@ -2013,7 +2070,7 @@ impl ExpressionSymbol { name, start, end, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), owner, } } @@ -2025,12 +2082,13 @@ pub struct CommentSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) content: String, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for CommentSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn get_sema_info(&self) -> &Self::SemanticInfo { &self.sema_info @@ -2086,6 +2144,10 @@ impl Symbol for CommentSymbol { vec![] } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"CommentSymbol\",\n"); @@ -2118,7 +2180,7 @@ impl CommentSymbol { start, end, content, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), } } @@ -2133,12 +2195,13 @@ pub struct DecoratorSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) name: String, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, } impl Symbol for DecoratorSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn get_sema_info(&self) -> &Self::SemanticInfo { &self.sema_info @@ -2194,6 +2257,10 @@ impl Symbol for DecoratorSymbol { vec![] } + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"CommentSymbol\",\n"); @@ -2226,7 +2293,7 @@ impl DecoratorSymbol { start, end, name, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), } } @@ -2242,14 +2309,15 @@ pub struct FunctionSymbol { pub(crate) start: Position, pub(crate) end: Position, pub(crate) owner: Option, - pub(crate) sema_info: KCLSymbolSemanticInfo, + pub(crate) sema_info: SymbolSemanticInfo, pub(crate) is_global: bool, } impl Symbol for FunctionSymbol { type SymbolData = SymbolData; - type SemanticInfo = KCLSymbolSemanticInfo; + type SemanticInfo = SymbolSemanticInfo; + type SymbolHint = SymbolHint; fn is_global(&self) -> bool { self.is_global @@ -2310,6 +2378,14 @@ impl Symbol for FunctionSymbol { self.get_attribute(name, data, module_info).is_some() } + fn get_sema_info(&self) -> &Self::SemanticInfo { + &self.sema_info + } + + fn get_hint(&self) -> Option<&Self::SymbolHint> { + None + } + fn simple_dump(&self) -> String { let mut output = "{\n".to_string(); output.push_str("\"kind\": \"FunctionSymbol\",\n"); @@ -2340,10 +2416,6 @@ impl Symbol for FunctionSymbol { output.push_str("\n}\n}"); Some(output) } - - fn get_sema_info(&self) -> &Self::SemanticInfo { - &self.sema_info - } } impl FunctionSymbol { @@ -2360,7 +2432,7 @@ impl FunctionSymbol { start, end, owner, - sema_info: KCLSymbolSemanticInfo::default(), + sema_info: SymbolSemanticInfo::default(), is_global, } } diff --git a/kclvm/tools/src/LSP/src/inlay_hints.rs b/kclvm/tools/src/LSP/src/inlay_hints.rs index c2363756d..e72b5afd6 100644 --- a/kclvm/tools/src/LSP/src/inlay_hints.rs +++ b/kclvm/tools/src/LSP/src/inlay_hints.rs @@ -1,23 +1,17 @@ -use kclvm_ast::ast::{self, Program}; -use kclvm_ast::pos::GetPos; -use kclvm_error::Position as KCLPos; +use kclvm_sema::core::symbol::SymbolHint; use kclvm_sema::core::{global_state::GlobalState, symbol::KCLSymbol}; -use kclvm_sema::ty::TypeKind; -use lsp_types::{InlayHint, InlayHintLabelPart, Position as LspPosition, Range}; +use lsp_types::{InlayHint, InlayHintLabelPart, Position as LspPosition}; use std::convert::TryInto; -pub fn inlay_hints(file: &str, gs: &GlobalState, program: &Program) -> Option> { +pub fn inlay_hints(file: &str, gs: &GlobalState) -> Option> { let mut inlay_hints: Vec = vec![]; let sema_db = gs.get_sema_db(); if let Some(file_sema) = sema_db.get_file_sema(file) { let symbols = file_sema.get_symbols(); for symbol_ref in symbols { if let Some(symbol) = gs.get_symbols().get_symbol(*symbol_ref) { - let (start, end) = symbol.get_range(); - if has_type_assignment(program, &start) { - if let Some(hint) = generate_inlay_hint(symbol, gs, &start, &end) { - inlay_hints.push(hint); - } + if let Some(hint) = symbol.get_hint() { + inlay_hints.push(generate_inlay_hint(symbol, hint)); } } } @@ -25,72 +19,66 @@ pub fn inlay_hints(file: &str, gs: &GlobalState, program: &Program) -> Option bool { - if let Some(stmt_node) = program.pos_to_stmt(start) { - if let ast::Stmt::Assign(assign_stmt) = stmt_node.node { - if assign_stmt - .targets - .iter() - .any(|target| target.get_pos() == *start) - && assign_stmt.ty.is_none() - { - return true; - } - } +#[inline] +fn generate_inlay_hint(symbol: &KCLSymbol, hint: &SymbolHint) -> InlayHint { + let (part, position) = get_hint_label(symbol, &hint); + InlayHint { + position, + label: lsp_types::InlayHintLabel::LabelParts(vec![part]), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some(true), + padding_right: Some(true), + data: None, } - false } -fn generate_inlay_hint( - symbol: &KCLSymbol, - gs: &GlobalState, - start: &KCLPos, - end: &KCLPos, -) -> Option { - match get_hint_label(symbol, gs) { - Some(label_parts) => { - let range = Range { - start: LspPosition::new( - (start.line - 1).try_into().unwrap(), - start.column.unwrap_or(0).try_into().unwrap(), - ), - end: LspPosition::new( - (end.line - 1).try_into().unwrap(), - end.column.unwrap_or(0).try_into().unwrap(), - ), - }; - Some(InlayHint { - position: range.end, - label: lsp_types::InlayHintLabel::LabelParts(label_parts), - kind: None, - text_edits: None, - tooltip: None, - padding_left: Some(true), - padding_right: Some(true), - data: None, - }) - } - None => None, +fn get_hint_label(symbol: &KCLSymbol, hint: &SymbolHint) -> (InlayHintLabelPart, LspPosition) { + let (start, end) = symbol.get_range(); + match hint { + SymbolHint::TypeHint(ty) => ( + InlayHintLabelPart { + value: format!(": {ty}"), + ..Default::default() + }, + LspPosition::new( + (end.line - 1).try_into().unwrap(), + end.column.unwrap_or(0).try_into().unwrap(), + ), + ), + SymbolHint::VarHint(var) => ( + InlayHintLabelPart { + value: format!("{var}: "), + ..Default::default() + }, + LspPosition::new( + (start.line - 1).try_into().unwrap(), + start.column.unwrap_or(0).try_into().unwrap(), + ), + ), } } -fn get_hint_label(symbol: &KCLSymbol, _gs: &GlobalState) -> Option> { - if let Some(ty) = &symbol.get_sema_info().ty { - let mut label_parts = Vec::new(); +#[cfg(test)] +mod tests { + use super::inlay_hints; + use crate::tests::compile_test_file; - match &ty.kind { - TypeKind::Str | TypeKind::Bool | TypeKind::Int | TypeKind::Float | TypeKind::Any => { - label_parts.push(InlayHintLabelPart { - value: format!("[: {}]", ty.ty_str()), - ..Default::default() - }); + #[macro_export] + macro_rules! inlay_hints_test_snapshot { + ($name:ident, $file:expr) => { + #[test] + fn $name() { + let (file, _, _, gs) = compile_test_file($file); + let res = inlay_hints(&file, &gs); + insta::assert_snapshot!(format!("{:#?}", res)); } - _ => { - return None; - } - } - Some(label_parts) - } else { - None + }; } + + inlay_hints_test_snapshot!( + test_assign_stmt_type_hint, + "src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k" + ); } diff --git a/kclvm/tools/src/LSP/src/request.rs b/kclvm/tools/src/LSP/src/request.rs index 1e62c1301..7afde3ccd 100644 --- a/kclvm/tools/src/LSP/src/request.rs +++ b/kclvm/tools/src/LSP/src/request.rs @@ -464,7 +464,7 @@ pub(crate) fn handle_inlay_hint( }, Err(_) => return Ok(None), }; - let res = inlay_hints(&file, &db.gs, &db.prog); + let res = inlay_hints(&file, &db.gs); if !snapshot.verify_request_version(db.version, &path)? { return Err(anyhow!(LSPError::Retry)); diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap new file mode 100644 index 000000000..fb56296b3 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__inlay_hints__tests__assign_stmt_type_hint.snap @@ -0,0 +1,294 @@ +--- +source: tools/src/LSP/src/inlay_hints.rs +expression: "format!(\"{:#?}\", res)" +--- +Some( + [ + InlayHint { + position: Position { + line: 0, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 1, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 2, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 3, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": (int) -> int", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 10, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Name", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 13, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": Name", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 14, + character: 4, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": any", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 16, + character: 1, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": str", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 17, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": [int | str]", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 18, + character: 2, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": {str:str}", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + InlayHint { + position: Position { + line: 21, + character: 3, + }, + label: LabelParts( + [ + InlayHintLabelPart { + value: ": number_multiplier(1Ki)", + tooltip: None, + location: None, + command: None, + }, + ], + ), + kind: None, + text_edits: None, + tooltip: None, + padding_left: Some( + true, + ), + padding_right: Some( + true, + ), + data: None, + }, + ], +) diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock index 9c32b8db3..176cb7dec 100644 --- a/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_with_line_test/main_pkg/kcl.mod.lock @@ -1,6 +1,6 @@ [dependencies] [dependencies.dep-with-line] name = "dep-with-line" - full_name = "dep-with-line_" + full_name = "dep-with-line_0.0.1" + version = "0.0.1" sum = "O2Z1djaB1lC38kNfhwUUYAlqGKE7seUqqys3DPcJfEw=" - path = "../dep-with-line" diff --git a/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock index 02b0b8e32..3fc8b46f8 100644 --- a/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock +++ b/kclvm/tools/src/LSP/src/test_data/goto_import_def_test/kcl.mod.lock @@ -1,8 +1,7 @@ [dependencies] [dependencies.konfig] name = "konfig" - full_name = "konfig_v0.0.1" - version = "v0.0.1" + full_name = "_" sum = "XFvHdBAoY/+qpJWmj8cjwOwZO8a3nX/7SE35cTxQOFU=" url = "https://github.com/awesome-kusion/konfig.git" git_tag = "v0.0.1" diff --git a/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k b/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k new file mode 100644 index 000000000..56b633380 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/inlay_hints/assign_stmt_type_hint/assign_stmt_type_hint.k @@ -0,0 +1,22 @@ +a = 1 +b = "" +c = "" +d = lambda x: int { + x = 1 + x +} +schema Name: + name: str + +n = Name { + +} +bb = n +aaaa = None +type name = "asdad" +f = "" +cc = [1, "", 3] +ee = { + a: "asda" +} +ccc = 1Ki