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_. - * Run `gopls -v version` to get version of Gopls from _the VS Code integrated terminal_. - * Run `code -v` or `code-insiders -v` to get version of VS Code or VS Code Insiders. - * Check your installed extensions to get the version of the VS Code Go extension - * Run Ctrl+Shift+P (Cmd+Shift+P on Mac OS) > `Go: Locate Configured Go Tools` command. -

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 containing module 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 in rootmodule/api/v1alpha1/types.go.
  • When I try to find references in rootmodule/cmd/main.go, I find the references in both rootmodule/cmd/main.go and rootmodule/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

Image

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.

Image

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).