func (m *MessageDefinition) descendants() []*MessageDefinition {
	descendants := make([]*MessageDefinition, 0)
	for i, child := range m.Descriptor.NestedType {
		path := append(m.path, []int32{messageMessagePath, int32(i)}...)
		message := &MessageDefinition{
			Parent:     m,
			Descriptor: child,
			File:       m.File,
			Comments:   commentsAtPath(path, m.File),
			path:       path,
		}
		descendants = append(descendants, message)
		descendants = append(descendants, message.descendants()...)
	}
	return descendants
}
descendants returns all the submessages defined within m, and all the
descendants of those, recursively.
package message
import (
	"github.com/golang/protobuf/protoc-gen-go/descriptor"
)
type MessageDefinition struct {
	Parent *MessageDefinition
	Descriptor *descriptor.DescriptorProto
	File *descriptor.FileDescriptorProto
	Comments DefinitionComments
	path []int32
}
func NewMessageFromFile(
	file *descriptor.FileDescriptorProto,
	nameToFiles map[string]*descriptor.FileDescriptorProto) map[string]*MessageDefinition {
	protoToMessages := make(map[string]*MessageDefinition)
	for i, descriptor := range file.MessageType {
		path := []int32{messagePath, int32(i)}
		message := &MessageDefinition{
			Parent:     nil,
			Descriptor: descriptor,
			File:       file,
			Comments:   commentsAtPath(path, file),
			path:       path,
		}
		protoToMessages[message.ProtoName()] = message
		for _, child := range message.descendants() {
			protoToMessages[child.ProtoName()] = child
		}
	}
	for _, depIdx := range file.PublicDependency {
		depFilename := file.Dependency[depIdx]
		depFile := nameToFiles[depFilename]
		depMessage := NewMessageFromFile(depFile, nameToFiles)
		for _, message := range depMessage {
			imported := &MessageDefinition{
				Parent:     message.Parent,
				Descriptor: message.Descriptor,
				File:       file,
				Comments:   commentsAtPath(message.path, depFile),
				path:       message.path,
			}
			protoToMessages[imported.ProtoName()] = imported
		}
	}
	return protoToMessages
}
func (m *MessageDefinition) ProtoName() string {
	prefix := "."
	if pkg := m.File.GetPackage(); pkg != "" {
		prefix += pkg + "."
	}
	if lineage := m.Lineage(); len(lineage) > 0 {
		for _, parent := range lineage {
			prefix += parent.Descriptor.GetName() + "."
		}
	}
	return prefix + m.Descriptor.GetName()
}
func (m *MessageDefinition) Lineage() []*MessageDefinition {
	var parents []*MessageDefinition
	for p := m.Parent; p != nil; p = p.Parent {
		parents = append([]*MessageDefinition{p}, parents...)
	}
	return parents
}