aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-23 21:12:46 -0400
committerBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-24 15:43:58 -0400
commitd13384a1e9a0758e4c608f4dfe3226e78fa4803e (patch)
tree30e42a80052a954f351780c16129195363d4fa22
parent495012ffe93385f399d3947952466448c692f0d4 (diff)
Goto definition on package use goes to package declaration
-rw-r--r--src/server/analysis.odin23
-rw-r--r--src/server/documents.odin28
-rw-r--r--tests/definition_test.odin48
3 files changed, 97 insertions, 2 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 8e1d7f0..9ee621a 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -2591,7 +2591,9 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -
symbol.uri = uri.uri
symbol.flags |= {.Local}
return symbol, true
- } else if global, ok := ast_context.globals[node.name]; ok {
+ }
+
+ if global, ok := ast_context.globals[node.name]; ok {
symbol.range = common.get_token_range(global.name_expr, ast_context.file.src)
uri := common.create_uri(global.expr.pos.file, ast_context.allocator)
symbol.pkg = ast_context.document_package
@@ -2599,6 +2601,25 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -
return symbol, true
}
+ for imp in ast_context.imports {
+ if imp.name == ast_context.current_package {
+ continue
+ }
+
+ if strings.compare(imp.base, node.name) == 0 {
+ symbol := Symbol {
+ type = .Package,
+ pkg = imp.name,
+ value = SymbolPackageValue{},
+ range = imp.range,
+ }
+
+ try_build_package(symbol.pkg)
+
+ return symbol, true
+ }
+ }
+
pkg := get_package_from_node(node)
if symbol, ok := lookup(node.name, pkg, node.pos.file); ok {
return symbol, ok
diff --git a/src/server/documents.odin b/src/server/documents.odin
index dee90d5..b513da6 100644
--- a/src/server/documents.odin
+++ b/src/server/documents.odin
@@ -29,6 +29,7 @@ Package :: struct {
base: string,
base_original: string,
original: string,
+ range: common.Range,
}
Document :: struct {
@@ -75,7 +76,7 @@ document_get_allocator :: proc() -> ^virtual.Arena {
return pop(&document_storage.free_allocators)
} else {
allocator := new(virtual.Arena)
- _ = virtual.arena_init_growing(allocator)
+ _ = virtual.arena_init_growing(allocator)
return allocator
}
}
@@ -427,6 +428,8 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) {
if i := strings.index(imp.fullpath, "\""); i == -1 {
continue
}
+ // TODO: Breakdown this range like with semantic tokens
+ range := get_import_range(imp, string(document.text))
//collection specified
if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 {
@@ -446,6 +449,7 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) {
import_: Package
import_.original = imp.fullpath
import_.name = strings.clone(path.join(elems = {dir, p}, allocator = context.temp_allocator))
+ import_.range = range
if imp.name.text != "" {
import_.base = imp.name.text
@@ -468,6 +472,7 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) {
allocator = context.temp_allocator,
)
import_.name = path.clean(import_.name)
+ import_.range = range
if imp.name.text != "" {
import_.base = imp.name.text
@@ -488,3 +493,24 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) {
document.imports = imports[:]
}
+
+get_import_range :: proc(imp: ^ast.Import_Decl, src: string) -> common.Range {
+ if imp.name.text != "" {
+ start := common.token_pos_to_position(imp.name.pos, src)
+ end := start
+ end.character += len(imp.name.text)
+ return {
+ start = start,
+ end = end,
+ }
+ }
+
+ start := common.token_pos_to_position(imp.relpath.pos, src)
+ end := start
+ text_len := len(imp.relpath.text)
+ end.character += text_len
+ return {
+ start = start,
+ end = end,
+ }
+}
diff --git a/tests/definition_test.odin b/tests/definition_test.odin
index 6e7c7a4..4810361 100644
--- a/tests/definition_test.odin
+++ b/tests/definition_test.odin
@@ -675,3 +675,51 @@ ast_goto_nested_using_struct_field :: proc(t: ^testing.T) {
test.expect_definition_locations(t, &source, locations[:])
}
+
+@(test)
+ast_goto_package_declaration :: proc(t: ^testing.T) {
+ packages := make([dynamic]test.Package, context.temp_allocator)
+
+ append(&packages, test.Package{pkg = "my_package", source = `package my_package
+ Bar :: struct{}
+ `})
+ source := test.Source {
+ main = `package test
+ import "my_package"
+
+ main :: proc() {
+ bar: m{*}y_package.Bar
+ }
+ `,
+ packages = packages[:],
+ }
+ locations := []common.Location {
+ {range = {start = {line = 1, character = 9}, end = {line = 1, character = 21}}},
+ }
+
+ test.expect_definition_locations(t, &source, locations[:])
+}
+
+@(test)
+ast_goto_package_declaration_with_alias :: proc(t: ^testing.T) {
+ packages := make([dynamic]test.Package, context.temp_allocator)
+
+ append(&packages, test.Package{pkg = "my_package", source = `package my_package
+ Bar :: struct{}
+ `})
+ source := test.Source {
+ main = `package test
+ import mp "my_package"
+
+ main :: proc() {
+ bar: m{*}p.Bar
+ }
+ `,
+ packages = packages[:],
+ }
+ locations := []common.Location {
+ {range = {start = {line = 1, character = 9}, end = {line = 1, character = 11}}},
+ }
+
+ test.expect_definition_locations(t, &source, locations[:])
+}