Browse Source

Allow public access to descriptor.proto as a dependency.

With this in place, generating APIs on github.com/google/googleapis works - previously annotations.proto failed.
Currently there's no access to the annotations (stored as extensions) but we could potentially expose those at a later date.
Jon Skeet 10 years ago
parent
commit
a39ababb7c

+ 15 - 0
csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs

@@ -368,5 +368,20 @@ namespace Google.Protobuf.Reflection
         {
             return "FileDescriptor for " + proto.Name;
         }
+
+        /// <summary>
+        /// Returns the file descriptor for descriptor.proto.
+        /// </summary>
+        /// <remarks>
+        /// This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for
+        /// annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf
+        /// runtime for reflection purposes. The messages are internal to the runtime as they would require
+        /// proto2 semantics for full support, but the file descriptor is available via this property. The
+        /// C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>.
+        /// </remarks>
+        /// <value>
+        /// The file descriptor for <c>descriptor.proto</c>.
+        /// </value>
+        public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorProtoFile.Descriptor; } }
     }
 }

+ 4 - 1
src/google/protobuf/compiler/csharp/csharp_helpers.h

@@ -117,7 +117,10 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) {
 inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
   // TODO: Do this better! (Currently this depends on a hack in generate_protos.sh to rename
   // the file...)
-  return descriptor->name() == "google/protobuf/descriptor_proto_file.proto";
+  // We need to be able to detect the "normal" name as well, for times that we're just
+  // depending on descriptor.proto instead of generating it.
+  return descriptor->name() == "google/protobuf/descriptor_proto_file.proto"
+      || descriptor->name() == "google/protobuf/descriptor.proto";
 }
 
 inline bool IsWrapperType(const FieldDescriptor* descriptor) {

+ 8 - 1
src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc

@@ -180,10 +180,17 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
       "descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,\n");
   printer->Print("    new pbr::FileDescriptor[] { ");
   for (int i = 0; i < file_->dependency_count(); i++) {
-    printer->Print(
+    // descriptor.proto is special: we don't allow access to the generated code, but there's
+    // a separately-exposed property to get at the file descriptor, specifically to allow this
+    // kind of dependency.
+    if (IsDescriptorProto(file_->dependency(i))) {
+      printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, ");
+    } else {
+      printer->Print(
       "$full_umbrella_class_name$.Descriptor, ",
       "full_umbrella_class_name",
       GetUmbrellaClassName(file_->dependency(i)));
+    }
   }
   printer->Print("},\n"
       "    new pbr::GeneratedCodeInfo(");