aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBradley Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-11 22:03:52 -0400
committerGitHub <noreply@github.com>2025-09-11 22:03:52 -0400
commitaa2e8f609ad3a48f1bf7570a7f34c01f89d53c5d (patch)
tree2dab8c6a774f0be610048b145081f08f9f6f2282
parent7b5eac698391e9d0b2d6fdac4ce4a857f92c33f2 (diff)
parent4cb9acda12fa0bb0a0b6fd6d46c163adc0544a4a (diff)
Merge pull request #998 from BradLewis/feat/nesting-structs-bitfield-improvements
Feat/nesting structs bitfield improvements
-rw-r--r--src/server/analysis.odin2
-rw-r--r--src/server/file_resolve.odin9
-rw-r--r--src/server/hover.odin56
-rw-r--r--src/server/references.odin93
-rw-r--r--src/server/symbol.odin9
-rw-r--r--tests/definition_test.odin48
-rw-r--r--tests/hover_test.odin30
-rw-r--r--tests/references_test.odin75
8 files changed, 262 insertions, 60 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 4f70fbd..7538fe1 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -3432,7 +3432,7 @@ make_symbol_struct_from_ast :: proc(
}
b := symbol_struct_value_builder_make(symbol, ast_context.allocator)
- write_struct_type(ast_context, &b, v, attributes, -1, inlined)
+ write_struct_type(ast_context, &b, v, attributes, -1)
symbol = to_symbol(b)
return symbol
}
diff --git a/src/server/file_resolve.odin b/src/server/file_resolve.odin
index d4db280..53fda8f 100644
--- a/src/server/file_resolve.odin
+++ b/src/server/file_resolve.odin
@@ -561,6 +561,15 @@ resolve_node :: proc(node: ^ast.Node, data: ^FileResolveData) {
resolve_node(n.name, data)
resolve_node(n.type, data)
resolve_node(n.bit_size, data)
+ if data.flag != .None {
+ data.symbols[cast(uintptr)n.name] = SymbolAndNode {
+ node = n.name,
+ symbol = Symbol{
+ range = common.get_token_range(n.name, string(data.document.text)),
+ uri = strings.clone(common.create_uri(n.pos.file, data.ast_context.allocator).uri, data.ast_context.allocator),
+ },
+ }
+ }
case:
}
diff --git a/src/server/hover.odin b/src/server/hover.odin
index 960a3a2..ef4c046 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -62,9 +62,9 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
return {}, false, true
}
- if position_context.type_cast != nil && // check that we're actually on the 'cast' word
+ if position_context.type_cast != nil &&
!position_in_node(position_context.type_cast.type, position_context.position) &&
- !position_in_node(position_context.type_cast.expr, position_context.position) {
+ !position_in_node(position_context.type_cast.expr, position_context.position) { // check that we're actually on the 'cast' word
if str, ok := keywords_docs[position_context.type_cast.tok.text]; ok {
hover.contents.kind = "markdown"
hover.contents.value = str
@@ -134,18 +134,24 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if symbol, ok := resolve_type_expression(&ast_context, field.type); ok {
if struct_symbol, ok := resolve_type_expression(
&ast_context,
- position_context.value_decl.names[0],
+ &position_context.struct_type.node,
); ok {
- if value, ok := struct_symbol.value.(SymbolStructValue); ok {
- 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
+ if value_decl_symbol, ok := resolve_type_expression(
+ &ast_context,
+ position_context.value_decl.names[0],
+ ); ok {
+ name := get_field_parent_name(value_decl_symbol, struct_symbol)
+ if value, ok := struct_symbol.value.(SymbolStructValue); ok {
+ construct_struct_field_symbol(
+ &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
+ }
}
}
}
@@ -162,12 +168,18 @@ get_hover_information :: proc(document: ^Document, position: common.Position) ->
if symbol, ok := resolve_type_expression(&ast_context, field.type); ok {
if bit_field_symbol, ok := resolve_type_expression(
&ast_context,
- position_context.value_decl.names[0],
+ &position_context.bit_field_type.node,
); ok {
- if value, ok := bit_field_symbol.value.(SymbolBitFieldValue); ok {
- construct_bit_field_field_symbol(&symbol, bit_field_symbol.name, value, i)
- hover.contents = write_hover_content(&ast_context, symbol)
- return hover, true, true
+ if value_decl_symbol, ok := resolve_type_expression(
+ &ast_context,
+ position_context.value_decl.names[0],
+ ); ok {
+ name := get_field_parent_name(value_decl_symbol, bit_field_symbol)
+ if value, ok := bit_field_symbol.value.(SymbolBitFieldValue); ok {
+ construct_bit_field_field_symbol(&symbol, name, value, i)
+ hover.contents = write_hover_content(&ast_context, symbol)
+ return hover, true, true
+ }
}
}
}
@@ -457,3 +469,11 @@ get_soa_field_hover :: proc(
}
return {}, false, true
}
+
+@(private = "file")
+get_field_parent_name :: proc(value_decl_symbol, symbol: Symbol) -> string {
+ if value_decl_symbol.range != symbol.range {
+ return symbol.name
+ }
+ return value_decl_symbol.name
+}
diff --git a/src/server/references.odin b/src/server/references.odin
index d3dc98f..f7be8c6 100644
--- a/src/server/references.odin
+++ b/src/server/references.odin
@@ -50,42 +50,13 @@ prepare_references :: proc(
ok = false
pkg := ""
- if position_context.struct_type != nil {
- found := false
- done_struct: for field in position_context.struct_type.fields.list {
- for name in field.names {
- if position_in_node(name, position_context.position) {
- symbol = Symbol {
- range = common.get_token_range(name, ast_context.file.src),
- pkg = ast_context.current_package,
- }
- found = true
- resolve_flag = .Field
- break done_struct
- }
- }
- if position_in_node(field.type, position_context.position) {
- node := get_desired_expr(field.type, position_context.position)
- symbol, ok = resolve_location_type_expression(ast_context, node)
- if !ok {
- return
- }
-
- found = true
- resolve_flag = .Identifier
- break done_struct
- }
- }
- if !found {
- return
- }
- } else if position_context.enum_type != nil {
+ if position_context.enum_type != nil {
found := false
done_enum: for field in position_context.enum_type.fields {
if ident, ok := field.derived.(^ast.Ident); ok {
if position_in_node(ident, position_context.position) {
symbol = Symbol {
- pkg = ast_context.current_package,
+ pkg = ast_context.current_package,
range = common.get_token_range(ident, ast_context.file.src),
}
found = true
@@ -96,7 +67,7 @@ prepare_references :: proc(
if position_in_node(value.field, position_context.position) {
symbol = Symbol {
range = common.get_token_range(value.field, ast_context.file.src),
- pkg = ast_context.current_package,
+ pkg = ast_context.current_package,
}
found = true
resolve_flag = .Field
@@ -198,17 +169,61 @@ prepare_references :: proc(
if !ok {
return
}
- } else if position_context.identifier != nil {
- ident := position_context.identifier.derived.(^ast.Ident)
- symbol, ok = resolve_location_identifier(ast_context, ident^)
+ } else {
+ // The order of these is important as a lot of the above can be defined within a struct so we
+ // need to make sure we resolve that last
+ if position_context.bit_field_type != nil {
+ for field in position_context.bit_field_type.fields {
+ if position_in_node(field.name, position_context.position) {
+ symbol = Symbol {
+ range = common.get_token_range(field.name, ast_context.file.src),
+ pkg = ast_context.current_package,
+ uri = document.uri.uri,
+ }
+ return symbol, .Field, true
+ }
+ if position_in_node(field.type, position_context.position) {
+ node := get_desired_expr(field.type, position_context.position)
+ if symbol, ok = resolve_location_type_expression(ast_context, node); ok {
+ return symbol, .Identifier, true
+ }
+ }
+ }
+ }
- resolve_flag = .Identifier
+ if position_context.struct_type != nil {
+ for field in position_context.struct_type.fields.list {
+ for name in field.names {
+ if position_in_node(name, position_context.position) {
+ symbol = Symbol {
+ range = common.get_token_range(name, ast_context.file.src),
+ pkg = ast_context.current_package,
+ uri = document.uri.uri,
+ }
+ return symbol, .Field, true
+ }
+ }
+ if position_in_node(field.type, position_context.position) {
+ node := get_desired_expr(field.type, position_context.position)
+ if symbol, ok = resolve_location_type_expression(ast_context, node); ok {
+ return symbol, .Identifier, true
+ }
+ }
+ }
+ }
- if !ok {
+ if position_context.identifier != nil {
+ ident := position_context.identifier.derived.(^ast.Ident)
+ symbol, ok = resolve_location_identifier(ast_context, ident^)
+
+ resolve_flag = .Identifier
+
+ if !ok {
+ return
+ }
+ } else {
return
}
- } else {
- return
}
if symbol.uri == "" {
symbol.uri = document.uri.uri
diff --git a/src/server/symbol.odin b/src/server/symbol.odin
index 3d176f1..f140694 100644
--- a/src/server/symbol.odin
+++ b/src/server/symbol.odin
@@ -378,7 +378,6 @@ write_struct_type :: proc(
v: ^ast.Struct_Type,
attributes: []^ast.Attribute,
base_using_index: int,
- inlined := false,
) {
b.poly = v.poly_params
// We clone this so we don't override docs and comments with temp allocated docs and comments
@@ -542,7 +541,7 @@ expand_usings :: proc(ast_context: ^AstContext, b: ^SymbolStructValueBuilder) {
if ident, ok := derived.(^ast.Ident); ok {
if v, ok := struct_type_from_identifier(ast_context, ident^); ok {
- write_struct_type(ast_context, b, v, {}, u, true)
+ write_struct_type(ast_context, b, v, {}, u)
} else {
clear(&ast_context.recursion_map)
if symbol, ok := resolve_type_identifier(ast_context, ident^); ok {
@@ -563,6 +562,12 @@ expand_usings :: proc(ast_context: ^AstContext, b: ^SymbolStructValueBuilder) {
}
} else if v, ok := derived.(^ast.Struct_Type); ok {
write_struct_type(ast_context, b, v, {}, u)
+ } else if v, ok := derived.(^ast.Bit_Field_Type); ok {
+ if symbol, ok := resolve_type_expression(ast_context, field_expr); ok {
+ if v, ok := symbol.value.(SymbolBitFieldValue); ok {
+ write_symbol_bitfield_value(ast_context, b, v, u)
+ }
+ }
}
delete_key(&ast_context.recursion_map, b.types[u])
}
diff --git a/tests/definition_test.odin b/tests/definition_test.odin
index 261ef83..6e7c7a4 100644
--- a/tests/definition_test.odin
+++ b/tests/definition_test.odin
@@ -627,3 +627,51 @@ ast_goto_soa_field :: proc(t: ^testing.T) {
test.expect_definition_locations(t, &source, locations[:])
}
+
+@(test)
+ast_goto_nested_using_bit_field_field :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: bit_field u8 {
+ b: u8 | 4
+ }
+ }
+
+ main :: proc() {
+ foo: Foo
+ b := foo.b{*}
+ }
+ `,
+ }
+ locations := []common.Location {
+ {range = {start = {line = 4, character = 4}, end = {line = 4, character = 5}}},
+ }
+
+ test.expect_definition_locations(t, &source, locations[:])
+}
+
+@(test)
+ast_goto_nested_using_struct_field :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: struct {
+ b: u8
+ }
+ }
+
+ main :: proc() {
+ foo: Foo
+ b := foo.b{*}
+ }
+ `,
+ }
+ locations := []common.Location {
+ {range = {start = {line = 4, character = 4}, end = {line = 4, character = 5}}},
+ }
+
+ test.expect_definition_locations(t, &source, locations[:])
+}
diff --git a/tests/hover_test.odin b/tests/hover_test.odin
index 8660eb7..72a68b5 100644
--- a/tests/hover_test.odin
+++ b/tests/hover_test.odin
@@ -4650,6 +4650,36 @@ ast_hover_comp_lit_map_key :: proc(t: ^testing.T) {
}
test.expect_hover(t, &source, "Foo.a: int")
}
+
+@(test)
+ast_hover_inner_struct_field :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ b: struct {
+ c{*}: int,
+ }
+ }
+ `,
+ }
+ test.expect_hover(t, &source, "struct.c: int")
+}
+
+@(test)
+ast_hover_using_bit_field_struct :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: bit_field u8 {
+ c{*}: u8 | 8,
+ },
+ }
+ `,
+ }
+ test.expect_hover(t, &source, "bit_field.c: u8 | 8")
+}
/*
Waiting for odin fix
diff --git a/tests/references_test.odin b/tests/references_test.odin
index c6e4438..0b8b5c0 100644
--- a/tests/references_test.odin
+++ b/tests/references_test.odin
@@ -1384,3 +1384,78 @@ ast_references_comp_lit_map_value :: proc(t: ^testing.T) {
test.expect_reference_locations(t, &source, locations[:])
}
+
+@(test)
+ast_references_nested_using_struct_field :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: struct {
+ b: u8,
+ }
+ }
+
+ main :: proc() {
+ foo: Foo
+ b := foo.b{*}
+ }
+ `,
+ }
+ locations := []common.Location {
+ {range = {start = {line = 4, character = 4}, end = {line = 4, character = 5}}},
+ {range = {start = {line = 10, character = 12}, end = {line = 10, character = 13}}},
+ }
+
+ test.expect_reference_locations(t, &source, locations[:])
+}
+
+@(test)
+ast_references_nested_using_bit_field_field :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: bit_field u8 {
+ b: u8 | 4
+ }
+ }
+
+ main :: proc() {
+ foo: Foo
+ b := foo.b{*}
+ }
+ `,
+ }
+ locations := []common.Location {
+ {range = {start = {line = 4, character = 4}, end = {line = 4, character = 5}}},
+ {range = {start = {line = 10, character = 12}, end = {line = 10, character = 13}}},
+ }
+
+ test.expect_reference_locations(t, &source, locations[:])
+}
+
+@(test)
+ast_references_nested_using_bit_field_field_from_declaration :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo :: struct {
+ a: int,
+ using _: bit_field u8 {
+ b{*}: u8 | 4
+ }
+ }
+
+ main :: proc() {
+ foo: Foo
+ b := foo.b
+ }
+ `,
+ }
+ locations := []common.Location {
+ {range = {start = {line = 4, character = 4}, end = {line = 4, character = 5}}},
+ {range = {start = {line = 10, character = 12}, end = {line = 10, character = 13}}},
+ }
+
+ test.expect_reference_locations(t, &source, locations[:])
+}