diff --git a/kclvm/loader/src/lib.rs b/kclvm/loader/src/lib.rs index 307fe34d2..5013ed4fd 100644 --- a/kclvm/loader/src/lib.rs +++ b/kclvm/loader/src/lib.rs @@ -105,7 +105,8 @@ pub enum ScopeKind { Lambda, SchemaDef, SchemaConfig, - Value, + SchemaConfigRightValue, + SchemaConfigLeftKey, Check, Callable, } @@ -254,9 +255,10 @@ impl From for ScopeKind { LocalSymbolScopeKind::Lambda => ScopeKind::Lambda, LocalSymbolScopeKind::SchemaDef => ScopeKind::SchemaDef, LocalSymbolScopeKind::SchemaConfig => ScopeKind::SchemaConfig, - LocalSymbolScopeKind::Value => ScopeKind::Value, + LocalSymbolScopeKind::SchemaConfigRightValue => ScopeKind::SchemaConfigRightValue, LocalSymbolScopeKind::Check => ScopeKind::Check, LocalSymbolScopeKind::Callable => ScopeKind::Callable, + LocalSymbolScopeKind::SchemaConfigLeftKey => ScopeKind::SchemaConfigLeftKey, } } } @@ -278,8 +280,8 @@ fn collect_scope_info( kclvm_sema::core::scope::ScopeKind::Local => { match scope_data.try_get_local_scope(&scope_ref) { Some(local) => match local.get_kind() { - LocalSymbolScopeKind::SchemaConfig | LocalSymbolScopeKind::Check => true, - _ => false, + LocalSymbolScopeKind::SchemaConfigRightValue => false, + _ => true, }, None => false, } diff --git a/kclvm/sema/src/advanced_resolver/mod.rs b/kclvm/sema/src/advanced_resolver/mod.rs index 66058882a..2ae0c328e 100644 --- a/kclvm/sema/src/advanced_resolver/mod.rs +++ b/kclvm/sema/src/advanced_resolver/mod.rs @@ -81,8 +81,10 @@ pub struct Context<'ctx> { // which means advanced resolver will will create the corresponding // ValueSymbol instead of an UnresolvedSymbol maybe_def: bool, - // whether lookup def in scope owner, default true, only in schema attr value is false - look_up_in_owner: bool, + // whether in schema config right value, affect lookup def + in_schema_config_r_value: bool, + // whether in schema def, affect lookup def + in_schema_def: bool, } impl<'ctx> Context<'ctx> { @@ -113,7 +115,8 @@ impl<'ctx> AdvancedResolver<'ctx> { end_pos: Position::dummy_pos(), cur_node: AstIndex::default(), maybe_def: false, - look_up_in_owner: true, + in_schema_config_r_value: false, + in_schema_def: false, }, }; // Scan all scehma symbol diff --git a/kclvm/sema/src/advanced_resolver/node.rs b/kclvm/sema/src/advanced_resolver/node.rs index 78cd6f5f3..8904d53e2 100644 --- a/kclvm/sema/src/advanced_resolver/node.rs +++ b/kclvm/sema/src/advanced_resolver/node.rs @@ -291,6 +291,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { end.clone(), LocalSymbolScopeKind::SchemaDef, ); + self.ctx.in_schema_def = true; let cur_scope = *self.ctx.scopes.last().unwrap(); self.gs .get_scopes_mut() @@ -407,7 +408,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for AdvancedResolver<'ctx> { if has_check { self.leave_scope(); } - + self.ctx.in_schema_def = false; self.leave_scope(); Ok(Some(schema_symbol)) @@ -1043,7 +1044,7 @@ impl<'ctx> AdvancedResolver<'ctx> { cur_scope, self.get_current_module_info(), maybe_def, - self.ctx.look_up_in_owner, + self.ctx.in_schema_def || !self.ctx.in_schema_config_r_value, ); if first_symbol.is_none() { // Maybe import package symbol @@ -1083,29 +1084,61 @@ impl<'ctx> AdvancedResolver<'ctx> { match first_symbol { Some(symbol_ref) => { let (start_pos, end_pos): Range = first_name.get_span_pos(); - let (def_start_pos, def_end_pos) = self + let def_symbol = self .gs .get_symbols() .get_symbol(symbol_ref) - .ok_or(anyhow!("first name symbol not found"))? - .get_range(); + .ok_or(anyhow!("first name symbol not found"))?; + let (def_start_pos, def_end_pos) = def_symbol.get_range(); + + let cur_scope = *self.ctx.scopes.last().unwrap(); + let ast_id = first_name.id.clone(); + let mut first_unresolved = UnresolvedSymbol::new( + first_name.node.clone(), + start_pos.clone(), + end_pos.clone(), + None, + ); + let name = def_symbol.get_name(); + first_unresolved.def = Some(symbol_ref); + let first_unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( + first_unresolved, + self.ctx.get_node_key(&ast_id), + self.ctx.current_pkgpath.clone().unwrap(), + ); + + match cur_scope.get_kind() { + crate::core::scope::ScopeKind::Local => { + let local_scope = self + .gs + .get_scopes() + .try_get_local_scope(&cur_scope) + .unwrap(); + match local_scope.get_kind() { + LocalSymbolScopeKind::SchemaConfigLeftKey => { + if let crate::core::symbol::SymbolKind::Attribute = + symbol_ref.get_kind() + { + let parent = local_scope.parent; + self.gs.get_scopes_mut().add_def_to_scope( + parent, + name, + first_unresolved_ref, + ); + } + } + _ => {} + } + } + _ => {} + } - // Get an unresolved symbol if def_start_pos != start_pos || def_end_pos != end_pos { - let ast_id = first_name.id.clone(); - let mut first_unresolved = - UnresolvedSymbol::new(first_name.node.clone(), start_pos, end_pos, None); - first_unresolved.def = Some(symbol_ref); - let first_unresolved_ref = self.gs.get_symbols_mut().alloc_unresolved_symbol( - first_unresolved, - self.ctx.get_node_key(&ast_id), - self.ctx.current_pkgpath.clone().unwrap(), - ); - let cur_scope = *self.ctx.scopes.last().unwrap(); self.gs .get_scopes_mut() .add_ref_to_scope(cur_scope, first_unresolved_ref); } + if names.len() > 1 { let mut parent_ty = match self .ctx @@ -1251,7 +1284,7 @@ impl<'ctx> AdvancedResolver<'ctx> { cur_scope, self.get_current_module_info(), true, - self.ctx.look_up_in_owner, + self.ctx.in_schema_def || !self.ctx.in_schema_config_r_value, ); match first_symbol { Some(symbol_ref) => { @@ -1767,7 +1800,7 @@ impl<'ctx> AdvancedResolver<'ctx> { let schema_symbol = self.ctx.schema_symbol_stack.last().unwrap_or(&None).clone(); let kind = match &schema_symbol { Some(_) => LocalSymbolScopeKind::SchemaConfig, - None => LocalSymbolScopeKind::Value, + None => LocalSymbolScopeKind::SchemaConfigRightValue, }; self.enter_local_scope( @@ -1785,26 +1818,38 @@ impl<'ctx> AdvancedResolver<'ctx> { } for entry in entries.iter() { - if let Some(key) = &entry.node.key { - self.ctx.maybe_def = true; - self.ctx.look_up_in_owner = true; - self.expr(key)?; - self.ctx.look_up_in_owner = false; - self.ctx.maybe_def = false; - } - let (start, end) = entry.node.value.get_span_pos(); - self.enter_local_scope( &self.ctx.current_filename.as_ref().unwrap().clone(), start, end, - LocalSymbolScopeKind::Value, + LocalSymbolScopeKind::SchemaConfigRightValue, ); - self.ctx.look_up_in_owner = false; + self.ctx.in_schema_config_r_value = true; self.expr(&entry.node.value)?; - self.ctx.look_up_in_owner = true; + self.ctx.in_schema_config_r_value = false; self.leave_scope(); + + if let Some(key) = &entry.node.key { + self.ctx.maybe_def = true; + self.ctx.in_schema_config_r_value = false; + self.enter_local_scope( + &self.ctx.current_filename.as_ref().unwrap().clone(), + key.get_pos(), + key.get_end_pos(), + LocalSymbolScopeKind::SchemaConfigLeftKey, + ); + if let Some(owner) = schema_symbol { + let cur_scope = self.ctx.scopes.last().unwrap(); + self.gs + .get_scopes_mut() + .set_owner_to_scope(*cur_scope, owner); + } + self.expr(key)?; + self.leave_scope(); + self.ctx.in_schema_config_r_value = true; + self.ctx.maybe_def = false; + } } self.leave_scope(); Ok(()) diff --git a/kclvm/sema/src/core/global_state.rs b/kclvm/sema/src/core/global_state.rs index 64dd5e60d..e26a4b79f 100644 --- a/kclvm/sema/src/core/global_state.rs +++ b/kclvm/sema/src/core/global_state.rs @@ -88,7 +88,8 @@ impl GlobalState { local: bool, get_def_from_owner: bool, ) -> Option { - match self.scopes.get_scope(&scope_ref)?.look_up_def( + let scope = self.scopes.get_scope(&scope_ref)?; + match scope.look_up_def( name, &self.scopes, &self.symbols, @@ -187,9 +188,8 @@ impl GlobalState { let get_def_from_owner = match scope_ref.kind { ScopeKind::Local => match scopes.try_get_local_scope(&scope_ref) { Some(local) => match local.kind { - super::scope::LocalSymbolScopeKind::SchemaConfig - | super::scope::LocalSymbolScopeKind::Check => true, - _ => false, + super::scope::LocalSymbolScopeKind::SchemaConfigRightValue => false, + _ => true, }, None => true, }, @@ -228,9 +228,8 @@ impl GlobalState { let get_def_from_owner = match scope_ref.kind { ScopeKind::Local => match scopes.try_get_local_scope(&scope_ref) { Some(local) => match local.kind { - super::scope::LocalSymbolScopeKind::SchemaConfig - | super::scope::LocalSymbolScopeKind::Check => true, - _ => false, + super::scope::LocalSymbolScopeKind::SchemaConfigRightValue => false, + _ => true, }, None => false, }, diff --git a/kclvm/sema/src/core/scope.rs b/kclvm/sema/src/core/scope.rs index 60b52fde3..c6c5bd0b1 100644 --- a/kclvm/sema/src/core/scope.rs +++ b/kclvm/sema/src/core/scope.rs @@ -410,7 +410,8 @@ pub enum LocalSymbolScopeKind { Lambda, SchemaDef, SchemaConfig, - Value, + SchemaConfigRightValue, + SchemaConfigLeftKey, Check, Callable, } @@ -549,13 +550,15 @@ impl Scope for LocalSymbolScope { // #Root[ // b = "bar" // foo = Foo #SchemaConfig[{ - // bar: #Value[b] + // #SchemaConfigLeftKey[bar]: #SchemaConfigRightValue[b] // }] // ] // ```` - // At position of `bar`, the scope kind is SchemaConfig, only get the definition of bar. + // At position of `bar`, the scope kind is SchemaConfigLeftKey, only get the definition of bar. // At position of seconde `b`, the scope is the child scope of SchemaConfig, need to recursively find the definition of `b`` at a higher level - if self.kind == LocalSymbolScopeKind::SchemaConfig && !recursive { + if self.kind == LocalSymbolScopeKind::SchemaConfig && !recursive + || self.kind == LocalSymbolScopeKind::SchemaConfigLeftKey + { return all_defs_map; } else { for def_ref in self.defs.values() { diff --git a/kclvm/tools/src/LSP/src/completion.rs b/kclvm/tools/src/LSP/src/completion.rs index 8b0c594b4..606879961 100644 --- a/kclvm/tools/src/LSP/src/completion.rs +++ b/kclvm/tools/src/LSP/src/completion.rs @@ -2064,4 +2064,28 @@ mod tests { 11, None ); + + completion_label_test_snapshot!( + schema_arg_1, + "src/test_data/completion_test/schema_def/schema_def.k", + 10, + 22, + None + ); + + completion_label_test_snapshot!( + schema_arg_2, + "src/test_data/completion_test/schema_def/schema_def.k", + 12, + 5, + None + ); + + completion_label_test_snapshot!( + schema_arg_3, + "src/test_data/completion_test/schema_def/schema_def.k", + 13, + 8, + None + ); } diff --git a/kclvm/tools/src/LSP/src/goto_def.rs b/kclvm/tools/src/LSP/src/goto_def.rs index d8e881147..ebd9a9e15 100644 --- a/kclvm/tools/src/LSP/src/goto_def.rs +++ b/kclvm/tools/src/LSP/src/goto_def.rs @@ -469,4 +469,25 @@ mod tests { 8, 11 ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_1, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 9, + 14 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_2, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 10, + 14 + ); + + goto_def_test_snapshot!( + goto_attr_in_schema_def_3, + "src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k", + 11, + 14 + ); } diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_1.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_2.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_3.snap new file mode 100644 index 000000000..f3bf7669e --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__completion__tests__schema_arg_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/completion.rs +expression: "format!(\"{:?}\", got_labels)" +--- +["Config", "Config{}", "Container", "Container{}", "Server", "Server(inputConfig){}", "config", "inputConfig", "mainContainer"] diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap new file mode 100644 index 000000000..d20ad9209 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_1.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 5, character: 0 }, end: Position { line: 5, character: 5 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap new file mode 100644 index 000000000..196e3cea7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_2.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 8, character: 4 }, end: Position { line: 8, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap new file mode 100644 index 000000000..cc43318b7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/snapshots/kcl_language_server__goto_def__tests__goto_attr_in_schema_def_3.snap @@ -0,0 +1,5 @@ +--- +source: tools/src/LSP/src/goto_def.rs +expression: "format!(\"{:?}\", { fmt_resp(& res) })" +--- +"path: \"src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k\", range: Range { start: Position { line: 9, character: 4 }, end: Position { line: 9, character: 9 } }" diff --git a/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k new file mode 100644 index 000000000..5130a9634 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/completion_test/schema_def/schema_def.k @@ -0,0 +1,13 @@ +schema Container: + name: str + + +schema Config: + mainContainer: Container + image: str + +schema Server[inputConfig: Config]: + config: Config = + mainContainer: {str:} + + if diff --git a/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k new file mode 100644 index 000000000..b2d6a1dd7 --- /dev/null +++ b/kclvm/tools/src/LSP/src/test_data/goto_def_test/goto_attr_in_schema_def/goto_attr_in_schema_def.k @@ -0,0 +1,12 @@ +schema Name: + name1: str + name2: str + name3: str + +name1 = "1" + +name = Name{ + name1 = name1 # (5,0) (5,5) + name2 = name1 # (8,4) (8,9) + name3 = name2 # (9,4) (9,9) +} \ No newline at end of file