protogen: conflict resolve local package names against predefined idents

Avoid importing packages with a local name that conflicts with a predefined
identifier (e.g., "string").

Change-Id: I51164635351895e8a060355e59d718240e26ef2e
Reviewed-on: https://go-review.googlesource.com/c/140178
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/protogen/names.go b/protogen/names.go
index 8ec8299..445613f 100644
--- a/protogen/names.go
+++ b/protogen/names.go
@@ -50,6 +50,48 @@
 	return GoPackageName(name)
 }
 
+var isGoPredeclaredIdentifier = map[string]bool{
+	"append":     true,
+	"bool":       true,
+	"byte":       true,
+	"cap":        true,
+	"close":      true,
+	"complex":    true,
+	"complex128": true,
+	"complex64":  true,
+	"copy":       true,
+	"delete":     true,
+	"error":      true,
+	"false":      true,
+	"float32":    true,
+	"float64":    true,
+	"imag":       true,
+	"int":        true,
+	"int16":      true,
+	"int32":      true,
+	"int64":      true,
+	"int8":       true,
+	"iota":       true,
+	"len":        true,
+	"make":       true,
+	"new":        true,
+	"nil":        true,
+	"panic":      true,
+	"print":      true,
+	"println":    true,
+	"real":       true,
+	"recover":    true,
+	"rune":       true,
+	"string":     true,
+	"true":       true,
+	"uint":       true,
+	"uint16":     true,
+	"uint32":     true,
+	"uint64":     true,
+	"uint8":      true,
+	"uintptr":    true,
+}
+
 // badToUnderscore is the mapping function used to generate Go names from package names,
 // which can be dotted in the input .proto file.  It replaces non-identifier characters such as
 // dot or dash with underscore.
diff --git a/protogen/protogen.go b/protogen/protogen.go
index 80e7dc1..fdacc43 100644
--- a/protogen/protogen.go
+++ b/protogen/protogen.go
@@ -833,7 +833,7 @@
 		return string(packageName) + "." + ident.GoName
 	}
 	packageName := cleanPackageName(baseName(string(ident.GoImportPath)))
-	for i, orig := 1, packageName; g.usedPackageNames[packageName]; i++ {
+	for i, orig := 1, packageName; g.usedPackageNames[packageName] || isGoPredeclaredIdentifier[string(packageName)]; i++ {
 		packageName = orig + GoPackageName(strconv.Itoa(i))
 	}
 	g.packageNames[ident.GoImportPath] = packageName
diff --git a/protogen/protogen_test.go b/protogen/protogen_test.go
index 6d8e5af..35f1899 100644
--- a/protogen/protogen_test.go
+++ b/protogen/protogen_test.go
@@ -272,6 +272,8 @@
 		// Reference to a different package with the same basename.
 		"golang.org/y/bar",
 		"golang.org/x/baz",
+		// Reference to a package conflicting with a predeclared identifier.
+		"golang.org/z/string",
 	} {
 		g.P("var _ = ", GoIdent{GoName: "X", GoImportPath: importPath}, " // ", importPath)
 	}
@@ -281,13 +283,15 @@
 	bar "golang.org/x/bar"
 	baz "golang.org/x/baz"
 	bar1 "golang.org/y/bar"
+	string1 "golang.org/z/string"
 )
 
-var _ = X      // "golang.org/x/foo"
-var _ = bar.X  // "golang.org/x/bar"
-var _ = bar.X  // "golang.org/x/bar"
-var _ = bar1.X // "golang.org/y/bar"
-var _ = baz.X  // "golang.org/x/baz"
+var _ = X         // "golang.org/x/foo"
+var _ = bar.X     // "golang.org/x/bar"
+var _ = bar.X     // "golang.org/x/bar"
+var _ = bar1.X    // "golang.org/y/bar"
+var _ = baz.X     // "golang.org/x/baz"
+var _ = string1.X // "golang.org/z/string"
 `
 	got, err := g.Content()
 	if err != nil {