What version of Go, VS Code & VS Code Go extension are you using?
go version go1.13.15 linux/amd64
golang.org/x/tools/gopls v0.9.4
golang.org/x/tools/gopls@v0.9.4 h1:YhHOxVi++ILnY+QnH9FGtRKZZrunSaR7OW8/dCp7bBk=
vscode:
Version: 1.70.2 (Universal)
Version Information
* Run `go version` to get version of Go from _the VS Code integrated terminal_. -
Share the Go related settings you have added/edited
see below
Run Preferences: Open Settings (JSON)
command to open your settings.json file.
Share all the settings with the go.
or ["go"]
or gopls
prefixes.
{
"go.autocompleteUnimportedPackages": true,
"go.languageServerFlags": [
],
"go.useLanguageServer": true,
"gopls": {
},
}
Describe the bug
Bug description:
Gopls only finds the references on package level, not on module level.
References in other packages can be found/peeked ONLY AFTER I opened certain package and see the reference,
which is useless, because the point of finding all references is it finds all references for me without needing to open
all the packages.
What I expect: Find all reference finds all references of a function on a module level, it should search all the packages in this module.
Steps to reproduce the behavior:
Use Find all references
all Peek references
feature on any function in a Go project using go module mode, this happens.
Screenshots or recordings
N/A
Comment From: adonovan
@adonovan
Comment From: findleyr
Gopls only finds the references on package level, not on module level.
FWIW, this is not what I observe, and is certainly not the intended behavior. Gopls should find all references within any workspace packages. In other words, if opening up a module root, gopls should find all references contained in any package inside the module. (golang/go#43144 catalogs a known bug about references in test variants, but that doesn't seem to be what is reported here).
It may be that somehow gopls is failing to compute workspace packages correctly. A more specific reproducer would be helpful.
Comment From: zejunlitg
@findleyr Hi, Does
Find all references
only consider opened packages? Is this the expected behavior? The global search feature of vscode can find all function reference just fine, so I'm curious.
Comment From: findleyr
No, find all references should consider all workspace packages. If you do not see this happening, it is either a bug or a misconfiguration (or both). If you had a small reproducer, or could share LSP logs, it would help us understand what is going on in your session.
Comment From: zejunlitg
No, find all references should consider all workspace packages. If you do not see this happening, it is either a bug or a misconfiguration (or both). If you had a small reproducer, or could share LSP logs, it would help us understand what is going on in your session.
I don't really have a minimal reproducer, but I do have a workspace error, could that be related?
Also, where do I find LSP logs, where are they located?
Comment From: findleyr
I don't really have a minimal reproducer, but I do have a workspace error, could that be related?
Yes, that is almost certainly related. What is your workspace error?
Instructions for how to collect logs are here: https://github.com/golang/vscode-go/blob/master/docs/troubleshooting.md#collect-gopls-information
Comment From: zejunlitg
I don't really have a minimal reproducer, but I do have a workspace error, could that be related?
Yes, that is almost certainly related. What is your workspace error?
Instructions for how to collect logs are here: https://github.com/golang/vscode-go/blob/master/docs/troubleshooting.md#collect-gopls-information
err: exit status 1: stderr: build github.com/...: cannot load github.com/...: import lookup disabled by -mod=readonly
: packages.Load errorgo list
Just created another playground using go module and the find all references seem to work as expected, but my actual working repo is still not working
Comment From: zejunlitg
I don't really have a minimal reproducer, but I do have a workspace error, could that be related?
Yes, that is almost certainly related. What is your workspace error?
Instructions for how to collect logs are here: https://github.com/golang/vscode-go/blob/master/docs/troubleshooting.md#collect-gopls-information
[Trace - 23:56:38.654 PM] Received notification 'window/logMessage'.
Params: {"type":3,"message":"2022/09/08 23:56:38 go/packages.Load golang/vscode-go#2: updating metadata for 593 packages\n"}
if a function in package A has been referenced in both package B and C, if I open a file where it referenced this function in package B, then Find all references
can find all references in package B, but still missing all the references in package C.
This is the only way I discovered to make Find all references
actually find references in other packages.
Comment From: findleyr
This error is surprising: cannot load github.com/...
.
Do you have a module path named "github.com" in your workspace?
Comment From: zejunlitg
This error is surprising:
cannot load github.com/...
.Do you have a module path named "github.com" in your workspace?
Yes, we're using module mod, this is some package inside our module, I can confirm 'Find all reference' only works after I open certain packages, I deliberately leave only one file open and when the packages are loaded(except for this workspace error), find all reference only finds itself, but after I open other packages where this function is referenced, those references are found as well.
Comment From: findleyr
Yes, we're using module mod
Sorry, I don't understand. Do you have a go.mod
file containing module github.com
somewhere?
Comment From: zejunlitg
Yes, we're using module mod
Sorry, I don't understand. Do you have a
go.mod
file containingmodule github.com
somewhere?
I do, there is a go.mod file, it's in the root directory of this repo.
Comment From: findleyr
Gopls is having trouble loading your workspace. Does go list ./...
from your repo root succeed for you?
Are you able to share the full logs from a gopls session?
Comment From: zejunlitg
Gopls is having trouble loading your workspace. Does
go list ./...
from your repo root succeed for you?Are you able to share the full logs from a gopls session?
It seems so, go list ./...
does work, I can't share the full logs as this is NDA codebase.
For now I simply don't use Find all references
as its behavior is not as expected, I just use global search.
Comment From: chezgi
this happens for me also. smaple project structure: - testgo.code-workspace - moda/[ go.mod, a.go ] - modb/[ go.mod, main.go]
testgo.code-workspace:
{
"folders": [
{
"path": "moda"
},
{
"path": "modb"
}
],
}
moda/go.mod
module github.com/test/moda
go 1.19
moda/a.go
package moda
import "fmt"
func TestFunc1() {
fmt.Println("test")
}
modb/go.mod
module github.com/test/modb
go 1.19
replace github.com/test/moda => ../moda/
require github.com/test/moda v0.0.0-00010101000000-000000000000
modb/main.go
package main
import "github.com/test/moda"
func main() {
moda.TestFunc1()
}
when doing "Find All References" in moda
it cant find modb
references,
but if i use "Find All References" in modb
if finds all references.
Comment From: roychoo
have the same issue here. is there any workaround?
Comment From: antonis19
Try the following commands from your workspace directory:
go work init
go work use .
This worked for me.
Comment From: theophanemayaud
Same problem. I have a repo with multiple go modules in /modules Opening in goland works fine, it is able to find all references across modules. However, vs code with go extension installed, when opening the same folder only finds references in the same module. Example is I have 2 modules B and C using code of another 3rd, module A. In goland from the definitions in module A, if I find usages, I see the references across all 3 modules. In vs code, - if I search for references from the definitions in module A, I only get results from module A - if I search for references from the uses in module B, I get results from B and A - if I search from C, I get results for C and A
Above suggestions didn't work, if I have a workspace defined with all modules or not doesn't make a difference (for goland it always works and for vs code it never does).
Either if it's a bug or by design, it makes using vs code not really an option for much of my daily go development work, even though it has other good features.
Comment From: renormalize
@theophanemayaud I see the exact behavior with a different editor, Helix.
In my use the case, the following is the structure:
.
├── rootmodule
│ ├── api
│ │ ├── v1alpha1
│ │ │ └── types.go
│ │ ├── go.mod
│ │ └── go.sum
│ ├── cmd
│ │ └── main.go
│ ├── go.mod
│ └── go.sum
└── go.work
I define types in rootmodule/api/v1alpha1/types.go
. I use the specified type in rootmodule/cmd/main.go
.
- When I try to find references in
rootmodule/api/v1alpha1/types.go
, I find the references only inrootmodule/api/v1alpha1/types.go
. - When I try to find references in
rootmodule/cmd/main.go
, I find the references in bothrootmodule/cmd/main.go
androotmodule/api/v1alpha1/types.go
.
The version of gopls
I use is v0.18.1
.
I doubt this is a VS Code specific issue, since I observe this behavior in a different editor as well.
Comment From: findleyr
@renormalize Does your go.work
use both of ./rootmodule and ./rootmodule/api? If so, then you should always get references in both, unless for some reason GOWORK is disabled in your workspace.
Comment From: findleyr
I understand that this is confusing, but let me summarize how it works for any gopls-backed editor:
When you find references from a file, it finds all references within the logical workspace of that file. https://github.com/golang/tools/blob/master/gopls/doc/workspace.md So, normally that would just be the current module. If you have a go.work file, it's all the modules in that go.work file.
The reason we don't find references across all logical builds is that they may actually be references to different symbols: if moda and modb both require modc, they may actually require different versions of modc.Symbol
, and we weren't sure whether people wanted to see references to two technically different versions of modc.Symbol
, which could theoretically have different types. We also weren't sure whether people would want to pay a performance penalty to reindex all workspaces, when they're logically working in only one at a time.
We have a way for users to declare which modules they are logically working on simultaneusly: go.work
files. So we thought that was a clean solution.
With that said, I did open an issue to reconsider this behavior: https://github.com/golang/go/issues/65755.
We could definitely multiplex across all logical builds based on (pkgPath, symbolName), if that's what people want. I'm a little surprised that we've hardly heard about this until now, though I can definitely understand the confusion.
Comment From: h9jiang
Just to provide my understanding on this, (not expert opinion, but I find it easy to understand). Please refer to findleyr for accurate, precise answer.
When using replace directive, it's still considering the package you are replacing as a dependency. The only difference is, you tell "go", where the module is. The point is, you are still considering it as a dependency and normally you don't care about any reference in your dependency.
Say, you are using github.com/google/go-cmp
in your module, and you want to find reference of cmp.Diff
. What you want to know is, all the appearance of cmp.Diff
in your module and the cmp.Diff
function declaration (because you may want to look at it's implementation). You normally don't want to see other appearance of cmp.Diff
in github.com/google/go-cmp
because you are the user of the cmp.Diff
function and you don't really care about how this function is being called inside of the package (test files, internal implementation details).
Take the comment above as example, module B's go mod file have replace directive, so module B is using code from module A residing in ../moda
. So if module B main.go
have a moda.FooFunc
, and you try to find all the references of this func. As stated in the previous paragraph, you got all themoda.FooFunc
in module B and the declaration of FooFunc
in ../moda
.
I think until this point, the statement but if i use "Find All References" in modb if finds all references.
is explained.
Then, when you are looking at module A, the go mod file does not mention anything related to module B. So technically, module A is not aware of module B. So when you try to find reference of FooFunc
, you can only find the references showing up in module A.
I think this explains doing "Find All References" in moda it cant find modb references,
However, a "go work file" is different from replace directive. See Go Work. A go work file allows user to tell gopls and go binary, "I'm working on multiple modules and I may change them at the same time". If you add module A and module B together to go.work file, gopls will realize you are working at two modules at the same time. When you are performing reference lookup, gopls will give you answer from both module A and module B. (My understanding over go work might not be precise, please refer to the link above to see accurate definition)
Verify the behavior below:
.
├── moda (package main)
│ ├── go.mod
│ ├── main.go <- FooFunc call
│ └── moda (package moda)
│ └── foofunc.go <- FooFunc decl
└── modb (package main)
├── go.mod <- replace moda with ../moda
└── main.go <- FooFunc call
4 directories, 5 files
Without a go.work file, when finding references in modb/main.go
, gopls gives me, reference in modb/main.go
itself and the decl in moda/moda/foofunc.go
Without a go.work file, when finding references in moda/main.go
or moda/moda/foofunc.go
, gopls gives me reference in moda/main.go
and decl in moda/moda/foofunc.go
.
After adding modb/go.work
using content below, finding references in modb/main.go
, gopls gives all references in moda and modb.
go 1.24
use .
use ../moda
The same if you add similar modb/go.work
and find references in moda/main.go
.
Note: Close other open files (in vscode, close the tab) while you are performing this experiment because gopls actually look at open files when you are locating references. So close all the file except the file you are executing finding references.
I hope this could help anyone who is interested in this issue.
Comment From: renormalize
Thank you @findleyr for the clear and concise explanation on why gopls behaves the way it does. It clicked when you mentioned that the dependency could be different versions in the modules, and therefore could be referring to different types.
Thanks @h9jiang for the very detailed explanation!
After restarting gopls, I see behavior as described and desired by me.
Understanding the behavior from the comments is far more satisfactory than steps to "fix" the behavior. Cheers!
Comment From: findleyr
Thank you, @renormalize. I think the actionable part of this is #65755, but I will leave this open for the specific question of what to do about references (#65755 is about the concept of multiplexing in general).