Sync from internal version.
        This is the support for the "public import" feature.

R=r
CC=golang-dev
http://codereview.appspot.com/3975043
diff --git a/compiler/generator/generator.go b/compiler/generator/generator.go
index fa67d86..079fe2a 100644
--- a/compiler/generator/generator.go
+++ b/compiler/generator/generator.go
@@ -200,6 +200,10 @@
 	desc []*Descriptor          // All the messages defined in this file.
 	enum []*EnumDescriptor      // All the enums defined in this file.
 	ext  []*ExtensionDescriptor // All the top-level extensions defined in this file.
+
+	// The full list of symbols that are exported.
+	// This is used for supporting public imports.
+	exported []Symbol
 }
 
 // PackageName is the package name we'll use in the generated code to refer to this file.
@@ -217,6 +221,60 @@
 	return BaseName(proto.GetString(d.Name))
 }
 
+func (d *FileDescriptor) addExport(symbol Symbol) {
+	d.exported = append(d.exported, symbol)
+}
+
+// Symbol is an interface representing an exported Go symbol.
+type Symbol interface {
+	// GenerateAlias should generate an appropriate alias
+	// for the symbol from the named package.
+	GenerateAlias(g *Generator, pkg string)
+}
+
+type messageSymbol struct {
+	sym                         string
+	hasExtensions, isMessageSet bool
+}
+
+func (ms messageSymbol) GenerateAlias(g *Generator, pkg string) {
+	remoteSym := pkg + "." + ms.sym
+
+	g.P("type ", ms.sym, " ", remoteSym)
+	g.P("func (this *", ms.sym, ") Reset() { (*", remoteSym, ")(this).Reset() }")
+	if ms.hasExtensions {
+		g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.ProtoPkg, ".ExtensionRange ",
+			"{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }")
+		g.P("func (this *", ms.sym, ") ExtensionMap() map[int32][]byte ",
+			"{ return (*", remoteSym, ")(this).ExtensionMap() }")
+		if ms.isMessageSet {
+			g.P("func (this *", ms.sym, ") Marshal() ([]byte, os.Error) ",
+				"{ return (*", remoteSym, ")(this).Marshal() }")
+			g.P("func (this *", ms.sym, ") Unmarshal(buf []byte) os.Error ",
+				"{ return (*", remoteSym, ")(this).Unmarshal(buf) }")
+		}
+	}
+}
+
+type enumSymbol string
+
+func (es enumSymbol) GenerateAlias(g *Generator, pkg string) {
+	s := string(es)
+	g.P("type ", s, " ", pkg, ".", s)
+	g.P("var ", s, "_name = ", pkg, ".", s, "_name")
+	g.P("var ", s, "_value = ", pkg, ".", s, "_value")
+	g.P("func New", s, "(x int32) *", s, " { e := ", s, "(x); return &e }")
+}
+
+type constOrVarSymbol struct {
+	sym string
+	typ string // either "const" or "var"
+}
+
+func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) {
+	g.P(cs.typ, " ", cs.sym, " = ", pkg, ".", cs.sym)
+}
+
 // Object is an interface abstracting the abilities shared by enums and messages.
 type Object interface {
 	PackageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
@@ -560,13 +618,24 @@
 	for _, p := range plugins {
 		p.Init(g)
 	}
-	// Generate the output.
-	for i, file := range g.genFiles {
+	// Generate the output. The generator runs for every file, even the files
+	// that we don't generate output for, so that we can collate the full list
+	// of exported symbols to support public imports.
+	genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
+	for _, file := range g.genFiles {
+		genFileMap[file] = true
+	}
+	i := 0
+	for _, file := range g.allFiles {
 		g.Reset()
 		g.generate(file)
+		if _, ok := genFileMap[file]; !ok {
+			continue
+		}
 		g.Response.File[i] = new(plugin.CodeGeneratorResponse_File)
 		g.Response.File[i].Name = proto.String(goFileName(*file.Name))
 		g.Response.File[i].Content = proto.String(g.String())
+		i++
 	}
 }
 
@@ -626,6 +695,15 @@
 	g.P()
 }
 
+func (g *Generator) fileByName(filename string) *FileDescriptor {
+	for _, fd := range g.allFiles {
+		if proto.GetString(fd.Name) == filename {
+			return fd
+		}
+	}
+	return nil
+}
+
 // Generate the header, including package definition and imports
 func (g *Generator) generateImports() {
 	// We almost always need a proto import.  Rather than computing when we
@@ -635,28 +713,23 @@
 	g.P(`import "math"`)
 	g.P(`import "os"`)
 	for _, s := range g.file.Dependency {
-		// Need to find the descriptor for this file
-		for _, fd := range g.allFiles {
-			// Do not import our own package.
-			if fd.PackageName() == g.packageName {
-				continue
-			}
-			if proto.GetString(fd.Name) == s {
-				filename := goFileName(s)
-				if substitution, ok := g.ImportMap[s]; ok {
-					filename = substitution
-				}
-				filename = g.ImportPrefix + filename
-				if strings.HasSuffix(filename, ".go") {
-					filename = filename[0 : len(filename)-3]
-				}
-				if _, ok := g.usedPackages[fd.PackageName()]; ok {
-					g.P("import ", fd.PackageName(), " ", Quote(filename))
-				} else {
-					log.Println("protoc-gen-go: discarding unused import:", filename)
-				}
-				break
-			}
+		fd := g.fileByName(s)
+		// Do not import our own package.
+		if fd.PackageName() == g.packageName {
+			continue
+		}
+		filename := goFileName(s)
+		if substitution, ok := g.ImportMap[s]; ok {
+			filename = substitution
+		}
+		filename = g.ImportPrefix + filename
+		if strings.HasSuffix(filename, ".go") {
+			filename = filename[0 : len(filename)-3]
+		}
+		if _, ok := g.usedPackages[fd.PackageName()]; ok {
+			g.P("import ", fd.PackageName(), " ", Quote(filename))
+		} else {
+			log.Println("protoc-gen-go: discarding unused import:", filename)
 		}
 	}
 	g.P()
@@ -670,6 +743,16 @@
 	g.P("var _ = math.Inf")
 	g.P("var _ os.Error")
 	g.P()
+
+	// Symbols from public imports.
+	for _, index := range g.file.PublicDependency {
+		fd := g.fileByName(g.file.Dependency[index])
+		g.P("// Types from public import ", *fd.Name)
+		for _, sym := range fd.exported {
+			sym.GenerateAlias(g, fd.PackageName())
+		}
+	}
+	g.P()
 }
 
 // Generate the enum definitions for this EnumDescriptor.
@@ -680,10 +763,13 @@
 	ccTypeName := CamelCaseSlice(typeName)
 	ccPrefix := enum.prefix()
 	g.P("type ", ccTypeName, " int32")
+	g.file.addExport(enumSymbol(ccTypeName))
 	g.P("const (")
 	g.In()
 	for _, e := range enum.Value {
-		g.P(ccPrefix+*e.Name, " = ", e.Number)
+		name := ccPrefix + *e.Name
+		g.P(name, " = ", e.Number)
+		g.file.addExport(constOrVarSymbol{name, "const"})
 	}
 	g.Out()
 	g.P(")")
@@ -907,9 +993,12 @@
 	g.P("}")
 
 	// Extension support methods
+	var hasExtensions, isMessageSet bool
 	if len(message.ExtensionRange) > 0 {
+		hasExtensions = true
 		// message_set_wire_format only makes sense when extensions are defined.
 		if opts := message.Options; opts != nil && proto.GetBool(opts.MessageSetWireFormat) {
+			isMessageSet = true
 			g.P()
 			g.P("func (this *", ccTypeName, ") Marshal() ([]byte, os.Error) {")
 			g.In()
@@ -952,6 +1041,8 @@
 		g.P("}")
 	}
 
+	g.file.addExport(messageSymbol{ccTypeName, hasExtensions, isMessageSet})
+
 	// Default constants
 	for _, field := range message.Field {
 		def := proto.GetString(field.DefaultValue)
@@ -996,6 +1087,7 @@
 			def = g.DefaultPackageName(enum) + enum.prefix() + def
 		}
 		g.P(kind, fieldname, " ", typename, " = ", def)
+		g.file.addExport(constOrVarSymbol{fieldname, kind})
 	}
 	g.P()
 
@@ -1029,6 +1121,8 @@
 	g.Out()
 	g.P("}")
 	g.P()
+
+	g.file.addExport(constOrVarSymbol{ccTypeName, "var"})
 }
 
 func (g *Generator) generateInitFunction() {
diff --git a/compiler/testdata/imp.proto b/compiler/testdata/imp.proto
index beb6805..6bf2a13 100644
--- a/compiler/testdata/imp.proto
+++ b/compiler/testdata/imp.proto
@@ -38,4 +38,11 @@
     DAVE = 1;
     MIKE = 2;
   }
+
+  extensions 90 to 100;
+}
+
+message ImportedExtendable {
+  option message_set_wire_format = true;
+  extensions 100 to max;
 }
diff --git a/compiler/testdata/test.pb.go.golden b/compiler/testdata/test.pb.go.golden
index 6a54d22..4d364e7 100644
--- a/compiler/testdata/test.pb.go.golden
+++ b/compiler/testdata/test.pb.go.golden
@@ -13,6 +13,7 @@
 var _ = math.Inf
 var _ os.Error
 
+
 type HatType int32
 const (
 	HatType_FEDORA = 1
diff --git a/proto/testdata/test.pb.go b/proto/testdata/test.pb.go
index eaed281..fa7a666 100644
--- a/proto/testdata/test.pb.go
+++ b/proto/testdata/test.pb.go
@@ -12,6 +12,7 @@
 var _ = math.Inf
 var _ os.Error
 
+
 type FOO int32
 const (
 	FOO_FOO1 = 1