diff --git a/src/common/ast.odin b/src/common/ast.odin index 1036b04f..dbe236a9 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -705,6 +705,13 @@ free_ast_node :: proc(node: ^ast.Node, allocator: mem.Allocator) { case ^Relative_Type: free_ast(n.tag, allocator) free_ast(n.type, allocator) + case ^Bit_Field_Type: + free_ast(n.backing_type, allocator) + for field in n.fields do free_ast(field, allocator) + case ^Bit_Field_Field: + free_ast(n.name, allocator) + free_ast(n.type, allocator) + free_ast(n.bit_size, allocator) case: panic(fmt.aprintf("free Unhandled node kind: %v", node.derived)) } @@ -913,6 +920,22 @@ node_equal_node :: proc(a, b: ^ast.Node) -> bool { ret &= node_equal(n.args, m.args) return ret } + case ^Bit_Field_Type: + if n, ok := a.derived.(^Bit_Field_Type); ok { + if len(n.fields) != len(m.fields) do return false + ret := node_equal(n.backing_type, m.backing_type) + for i in 0.. ^Document { + if len(bit_field_type.fields) == 0 { + return empty() + } + + document := empty() + + name_alignment, type_alignment := get_possible_bit_field_alignment(bit_field_type.fields) + + for field, i in bit_field_type.fields { + if i == 0 && .Enforce_Newline in options { + comment, _ := visit_comments(p, bit_field_type.fields[i].pos) + if _, is_nil := comment.(Document_Nil); !is_nil { + comment = cons(comment, newline(1)) + } + document = cons(comment, document) + } + + if (.Enforce_Newline in options) { + document = cons( + document, + cons_with_nopl( + cons( + visit_expr(p, field.name), + text_position(p, ":", field.name.end), + ), + cons_with_nopl( + cons( + repeat_space( + name_alignment - get_node_length(field.name), + ), + visit_expr(p, field.type), + ), + cons_with_nopl( + cons( + repeat_space( + type_alignment - get_node_length(field.type), + ), + text_position(p, "|", field.type.end), + ), + visit_expr(p, field.bit_size), + ), + ), + ), + ) + } else { + document = group( + cons_with_opl( + document, + cons_with_nopl( + cons( + visit_expr(p, field.name), + text_position(p, ":", field.name.end), + ), + cons_with_nopl( + cons_with_nopl( + visit_expr(p, field.type), + text_position(p, "|", field.type.end), + ), + visit_expr(p, field.bit_size), + ), + ), + ), + ) + } + + if (i != len(bit_field_type.fields) - 1 || .Trailing in options) && + .Add_Comma in options { + document = cons(document, text(",")) + } + + if (i != len(bit_field_type.fields) - 1 && .Enforce_Newline in options) { + comment, _ := visit_comments(p, bit_field_type.fields[i + 1].pos) + document = cons(document, comment, newline(1)) + } else if .Enforce_Newline in options { + comment, _ := visit_comments(p, bit_field_type.end) + document = cons(document, comment) + } + } + + return document +} + @(private) visit_union_exprs :: proc( p: ^Printer, @@ -1850,6 +1938,36 @@ visit_expr :: proc( document = cons(document, newline(1), text_position(p, "}", v.end)) } + set_source_position(p, v.end) + case ^Bit_Field_Type: + document = text_position(p, "bit_field", v.pos) + + document = cons_with_nopl(document, visit_expr(p, v.backing_type)) + + if len(v.fields) == 0 { + document = cons_with_nopl(document, text("{")) + document = cons(document, text("}")) + } else { + document = cons(document, break_with_space(), visit_begin_brace(p, v.pos, .Generic)) + set_source_position(p, v.fields[0].pos) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.open), + visit_bit_field_fields( + p, + v^, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) + set_source_position(p, v.end) + + document = cons(document, newline(1), text_position(p, "}", v.end)) + } + set_source_position(p, v.end) case ^Proc_Lit: switch v.inlining { @@ -2845,3 +2963,13 @@ get_possible_enum_alignment :: proc(exprs: []^ast.Expr) -> int { return longest_name } + +@(private) +get_possible_bit_field_alignment :: proc(fields: []^ast.Bit_Field_Field) -> (longest_name: int, longest_type: int) { + for field in fields { + longest_name = max(longest_name, get_node_length(field.name)) + longest_type = max(longest_type, get_node_length(field.type)) + } + + return +} diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 932cc1b0..100695cf 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -46,6 +46,7 @@ DocumentPositionContext :: struct { bitset_type: ^ast.Bit_Set_Type, enum_type: ^ast.Enum_Type, field_value: ^ast.Field_Value, + bit_field_type: ^ast.Bit_Field_Type, implicit: bool, //used for completion arrow: bool, binary: ^ast.Binary_Expr, //used for completion @@ -189,6 +190,30 @@ resolve_type_comp_literal :: proc( } } } + } else if s, ok := current_symbol.value.(SymbolBitFieldValue); ok { + for name, i in s.names { + if name == + field_value.field.derived.(^ast.Ident).name { + if symbol, ok := resolve_type_expression( + ast_context, + s.types[i], + ); ok { + //Stop at bitset, because we don't want to enter a comp_lit of a bitset + if _, ok := symbol.value.(SymbolBitSetValue); + ok { + return current_symbol, + current_comp_lit, + true + } + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + cast(^ast.Comp_Lit)field_value.value, + ) + } + } + } } } } else if comp_value, ok := elem.derived.(^ast.Comp_Lit); ok { //indexed @@ -198,6 +223,26 @@ resolve_type_comp_literal :: proc( return {}, {}, false } + if symbol, ok := resolve_type_expression( + ast_context, + s.types[element_index], + ); ok { + //Stop at bitset, because we don't want to enter a comp_lit of a bitset + if _, ok := symbol.value.(SymbolBitSetValue); ok { + return current_symbol, current_comp_lit, true + } + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + comp_value, + ) + } + case SymbolBitFieldValue: + if len(s.types) <= element_index { + return {}, {}, false + } + if symbol, ok := resolve_type_expression( ast_context, s.types[element_index], @@ -825,6 +870,14 @@ internal_resolve_type_expression :: proc( true, ), true + case ^Bit_Field_Type: + return make_symbol_bit_field_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), + true case ^Basic_Directive: return resolve_basic_directive(ast_context, v^) case ^Binary_Expr: @@ -1068,6 +1121,18 @@ internal_resolve_type_expression :: proc( return symbol, ok } } + case SymbolBitFieldValue: + for name, i in s.names { + if v.field != nil && name == v.field.name { + ast_context.field_name = v.field^ + symbol, ok := internal_resolve_type_expression( + ast_context, + s.types[i], + ) + symbol.type = .Variable + return symbol, ok + } + } case SymbolPackageValue: try_build_package(ast_context.current_package) @@ -1309,6 +1374,10 @@ internal_resolve_type_identifier :: proc( return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name + case ^Bit_Field_Type: + return_symbol, ok = + make_symbol_bit_field_from_ast(ast_context, v^, node), true + return_symbol.name = node.name case ^Proc_Lit: if !is_procedure_generic(v.type) { return_symbol, ok = @@ -1441,6 +1510,15 @@ internal_resolve_type_identifier :: proc( return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name + case ^Bit_Field_Type: + return_symbol, ok = + make_symbol_bit_field_from_ast( + ast_context, + v^, + node, + ), + true + return_symbol.name = node.name case ^Proc_Lit: if !is_procedure_generic(v.type) { return_symbol, ok = @@ -1910,6 +1988,34 @@ resolve_implicit_selector :: proc( type = s.types[elem_index] } + return resolve_type_expression(ast_context, type) + } else if s, ok := comp_symbol.value.(SymbolBitFieldValue); ok { + ast_context.current_package = comp_symbol.pkg + + //We can either have the final + elem_index := -1 + + for elem, i in comp_lit.elems { + if position_in_node(elem, position_context.position) { + elem_index = i + } + } + + type: ^ast.Expr + + for name, i in s.names { + if name != field_name { + continue + } + + type = s.types[i] + break + } + + if type == nil && len(s.types) > elem_index { + type = s.types[elem_index] + } + return resolve_type_expression(ast_context, type) } } @@ -2018,7 +2124,7 @@ resolve_unresolved_symbol :: proc( } #partial switch v in symbol.value { - case SymbolStructValue: + case SymbolStructValue, SymbolBitFieldValue: symbol.type = .Struct case SymbolPackageValue: symbol.type = .Package @@ -2105,7 +2211,12 @@ resolve_location_comp_lit_field :: proc( if name == field.name { symbol.range = struct_value.ranges[i] } - + } + } else if bit_field_value, ok := symbol.value.(SymbolBitFieldValue); ok { + for name, i in bit_field_value.names { + if name == field.name { + symbol.range = bit_field_value.ranges[i] + } } } @@ -2170,6 +2281,12 @@ resolve_location_selector :: proc( symbol.range = v.ranges[i] } } + case SymbolBitFieldValue: + for name, i in v.names { + if strings.compare(name, field) == 0 { + symbol.range = v.ranges[i] + } + } case SymbolPackageValue: if pkg, ok := lookup(field, symbol.pkg); ok { symbol.range = pkg.range @@ -2838,6 +2955,49 @@ make_symbol_struct_from_ast :: proc( return symbol } +make_symbol_bit_field_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Bit_Field_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { + symbol := Symbol { + range = common.get_token_range(v, ast_context.file.src), + type = .Struct, + pkg = get_package_from_node(v.node), + name = ident.name, + } + + if inlined { + symbol.flags |= {.Anonymous} + symbol.name = "bit_field" + } + + names := make([dynamic]string, ast_context.allocator) + types := make([dynamic]^ast.Expr, ast_context.allocator) + ranges := make([dynamic]common.Range, 0, ast_context.allocator) + + for field in v.fields { + if identifier, ok := field.name.derived.(^ast.Ident); + ok && field.type != nil { + append(&names, identifier.name) + append(&types, field.type) + append( + &ranges, + common.get_token_range(identifier, ast_context.file.src), + ) + } + } + + symbol.value = SymbolBitFieldValue { + names = names[:], + types = types[:], + ranges = ranges[:], + } + + return symbol +} + get_globals :: proc(file: ast.File, ast_context: ^AstContext) { exprs := common.collect_globals(file) @@ -3075,7 +3235,7 @@ get_locals_block_stmt :: proc( } get_locals_using :: proc(expr: ^ast.Expr, ast_context: ^AstContext) { - if symbol, expr, ok := unwrap_procedure_until_struct_or_package( + if symbol, expr, ok := unwrap_procedure_until_struct_bit_field_or_package( ast_context, expr, ); ok { @@ -3114,6 +3274,36 @@ get_locals_using :: proc(expr: ^ast.Expr, ast_context: ^AstContext) { false, ) } + case SymbolBitFieldValue: + for name, i in v.names { + selector := new_type( + ast.Selector_Expr, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) + selector.expr = expr + selector.field = new_type( + ast.Ident, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) + selector.field.name = name + store_local( + ast_context, + expr, + selector, + 0, + name, + ast_context.local_id, + false, + ast_context.non_mutable_only, + true, + "", + false, + ) + } } } } @@ -3927,7 +4117,7 @@ concatenate_raw_string_information :: proc( } } -unwrap_procedure_until_struct_or_package :: proc( +unwrap_procedure_until_struct_bit_field_or_package :: proc( ast_context: ^AstContext, node: ^ast.Expr, ) -> ( @@ -3964,7 +4154,7 @@ unwrap_procedure_until_struct_or_package :: proc( } expr = v.return_types[0].type - case SymbolStructValue, SymbolPackageValue: + case SymbolStructValue, SymbolPackageValue, SymbolBitFieldValue: ok = true return case: @@ -4124,6 +4314,15 @@ get_signature :: proc( } else { return "union" } + case SymbolBitFieldValue: + if is_variable { + return strings.concatenate( + {pointer_prefix, symbol.name}, + ast_context.allocator, + ) + } else { + return "bit_field" + } case SymbolMultiPointer: return strings.concatenate( a = {pointer_prefix, "[^]", common.node_to_string(v.expr)}, @@ -5084,6 +5283,14 @@ get_document_position_node :: proc( get_document_position(n.y, position_context) case ^ast.Or_Return_Expr: get_document_position(n.expr, position_context) + case ^ast.Bit_Field_Type: + position_context.bit_field_type = cast(^Bit_Field_Type)node + get_document_position(n.backing_type, position_context) + get_document_position(n.fields, position_context) + case ^ast.Bit_Field_Field: + get_document_position(n.name, position_context) + get_document_position(n.type, position_context) + get_document_position(n.bit_size, position_context) case: } } diff --git a/src/server/clone.odin b/src/server/clone.odin index 796bf334..d535d19d 100644 --- a/src/server/clone.odin +++ b/src/server/clone.odin @@ -287,6 +287,13 @@ clone_node :: proc( case ^Relative_Type: r.tag = clone_type(r.tag, allocator, unique_strings) r.type = clone_type(r.type, allocator, unique_strings) + case ^Bit_Field_Type: + r.backing_type = clone_type(r.backing_type, allocator, unique_strings) + r.fields = clone_type(r.fields, allocator, unique_strings) + case ^Bit_Field_Field: + r.name = clone_type(r.name, allocator, unique_strings) + r.type = clone_type(r.type, allocator, unique_strings) + r.bit_size = clone_type(r.bit_size, allocator, unique_strings) case: } diff --git a/src/server/collector.odin b/src/server/collector.odin index 33c48228..fde4f30f 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -191,6 +191,41 @@ collect_struct_fields :: proc( return value } +collect_bit_field_fields :: proc( + collection: ^SymbolCollection, + fields: []^ast.Bit_Field_Field, + package_map: map[string]string, + file: ast.File, +) -> SymbolBitFieldValue { + names := make([dynamic]string, 0, len(fields), collection.allocator) + types := make([dynamic]^ast.Expr, 0, len(fields), collection.allocator) + ranges := make([dynamic]common.Range, 0, len(fields), collection.allocator) + + for field, i in fields { + if ident, ok := field.name.derived.(^ast.Ident); ok { + append(&names, get_index_unique_string(collection, ident.name)) + + cloned := clone_type( + field.type, + collection.allocator, + &collection.unique_strings, + ) + replace_package_alias(cloned, package_map, collection) + append(&types, cloned) + + append(&ranges, common.get_token_range(ident, file.src)) + } + } + + value := SymbolBitFieldValue { + names = names[:], + types = types[:], + ranges = ranges[:], + } + + return value +} + collect_enum_fields :: proc( collection: ^SymbolCollection, fields: []^ast.Expr, @@ -648,6 +683,16 @@ collect_symbols :: proc( token_type = .Enum symbol.value = collect_bitset_field(collection, v^, package_map) symbol.signature = "bitset" + case ^ast.Bit_Field_Type: + token = v^ + token_type = .Struct + symbol.value = collect_bit_field_fields( + collection, + v.fields, + package_map, + file, + ) + symbol.signature = "bit_field" case ^ast.Map_Type: token = v^ token_type = .Variable @@ -999,6 +1044,13 @@ replace_package_alias_node :: proc( case ^Proc_Lit: case ^Multi_Pointer_Type: replace_package_alias(n.elem, package_map, collection) + case ^Bit_Field_Type: + replace_package_alias(n.backing_type, package_map, collection) + replace_package_alias(n.fields, package_map, collection) + case ^Bit_Field_Field: + replace_package_alias(n.name, package_map, collection) + replace_package_alias(n.type, package_map, collection) + replace_package_alias(n.bit_size, package_map, collection) case: } } diff --git a/src/server/completion.odin b/src/server/completion.odin index caba5bf8..f917498e 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -260,7 +260,40 @@ get_comp_lit_completion :: proc( append(&items, item) } } + case SymbolBitFieldValue: + for name, i in v.names { + if name == "_" { + continue + } + + ast_context.current_package = symbol.pkg + + if resolved, ok := resolve_type_expression( + ast_context, + v.types[i], + ); ok { + if field_exists_in_comp_lit( + position_context.comp_lit, + 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, + } + + append(&items, item) + } + } } } @@ -609,6 +642,52 @@ get_selector_completion :: proc( } } + case SymbolBitFieldValue: + list.isIncomplete = false + + for name, i in v.names { + if name == "_" { + continue + } + + if selector.pkg != "" { + ast_context.current_package = selector.pkg + } else { + ast_context.current_package = ast_context.document_package + } + + if symbol, ok := resolve_type_expression(ast_context, v.types[i]); + ok { + item := CompletionItem { + label = name, + kind = .Field, + detail = fmt.tprintf( + "%v.%v: %v", + selector.name, + name, + type_to_string(ast_context, v.types[i]), + ), + documentation = symbol.doc, + } + + append(&items, item) + } else { + //just give some generic symbol with name. + item := CompletionItem { + label = symbol.name, + kind = .Field, + detail = fmt.tprintf( + "%v: %v", + name, + common.node_to_string(v.types[i]), + ), + documentation = symbol.doc, + } + + append(&items, item) + } + } + case SymbolPackageValue: list.isIncomplete = true diff --git a/src/server/document_symbols.odin b/src/server/document_symbols.odin index 334bb6e7..8a0cb2d9 100644 --- a/src/server/document_symbols.odin +++ b/src/server/document_symbols.odin @@ -62,7 +62,7 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { symbol.name = k #partial switch v in global.expr.derived { - case ^ast.Struct_Type: + case ^ast.Struct_Type, ^ast.Bit_Field_Type: symbol.kind = .Struct case ^ast.Proc_Lit, ^ast.Proc_Group: symbol.kind = .Function diff --git a/src/server/hover.odin b/src/server/hover.odin index c3dccbc9..566b41c9 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -165,6 +165,26 @@ get_hover_information :: proc( } } } + } else if v, ok := comp_symbol.value.(SymbolBitFieldValue); ok { + for name, i in v.names { + if name == field.name { + if symbol, ok := resolve_type_expression( + &ast_context, + v.types[i], + ); ok { + symbol.name = name + symbol.pkg = comp_symbol.name + symbol.signature = common.node_to_string( + v.types[i], + ) + hover.contents = write_hover_content( + &ast_context, + symbol, + ) + return hover, true, true + } + } + } } } } @@ -268,6 +288,24 @@ get_hover_information :: proc( } } } + case SymbolBitFieldValue: + for name, i in v.names { + if name == field { + if symbol, ok := resolve_type_expression( + &ast_context, + v.types[i], + ); ok { + symbol.name = name + symbol.pkg = selector.name + symbol.signature = common.node_to_string(v.types[i]) + hover.contents = write_hover_content( + &ast_context, + symbol, + ) + return hover, true, true + } + } + } case SymbolPackageValue: if position_context.field != nil { if ident, ok := position_context.field.derived.(^ast.Ident); diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index 7fafc21e..643709cd 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -759,6 +759,16 @@ visit_node :: proc( visit_proc_type(n.type, builder, ast_context) visit(n.body, builder, ast_context) + case ^Bit_Field_Type: + write_semantic_string( + builder, + n.pos, + "bit_field", + ast_context.file.src, + .Keyword, + .None, + ) + visit_bit_field_fields(n^, builder, ast_context) case: } } @@ -1050,6 +1060,27 @@ visit_struct_fields :: proc( } } +visit_bit_field_fields :: proc( + node: ast.Bit_Field_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { + for field in node.fields { + if ident, ok := field.name.derived.(^ast.Ident); ok { + write_semantic_node( + builder, + ident, + ast_context.file.src, + .Property, + .None, + ) + } + + visit(field.type, builder, ast_context) + visit(field.bit_size, builder, ast_context) + } +} + visit_selector :: proc( selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, @@ -1125,6 +1156,14 @@ visit_selector :: proc( .Function, .None, ) + case SymbolBitFieldValue: + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Struct, + .None, + ) } } } diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 10750a8d..31c5fa80 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -28,6 +28,12 @@ SymbolStructValue :: struct { args: []^ast.Expr, //The arguments in the call expression for poly } +SymbolBitFieldValue :: struct { + names: []string, + ranges: []common.Range, + types: []^ast.Expr, +} + SymbolPackageValue :: struct {} SymbolProcedureValue :: struct { @@ -126,6 +132,7 @@ SymbolValue :: union { SymbolBasicValue, SymbolUntypedValue, SymbolMatrixValue, + SymbolBitFieldValue, } SymbolFlag :: enum { @@ -185,7 +192,8 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { symbol.signature != "struct" && symbol.signature != "union" && symbol.signature != "enum" && - symbol.signature != "bitset" { + symbol.signature != "bitset" && + symbol.signature != "bit_field" { delete(symbol.signature, allocator) } @@ -235,6 +243,9 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { case SymbolUntypedValue: delete(v.tok.text) case SymbolPackageValue: + case SymbolBitFieldValue: + delete(v.names, allocator) + common.free_ast(v.types, allocator) } } @@ -346,6 +357,9 @@ symbol_to_expr :: proc( type.params = new_type(ast.Field_List, pos, end, allocator) type.params.list = v.arg_types return type + case SymbolBitFieldValue: + type := new_type(ast.Bit_Field_Type, pos, end, allocator) + return type case: return nil } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 7ca39463..cde8ffd0 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -2633,3 +2633,30 @@ ast_completion_infer_bitset_package :: proc(t: ^testing.T) { test.expect_completion_labels(t, &source, ".", {"ONE", "TWO"}) } + +@(test) +ast_simple_bit_field_completion :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + + My_Bit_Field :: bit_field uint { + one: int | 1, + two: int | 1, + three: int | 1, + } + + main :: proc() { + my_bit_field: My_Bit_Field; + my_bit_field.{*} + } + `, + packages = {}, + } + + test.expect_completion_details( + t, + &source, + ".", + {"My_Bit_Field.one: int", "My_Bit_Field.two: int", "My_Bit_Field.three: int"}, + ) +} diff --git a/tests/definition_test.odin b/tests/definition_test.odin index bf9fcd7d..5c60dc87 100644 --- a/tests/definition_test.odin +++ b/tests/definition_test.odin @@ -89,3 +89,86 @@ ast_goto_untyped_comp_lit_in_proc :: proc(t: ^testing.T) { test.expect_definition_locations(t, &source, {location}) } + +@(test) +ast_goto_bit_field_definition :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + My_Bit_Field :: bit_field uint { + one: int | 1, + two: int | 1, + } + + main :: proc() { + it: My_B{*}it_Field + } + `, + packages = {}, + } + + location := common.Location { + range = { + start = {line = 1, character = 3}, + end = {line = 1, character = 15}, + }, + } + + test.expect_definition_locations(t, &source, {location}) +} + +@(test) +ast_goto_bit_field_field_definition :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + My_Bit_Field :: bit_field uint { + one: int | 1, + two: int | 1, + } + + main :: proc() { + it: My_Bit_Field + it.on{*}e + } + `, + packages = {}, + } + + location := common.Location { + range = { + start = {line = 2, character = 4}, + end = {line = 2, character = 7}, + }, + } + + test.expect_definition_locations(t, &source, {location}) +} + +@(test) +ast_goto_bit_field_field_in_proc :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + My_Struct :: bit_field uint { + one: int | 1, + two: int | 2, + } + + my_function :: proc(my_struct: My_Struct) { + + } + + main :: proc() { + my_function({on{*}e = 2, two = 3}) + } + `, + packages = {}, + } + + location := common.Location { + range = { + start = {line = 2, character = 4}, + end = {line = 2, character = 7}, + }, + } + + test.expect_definition_locations(t, &source, {location}) +}