diff options
| author | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-08-07 21:04:19 -0400 |
|---|---|---|
| committer | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-08-11 16:34:19 -0400 |
| commit | 790cf8a16315d65bd80478aecfb34d7ff5dae31b (patch) | |
| tree | c8f7e7ad40a9724fef3438a0832cb1c5791dfbbf | |
| parent | 03cbe19af2b3c74519be11c4de220eb9d36fa90d (diff) | |
Remove type information from the signature and write nested struct fields correctly
| -rw-r--r-- | src/server/analysis.odin | 32 | ||||
| -rw-r--r-- | src/server/documentation.odin | 119 | ||||
| -rw-r--r-- | src/server/symbol.odin | 13 | ||||
| -rw-r--r-- | tests/hover_test.odin | 65 |
4 files changed, 155 insertions, 74 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 4401d5b..c5b9b29 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -1048,13 +1048,13 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex return internal_resolve_type_expression(ast_context, v.values[0], out) } case ^Union_Type: - out^, ok = make_symbol_union_from_ast(ast_context, v^, ast_context.field_name, true), true + out^, ok = make_symbol_union_from_ast(ast_context, v^, ast_context.field_name.name, true), true return ok case ^Enum_Type: - out^, ok = make_symbol_enum_from_ast(ast_context, v^, ast_context.field_name, true), true + out^, ok = make_symbol_enum_from_ast(ast_context, v^, ast_context.field_name.name, true), true return ok case ^Struct_Type: - out^, ok = make_symbol_struct_from_ast(ast_context, v, ast_context.field_name, {}, true), true + out^, ok = make_symbol_struct_from_ast(ast_context, v, ast_context.field_name.name, {}, true), true return ok case ^Bit_Set_Type: out^, ok = make_symbol_bitset_from_ast(ast_context, v^, ast_context.field_name, true), true @@ -1690,13 +1690,13 @@ resolve_local_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, loca case ^ast.Ident: return_symbol, ok = internal_resolve_type_identifier(ast_context, v^) case ^ast.Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node.name), true return_symbol.name = node.name case ^ast.Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node.name), true return_symbol.name = node.name case ^ast.Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, {}), true + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node.name, {}), true return_symbol.name = node.name case ^ast.Bit_Set_Type: return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true @@ -1790,16 +1790,16 @@ resolve_global_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, glo } case ^ast.Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, global.attributes), true + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node.name, global.attributes), true return_symbol.name = node.name case ^ast.Bit_Set_Type: return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^ast.Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node.name), true return_symbol.name = node.name case ^ast.Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node.name), true return_symbol.name = node.name case ^ast.Bit_Field_Type: return_symbol, ok = make_symbol_bit_field_from_ast(ast_context, v, node), true @@ -3151,14 +3151,14 @@ make_symbol_poly_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Ident) make_symbol_union_from_ast :: proc( ast_context: ^AstContext, v: ast.Union_Type, - ident: ast.Ident, + name: string, inlined := false, ) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Union, pkg = get_package_from_node(v.node), - name = ident.name, + name = name, uri = common.create_uri(v.pos.file, ast_context.allocator).uri, } @@ -3198,13 +3198,13 @@ make_symbol_union_from_ast :: proc( make_symbol_enum_from_ast :: proc( ast_context: ^AstContext, v: ast.Enum_Type, - ident: ast.Ident, + name: string, inlined := false, ) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, - name = ident.name, + name = name, pkg = get_package_from_node(v.node), uri = common.create_uri(v.pos.file, ast_context.allocator).uri, } @@ -3283,7 +3283,7 @@ make_symbol_bitset_from_ast :: proc( make_symbol_struct_from_ast :: proc( ast_context: ^AstContext, v: ^ast.Struct_Type, - ident: ast.Ident, + name: string, attributes: []^ast.Attribute, inlined := false, ) -> Symbol { @@ -3292,7 +3292,7 @@ make_symbol_struct_from_ast :: proc( range = common.get_token_range(v, ast_context.file.src), type = .Struct, pkg = get_package_from_node(v.node), - name = ident.name, + name = name, uri = common.create_uri(v.pos.file, ast_context.allocator).uri, } @@ -3302,7 +3302,7 @@ make_symbol_struct_from_ast :: proc( } b := symbol_struct_value_builder_make(symbol, ast_context.allocator) - write_struct_type(ast_context, &b, v, ident, attributes, -1, inlined) + write_struct_type(ast_context, &b, v, attributes, -1, inlined) symbol = to_symbol(b) return symbol } diff --git a/src/server/documentation.odin b/src/server/documentation.odin index c572e79..f0e7b1b 100644 --- a/src/server/documentation.odin +++ b/src/server/documentation.odin @@ -141,19 +141,14 @@ construct_symbol_docs :: proc(symbol: Symbol, markdown := true, allocator := con } // Returns the fully detailed signature for the symbol, including things like attributes and fields -get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { - show_type_info := symbol.type == .Variable || symbol.type == .Field - +get_signature :: proc(ast_context: ^AstContext, symbol: Symbol, depth := 0) -> string { pointer_prefix := repeat("^", symbol.pointers, ast_context.allocator) #partial switch v in symbol.value { case SymbolEnumValue: sb := strings.builder_make(ast_context.allocator) - if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) - strings.write_string(&sb, " :: ") - } if len(v.names) == 0 { + write_indent(&sb, depth) strings.write_string(&sb, "enum {}") if symbol.comment != "" { fmt.sbprintf(&sb, " %s", symbol.comment) @@ -174,25 +169,22 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } strings.write_string(&sb, "{\n") for i in 0 ..< len(v.names) { - append_docs(&sb, v.docs, i) - strings.write_string(&sb, "\t") + write_docs(&sb, v.docs, i, depth+1) + write_indent(&sb, depth+1) strings.write_string(&sb, v.names[i]) if i < len(v.values) && v.values[i] != nil { fmt.sbprintf(&sb, "%*s= ", longestNameLen - len(v.names[i]) + 1, "") build_string_node(v.values[i], &sb, false) } strings.write_string(&sb, ",") - append_comments(&sb, v.comments, i) + write_comments(&sb, v.comments, i) strings.write_string(&sb, "\n") } + write_indent(&sb, depth) strings.write_string(&sb, "}") return strings.to_string(sb) case SymbolStructValue: sb := strings.builder_make(ast_context.allocator) - if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) - strings.write_string(&sb, " :: ") - } if len(v.names) == 0 { strings.write_string(&sb, "struct {}") if symbol.comment != "" { @@ -200,14 +192,10 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } return strings.to_string(sb) } - write_struct_hover(ast_context, &sb, v) + write_struct_hover(ast_context, &sb, v, depth) return strings.to_string(sb) case SymbolUnionValue: sb := strings.builder_make(ast_context.allocator) - if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) - strings.write_string(&sb, " :: ") - } strings.write_string(&sb, "union") write_poly_list(&sb, v.poly, v.poly_names) if v.kind != .Normal { @@ -223,13 +211,14 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } strings.write_string(&sb, " {\n") for i in 0 ..< len(v.types) { - append_docs(&sb, v.docs, i) - strings.write_string(&sb, "\t") + write_docs(&sb, v.docs, i, depth+1) + write_indent(&sb, depth+1) build_string_node(v.types[i], &sb, false) strings.write_string(&sb, ",") - append_comments(&sb, v.comments, i) + write_comments(&sb, v.comments, i) strings.write_string(&sb, "\n") } + write_indent(&sb, depth) strings.write_string(&sb, "}") return strings.to_string(sb) case SymbolAggregateValue: @@ -237,27 +226,21 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { strings.write_string(&sb, "proc {\n") for symbol in v.symbols { if value, ok := symbol.value.(SymbolProcedureValue); ok { - fmt.sbprintf(&sb, "\t%s :: ", symbol.name) + write_indent(&sb, depth+1) + fmt.sbprintf(&sb, "%s :: ", symbol.name) write_procedure_symbol_signature(&sb, value, detailed_signature=false) strings.write_string(&sb, ",\n") } } + write_indent(&sb, depth) strings.write_string(&sb, "}") return strings.to_string(sb) case SymbolProcedureValue: sb := strings.builder_make(ast_context.allocator) - if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) - strings.write_string(&sb, " :: ") - } write_procedure_symbol_signature(&sb, v, detailed_signature=true) return strings.to_string(sb) case SymbolBitFieldValue: sb := strings.builder_make(ast_context.allocator) - if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) - strings.write_string(&sb, " :: ") - } strings.write_string(&sb, "bit_field ") build_string_node(v.backing_type, &sb, false) if len(v.names) == 0 { @@ -282,14 +265,16 @@ get_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string { } for name, i in v.names { - append_docs(&sb, v.docs, i) - fmt.sbprintf(&sb, "\t%s:%*s", v.names[i], longest_name_len - len(name) + 1, "") + write_docs(&sb, v.docs, i, depth+1) + write_indent(&sb, depth+1) + fmt.sbprintf(&sb, "%s:%*s", v.names[i], longest_name_len - len(name) + 1, "") fmt.sbprintf(&sb, "%s%*s| ", type_names[i], longest_type_len - len(type_names[i]) + 1, "") build_string_node(v.bit_sizes[i], &sb, false) strings.write_string(&sb, ",") - append_comments(&sb, v.comments, i) + write_comments(&sb, v.comments, i) strings.write_string(&sb, "\n") } + write_indent(&sb, depth) strings.write_string(&sb, "}") return strings.to_string(sb) } @@ -337,7 +322,7 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string } sb := strings.builder_make(ast_context.allocator) if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) + write_type_information(&sb, ast_context, symbol, pointer_prefix) } else { strings.write_string(&sb, pointer_prefix) strings.write_string(&sb, "enum {..}") @@ -353,7 +338,7 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string case SymbolProcedureValue: sb := strings.builder_make(ast_context.allocator) if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) + write_type_information(&sb, ast_context, symbol, pointer_prefix) strings.write_string(&sb, " :: ") } write_procedure_symbol_signature(&sb, v, detailed_signature=true) @@ -363,7 +348,7 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string case SymbolStructValue: sb := strings.builder_make(ast_context.allocator) if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) + write_type_information(&sb, ast_context, symbol, pointer_prefix) write_poly_list(&sb, v.poly, v.poly_names) } else { strings.write_string(&sb, pointer_prefix) @@ -375,7 +360,7 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string case SymbolUnionValue: sb := strings.builder_make(ast_context.allocator) if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) + write_type_information(&sb, ast_context, symbol, pointer_prefix) write_poly_list(&sb, v.poly, v.poly_names) } else { strings.write_string(&sb, pointer_prefix) @@ -387,7 +372,7 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string case SymbolBitFieldValue: sb := strings.builder_make(ast_context.allocator) if show_type_info { - append_type_information(&sb, ast_context, symbol, pointer_prefix) + write_type_information(&sb, ast_context, symbol, pointer_prefix) } else { fmt.sbprintf(&sb, "%sbit_field ", pointer_prefix) build_string_node(v.backing_type, &sb, false) @@ -444,6 +429,12 @@ get_short_signature :: proc(ast_context: ^AstContext, symbol: Symbol) -> string return "" } +write_indent :: proc(sb: ^strings.Builder, level: int) { + for _ in 0..<level { + strings.write_string(sb, "\t") + } +} + get_enum_field_signature :: proc(value: SymbolEnumValue, index: int, allocator := context.temp_allocator) -> string { sb := strings.builder_make(allocator) fmt.sbprintf(&sb, ".%s", value.names[index]) @@ -542,7 +533,7 @@ write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: SymbolProc } } -write_struct_hover :: proc(ast_context: ^AstContext, sb: ^strings.Builder, v: SymbolStructValue) { +write_struct_hover :: proc(ast_context: ^AstContext, sb: ^strings.Builder, v: SymbolStructValue, depth: int) { using_prefix := "using " longestNameLen := 0 for name, i in v.names { @@ -574,7 +565,9 @@ write_struct_hover :: proc(ast_context: ^AstContext, sb: ^strings.Builder, v: Sy for i in 0 ..< len(v.names) { if i < len(v.from_usings) { if index := v.from_usings[i]; index != using_index && index != -1 { - fmt.sbprintf(sb, "\n\t// from `using %s: ", v.names[index]) + strings.write_string(sb, "\n") + write_indent(sb, depth+1) + fmt.sbprintf(sb, "// from `using %s: ", v.names[index]) build_string_node(v.types[index], sb, false) if backing_type, ok := v.backing_types[index]; ok { strings.write_string(sb, " (bit_field ") @@ -585,23 +578,25 @@ write_struct_hover :: proc(ast_context: ^AstContext, sb: ^strings.Builder, v: Sy using_index = index } } - append_docs(sb, v.docs, i) - strings.write_string(sb, "\t") + write_docs(sb, v.docs, i, depth+1) + write_indent(sb, depth+1) name_len := len(v.names[i]) if _, ok := v.usings[i]; ok { strings.write_string(sb, using_prefix) name_len += len(using_prefix) } - fmt.sbprintf(sb, "%s:%*s%s", v.names[i], longestNameLen - name_len + 1, "", type_names[i]) + fmt.sbprintf(sb, "%s:%*s", v.names[i], longestNameLen - name_len + 1, "") + write_node(ast_context, sb, v.types[i], v.names[i], depth + 1) if bit_size, ok := v.bit_sizes[i]; ok { fmt.sbprintf(sb, "%*s| ", longest_type_len - len(type_names[i]) + 1, "") build_string_node(bit_size, sb, false) } strings.write_string(sb, ",") - append_comments(sb, v.comments, i) + write_comments(sb, v.comments, i) strings.write_string(sb, "\n") } + write_indent(sb, depth) strings.write_string(sb, "}") } @@ -649,7 +644,33 @@ write_union_kind :: proc(sb: ^strings.Builder, kind: ast.Union_Type_Kind) { } } -append_type_information :: proc( +write_node :: proc(ast_context: ^AstContext, sb: ^strings.Builder, node: ^ast.Node, name: string, depth: int) { + if node == nil { + return + } + + #partial switch n in node.derived { + case ^ast.Struct_Type: + symbol := make_symbol_struct_from_ast(ast_context, n, name, {}, true) + inner_sig := get_signature(ast_context, symbol, depth) + strings.write_string(sb, inner_sig) + return + case ^ast.Union_Type: + symbol := make_symbol_union_from_ast(ast_context, n^, name, true) + inner_sig := get_signature(ast_context, symbol, depth) + strings.write_string(sb, inner_sig) + return + case ^ast.Enum_Type: + symbol := make_symbol_enum_from_ast(ast_context, n^, name, true) + inner_sig := get_signature(ast_context, symbol, depth) + strings.write_string(sb, inner_sig) + return + } + + build_string_node(node, sb, false) +} + +write_type_information :: proc( sb: ^strings.Builder, ast_context: ^AstContext, symbol: Symbol, @@ -664,15 +685,15 @@ append_type_information :: proc( return } -append_docs :: proc(sb: ^strings.Builder, docs: []^ast.Comment_Group, index: int) { +write_docs :: proc(sb: ^strings.Builder, docs: []^ast.Comment_Group, index: int, depth := 0) { if index < len(docs) && docs[index] != nil { for c in docs[index].list { - fmt.sbprintf(sb, "\t%s\n", c.text) + fmt.sbprintf(sb, "%.*s%s\n", depth, "\t", c.text) } } } -append_comments :: proc(sb: ^strings.Builder, comments: []^ast.Comment_Group, index: int) { +write_comments :: proc(sb: ^strings.Builder, comments: []^ast.Comment_Group, index: int) { if index < len(comments) && comments[index] != nil { for c in comments[index].list { fmt.sbprintf(sb, " %s", c.text) diff --git a/src/server/symbol.odin b/src/server/symbol.odin index cf2c4ed..5487150 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -35,6 +35,14 @@ SymbolStructValue :: struct { // Extra fields for embedded bit fields via usings backing_types: map[int]^ast.Expr, // the base type for the bit field bit_sizes: map[int]^ast.Expr, // the bit size of the bit field field + + // Tag information + align: ^ast.Expr, + min_field_align: ^ast.Expr, + max_field_align: ^ast.Expr, + is_packed: bool, + is_raw_union: bool, + is_no_copy: bool, } SymbolBitFieldValue :: struct { @@ -331,7 +339,6 @@ write_struct_type :: proc( ast_context: ^AstContext, b: ^SymbolStructValueBuilder, v: ^ast.Struct_Type, - ident: ast.Ident, attributes: []^ast.Attribute, base_using_index: int, inlined := false, @@ -478,7 +485,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, ident^, {}, u, true) + write_struct_type(ast_context, b, v, {}, u, true) } else { clear(&ast_context.recursion_map) if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { @@ -498,7 +505,7 @@ expand_usings :: proc(ast_context: ^AstContext, b: ^SymbolStructValueBuilder) { } } } else if v, ok := derived.(^ast.Struct_Type); ok { - write_struct_type(ast_context, b, v, ast_context.field_name, {}, u) + write_struct_type(ast_context, b, v, {}, u) } delete_key(&ast_context.recursion_map, b.types[u]) } diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 46bd45c..f3c0af7 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -3709,11 +3709,7 @@ ast_hover_binary_expr_not_eq :: proc(t: ^testing.T) { } `, } - test.expect_hover( - t, - &source, - "test.foo: bool" - ) + test.expect_hover(t, &source, "test.foo: bool") } @(test) @@ -3728,10 +3724,67 @@ ast_hover_bit_set_in :: proc(t: ^testing.T) { } `, } + test.expect_hover(t, &source, "test.foo: bool") +} + +@(test) +ast_hover_nested_struct :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Fo{*}o :: struct { + foo: int, + bar: struct { + i: int, + s: string, + } + } + `, + } + test.expect_hover( + t, + &source, + "test.Foo: struct {\n\tfoo: int,\n\tbar: struct {\n\t\ti: int,\n\t\ts: string,\n\t},\n}", + ) +} + +@(test) +ast_hover_nested_struct_union :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Fo{*}o :: struct { + foo: int, + bar: union #no_nil { + int, // int comment + string, + } + } + `, + } + test.expect_hover( + t, + &source, + "test.Foo: struct {\n\tfoo: int,\n\tbar: union #no_nil {\n\t\tint, // int comment\n\t\tstring,\n\t},\n}" + ) +} + +@(test) +ast_hover_nested_struct_enum :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Fo{*}o :: struct { + foo: int, + bar: enum { + // A doc + A, + B, + } + } + `, + } test.expect_hover( t, &source, - "test.foo: bool" + "test.Foo: struct {\n\tfoo: int,\n\tbar: enum {\n\t// A doc\n\t\tA,\n\t\tB,\n\t},\n}" ) } /* |