cmd/gomobile: handle modules replaced by other versioned modules

Previously, gomobile bind's go.mod generation logic assumed
replacing module was always located in the disk, but is not
always true. It's valid to replace a module(version) with
another module&version.

For example,

replace golang.org/x/tools => ../

causes:

{
        "Path": "golang.org/x/tools",
        "Version": "v0.0.0-20191017151554-a3bc800455d5",
        "Replace": {
                "Path": "../",
                "Dir": "/usr/local/google/home/hakim/go/src/golang.org/x/tools",
                "GoMod": "/usr/local/google/home/hakim/go/src/golang.org/x/tools/go.mod",
                "GoVersion": "1.11"
        },
        "Dir": "/usr/local/google/home/hakim/go/src/golang.org/x/tools",
        "GoMod": "/usr/local/google/home/hakim/go/src/golang.org/x/tools/go.mod",
        "GoVersion": "1.11"
}

replace github.com/anacrolix/torrent v1.13.0 => gitlab.com/axet/torrent v0.0.0-20200205141541-92b4b9e7387e

causes:

{
        "Path": "github.com/anacrolix/torrent",
        "Version": "v1.13.0",
        "Replace": {
                "Path": "gitlab.com/axet/torrent",
                "Version": "v0.0.0-20200205141541-92b4b9e7387e",
                "Time": "2020-02-05T14:15:41Z",
                "Dir": "/usr/local/google/home/hakim/go/pkg/mod/gitlab.com/axet/torrent@v0.0.0-20200205141541-92b4b9e7387e",
                "GoMod": "/usr/local/google/home/hakim/go/pkg/mod/cache/download/gitlab.com/axet/torrent/@v/v0.0.0-20200205141541-92b4b9e7387e.mod"
        },
        "Dir": "/usr/local/google/home/hakim/go/pkg/mod/gitlab.com/axet/torrent@v0.0.0-20200205141541-92b4b9e7387e",
        "GoMod": "/usr/local/google/home/hakim/go/pkg/mod/cache/download/gitlab.com/axet/torrent/@v/v0.0.0-20200205141541-92b4b9e7387e.mod"
}

Also, while we are here, trim down the entries added to the generated
go.mod. We need the main module, and the replaced module info.
We may want to pin golang.org/x/mobile version if possible, but I don't
know a reliable way to achieve that yet.

Fixes golang/go#37048

Change-Id: Ibd7332338c0a3c4165a642c3e86852061f6ab13b
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/218057
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Hajime Hoshi <hajimehoshi@gmail.com>
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index d29d062..af1ec26 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -235,6 +235,7 @@
 	if targetOS == "darwin" {
 		tags = append(tags, "ios")
 	}
+	// TODO(hyangah): probably we don't need to add all the dependencies.
 	cmd.Args = append(cmd.Args, "-m", "-json", "-tags="+strings.Join(tags, ","), "all")
 	cmd.Dir = src
 
@@ -245,6 +246,7 @@
 	}
 
 	type Module struct {
+		Main    bool
 		Path    string
 		Version string
 		Dir     string
@@ -263,12 +265,21 @@
 		if mod != nil {
 			switch {
 			case mod.Replace != nil:
-				f.AddReplace(mod.Path, mod.Version, mod.Replace.Dir, mod.Replace.Version)
-			case mod.Version == "":
+				p, v := mod.Replace.Path, mod.Replace.Version
+				if modfile.IsDirectoryPath(p) {
+					// replaced by a local directory
+					p = mod.Replace.Dir
+				}
+				f.AddReplace(mod.Path, mod.Version, p, v)
+			case mod.Main, mod.Path == "golang.org/x/mobile":
+				// We are binding this module or it has
+				// explicit dependency on golang.org/x/mobile.
 				// When the version part is empty, the module is local and mod.Dir represents the location.
-				f.AddReplace(mod.Path, "", mod.Dir, "")
-			default:
-				f.AddRequire(mod.Path, mod.Version)
+				if v := mod.Version; v == "" {
+					f.AddReplace(mod.Path, mod.Version, mod.Dir, "")
+				} else {
+					f.AddRequire(mod.Path, v)
+				}
 			}
 		}
 		if err == io.EOF {