imports: handle missing main module

If GO111MODULE=on but there's no go.mod, GOMOD will be set to /dev/null
or NUL and there will be no main module. goimports should handle this
case roughly the same way the go command does.

Fixes golang/go#30855

Change-Id: I6fbf4c056000db5abd8788a6014ae5f13b1c8cd4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/167860
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/imports/mod.go b/imports/mod.go
index ec76914..018c43c 100644
--- a/imports/mod.go
+++ b/imports/mod.go
@@ -24,6 +24,7 @@
 type moduleResolver struct {
 	env *fixEnv
 
+	initialized   bool
 	main          *moduleJSON
 	modsByModPath []*moduleJSON // All modules, ordered by # of path components in module Path...
 	modsByDir     []*moduleJSON // ...or Dir.
@@ -48,7 +49,7 @@
 }
 
 func (r *moduleResolver) init() error {
-	if r.main != nil {
+	if r.initialized {
 		return nil
 	}
 	stdout, err := r.env.invokeGo("list", "-m", "-json", "...")
@@ -87,6 +88,7 @@
 		return count(j) < count(i) // descending order
 	})
 
+	r.initialized = true
 	return nil
 }
 
@@ -202,7 +204,9 @@
 	// Walk GOROOT, GOPATH/pkg/mod, and the main module.
 	roots := []gopathwalk.Root{
 		{filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT},
-		{r.main.Dir, gopathwalk.RootCurrentModule},
+	}
+	if r.main != nil {
+		roots = append(roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
 	}
 	for _, p := range filepath.SplitList(r.env.GOPATH) {
 		roots = append(roots, gopathwalk.Root{filepath.Join(p, "/pkg/mod"), gopathwalk.RootModuleCache})
diff --git a/imports/mod_112_test.go b/imports/mod_112_test.go
new file mode 100644
index 0000000..0305f48
--- /dev/null
+++ b/imports/mod_112_test.go
@@ -0,0 +1,21 @@
+// +build go1.12
+
+package imports
+
+import (
+	"testing"
+)
+
+// Tests that we handle GO111MODULE=on with no go.mod file. See #30855.
+func TestNoMainModule(t *testing.T) {
+	mt := setup(t, `
+-- x.go --
+package x
+`, "")
+	defer mt.cleanup()
+	if _, err := mt.env.invokeGo("mod", "download", "rsc.io/quote@v1.5.1"); err != nil {
+		t.Fatal(err)
+	}
+
+	mt.assertScanFinds("rsc.io/quote", "quote")
+}
diff --git a/imports/mod_test.go b/imports/mod_test.go
index bda2c06..a6bf8d6 100644
--- a/imports/mod_test.go
+++ b/imports/mod_test.go
@@ -5,6 +5,7 @@
 import (
 	"archive/zip"
 	"fmt"
+	"go/build"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -515,6 +516,7 @@
 	}
 
 	env := &fixEnv{
+		GOROOT:      build.Default.GOROOT,
 		GOPATH:      filepath.Join(dir, "gopath"),
 		GO111MODULE: "on",
 		GOPROXY:     "file://" + filepath.ToSlash(proxyDir),