cmd/protoc-gen-go: refactor package

Refactor the internal logic of protoc-gen-go to better plumb local
settings and parameters down the call tree.

Change-Id: I09fec188d7359f2b66be584aa8f10e682a7b6796
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/214357
Reviewed-by: Patrik Nyblom <pnyb@google.com>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
index 72e97fc..161a8c8 100644
--- a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
+++ b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation.pb.go
@@ -11,7 +11,6 @@
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
-	sync "sync"
 )
 
 var File_grpc_deprecation_proto protoreflect.FileDescriptor
@@ -35,18 +34,6 @@
 	0x6f, 0x33,
 }
 
-var (
-	file_grpc_deprecation_proto_rawDescOnce sync.Once
-	file_grpc_deprecation_proto_rawDescData = file_grpc_deprecation_proto_rawDesc
-)
-
-func file_grpc_deprecation_proto_rawDescGZIP() []byte {
-	file_grpc_deprecation_proto_rawDescOnce.Do(func() {
-		file_grpc_deprecation_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_deprecation_proto_rawDescData)
-	})
-	return file_grpc_deprecation_proto_rawDescData
-}
-
 var file_grpc_deprecation_proto_goTypes = []interface{}{
 	(*Request)(nil),  // 0: goproto.protoc.grpc.Request
 	(*Response)(nil), // 1: goproto.protoc.grpc.Response
diff --git a/cmd/protoc-gen-go/internal_gengo/flags.go b/cmd/protoc-gen-go/internal_gengo/flags.go
deleted file mode 100644
index e89f4d4..0000000
--- a/cmd/protoc-gen-go/internal_gengo/flags.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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 internal_gengo
-
-import (
-	"google.golang.org/protobuf/compiler/protogen"
-	"google.golang.org/protobuf/internal/encoding/wire"
-
-	"google.golang.org/protobuf/types/descriptorpb"
-)
-
-// messageFlags provides flags that control the generated API.
-type messageFlags struct {
-	IsTracked bool
-	HasWeak   bool
-}
-
-func loadMessageFlags(message *protogen.Message) messageFlags {
-	var flags messageFlags
-	flags.IsTracked = isTrackedMessage(message)
-	for _, field := range message.Fields {
-		if field.Desc.IsWeak() {
-			flags.HasWeak = true
-			break
-		}
-	}
-	return flags
-}
-
-// isTrackedMessage reports whether field tracking is enabled on the message.
-// It is a variable so that the behavior is easily overridden in another file.
-var isTrackedMessage = func(message *protogen.Message) (tracked bool) {
-	const trackFieldUse_fieldNumber = 37383685
-
-	// Decode the option from unknown fields to avoid a dependency on the
-	// annotation proto from protoc-gen-go.
-	b := message.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown()
-	for len(b) > 0 {
-		num, typ, n := wire.ConsumeTag(b)
-		b = b[n:]
-		if num == trackFieldUse_fieldNumber && typ == wire.VarintType {
-			v, _ := wire.ConsumeVarint(b)
-			tracked = wire.DecodeBool(v)
-		}
-		m := wire.ConsumeFieldValue(num, typ, b)
-		b = b[m:]
-	}
-	return tracked
-}
diff --git a/cmd/protoc-gen-go/internal_gengo/init.go b/cmd/protoc-gen-go/internal_gengo/init.go
new file mode 100644
index 0000000..ffa7f00
--- /dev/null
+++ b/cmd/protoc-gen-go/internal_gengo/init.go
@@ -0,0 +1,168 @@
+// 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 internal_gengo
+
+import (
+	"unicode"
+	"unicode/utf8"
+
+	"google.golang.org/protobuf/compiler/protogen"
+	"google.golang.org/protobuf/internal/encoding/wire"
+
+	"google.golang.org/protobuf/types/descriptorpb"
+)
+
+type fileInfo struct {
+	*protogen.File
+
+	allEnums      []*enumInfo
+	allMessages   []*messageInfo
+	allExtensions []*extensionInfo
+
+	allEnumsByPtr         map[*enumInfo]int    // value is index into allEnums
+	allMessagesByPtr      map[*messageInfo]int // value is index into allMessages
+	allMessageFieldsByPtr map[*messageInfo]*structFields
+
+	// needRawDesc specifies whether the generator should emit logic to provide
+	// the legacy raw descriptor in GZIP'd form.
+	// This is updated by enum and message generation logic as necessary,
+	// and checked at the end of file generation.
+	needRawDesc bool
+}
+
+type structFields struct {
+	count      int
+	unexported map[int]string
+}
+
+func (sf *structFields) append(name string) {
+	if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) {
+		if sf.unexported == nil {
+			sf.unexported = make(map[int]string)
+		}
+		sf.unexported[sf.count] = name
+	}
+	sf.count++
+}
+
+func newFileInfo(file *protogen.File) *fileInfo {
+	f := &fileInfo{File: file}
+
+	// Collect all enums, messages, and extensions in "flattened ordering".
+	// See filetype.TypeBuilder.
+	var walkMessages func([]*protogen.Message, func(*protogen.Message))
+	walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) {
+		for _, m := range messages {
+			f(m)
+			walkMessages(m.Messages, f)
+		}
+	}
+	initEnumInfos := func(enums []*protogen.Enum) {
+		for _, enum := range enums {
+			f.allEnums = append(f.allEnums, newEnumInfo(f, enum))
+		}
+	}
+	initMessageInfos := func(messages []*protogen.Message) {
+		for _, message := range messages {
+			f.allMessages = append(f.allMessages, newMessageInfo(f, message))
+		}
+	}
+	initExtensionInfos := func(extensions []*protogen.Extension) {
+		for _, extension := range extensions {
+			f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension))
+		}
+	}
+	initEnumInfos(f.Enums)
+	initMessageInfos(f.Messages)
+	initExtensionInfos(f.Extensions)
+	walkMessages(f.Messages, func(m *protogen.Message) {
+		initEnumInfos(m.Enums)
+		initMessageInfos(m.Messages)
+		initExtensionInfos(m.Extensions)
+	})
+
+	// Derive a reverse mapping of enum and message pointers to their index
+	// in allEnums and allMessages.
+	if len(f.allEnums) > 0 {
+		f.allEnumsByPtr = make(map[*enumInfo]int)
+		for i, e := range f.allEnums {
+			f.allEnumsByPtr[e] = i
+		}
+	}
+	if len(f.allMessages) > 0 {
+		f.allMessagesByPtr = make(map[*messageInfo]int)
+		f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields)
+		for i, m := range f.allMessages {
+			f.allMessagesByPtr[m] = i
+			f.allMessageFieldsByPtr[m] = new(structFields)
+		}
+	}
+
+	return f
+}
+
+type enumInfo struct {
+	*protogen.Enum
+
+	genJSONMethod    bool
+	genRawDescMethod bool
+}
+
+func newEnumInfo(f *fileInfo, enum *protogen.Enum) *enumInfo {
+	e := &enumInfo{Enum: enum}
+	e.genJSONMethod = true
+	e.genRawDescMethod = true
+	return e
+}
+
+type messageInfo struct {
+	*protogen.Message
+
+	genRawDescMethod  bool
+	genExtRangeMethod bool
+
+	isTracked bool
+	hasWeak   bool
+}
+
+func newMessageInfo(f *fileInfo, message *protogen.Message) *messageInfo {
+	m := &messageInfo{Message: message}
+	m.genRawDescMethod = true
+	m.genExtRangeMethod = true
+	m.isTracked = isTrackedMessage(m)
+	for _, field := range m.Fields {
+		m.hasWeak = m.hasWeak || field.Desc.IsWeak()
+	}
+	return m
+}
+
+// isTrackedMessage reports whether field tracking is enabled on the message.
+func isTrackedMessage(m *messageInfo) (tracked bool) {
+	const trackFieldUse_fieldNumber = 37383685
+
+	// Decode the option from unknown fields to avoid a dependency on the
+	// annotation proto from protoc-gen-go.
+	b := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown()
+	for len(b) > 0 {
+		num, typ, n := wire.ConsumeTag(b)
+		b = b[n:]
+		if num == trackFieldUse_fieldNumber && typ == wire.VarintType {
+			v, _ := wire.ConsumeVarint(b)
+			tracked = wire.DecodeBool(v)
+		}
+		m := wire.ConsumeFieldValue(num, typ, b)
+		b = b[m:]
+	}
+	return tracked
+}
+
+type extensionInfo struct {
+	*protogen.Extension
+}
+
+func newExtensionInfo(f *fileInfo, extension *protogen.Extension) *extensionInfo {
+	x := &extensionInfo{Extension: extension}
+	return x
+}
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index f738822..b89d3b3 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -53,68 +53,11 @@
 	Ident(string) protogen.GoIdent
 }
 
-type fileInfo struct {
-	*protogen.File
-
-	allEnums      []*protogen.Enum
-	allMessages   []*protogen.Message
-	allExtensions []*protogen.Extension
-
-	allEnumsByPtr         map[*protogen.Enum]int    // value is index into allEnums
-	allMessagesByPtr      map[*protogen.Message]int // value is index into allMessages
-	allMessageFieldsByPtr map[*protogen.Message]*structFields
-}
-
-type structFields struct {
-	count      int
-	unexported map[int]string
-}
-
-func (sf *structFields) append(name string) {
-	if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) {
-		if sf.unexported == nil {
-			sf.unexported = make(map[int]string)
-		}
-		sf.unexported[sf.count] = name
-	}
-	sf.count++
-}
-
 // GenerateFile generates the contents of a .pb.go file.
 func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile {
 	filename := file.GeneratedFilenamePrefix + ".pb.go"
 	g := gen.NewGeneratedFile(filename, file.GoImportPath)
-	f := &fileInfo{
-		File: file,
-	}
-
-	// Collect all enums, messages, and extensions in "flattened ordering".
-	// See filetype.TypeBuilder.
-	f.allEnums = append(f.allEnums, f.Enums...)
-	f.allMessages = append(f.allMessages, f.Messages...)
-	f.allExtensions = append(f.allExtensions, f.Extensions...)
-	walkMessages(f.Messages, func(m *protogen.Message) {
-		f.allEnums = append(f.allEnums, m.Enums...)
-		f.allMessages = append(f.allMessages, m.Messages...)
-		f.allExtensions = append(f.allExtensions, m.Extensions...)
-	})
-
-	// Derive a reverse mapping of enum and message pointers to their index
-	// in allEnums and allMessages.
-	if len(f.allEnums) > 0 {
-		f.allEnumsByPtr = make(map[*protogen.Enum]int)
-		for i, e := range f.allEnums {
-			f.allEnumsByPtr[e] = i
-		}
-	}
-	if len(f.allMessages) > 0 {
-		f.allMessagesByPtr = make(map[*protogen.Message]int)
-		f.allMessageFieldsByPtr = make(map[*protogen.Message]*structFields)
-		for i, m := range f.allMessages {
-			f.allMessagesByPtr[m] = i
-			f.allMessageFieldsByPtr[m] = new(structFields)
-		}
-	}
+	f := newFileInfo(file)
 
 	genStandaloneComments(g, f, fieldnum.FileDescriptorProto_Syntax)
 	genGeneratedHeader(gen, g, f)
@@ -137,26 +80,18 @@
 		genImport(gen, g, f, imps.Get(i))
 	}
 	for _, enum := range f.allEnums {
-		genEnum(gen, g, f, enum)
+		genEnum(g, f, enum)
 	}
 	for _, message := range f.allMessages {
-		genMessage(gen, g, f, message)
+		genMessage(g, f, message)
 	}
-	genExtensions(gen, g, f)
+	genExtensions(g, f)
 
 	genReflectFileDescriptor(gen, g, f)
 
 	return g
 }
 
-// walkMessages calls f on each message and all of its descendants.
-func walkMessages(messages []*protogen.Message, f func(*protogen.Message)) {
-	for _, m := range messages {
-		f(m)
-		walkMessages(m.Messages, f)
-	}
-}
-
 // genStandaloneComments prints all leading comments for a FileDescriptorProto
 // location identified by the field number n.
 func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) {
@@ -276,41 +211,41 @@
 	g.P()
 }
 
-func genEnum(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, enum *protogen.Enum) {
+func genEnum(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) {
 	// Enum type declaration.
-	g.Annotate(enum.GoIdent.GoName, enum.Location)
-	leadingComments := appendDeprecationSuffix(enum.Comments.Leading,
-		enum.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated())
+	g.Annotate(e.GoIdent.GoName, e.Location)
+	leadingComments := appendDeprecationSuffix(e.Comments.Leading,
+		e.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated())
 	g.P(leadingComments,
-		"type ", enum.GoIdent, " int32")
+		"type ", e.GoIdent, " int32")
 
 	// Enum value constants.
 	g.P("const (")
-	for _, value := range enum.Values {
+	for _, value := range e.Values {
 		g.Annotate(value.GoIdent.GoName, value.Location)
 		leadingComments := appendDeprecationSuffix(value.Comments.Leading,
 			value.Desc.Options().(*descriptorpb.EnumValueOptions).GetDeprecated())
 		g.P(leadingComments,
-			value.GoIdent, " ", enum.GoIdent, " = ", value.Desc.Number(),
+			value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(),
 			trailingComment(value.Comments.Trailing))
 	}
 	g.P(")")
 	g.P()
 
 	// Enum value maps.
-	g.P("// Enum value maps for ", enum.GoIdent, ".")
+	g.P("// Enum value maps for ", e.GoIdent, ".")
 	g.P("var (")
-	g.P(enum.GoIdent.GoName+"_name", " = map[int32]string{")
-	for _, value := range enum.Values {
+	g.P(e.GoIdent.GoName+"_name", " = map[int32]string{")
+	for _, value := range e.Values {
 		duplicate := ""
-		if value.Desc != enum.Desc.Values().ByNumber(value.Desc.Number()) {
+		if value.Desc != e.Desc.Values().ByNumber(value.Desc.Number()) {
 			duplicate = "// Duplicate value: "
 		}
 		g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",")
 	}
 	g.P("}")
-	g.P(enum.GoIdent.GoName+"_value", " = map[string]int32{")
-	for _, value := range enum.Values {
+	g.P(e.GoIdent.GoName+"_value", " = map[string]int32{")
+	for _, value := range e.Values {
 		g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",")
 	}
 	g.P("}")
@@ -322,59 +257,55 @@
 	// NOTE: A pointer value is needed to represent presence in proto2.
 	// Since a proto2 message can reference a proto3 enum, it is useful to
 	// always generate this method (even on proto3 enums) to support that case.
-	g.P("func (x ", enum.GoIdent, ") Enum() *", enum.GoIdent, " {")
-	g.P("p := new(", enum.GoIdent, ")")
+	g.P("func (x ", e.GoIdent, ") Enum() *", e.GoIdent, " {")
+	g.P("p := new(", e.GoIdent, ")")
 	g.P("*p = x")
 	g.P("return p")
 	g.P("}")
 	g.P()
 
 	// String method.
-	g.P("func (x ", enum.GoIdent, ") String() string {")
+	g.P("func (x ", e.GoIdent, ") String() string {")
 	g.P("return ", protoimplPackage.Ident("X"), ".EnumStringOf(x.Descriptor(), ", protoreflectPackage.Ident("EnumNumber"), "(x))")
 	g.P("}")
 	g.P()
 
-	genEnumReflectMethods(gen, g, f, enum)
+	genEnumReflectMethods(g, f, e)
 
 	// UnmarshalJSON method.
-	if enum.Desc.Syntax() == protoreflect.Proto2 {
+	if e.genJSONMethod && e.Desc.Syntax() == protoreflect.Proto2 {
 		g.P("// Deprecated: Do not use.")
-		g.P("func (x *", enum.GoIdent, ") UnmarshalJSON(b []byte) error {")
+		g.P("func (x *", e.GoIdent, ") UnmarshalJSON(b []byte) error {")
 		g.P("num, err := ", protoimplPackage.Ident("X"), ".UnmarshalJSONEnum(x.Descriptor(), b)")
 		g.P("if err != nil {")
 		g.P("return err")
 		g.P("}")
-		g.P("*x = ", enum.GoIdent, "(num)")
+		g.P("*x = ", e.GoIdent, "(num)")
 		g.P("return nil")
 		g.P("}")
 		g.P()
 	}
 
 	// EnumDescriptor method.
-	var indexes []string
-	for i := 1; i < len(enum.Location.Path); i += 2 {
-		indexes = append(indexes, strconv.Itoa(int(enum.Location.Path[i])))
+	if e.genRawDescMethod {
+		var indexes []string
+		for i := 1; i < len(e.Location.Path); i += 2 {
+			indexes = append(indexes, strconv.Itoa(int(e.Location.Path[i])))
+		}
+		g.P("// Deprecated: Use ", e.GoIdent, ".Descriptor instead.")
+		g.P("func (", e.GoIdent, ") EnumDescriptor() ([]byte, []int) {")
+		g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}")
+		g.P("}")
+		g.P()
+		f.needRawDesc = true
 	}
-	g.P("// Deprecated: Use ", enum.GoIdent, ".Descriptor instead.")
-	g.P("func (", enum.GoIdent, ") EnumDescriptor() ([]byte, []int) {")
-	g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}")
-	g.P("}")
-	g.P()
 }
 
-type messageInfo struct {
-	*protogen.Message
-	messageFlags
-}
-
-func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, message *protogen.Message) {
-	if message.Desc.IsMapEntry() {
+func genMessage(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+	if m.Desc.IsMapEntry() {
 		return
 	}
 
-	m := &messageInfo{message, loadMessageFlags(message)}
-
 	// Message type declaration.
 	g.Annotate(m.GoIdent.GoName, m.Location)
 	leadingComments := appendDeprecationSuffix(m.Comments.Leading,
@@ -386,12 +317,12 @@
 	g.P()
 
 	genMessageDefaultDecls(g, f, m)
-	genMessageMethods(gen, g, f, m)
-	genMessageOneofWrapperTypes(gen, g, f, m)
+	genMessageMethods(g, f, m)
+	genMessageOneofWrapperTypes(g, f, m)
 }
 
 func genMessageFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
-	sf := f.allMessageFieldsByPtr[m.Message]
+	sf := f.allMessageFieldsByPtr[m]
 	genMessageInternalFields(g, f, m, sf)
 	for _, field := range m.Fields {
 		genMessageField(g, f, m, field, sf)
@@ -403,7 +334,7 @@
 	sf.append(genname.State)
 	g.P(genname.SizeCache, " ", protoimplPackage.Ident("SizeCache"))
 	sf.append(genname.SizeCache)
-	if m.HasWeak {
+	if m.hasWeak {
 		g.P(genname.WeakFields, " ", protoimplPackage.Ident("WeakFields"))
 		sf.append(genname.WeakFields)
 	}
@@ -431,7 +362,7 @@
 		tags := structTags{
 			{"protobuf_oneof", string(oneof.Desc.Name())},
 		}
-		if m.IsTracked {
+		if m.isTracked {
 			tags = append(tags, gotrackTags...)
 		}
 
@@ -466,7 +397,7 @@
 			{"protobuf_val", fieldProtobufTagValue(val)},
 		}...)
 	}
-	if m.IsTracked {
+	if m.isTracked {
 		tags = append(tags, gotrackTags...)
 	}
 
@@ -541,18 +472,18 @@
 	g.P()
 }
 
-func genMessageMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
-	genMessageBaseMethods(gen, g, f, m)
-	genMessageGetterMethods(gen, g, f, m)
-	genMessageSetterMethods(gen, g, f, m)
+func genMessageMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+	genMessageBaseMethods(g, f, m)
+	genMessageGetterMethods(g, f, m)
+	genMessageSetterMethods(g, f, m)
 }
 
-func genMessageBaseMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+func genMessageBaseMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
 	// Reset method.
 	g.P("func (x *", m.GoIdent, ") Reset() {")
 	g.P("*x = ", m.GoIdent, "{}")
 	g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " {")
-	g.P("mi := &", messageTypesVarName(f), "[", f.allMessagesByPtr[m.Message], "]")
+	g.P("mi := &", messageTypesVarName(f), "[", f.allMessagesByPtr[m], "]")
 	g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))")
 	g.P("ms.StoreMessageInfo(mi)")
 	g.P("}")
@@ -570,26 +501,30 @@
 	g.P()
 
 	// ProtoReflect method.
-	genMessageReflectMethods(gen, g, f, m)
+	genMessageReflectMethods(g, f, m)
 
 	// Descriptor method.
-	var indexes []string
-	for i := 1; i < len(m.Location.Path); i += 2 {
-		indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i])))
+	if m.genRawDescMethod {
+		var indexes []string
+		for i := 1; i < len(m.Location.Path); i += 2 {
+			indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i])))
+		}
+		g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.")
+		g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {")
+		g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}")
+		g.P("}")
+		g.P()
+		f.needRawDesc = true
 	}
-	g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.")
-	g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {")
-	g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}")
-	g.P("}")
-	g.P()
 
 	// ExtensionRangeArray method.
-	if extranges := m.Desc.ExtensionRanges(); extranges.Len() > 0 {
+	extRanges := m.Desc.ExtensionRanges()
+	if m.genExtRangeMethod && extRanges.Len() > 0 {
 		protoExtRange := protoifacePackage.Ident("ExtensionRangeV1")
 		extRangeVar := "extRange_" + m.GoIdent.GoName
 		g.P("var ", extRangeVar, " = []", protoExtRange, " {")
-		for i := 0; i < extranges.Len(); i++ {
-			r := extranges.Get(i)
+		for i := 0; i < extRanges.Len(); i++ {
+			r := extRanges.Get(i)
 			g.P("{Start:", r[0], ", End:", r[1]-1 /* inclusive */, "},")
 		}
 		g.P("}")
@@ -602,9 +537,9 @@
 	}
 }
 
-func genMessageGetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+func genMessageGetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
 	for _, field := range m.Fields {
-		genNoInterfacePragma(g, m.IsTracked)
+		genNoInterfacePragma(g, m.isTracked)
 
 		// Getter for parent oneof.
 		if oneof := field.Oneof; oneof != nil && oneof.Fields[0] == field {
@@ -663,13 +598,13 @@
 	}
 }
 
-func genMessageSetterMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+func genMessageSetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
 	for _, field := range m.Fields {
 		if !field.Desc.IsWeak() {
 			continue
 		}
 
-		genNoInterfacePragma(g, m.IsTracked)
+		genNoInterfacePragma(g, m.isTracked)
 
 		g.Annotate(m.GoIdent.GoName+".Set"+field.GoName, field.Location)
 		leadingComments := appendDeprecationSuffix("",
@@ -778,29 +713,29 @@
 	return string(field.Desc.Name()) + ",omitempty"
 }
 
-func genExtensions(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) {
+func genExtensions(g *protogen.GeneratedFile, f *fileInfo) {
 	if len(f.allExtensions) == 0 {
 		return
 	}
 
 	g.P("var ", extensionTypesVarName(f), " = []", protoimplPackage.Ident("ExtensionInfo"), "{")
-	for _, extension := range f.allExtensions {
+	for _, x := range f.allExtensions {
 		// For MessageSet extensions, the name used is the parent message.
-		name := extension.Desc.FullName()
-		if messageset.IsMessageSetExtension(extension.Desc) {
+		name := x.Desc.FullName()
+		if messageset.IsMessageSetExtension(x.Desc) {
 			name = name.Parent()
 		}
 
 		g.P("{")
-		g.P("ExtendedType: (*", extension.Extendee.GoIdent, ")(nil),")
-		goType, pointer := fieldGoType(g, f, extension)
+		g.P("ExtendedType: (*", x.Extendee.GoIdent, ")(nil),")
+		goType, pointer := fieldGoType(g, f, x.Extension)
 		if pointer {
 			goType = "*" + goType
 		}
 		g.P("ExtensionType: (", goType, ")(nil),")
-		g.P("Field: ", extension.Desc.Number(), ",")
+		g.P("Field: ", x.Desc.Number(), ",")
 		g.P("Name: ", strconv.Quote(string(name)), ",")
-		g.P("Tag: ", strconv.Quote(fieldProtobufTagValue(extension)), ",")
+		g.P("Tag: ", strconv.Quote(fieldProtobufTagValue(x.Extension)), ",")
 		g.P("Filename: ", strconv.Quote(f.Desc.Path()), ",")
 		g.P("},")
 	}
@@ -809,21 +744,21 @@
 
 	// Group extensions by the target message.
 	var orderedTargets []protogen.GoIdent
-	allExtensionsByTarget := make(map[protogen.GoIdent][]*protogen.Extension)
-	allExtensionsByPtr := make(map[*protogen.Extension]int)
-	for i, extension := range f.allExtensions {
-		target := extension.Extendee.GoIdent
+	allExtensionsByTarget := make(map[protogen.GoIdent][]*extensionInfo)
+	allExtensionsByPtr := make(map[*extensionInfo]int)
+	for i, x := range f.allExtensions {
+		target := x.Extendee.GoIdent
 		if len(allExtensionsByTarget[target]) == 0 {
 			orderedTargets = append(orderedTargets, target)
 		}
-		allExtensionsByTarget[target] = append(allExtensionsByTarget[target], extension)
-		allExtensionsByPtr[extension] = i
+		allExtensionsByTarget[target] = append(allExtensionsByTarget[target], x)
+		allExtensionsByPtr[x] = i
 	}
 	for _, target := range orderedTargets {
 		g.P("// Extension fields to ", target, ".")
 		g.P("var (")
-		for _, extension := range allExtensionsByTarget[target] {
-			xd := extension.Desc
+		for _, x := range allExtensionsByTarget[target] {
+			xd := x.Desc
 			typeName := xd.Kind().String()
 			switch xd.Kind() {
 			case protoreflect.EnumKind:
@@ -833,17 +768,17 @@
 			}
 			fieldName := string(xd.Name())
 
-			leadingComments := extension.Comments.Leading
+			leadingComments := x.Comments.Leading
 			if leadingComments != "" {
 				leadingComments += "\n"
 			}
 			leadingComments += protogen.Comments(fmt.Sprintf(" %v %v %v = %v;\n",
 				xd.Cardinality(), typeName, fieldName, xd.Number()))
 			leadingComments = appendDeprecationSuffix(leadingComments,
-				extension.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
+				x.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
 			g.P(leadingComments,
-				"E_", extension.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[extension], "]",
-				trailingComment(extension.Comments.Trailing))
+				"E_", x.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[x], "]",
+				trailingComment(x.Comments.Trailing))
 		}
 		g.P(")")
 		g.P()
@@ -852,7 +787,7 @@
 
 // genMessageOneofWrapperTypes generates the oneof wrapper types and
 // associates the types with the parent message type.
-func genMessageOneofWrapperTypes(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+func genMessageOneofWrapperTypes(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
 	for _, oneof := range m.Oneofs {
 		ifName := oneofInterfaceName(oneof)
 		g.P("type ", ifName, " interface {")
@@ -867,7 +802,7 @@
 			tags := structTags{
 				{"protobuf", fieldProtobufTagValue(field)},
 			}
-			if m.IsTracked {
+			if m.isTracked {
 				tags = append(tags, gotrackTags...)
 			}
 			leadingComments := appendDeprecationSuffix(field.Comments.Leading,
diff --git a/cmd/protoc-gen-go/internal_gengo/reflect.go b/cmd/protoc-gen-go/internal_gengo/reflect.go
index 7439bf6..b60f4ce 100644
--- a/cmd/protoc-gen-go/internal_gengo/reflect.go
+++ b/cmd/protoc-gen-go/internal_gengo/reflect.go
@@ -79,10 +79,10 @@
 	}
 	var depOffsets []offsetEntry
 	for _, enum := range f.allEnums {
-		genEnum(enum, "")
+		genEnum(enum.Enum, "")
 	}
 	for _, message := range f.allMessages {
-		genMessage(message, "")
+		genMessage(message.Message, "")
 	}
 	depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "field type_name"})
 	for _, message := range f.allMessages {
@@ -259,48 +259,50 @@
 	g.P("}")
 	g.P()
 
-	onceVar := rawDescVarName(f) + "Once"
-	dataVar := rawDescVarName(f) + "Data"
-	g.P("var (")
-	g.P(onceVar, " ", syncPackage.Ident("Once"))
-	g.P(dataVar, " = ", rawDescVarName(f))
-	g.P(")")
-	g.P()
+	if f.needRawDesc {
+		onceVar := rawDescVarName(f) + "Once"
+		dataVar := rawDescVarName(f) + "Data"
+		g.P("var (")
+		g.P(onceVar, " ", syncPackage.Ident("Once"))
+		g.P(dataVar, " = ", rawDescVarName(f))
+		g.P(")")
+		g.P()
 
-	g.P("func ", rawDescVarName(f), "GZIP() []byte {")
-	g.P(onceVar, ".Do(func() {")
-	g.P(dataVar, " = ", protoimplPackage.Ident("X"), ".CompressGZIP(", dataVar, ")")
-	g.P("})")
-	g.P("return ", dataVar)
-	g.P("}")
-	g.P()
+		g.P("func ", rawDescVarName(f), "GZIP() []byte {")
+		g.P(onceVar, ".Do(func() {")
+		g.P(dataVar, " = ", protoimplPackage.Ident("X"), ".CompressGZIP(", dataVar, ")")
+		g.P("})")
+		g.P("return ", dataVar)
+		g.P("}")
+		g.P()
+	}
 }
 
-func genEnumReflectMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, enum *protogen.Enum) {
-	idx := f.allEnumsByPtr[enum]
+func genEnumReflectMethods(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) {
+	idx := f.allEnumsByPtr[e]
 	typesVar := enumTypesVarName(f)
 
 	// Descriptor method.
-	g.P("func (", enum.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {")
+	g.P("func (", e.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {")
 	g.P("return ", typesVar, "[", idx, "].Descriptor()")
 	g.P("}")
 	g.P()
 
 	// Type method.
-	g.P("func (", enum.GoIdent, ") Type() ", protoreflectPackage.Ident("EnumType"), " {")
+	g.P("func (", e.GoIdent, ") Type() ", protoreflectPackage.Ident("EnumType"), " {")
 	g.P("return &", typesVar, "[", idx, "]")
 	g.P("}")
 	g.P()
 
 	// Number method.
-	g.P("func (x ", enum.GoIdent, ") Number() ", protoreflectPackage.Ident("EnumNumber"), " {")
+	g.P("func (x ", e.GoIdent, ") Number() ", protoreflectPackage.Ident("EnumNumber"), " {")
 	g.P("return ", protoreflectPackage.Ident("EnumNumber"), "(x)")
 	g.P("}")
 	g.P()
 }
 
-func genMessageReflectMethods(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
-	idx := f.allMessagesByPtr[m.Message]
+func genMessageReflectMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
+	idx := f.allMessagesByPtr[m]
 	typesVar := messageTypesVarName(f)
 
 	// ProtoReflect method.
diff --git a/internal/testprotos/annotation/annotation.pb.go b/internal/testprotos/annotation/annotation.pb.go
index 74b4cdc..2aee53b 100644
--- a/internal/testprotos/annotation/annotation.pb.go
+++ b/internal/testprotos/annotation/annotation.pb.go
@@ -12,7 +12,6 @@
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	descriptorpb "google.golang.org/protobuf/types/descriptorpb"
 	reflect "reflect"
-	sync "sync"
 )
 
 var file_annotation_annotation_proto_extTypes = []protoimpl.ExtensionInfo{
@@ -56,18 +55,6 @@
 	0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
 }
 
-var (
-	file_annotation_annotation_proto_rawDescOnce sync.Once
-	file_annotation_annotation_proto_rawDescData = file_annotation_annotation_proto_rawDesc
-)
-
-func file_annotation_annotation_proto_rawDescGZIP() []byte {
-	file_annotation_annotation_proto_rawDescOnce.Do(func() {
-		file_annotation_annotation_proto_rawDescData = protoimpl.X.CompressGZIP(file_annotation_annotation_proto_rawDescData)
-	})
-	return file_annotation_annotation_proto_rawDescData
-}
-
 var file_annotation_annotation_proto_goTypes = []interface{}{
 	(*descriptorpb.MessageOptions)(nil), // 0: google.protobuf.MessageOptions
 }
diff --git a/internal/testprotos/test/ext.pb.go b/internal/testprotos/test/ext.pb.go
index fe3f48d..e98a6db 100644
--- a/internal/testprotos/test/ext.pb.go
+++ b/internal/testprotos/test/ext.pb.go
@@ -11,7 +11,6 @@
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
-	sync "sync"
 )
 
 var file_test_ext_proto_extTypes = []protoimpl.ExtensionInfo{
@@ -49,18 +48,6 @@
 	0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
 }
 
-var (
-	file_test_ext_proto_rawDescOnce sync.Once
-	file_test_ext_proto_rawDescData = file_test_ext_proto_rawDesc
-)
-
-func file_test_ext_proto_rawDescGZIP() []byte {
-	file_test_ext_proto_rawDescOnce.Do(func() {
-		file_test_ext_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_ext_proto_rawDescData)
-	})
-	return file_test_ext_proto_rawDescData
-}
-
 var file_test_ext_proto_goTypes = []interface{}{
 	(*TestAllExtensions)(nil), // 0: goproto.proto.test.TestAllExtensions
 }