UmbrellaClassGenerator.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System;
  2. using Google.ProtocolBuffers.DescriptorProtos;
  3. using Google.ProtocolBuffers.Descriptors;
  4. namespace Google.ProtocolBuffers.ProtoGen {
  5. /// <summary>
  6. /// Generator for the class describing the .proto file in general,
  7. /// containing things like the message descriptor.
  8. /// </summary>
  9. internal sealed class UmbrellaClassGenerator : SourceGeneratorBase<FileDescriptor>, ISourceGenerator {
  10. internal UmbrellaClassGenerator(FileDescriptor descriptor)
  11. : base(descriptor) {
  12. }
  13. public void Generate(TextGenerator writer) {
  14. WriteIntroduction(writer);
  15. WriteDescriptor(writer);
  16. WriteChildren(writer, "Extensions", Descriptor.Extensions);
  17. writer.WriteLine("#region Static variables");
  18. foreach (MessageDescriptor message in Descriptor.MessageTypes) {
  19. new MessageGenerator(message).GenerateStaticVariables(writer);
  20. }
  21. writer.WriteLine("#endregion");
  22. // The class declaration either gets closed before or after the children are written.
  23. if (!DescriptorUtil.NestClasses(Descriptor)) {
  24. writer.Outdent();
  25. writer.WriteLine("}");
  26. }
  27. WriteChildren(writer, "Enums", Descriptor.EnumTypes);
  28. WriteChildren(writer, "Messages", Descriptor.MessageTypes);
  29. WriteChildren(writer, "Services", Descriptor.Services);
  30. if (DescriptorUtil.NestClasses(Descriptor)) {
  31. writer.Outdent();
  32. writer.WriteLine("}");
  33. }
  34. if (DescriptorUtil.GetNamespace(Descriptor) != "") {
  35. writer.Outdent();
  36. writer.WriteLine("}");
  37. }
  38. }
  39. private void WriteIntroduction(TextGenerator writer) {
  40. writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!");
  41. writer.WriteLine();
  42. Helpers.WriteNamespaces(writer);
  43. if (DescriptorUtil.GetNamespace(Descriptor) != "") {
  44. writer.WriteLine("namespace {0} {{", DescriptorUtil.GetNamespace(Descriptor));
  45. writer.Indent();
  46. writer.WriteLine();
  47. }
  48. writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, DescriptorUtil.GetUmbrellaClassName(Descriptor));
  49. writer.WriteLine();
  50. writer.Indent();
  51. }
  52. private void WriteDescriptor(TextGenerator writer) {
  53. writer.WriteLine("#region Descriptor");
  54. writer.WriteLine("public static pbd::FileDescriptor Descriptor {");
  55. writer.WriteLine(" get { return descriptor; }");
  56. writer.WriteLine("}");
  57. writer.WriteLine("private static readonly pbd::FileDescriptor descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom(");
  58. writer.WriteLine(" global::System.Convert.FromBase64String(");
  59. writer.Indent();
  60. writer.Indent();
  61. // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
  62. byte[] bytes = Descriptor.Proto.ToByteArray();
  63. string base64 = Convert.ToBase64String(bytes);
  64. while (base64.Length > 60) {
  65. writer.WriteLine("\"{0}\" + ", base64.Substring(0, 60));
  66. base64 = base64.Substring(60);
  67. }
  68. writer.WriteLine("\"{0}\"),", base64);
  69. writer.WriteLine("new pbd::FileDescriptor[] {");
  70. foreach (FileDescriptor dependency in Descriptor.Dependencies) {
  71. // TODO(jonskeet): The normal code won't work for the bootstrapping descriptor, because we don't get unknown fields :(
  72. if (dependency.Package == "google.protobuf" && dependency.Name.EndsWith("descriptor.proto")) {
  73. writer.WriteLine(" global::" + typeof(DescriptorProtoFile).FullName + ".Descriptor, ");
  74. continue;
  75. }
  76. writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency));
  77. }
  78. writer.WriteLine("});");
  79. writer.Outdent();
  80. writer.Outdent();
  81. writer.WriteLine("#endregion");
  82. writer.WriteLine();
  83. }
  84. }
  85. }