rules_go icon indicating copy to clipboard operation
rules_go copied to clipboard

gopackagesdriver fails to handle go to definition in a third-party source file

Open aignas opened this issue 3 years ago • 0 comments

What version of rules_go are you using?

0.29.0

What version of gazelle are you using?

0.24.0

What version of Bazel are you using?

4.2.1

Does this issue reproduce with the latest releases of all the above?

Yes.

What operating system and processor architecture are you using?

amd64

What did you do?

  • Write some code which calls an external library function or type.
  • Go to definition of that external function or type.
  • Go to definition of something that is used within that external function or type, which would lead us to going to some other type or function within the same package.

What did you expect to see?

I can successfully jump to a different function.

What did you see instead?

The gopackagesdriver fails with (the filepath is taken from my editor when I go to definition once):

$ echo {} | ./tools/go/gopackagesdriver.sh file=/private/var/tmp/_bazel_ignas.anikevicius/1df979b2c502142e517abdf16d459cdc/external/com_github_stretchr_testify/assert/assertions.go | jq
Loading:
Loading: 0 packages loaded
Analyzing: target @io_bazel_rules_go//go/tools/gopackagesdriver:gopackagesdriver (0 packages loaded, 0 targets configured)
INFO: Analyzed target @io_bazel_rules_go//go/tools/gopackagesdriver:gopackagesdriver (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
[0 / 1] [Prepa] BazelWorkspaceStatusAction stable-status.txt
Target @io_bazel_rules_go//go/tools/gopackagesdriver:gopackagesdriver up-to-date:
  bazel-bin/external/io_bazel_rules_go/go/tools/gopackagesdriver/gopackagesdriver_/gopackagesdriver
INFO: Elapsed time: 0.270s, Critical Path: 0.08s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/external/io_bazel_rules_go/go/tools/gopackagesdriver/gopackagesdriver_/gopackagesdriver 'file=/private/var/tmp/_bazel_ignas.anikevicius/1df979b2c502142e517abdf16d459cdc/external/com_github_stretchr_testify/assert/assertions.go'
INFO: Build completed successfully, 1 total action
Running: [bazel info --tool_tag=gopackagesdriver --ui_actions_shown=0]
Running: [bazel query --tool_tag=gopackagesdriver --ui_actions_shown=0 --ui_event_filters=-info,-stderr --noshow_progress --order_output=no --output=label --nodep_deps --noimplicit_deps --notool_deps kind("go_library|go_test", same_pkg_direct_rdeps("../../../../../../../private/var/tmp/_bazel_ignas.anikevicius/1df979b2c502142e517abdf16d459cdc/external/com_github_stretchr_testify/assert/assertions.go"))]
ERROR: Bad target pattern '../../../../../../../private/var/tmp/_bazel_ignas.anikevicius/1df979b2c502142e517abdf16d459cdc/external/com_github_stretchr_testify/assert/assertions.go': package name component contains only '.' characters
error: unable to build JSON files: query failed: unable to query: bazel query failed: exit status 7{
  "NotHandled": false,
  "Sizes": {
    "WordSize": 8,
    "MaxAlign": 8
  },
  "Packages": []
}

Potential fix

Looking at the code, I think that this part of the code may be extended to handle third-party dependencies, but I am not sure if there is a more elegant approach:

diff --git a/go/tools/gopackagesdriver/bazel_json_builder.go b/go/tools/gopackagesdriver/bazel_json_builder.go
index 14f00188..ac5cc878 100644
--- a/go/tools/gopackagesdriver/bazel_json_builder.go
+++ b/go/tools/gopackagesdriver/bazel_json_builder.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 	"path/filepath"
 	"strings"
+	"regexp"
 )
 
 type BazelJSONBuilder struct {
@@ -26,16 +27,25 @@ type BazelJSONBuilder struct {
 	requests []string
 }
 
+var externalRe = regexp.MustCompile(".*/external/([^/]+)/(.*)/([^/]+.go)")
+
 const (
 	RulesGoStdlibLabel = "@io_bazel_rules_go//:stdlib"
 )
 
 func (b *BazelJSONBuilder) fileQuery(filename string) string {
+	var label string
 	if filepath.IsAbs(filename) {
-		fp, _ := filepath.Rel(b.bazel.WorkspaceRoot(), filename)
-		filename = fp
+		label, _ = filepath.Rel(b.bazel.WorkspaceRoot(), filename)
 	}
-	return fmt.Sprintf(`kind("go_library|go_test", same_pkg_direct_rdeps("%s"))`, filename)
+
+	if matches := externalRe.FindStringSubmatch(filename); len(matches) == 4 {
+		// if filepath is for a third party lib, we need to know, what external
+		// library this file is part of.
+		label = fmt.Sprintf("@%s//%s:%s", matches[1], matches[2], matches[3])
+	}
+
+	return fmt.Sprintf(`kind("go_library|go_test", same_pkg_direct_rdeps("%s"))`, label)
 }
 
 func (b *BazelJSONBuilder) packageQuery(importPath string) string {

aignas avatar Jan 21 '22 14:01 aignas