From 8872d73933e70193a6aee866199ac2506b93c43c Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sun, 6 Jul 2025 12:00:42 -0400 Subject: Ensure uris are attached to every symbol for improved reference resolution --- src/server/analysis.odin | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/server/analysis.odin') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 7914d2f..f6f6cb0 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -760,6 +760,7 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou type = candidates[0].type, name = candidates[0].name, pkg = candidates[0].pkg, + uri = candidates[0].uri, value = SymbolAggregateValue{symbols = candidates[:]}, }, true @@ -1352,6 +1353,7 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide name = ident.name, pkg = ast_context.current_package, value = SymbolBasicValue{ident = ident}, + uri = common.create_uri(ident.pos.file, ast_context.allocator).uri, }, true } @@ -2549,6 +2551,7 @@ make_symbol_procedure_from_ast :: proc( type = .Function if !type else .Type_Function, pkg = get_package_from_node(n^), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } return_types := make([dynamic]^ast.Field, ast_context.allocator) @@ -2597,6 +2600,7 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, type = .Type, pkg = get_package_from_node(v.node), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } if v.len != nil { @@ -2627,6 +2631,7 @@ make_symbol_dynamic_array_from_ast :: proc( type = .Type, pkg = get_package_from_node(v.node), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } symbol.value = SymbolDynamicArrayValue { @@ -2648,6 +2653,7 @@ make_symbol_matrix_from_ast :: proc(ast_context: ^AstContext, v: ast.Matrix_Type type = .Type, pkg = get_package_from_node(v.node), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } symbol.value = SymbolMatrixValue { @@ -2670,6 +2676,7 @@ make_symbol_multi_pointer_from_ast :: proc( type = .Type, pkg = get_package_from_node(v.node), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } symbol.value = SymbolMultiPointerValue { @@ -2685,6 +2692,7 @@ make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type, name type = .Type, pkg = get_package_from_node(v.node), name = name.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } symbol.value = SymbolMapValue { @@ -2720,6 +2728,7 @@ make_symbol_union_from_ast :: proc( type = .Union, pkg = get_package_from_node(v.node), name = ident.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } if inlined { @@ -2759,6 +2768,7 @@ make_symbol_enum_from_ast :: proc( type = .Enum, name = ident.name, pkg = get_package_from_node(v.node), + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } if inlined { @@ -2813,6 +2823,7 @@ make_symbol_bitset_from_ast :: proc( type = .Enum, name = ident.name, pkg = get_package_from_node(v.node), + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } if inlined { @@ -2840,6 +2851,8 @@ make_symbol_struct_from_ast :: proc( type = .Struct, pkg = get_package_from_node(v.node), name = ident.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri + } if inlined { @@ -2865,6 +2878,7 @@ make_symbol_bit_field_from_ast :: proc( type = .Struct, pkg = get_package_from_node(v.node), name = ident.name, + uri = common.create_uri(v.pos.file, ast_context.allocator).uri } if inlined { -- cgit v1.2.3 From 0a64647eafc7870a151f7a03a3b32a40b42fb819 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sun, 6 Jul 2025 14:44:24 -0400 Subject: Correctly resolve struct fields that are immediately accessed from a proc return --- src/server/analysis.odin | 76 +++++++++++++++++++++++++------------------- src/server/file_resolve.odin | 2 +- tests/definition_test.odin | 26 +++++++++++++++ tests/references_test.odin | 56 ++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 34 deletions(-) (limited to 'src/server/analysis.odin') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index f6f6cb0..4b66717 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -2253,50 +2253,60 @@ resolve_location_selector :: proc(ast_context: ^AstContext, selector_expr: ^ast. set_ast_package_set_scoped(ast_context, ast_context.document_package) if selector, ok := selector_expr.derived.(^ast.Selector_Expr); ok { - symbol = resolve_type_expression(ast_context, selector.expr) or_return + return resolve_symbol_selector(ast_context, selector, symbol) + } - field: string + return {}, false +} - if selector.field != nil { - #partial switch v in selector.field.derived { - case ^ast.Ident: - field = v.name - } +resolve_symbol_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selector_Expr, symbol: Symbol) ->(Symbol, bool) { + field: string + symbol := symbol + + if selector.field != nil { + #partial switch v in selector.field.derived { + case ^ast.Ident: + field = v.name } + } - #partial switch v in symbol.value { - case SymbolEnumValue: - for name, i in v.names { - if strings.compare(name, field) == 0 { - symbol.range = v.ranges[i] - } - } - case SymbolStructValue: - for name, i in v.names { - if strings.compare(name, field) == 0 { - symbol.range = v.ranges[i] - } + #partial switch v in symbol.value { + case SymbolEnumValue: + for name, i in v.names { + if strings.compare(name, field) == 0 { + symbol.range = v.ranges[i] } - case SymbolBitFieldValue: - for name, i in v.names { - if strings.compare(name, field) == 0 { - symbol.range = v.ranges[i] - } + } + case SymbolStructValue: + for name, i in v.names { + if strings.compare(name, field) == 0 { + symbol.range = v.ranges[i] } - case SymbolPackageValue: - if pkg, ok := lookup(field, symbol.pkg); ok { - symbol.range = pkg.range - symbol.uri = pkg.uri - } else { - return {}, false + } + case SymbolBitFieldValue: + for name, i in v.names { + if strings.compare(name, field) == 0 { + symbol.range = v.ranges[i] } } - - return symbol, true + case SymbolPackageValue: + if pkg, ok := lookup(field, symbol.pkg); ok { + symbol.range = pkg.range + symbol.uri = pkg.uri + } else { + return {}, false + } + case SymbolProcedureValue: + if len(v.return_types) != 1 { + return {}, false + } + if s, ok := resolve_type_expression(ast_context, v.return_types[0].type); ok { + return resolve_symbol_selector(ast_context, selector, s) + } } - return {}, false + return symbol, true } diff --git a/src/server/file_resolve.odin b/src/server/file_resolve.odin index 86ef1f5..f6096c5 100644 --- a/src/server/file_resolve.odin +++ b/src/server/file_resolve.odin @@ -202,7 +202,7 @@ resolve_node :: proc(node: ^ast.Node, data: ^FileResolveData) { #partial switch v in n.expr.derived { // TODO: Should there be more here? - case ^ast.Selector_Expr, ^ast.Index_Expr, ^ast.Ident, ^ast.Paren_Expr: + case ^ast.Selector_Expr, ^ast.Index_Expr, ^ast.Ident, ^ast.Paren_Expr, ^ast.Call_Expr: resolve_node(n.expr, data) } } else { diff --git a/tests/definition_test.odin b/tests/definition_test.odin index 6a61449..a40e44a 100644 --- a/tests/definition_test.odin +++ b/tests/definition_test.odin @@ -517,3 +517,29 @@ ast_goto_enum_from_map_key :: proc(t: ^testing.T) { test.expect_definition_locations(t, &source, {location}) } + +@(test) +ast_goto_struct_field_from_proc :: proc (t: ^testing.T) { + source := test.Source { + main = `package test + + Bar :: struct { + bar: int, + } + + foo :: proc() -> Bar { + return Bar{} + } + + main :: proc() { + bar := foo().b{*}ar + } + `, + } + + locations := []common.Location { + {range = {start = {line = 3, character = 3}, end = {line = 3, character = 6}}}, + } + + test.expect_definition_locations(t, &source, locations[:]) +} diff --git a/tests/references_test.odin b/tests/references_test.odin index da6ac4e..7009717 100644 --- a/tests/references_test.odin +++ b/tests/references_test.odin @@ -650,3 +650,59 @@ ast_reference_enum_bitset :: proc (t: ^testing.T) { test.expect_reference_locations(t, &source, locations[:]) } + +@(test) +ast_reference_struct_field_from_proc :: proc (t: ^testing.T) { + source := test.Source { + main = `package test + + Bar :: struct { + bar: int, + } + + foo :: proc() -> Bar { + return Bar{} + } + + main :: proc() { + bar := foo().b{*}ar + } + `, + } + + locations := []common.Location { + {range = {start = {line = 3, character = 3}, end = {line = 3, character = 6}}}, + {range = {start = {line = 11, character = 16}, end = {line = 11, character = 19}}}, + } + + test.expect_reference_locations(t, &source, locations[:]) +} + +@(test) +ast_reference_proc_with_immediate_return_field_access :: proc (t: ^testing.T) { + source := test.Source { + main = `package test + + Bar :: struct { + bar: int, + } + + foo :: proc() -> Bar { + return Bar{} + } + + main :: proc() { + bar := f{*}oo().bar + bar2 := foo().bar + } + `, + } + + locations := []common.Location { + {range = {start = {line = 6, character = 2}, end = {line = 6, character = 5}}}, + {range = {start = {line = 11, character = 10}, end = {line = 11, character = 13}}}, + {range = {start = {line = 12, character = 11}, end = {line = 12, character = 14}}}, + } + + test.expect_reference_locations(t, &source, locations[:]) +} -- cgit v1.2.3