diff options
| author | Daniel Gavin <danielgavin5@hotmail.com> | 2022-07-30 02:47:07 +0200 |
|---|---|---|
| committer | Daniel Gavin <danielgavin5@hotmail.com> | 2022-07-30 02:47:07 +0200 |
| commit | 992edc6330e07e5e63b867fc34ebf30250d6dabd (patch) | |
| tree | 8d87a5837c3c5ec4557863302b297ec62e76bded /src | |
| parent | 0fc9da70bdc160ec6caf4cf5ffe50408a24d6d7a (diff) | |
working on supporting references
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/ast.odin | 3 | ||||
| -rw-r--r-- | src/server/analysis.odin | 215 | ||||
| -rw-r--r-- | src/server/collector.odin | 10 | ||||
| -rw-r--r-- | src/server/definition.odin | 50 | ||||
| -rw-r--r-- | src/server/references.odin | 110 | ||||
| -rw-r--r-- | src/server/symbol.odin | 9 | ||||
| -rw-r--r-- | src/server/types.odin | 2 |
7 files changed, 244 insertions, 155 deletions
diff --git a/src/common/ast.odin b/src/common/ast.odin index c3be1fe..71f74a4 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -67,6 +67,7 @@ keyword_map: map[string]bool = { GlobalExpr :: struct { name: string, + name_expr: ^ast.Expr, expr: ^ast.Expr, mutable: bool, docs: ^ast.Comment_Group, @@ -142,6 +143,7 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a if value_decl.type != nil { append(exprs, GlobalExpr { name = str, + name_expr = name, expr = value_decl.type, mutable = value_decl.is_mutable, docs = value_decl.docs, @@ -153,6 +155,7 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a if len(value_decl.values) > i { append(exprs, GlobalExpr { name = str, + name_expr = name, expr = value_decl.values[i], mutable = value_decl.is_mutable, docs = value_decl.docs, diff --git a/src/server/analysis.odin b/src/server/analysis.odin index f130935..bd4f7d4 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -30,6 +30,7 @@ DocumentPositionContext :: struct { line: int, function: ^ast.Proc_Lit, //used to help with type resolving in function scope selector: ^ast.Expr, //used for completion + selector_expr: ^ast.Selector_Expr, identifier: ^ast.Node, implicit_context: ^ast.Implicit, tag: ^ast.Node, @@ -38,6 +39,10 @@ DocumentPositionContext :: struct { returns: ^ast.Return_Stmt, //used for completion comp_lit: ^ast.Comp_Lit, //used for completion parent_comp_lit: ^ast.Comp_Lit, //used for completion + struct_type: ^ast.Struct_Type, + union_type: ^ast.Union_Type, + bitset_type: ^ast.Bit_Set_Type, + enum_type: ^ast.Enum_Type, field_value: ^ast.Field_Value, implicit: bool, //used for completion arrow: bool, @@ -80,7 +85,7 @@ AstContext :: struct { call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions position: common.AbsolutePosition, value_decl: ^ast.Value_Decl, - field_name: string, + field_name: ast.Ident, uri: string, fullpath: string, recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion. @@ -846,7 +851,6 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S if ast_context.recursion_counter > 200 { log.error("Recursion passed 200 attempts - giving up", node) - assert(false) return {}, false } @@ -1026,7 +1030,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S for name, i in s.names { if v.field != nil && name == v.field.name { - ast_context.field_name = v.field.name + ast_context.field_name = v.field^ symbol, ok := resolve_type_expression(ast_context, s.types[i]) symbol.type = .Variable return symbol, ok @@ -1146,7 +1150,6 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S if ast_context.recursion_counter > 200 { log.error("Recursion passed 200 attempts - giving up", node) - assert(false) return {}, false } @@ -1227,33 +1230,33 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node.name), true + return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true } else { if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node.name), true + return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name @@ -1293,33 +1296,33 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node.name), true + return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true } else { if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node.name), true + return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node.name), true + return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name @@ -1407,6 +1410,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: SymbolStructValue) -> SymbolStructValue { names := slice.to_dynamic(value.names, ast_context.allocator) types := slice.to_dynamic(value.types, ast_context.allocator) + ranges := slice.to_dynamic(value.ranges, ast_context.allocator) for k, v in value.usings { ast_context.current_package = symbol.pkg @@ -1433,6 +1437,10 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: Sy for type in struct_value.types { append(&types, type) } + + for range in struct_value.ranges { + append(&ranges, range) + } } } } @@ -1440,6 +1448,7 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: Sy return { names = names[:], types = types[:], + ranges = ranges[:], } } @@ -1575,6 +1584,46 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) - return {}, false } +resolve_location_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selector_Expr) -> (Symbol, bool) { + ast_context.use_locals = true + ast_context.use_globals = true + ast_context.current_package = ast_context.document_package + + symbol, ok := resolve_type_expression(ast_context, selector.expr) + + if !ok { + return {}, false + } + + field: string + + if selector.field != nil { + #partial switch v in selector.field.derived { + case ^ast.Ident: + field = v.name + } + } + + #partial switch v in symbol.value { + case SymbolStructValue: + 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 + symbol.uri = pkg.uri + } else { + return {}, false + } + } + + return symbol, true +} + + resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, binary: ^ast.Binary_Expr) -> (Symbol, bool) { //Fairly simple function to find the earliest identifier symbol in binary expression. @@ -1669,12 +1718,12 @@ get_using_packages :: proc(ast_context: ^AstContext) -> []string { return usings } -make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: string) -> Symbol { +make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: ast.Ident) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), type = .Function, pkg = get_package_from_node(n^), - name = name, + name = name.name, } return_types := make([dynamic]^ast.Field, ast_context.allocator) @@ -1692,7 +1741,7 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v } } - if expr, ok := ast_context.globals[name]; ok { + if expr, ok := ast_context.globals[name.name]; ok { if expr.deprecated { symbol.flags |= {.Distinct} } @@ -1701,17 +1750,18 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v symbol.value = SymbolProcedureValue { return_types = return_types[:], arg_types = arg_types[:], + generic = v.generic, } return symbol } -make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, name: string) -> Symbol { +make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, name: ast.Ident) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), type = .Variable, pkg = get_package_from_node(v.node), - name = name, + name = name.name, } if v.len != nil { @@ -1728,12 +1778,12 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, return symbol } -make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type, name: string) -> Symbol { +make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type, name: ast.Ident) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), type = .Variable, pkg = get_package_from_node(v.node), - name = name, + name = name.name, } symbol.value = SymbolDynamicArrayValue { @@ -1743,12 +1793,12 @@ make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dyna return symbol } -make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Multi_Pointer_Type, name: string) -> Symbol { +make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Multi_Pointer_Type, name: ast.Ident) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), type = .Variable, pkg = get_package_from_node(v.node), - name = name, + name = name.name, } symbol.value = SymbolMultiPointer { @@ -1758,12 +1808,12 @@ make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Mult return symbol } -make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type, name: string) -> Symbol { +make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type, name: ast.Ident) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), type = .Variable, pkg = get_package_from_node(v.node), - name = name, + name = name.name, } symbol.value = SymbolMapValue { @@ -1788,12 +1838,12 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, return symbol } -make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: string, inlined := false) -> Symbol { +make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: ast.Ident, 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 = ident.name, } if inlined { @@ -1822,11 +1872,11 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, return symbol } -make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: string, inlined := false) -> Symbol { +make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: ast.Ident, inlined := false) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, - name = ident, + name = ident.name, pkg = get_package_from_node(v.node), } @@ -1857,11 +1907,11 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id return symbol } -make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: string, inlined := false) -> Symbol { +make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: ast.Ident, inlined := false) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), type = .Enum, - name = ident, + name = ident.name, pkg = get_package_from_node(v.node), } @@ -1877,12 +1927,12 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ return symbol } -make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: string, inlined := false) -> Symbol { +make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_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 = ident.name, } if inlined { @@ -1890,9 +1940,10 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type symbol.name = "struct" } - names := make([dynamic]string, ast_context.allocator) - types := make([dynamic]^ast.Expr, ast_context.allocator) + names := make([dynamic]string, ast_context.allocator) + types := make([dynamic]^ast.Expr, ast_context.allocator) usings := make(map[string]bool, 0, ast_context.allocator) + ranges := make([dynamic]common.Range, 0, ast_context.allocator) for field in v.fields.list { for n in field.names { @@ -1909,6 +1960,8 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type if .Using in field.flags { usings[identifier.name] = true } + + append(&ranges, common.get_token_range(n, ast_context.file.src)) } } } @@ -1916,6 +1969,7 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type symbol.value = SymbolStructValue { names = names[:], types = types[:], + ranges = ranges[:], usings = usings, } @@ -2487,8 +2541,9 @@ clear_locals :: proc(ast_context: ^AstContext) { ResolveReferenceFlag :: enum { None, - Identifier, - Call, + Variable, + Constant, + StructElement, } resolve_entire_file :: proc(document: ^Document, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) -> map[uintptr]SymbolAndNode { @@ -2501,14 +2556,14 @@ resolve_entire_file :: proc(document: ^Document, reference := "", flag := Resolv symbols := make(map[uintptr]SymbolAndNode, 10000, allocator) for decl in document.ast.decls { - resolve_entire_decl(&ast_context, decl, &symbols, reference, flag, allocator) + resolve_entire_decl(&ast_context, document, decl, &symbols, reference, flag, allocator) clear(&ast_context.locals) } return symbols } -resolve_entire_decl :: proc(ast_context: ^AstContext, decl: ^ast.Node, symbols: ^map[uintptr]SymbolAndNode, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) { +resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: ^ast.Node, symbols: ^map[uintptr]SymbolAndNode, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) { Scope :: struct { offset: int, id: int, @@ -2522,6 +2577,7 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, decl: ^ast.Node, symbols: last_visit: ^ast.Node, resolve_flag: ResolveReferenceFlag, reference: string, + document: ^Document, } data := Visit_Data { @@ -2530,6 +2586,7 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, decl: ^ast.Node, symbols: scopes = make([dynamic]Scope, allocator), resolve_flag = flag, reference = reference, + document = document, } visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { @@ -2622,16 +2679,37 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, decl: ^ast.Node, symbols: } } else { #partial done: switch v in node.derived { + case ^ast.Selector_Expr: + document : ^Document = data.document + + position_context := DocumentPositionContext { + position = v.pos.offset, + } + + get_document_position_decls(document.ast.decls[:], &position_context) + + if symbol, ok := resolve_location_selector(ast_context, v); ok { + data.symbols[cast(uintptr)node] = SymbolAndNode { + node = v, + symbol = symbol, + } + } case ^ast.Ident: - if data.resolve_flag != .Identifier { + if data.resolve_flag == .Variable && v.name != data.reference { break done } - if v.name != data.reference { - break done + document : ^Document = data.document + + position_context := DocumentPositionContext { + position = v.pos.offset, } - //get_document_position() + get_document_position_decls(document.ast.decls[:], &position_context) + + if position_context.field_value != nil && position_in_node(position_context.field_value.field, v.pos.offset) { + break done + } if symbol, ok := resolve_location_identifier(ast_context, v^); ok { data.symbols[cast(uintptr)node] = SymbolAndNode { @@ -2888,6 +2966,22 @@ type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string { return common.node_to_string(expr) } +get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^DocumentPositionContext) -> bool { + exists_in_decl := false + for decl in decls { + if position_in_node(decl, position_context.position) { + get_document_position(decl, position_context) + exists_in_decl = true + #partial switch v in decl.derived { + case ^ast.Expr_Stmt: + position_context.global_lhs_stmt = true + } + break + } + } + return exists_in_decl +} + /* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ @@ -2907,19 +3001,7 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.position = absolute_position - exists_in_decl := false - - for decl in document.ast.decls { - if position_in_node(decl, position_context.position) { - get_document_position(decl, &position_context) - exists_in_decl = true - #partial switch v in decl.derived { - case ^ast.Expr_Stmt: - position_context.global_lhs_stmt = true - } - break - } - } + exists_in_decl := get_document_position_decls(document.ast.decls[:], &position_context) for import_stmt in document.ast.imports { if position_in_node(import_stmt, position_context.position) { @@ -3340,6 +3422,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP } else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil { position_context.selector = n.expr position_context.field = n.field + position_context.selector_expr = cast(^Selector_Expr)node get_document_position(n.expr, position_context) get_document_position(n.field, position_context) } else { @@ -3495,17 +3578,21 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP case ^Multi_Pointer_Type: get_document_position(n.elem, position_context) case ^Struct_Type: + position_context.struct_type = cast(^Struct_Type)node get_document_position(n.poly_params, position_context) get_document_position(n.align, position_context) get_document_position(n.fields, position_context) case ^Union_Type: + position_context.union_type = cast(^Union_Type)node get_document_position(n.poly_params, position_context) get_document_position(n.align, position_context) get_document_position(n.variants, position_context) case ^Enum_Type: + position_context.enum_type = cast(^Enum_Type)node get_document_position(n.base_type, position_context) get_document_position(n.fields, position_context) case ^Bit_Set_Type: + position_context.bitset_type = cast(^Bit_Set_Type)node get_document_position(n.elem, position_context) get_document_position(n.underlying, position_context) case ^Map_Type: diff --git a/src/server/collector.odin b/src/server/collector.odin index 53486ad..464b22f 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -93,10 +93,11 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. return value } -collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.Struct_Type, package_map: map[string]string) -> SymbolStructValue { +collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.Struct_Type, package_map: map[string]string, file: ast.File) -> SymbolStructValue { names := make([dynamic]string, 0, collection.allocator) types := make([dynamic]^ast.Expr, 0, collection.allocator) usings := make(map[string]bool, 0, collection.allocator) + ranges := make([dynamic]common.Range, 0, collection.allocator) for field in struct_type.fields.list { for n in field.names { @@ -110,12 +111,15 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St if .Using in field.flags { usings[names[len(names) - 1]] = true } + + append(&ranges, common.get_token_range(n, file.src)) } } value := SymbolStructValue { names = names[:], types = types[:], + ranges = ranges[:], usings = usings, poly = cast(^ast.Field_List)clone_type(struct_type.poly_params, collection.allocator, &collection.unique_strings), } @@ -304,7 +308,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri case ^ast.Struct_Type: token = v^ token_type = .Struct - symbol.value = collect_struct_fields(collection, v^, package_map) + symbol.value = collect_struct_fields(collection, v^, package_map, file) symbol.signature = "struct" case ^ast.Enum_Type: token = v^ @@ -367,7 +371,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri token = expr.expr } - symbol.range = common.get_token_range(token, file.src) + symbol.range = common.get_token_range(expr.name_expr, file.src) symbol.name = get_index_unique_string(collection, name) symbol.type = token_type symbol.doc = common.get_doc(expr.docs, collection.allocator) diff --git a/src/server/definition.odin b/src/server/definition.odin index 6a0d07b..9a4660e 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -38,7 +38,7 @@ get_definition_location :: proc(document: ^Document, position: common.Position) get_locals(document.ast, position_context.function, &ast_context, &position_context) } - if position_context.selector != nil { + if position_context.selector_expr != nil { //if the base selector is the client wants to go to. if base, ok := position_context.selector.derived.(^ast.Ident); ok && position_context.identifier != nil { ident := position_context.identifier.derived.(^ast.Ident) @@ -62,51 +62,9 @@ get_definition_location :: proc(document: ^Document, position: common.Position) } } - //otherwise it's the field the client wants to go to. - - selector: Symbol - - ast_context.use_locals = true - ast_context.use_globals = true - ast_context.current_package = ast_context.document_package - - selector, ok = resolve_type_expression(&ast_context, position_context.selector) - - if !ok { - return {}, false - } - - field: string - - if position_context.field != nil { - #partial switch v in position_context.field.derived { - case ^ast.Ident: - field = v.name - } - } - - uri = selector.uri - - #partial switch v in selector.value { - case SymbolEnumValue: - location.range = selector.range - case SymbolStructValue: - for name, i in v.names { - if strings.compare(name, field) == 0 { - location.range = common.get_token_range(v.types[i]^, document.ast.src) - } - } - case SymbolPackageValue: - if symbol, ok := lookup(field, selector.pkg); ok { - location.range = symbol.range - uri = symbol.uri - } else { - return {}, false - } - } - - if !ok { - return {}, false + if resolved, ok := resolve_location_selector(&ast_context, position_context.selector_expr); ok { + location.range = resolved.range + uri = resolved.uri } } else if position_context.identifier != nil { if resolved, ok := resolve_location_identifier(&ast_context, position_context.identifier.derived.(^ast.Ident)^); ok { diff --git a/src/server/references.odin b/src/server/references.odin index 4fd6dec..28f811c 100644 --- a/src/server/references.odin +++ b/src/server/references.odin @@ -26,16 +26,28 @@ walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno } if strings.contains(info.name, ".odin") { - append(&fullpaths, strings.clone(info.fullpath, runtime.default_allocator())) + append(&fullpaths, strings.clone(info.fullpath, context.allocator)) } return 0, false } +position_in_struct_names :: proc(position_context: ^DocumentPositionContext, type: ^ast.Struct_Type) -> bool { + for field in type.fields.list { + for name in field.names { + if position_in_node(name, position_context.position) { + return true + } + } + } + + return false +} + resolve_references :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext) -> ([]common.Location, bool) { - locations := make([dynamic]common.Location, 0, context.allocator) - fullpaths = make([dynamic]string, 10, context.allocator) + locations := make([dynamic]common.Location, 0, ast_context.allocator) + fullpaths = make([dynamic]string, 10, ast_context.allocator) resolve_flag: ResolveReferenceFlag reference := "" @@ -43,41 +55,54 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document ok: bool pkg := "" - if position_context.selector != nil { - - } else if position_context.call != nil { + walker_arena: mem.Arena + mem.init_arena(&walker_arena, make([]byte, mem.Megabyte*5)) + + { + context.temp_allocator = mem.arena_allocator(&walker_arena) + filepath.walk(filepath.dir(os.args[0], context.allocator), walk_directories) + } + if position_context.struct_type != nil && position_in_struct_names(position_context, position_context.struct_type) { + return {}, true + } else if position_context.enum_type != nil { + return {}, true + } else if position_context.bitset_type != nil { + return {}, true + } else if position_context.union_type != nil { + return {}, true + } else if position_context.selector_expr != nil { + return {}, true } else if position_context.identifier != nil { - resolve_flag = .Identifier ident := position_context.identifier.derived.(^ast.Ident) + + if resolved, ok := resolve_type_identifier(ast_context, ident^); ok { + if resolved.type == .Variable { + resolve_flag = .Variable + } else { + resolve_flag = .Constant + } + } + reference = ident.name symbol, ok = resolve_location_identifier(ast_context, ident^) location := common.Location { range = common.get_token_range(position_context.identifier^, string(ast_context.file.src)), - uri = strings.clone(symbol.uri, runtime.default_allocator()), - } + uri = strings.clone(symbol.uri, ast_context.allocator), + } + append(&locations, location) } if !ok { - return {}, false + return {}, true } - symbol_uri := strings.clone(symbol.uri, context.allocator) - symbol_pkg := strings.clone(symbol.pkg, context.allocator) - symbol_range := symbol.range - - temp_arena: mem.Arena + resolve_arena: mem.Arena + mem.init_arena(&resolve_arena, make([]byte, mem.Megabyte*25)) - mem.init_arena(&temp_arena, make([]byte, mem.Megabyte*25, runtime.default_allocator())) - - context.allocator = mem.arena_allocator(&temp_arena) - - { - context.temp_allocator = context.allocator - filepath.walk(filepath.dir(os.args[0], context.temp_allocator), walk_directories) - } + context.allocator = mem.arena_allocator(&resolve_arena) for fullpath in fullpaths { data, ok := os.read_entire_file(fullpath, context.allocator) @@ -134,7 +159,7 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document in_pkg := false for pkg in document.imports { - if pkg.name == symbol_pkg || symbol.pkg == ast_context.document_package { + if pkg.name == symbol.pkg || symbol.pkg == ast_context.document_package { in_pkg = true } } @@ -143,33 +168,32 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document symbols_and_nodes := resolve_entire_file(&document, reference, resolve_flag, context.allocator) for k, v in symbols_and_nodes { - if v.symbol.uri == symbol_uri && v.symbol.range == symbol_range { + if v.symbol.uri == symbol.uri && v.symbol.range == symbol.range { location := common.Location { range = common.get_token_range(v.node^, string(document.text)), - uri = strings.clone(v.symbol.uri, runtime.default_allocator()), + uri = strings.clone(v.symbol.uri, ast_context.allocator), } append(&locations, location) } } } - - - delete(fullpath) free_all(context.allocator) } - delete(fullpaths) - delete(temp_arena.data) - delete(symbol_uri) - - - return locations[:], true } get_references :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + data := make([]byte, mem.Megabyte*55, runtime.default_allocator()) + //defer delete(data) + + arena: mem.Arena + mem.init_arena(&arena, data) + + context.allocator = mem.arena_allocator(&arena) + + ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath, context.allocator) position_context, ok := get_document_position_context(document, position, .Hover) @@ -181,5 +205,17 @@ get_references :: proc(document: ^Document, position: common.Position) -> ([]com get_locals(document.ast, position_context.function, &ast_context, &position_context) } - return resolve_references(&ast_context, &position_context) + locations, ok2 := resolve_references(&ast_context, &position_context) + + temp_locations := make([dynamic]common.Location, 0, context.temp_allocator) + + for location in locations { + temp_location := common.Location { + range = location.range, + uri = strings.clone(location.uri, context.temp_allocator), + } + append(&temp_locations, temp_location) + } + + return temp_locations[:], ok2 }
\ No newline at end of file diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 2d11114..4b4eea7 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -16,10 +16,11 @@ SymbolAndNode :: struct { } SymbolStructValue :: struct { - names: []string, - types: []^ast.Expr, - usings: map[string]bool, - poly: ^ast.Field_List, + names: []string, + ranges: []common.Range, + types: []^ast.Expr, + usings: map[string]bool, + poly: ^ast.Field_List, } SymbolPackageValue :: struct {} diff --git a/src/server/types.odin b/src/server/types.odin index 6cab934..78e7241 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -147,7 +147,7 @@ CompletionItemCapabilities :: struct { CompletionClientCapabilities :: struct { documentationFormat: [dynamic]string, completionItem: CompletionItemCapabilities, -} +} ParameterInformationCapabilities :: struct { labelOffsetSupport: bool, |