compiler/protogen: make paths=import work with M overrides

In the default .pb.go filename generation mode, we generate the filename
from the import path when a file has a go_package option and the source
.proto filename otherwise.

Change filename generation when an explicit mode of paths=import is
specified to always use the import path, no matter how it was
determiend. The practical effect is that you can override the import
path of a file with Mx.proto=import/path and have this behave
identically to setting a go_package option in the file.

Change-Id: I954b3f9d5fd17d08896629bfc77945dea1732bd6
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/219597
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/compiler/protogen/protogen.go b/compiler/protogen/protogen.go
index ee8d0f7..de9cb8b 100644
--- a/compiler/protogen/protogen.go
+++ b/compiler/protogen/protogen.go
@@ -232,7 +232,7 @@
 		packageName, importPath := goPackageOption(fdesc)
 		switch {
 		case importPaths[filename] != "":
-			// Command line: M=foo.proto=quux/bar
+			// Command line: Mfoo.proto=quux/bar
 			//
 			// Explicit mapping of source file to import path.
 		case generatedFileNames[filename] && packageImportPath != "":
@@ -453,16 +453,19 @@
 	if ext := path.Ext(prefix); ext == ".proto" || ext == ".protodevel" {
 		prefix = prefix[:len(prefix)-len(ext)]
 	}
-	if gen.pathType == pathTypeImport {
-		// If paths=import (the default) and the file contains a go_package option
-		// with a full import path, the output filename is derived from the Go import
-		// path.
-		//
-		// Pass the paths=source_relative flag to always derive the output filename
-		// from the input filename instead.
+	switch gen.pathType {
+	case pathTypeLegacy:
+		// The default is to derive the output filename from the Go import path
+		// if the file contains a go_package option,or from the input filename instead.
 		if _, importPath := goPackageOption(p); importPath != "" {
 			prefix = path.Join(string(importPath), path.Base(prefix))
 		}
+	case pathTypeImport:
+		// If paths=import, the output filename is derived from the Go import path.
+		prefix = path.Join(string(f.GoImportPath), path.Base(prefix))
+	case pathTypeSourceRelative:
+		// If paths=source_relative, the output filename is derived from
+		// the input filename.
 	}
 	f.GoDescriptorIdent = GoIdent{
 		GoName:       "File_" + strs.GoSanitized(p.GetName()),
@@ -1282,7 +1285,8 @@
 type pathType int
 
 const (
-	pathTypeImport pathType = iota
+	pathTypeLegacy pathType = iota
+	pathTypeImport
 	pathTypeSourceRelative
 )
 
diff --git a/compiler/protogen/protogen_test.go b/compiler/protogen/protogen_test.go
index 5cc3d66..1f7b75c 100644
--- a/compiler/protogen/protogen_test.go
+++ b/compiler/protogen/protogen_test.go
@@ -159,6 +159,15 @@
 			wantImportPath:     "golang.org/x/foo",
 			wantFilenamePrefix: "golang.org/x/foo/filename",
 		},
+		{
+			desc:               "paths=import uses import path from command line",
+			parameter:          "paths=import,Mdir/filename.proto=golang.org/x/bar",
+			goPackageOption:    "golang.org/x/foo",
+			generate:           true,
+			wantPackageName:    "foo",
+			wantImportPath:     "golang.org/x/bar",
+			wantFilenamePrefix: "golang.org/x/bar/filename",
+		},
 	} {
 		context := fmt.Sprintf(`
 TEST: %v