cmd/protoc-gen-go-grpc: add Unimplemented...Server type

Also add deprecation comments on methods.

Forward port:
  https://github.com/golang/protobuf/pull/785
  https://github.com/golang/protobuf/pull/952

Fixes golang/protobuf#816

Change-Id: Id4d9f08b39fe16eaf57fb7a92fb8ada222b5cbf4
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/205246
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go-grpc/internal_gengogrpc/grpc.go b/cmd/protoc-gen-go-grpc/internal_gengogrpc/grpc.go
index fd25cd0..a4523a6 100644
--- a/cmd/protoc-gen-go-grpc/internal_gengogrpc/grpc.go
+++ b/cmd/protoc-gen-go-grpc/internal_gengogrpc/grpc.go
@@ -18,6 +18,8 @@
 const (
 	contextPackage = protogen.GoImportPath("context")
 	grpcPackage    = protogen.GoImportPath("google.golang.org/grpc")
+	codesPackage   = protogen.GoImportPath("google.golang.org/grpc/codes")
+	statusPackage  = protogen.GoImportPath("google.golang.org/grpc/status")
 )
 
 // GenerateFile generates a _grpc.pb.go file containing gRPC service definitions.
@@ -72,6 +74,9 @@
 	g.P("type ", clientName, " interface {")
 	for _, method := range service.Methods {
 		g.Annotate(clientName+"."+method.GoName, method.Location)
+		if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+			g.P(deprecationComment)
+		}
 		g.P(method.Comments.Leading,
 			clientSignature(g, method))
 	}
@@ -118,12 +123,31 @@
 	g.P("type ", serverType, " interface {")
 	for _, method := range service.Methods {
 		g.Annotate(serverType+"."+method.GoName, method.Location)
+		if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+			g.P(deprecationComment)
+		}
 		g.P(method.Comments.Leading,
 			serverSignature(g, method))
 	}
 	g.P("}")
 	g.P()
 
+	// Server Unimplemented struct for forward compatibility.
+	g.P("// Unimplemented", serverType, " can be embedded to have forward compatible implementations.")
+	g.P("type Unimplemented", serverType, " struct {")
+	g.P("}")
+	g.P()
+	for _, method := range service.Methods {
+		nilArg := ""
+		if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() {
+			nilArg = "nil,"
+		}
+		g.P("func (*Unimplemented", serverType, ") ", serverSignature(g, method), "{")
+		g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(", codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not implemented")`)
+		g.P("}")
+	}
+	g.P()
+
 	// Server registration.
 	if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
 		g.P(deprecationComment)
diff --git a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation_grpc.pb.go b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation_grpc.pb.go
index fd5cbc2..02124aa 100644
--- a/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation_grpc.pb.go
+++ b/cmd/protoc-gen-go-grpc/testdata/grpc/deprecation_grpc.pb.go
@@ -5,6 +5,8 @@
 import (
 	context "context"
 	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
 )
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -21,6 +23,7 @@
 //
 // Deprecated: Do not use.
 type DeprecatedServiceClient interface {
+	// Deprecated: Do not use.
 	DeprecatedCall(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
 }
 
@@ -47,9 +50,18 @@
 //
 // Deprecated: Do not use.
 type DeprecatedServiceServer interface {
+	// Deprecated: Do not use.
 	DeprecatedCall(context.Context, *Request) (*Response, error)
 }
 
+// UnimplementedDeprecatedServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedDeprecatedServiceServer struct {
+}
+
+func (*UnimplementedDeprecatedServiceServer) DeprecatedCall(context.Context, *Request) (*Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method DeprecatedCall not implemented")
+}
+
 // Deprecated: Do not use.
 func RegisterDeprecatedServiceServer(s *grpc.Server, srv DeprecatedServiceServer) {
 	s.RegisterService(&_DeprecatedService_serviceDesc, srv)
diff --git a/cmd/protoc-gen-go-grpc/testdata/grpc/grpc_grpc.pb.go b/cmd/protoc-gen-go-grpc/testdata/grpc/grpc_grpc.pb.go
index b638f8c..376ccdb 100644
--- a/cmd/protoc-gen-go-grpc/testdata/grpc/grpc_grpc.pb.go
+++ b/cmd/protoc-gen-go-grpc/testdata/grpc/grpc_grpc.pb.go
@@ -5,6 +5,8 @@
 import (
 	context "context"
 	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
 )
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -153,6 +155,23 @@
 	BidiCall(TestService_BidiCallServer) error
 }
 
+// UnimplementedTestServiceServer can be embedded to have forward compatible implementations.
+type UnimplementedTestServiceServer struct {
+}
+
+func (*UnimplementedTestServiceServer) UnaryCall(context.Context, *Request) (*Response, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method UnaryCall not implemented")
+}
+func (*UnimplementedTestServiceServer) DownstreamCall(*Request, TestService_DownstreamCallServer) error {
+	return status.Errorf(codes.Unimplemented, "method DownstreamCall not implemented")
+}
+func (*UnimplementedTestServiceServer) UpstreamCall(TestService_UpstreamCallServer) error {
+	return status.Errorf(codes.Unimplemented, "method UpstreamCall not implemented")
+}
+func (*UnimplementedTestServiceServer) BidiCall(TestService_BidiCallServer) error {
+	return status.Errorf(codes.Unimplemented, "method BidiCall not implemented")
+}
+
 func RegisterTestServiceServer(s *grpc.Server, srv TestServiceServer) {
 	s.RegisterService(&_TestService_serviceDesc, srv)
 }