aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-06-13 12:37:13 -0400
committerBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-06-13 12:37:49 -0400
commit0b468f033a3a2244a50868e4dccc2604ab4ab7ee (patch)
treef7803aff6a19a116050fb3825290d9933a1835b1
parent44b5d023e42b27a2ff72f9d572a43f11df39c01b (diff)
Fix issue with field completions in multi-pointer structs and rename `SymbolMultiPointer`
-rw-r--r--src/server/analysis.odin10
-rw-r--r--src/server/collector.odin4
-rw-r--r--src/server/completion.odin62
-rw-r--r--src/server/semantic_tokens.odin2
-rw-r--r--src/server/symbol.odin7
-rw-r--r--tests/completions_test.odin58
6 files changed, 112 insertions, 31 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 593edc9..1a7e4a7 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -449,8 +449,8 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast.
}
return is_symbol_same_typed(ast_context, a_symbol, b_symbol)
- case SymbolMultiPointer:
- b_value := b.value.(SymbolMultiPointer)
+ case SymbolMultiPointerValue:
+ b_value := b.value.(SymbolMultiPointerValue)
a_symbol: Symbol
b_symbol: Symbol
@@ -963,7 +963,7 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex
symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
case SymbolMapValue:
symbol, ok = internal_resolve_type_expression(ast_context, v2.value)
- case SymbolMultiPointer:
+ case SymbolMultiPointerValue:
symbol, ok = internal_resolve_type_expression(ast_context, v2.expr)
}
@@ -2481,7 +2481,7 @@ make_symbol_multi_pointer_from_ast :: proc(
name = name.name,
}
- symbol.value = SymbolMultiPointer {
+ symbol.value = SymbolMultiPointerValue {
expr = v.elem,
}
@@ -3950,7 +3950,7 @@ get_signature :: proc(
} else {
return "bit_field"
}
- case SymbolMultiPointer:
+ case SymbolMultiPointerValue:
return strings.concatenate(
a = {pointer_prefix, "[^]", common.node_to_string(v.expr)},
allocator = ast_context.allocator,
diff --git a/src/server/collector.odin b/src/server/collector.odin
index c757e74..037f43a 100644
--- a/src/server/collector.odin
+++ b/src/server/collector.odin
@@ -320,12 +320,12 @@ collect_multi_pointer :: proc(
collection: ^SymbolCollection,
array: ast.Multi_Pointer_Type,
package_map: map[string]string,
-) -> SymbolMultiPointer {
+) -> SymbolMultiPointerValue {
elem := clone_type(array.elem, collection.allocator, &collection.unique_strings)
replace_package_alias(elem, package_map, collection)
- return SymbolMultiPointer{expr = elem}
+ return SymbolMultiPointerValue{expr = elem}
}
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 30e7ac6..5136518 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -140,6 +140,7 @@ get_completion_list :: proc(
}
}
+
switch completion_type {
case .Comp_Lit:
get_comp_lit_completion(&ast_context, &position_context, &list)
@@ -266,6 +267,8 @@ get_comp_lit_completion :: proc(
if symbol, ok := resolve_comp_literal(ast_context, position_context); ok {
#partial switch v in symbol.value {
case SymbolStructValue:
+ get_struct_field_completion(ast_context, position_context, &items, symbol)
+ case SymbolBitFieldValue:
for name, i in v.names {
if name == "_" {
continue
@@ -288,33 +291,54 @@ get_comp_lit_completion :: proc(
append(&items, item)
}
}
- case SymbolBitFieldValue:
- for name, i in v.names {
- if name == "_" {
- continue
+ case SymbolMultiPointerValue:
+ if resolved, ok := resolve_type_expression(ast_context, v.expr); ok {
+ if value, ok := resolved.value.(SymbolStructValue); ok {
+ get_struct_field_completion(ast_context, position_context, &items, resolved)
}
+ }
+ }
+ }
- set_ast_package_set_scoped(ast_context, symbol.pkg)
+ list.items = items[:]
+}
- if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok {
- if field_exists_in_comp_lit(position_context.comp_lit, name) {
- continue
- }
+get_struct_field_completion :: proc(
+ ast_context: ^AstContext,
+ position_context: ^DocumentPositionContext,
+ items: ^[dynamic]CompletionItem,
+ symbol: Symbol,
+) {
+ v := symbol.value.(SymbolStructValue)
+ for name, i in v.names {
+ if name == "_" {
+ continue
+ }
- item := CompletionItem {
- label = name,
- kind = .Field,
- detail = fmt.tprintf("%v.%v: %v", symbol.name, name, common.node_to_string(v.types[i])),
- documentation = resolved.doc,
- }
+ set_ast_package_set_scoped(ast_context, symbol.pkg)
- append(&items, item)
+ if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok {
+ if field_exists_in_comp_lit(position_context.comp_lit, name) {
+ continue
+ }
+
+ if value, ok := resolved.value.(SymbolStructValue); ok {
+ get_struct_field_completion(ast_context, position_context, items, resolved)
+ continue
+ } else {
+ item := CompletionItem {
+ label = name,
+ kind = .Field,
+ detail = fmt.tprintf("%v.%v: %v", symbol.name, name, common.node_to_string(v.types[i])),
+ documentation = resolved.doc,
}
+
+ append(items, item)
}
+
}
}
- list.items = items[:]
}
get_selector_completion :: proc(
@@ -1290,7 +1314,7 @@ get_identifier_completion :: proc(
ident.name = k
if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.signature = get_signature(ast_context, symbol, short_signature=true)
+ symbol.signature = get_signature(ast_context, symbol, short_signature = true)
build_procedure_symbol_signature(&symbol)
@@ -1331,7 +1355,7 @@ get_identifier_completion :: proc(
ident.name = k
if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
- symbol.signature = get_signature(ast_context, symbol, short_signature=true)
+ symbol.signature = get_signature(ast_context, symbol, short_signature = true)
build_procedure_symbol_signature(&symbol)
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index 457bcfb..da3a2ce 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -572,7 +572,7 @@ visit_ident :: proc(
SymbolFixedArrayValue,
SymbolSliceValue,
SymbolMapValue,
- SymbolMultiPointer,
+ SymbolMultiPointerValue,
SymbolBasicValue:
write_semantic_node(builder, ident, .Type, modifiers)
case SymbolUntypedValue:
diff --git a/src/server/symbol.odin b/src/server/symbol.odin
index 7286028..fd12a87 100644
--- a/src/server/symbol.odin
+++ b/src/server/symbol.odin
@@ -68,8 +68,7 @@ SymbolDynamicArrayValue :: struct {
expr: ^ast.Expr,
}
-// TODO rename to SymbolMultiPointerValue
-SymbolMultiPointer :: struct {
+SymbolMultiPointerValue :: struct {
expr: ^ast.Expr,
}
@@ -130,7 +129,7 @@ SymbolValue :: union {
SymbolAggregateValue,
SymbolDynamicArrayValue,
SymbolFixedArrayValue,
- SymbolMultiPointer,
+ SymbolMultiPointerValue,
SymbolMapValue,
SymbolSliceValue,
SymbolBasicValue,
@@ -211,7 +210,7 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) {
common.free_ast(v.expr, allocator)
common.free_ast(v.x, allocator)
common.free_ast(v.y, allocator)
- case SymbolMultiPointer:
+ case SymbolMultiPointerValue:
common.free_ast(v.expr, allocator)
case SymbolProcedureValue:
common.free_ast(v.return_types, allocator)
diff --git a/tests/completions_test.odin b/tests/completions_test.odin
index 5e8c5d8..ee4b1e3 100644
--- a/tests/completions_test.odin
+++ b/tests/completions_test.odin
@@ -3207,3 +3207,61 @@ ast_completion_on_string_iterator :: proc(t: ^testing.T) {
test.expect_completion_details(t, &source, "", {"test.linze: string"})
}
+
+@(test)
+ast_completion_multi_pointer :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package main
+
+ S1 :: struct {
+ s2_ptr: [^]S2,
+ }
+
+ S2 :: struct {
+ field: int,
+ }
+
+ main :: proc() {
+ x := S1 {
+ s2_ptr = &S2 {
+ {*}
+ }
+ }
+ }
+ `,
+ }
+
+ test.expect_completion_details(t, &source, "", {"S2.field: int"})
+}
+
+@(test)
+ast_completion_multi_pointer_nested :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package main
+
+ S1 :: struct {
+ s2_ptr: [^]S2,
+ }
+
+ S2 :: struct {
+ field: S3,
+ }
+
+ S3 :: struct {
+ s3: int,
+ }
+
+ main :: proc() {
+ x := S1 {
+ s2_ptr = &S2 {
+ field = S3 {
+ {*}
+ }
+ }
+ }
+ }
+ `,
+ }
+
+ test.expect_completion_details(t, &source, "", {"S3.s3: int"})
+}