From 11be114305845bb0bc2674d8c1d8324e1011256a Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sun, 17 Aug 2025 20:12:19 -0400 Subject: Add hover information for soa fields and variables --- src/server/hover.odin | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/server/hover.odin') diff --git a/src/server/hover.odin b/src/server/hover.odin index 2c68ad0..44fde02 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -347,6 +347,15 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> return hover, true, true } } + case SymbolSliceValue: + if .Soa in selector.flags { + if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, field); ok { + symbol.pkg = selector.name + build_documentation(&ast_context, &symbol, false) + hover.contents = write_hover_content(&ast_context, symbol) + return hover, true, true + } + } } } else if position_context.implicit_selector_expr != nil { implicit_selector := position_context.implicit_selector_expr -- cgit v1.2.3 From ad58adbd01d1f0481feceb5381f53adba541d021 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sun, 17 Aug 2025 20:54:10 -0400 Subject: Correctly handle fixed array #soa --- src/server/analysis.odin | 27 +++++++++++++++++---------- src/server/completion.odin | 31 +++++++++++++++++++++++-------- src/server/hover.odin | 20 +++++++++++++++++++- tests/completions_test.odin | 19 +++++++++++++++++++ tests/hover_test.odin | 17 +++++++++++++++++ 5 files changed, 95 insertions(+), 19 deletions(-) (limited to 'src/server/hover.odin') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 19c4e0a..d1282bb 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -1301,17 +1301,24 @@ resolve_type_assertion_expr :: proc(ast_context: ^AstContext, v: ^ast.Type_Asser return symbol, ok } -resolve_soa_selector_field :: proc(ast_context: ^AstContext, expr: ^ast.Expr, name: string) -> (Symbol, bool) { +resolve_soa_selector_field :: proc(ast_context: ^AstContext, expr: ^ast.Expr, size: ^ast.Expr, name: string) -> (Symbol, bool) { if symbol, ok := resolve_type_expression(ast_context, expr); ok { if v, ok := symbol.value.(SymbolStructValue); ok { for n, i in v.names { if n == name { - value := SymbolMultiPointerValue { - expr = v.types[i], + if size != nil { + symbol.value = SymbolFixedArrayValue{ + expr = v.types[i], + len = size, + } + } else { + symbol.value = SymbolMultiPointerValue { + expr = v.types[i], + } } + symbol.name = name symbol.type = .Field - symbol.value = value symbol.range = v.ranges[i] return symbol, true } @@ -1333,7 +1340,7 @@ resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selecto #partial switch s in selector.value { case SymbolFixedArrayValue: if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, node.field.name) + return resolve_soa_selector_field(ast_context, s.expr, s.len, node.field.name) } components_count := 0 for c in node.field.name { @@ -1409,11 +1416,11 @@ resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selecto return selector, true case SymbolSliceValue: if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, node.field.name) + return resolve_soa_selector_field(ast_context, s.expr, nil, node.field.name) } case SymbolDynamicArrayValue: if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, node.field.name) + return resolve_soa_selector_field(ast_context, s.expr, nil, node.field.name) } } } @@ -2632,15 +2639,15 @@ resolve_symbol_selector :: proc( } case SymbolSliceValue: if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, field) + return resolve_soa_selector_field(ast_context, v.expr, nil, field) } case SymbolDynamicArrayValue: if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, field) + return resolve_soa_selector_field(ast_context, v.expr, nil, field) } case SymbolFixedArrayValue: if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, field) + return resolve_soa_selector_field(ast_context, v.expr, v.len, field) } } diff --git a/src/server/completion.odin b/src/server/completion.odin index ea55091..9f795cc 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -504,7 +504,13 @@ get_comp_lit_completion :: proc( return false } -add_soa_field_completion :: proc(ast_context: ^AstContext, expr: ^ast.Expr, results: ^[dynamic]CompletionResult, parent_name: string) { +add_soa_field_completion :: proc( + ast_context: ^AstContext, + expr: ^ast.Expr, + size: ^ast.Expr, + results: ^[dynamic]CompletionResult, + parent_name: string, +) { if symbol, ok := resolve_type_expression(ast_context, expr); ok { if v, ok := symbol.value.(SymbolStructValue); ok { for name, i in v.names { @@ -513,11 +519,20 @@ add_soa_field_completion :: proc(ast_context: ^AstContext, expr: ^ast.Expr, resu } resolved := Symbol { - name = name, - type = .Field, + name = name, + type = .Field, range = v.ranges[i], - pkg = parent_name, - value = SymbolMultiPointerValue{expr = v.types[i]}, + pkg = parent_name, + } + if size != nil { + resolved.value = SymbolFixedArrayValue{ + expr = v.types[i], + len = size, + } + } else { + resolved.value = SymbolMultiPointerValue { + expr = v.types[i], + } } build_documentation(ast_context, &resolved) append(results, CompletionResult{symbol = resolved}) @@ -677,7 +692,7 @@ get_selector_completion :: proc( } } if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, results, selector.name) + add_soa_field_completion(ast_context, v.expr, v.len, results, selector.name) } case SymbolUnionValue: is_incomplete = false @@ -867,13 +882,13 @@ get_selector_completion :: proc( is_incomplete = false append_magic_array_like_completion(position_context, selector, results) if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, results, selector.name) + add_soa_field_completion(ast_context, v.expr, nil, results, selector.name) } case SymbolSliceValue: is_incomplete = false append_magic_array_like_completion(position_context, selector, results) if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, results, selector.name) + add_soa_field_completion(ast_context, v.expr, nil, results, selector.name) } case SymbolMapValue: is_incomplete = false diff --git a/src/server/hover.odin b/src/server/hover.odin index 44fde02..a36dc54 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -349,7 +349,25 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } case SymbolSliceValue: if .Soa in selector.flags { - if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, field); ok { + if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, nil, field); ok { + symbol.pkg = selector.name + build_documentation(&ast_context, &symbol, false) + hover.contents = write_hover_content(&ast_context, symbol) + return hover, true, true + } + } + case SymbolDynamicArrayValue: + if .Soa in selector.flags { + if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, nil, field); ok { + symbol.pkg = selector.name + build_documentation(&ast_context, &symbol, false) + hover.contents = write_hover_content(&ast_context, symbol) + return hover, true, true + } + } + case SymbolFixedArrayValue: + if .Soa in selector.flags { + if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, v.len, field); ok { symbol.pkg = selector.name build_documentation(&ast_context, &symbol, false) hover.contents = write_hover_content(&ast_context, symbol) diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 3c57a87..6a5e1a7 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -4434,3 +4434,22 @@ ast_completion_soa_slice_fields :: proc(t: ^testing.T) { test.expect_completion_docs(t, &source, "", {"foos.x: [^]int", "foos.y: [^]string"}) } + +@(test) +ast_completion_soa_fixed_array_fields :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x: int, + y: string, + } + + main :: proc() { + foos: #soa[3]Foo + foos.{*} + } + `, + } + + test.expect_completion_docs(t, &source, "", {"foos.x: [3]int", "foos.y: [3]string"}) +} diff --git a/tests/hover_test.odin b/tests/hover_test.odin index b48c98f..53414e5 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -4196,6 +4196,23 @@ ast_hover_identifier_soa_slice_field :: proc(t: ^testing.T) { } test.expect_hover(t, &source, "test.x: [^]int") } + +@(test) +ast_hover_soa_fixed_array_field :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x, y: int, + } + + main :: proc() { + foos: #soa[6]Foo + foos.x{*} + } + `, + } + test.expect_hover(t, &source, "foos.x: [6]int") +} /* Waiting for odin fix -- cgit v1.2.3 From cad56817a9b39819fc5a4f05bdc01dd0c5f50f13 Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:28:38 -0400 Subject: Add support for soa pointers --- src/server/analysis.odin | 55 +++++++++++++++++++++++-------------- src/server/ast.odin | 10 +++++++ src/server/completion.odin | 31 ++++++++++++--------- src/server/documentation.odin | 9 ++++++ src/server/hover.odin | 64 +++++++++++++++++++++++++------------------ src/server/symbol.odin | 1 + tests/completions_test.odin | 19 +++++++++++++ tests/hover_test.odin | 33 ++++++++++++++++++++++ tests/references_test.odin | 22 +++++++++++++++ 9 files changed, 184 insertions(+), 60 deletions(-) (limited to 'src/server/hover.odin') diff --git a/src/server/analysis.odin b/src/server/analysis.odin index d1282bb..e2ce2a6 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -1145,6 +1145,9 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex case ^Pointer_Type: ok := internal_resolve_type_expression(ast_context, v.elem, out) out.pointers += 1 + if pointer_is_soa(v^) { + out.flags += {.SoaPointer} + } return ok case ^Matrix_Index_Expr: if ok := internal_resolve_type_expression(ast_context, v.expr, out); ok { @@ -1301,15 +1304,35 @@ resolve_type_assertion_expr :: proc(ast_context: ^AstContext, v: ^ast.Type_Asser return symbol, ok } -resolve_soa_selector_field :: proc(ast_context: ^AstContext, expr: ^ast.Expr, size: ^ast.Expr, name: string) -> (Symbol, bool) { +resolve_soa_selector_field :: proc( + ast_context: ^AstContext, + selector: Symbol, + expr: ^ast.Expr, + size: ^ast.Expr, + name: string, +) -> ( + Symbol, + bool, +) { + if .Soa not_in selector.flags && .SoaPointer not_in selector.flags { + return {}, false + } + if symbol, ok := resolve_type_expression(ast_context, expr); ok { if v, ok := symbol.value.(SymbolStructValue); ok { for n, i in v.names { if n == name { - if size != nil { - symbol.value = SymbolFixedArrayValue{ + if .SoaPointer in selector.flags { + if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok { + symbol.value = resolved.value + symbol.pkg = symbol.name + } else { + return {}, false + } + } else if size != nil { + symbol.value = SymbolFixedArrayValue { expr = v.types[i], - len = size, + len = size, } } else { symbol.value = SymbolMultiPointerValue { @@ -1339,8 +1362,8 @@ resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selecto symbol := Symbol{} #partial switch s in selector.value { case SymbolFixedArrayValue: - if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, s.len, node.field.name) + if symbol, ok := resolve_soa_selector_field(ast_context, selector, s.expr, s.len, node.field.name); ok { + return symbol, ok } components_count := 0 for c in node.field.name { @@ -1415,13 +1438,9 @@ resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selecto selector.type = .EnumMember return selector, true case SymbolSliceValue: - if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, nil, node.field.name) - } + return resolve_soa_selector_field(ast_context, selector, s.expr, nil, node.field.name) case SymbolDynamicArrayValue: - if .Soa in selector.flags { - return resolve_soa_selector_field(ast_context, s.expr, nil, node.field.name) - } + return resolve_soa_selector_field(ast_context, selector, s.expr, nil, node.field.name) } } @@ -2638,17 +2657,11 @@ resolve_symbol_selector :: proc( return resolve_symbol_selector(ast_context, selector, s) } case SymbolSliceValue: - if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, nil, field) - } + return resolve_soa_selector_field(ast_context, symbol, v.expr, nil, field) case SymbolDynamicArrayValue: - if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, nil, field) - } + return resolve_soa_selector_field(ast_context, symbol, v.expr, nil, field) case SymbolFixedArrayValue: - if .Soa in symbol.flags { - return resolve_soa_selector_field(ast_context, v.expr, v.len, field) - } + return resolve_soa_selector_field(ast_context, symbol, v.expr, v.len, field) } return symbol, true diff --git a/src/server/ast.odin b/src/server/ast.odin index f7f3083..36f6a88 100644 --- a/src/server/ast.odin +++ b/src/server/ast.odin @@ -243,6 +243,15 @@ unwrap_pointer_expr :: proc(expr: ^ast.Expr) -> (^ast.Expr, int, bool) { return expr, n, true } +pointer_is_soa :: proc(pointer: ast.Pointer_Type) -> bool { + if pointer.tag != nil { + if basic, ok := pointer.tag.derived.(^ast.Basic_Directive); ok && basic.name == "soa" { + return true + } + } + return false +} + array_is_soa :: proc(array: ast.Array_Type) -> bool { if array.tag != nil { if basic, ok := array.tag.derived.(^ast.Basic_Directive); ok && basic.name == "soa" { @@ -1216,6 +1225,7 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_poi build_string(n.results, builder, remove_pointers) } case ^Pointer_Type: + build_string(n.tag, builder, remove_pointers) if !remove_pointers { strings.write_string(builder, "^") } diff --git a/src/server/completion.odin b/src/server/completion.odin index 9f795cc..c8f43f7 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -506,11 +506,15 @@ get_comp_lit_completion :: proc( add_soa_field_completion :: proc( ast_context: ^AstContext, + selector: Symbol, expr: ^ast.Expr, size: ^ast.Expr, results: ^[dynamic]CompletionResult, parent_name: string, ) { + if .Soa not_in selector.flags && .SoaPointer not_in selector.flags { + return + } if symbol, ok := resolve_type_expression(ast_context, expr); ok { if v, ok := symbol.value.(SymbolStructValue); ok { for name, i in v.names { @@ -519,21 +523,28 @@ add_soa_field_completion :: proc( } resolved := Symbol { - name = name, type = .Field, range = v.ranges[i], pkg = parent_name, } - if size != nil { - resolved.value = SymbolFixedArrayValue{ + if .SoaPointer in selector.flags { + if s, ok := resolve_type_expression(ast_context, v.types[i]); ok { + resolved.value = s.value + resolved.pkg = symbol.name + } else { + continue + } + } else if size != nil { + resolved.value = SymbolFixedArrayValue { expr = v.types[i], - len = size, + len = size, } } else { resolved.value = SymbolMultiPointerValue { expr = v.types[i], } } + resolved.name = name build_documentation(ast_context, &resolved) append(results, CompletionResult{symbol = resolved}) } @@ -691,9 +702,7 @@ get_selector_completion :: proc( append(results, CompletionResult{completion_item = item}) } } - if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, v.len, results, selector.name) - } + add_soa_field_completion(ast_context, selector, v.expr, v.len, results, selector.name) case SymbolUnionValue: is_incomplete = false @@ -881,15 +890,11 @@ get_selector_completion :: proc( case SymbolDynamicArrayValue: is_incomplete = false append_magic_array_like_completion(position_context, selector, results) - if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, nil, results, selector.name) - } + add_soa_field_completion(ast_context, selector, v.expr, nil, results, selector.name) case SymbolSliceValue: is_incomplete = false append_magic_array_like_completion(position_context, selector, results) - if .Soa in selector.flags { - add_soa_field_completion(ast_context, v.expr, nil, results, selector.name) - } + add_soa_field_completion(ast_context, selector, v.expr, nil, results, selector.name) case SymbolMapValue: is_incomplete = false append_magic_map_completion(position_context, selector, results) diff --git a/src/server/documentation.odin b/src/server/documentation.odin index 84d8c2e..dc0784d 100644 --- a/src/server/documentation.odin +++ b/src/server/documentation.odin @@ -372,6 +372,9 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy write_node(sb, ast_context, v.expr, "", short_signature = true) return case SymbolDynamicArrayValue: + if .SoaPointer in symbol.flags { + strings.write_string(sb, "#soa") + } strings.write_string(sb, pointer_prefix) if .Soa in symbol.flags { strings.write_string(sb, "#soa") @@ -380,6 +383,9 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy write_node(sb, ast_context, v.expr, "", short_signature = true) return case SymbolSliceValue: + if .SoaPointer in symbol.flags { + strings.write_string(sb, "#soa") + } strings.write_string(sb, pointer_prefix) if .Soa in symbol.flags { strings.write_string(sb, "#soa") @@ -388,6 +394,9 @@ write_short_signature :: proc(sb: ^strings.Builder, ast_context: ^AstContext, sy write_node(sb, ast_context, v.expr, "", short_signature = true) return case SymbolFixedArrayValue: + if .SoaPointer in symbol.flags { + strings.write_string(sb, "#soa") + } strings.write_string(sb, pointer_prefix) if .Soa in symbol.flags { strings.write_string(sb, "#soa") diff --git a/src/server/hover.odin b/src/server/hover.odin index a36dc54..03cdedf 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -153,7 +153,12 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> position_context.value_decl.names[0], ); ok { if value, ok := struct_symbol.value.(SymbolStructValue); ok { - construct_struct_field_symbol(&symbol, struct_symbol.name, value, field_index+name_index) + construct_struct_field_symbol( + &symbol, + struct_symbol.name, + value, + field_index + name_index, + ) build_documentation(&ast_context, &symbol, true) hover.contents = write_hover_content(&ast_context, symbol) return hover, true, true @@ -188,7 +193,8 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } } - if position_context.field_value != nil && position_in_node(position_context.field_value.field, position_context.position) { + if position_context.field_value != nil && + position_in_node(position_context.field_value.field, position_context.position) { if position_context.comp_lit != nil { if comp_symbol, ok := resolve_comp_literal(&ast_context, &position_context); ok { if field, ok := position_context.field_value.field.derived.(^ast.Ident); ok { @@ -348,32 +354,11 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> } } case SymbolSliceValue: - if .Soa in selector.flags { - if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, nil, field); ok { - symbol.pkg = selector.name - build_documentation(&ast_context, &symbol, false) - hover.contents = write_hover_content(&ast_context, symbol) - return hover, true, true - } - } + return get_soa_hover(&ast_context, selector, v.expr, nil, field) case SymbolDynamicArrayValue: - if .Soa in selector.flags { - if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, nil, field); ok { - symbol.pkg = selector.name - build_documentation(&ast_context, &symbol, false) - hover.contents = write_hover_content(&ast_context, symbol) - return hover, true, true - } - } + return get_soa_hover(&ast_context, selector, v.expr, nil, field) case SymbolFixedArrayValue: - if .Soa in selector.flags { - if symbol, ok := resolve_soa_selector_field(&ast_context, v.expr, v.len, field); ok { - symbol.pkg = selector.name - build_documentation(&ast_context, &symbol, false) - hover.contents = write_hover_content(&ast_context, symbol) - return hover, true, true - } - } + return get_soa_hover(&ast_context, selector, v.expr, v.len, field) } } else if position_context.implicit_selector_expr != nil { implicit_selector := position_context.implicit_selector_expr @@ -452,3 +437,30 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> return hover, false, true } + +@(private = "file") +get_soa_hover :: proc( + ast_context: ^AstContext, + selector: Symbol, + expr: ^ast.Expr, + size: ^ast.Expr, + field: string, +) -> ( + Hover, + bool, + bool, +) { + if .SoaPointer not_in selector.flags && .Soa not_in selector.flags { + return {}, false, true + } + if symbol, ok := resolve_soa_selector_field(ast_context, selector, expr, size, field); ok { + if selector.name != "" { + symbol.pkg = selector.name + } + build_documentation(ast_context, &symbol, false) + hover: Hover + hover.contents = write_hover_content(ast_context, symbol) + return hover, true, true + } + return {}, false, true +} diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 2e2f26b..d163e45 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -197,6 +197,7 @@ SymbolFlag :: enum { ObjC, ObjCIsClassMethod, // should be set true only when ObjC is enabled Soa, + SoaPointer, Parameter, //If the symbol is a procedure argument } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 6a5e1a7..9fcc797 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -4453,3 +4453,22 @@ ast_completion_soa_fixed_array_fields :: proc(t: ^testing.T) { test.expect_completion_docs(t, &source, "", {"foos.x: [3]int", "foos.y: [3]string"}) } + +@(test) +ast_completion_soa_pointer :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x: int, + y: string, + } + + main :: proc() { + foos: #soa^#soa[3]Foo + foos.{*} + } + `, + } + + test.expect_completion_docs(t, &source, "", {"Foo.x: int", "Foo.y: string"}) +} diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 53414e5..7301a7e 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -4213,6 +4213,39 @@ ast_hover_soa_fixed_array_field :: proc(t: ^testing.T) { } test.expect_hover(t, &source, "foos.x: [6]int") } + +@(test) +ast_hover_soa_pointer :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x, y: int, + } + + main :: proc() { + f{*}oo: #soa^#soa[6]Foo + } + `, + } + test.expect_hover(t, &source, "test.foo: #soa^#soa[6]Foo") +} + +@(test) +ast_hover_soa_pointer_field :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x, y: int, + } + + main :: proc() { + foo: #soa^#soa[6]Foo + foo.x{*} + } + `, + } + test.expect_hover(t, &source, "Foo.x: int") +} /* Waiting for odin fix diff --git a/tests/references_test.odin b/tests/references_test.odin index aa3c6b5..3510283 100644 --- a/tests/references_test.odin +++ b/tests/references_test.odin @@ -1170,3 +1170,25 @@ ast_references_soa_field :: proc(t: ^testing.T) { test.expect_reference_locations(t, &source, locations[:]) } + +@(test) +ast_references_soa_pointer_field :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Foo :: struct { + x, y: int, + } + + main :: proc() { + foos: #soa^#soa[]Foo + x := foos.x{*} + } + `, + } + locations := []common.Location { + {range = {start = {line = 2, character = 3}, end = {line = 2, character = 4}}}, + {range = {start = {line = 7, character = 13}, end = {line = 7, character = 14}}}, + } + + test.expect_reference_locations(t, &source, locations[:]) +} -- cgit v1.2.3