diff options
| author | Bradley Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-09-11 22:03:52 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-11 22:03:52 -0400 |
| commit | aa2e8f609ad3a48f1bf7570a7f34c01f89d53c5d (patch) | |
| tree | 2dab8c6a774f0be610048b145081f08f9f6f2282 | |
| parent | 7b5eac698391e9d0b2d6fdac4ce4a857f92c33f2 (diff) | |
| parent | 4cb9acda12fa0bb0a0b6fd6d46c163adc0544a4a (diff) | |
Merge pull request #998 from BradLewis/feat/nesting-structs-bitfield-improvements
Feat/nesting structs bitfield improvements
| -rw-r--r-- | src/server/analysis.odin | 2 | ||||
| -rw-r--r-- | src/server/file_resolve.odin | 9 | ||||
| -rw-r--r-- | src/server/hover.odin | 56 | ||||
| -rw-r--r-- | src/server/references.odin | 93 | ||||
| -rw-r--r-- | src/server/symbol.odin | 9 | ||||
| -rw-r--r-- | tests/definition_test.odin | 48 | ||||
| -rw-r--r-- | tests/hover_test.odin | 30 | ||||
| -rw-r--r-- | tests/references_test.odin | 75 |
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[:]) +} |