From 853634b50beeeac639bf56121ab878487fb3fa7a Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 11:36:38 +0200 Subject: [PATCH 01/14] Emit definition for all package statements, not just the best one Every file's package statement is an equally valid declaration of the package. Previously only one heuristically chosen file got the Definition role while others were marked as ReadAccess. Now all package statements are definitions, with the best file still providing the SymbolInformation documentation. --- internal/index/scip.go | 6 +++--- internal/testdata/snapshots/output/embedded/embedded.go | 2 +- internal/testdata/snapshots/output/embedded/something.go | 2 +- .../snapshots/output/generallyeric/new_operators.go | 2 +- internal/testdata/snapshots/output/generallyeric/person.go | 2 +- internal/testdata/snapshots/output/impls/remote_impls.go | 2 +- internal/testdata/snapshots/output/initial/builtin_types.go | 2 +- internal/testdata/snapshots/output/initial/child_symbols.go | 2 +- .../testdata/snapshots/output/initial/func_declarations.go | 2 +- .../snapshots/output/initial/methods_and_receivers.go | 2 +- internal/testdata/snapshots/output/initial/rangefunc.go | 2 +- .../testdata/snapshots/output/initial/toplevel_decls.go | 2 +- .../testdata/snapshots/output/initial/type_declarations.go | 2 +- internal/testdata/snapshots/output/initial/type_hovers.go | 2 +- .../snapshots/output/inlinestruct/inlinestruct_func.go | 2 +- .../output/inlinestruct/inlinestruct_genericindex.go | 2 +- .../snapshots/output/inlinestruct/inlinestruct_interface.go | 2 +- .../snapshots/output/inlinestruct/inlinestruct_map.go | 2 +- .../snapshots/output/inlinestruct/inlinestruct_multivar.go | 2 +- .../snapshots/output/package-documentation/secondary.go | 2 +- .../output/sharedtestmodule/cmd/gitserver/server/cleanup.go | 2 +- .../sharedtestmodule/cmd/gitserver/server/cleanup_test.go | 2 +- .../sharedtestmodule/cmd/gitserver/server/server_test.go | 2 +- .../testdata/snapshots/output/testdata/anonymous_structs.go | 2 +- .../snapshots/output/testdata/duplicate_path_id/main.go | 2 +- .../snapshots/output/testdata/external_composite.go | 2 +- .../testdata/snapshots/output/testdata/implementations.go | 2 +- .../snapshots/output/testdata/implementations_embedded.go | 2 +- .../snapshots/output/testdata/implementations_methods.go | 2 +- .../snapshots/output/testdata/implementations_remote.go | 2 +- .../snapshots/output/testdata/internal/secret/secret.go | 2 +- internal/testdata/snapshots/output/testdata/named_import.go | 2 +- internal/testdata/snapshots/output/testdata/parallel.go | 2 +- internal/testdata/snapshots/output/testdata/typealias.go | 2 +- internal/testdata/snapshots/output/testdata/typeswitch.go | 2 +- internal/testdata/snapshots/output/testspecial/foo_test.go | 2 +- 36 files changed, 38 insertions(+), 38 deletions(-) diff --git a/internal/index/scip.go b/internal/index/scip.go index ac455905..9494388f 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -214,16 +214,16 @@ func indexVisitPackages( if pkgDeclaration != nil { position := pkg.Fset.Position(f.Name.NamePos) - role := int32(scip.SymbolRole_ReadAccess) + // Every package statement is a definition of the package symbol. + // The "best" file also provides the SymbolInformation with documentation. if f == pkgDeclaration { doc.SetNewSymbolForPos(pkgSymbol, pkgDeclaration, f.Name, f.Name.NamePos) - role = int32(scip.SymbolRole_Definition) } doc.PackageOccurrence = &scip.Occurrence{ Range: symbols.RangeFromName(position, f.Name.Name, false), Symbol: pkgSymbol, - SymbolRoles: role, + SymbolRoles: int32(scip.SymbolRole_Definition), } } } diff --git a/internal/testdata/snapshots/output/embedded/embedded.go b/internal/testdata/snapshots/output/embedded/embedded.go index b8a97664..6b4264ab 100755 --- a/internal/testdata/snapshots/output/embedded/embedded.go +++ b/internal/testdata/snapshots/output/embedded/embedded.go @@ -1,5 +1,5 @@ package embedded -// ^^^^^^^^ reference 0.1.test `sg/embedded`/ +// ^^^^^^^^ definition 0.1.test `sg/embedded`/ import ( "fmt" diff --git a/internal/testdata/snapshots/output/embedded/something.go b/internal/testdata/snapshots/output/embedded/something.go index 1a619894..6e3bce0a 100755 --- a/internal/testdata/snapshots/output/embedded/something.go +++ b/internal/testdata/snapshots/output/embedded/something.go @@ -1,5 +1,5 @@ package embedded -// ^^^^^^^^ reference 0.1.test `sg/embedded`/ +// ^^^^^^^^ definition 0.1.test `sg/embedded`/ import "fmt" // ^^^ reference github.com/golang/go/src go1.22 fmt/ diff --git a/internal/testdata/snapshots/output/generallyeric/new_operators.go b/internal/testdata/snapshots/output/generallyeric/new_operators.go index 9b63ca5a..24d3f7d3 100755 --- a/internal/testdata/snapshots/output/generallyeric/new_operators.go +++ b/internal/testdata/snapshots/output/generallyeric/new_operators.go @@ -1,5 +1,5 @@ package generallyeric -// ^^^^^^^^^^^^^ reference 0.1.test `sg/generallyeric`/ +// ^^^^^^^^^^^^^ definition 0.1.test `sg/generallyeric`/ type Number interface { // ^^^^^^ definition 0.1.test `sg/generallyeric`/Number# diff --git a/internal/testdata/snapshots/output/generallyeric/person.go b/internal/testdata/snapshots/output/generallyeric/person.go index 9330b9e8..2e8fbb36 100755 --- a/internal/testdata/snapshots/output/generallyeric/person.go +++ b/internal/testdata/snapshots/output/generallyeric/person.go @@ -1,5 +1,5 @@ package generallyeric -// ^^^^^^^^^^^^^ reference 0.1.test `sg/generallyeric`/ +// ^^^^^^^^^^^^^ definition 0.1.test `sg/generallyeric`/ import "fmt" // ^^^ reference github.com/golang/go/src go1.22 fmt/ diff --git a/internal/testdata/snapshots/output/impls/remote_impls.go b/internal/testdata/snapshots/output/impls/remote_impls.go index cd3eebd5..ea50aced 100755 --- a/internal/testdata/snapshots/output/impls/remote_impls.go +++ b/internal/testdata/snapshots/output/impls/remote_impls.go @@ -1,5 +1,5 @@ package impls -// ^^^^^ reference 0.1.test `sg/impls`/ +// ^^^^^ definition 0.1.test `sg/impls`/ import "net/http" // ^^^^^^^^ reference github.com/golang/go/src go1.22 `net/http`/ diff --git a/internal/testdata/snapshots/output/initial/builtin_types.go b/internal/testdata/snapshots/output/initial/builtin_types.go index 7ab7e27d..31bd185f 100755 --- a/internal/testdata/snapshots/output/initial/builtin_types.go +++ b/internal/testdata/snapshots/output/initial/builtin_types.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ //⌄ enclosing_range_start 0.1.test `sg/initial`/UsesBuiltin(). func UsesBuiltin() int { diff --git a/internal/testdata/snapshots/output/initial/child_symbols.go b/internal/testdata/snapshots/output/initial/child_symbols.go index 77f2ece1..ae8024d7 100755 --- a/internal/testdata/snapshots/output/initial/child_symbols.go +++ b/internal/testdata/snapshots/output/initial/child_symbols.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ // Const is a constant equal to 5. It's the best constant I've ever written. 😹 const Const = 5 diff --git a/internal/testdata/snapshots/output/initial/func_declarations.go b/internal/testdata/snapshots/output/initial/func_declarations.go index 441f3ade..58d79813 100755 --- a/internal/testdata/snapshots/output/initial/func_declarations.go +++ b/internal/testdata/snapshots/output/initial/func_declarations.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ //⌄ enclosing_range_start 0.1.test `sg/initial`/UsesLater(). func UsesLater() { diff --git a/internal/testdata/snapshots/output/initial/methods_and_receivers.go b/internal/testdata/snapshots/output/initial/methods_and_receivers.go index ac8264aa..03f33a8f 100755 --- a/internal/testdata/snapshots/output/initial/methods_and_receivers.go +++ b/internal/testdata/snapshots/output/initial/methods_and_receivers.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ import "fmt" // ^^^ reference github.com/golang/go/src go1.22 fmt/ diff --git a/internal/testdata/snapshots/output/initial/rangefunc.go b/internal/testdata/snapshots/output/initial/rangefunc.go index 7726d54b..13a83a3d 100755 --- a/internal/testdata/snapshots/output/initial/rangefunc.go +++ b/internal/testdata/snapshots/output/initial/rangefunc.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ import ( "slices" diff --git a/internal/testdata/snapshots/output/initial/toplevel_decls.go b/internal/testdata/snapshots/output/initial/toplevel_decls.go index 255ca4f0..4e745a75 100755 --- a/internal/testdata/snapshots/output/initial/toplevel_decls.go +++ b/internal/testdata/snapshots/output/initial/toplevel_decls.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ const MY_THING = 10 // ^^^^^^^^ definition 0.1.test `sg/initial`/MY_THING. diff --git a/internal/testdata/snapshots/output/initial/type_declarations.go b/internal/testdata/snapshots/output/initial/type_declarations.go index 1b4ba27a..8d383613 100755 --- a/internal/testdata/snapshots/output/initial/type_declarations.go +++ b/internal/testdata/snapshots/output/initial/type_declarations.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ type LiteralType int // ^^^^^^^^^^^ definition 0.1.test `sg/initial`/LiteralType# diff --git a/internal/testdata/snapshots/output/initial/type_hovers.go b/internal/testdata/snapshots/output/initial/type_hovers.go index b6c3c819..4a499a87 100755 --- a/internal/testdata/snapshots/output/initial/type_hovers.go +++ b/internal/testdata/snapshots/output/initial/type_hovers.go @@ -1,5 +1,5 @@ package initial -// ^^^^^^^ reference 0.1.test `sg/initial`/ +// ^^^^^^^ definition 0.1.test `sg/initial`/ type ( // HoverTypeList is a cool struct diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_func.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_func.go index 06d9095d..ae341db7 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_func.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_func.go @@ -1,5 +1,5 @@ package inlinestruct -// ^^^^^^^^^^^^ reference 0.1.test `sg/inlinestruct`/ +// ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ type InFuncSig struct { // ^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/InFuncSig# diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_genericindex.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_genericindex.go index 5d76b16b..6af8bffb 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_genericindex.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_genericindex.go @@ -1,5 +1,5 @@ package inlinestruct -// ^^^^^^^^^^^^ reference 0.1.test `sg/inlinestruct`/ +// ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ type Processor[T any] interface { // ^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/Processor# diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_interface.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_interface.go index 0eb2c632..ebaba8da 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_interface.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_interface.go @@ -1,5 +1,5 @@ package inlinestruct -// ^^^^^^^^^^^^ reference 0.1.test `sg/inlinestruct`/ +// ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ import "context" // ^^^^^^^ reference github.com/golang/go/src go1.22 context/ diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_map.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_map.go index 54ee2597..49b1b86a 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_map.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_map.go @@ -1,5 +1,5 @@ package inlinestruct -// ^^^^^^^^^^^^ reference 0.1.test `sg/inlinestruct`/ +// ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ var testHook = func(map[string]string) {} // ^^^^^^^^ definition 0.1.test `sg/inlinestruct`/testHook. diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_multivar.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_multivar.go index 0f62616c..acbd430f 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct_multivar.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct_multivar.go @@ -1,5 +1,5 @@ package inlinestruct -// ^^^^^^^^^^^^ reference 0.1.test `sg/inlinestruct`/ +// ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ type Params struct{} // ^^^^^^ definition 0.1.test `sg/inlinestruct`/Params# diff --git a/internal/testdata/snapshots/output/package-documentation/secondary.go b/internal/testdata/snapshots/output/package-documentation/secondary.go index d8a9c68f..d5a9b7a0 100755 --- a/internal/testdata/snapshots/output/package-documentation/secondary.go +++ b/internal/testdata/snapshots/output/package-documentation/secondary.go @@ -1,5 +1,5 @@ package packagedocumentation -// ^^^^^^^^^^^^^^^^^^^^ reference github.com/sourcegraph/scip-go 0.1.test `github.com/sourcegraph/scip-go/internal/testdata/snapshots/input/package-documentation`/ +// ^^^^^^^^^^^^^^^^^^^^ definition github.com/sourcegraph/scip-go 0.1.test `github.com/sourcegraph/scip-go/internal/testdata/snapshots/input/package-documentation`/ //⌄ enclosing_range_start github.com/sourcegraph/scip-go 0.1.test `github.com/sourcegraph/scip-go/internal/testdata/snapshots/input/package-documentation`/AlsoExporter(). func AlsoExporter() {} diff --git a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup.go b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup.go index cac051df..3df64f59 100755 --- a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup.go +++ b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup.go @@ -1,5 +1,5 @@ package server -// ^^^^^^ reference 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ +// ^^^^^^ definition 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ //⌄ enclosing_range_start 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/LiterallyAnything(). func LiterallyAnything() {} diff --git a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup_test.go b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup_test.go index 8a413ff4..f0de6753 100755 --- a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup_test.go +++ b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/cleanup_test.go @@ -1,5 +1,5 @@ package server -// ^^^^^^ reference 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ +// ^^^^^^ definition 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ import "testing" // ^^^^^^^ reference github.com/golang/go/src go1.22 testing/ diff --git a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server_test.go b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server_test.go index 9270cd06..01de209a 100755 --- a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server_test.go +++ b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server_test.go @@ -1,5 +1,5 @@ package server -// ^^^^^^ reference 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ +// ^^^^^^ definition 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ import "testing" // ^^^^^^^ reference github.com/golang/go/src go1.22 testing/ diff --git a/internal/testdata/snapshots/output/testdata/anonymous_structs.go b/internal/testdata/snapshots/output/testdata/anonymous_structs.go index d944bc42..b2345a0d 100755 --- a/internal/testdata/snapshots/output/testdata/anonymous_structs.go +++ b/internal/testdata/snapshots/output/testdata/anonymous_structs.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import "fmt" // ^^^ reference github.com/golang/go/src go1.22 fmt/ diff --git a/internal/testdata/snapshots/output/testdata/duplicate_path_id/main.go b/internal/testdata/snapshots/output/testdata/duplicate_path_id/main.go index b647f4af..b19080f5 100755 --- a/internal/testdata/snapshots/output/testdata/duplicate_path_id/main.go +++ b/internal/testdata/snapshots/output/testdata/duplicate_path_id/main.go @@ -1,5 +1,5 @@ package gosrc -// ^^^^^ reference 0.1.test `sg/testdata/duplicate_path_id`/ +// ^^^^^ definition 0.1.test `sg/testdata/duplicate_path_id`/ type importMeta struct{} // ^^^^^^^^^^ definition 0.1.test `sg/testdata/duplicate_path_id`/importMeta# diff --git a/internal/testdata/snapshots/output/testdata/external_composite.go b/internal/testdata/snapshots/output/testdata/external_composite.go index 45911271..89ab3b51 100755 --- a/internal/testdata/snapshots/output/testdata/external_composite.go +++ b/internal/testdata/snapshots/output/testdata/external_composite.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import "net/http" // ^^^^^^^^ reference github.com/golang/go/src go1.22 `net/http`/ diff --git a/internal/testdata/snapshots/output/testdata/implementations.go b/internal/testdata/snapshots/output/testdata/implementations.go index b67c12cd..b93f375e 100755 --- a/internal/testdata/snapshots/output/testdata/implementations.go +++ b/internal/testdata/snapshots/output/testdata/implementations.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ type I0 interface{} // ^^ definition 0.1.test `sg/testdata`/I0# diff --git a/internal/testdata/snapshots/output/testdata/implementations_embedded.go b/internal/testdata/snapshots/output/testdata/implementations_embedded.go index 74ddc350..89d0cc8f 100755 --- a/internal/testdata/snapshots/output/testdata/implementations_embedded.go +++ b/internal/testdata/snapshots/output/testdata/implementations_embedded.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import "io" // ^^ reference github.com/golang/go/src go1.22 io/ diff --git a/internal/testdata/snapshots/output/testdata/implementations_methods.go b/internal/testdata/snapshots/output/testdata/implementations_methods.go index 2cbe6592..4dab43ad 100755 --- a/internal/testdata/snapshots/output/testdata/implementations_methods.go +++ b/internal/testdata/snapshots/output/testdata/implementations_methods.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ type InterfaceWithSingleMethod interface { // ^^^^^^^^^^^^^^^^^^^^^^^^^ definition 0.1.test `sg/testdata`/InterfaceWithSingleMethod# diff --git a/internal/testdata/snapshots/output/testdata/implementations_remote.go b/internal/testdata/snapshots/output/testdata/implementations_remote.go index f431920d..7aedf2a1 100755 --- a/internal/testdata/snapshots/output/testdata/implementations_remote.go +++ b/internal/testdata/snapshots/output/testdata/implementations_remote.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import "net/http" // ^^^^^^^^ reference github.com/golang/go/src go1.22 `net/http`/ diff --git a/internal/testdata/snapshots/output/testdata/internal/secret/secret.go b/internal/testdata/snapshots/output/testdata/internal/secret/secret.go index 1b578327..3492bb75 100755 --- a/internal/testdata/snapshots/output/testdata/internal/secret/secret.go +++ b/internal/testdata/snapshots/output/testdata/internal/secret/secret.go @@ -1,5 +1,5 @@ package secret -// ^^^^^^ reference 0.1.test `sg/testdata/internal/secret`/ +// ^^^^^^ definition 0.1.test `sg/testdata/internal/secret`/ // SecretScore is like score but _secret_. const SecretScore = uint64(43) diff --git a/internal/testdata/snapshots/output/testdata/named_import.go b/internal/testdata/snapshots/output/testdata/named_import.go index 1a02fb1a..473e40d4 100755 --- a/internal/testdata/snapshots/output/testdata/named_import.go +++ b/internal/testdata/snapshots/output/testdata/named_import.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import ( . "fmt" diff --git a/internal/testdata/snapshots/output/testdata/parallel.go b/internal/testdata/snapshots/output/testdata/parallel.go index b0575a01..3bb81655 100755 --- a/internal/testdata/snapshots/output/testdata/parallel.go +++ b/internal/testdata/snapshots/output/testdata/parallel.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import ( "context" diff --git a/internal/testdata/snapshots/output/testdata/typealias.go b/internal/testdata/snapshots/output/testdata/typealias.go index db0228f4..86dae0ff 100755 --- a/internal/testdata/snapshots/output/testdata/typealias.go +++ b/internal/testdata/snapshots/output/testdata/typealias.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ import ( "sg/testdata/internal/secret" diff --git a/internal/testdata/snapshots/output/testdata/typeswitch.go b/internal/testdata/snapshots/output/testdata/typeswitch.go index 743227ad..da910994 100755 --- a/internal/testdata/snapshots/output/testdata/typeswitch.go +++ b/internal/testdata/snapshots/output/testdata/typeswitch.go @@ -1,5 +1,5 @@ package testdata -// ^^^^^^^^ reference 0.1.test `sg/testdata`/ +// ^^^^^^^^ definition 0.1.test `sg/testdata`/ //⌄ enclosing_range_start 0.1.test `sg/testdata`/Switch(). func Switch(interfaceValue interface{}) bool { diff --git a/internal/testdata/snapshots/output/testspecial/foo_test.go b/internal/testdata/snapshots/output/testspecial/foo_test.go index a29ecb68..094bb287 100755 --- a/internal/testdata/snapshots/output/testspecial/foo_test.go +++ b/internal/testdata/snapshots/output/testspecial/foo_test.go @@ -1,5 +1,5 @@ package testspecial -// ^^^^^^^^^^^ reference 0.1.test `sg/testspecial`/ +// ^^^^^^^^^^^ definition 0.1.test `sg/testspecial`/ //⌄ enclosing_range_start 0.1.test `sg/testspecial`/TestFoo_Whitebox(). func TestFoo_Whitebox() { Foo() } From 4df9ba148c10ee6fe02c8aac77889c1ef722f011 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 14:48:21 +0200 Subject: [PATCH 02/14] Simplify package symbol handling - Rename findBestPackageDefinitionPath to findPackageDocFile to reflect its actual purpose: picking the file for package documentation - Remove redundant pkgDeclaration != nil guard (always true at that point) - Drop PackageName struct; store symbol string directly in pkgSymbols map - SetPkgSymbol now returns the symbol string, removing a separate Get call - Remove unused go/ast import from lookup.go --- internal/index/package_ident.go | 4 ++- internal/index/package_ident_test.go | 4 +-- internal/index/scip.go | 34 ++++++++----------- internal/lookup/lookup.go | 49 ++++++++++------------------ internal/visitors/visitor_file.go | 12 +++---- 5 files changed, 42 insertions(+), 61 deletions(-) diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index 375f932f..9811b2b9 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -10,7 +10,9 @@ import ( "golang.org/x/tools/go/packages" ) -func findBestPackageDefinitionPath(pkg *packages.Package) (*ast.File, error) { +// findPackageDocFile picks the file whose doc comment should represent +// the package's documentation in the SCIP index. +func findPackageDocFile(pkg *packages.Package) (*ast.File, error) { if pkg.PkgPath == "builtin" { return nil, nil } diff --git a/internal/index/package_ident_test.go b/internal/index/package_ident_test.go index 6ec5d340..609ec890 100644 --- a/internal/index/package_ident_test.go +++ b/internal/index/package_ident_test.go @@ -8,7 +8,7 @@ import ( "golang.org/x/tools/go/packages" ) -func TestIndexer_findBestPackageDefinitionPath(t *testing.T) { +func TestIndexer_findPackageDocFile(t *testing.T) { type FileInfo struct { Name string Docs bool @@ -58,7 +58,7 @@ func TestIndexer_findBestPackageDefinitionPath(t *testing.T) { t.Run(name, func(t *testing.T) { pkg, names := makePackage(pkgName, fileInfo) - pkgToken, _ := findBestPackageDefinitionPath(pkg) + pkgToken, _ := findPackageDocFile(pkg) if name := names[pkgToken]; name != expected { t.Errorf("incorrect hover text documentation. want=%s have=%s", name, expected) } diff --git a/internal/index/scip.go b/internal/index/scip.go index 9494388f..e9354da7 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -187,44 +187,38 @@ func indexVisitPackages( slog.Debug("Visiting package", "path", pkg.PkgPath) visitors.VisitPackageSyntax(opts.ModuleRoot, pkg, pathToDocuments, globalSymbols) - // Handle that packages can have many files for one package. - // This finds the "definitive" package declaration - pkgDeclaration, err := findBestPackageDefinitionPath(pkg) + // Find the file whose doc comment represents the package documentation. + pkgDocFile, err := findPackageDocFile(pkg) if err != nil { panic(fmt.Sprintf("Unhandled package declaration: %s", err)) } - if pkgDeclaration == nil { + if pkgDocFile == nil { atomic.AddUint64(&count, 1) continue } - globalSymbols.SetPkgName(pkg, pkgDeclaration) + pkgSymbol := globalSymbols.SetPkgSymbol(pkg) // If we don't have this package anywhere, don't try to create a new symbol if _, ok := projectPackages[newtypes.GetID(pkg)]; !ok { atomic.AddUint64(&count, 1) continue } - - pkgSymbol := globalSymbols.GetPkgNameSymbol(pkg).Symbol for _, f := range pkg.Syntax { doc := pathToDocuments[pkg.Fset.File(f.Package).Name()] + position := pkg.Fset.Position(f.Name.NamePos) - if pkgDeclaration != nil { - position := pkg.Fset.Position(f.Name.NamePos) - - // Every package statement is a definition of the package symbol. - // The "best" file also provides the SymbolInformation with documentation. - if f == pkgDeclaration { - doc.SetNewSymbolForPos(pkgSymbol, pkgDeclaration, f.Name, f.Name.NamePos) - } + // The doc file provides the SymbolInformation with documentation. + if f == pkgDocFile { + doc.SetNewSymbolForPos(pkgSymbol, pkgDocFile, f.Name, f.Name.NamePos) + } - doc.PackageOccurrence = &scip.Occurrence{ - Range: symbols.RangeFromName(position, f.Name.Name, false), - Symbol: pkgSymbol, - SymbolRoles: int32(scip.SymbolRole_Definition), - } + // Every package statement is a definition of the package symbol. + doc.PackageOccurrence = &scip.Occurrence{ + Range: symbols.RangeFromName(position, f.Name.Name, false), + Symbol: pkgSymbol, + SymbolRoles: int32(scip.SymbolRole_Definition), } } diff --git a/internal/lookup/lookup.go b/internal/lookup/lookup.go index 5f7f1ac5..b5a5fc99 100644 --- a/internal/lookup/lookup.go +++ b/internal/lookup/lookup.go @@ -3,7 +3,6 @@ package lookup import ( "errors" "fmt" - "go/ast" "go/token" "go/types" "log/slog" @@ -24,8 +23,8 @@ func NewPackageSymbols(pkg *packages.Package) *Package { func NewGlobalSymbols() *Global { return &Global{ - symbols: map[newtypes.PackageID]*Package{}, - pkgNames: map[newtypes.PackageID]*PackageName{}, + symbols: map[newtypes.PackageID]*Package{}, + pkgSymbols: map[newtypes.PackageID]string{}, } } @@ -82,15 +81,10 @@ func (p *Package) GetSymbol(pos token.Pos) (string, bool) { } } -type PackageName struct { - Symbol *scip.SymbolInformation - Pos token.Pos -} - type Global struct { - m sync.Mutex - symbols map[newtypes.PackageID]*Package - pkgNames map[newtypes.PackageID]*PackageName + m sync.Mutex + symbols map[newtypes.PackageID]*Package + pkgSymbols map[newtypes.PackageID]string } func (p *Global) Add(pkgSymbols *Package) { @@ -99,33 +93,24 @@ func (p *Global) Add(pkgSymbols *Package) { p.m.Unlock() } -func (p *Global) SetPkgName(pkg *packages.Package, pkgDeclaration *ast.File) { +func (p *Global) SetPkgSymbol(pkg *packages.Package) string { + sym := symbols.FromDescriptors(pkg, &scip.Descriptor{ + Name: pkg.PkgPath, + Suffix: scip.Descriptor_Namespace, + }) p.m.Lock() - p.pkgNames[newtypes.GetID(pkg)] = &PackageName{ - Symbol: &scip.SymbolInformation{ - Symbol: symbols.FromDescriptors(pkg, &scip.Descriptor{ - Name: pkg.PkgPath, - Suffix: scip.Descriptor_Namespace, - }), - Documentation: []string{}, - Relationships: []*scip.Relationship{}, - }, - Pos: pkgDeclaration.Name.NamePos, - } + p.pkgSymbols[newtypes.GetID(pkg)] = sym p.m.Unlock() + return sym } -func (p *Global) GetPkgNameSymbolByID(pkgID newtypes.PackageID) *scip.SymbolInformation { - named, ok := p.pkgNames[pkgID] - if !ok { - return nil - } - - return named.Symbol +func (p *Global) GetPkgSymbolByID(pkgID newtypes.PackageID) (string, bool) { + sym, ok := p.pkgSymbols[pkgID] + return sym, ok } -func (p *Global) GetPkgNameSymbol(pkg *packages.Package) *scip.SymbolInformation { - return p.GetPkgNameSymbolByID(newtypes.GetID(pkg)) +func (p *Global) GetPkgSymbol(pkg *packages.Package) (string, bool) { + return p.GetPkgSymbolByID(newtypes.GetID(pkg)) } func (p *Global) GetPackage(pkg *packages.Package) *Package { diff --git a/internal/visitors/visitor_file.go b/internal/visitors/visitor_file.go index 182306ce..c41063ce 100644 --- a/internal/visitors/visitor_file.go +++ b/internal/visitors/visitor_file.go @@ -169,13 +169,13 @@ func (v *fileVisitor) Visit(n ast.Node) ast.Visitor { if overrideSymbol, ok := v.overrides.pkgNameOverride[pkgID]; ok { symbolName = overrideSymbol } else { - symbol := v.globalSymbols.GetPkgNameSymbolByID(pkgID) - if symbol == nil { + sym, ok := v.globalSymbols.GetPkgSymbolByID(pkgID) + if !ok { slog.Debug(fmt.Sprintf("Missing symbol for package: %s", sel.Imported().Path())) return nil } - symbolName = symbol.Symbol + symbolName = sym } v.AppendSymbolReference(symbolName, scipRange(startPosition, endPosition, sel), nil) @@ -306,13 +306,13 @@ func (v *fileVisitor) emitImportReference( return } - symbol := globalSymbols.GetPkgNameSymbol(importedPackage) - if symbol == nil { + sym, ok := globalSymbols.GetPkgSymbol(importedPackage) + if !ok { slog.Debug(fmt.Sprintf("Missing symbol information for package: %s", importedPackage.ID)) return } - v.AppendSymbolReference(symbol.Symbol, scipRange, nil) + v.AppendSymbolReference(sym, scipRange, nil) } // NewDefinition emits a scip.Occurence ONLY. This will not emit a From 9c7f54de9ce7389a0d123d355c725aa844b0bbfd Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 15:00:53 +0200 Subject: [PATCH 03/14] Simplify findPackageDocFile to only return files with doc comments Previously findBestPackageDefinitionPath always returned a file using levenshtein distance heuristics, even when no file had a doc comment. Now findPackageDocFile returns nil when no file has documentation, which means no SymbolInformation is emitted for undocumented packages. This removes the levenshtein dependency and the error return value. --- go.mod | 1 - go.sum | 6 - internal/index/package_ident.go | 79 +++-------- internal/index/package_ident_test.go | 124 ++++++++---------- internal/index/scip.go | 11 +- .../testdata/snapshots/output/alias/main.go | 2 - .../output/embedded/internal/nested.go | 2 - .../snapshots/output/embedded/nested.go | 2 - .../testdata/snapshots/output/impls/impls.go | 2 - .../output/inlinestruct/inlinestruct.go | 2 - .../replace-directives/replace_directives.go | 2 - .../cmd/gitserver/server/server.go | 2 - .../snapshots/output/switches/switches.go | 2 - .../testdata/cmd/minimal_main/minimal_main.go | 2 - .../sandbox_unsupported_test.go | 2 - .../snapshots/output/testdata/data.go | 2 - .../output/testdata/duplicate_path_id/two.go | 2 - .../snapshots/output/testspecial/foo.go | 2 - .../output/testspecial/foo_other_test.go | 2 - 19 files changed, 78 insertions(+), 171 deletions(-) diff --git a/go.mod b/go.mod index 828f86f2..99cb5c92 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/sourcegraph/scip-go go 1.25.0 require ( - github.com/agnivade/levenshtein v1.2.1 github.com/alecthomas/kong v1.14.0 github.com/scip-code/scip/bindings/go/scip v0.7.0 golang.org/x/mod v0.34.0 diff --git a/go.sum b/go.sum index a918cab9..db362d8b 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,11 @@ -github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= -github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/kong v1.14.0 h1:gFgEUZWu2ZmZ+UhyZ1bDhuutbKN1nTtJTwh19Wsn21s= github.com/alecthomas/kong v1.14.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= -github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index 9811b2b9..ba63e15e 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -2,87 +2,46 @@ package index import ( "go/ast" - "math" "path" "strings" - "github.com/agnivade/levenshtein" "golang.org/x/tools/go/packages" ) // findPackageDocFile picks the file whose doc comment should represent -// the package's documentation in the SCIP index. -func findPackageDocFile(pkg *packages.Package) (*ast.File, error) { - if pkg.PkgPath == "builtin" { - return nil, nil - } - - // Unsafe is special case for builtin - if pkg.PkgPath == "unsafe" { - return nil, nil - } - - if len(pkg.Syntax) == 0 { - // This case can be triggered when a package directory only contains `_test.go` files, - // as those files will be compiled as part of a separate _test package. - return nil, nil - } - - files := []*ast.File{} - filesWithDocs := []*ast.File{} +// the package's documentation in the SCIP index. Returns nil if no file +// has a package doc comment. +func findPackageDocFile(pkg *packages.Package) *ast.File { + var filesWithDocs []*ast.File for _, f := range pkg.Syntax { - // pos := pkg.Fset.Position(f.Pos()) - - files = append(files, f) if f.Doc != nil { filesWithDocs = append(filesWithDocs, f) } } - // The idiomatic way is to _only_ have one .go file per package that has a docstring - // for the package. This should generally return here. if len(filesWithDocs) == 1 { - return filesWithDocs[0], nil + return filesWithDocs[0] } - // If we for some reason have more than one .go file per package that has a docstring, - // only consider returning paths that contain the docstring (instead of any of the possible - // paths). - if len(filesWithDocs) > 1 { - files = filesWithDocs + if len(filesWithDocs) == 0 { + return nil } - // Try to only pick non _test files for non _test packages and vice versa. - files = filterBasedOnTestFiles(pkg, files) - - // Find the best remaining path. - // Chooses: - // 1. doc.go - // 2. exact match - // 3. computes levenshtein and picks best score - var bestFile *ast.File - - minDistance := math.MaxInt32 - for _, f := range files { - fPath := pkg.Fset.Position(f.Pos()).Filename - fileName := fileNameWithoutExtension(fPath) - - if "doc.go" == path.Base(fPath) { - return f, nil + // Multiple files have doc comments. Prefer doc.go, then the file matching + // the package name, then pick the first candidate. + candidates := filterBasedOnTestFiles(pkg, filesWithDocs) + for _, f := range candidates { + if path.Base(pkg.Fset.Position(f.Pos()).Filename) == "doc.go" { + return f } - - if pkg.Name == fileName { - return f, nil - } - - distance := levenshtein.ComputeDistance(pkg.Name, fileName) - if distance < minDistance { - minDistance = distance - bestFile = f + } + for _, f := range candidates { + if fileNameWithoutExtension(pkg.Fset.Position(f.Pos()).Filename) == pkg.Name { + return f } } - return bestFile, nil + return candidates[0] } func fileNameWithoutExtension(fileName string) string { @@ -92,7 +51,7 @@ func fileNameWithoutExtension(fileName string) string { func filterBasedOnTestFiles(pkg *packages.Package, files []*ast.File) []*ast.File { packageNameEndsWithTest := strings.HasSuffix(pkg.Name, "_test") - preferredFiles := []*ast.File{} + var preferredFiles []*ast.File for _, f := range files { fPath := pkg.Fset.Position(f.Pos()) if packageNameEndsWithTest == strings.HasSuffix(fPath.Filename, "_test.go") { diff --git a/internal/index/package_ident_test.go b/internal/index/package_ident_test.go index 609ec890..4d7d7697 100644 --- a/internal/index/package_ident_test.go +++ b/internal/index/package_ident_test.go @@ -8,7 +8,7 @@ import ( "golang.org/x/tools/go/packages" ) -func TestIndexer_findPackageDocFile(t *testing.T) { +func TestFindPackageDocFile(t *testing.T) { type FileInfo struct { Name string Docs bool @@ -17,31 +17,28 @@ func TestIndexer_findPackageDocFile(t *testing.T) { makePackage := func(pkgName string, fileInfo []FileInfo) (*packages.Package, map[*ast.File]string) { fset := token.NewFileSet() - files := map[string]*ast.File{} syntax := []*ast.File{} posMap := map[*ast.File]string{} - for idx, info := range fileInfo { + for _, info := range fileInfo { var doc *ast.CommentGroup if info.Docs { doc = &ast.CommentGroup{} } + tf := fset.AddFile(info.Name, fset.Base(), 1) + f := &ast.File{ Doc: doc, - Package: 0, + Package: tf.Pos(0), Name: &ast.Ident{ - NamePos: token.Pos(idx), - Name: pkgName, - Obj: &ast.Object{}, + Name: pkgName, + Obj: &ast.Object{}, }, } - files[info.Name] = f syntax = append(syntax, f) posMap[f] = info.Name - - fset.AddFile(info.Name, fset.Base(), 1) } return &packages.Package{ @@ -54,67 +51,62 @@ func TestIndexer_findPackageDocFile(t *testing.T) { }, posMap } - makeTest := func(name, pkgName, expected string, fileInfo []FileInfo) { - t.Run(name, func(t *testing.T) { - pkg, names := makePackage(pkgName, fileInfo) - - pkgToken, _ := findPackageDocFile(pkg) - if name := names[pkgToken]; name != expected { - t.Errorf("incorrect hover text documentation. want=%s have=%s", name, expected) - } - }) - } - - makeTest("Should find exact name match", - "smol", - "smol.go", - []FileInfo{ + t.Run("returns nil when no file has docs", func(t *testing.T) { + pkg, _ := makePackage("smol", []FileInfo{ {"smol.go", false}, {"other.go", false}, - }, - ) - - makeTest("Should return something even if nothing matches", - "smol", - "random.go", - []FileInfo{ - {"random.go", false}, - }, - ) - - makeTest("Should not pick _test files if package is not a test package", - "unreleated", - "smol.go", - []FileInfo{ - {"smol.go", false}, - {"smol_test.go", false}, - }, - ) + }) + if f := findPackageDocFile(pkg); f != nil { + t.Errorf("expected nil, got a file") + } + }) - makeTest("Pick whatever has documentation", - "mylib", - "has_docs.go", - []FileInfo{ + t.Run("returns the single file with docs", func(t *testing.T) { + pkg, names := makePackage("mylib", []FileInfo{ {"mylib.go", false}, {"has_docs.go", true}, - }, - ) + }) + f := findPackageDocFile(pkg) + if f == nil { + t.Fatal("expected a file, got nil") + } + if name := names[f]; name != "has_docs.go" { + t.Errorf("want=has_docs.go have=%s", name) + } + }) + + t.Run("prefers doc.go when multiple files have docs", func(t *testing.T) { + pkg, names := makePackage("mylib", []FileInfo{ + {"mylib.go", true}, + {"doc.go", true}, + }) + f := findPackageDocFile(pkg) + if f == nil { + t.Fatal("expected a file, got nil") + } + if name := names[f]; name != "doc.go" { + t.Errorf("want=doc.go have=%s", name) + } + }) - makeTest("should pick a name that is a closer edit distance than one far away", - "http_router", - "httprouter.go", - []FileInfo{ - {"httprouter.go", false}, - {"httpother.go", false}, - }, - ) + t.Run("prefers exact package name match when multiple files have docs", func(t *testing.T) { + pkg, names := makePackage("mylib", []FileInfo{ + {"other.go", true}, + {"mylib.go", true}, + }) + f := findPackageDocFile(pkg) + if f == nil { + t.Fatal("expected a file, got nil") + } + if name := names[f]; name != "mylib.go" { + t.Errorf("want=mylib.go have=%s", name) + } + }) - makeTest("should prefer test packages over other packages if the package name has test suffix", - "mylib_test", - "mylib_test.go", - []FileInfo{ - {"mylib_test.go", false}, - {"mylib.go", false}, - }, - ) + t.Run("returns nil for empty syntax", func(t *testing.T) { + pkg, _ := makePackage("mylib", []FileInfo{}) + if f := findPackageDocFile(pkg); f != nil { + t.Errorf("expected nil, got a file") + } + }) } diff --git a/internal/index/scip.go b/internal/index/scip.go index e9354da7..a99ccee5 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -2,7 +2,6 @@ package index import ( _ "embed" - "fmt" "go/ast" "log/slog" "maps" @@ -188,15 +187,7 @@ func indexVisitPackages( visitors.VisitPackageSyntax(opts.ModuleRoot, pkg, pathToDocuments, globalSymbols) // Find the file whose doc comment represents the package documentation. - pkgDocFile, err := findPackageDocFile(pkg) - if err != nil { - panic(fmt.Sprintf("Unhandled package declaration: %s", err)) - } - - if pkgDocFile == nil { - atomic.AddUint64(&count, 1) - continue - } + pkgDocFile := findPackageDocFile(pkg) pkgSymbol := globalSymbols.SetPkgSymbol(pkg) diff --git a/internal/testdata/snapshots/output/alias/main.go b/internal/testdata/snapshots/output/alias/main.go index 5b0d7225..b9f86270 100755 --- a/internal/testdata/snapshots/output/alias/main.go +++ b/internal/testdata/snapshots/output/alias/main.go @@ -1,7 +1,5 @@ package main // ^^^^ definition github.com/sourcegraph/scip-go 0.1.test `github.com/sourcegraph/scip-go/internal/testdata/snapshots/input/alias`/ -// documentation -// > package main // Check that we don't panic // Copied from https://github.com/golang/go/issues/68877#issuecomment-2290000187 diff --git a/internal/testdata/snapshots/output/embedded/internal/nested.go b/internal/testdata/snapshots/output/embedded/internal/nested.go index db50f6d3..6cc5c289 100755 --- a/internal/testdata/snapshots/output/embedded/internal/nested.go +++ b/internal/testdata/snapshots/output/embedded/internal/nested.go @@ -1,7 +1,5 @@ package nested_internal // ^^^^^^^^^^^^^^^ definition 0.1.test `sg/embedded/internal`/ -// documentation -// > package nested_internal import ( "fmt" diff --git a/internal/testdata/snapshots/output/embedded/nested.go b/internal/testdata/snapshots/output/embedded/nested.go index 00e809f3..88e9c960 100755 --- a/internal/testdata/snapshots/output/embedded/nested.go +++ b/internal/testdata/snapshots/output/embedded/nested.go @@ -1,7 +1,5 @@ package embedded // ^^^^^^^^ definition 0.1.test `sg/embedded`/ -// documentation -// > package embedded import "net/http" // ^^^^^^^^ reference github.com/golang/go/src go1.22 `net/http`/ diff --git a/internal/testdata/snapshots/output/impls/impls.go b/internal/testdata/snapshots/output/impls/impls.go index 01532d53..6a6d64d0 100755 --- a/internal/testdata/snapshots/output/impls/impls.go +++ b/internal/testdata/snapshots/output/impls/impls.go @@ -1,7 +1,5 @@ package impls // ^^^^^ definition 0.1.test `sg/impls`/ -// documentation -// > package impls type I1 interface { // ^^ definition 0.1.test `sg/impls`/I1# diff --git a/internal/testdata/snapshots/output/inlinestruct/inlinestruct.go b/internal/testdata/snapshots/output/inlinestruct/inlinestruct.go index 70f5909b..64f654b5 100755 --- a/internal/testdata/snapshots/output/inlinestruct/inlinestruct.go +++ b/internal/testdata/snapshots/output/inlinestruct/inlinestruct.go @@ -1,7 +1,5 @@ package inlinestruct // ^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/ -// documentation -// > package inlinestruct type FieldInterface interface { // ^^^^^^^^^^^^^^ definition 0.1.test `sg/inlinestruct`/FieldInterface# diff --git a/internal/testdata/snapshots/output/replace-directives/replace_directives.go b/internal/testdata/snapshots/output/replace-directives/replace_directives.go index 6cb1b2f0..7f5dffdb 100755 --- a/internal/testdata/snapshots/output/replace-directives/replace_directives.go +++ b/internal/testdata/snapshots/output/replace-directives/replace_directives.go @@ -1,7 +1,5 @@ package replacers // ^^^^^^^^^ definition 0.1.test `sg/replace-directives`/ -// documentation -// > package replacers import ( "fmt" diff --git a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server.go b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server.go index e72bff55..4aca0ae5 100755 --- a/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server.go +++ b/internal/testdata/snapshots/output/sharedtestmodule/cmd/gitserver/server/server.go @@ -1,7 +1,5 @@ package server // ^^^^^^ definition 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/ -// documentation -// > package server //⌄ enclosing_range_start 0.1.test `sg/sharedtestmodule/cmd/gitserver/server`/AnythingAtAll(). func AnythingAtAll() {} diff --git a/internal/testdata/snapshots/output/switches/switches.go b/internal/testdata/snapshots/output/switches/switches.go index afd3338f..1898f871 100755 --- a/internal/testdata/snapshots/output/switches/switches.go +++ b/internal/testdata/snapshots/output/switches/switches.go @@ -1,7 +1,5 @@ package switches // ^^^^^^^^ definition 0.1.test `sg/switches`/ -// documentation -// > package switches // CustomSwitch does the things in a switch type CustomSwitch struct{} diff --git a/internal/testdata/snapshots/output/testdata/cmd/minimal_main/minimal_main.go b/internal/testdata/snapshots/output/testdata/cmd/minimal_main/minimal_main.go index 9f1c3277..695e577c 100755 --- a/internal/testdata/snapshots/output/testdata/cmd/minimal_main/minimal_main.go +++ b/internal/testdata/snapshots/output/testdata/cmd/minimal_main/minimal_main.go @@ -1,7 +1,5 @@ package main // ^^^^ definition 0.1.test `sg/testdata/cmd/minimal_main`/ -// documentation -// > package main type User struct { // ^^^^ definition 0.1.test `sg/testdata/cmd/minimal_main`/User# diff --git a/internal/testdata/snapshots/output/testdata/conflicting_test_symbols/sandbox_unsupported_test.go b/internal/testdata/snapshots/output/testdata/conflicting_test_symbols/sandbox_unsupported_test.go index 128caac5..5f797f46 100755 --- a/internal/testdata/snapshots/output/testdata/conflicting_test_symbols/sandbox_unsupported_test.go +++ b/internal/testdata/snapshots/output/testdata/conflicting_test_symbols/sandbox_unsupported_test.go @@ -3,8 +3,6 @@ package osl // ^^^ definition 0.1.test `sg/testdata/conflicting_test_symbols`/ -// documentation -// > package osl import ( "errors" diff --git a/internal/testdata/snapshots/output/testdata/data.go b/internal/testdata/snapshots/output/testdata/data.go index a4fb5b49..39b1119c 100755 --- a/internal/testdata/snapshots/output/testdata/data.go +++ b/internal/testdata/snapshots/output/testdata/data.go @@ -1,7 +1,5 @@ package testdata // ^^^^^^^^ definition 0.1.test `sg/testdata`/ -// documentation -// > package testdata import ( "context" diff --git a/internal/testdata/snapshots/output/testdata/duplicate_path_id/two.go b/internal/testdata/snapshots/output/testdata/duplicate_path_id/two.go index f85af41e..76d551a5 100755 --- a/internal/testdata/snapshots/output/testdata/duplicate_path_id/two.go +++ b/internal/testdata/snapshots/output/testdata/duplicate_path_id/two.go @@ -1,7 +1,5 @@ package gosrc // ^^^^^ definition 0.1.test `sg/testdata/duplicate_path_id`/ -// documentation -// > package gosrc //⌄ enclosing_range_start 0.1.test `sg/testdata/duplicate_path_id`/init(). func init() {} diff --git a/internal/testdata/snapshots/output/testspecial/foo.go b/internal/testdata/snapshots/output/testspecial/foo.go index 0ba160c2..88471e57 100755 --- a/internal/testdata/snapshots/output/testspecial/foo.go +++ b/internal/testdata/snapshots/output/testspecial/foo.go @@ -1,7 +1,5 @@ package testspecial // ^^^^^^^^^^^ definition 0.1.test `sg/testspecial`/ -// documentation -// > package testspecial //⌄ enclosing_range_start 0.1.test `sg/testspecial`/Foo(). func Foo() {} diff --git a/internal/testdata/snapshots/output/testspecial/foo_other_test.go b/internal/testdata/snapshots/output/testspecial/foo_other_test.go index 6045f771..bb7ad64f 100755 --- a/internal/testdata/snapshots/output/testspecial/foo_other_test.go +++ b/internal/testdata/snapshots/output/testspecial/foo_other_test.go @@ -1,7 +1,5 @@ package testspecial_test // ^^^^^^^^^^^^^^^^ definition 0.1.test `sg/testspecial_test`/ -// documentation -// > package testspecial_test import ( "testing" From 8e07762948a902c6588890f2f02c1c06db797215 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 15:14:37 +0200 Subject: [PATCH 04/14] Use display_name and signature_documentation for package symbols Instead of stuffing everything into the legacy documentation field, emit proper SCIP fields per the proto spec: - display_name: the package name (e.g. 'initial') - signature_documentation: 'package ' as Go source - documentation: only the actual doc comment, when present --- internal/document/document.go | 5 +++++ internal/index/scip.go | 20 ++++++++++++++++--- .../snapshots/output/initial/builtin_types.go | 3 +++ .../output/initial/package_definition.go | 3 --- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/internal/document/document.go b/internal/document/document.go index 2a518da7..7f23e746 100644 --- a/internal/document/document.go +++ b/internal/document/document.go @@ -61,6 +61,11 @@ func (d *Document) GetSymbol(pos token.Pos) (string, bool) { return d.pkgSymbols.GetSymbol(pos) } +// SetSymbolInformation registers a pre-built SymbolInformation at the given position. +func (d *Document) SetSymbolInformation(pos token.Pos, info *scip.SymbolInformation) { + d.pkgSymbols.Set(pos, info) +} + // SetNewSymbol declares a new symbol and tracks it within a Document. // // NOTE: Does NOT emit a new occurrence diff --git a/internal/index/scip.go b/internal/index/scip.go index a99ccee5..059c0842 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -196,13 +196,27 @@ func indexVisitPackages( atomic.AddUint64(&count, 1) continue } + // Build SymbolInformation for the package symbol. + symInfo := &scip.SymbolInformation{ + Symbol: pkgSymbol, + DisplayName: pkg.Name, + SignatureDocumentation: &scip.Document{ + Language: "go", + Text: "package " + pkg.Name, + }, + } + if pkgDocFile != nil && pkgDocFile.Doc != nil { + symInfo.Documentation = []string{pkgDocFile.Doc.Text()} + } + + symInfoEmitted := false for _, f := range pkg.Syntax { doc := pathToDocuments[pkg.Fset.File(f.Package).Name()] position := pkg.Fset.Position(f.Name.NamePos) - // The doc file provides the SymbolInformation with documentation. - if f == pkgDocFile { - doc.SetNewSymbolForPos(pkgSymbol, pkgDocFile, f.Name, f.Name.NamePos) + if !symInfoEmitted { + doc.SetSymbolInformation(f.Name.NamePos, symInfo) + symInfoEmitted = true } // Every package statement is a definition of the package symbol. diff --git a/internal/testdata/snapshots/output/initial/builtin_types.go b/internal/testdata/snapshots/output/initial/builtin_types.go index 31bd185f..2f2baf97 100755 --- a/internal/testdata/snapshots/output/initial/builtin_types.go +++ b/internal/testdata/snapshots/output/initial/builtin_types.go @@ -1,5 +1,8 @@ package initial // ^^^^^^^ definition 0.1.test `sg/initial`/ +// documentation +// > This is a module for testing purposes. +// > This should now be the place that has a definition //⌄ enclosing_range_start 0.1.test `sg/initial`/UsesBuiltin(). func UsesBuiltin() int { diff --git a/internal/testdata/snapshots/output/initial/package_definition.go b/internal/testdata/snapshots/output/initial/package_definition.go index dbcd19f8..12ccce63 100755 --- a/internal/testdata/snapshots/output/initial/package_definition.go +++ b/internal/testdata/snapshots/output/initial/package_definition.go @@ -2,7 +2,4 @@ // This should now be the place that has a definition package initial // ^^^^^^^ definition 0.1.test `sg/initial`/ -// documentation -// > This is a module for testing purposes. -// > This should now be the place that has a definition From c0d0af1cd852145e7e40a80a94d9a383c085b563 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 15:19:28 +0200 Subject: [PATCH 05/14] Fix internal/loader/stdlib.go package comment --- internal/loader/stdlib.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/loader/stdlib.go b/internal/loader/stdlib.go index bc74f08d..6f33f4bd 100644 --- a/internal/loader/stdlib.go +++ b/internal/loader/stdlib.go @@ -1,5 +1,6 @@ // THIS FILE IS GENERATED. NO NEED TO REGENERATE FOR GO 1.25 OR LATER. // Generated by: go version go1.24.0 darwin/arm64 + package loader var contained = struct{}{} From c7f3d5fea0792eae120d4b719ca5dc12cc6f1f85 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 16:00:09 +0200 Subject: [PATCH 06/14] Simplify findPackageDoc to return doc text string directly Instead of returning *ast.File and extracting Doc.Text() at the call site, return the doc comment text directly. This removes the need for the caller to know about ast.File internals. --- internal/index/package_ident.go | 27 +++---- internal/index/package_ident_test.go | 104 ++++++++++++--------------- internal/index/scip.go | 7 +- 3 files changed, 60 insertions(+), 78 deletions(-) diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index ba63e15e..fcbe999c 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -8,10 +8,10 @@ import ( "golang.org/x/tools/go/packages" ) -// findPackageDocFile picks the file whose doc comment should represent -// the package's documentation in the SCIP index. Returns nil if no file +// findPackageDoc returns the doc comment text for the package, picking the +// best file when multiple files have doc comments. Returns "" if no file // has a package doc comment. -func findPackageDocFile(pkg *packages.Package) *ast.File { +func findPackageDoc(pkg *packages.Package) string { var filesWithDocs []*ast.File for _, f := range pkg.Syntax { if f.Doc != nil { @@ -19,29 +19,24 @@ func findPackageDocFile(pkg *packages.Package) *ast.File { } } - if len(filesWithDocs) == 1 { - return filesWithDocs[0] - } - - if len(filesWithDocs) == 0 { - return nil + candidates := filterBasedOnTestFiles(pkg, filesWithDocs) + if len(candidates) == 0 { + return "" } - // Multiple files have doc comments. Prefer doc.go, then the file matching - // the package name, then pick the first candidate. - candidates := filterBasedOnTestFiles(pkg, filesWithDocs) + // Prefer doc.go, then the file matching the package name, then pick the + // first candidate. for _, f := range candidates { if path.Base(pkg.Fset.Position(f.Pos()).Filename) == "doc.go" { - return f + return f.Doc.Text() } } for _, f := range candidates { if fileNameWithoutExtension(pkg.Fset.Position(f.Pos()).Filename) == pkg.Name { - return f + return f.Doc.Text() } } - - return candidates[0] + return candidates[0].Doc.Text() } func fileNameWithoutExtension(fileName string) string { diff --git a/internal/index/package_ident_test.go b/internal/index/package_ident_test.go index 4d7d7697..5e85ed97 100644 --- a/internal/index/package_ident_test.go +++ b/internal/index/package_ident_test.go @@ -3,110 +3,100 @@ package index import ( "go/ast" "go/token" + "strings" "testing" "golang.org/x/tools/go/packages" ) -func TestFindPackageDocFile(t *testing.T) { +func TestFindPackageDoc(t *testing.T) { type FileInfo struct { - Name string - Docs bool + Name string + DocText string } - makePackage := func(pkgName string, fileInfo []FileInfo) (*packages.Package, map[*ast.File]string) { + makePackage := func(pkgName string, fileInfo []FileInfo) *packages.Package { fset := token.NewFileSet() - - syntax := []*ast.File{} - posMap := map[*ast.File]string{} + var syntax []*ast.File for _, info := range fileInfo { var doc *ast.CommentGroup - if info.Docs { - doc = &ast.CommentGroup{} + if info.DocText != "" { + doc = &ast.CommentGroup{ + List: []*ast.Comment{{Text: "// " + info.DocText}}, + } } tf := fset.AddFile(info.Name, fset.Base(), 1) - f := &ast.File{ + syntax = append(syntax, &ast.File{ Doc: doc, Package: tf.Pos(0), - Name: &ast.Ident{ - Name: pkgName, - Obj: &ast.Object{}, - }, - } - - syntax = append(syntax, f) - posMap[f] = info.Name + Name: &ast.Ident{Name: pkgName}, + }) } return &packages.Package{ - ID: "test-package", Name: pkgName, PkgPath: "test-package", - Imports: map[string]*packages.Package{}, Fset: fset, Syntax: syntax, - }, posMap + } } - t.Run("returns nil when no file has docs", func(t *testing.T) { - pkg, _ := makePackage("smol", []FileInfo{ - {"smol.go", false}, - {"other.go", false}, + t.Run("returns empty when no file has docs", func(t *testing.T) { + pkg := makePackage("smol", []FileInfo{ + {"smol.go", ""}, + {"other.go", ""}, }) - if f := findPackageDocFile(pkg); f != nil { - t.Errorf("expected nil, got a file") + if doc := findPackageDoc(pkg); doc != "" { + t.Errorf("expected empty, got %q", doc) } }) - t.Run("returns the single file with docs", func(t *testing.T) { - pkg, names := makePackage("mylib", []FileInfo{ - {"mylib.go", false}, - {"has_docs.go", true}, + t.Run("returns doc from the single file with docs", func(t *testing.T) { + pkg := makePackage("mylib", []FileInfo{ + {"mylib.go", ""}, + {"has_docs.go", "Package docs here"}, }) - f := findPackageDocFile(pkg) - if f == nil { - t.Fatal("expected a file, got nil") - } - if name := names[f]; name != "has_docs.go" { - t.Errorf("want=has_docs.go have=%s", name) + doc := findPackageDoc(pkg) + if doc == "" { + t.Fatal("expected doc text, got empty") } }) t.Run("prefers doc.go when multiple files have docs", func(t *testing.T) { - pkg, names := makePackage("mylib", []FileInfo{ - {"mylib.go", true}, - {"doc.go", true}, + pkg := makePackage("mylib", []FileInfo{ + {"mylib.go", "from mylib"}, + {"doc.go", "from doc.go"}, }) - f := findPackageDocFile(pkg) - if f == nil { - t.Fatal("expected a file, got nil") + doc := findPackageDoc(pkg) + if doc == "" { + t.Fatal("expected doc text, got empty") } - if name := names[f]; name != "doc.go" { - t.Errorf("want=doc.go have=%s", name) + if !strings.Contains(doc, "from doc.go") { + t.Errorf("expected doc from doc.go, got %q", doc) } }) t.Run("prefers exact package name match when multiple files have docs", func(t *testing.T) { - pkg, names := makePackage("mylib", []FileInfo{ - {"other.go", true}, - {"mylib.go", true}, + pkg := makePackage("mylib", []FileInfo{ + {"other.go", "from other"}, + {"mylib.go", "from mylib"}, }) - f := findPackageDocFile(pkg) - if f == nil { - t.Fatal("expected a file, got nil") + doc := findPackageDoc(pkg) + if doc == "" { + t.Fatal("expected doc text, got empty") } - if name := names[f]; name != "mylib.go" { - t.Errorf("want=mylib.go have=%s", name) + if !strings.Contains(doc, "from mylib") { + t.Errorf("expected doc from mylib.go, got %q", doc) } }) - t.Run("returns nil for empty syntax", func(t *testing.T) { - pkg, _ := makePackage("mylib", []FileInfo{}) - if f := findPackageDocFile(pkg); f != nil { - t.Errorf("expected nil, got a file") + t.Run("returns empty for empty syntax", func(t *testing.T) { + pkg := makePackage("mylib", []FileInfo{}) + if doc := findPackageDoc(pkg); doc != "" { + t.Errorf("expected empty, got %q", doc) } }) } diff --git a/internal/index/scip.go b/internal/index/scip.go index 059c0842..bb1cf10b 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -186,9 +186,6 @@ func indexVisitPackages( slog.Debug("Visiting package", "path", pkg.PkgPath) visitors.VisitPackageSyntax(opts.ModuleRoot, pkg, pathToDocuments, globalSymbols) - // Find the file whose doc comment represents the package documentation. - pkgDocFile := findPackageDocFile(pkg) - pkgSymbol := globalSymbols.SetPkgSymbol(pkg) // If we don't have this package anywhere, don't try to create a new symbol @@ -205,8 +202,8 @@ func indexVisitPackages( Text: "package " + pkg.Name, }, } - if pkgDocFile != nil && pkgDocFile.Doc != nil { - symInfo.Documentation = []string{pkgDocFile.Doc.Text()} + if pkgDoc := findPackageDoc(pkg); pkgDoc != "" { + symInfo.Documentation = []string{pkgDoc} } symInfoEmitted := false From e670ad3748b4dcf463e5762f51c93d6371465b23 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 16:10:34 +0200 Subject: [PATCH 07/14] Return all package doc comments sorted by relevance findPackageDocs now returns all doc comments from all files in the package, sorted by relevance: doc.go first, then exact package name match, then other non-test files, and test files last. Previously only the single best doc comment was returned and test files were excluded entirely. --- internal/document/document.go | 4 +- internal/index/package_ident.go | 67 ++++++++++++---------------- internal/index/package_ident_test.go | 52 +++++++++++---------- internal/index/scip.go | 9 ++-- 4 files changed, 63 insertions(+), 69 deletions(-) diff --git a/internal/document/document.go b/internal/document/document.go index 7f23e746..a9b8d9bd 100644 --- a/internal/document/document.go +++ b/internal/document/document.go @@ -62,7 +62,9 @@ func (d *Document) GetSymbol(pos token.Pos) (string, bool) { } // SetSymbolInformation registers a pre-built SymbolInformation at the given position. -func (d *Document) SetSymbolInformation(pos token.Pos, info *scip.SymbolInformation) { +func (d *Document) SetSymbolInformation( + pos token.Pos, info *scip.SymbolInformation, +) { d.pkgSymbols.Set(pos, info) } diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index fcbe999c..2a46ffea 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -3,15 +3,17 @@ package index import ( "go/ast" "path" + "sort" "strings" "golang.org/x/tools/go/packages" ) -// findPackageDoc returns the doc comment text for the package, picking the -// best file when multiple files have doc comments. Returns "" if no file -// has a package doc comment. -func findPackageDoc(pkg *packages.Package) string { +// findPackageDocs returns all doc comment texts for the package, sorted by +// relevance: doc.go first, then the file matching the package name, then +// other matching files, and finally test/non-test mismatched files last. +// Returns nil if no file has a package doc comment. +func findPackageDocs(pkg *packages.Package) []string { var filesWithDocs []*ast.File for _, f := range pkg.Syntax { if f.Doc != nil { @@ -19,44 +21,33 @@ func findPackageDoc(pkg *packages.Package) string { } } - candidates := filterBasedOnTestFiles(pkg, filesWithDocs) - if len(candidates) == 0 { - return "" + if len(filesWithDocs) == 0 { + return nil } - // Prefer doc.go, then the file matching the package name, then pick the - // first candidate. - for _, f := range candidates { - if path.Base(pkg.Fset.Position(f.Pos()).Filename) == "doc.go" { - return f.Doc.Text() - } - } - for _, f := range candidates { - if fileNameWithoutExtension(pkg.Fset.Position(f.Pos()).Filename) == pkg.Name { - return f.Doc.Text() - } - } - return candidates[0].Doc.Text() -} + sort.SliceStable(filesWithDocs, func(i, j int) bool { + return fileRelevance(pkg, filesWithDocs[i]) < fileRelevance(pkg, filesWithDocs[j]) + }) -func fileNameWithoutExtension(fileName string) string { - return strings.TrimSuffix(fileName, path.Ext(fileName)) -} - -func filterBasedOnTestFiles(pkg *packages.Package, files []*ast.File) []*ast.File { - packageNameEndsWithTest := strings.HasSuffix(pkg.Name, "_test") - - var preferredFiles []*ast.File - for _, f := range files { - fPath := pkg.Fset.Position(f.Pos()) - if packageNameEndsWithTest == strings.HasSuffix(fPath.Filename, "_test.go") { - preferredFiles = append(preferredFiles, f) - } + docs := make([]string, 0, len(filesWithDocs)) + for _, f := range filesWithDocs { + docs = append(docs, f.Doc.Text()) } + return docs +} - if len(preferredFiles) > 0 { - return preferredFiles +// fileRelevance returns a sort key: lower is more relevant. +func fileRelevance(pkg *packages.Package, f *ast.File) int { + fPath := pkg.Fset.Position(f.Pos()).Filename + + switch { + case path.Base(fPath) == "doc.go": + return 0 + case strings.TrimSuffix(path.Base(fPath), path.Ext(fPath)) == pkg.Name: + return 1 + case !strings.HasSuffix(fPath, "_test.go"): + return 2 + default: + return 3 } - - return files } diff --git a/internal/index/package_ident_test.go b/internal/index/package_ident_test.go index 5e85ed97..540c3c8c 100644 --- a/internal/index/package_ident_test.go +++ b/internal/index/package_ident_test.go @@ -9,7 +9,7 @@ import ( "golang.org/x/tools/go/packages" ) -func TestFindPackageDoc(t *testing.T) { +func TestFindPackageDocs(t *testing.T) { type FileInfo struct { Name string DocText string @@ -44,59 +44,63 @@ func TestFindPackageDoc(t *testing.T) { } } - t.Run("returns empty when no file has docs", func(t *testing.T) { + t.Run("returns nil when no file has docs", func(t *testing.T) { pkg := makePackage("smol", []FileInfo{ {"smol.go", ""}, {"other.go", ""}, }) - if doc := findPackageDoc(pkg); doc != "" { - t.Errorf("expected empty, got %q", doc) + if docs := findPackageDocs(pkg); docs != nil { + t.Errorf("expected nil, got %v", docs) } }) - t.Run("returns doc from the single file with docs", func(t *testing.T) { + t.Run("returns single doc", func(t *testing.T) { pkg := makePackage("mylib", []FileInfo{ {"mylib.go", ""}, - {"has_docs.go", "Package docs here"}, + {"has_docs.go", "Package docs"}, }) - doc := findPackageDoc(pkg) - if doc == "" { - t.Fatal("expected doc text, got empty") + docs := findPackageDocs(pkg) + if len(docs) != 1 { + t.Fatalf("expected 1 doc, got %d", len(docs)) } }) - t.Run("prefers doc.go when multiple files have docs", func(t *testing.T) { + t.Run("returns all docs sorted with doc.go first", func(t *testing.T) { pkg := makePackage("mylib", []FileInfo{ {"mylib.go", "from mylib"}, {"doc.go", "from doc.go"}, + {"other.go", "from other"}, }) - doc := findPackageDoc(pkg) - if doc == "" { - t.Fatal("expected doc text, got empty") + docs := findPackageDocs(pkg) + if len(docs) != 3 { + t.Fatalf("expected 3 docs, got %d", len(docs)) + } + if !strings.Contains(docs[0], "from doc.go") { + t.Errorf("expected doc.go first, got %q", docs[0]) } - if !strings.Contains(doc, "from doc.go") { - t.Errorf("expected doc from doc.go, got %q", doc) + if !strings.Contains(docs[1], "from mylib") { + t.Errorf("expected mylib.go second, got %q", docs[1]) } }) - t.Run("prefers exact package name match when multiple files have docs", func(t *testing.T) { + t.Run("returns all docs sorted with package name match first when no doc.go", func(t *testing.T) { pkg := makePackage("mylib", []FileInfo{ {"other.go", "from other"}, {"mylib.go", "from mylib"}, }) - doc := findPackageDoc(pkg) - if doc == "" { - t.Fatal("expected doc text, got empty") + docs := findPackageDocs(pkg) + if len(docs) != 2 { + t.Fatalf("expected 2 docs, got %d", len(docs)) } - if !strings.Contains(doc, "from mylib") { - t.Errorf("expected doc from mylib.go, got %q", doc) + if !strings.Contains(docs[0], "from mylib") { + t.Errorf("expected mylib.go first, got %q", docs[0]) } }) - t.Run("returns empty for empty syntax", func(t *testing.T) { + t.Run("returns nil for empty syntax", func(t *testing.T) { pkg := makePackage("mylib", []FileInfo{}) - if doc := findPackageDoc(pkg); doc != "" { - t.Errorf("expected empty, got %q", doc) + if docs := findPackageDocs(pkg); docs != nil { + t.Errorf("expected nil, got %v", docs) } }) } diff --git a/internal/index/scip.go b/internal/index/scip.go index bb1cf10b..9a4a6f4b 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -195,16 +195,14 @@ func indexVisitPackages( } // Build SymbolInformation for the package symbol. symInfo := &scip.SymbolInformation{ - Symbol: pkgSymbol, - DisplayName: pkg.Name, + Symbol: pkgSymbol, + DisplayName: pkg.Name, + Documentation: findPackageDocs(pkg), SignatureDocumentation: &scip.Document{ Language: "go", Text: "package " + pkg.Name, }, } - if pkgDoc := findPackageDoc(pkg); pkgDoc != "" { - symInfo.Documentation = []string{pkgDoc} - } symInfoEmitted := false for _, f := range pkg.Syntax { @@ -216,7 +214,6 @@ func indexVisitPackages( symInfoEmitted = true } - // Every package statement is a definition of the package symbol. doc.PackageOccurrence = &scip.Occurrence{ Range: symbols.RangeFromName(position, f.Name.Name, false), Symbol: pkgSymbol, From 38dc9d4722525b65bf09eddb4bb76769c85c38f8 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 19:51:32 +0200 Subject: [PATCH 08/14] Add snapshot test for package definition and documentation changes Covers: all package declarations as definitions, display_name and signature_documentation fields, multi-file doc comment collection sorted by relevance, and file header comments separated by blank lines not treated as doc comments. --- .../testdata/snapshots/input/pr199/doc.go | 4 ++++ .../testdata/snapshots/input/pr199/go.mod | 3 +++ .../testdata/snapshots/input/pr199/no_doc.go | 5 +++++ .../testdata/snapshots/input/pr199/pr199.go | 4 ++++ .../snapshots/input/pr199/pr199_test.go | 6 ++++++ .../testdata/snapshots/output/pr199/doc.go | 19 +++++++++++++++++++ .../testdata/snapshots/output/pr199/no_doc.go | 14 ++++++++++++++ .../testdata/snapshots/output/pr199/pr199.go | 13 +++++++++++++ .../snapshots/output/pr199/pr199_test.go | 19 +++++++++++++++++++ 9 files changed, 87 insertions(+) create mode 100644 internal/testdata/snapshots/input/pr199/doc.go create mode 100644 internal/testdata/snapshots/input/pr199/go.mod create mode 100644 internal/testdata/snapshots/input/pr199/no_doc.go create mode 100644 internal/testdata/snapshots/input/pr199/pr199.go create mode 100644 internal/testdata/snapshots/input/pr199/pr199_test.go create mode 100755 internal/testdata/snapshots/output/pr199/doc.go create mode 100755 internal/testdata/snapshots/output/pr199/no_doc.go create mode 100755 internal/testdata/snapshots/output/pr199/pr199.go create mode 100755 internal/testdata/snapshots/output/pr199/pr199_test.go diff --git a/internal/testdata/snapshots/input/pr199/doc.go b/internal/testdata/snapshots/input/pr199/doc.go new file mode 100644 index 00000000..efd9b218 --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/doc.go @@ -0,0 +1,4 @@ +// Package pr199 tests package definition and documentation handling. +package pr199 + +func FromDoc() {} diff --git a/internal/testdata/snapshots/input/pr199/go.mod b/internal/testdata/snapshots/input/pr199/go.mod new file mode 100644 index 00000000..793fd4d1 --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/go.mod @@ -0,0 +1,3 @@ +module sg/pr199 + +go 1.23 diff --git a/internal/testdata/snapshots/input/pr199/no_doc.go b/internal/testdata/snapshots/input/pr199/no_doc.go new file mode 100644 index 00000000..362961bd --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/no_doc.go @@ -0,0 +1,5 @@ +// THIS FILE IS GENERATED. + +package pr199 + +func FromNoDoc() {} diff --git a/internal/testdata/snapshots/input/pr199/pr199.go b/internal/testdata/snapshots/input/pr199/pr199.go new file mode 100644 index 00000000..3de8b0d6 --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/pr199.go @@ -0,0 +1,4 @@ +// Additional documentation from the main file. +package pr199 + +func FromMain() {} diff --git a/internal/testdata/snapshots/input/pr199/pr199_test.go b/internal/testdata/snapshots/input/pr199/pr199_test.go new file mode 100644 index 00000000..63ab3f78 --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/pr199_test.go @@ -0,0 +1,6 @@ +// Test file documentation for pr199. +package pr199 + +import "testing" + +func TestExample(t *testing.T) {} diff --git a/internal/testdata/snapshots/output/pr199/doc.go b/internal/testdata/snapshots/output/pr199/doc.go new file mode 100755 index 00000000..f7663386 --- /dev/null +++ b/internal/testdata/snapshots/output/pr199/doc.go @@ -0,0 +1,19 @@ + // Package pr199 tests package definition and documentation handling. + package pr199 +// ^^^^^ definition 0.1.test `sg/pr199`/ +// documentation +// > Package pr199 tests package definition and documentation handling. +// documentation +// > Additional documentation from the main file. +// documentation +// > Test file documentation for pr199. + +//⌄ enclosing_range_start 0.1.test `sg/pr199`/FromDoc(). + func FromDoc() {} +// ^^^^^^^ definition 0.1.test `sg/pr199`/FromDoc(). +// documentation +// > ```go +// > func FromDoc() +// > ``` +// ⌃ enclosing_range_end 0.1.test `sg/pr199`/FromDoc(). + diff --git a/internal/testdata/snapshots/output/pr199/no_doc.go b/internal/testdata/snapshots/output/pr199/no_doc.go new file mode 100755 index 00000000..b7d59d69 --- /dev/null +++ b/internal/testdata/snapshots/output/pr199/no_doc.go @@ -0,0 +1,14 @@ + // THIS FILE IS GENERATED. + + package pr199 +// ^^^^^ definition 0.1.test `sg/pr199`/ + +//⌄ enclosing_range_start 0.1.test `sg/pr199`/FromNoDoc(). + func FromNoDoc() {} +// ^^^^^^^^^ definition 0.1.test `sg/pr199`/FromNoDoc(). +// documentation +// > ```go +// > func FromNoDoc() +// > ``` +// ⌃ enclosing_range_end 0.1.test `sg/pr199`/FromNoDoc(). + diff --git a/internal/testdata/snapshots/output/pr199/pr199.go b/internal/testdata/snapshots/output/pr199/pr199.go new file mode 100755 index 00000000..2d4aeec8 --- /dev/null +++ b/internal/testdata/snapshots/output/pr199/pr199.go @@ -0,0 +1,13 @@ + // Additional documentation from the main file. + package pr199 +// ^^^^^ definition 0.1.test `sg/pr199`/ + +//⌄ enclosing_range_start 0.1.test `sg/pr199`/FromMain(). + func FromMain() {} +// ^^^^^^^^ definition 0.1.test `sg/pr199`/FromMain(). +// documentation +// > ```go +// > func FromMain() +// > ``` +// ⌃ enclosing_range_end 0.1.test `sg/pr199`/FromMain(). + diff --git a/internal/testdata/snapshots/output/pr199/pr199_test.go b/internal/testdata/snapshots/output/pr199/pr199_test.go new file mode 100755 index 00000000..cb14dddb --- /dev/null +++ b/internal/testdata/snapshots/output/pr199/pr199_test.go @@ -0,0 +1,19 @@ + // Test file documentation for pr199. + package pr199 +// ^^^^^ definition 0.1.test `sg/pr199`/ + + import "testing" +// ^^^^^^^ reference github.com/golang/go/src go1.22 testing/ + +//⌄ enclosing_range_start 0.1.test `sg/pr199`/TestExample(). + func TestExample(t *testing.T) {} +// ^^^^^^^^^^^ definition 0.1.test `sg/pr199`/TestExample(). +// documentation +// > ```go +// > func TestExample(t *T) +// > ``` +// ^ definition local 0 +// ^^^^^^^ reference github.com/golang/go/src go1.22 testing/ +// ^ reference github.com/golang/go/src go1.22 testing/T# +// ⌃ enclosing_range_end 0.1.test `sg/pr199`/TestExample(). + From dc224e3fa9ef3653e51ef42754b5d219ca589d6f Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 20:05:50 +0200 Subject: [PATCH 09/14] Remove redundant empty check in findPackageDocs The sort and loop handle empty input naturally. Use var instead of make so nil is returned when no files have doc comments. --- internal/index/package_ident.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index 2a46ffea..0839bb2b 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -21,15 +21,11 @@ func findPackageDocs(pkg *packages.Package) []string { } } - if len(filesWithDocs) == 0 { - return nil - } - sort.SliceStable(filesWithDocs, func(i, j int) bool { return fileRelevance(pkg, filesWithDocs[i]) < fileRelevance(pkg, filesWithDocs[j]) }) - docs := make([]string, 0, len(filesWithDocs)) + var docs []string for _, f := range filesWithDocs { docs = append(docs, f.Doc.Text()) } From 57735d4550b700287b3ad69a2b54a3d23326ee18 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 20:09:52 +0200 Subject: [PATCH 10/14] Pass filename string to fileRelevance instead of ast.File --- internal/index/package_ident.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/index/package_ident.go b/internal/index/package_ident.go index 0839bb2b..868a8cae 100644 --- a/internal/index/package_ident.go +++ b/internal/index/package_ident.go @@ -22,7 +22,9 @@ func findPackageDocs(pkg *packages.Package) []string { } sort.SliceStable(filesWithDocs, func(i, j int) bool { - return fileRelevance(pkg, filesWithDocs[i]) < fileRelevance(pkg, filesWithDocs[j]) + fi := pkg.Fset.Position(filesWithDocs[i].Pos()).Filename + fj := pkg.Fset.Position(filesWithDocs[j].Pos()).Filename + return fileRelevance(pkg.Name, fi) < fileRelevance(pkg.Name, fj) }) var docs []string @@ -33,15 +35,13 @@ func findPackageDocs(pkg *packages.Package) []string { } // fileRelevance returns a sort key: lower is more relevant. -func fileRelevance(pkg *packages.Package, f *ast.File) int { - fPath := pkg.Fset.Position(f.Pos()).Filename - +func fileRelevance(pkgName, filename string) int { switch { - case path.Base(fPath) == "doc.go": + case path.Base(filename) == "doc.go": return 0 - case strings.TrimSuffix(path.Base(fPath), path.Ext(fPath)) == pkg.Name: + case strings.TrimSuffix(path.Base(filename), path.Ext(filename)) == pkgName: return 1 - case !strings.HasSuffix(fPath, "_test.go"): + case !strings.HasSuffix(filename, "_test.go"): return 2 default: return 3 From 825b7f3f365681b12e253263ad182b2efcb7b50f Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 20:17:34 +0200 Subject: [PATCH 11/14] Improve package_ident tests: compare full slices and add fileRelevance test --- internal/index/package_ident_test.go | 64 +++++++++++++++++----------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/internal/index/package_ident_test.go b/internal/index/package_ident_test.go index 540c3c8c..883ce330 100644 --- a/internal/index/package_ident_test.go +++ b/internal/index/package_ident_test.go @@ -3,7 +3,7 @@ package index import ( "go/ast" "go/token" - "strings" + "slices" "testing" "golang.org/x/tools/go/packages" @@ -44,6 +44,11 @@ func TestFindPackageDocs(t *testing.T) { } } + // doc produces the text that ast.CommentGroup.Text() returns for a "// text" comment. + doc := func(text string) string { + return text + "\n" + } + t.Run("returns nil when no file has docs", func(t *testing.T) { pkg := makePackage("smol", []FileInfo{ {"smol.go", ""}, @@ -54,14 +59,22 @@ func TestFindPackageDocs(t *testing.T) { } }) + t.Run("returns nil for empty syntax", func(t *testing.T) { + pkg := makePackage("mylib", []FileInfo{}) + if docs := findPackageDocs(pkg); docs != nil { + t.Errorf("expected nil, got %v", docs) + } + }) + t.Run("returns single doc", func(t *testing.T) { pkg := makePackage("mylib", []FileInfo{ {"mylib.go", ""}, {"has_docs.go", "Package docs"}, }) - docs := findPackageDocs(pkg) - if len(docs) != 1 { - t.Fatalf("expected 1 doc, got %d", len(docs)) + want := []string{doc("Package docs")} + got := findPackageDocs(pkg) + if !slices.Equal(got, want) { + t.Errorf("want %v, got %v", want, got) } }) @@ -71,15 +84,10 @@ func TestFindPackageDocs(t *testing.T) { {"doc.go", "from doc.go"}, {"other.go", "from other"}, }) - docs := findPackageDocs(pkg) - if len(docs) != 3 { - t.Fatalf("expected 3 docs, got %d", len(docs)) - } - if !strings.Contains(docs[0], "from doc.go") { - t.Errorf("expected doc.go first, got %q", docs[0]) - } - if !strings.Contains(docs[1], "from mylib") { - t.Errorf("expected mylib.go second, got %q", docs[1]) + want := []string{doc("from doc.go"), doc("from mylib"), doc("from other")} + got := findPackageDocs(pkg) + if !slices.Equal(got, want) { + t.Errorf("want %v, got %v", want, got) } }) @@ -88,19 +96,27 @@ func TestFindPackageDocs(t *testing.T) { {"other.go", "from other"}, {"mylib.go", "from mylib"}, }) - docs := findPackageDocs(pkg) - if len(docs) != 2 { - t.Fatalf("expected 2 docs, got %d", len(docs)) - } - if !strings.Contains(docs[0], "from mylib") { - t.Errorf("expected mylib.go first, got %q", docs[0]) + want := []string{doc("from mylib"), doc("from other")} + got := findPackageDocs(pkg) + if !slices.Equal(got, want) { + t.Errorf("want %v, got %v", want, got) } }) +} - t.Run("returns nil for empty syntax", func(t *testing.T) { - pkg := makePackage("mylib", []FileInfo{}) - if docs := findPackageDocs(pkg); docs != nil { - t.Errorf("expected nil, got %v", docs) +func TestFileRelevance(t *testing.T) { + tests := []struct { + filename string + want int + }{ + {"doc.go", 0}, + {"mylib.go", 1}, + {"other.go", 2}, + {"other_test.go", 3}, + } + for _, tt := range tests { + if got := fileRelevance("mylib", tt.filename); got != tt.want { + t.Errorf("fileRelevance(%q) = %d, want %d", tt.filename, got, tt.want) } - }) + } } From 553ca6921a4d095b8bc0b7e64880e14fcc08b708 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 20:50:46 +0200 Subject: [PATCH 12/14] Move SetSymbolInformation outside the loop and remove dead code Register the package SymbolInformation on the first file before iterating, removing the symInfoEmitted flag. Also remove the unused packagePrefixes function. --- internal/index/scip.go | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/internal/index/scip.go b/internal/index/scip.go index 9a4a6f4b..3ad22b8a 100644 --- a/internal/index/scip.go +++ b/internal/index/scip.go @@ -193,7 +193,7 @@ func indexVisitPackages( atomic.AddUint64(&count, 1) continue } - // Build SymbolInformation for the package symbol. + symInfo := &scip.SymbolInformation{ Symbol: pkgSymbol, DisplayName: pkg.Name, @@ -203,17 +203,14 @@ func indexVisitPackages( Text: "package " + pkg.Name, }, } + firstFile := pkg.Syntax[0] + firstDoc := pathToDocuments[pkg.Fset.File(firstFile.Package).Name()] + firstDoc.SetSymbolInformation(firstFile.Name.NamePos, symInfo) - symInfoEmitted := false for _, f := range pkg.Syntax { doc := pathToDocuments[pkg.Fset.File(f.Package).Name()] position := pkg.Fset.Position(f.Name.NamePos) - if !symInfoEmitted { - doc.SetSymbolInformation(f.Name.NamePos, symInfo) - symInfoEmitted = true - } - doc.PackageOccurrence = &scip.Occurrence{ Range: symbols.RangeFromName(position, f.Name.Name, false), Symbol: pkgSymbol, @@ -229,16 +226,3 @@ func indexVisitPackages( return pathToDocuments, globalSymbols } - -// packagePrefixes returns all prefix of the go package path. For example, the package -// `foo/bar/baz` will return the slice containing `foo/bar/baz`, `foo/bar`, and `foo`. -func packagePrefixes(packageName string) []string { - parts := strings.Split(packageName, "/") - prefixes := make([]string, len(parts)) - - for i := 1; i <= len(parts); i++ { - prefixes[len(parts)-i] = strings.Join(parts[:i], "/") - } - - return prefixes -} From 54b4cf36c8653ca2a843acb0a92142e7ffec893e Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 21:02:57 +0200 Subject: [PATCH 13/14] Clean up pr199 test: remove unnecessary comment and add README --- internal/testdata/snapshots/input/pr199/README.md | 11 +++++++++++ internal/testdata/snapshots/input/pr199/no_doc.go | 3 +-- internal/testdata/snapshots/output/pr199/doc.go | 2 ++ internal/testdata/snapshots/output/pr199/no_doc.go | 3 +-- 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 internal/testdata/snapshots/input/pr199/README.md diff --git a/internal/testdata/snapshots/input/pr199/README.md b/internal/testdata/snapshots/input/pr199/README.md new file mode 100644 index 00000000..14a3a3a8 --- /dev/null +++ b/internal/testdata/snapshots/input/pr199/README.md @@ -0,0 +1,11 @@ +# pr199 --- Package definition and documentation + +This test covers the package symbol handling introduced in PR #199: + +- Every `package` declaration is emitted as a **definition**, not just one per + package. +- `display_name` and `signature_documentation` are set for all package symbols. +- `documentation` collects doc comments from **all** files, sorted by relevance: + `doc.go` \> exact package name match \> other files \> test files. +- Files without a doc comment (`no_doc.go`) do not contribute to + `documentation`. diff --git a/internal/testdata/snapshots/input/pr199/no_doc.go b/internal/testdata/snapshots/input/pr199/no_doc.go index 362961bd..8d59fc51 100644 --- a/internal/testdata/snapshots/input/pr199/no_doc.go +++ b/internal/testdata/snapshots/input/pr199/no_doc.go @@ -1,5 +1,4 @@ -// THIS FILE IS GENERATED. - +// Documentation for no_doc.go. package pr199 func FromNoDoc() {} diff --git a/internal/testdata/snapshots/output/pr199/doc.go b/internal/testdata/snapshots/output/pr199/doc.go index f7663386..188a1d0c 100755 --- a/internal/testdata/snapshots/output/pr199/doc.go +++ b/internal/testdata/snapshots/output/pr199/doc.go @@ -6,6 +6,8 @@ // documentation // > Additional documentation from the main file. // documentation +// > Documentation for no_doc.go. +// documentation // > Test file documentation for pr199. //⌄ enclosing_range_start 0.1.test `sg/pr199`/FromDoc(). diff --git a/internal/testdata/snapshots/output/pr199/no_doc.go b/internal/testdata/snapshots/output/pr199/no_doc.go index b7d59d69..fdc9d045 100755 --- a/internal/testdata/snapshots/output/pr199/no_doc.go +++ b/internal/testdata/snapshots/output/pr199/no_doc.go @@ -1,5 +1,4 @@ - // THIS FILE IS GENERATED. - + // Documentation for no_doc.go. package pr199 // ^^^^^ definition 0.1.test `sg/pr199`/ From e8298d2ee357b7c38f688da82e6da6e6bf3372c5 Mon Sep 17 00:00:00 2001 From: jupblb Date: Fri, 10 Apr 2026 21:43:36 +0200 Subject: [PATCH 14/14] Fix nix setup --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ef14ad3f..54d17f85 100644 --- a/flake.nix +++ b/flake.nix @@ -26,7 +26,7 @@ pname = "scip-go"; inherit version; src = ./.; - vendorHash = "sha256-JCzF4wT8un6Twpo/KLhWfYIfmjfOK6ygF1KSfed0PHY="; + vendorHash = "sha256-KhmL7QzqPhGyqE8HLfk0YUywzIlvVsVEeNqilRpHFbo="; subPackages = [ "cmd/scip-go" ]; env.CGO_ENABLED = 0; checkPhase = "go test ./...";