You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is related to #20818 (but is much more specific/limited). It's also similar to this issue I previously filed: #19190.
This is a longstanding issue we've faced at my company. The problem occurs when running goimports or when gopls automatically adds imports.
Goimports and gopls have a notion of a "local" name prefix. The idea is that you can say that there are some imports which should be grouped separately from normal third-party imports. We set local to be the name of our module. Therefore, we have three groups of imports:
other packages in the module
The groups should be listed in this order, and the documentation for the "local" feature says as much. For instance, to quote goimports -h:
put imports beginning with this string after 3rd-party packages; comma-separated list
What did you do?
To demo the issue, consider this minimal tree (or see a GitHub repo):
require golang.org/x/tools v0.1.10
I dug into the code and I understand why this is happening.
There is code in golang.org/x/tools/internal/imports (importGroup) which has a notion of import groups. It assigns a "group number" to each import and that looks correct to me:
"fmt" -> group 0
"golang.org/x/tools/container/intsets" -> group 1 (first import path component has a dot)
"mycorp/d" -> group 3 (matches local prefix)
In most cases, if goimports/gopls is responsible for adding all the imports, it will create the groups in that order. However, this issue is an example of a case where it does not do so.
The problem is that astutil.AddNamedImport does not have a notion of local import groups. It only uses "does the first import path component have a dot?" as the heuristic for whether an import is in the stdlib. Goimports/gopls first use astutil.AddNamedImport to add the imports, then sort the import groups, and then break apart groups by group number (if necessary).
So in the case where we first delete "golang.org/x/tools/container/intsets", we have