go/packages: add String methods for LoadMode

This String method makes it easier to debug GOPACKAGESDRIVER code and identify
LoadModes in use.

Change-Id: I80bf434fc007470b437fb5cf667254737c3a814f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/200539
Reviewed-by: Michael Matloob <matloob@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/go/packages/loadmode_string.go b/go/packages/loadmode_string.go
new file mode 100644
index 0000000..aff94a3
--- /dev/null
+++ b/go/packages/loadmode_string.go
@@ -0,0 +1,57 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packages
+
+import (
+	"fmt"
+	"strings"
+)
+
+var allModes = []LoadMode{
+	NeedName,
+	NeedFiles,
+	NeedCompiledGoFiles,
+	NeedImports,
+	NeedDeps,
+	NeedExportsFile,
+	NeedTypes,
+	NeedSyntax,
+	NeedTypesInfo,
+	NeedTypesSizes,
+}
+
+var modeStrings = []string{
+	"NeedName",
+	"NeedFiles",
+	"NeedCompiledGoFiles",
+	"NeedImports",
+	"NeedDeps",
+	"NeedExportsFile",
+	"NeedTypes",
+	"NeedSyntax",
+	"NeedTypesInfo",
+	"NeedTypesSizes",
+}
+
+func (mod LoadMode) String() string {
+	m := mod
+	if m == 0 {
+		return fmt.Sprintf("LoadMode(0)")
+	}
+	var out []string
+	for i, x := range allModes {
+		if x > m {
+			break
+		}
+		if (m & x) != 0 {
+			out = append(out, modeStrings[i])
+			m = m ^ x
+		}
+	}
+	if m != 0 {
+		out = append(out, "Unknown")
+	}
+	return fmt.Sprintf("LoadMode(%s)", strings.Join(out, "|"))
+}
diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go
index ff8bcc6..603c959 100644
--- a/go/packages/packages_test.go
+++ b/go/packages/packages_test.go
@@ -2526,6 +2526,83 @@
 	}
 }
 
+func TestLoadModeStrings(t *testing.T) {
+	testcases := []struct {
+		mode     packages.LoadMode
+		expected string
+	}{
+		{
+			packages.LoadMode(0),
+			"LoadMode(0)",
+		},
+		{
+			packages.NeedName,
+			"LoadMode(NeedName)",
+		},
+		{
+			packages.NeedFiles,
+			"LoadMode(NeedFiles)",
+		},
+		{
+			packages.NeedCompiledGoFiles,
+			"LoadMode(NeedCompiledGoFiles)",
+		},
+		{
+			packages.NeedImports,
+			"LoadMode(NeedImports)",
+		},
+		{
+			packages.NeedDeps,
+			"LoadMode(NeedDeps)",
+		},
+		{
+			packages.NeedExportsFile,
+			"LoadMode(NeedExportsFile)",
+		},
+		{
+			packages.NeedTypes,
+			"LoadMode(NeedTypes)",
+		},
+		{
+			packages.NeedSyntax,
+			"LoadMode(NeedSyntax)",
+		},
+		{
+			packages.NeedTypesInfo,
+			"LoadMode(NeedTypesInfo)",
+		},
+		{
+			packages.NeedTypesSizes,
+			"LoadMode(NeedTypesSizes)",
+		},
+		{
+			packages.NeedName | packages.NeedExportsFile,
+			"LoadMode(NeedName|NeedExportsFile)",
+		},
+		{
+			packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes,
+			"LoadMode(NeedName|NeedFiles|NeedCompiledGoFiles|NeedImports|NeedDeps|NeedExportsFile|NeedTypes|NeedSyntax|NeedTypesInfo|NeedTypesSizes)",
+		},
+		{
+			packages.NeedName | 8192,
+			"LoadMode(NeedName|Unknown)",
+		},
+		{
+			4096,
+			"LoadMode(Unknown)",
+		},
+	}
+
+	for tcInd, tc := range testcases {
+		t.Run(fmt.Sprintf("test-%d", tcInd), func(t *testing.T) {
+			actual := tc.mode.String()
+			if tc.expected != actual {
+				t.Errorf("want %#v, got %#v", tc.expected, actual)
+			}
+		})
+	}
+}
+
 func errorMessages(errors []packages.Error) []string {
 	var msgs []string
 	for _, err := range errors {