aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBradley Lewis <22850972+BradLewis@users.noreply.github.com>2026-01-27 20:26:02 +1100
committerGitHub <noreply@github.com>2026-01-27 20:26:02 +1100
commit22f7394233da7b68ce78d370d62105456bdaecb0 (patch)
treec53cf0ea039699ad78e237b96d7eb882960369f0 /src
parenta243fa37d7735dc8777d445d2d3c9965f92f9c02 (diff)
parentaa993b9b366c79b978fb0901fdd75295f9cc0426 (diff)
Merge pull request #1263 from pnarimani/overload_resolution
Procedure Overload Resolution
Diffstat (limited to 'src')
-rw-r--r--src/common/config.odin1
-rw-r--r--src/server/definition.odin129
-rw-r--r--src/server/requests.odin4
-rw-r--r--src/server/types.odin1
-rw-r--r--src/testing/testing.odin2
5 files changed, 130 insertions, 7 deletions
diff --git a/src/common/config.odin b/src/common/config.odin
index 441e8a9..f2ae68f 100644
--- a/src/common/config.odin
+++ b/src/common/config.odin
@@ -33,6 +33,7 @@ Config :: struct {
enable_std_references: bool,
enable_import_fixer: bool,
enable_fake_method: bool,
+ enable_overload_resolution: bool,
enable_procedure_snippet: bool,
enable_checker_only_saved: bool,
enable_auto_import: bool,
diff --git a/src/server/definition.odin b/src/server/definition.odin
index c793f32..869816c 100644
--- a/src/server/definition.odin
+++ b/src/server/definition.odin
@@ -42,7 +42,7 @@ get_all_package_file_locations :: proc(
return true
}
-get_definition_location :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) {
+get_definition_location :: proc(document: ^Document, position: common.Position, config: ^common.Config) -> ([]common.Location, bool) {
locations := make([dynamic]common.Location, context.temp_allocator)
location: common.Location
@@ -100,6 +100,14 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
}
if resolved, ok := resolve_location_selector(&ast_context, position_context.selector_expr); ok {
+ if config.enable_overload_resolution {
+ resolved = try_resolve_proc_group_overload(
+ &ast_context,
+ &position_context,
+ resolved,
+ position_context.selector_expr,
+ )
+ }
location.range = resolved.range
uri = resolved.uri
} else {
@@ -139,12 +147,12 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
&ast_context,
position_context.identifier.derived.(^ast.Ident)^,
); ok {
+ if config.enable_overload_resolution {
+ resolved = try_resolve_proc_group_overload(&ast_context, &position_context, resolved)
+ }
if v, ok := resolved.value.(SymbolAggregateValue); ok {
for symbol in v.symbols {
- append(&locations, common.Location {
- range = symbol.range,
- uri = symbol.uri,
- })
+ append(&locations, common.Location{range = symbol.range, uri = symbol.uri})
}
}
location.range = resolved.range
@@ -167,3 +175,114 @@ get_definition_location :: proc(document: ^Document, position: common.Position)
return locations[:], true
}
+
+
+try_resolve_proc_group_overload :: proc(
+ ast_context: ^AstContext,
+ position_context: ^DocumentPositionContext,
+ symbol: Symbol,
+ selector_expr: ^ast.Node = nil,
+) -> Symbol {
+ if position_context.call == nil {
+ return symbol
+ }
+
+ call, is_call := position_context.call.derived.(^ast.Call_Expr)
+ if !is_call {
+ return symbol
+ }
+
+ if position_in_exprs(call.args, position_context.position) {
+ return symbol
+ }
+
+ // For selector expressions, we need to look up the full symbol to check if it's a proc group
+ full_symbol := symbol
+ if result, ok := get_full_symbol_from_selector(ast_context, selector_expr, symbol); ok {
+ full_symbol = result
+ } else if result, ok := get_full_symbol_from_identifier(ast_context, position_context, symbol); ok {
+ full_symbol = result
+ }
+
+ proc_group_value, is_proc_group := full_symbol.value.(SymbolProcedureGroupValue)
+ if !is_proc_group {
+ return symbol
+ }
+
+ old_call := ast_context.call
+ ast_context.call = call
+ defer {
+ ast_context.call = old_call
+ }
+
+ if resolved, ok := resolve_function_overload(ast_context, proc_group_value.group.derived.(^ast.Proc_Group)); ok {
+ if resolved.name != "" {
+ if global, ok := ast_context.globals[resolved.name]; ok {
+ resolved.range = common.get_token_range(global.name_expr, ast_context.file.src)
+ resolved.uri = common.create_uri(global.name_expr.pos.file, ast_context.allocator).uri
+ } else if indexed_symbol, ok := lookup(resolved.name, resolved.pkg, ast_context.fullpath); ok {
+ resolved.range = indexed_symbol.range
+ resolved.uri = indexed_symbol.uri
+ }
+ }
+ return resolved
+ }
+
+ return symbol
+}
+
+get_full_symbol_from_selector :: proc(
+ ast_context: ^AstContext,
+ selector_expr: ^ast.Node,
+ symbol: Symbol,
+) -> (
+ full_symbol: Symbol,
+ ok: bool,
+) {
+ if selector_expr == nil do return
+
+ selector := selector_expr.derived.(^ast.Selector_Expr) or_return
+
+ _, is_pkg := symbol.value.(SymbolPackageValue)
+ if !is_pkg && symbol.value != nil do return
+
+ if selector.field == nil do return
+
+ ident := selector.field.derived.(^ast.Ident) or_return
+
+ return lookup(ident.name, symbol.pkg, ast_context.fullpath);
+}
+
+get_full_symbol_from_identifier :: proc(
+ ast_context: ^AstContext,
+ position_context: ^DocumentPositionContext,
+ symbol: Symbol,
+) -> (
+ full_symbol: Symbol,
+ ok: bool,
+) {
+ if position_context.identifier == nil || symbol.value != nil do return
+
+ // For identifiers (non-selector), the symbol from resolve_location_identifier may not have
+ // value set (e.g., for globals). We need to do a lookup to get the full symbol.
+ ident := position_context.identifier.derived.(^ast.Ident) or_return
+
+ pkg := symbol.pkg if symbol.pkg != "" else ast_context.document_package
+
+ if pkg_symbol, ok := lookup(ident.name, pkg, ast_context.fullpath); ok {
+ return pkg_symbol, true
+ }
+
+ // If lookup fails (e.g., in tests without full indexing), try checking if it's a proc group
+
+ global := ast_context.globals[ident.name] or_return
+ if proc_group, is_proc_group := global.expr.derived.(^ast.Proc_Group); is_proc_group {
+ full_symbol = symbol
+ full_symbol.value = SymbolProcedureGroupValue {
+ group = global.expr,
+ }
+ return full_symbol, true
+ }
+
+ return Symbol{}, false
+}
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 0d6e025..64142ed 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -454,6 +454,8 @@ read_ols_initialize_options :: proc(config: ^common.Config, ols_config: OlsConfi
ols_config.enable_inlay_hints_implicit_return.(bool) or_else config.enable_inlay_hints_implicit_return
config.enable_fake_method = ols_config.enable_fake_methods.(bool) or_else config.enable_fake_method
+ config.enable_overload_resolution =
+ ols_config.enable_overload_resolution.(bool) or_else config.enable_overload_resolution
// Delete overriding collections.
for it in ols_config.collections {
@@ -861,7 +863,7 @@ request_definition :: proc(
return .InternalError
}
- locations, ok2 := get_definition_location(document, definition_params.position)
+ locations, ok2 := get_definition_location(document, definition_params.position, config)
if !ok2 {
log.warn("Failed to get definition location")
diff --git a/src/server/types.odin b/src/server/types.odin
index c0bcf9e..c65e181 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -419,6 +419,7 @@ OlsConfig :: struct {
enable_hover: Maybe(bool),
enable_document_symbols: Maybe(bool),
enable_fake_methods: Maybe(bool),
+ enable_overload_resolution: Maybe(bool),
enable_references: Maybe(bool),
enable_document_highlights: Maybe(bool),
enable_document_links: Maybe(bool),
diff --git a/src/testing/testing.odin b/src/testing/testing.odin
index 373ef62..2013f79 100644
--- a/src/testing/testing.odin
+++ b/src/testing/testing.odin
@@ -346,7 +346,7 @@ expect_definition_locations :: proc(t: ^testing.T, src: ^Source, expect_location
setup(src)
defer teardown(src)
- locations, ok := server.get_definition_location(src.document, src.position)
+ locations, ok := server.get_definition_location(src.document, src.position, &src.config)
if !ok {
log.error("Failed get_definition_location")