diff options
| author | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-06-09 14:32:59 -0400 |
|---|---|---|
| committer | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-06-13 15:23:36 -0400 |
| commit | 8816d531da666959b7df0c64401b8fa064b0cd3d (patch) | |
| tree | 893cf9b15bb610f13b2c6cf3c2c3148166341ed4 /src/server/analysis.odin | |
| parent | 023c8a0fd1d8d8e54b38bf990a74816a31dee68e (diff) | |
Add textDocument/typeDefinition support
Diffstat (limited to 'src/server/analysis.odin')
| -rw-r--r-- | src/server/analysis.odin | 238 |
1 files changed, 163 insertions, 75 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 1a7e4a7..9e43467 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -796,6 +796,39 @@ check_node_recursion :: proc(ast_context: ^AstContext, node: ^ast.Node) -> bool return false } +// Resolves the location of the underlying type of the expression +resolve_location_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (Symbol, bool) { + if node == nil { + return {}, false + } + + //Try to prevent stack overflows and prevent indexing out of bounds. + if ast_context.deferred_count >= DeferredDepth { + return {}, false + } + + set_ast_package_scoped(ast_context) + + if check_node_recursion(ast_context, node) { + return {}, false + } + + // TODO: there is likely more of these that will be needed as well. + // I think we'll need a better way to manage this all + #partial switch n in node.derived { + case ^ast.Ident: + if _, ok := common.keyword_map[n.name]; ok { + return {}, true + } + return resolve_location_type_identifier(ast_context, n^) + case ^ast.Basic_Lit: + return {}, true + case ^ast.Array_Type: + return resolve_location_type_expression(ast_context, n.elem) + } + return resolve_type_expression(ast_context, node) +} + resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (Symbol, bool) { clear(&ast_context.recursion_map) return internal_resolve_type_expression(ast_context, node) @@ -929,7 +962,7 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex } case ^Proc_Lit: if v.type.results != nil { - if len(v.type.results.list) == 1 { + if len(v.type.results.list) > 0 { return internal_resolve_type_expression(ast_context, v.type.results.list[0].type) } } @@ -1004,96 +1037,123 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex return selector, true } case ^Selector_Expr: - if selector, ok := internal_resolve_type_expression(ast_context, v.expr); ok { - ast_context.use_locals = false + return resolve_selector_expression(ast_context, v) + case ^ast.Poly_Type: + if v.specialization != nil { + return internal_resolve_type_expression(ast_context, v.specialization) + } - set_ast_package_from_symbol_scoped(ast_context, selector) + case: + log.warnf("default node kind, internal_resolve_type_expression: %v", v) + } - #partial switch s in selector.value { - case SymbolFixedArrayValue: - components_count := 0 - for c in v.field.name { - if c == 'x' || c == 'y' || c == 'z' || c == 'w' || c == 'r' || c == 'g' || c == 'b' || c == 'a' { - components_count += 1 - } else { - return {}, false - } - } + return Symbol{}, false +} - if components_count == 0 { - return {}, false - } +resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selector_Expr) -> (Symbol, bool) { + if selector, ok := internal_resolve_type_expression(ast_context, node.expr); ok { + ast_context.use_locals = false - if components_count == 1 { - set_ast_package_from_symbol_scoped(ast_context, selector) + set_ast_package_from_symbol_scoped(ast_context, selector) - symbol, ok := internal_resolve_type_expression(ast_context, s.expr) - symbol.type = .Variable - return symbol, ok + #partial switch s in selector.value { + case SymbolFixedArrayValue: + components_count := 0 + for c in node.field.name { + if c == 'x' || c == 'y' || c == 'z' || c == 'w' || c == 'r' || c == 'g' || c == 'b' || c == 'a' { + components_count += 1 } else { - value := SymbolFixedArrayValue { - expr = s.expr, - len = make_int_basic_value(ast_context, components_count, s.len.pos, s.len.end), - } - selector.value = value - selector.type = .Variable - return selector, true + return {}, false } - case SymbolProcedureValue: - if len(s.return_types) == 1 { - selector_expr := new_type( - ast.Selector_Expr, - s.return_types[0].node.pos, - s.return_types[0].node.end, - ast_context.allocator, - ) - selector_expr.expr = s.return_types[0].type - selector_expr.field = v.field + } + + if components_count == 0 { + return {}, false + } + + if components_count == 1 { + set_ast_package_from_symbol_scoped(ast_context, selector) - return internal_resolve_type_expression(ast_context, selector_expr) + symbol, ok := internal_resolve_type_expression(ast_context, s.expr) + symbol.type = .Variable + return symbol, ok + } else { + value := SymbolFixedArrayValue { + expr = s.expr, + len = make_int_basic_value(ast_context, components_count, s.len.pos, s.len.end), } - case SymbolStructValue: - 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 - } + selector.value = value + selector.type = .Variable + return selector, true + } + case SymbolProcedureValue: + if len(s.return_types) == 1 { + selector_expr := new_type( + ast.Selector_Expr, + s.return_types[0].node.pos, + s.return_types[0].node.end, + ast_context.allocator, + ) + selector_expr.expr = s.return_types[0].type + selector_expr.field = node.field + + return internal_resolve_type_expression(ast_context, selector_expr) + } + case SymbolStructValue: + for name, i in s.names { + if node.field != nil && name == node.field.name { + ast_context.field_name = node.field^ + symbol, ok := internal_resolve_type_expression(ast_context, s.types[i]) + symbol.type = .Variable + 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 SymbolBitFieldValue: + for name, i in s.names { + if node.field != nil && name == node.field.name { + ast_context.field_name = node.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) + } + case SymbolPackageValue: + try_build_package(ast_context.current_package) - if v.field != nil { - return resolve_symbol_return(ast_context, lookup(v.field.name, selector.pkg)) - } else { - return Symbol{}, false - } - case SymbolEnumValue: - // enum members probably require own symbol value - selector.type = .EnumMember - return selector, true + if node.field != nil { + return resolve_symbol_return(ast_context, lookup(node.field.name, selector.pkg)) + } else { + return Symbol{}, false } + case SymbolEnumValue: + // enum members probably require own symbol value + selector.type = .EnumMember + return selector, true } - case ^ast.Poly_Type: - if v.specialization != nil { - return internal_resolve_type_expression(ast_context, v.specialization) - } - - case: - log.warnf("default node kind, internal_resolve_type_expression: %v", v) } - return Symbol{}, false + return {}, false +} + +// returns the symbol of the first return type of a proc +resolve_symbol_proc_first_return_symbol :: proc(ast_context: ^AstContext, symbol: Symbol) -> (Symbol, bool) { + if v, ok := symbol.value.(SymbolProcedureValue); ok { + if len(v.return_types) > 0 { + if ast_context.current_package != symbol.pkg { + current_package := ast_context.current_package + defer { + ast_context.current_package = current_package + } + ast_context.current_package = symbol.pkg + return resolve_type_expression(ast_context, v.return_types[0].type) + } else { + return resolve_location_type_expression(ast_context, v.return_types[0].type) + } + } else { + return {}, true + } + } + return {}, false } store_local :: proc( @@ -1962,6 +2022,33 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> return true } +// Resolves the location of the underlying type of the identifier +resolve_location_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { + // TODO: will likely need to clean this up and find a way for this flow to make sense. + // Ideally we need a way to extract the full symbol of a global + if local, ok := get_local(ast_context^, node); ok { + #partial switch n in local.rhs.derived { + case ^ast.Ident: + return resolve_location_identifier(ast_context, n^) + case ^ast.Basic_Lit: + return {}, true + case ^ast.Array_Type: + if elem, ok := n.elem.derived.(^ast.Ident); ok { + return resolve_location_identifier(ast_context, elem^) + } + case ^ast.Selector_Expr: + return resolve_selector_expression(ast_context, n) + } + } else if global, ok := ast_context.globals[node.name]; ok { + if v, ok := global.expr.derived.(^ast.Proc_Lit); ok { + if symbol, ok := resolve_type_expression(ast_context, global.name_expr); ok { + return symbol, ok + } + } + } + return resolve_location_identifier(ast_context, node) +} + resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { symbol: Symbol @@ -1994,6 +2081,7 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) - return {}, false } + resolve_location_comp_lit_field :: proc( ast_context: ^AstContext, position_context: ^DocumentPositionContext, |