diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index 500e467c8a..bad58faa9f 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -368,5 +368,20 @@ namespace Google.Protobuf.Reflection { return "FileDescriptor for " + proto.Name; } + + /// + /// Returns the file descriptor for descriptor.proto. + /// + /// + /// This is used for protos which take a direct dependency on descriptor.proto, typically for + /// annotations. While descriptor.proto 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 descriptor.proto. + /// + /// + /// The file descriptor for descriptor.proto. + /// + public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorProtoFile.Descriptor; } } } } \ No newline at end of file diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index 1d17af61be..278e05f38f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/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) { diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc index 0ffae3d4a9..399c64e181 100644 --- a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc +++ b/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(");