in protoc-gen-go/generator/generator.go [1106:1202]
func (g *Generator) generate(file *FileDescriptor) {
g.file = file
g.usedPackages = make(map[GoImportPath]bool)
g.packageNames = make(map[GoImportPath]GoPackageName)
g.usedPackageNames = make(map[GoPackageName]bool)
g.addedImports = make(map[GoImportPath]bool)
for name := range globalPackageNames {
g.usedPackageNames[name] = true
}
g.P("// This is a compile-time assertion to ensure that this generated file")
g.P("// is compatible with the proto package it is being compiled against.")
g.P("// A compilation error at this line likely means your copy of the")
g.P("// proto package needs to be updated.")
g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
g.P()
for _, td := range g.file.imp {
g.generateImported(td)
}
for _, enum := range g.file.enum {
g.generateEnum(enum)
}
for _, desc := range g.file.desc {
// Don't generate virtual messages for maps.
if desc.GetOptions().GetMapEntry() {
continue
}
g.generateMessage(desc)
}
for _, ext := range g.file.ext {
g.generateExtension(ext)
}
g.generateInitFunction()
g.generateFileDescriptor(file)
// Run the plugins before the imports so we know which imports are necessary.
g.runPlugins(file)
// Generate header and imports last, though they appear first in the output.
rem := g.Buffer
remAnno := g.annotations
g.Buffer = new(bytes.Buffer)
g.annotations = nil
g.generateHeader()
g.generateImports()
if !g.writeOutput {
return
}
// Adjust the offsets for annotations displaced by the header and imports.
for _, anno := range remAnno {
*anno.Begin += int32(g.Len())
*anno.End += int32(g.Len())
g.annotations = append(g.annotations, anno)
}
g.Write(rem.Bytes())
// Reformat generated code and patch annotation locations.
fset := token.NewFileSet()
original := g.Bytes()
if g.annotateCode {
// make a copy independent of g; we'll need it after Reset.
original = append([]byte(nil), original...)
}
fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments)
if err != nil {
// Print out the bad code with line numbers.
// This should never happen in practice, but it can while changing generated code,
// so consider this a debugging aid.
var src bytes.Buffer
s := bufio.NewScanner(bytes.NewReader(original))
for line := 1; s.Scan(); line++ {
fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes())
}
g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String())
}
ast.SortImports(fset, fileAST)
g.Reset()
err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST)
if err != nil {
g.Fail("generated Go source code could not be reformatted:", err.Error())
}
if g.annotateCode {
m, err := remap.Compute(original, g.Bytes())
if err != nil {
g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error())
}
for _, anno := range g.annotations {
new, ok := m.Find(int(*anno.Begin), int(*anno.End))
if !ok {
g.Fail("span in formatted generated Go source code could not be mapped back to the original code")
}
*anno.Begin = int32(new.Pos)
*anno.End = int32(new.End)
}
}
}