From d6343be707cb6a067fe2b5ccc2efd7848072d17c Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 12 Nov 2008 23:39:44 +0000 Subject: [PATCH] Refactored options --- protos/google/protobuf/csharp_options.proto | 25 +- protos/google/protobuf/unittest.proto | 4 +- .../protobuf/unittest_custom_options.proto | 4 +- .../unittest_embed_optimize_for.proto | 4 +- protos/google/protobuf/unittest_import.proto | 4 +- protos/google/protobuf/unittest_mset.proto | 4 +- .../protobuf/unittest_optimize_for.proto | 4 +- src/ProtoGen.Test/DescriptorUtilTest.cs | 4 +- src/ProtoGen.Test/HelpersTest.cs | 33 -- src/ProtoGen.Test/ProtoGen.Test.csproj | 1 - src/ProtoGen/DescriptorUtil.cs | 77 +--- src/ProtoGen/ExtensionGenerator.cs | 6 +- src/ProtoGen/FieldGeneratorBase.cs | 12 +- src/ProtoGen/Generator.cs | 16 +- src/ProtoGen/Helpers.cs | 60 --- src/ProtoGen/MessageGenerator.cs | 18 +- src/ProtoGen/ProtoGen.csproj | 2 + src/ProtoGen/ServiceGenerator.cs | 26 +- src/ProtoGen/SourceGeneratorBase.cs | 50 ++- src/ProtoGen/UmbrellaClassGenerator.cs | 21 +- src/ProtocolBuffers.Test/NameHelpersTest.cs | 32 ++ .../ProtocolBuffers.Test.csproj | 3 + .../UnitTestCustomOptionsProtoFile.cs | 6 +- .../UnitTestEmbedOptimizeForProtoFile.cs | 6 +- .../TestProtos/UnitTestImportProtoFile.cs | 6 +- .../TestProtos/UnitTestMessageSetProtoFile.cs | 6 +- .../UnitTestOptimizeForProtoFile.cs | 6 +- .../TestProtos/UnitTestProtoFile.cs | 6 +- .../TestProtos/___7469.tmp | 0 .../DescriptorProtos/CSharpOptions.cs | 392 +++++++++++++++++- .../Descriptors/FileDescriptor.cs | 58 ++- src/ProtocolBuffers/NameHelpers.cs | 78 ++++ src/ProtocolBuffers/ProtocolBuffers.csproj | 1 + todo.txt | 5 +- 34 files changed, 684 insertions(+), 296 deletions(-) delete mode 100644 src/ProtoGen.Test/HelpersTest.cs create mode 100644 src/ProtocolBuffers.Test/NameHelpersTest.cs create mode 100644 src/ProtocolBuffers.Test/TestProtos/___7469.tmp create mode 100644 src/ProtocolBuffers/NameHelpers.cs diff --git a/protos/google/protobuf/csharp_options.proto b/protos/google/protobuf/csharp_options.proto index 5ebaebd1..6d81c5cd 100644 --- a/protos/google/protobuf/csharp_options.proto +++ b/protos/google/protobuf/csharp_options.proto @@ -4,13 +4,22 @@ import "google/protobuf/descriptor.proto"; package google.protobuf; -option (CSharpNamespace) = "Google.ProtocolBuffers.DescriptorProtos"; -option (CSharpUmbrellaClassname) = "CSharpOptions"; +message CSharpFileOptions { + optional string namespace = 1; + optional string umbrella_classname= 2; + optional bool public_classes = 3; + optional bool multiple_files = 4; + optional bool nest_classes = 5; -extend FileOptions { - optional string CSharpNamespace = 20000; - optional string CSharpUmbrellaClassname = 20001; - optional bool CSharpMultipleFiles = 20002; - optional bool CSharpNestClasses = 20003; - optional bool CSharpPublicClasses = 20004; + extend FileOptions { + optional CSharpFileOptions csharp_options = 1000; + } +} + +message CSharpFieldOptions { + optional string property_name = 1; + + extend FieldOptions { + optional CSharpFieldOptions csharp_options = 1000; + } } diff --git a/protos/google/protobuf/unittest.proto b/protos/google/protobuf/unittest.proto index cf5322b6..45ee42b1 100644 --- a/protos/google/protobuf/unittest.proto +++ b/protos/google/protobuf/unittest.proto @@ -2,8 +2,8 @@ // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; import "google/protobuf/descriptor.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/protos/google/protobuf/unittest_custom_options.proto b/protos/google/protobuf/unittest_custom_options.proto index 09a481a2..44525279 100644 --- a/protos/google/protobuf/unittest_custom_options.proto +++ b/protos/google/protobuf/unittest_custom_options.proto @@ -1,8 +1,8 @@ // Additional options required for C# generation. File from copyright // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestCustomOptionsProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestCustomOptionsProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/protos/google/protobuf/unittest_embed_optimize_for.proto b/protos/google/protobuf/unittest_embed_optimize_for.proto index 4af6e58a..9ab1092a 100644 --- a/protos/google/protobuf/unittest_embed_optimize_for.proto +++ b/protos/google/protobuf/unittest_embed_optimize_for.proto @@ -2,8 +2,8 @@ // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; import "google/protobuf/descriptor.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestEmbedOptimizeForProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestEmbedOptimizeForProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/protos/google/protobuf/unittest_import.proto b/protos/google/protobuf/unittest_import.proto index d2ebad90..7af5b74c 100644 --- a/protos/google/protobuf/unittest_import.proto +++ b/protos/google/protobuf/unittest_import.proto @@ -2,8 +2,8 @@ // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; import "google/protobuf/descriptor.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestImportProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestImportProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/protos/google/protobuf/unittest_mset.proto b/protos/google/protobuf/unittest_mset.proto index 75a2771b..74f30021 100644 --- a/protos/google/protobuf/unittest_mset.proto +++ b/protos/google/protobuf/unittest_mset.proto @@ -2,8 +2,8 @@ // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; import "google/protobuf/descriptor.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestMessageSetProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestMessageSetProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/protos/google/protobuf/unittest_optimize_for.proto b/protos/google/protobuf/unittest_optimize_for.proto index 8e4ec113..204d09f9 100644 --- a/protos/google/protobuf/unittest_optimize_for.proto +++ b/protos/google/protobuf/unittest_optimize_for.proto @@ -2,8 +2,8 @@ // line onwards is as per original distribution. import "google/protobuf/csharp_options.proto"; import "google/protobuf/descriptor.proto"; -option (google.protobuf.CSharpNamespace) = "Google.ProtocolBuffers.TestProtos"; -option (google.protobuf.CSharpUmbrellaClassname) = "UnitTestOptimizeForProtoFile"; +option (google.protobuf.CSharpFileOptions.csharp_options).namespace = "Google.ProtocolBuffers.TestProtos"; +option (google.protobuf.CSharpFileOptions.csharp_options).umbrella_classname = "UnitTestOptimizeForProtoFile"; // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. diff --git a/src/ProtoGen.Test/DescriptorUtilTest.cs b/src/ProtoGen.Test/DescriptorUtilTest.cs index 0cbc1c3c..2eb60ef1 100644 --- a/src/ProtoGen.Test/DescriptorUtilTest.cs +++ b/src/ProtoGen.Test/DescriptorUtilTest.cs @@ -5,7 +5,7 @@ using NUnit.Framework; namespace Google.ProtocolBuffers.ProtoGen { [TestFixture] public class DescriptorUtilTest { - + /* FIXME: Move these around! [Test] public void ExplicitNamespace() { FileDescriptorProto proto = new FileDescriptorProto.Builder { @@ -64,6 +64,6 @@ namespace Google.ProtocolBuffers.ProtoGen { FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x/y/foo_bar" }.Build(); FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null); Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor)); - } + } */ } } diff --git a/src/ProtoGen.Test/HelpersTest.cs b/src/ProtoGen.Test/HelpersTest.cs deleted file mode 100644 index 6896cfb6..00000000 --- a/src/ProtoGen.Test/HelpersTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Google.ProtocolBuffers.ProtoGen; -using NUnit.Framework; - -namespace Google.ProtocolBuffers.ProtoGen { - [TestFixture] - public class HelpersTest { - - [Test] - public void UnderscoresToPascalCase() { - Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_bar")); - Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("foo_bar")); - Assert.AreEqual("Foo0Bar", Helpers.UnderscoresToPascalCase("Foo0bar")); - Assert.AreEqual("FooBar", Helpers.UnderscoresToPascalCase("Foo_+_Bar")); - } - - [Test] - public void UnderscoresToCamelCase() { - Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_bar")); - Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("foo_bar")); - Assert.AreEqual("foo0Bar", Helpers.UnderscoresToCamelCase("Foo0bar")); - Assert.AreEqual("fooBar", Helpers.UnderscoresToCamelCase("Foo_+_Bar")); - } - - [Test] - public void StripSuffix() { - string text = "FooBar"; - Assert.IsFalse(Helpers.StripSuffix(ref text, "Foo")); - Assert.AreEqual("FooBar", text); - Assert.IsTrue(Helpers.StripSuffix(ref text, "Bar")); - Assert.AreEqual("Foo", text); - } - } -} \ No newline at end of file diff --git a/src/ProtoGen.Test/ProtoGen.Test.csproj b/src/ProtoGen.Test/ProtoGen.Test.csproj index 805c69ae..a1334493 100644 --- a/src/ProtoGen.Test/ProtoGen.Test.csproj +++ b/src/ProtoGen.Test/ProtoGen.Test.csproj @@ -47,7 +47,6 @@ - diff --git a/src/ProtoGen/DescriptorUtil.cs b/src/ProtoGen/DescriptorUtil.cs index 72df575c..1d479bf0 100644 --- a/src/ProtoGen/DescriptorUtil.cs +++ b/src/ProtoGen/DescriptorUtil.cs @@ -10,80 +10,11 @@ namespace Google.ProtocolBuffers.ProtoGen { /// internal static class DescriptorUtil { - internal static bool NestClasses(IDescriptor descriptor) { - // Defaults to false - return descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses); - } - - internal static string GetNamespace(FileDescriptor descriptor) { - if (descriptor.Name == "google/protobuf/descriptor.proto") { - return typeof(DescriptorProtoFile).Namespace; - } - return descriptor.Options.HasExtension(CSharpOptions.CSharpNamespace) ? - descriptor.Options.GetExtension(CSharpOptions.CSharpNamespace) : descriptor.Package; - } - - // Groups are hacky: The name of the field is just the lower-cased name - // of the group type. In C#, though, we would like to retain the original - // capitalization of the type name. - internal static string GetFieldName(FieldDescriptor descriptor) { - if (descriptor.FieldType == FieldType.Group) { - return descriptor.MessageType.Name; - } else { - return descriptor.Name; - } - } - - internal static string GetClassName(IDescriptor descriptor) { - return ToCSharpName(descriptor.FullName, descriptor.File); - } - - internal static string GetFullUmbrellaClassName(FileDescriptor descriptor) { - string result = GetNamespace(descriptor); + internal static string GetFullUmbrellaClassName(IDescriptor descriptor) { + CSharpFileOptions options = descriptor.File.CSharpOptions; + string result = options.Namespace; if (result != "") result += '.'; - result += GetUmbrellaClassName(descriptor); - return "global::" + result; - } - - internal static string GetUmbrellaClassName(FileDescriptor descriptor) { - if (descriptor.Name == "google/protobuf/descriptor.proto") { - return typeof(DescriptorProtoFile).Name; - } - FileOptions options = descriptor.Options; - if (options.HasExtension(CSharpOptions.CSharpUmbrellaClassname)) { - return descriptor.Options.GetExtension(CSharpOptions.CSharpUmbrellaClassname); - } - int lastSlash = descriptor.Name.LastIndexOf('/'); - string baseName = descriptor.Name.Substring(lastSlash + 1); - return Helpers.UnderscoresToPascalCase(StripProto(baseName)); - } - - private static string StripProto(string text) { - if (!Helpers.StripSuffix(ref text, ".protodevel")) { - Helpers.StripSuffix(ref text, ".proto"); - } - return text; - } - - private static string ToCSharpName(string name, FileDescriptor file) { - string result; - if (!NestClasses(file)) { - result = GetNamespace(file); - } else { - result = GetUmbrellaClassName(file); - } - if (result != "") { - result += '.'; - } - string classname; - if (file.Package == "") { - classname = name; - } else { - // Strip the proto package from full_name since we've replaced it with - // the C# namespace. - classname = name.Substring(file.Package.Length + 1); - } - result += classname.Replace(".", ".Types."); + result += options.UmbrellaClassname; return "global::" + result; } diff --git a/src/ProtoGen/ExtensionGenerator.cs b/src/ProtoGen/ExtensionGenerator.cs index d5a233b1..d1acacdf 100644 --- a/src/ProtoGen/ExtensionGenerator.cs +++ b/src/ProtoGen/ExtensionGenerator.cs @@ -9,15 +9,15 @@ namespace Google.ProtocolBuffers.ProtoGen { } public void Generate(TextGenerator writer) { - string name = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor)); + string name = NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor)); string type; switch (Descriptor.MappedType) { case MappedType.Message: - type = DescriptorUtil.GetClassName(Descriptor.MessageType); + type = GetClassName(Descriptor.MessageType); break; case MappedType.Enum: - type = DescriptorUtil.GetClassName(Descriptor.EnumType); + type = GetClassName(Descriptor.EnumType); break; default: type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType); diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs index 6c8f5416..a6e086ed 100644 --- a/src/ProtoGen/FieldGeneratorBase.cs +++ b/src/ProtoGen/FieldGeneratorBase.cs @@ -50,7 +50,7 @@ namespace Google.ProtocolBuffers.ProtoGen { if (!Descriptor.HasDefaultValue) { return "pb::ByteString.Empty"; } - return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index); + return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index); case FieldType.String: if (AllPrintableAscii(Descriptor.Proto.DefaultValue)) { // All chars are ASCII and printable. In this case we only @@ -61,7 +61,7 @@ namespace Google.ProtocolBuffers.ProtoGen { .Replace("\"", "\\\"") + "\""; } - return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", DescriptorUtil.GetClassName(Descriptor.ContainingType), Descriptor.Index); + return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue", GetClassName(Descriptor.ContainingType), Descriptor.Index); case FieldType.Enum: return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name; case FieldType.Message: @@ -88,11 +88,11 @@ namespace Google.ProtocolBuffers.ProtoGen { } protected string CapitalizedName { - get { return Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(Descriptor)); } + get { return NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor)); } } protected string Name { - get { return Helpers.UnderscoresToCamelCase(DescriptorUtil.GetFieldName(Descriptor)); } + get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); } } protected int Number { @@ -103,10 +103,10 @@ namespace Google.ProtocolBuffers.ProtoGen { get { switch (Descriptor.FieldType) { case FieldType.Enum: - return DescriptorUtil.GetClassName(Descriptor.EnumType); + return GetClassName(Descriptor.EnumType); case FieldType.Message: case FieldType.Group: - return DescriptorUtil.GetClassName(Descriptor.MessageType); + return GetClassName(Descriptor.MessageType); default: return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType); } diff --git a/src/ProtoGen/Generator.cs b/src/ProtoGen/Generator.cs index b447d42f..f7a82cca 100644 --- a/src/ProtoGen/Generator.cs +++ b/src/ProtoGen/Generator.cs @@ -30,11 +30,8 @@ namespace Google.ProtocolBuffers.ProtoGen { foreach (string inputFile in options.InputFiles) { FileDescriptorSet descriptorProtos; ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance(); - extensionRegistry.Add(CSharpOptions.CSharpUmbrellaClassname); - extensionRegistry.Add(CSharpOptions.CSharpMultipleFiles); - extensionRegistry.Add(CSharpOptions.CSharpNamespace); - extensionRegistry.Add(CSharpOptions.CSharpNestClasses); - extensionRegistry.Add(CSharpOptions.CSharpPublicClasses); + extensionRegistry.Add(CSharpFileOptions.CSharpOptions); + extensionRegistry.Add(CSharpFieldOptions.CSharpOptions); using (Stream inputStream = File.OpenRead(inputFile)) { descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry); } @@ -51,12 +48,9 @@ namespace Google.ProtocolBuffers.ProtoGen { /// already have been resolved. /// private void Generate(FileDescriptor descriptor) { - string umbrellaClass = DescriptorUtil.GetUmbrellaClassName(descriptor); - string ns = DescriptorUtil.GetNamespace(descriptor); - using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, umbrellaClass + ".cs"))) { - TextGenerator writer = new TextGenerator(textWriter); - - UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor); + UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor); + using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, descriptor.CSharpOptions.UmbrellaClassname + ".cs"))) { + TextGenerator writer = new TextGenerator(textWriter); ucg.Generate(writer); /* GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes); diff --git a/src/ProtoGen/Helpers.cs b/src/ProtoGen/Helpers.cs index 74697bfa..a6a0e6c4 100644 --- a/src/ProtoGen/Helpers.cs +++ b/src/ProtoGen/Helpers.cs @@ -8,71 +8,11 @@ namespace Google.ProtocolBuffers.ProtoGen { /// Helpers to resolve class names etc. /// internal static class Helpers { - internal static string UnderscoresToPascalCase(string input) { - return UnderscoresToPascalOrCamelCase(input, true); - } - - internal static string UnderscoresToCamelCase(string input) { - return UnderscoresToPascalOrCamelCase(input, false); - } - internal static void WriteNamespaces(TextGenerator writer) { writer.WriteLine("using pb = global::Google.ProtocolBuffers;"); writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); writer.WriteLine("using scg = global::System.Collections.Generic;"); } - - /// - /// Converts a string to Pascal or Camel case. The first letter is capitalized or - /// lower-cased depending on is true. - /// After the first letter, any punctuation is removed but triggers capitalization - /// of the next letter. Digits are preserved but trigger capitalization of the next - /// letter. - /// All capitalisation is done in the invariant culture. - /// - private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) { - StringBuilder result = new StringBuilder(); - bool capitaliseNext = pascal; - for (int i=0; i < input.Length; i++) { - char c = input[i]; - if ('a' <= c && c <= 'z') { - if (capitaliseNext) { - result.Append(char.ToUpperInvariant(c)); - } else { - result.Append(c); - } - capitaliseNext = false; - } else if ('A' <= c && c <= 'Z') { - if (i == 0 && !pascal) { - // Force first letter to lower-case unless explicitly told to - // capitalize it. - result.Append(char.ToLowerInvariant(c)); - } else { - // Capital letters after the first are left as-is. - result.Append(c); - } - capitaliseNext = false; - } else if ('0' <= c && c <= '9') { - result.Append(c); - capitaliseNext = true; - } else { - capitaliseNext = true; - } - } - return result.ToString(); - } - - /// - /// Attempts to strip a suffix from a string, returning whether - /// or not the suffix was actually present. - /// - internal static bool StripSuffix(ref string text, string suffix) { - if (text.EndsWith(suffix)) { - text = text.Substring(0, text.Length - suffix.Length); - return true; - } - return false; - } } } diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs index 52dc6d07..f877ac6d 100644 --- a/src/ProtoGen/MessageGenerator.cs +++ b/src/ProtoGen/MessageGenerator.cs @@ -15,7 +15,7 @@ namespace Google.ProtocolBuffers.ProtoGen { } private string FullClassName { - get { return DescriptorUtil.GetClassName(Descriptor); } + get { return GetClassName(Descriptor); } } /// @@ -38,7 +38,7 @@ namespace Google.ProtocolBuffers.ProtoGen { string identifier = GetUniqueFileScopeIdentifier(Descriptor); // The descriptor for this type. - string access = Descriptor.File.Options.GetExtension(CSharpOptions.CSharpNestClasses) ? "private" : "internal"; + string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal"; writer.WriteLine("{0} static readonly pbd::MessageDescriptor internal__{1}__Descriptor", access, identifier); if (Descriptor.ContainingType == null) { writer.WriteLine(" = Descriptor.MessageTypes[{0}];", Descriptor.Index); @@ -51,7 +51,7 @@ namespace Google.ProtocolBuffers.ProtoGen { FullClassName, identifier); writer.Print(" new string[] { "); foreach (FieldDescriptor field in Descriptor.Fields) { - writer.Write("\"{0}\", ", Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field))); + writer.Write("\"{0}\", ", NameHelpers.UnderscoresToPascalCase(GetFieldName(field))); } writer.WriteLine("});"); @@ -80,12 +80,12 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine("public static pbd::MessageDescriptor Descriptor {"); - writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File), + writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor), GetUniqueFileScopeIdentifier(Descriptor)); writer.WriteLine("}"); writer.WriteLine(); writer.WriteLine("protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{", ClassName); - writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File), + writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}", DescriptorUtil.GetFullUmbrellaClassName(Descriptor), GetUniqueFileScopeIdentifier(Descriptor)); writer.WriteLine("}"); writer.WriteLine(); @@ -186,7 +186,7 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(); } - private static void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) { + private void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor) { SourceGenerators.CreateFieldGenerator(fieldDescriptor).GenerateSerializationCode(writer); } @@ -415,7 +415,7 @@ namespace Google.ProtocolBuffers.ProtoGen { // "has" fields into a single bitfield. foreach (FieldDescriptor field in Descriptor.Fields) { if (field.IsRequired) { - writer.WriteLine("if (!has{0}) return false;", Helpers.UnderscoresToPascalCase(field.Name)); + writer.WriteLine("if (!has{0}) return false;", NameHelpers.UnderscoresToPascalCase(field.Name)); } } @@ -425,9 +425,9 @@ namespace Google.ProtocolBuffers.ProtoGen { !HasRequiredFields(field.MessageType, new Dictionary())) { continue; } - string propertyName = Helpers.UnderscoresToPascalCase(DescriptorUtil.GetFieldName(field)); + string propertyName = NameHelpers.UnderscoresToPascalCase(GetFieldName(field)); if (field.IsRepeated) { - writer.WriteLine("foreach ({0} element in {1}List) {{", DescriptorUtil.GetClassName(field.MessageType), propertyName); + writer.WriteLine("foreach ({0} element in {1}List) {{", GetClassName(field.MessageType), propertyName); writer.WriteLine(" if (!element.IsInitialized) return false;"); writer.WriteLine("}"); } else if (field.IsOptional) { diff --git a/src/ProtoGen/ProtoGen.csproj b/src/ProtoGen/ProtoGen.csproj index f48df42c..126c1d04 100644 --- a/src/ProtoGen/ProtoGen.csproj +++ b/src/ProtoGen/ProtoGen.csproj @@ -36,6 +36,8 @@ + + diff --git a/src/ProtoGen/ServiceGenerator.cs b/src/ProtoGen/ServiceGenerator.cs index d36eec19..ebc9d46c 100644 --- a/src/ProtoGen/ServiceGenerator.cs +++ b/src/ProtoGen/ServiceGenerator.cs @@ -20,17 +20,17 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.Indent(); foreach (MethodDescriptor method in Descriptor.Methods) { - writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, Helpers.UnderscoresToPascalCase(method.Name)); + writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel, NameHelpers.UnderscoresToPascalCase(method.Name)); writer.WriteLine(" pb::IRpcController controller,"); - writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType)); - writer.WriteLine(" global::System.Action<{0}> done);", DescriptorUtil.GetClassName(method.OutputType)); + writer.WriteLine(" {0} request,", GetClassName(method.InputType)); + writer.WriteLine(" global::System.Action<{0}> done);", GetClassName(method.OutputType)); } // Generate Descriptor and DescriptorForType. writer.WriteLine(); writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel); writer.WriteLine(" get {{ return {0}.Descriptor.Services[{1}]; }}", - DescriptorUtil.GetUmbrellaClassName(Descriptor.File), Descriptor.Index); + Descriptor.File.CSharpOptions.UmbrellaClassname, Descriptor.Index); writer.WriteLine("}"); writer.WriteLine("{0} pbd::ServiceDescriptor DescriptorForType {{", ClassAccessLevel); writer.WriteLine(" get { return Descriptor; }"); @@ -62,8 +62,8 @@ namespace Google.ProtocolBuffers.ProtoGen { foreach (MethodDescriptor method in Descriptor.Methods) { writer.WriteLine("case {0}:", method.Index); writer.WriteLine(" this.{0}(controller, ({1}) request,", - Helpers.UnderscoresToPascalCase(method.Name), DescriptorUtil.GetClassName(method.InputType)); - writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", DescriptorUtil.GetClassName(method.OutputType)); + NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType)); + writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", GetClassName(method.OutputType)); writer.WriteLine(" done));"); writer.WriteLine(" return;"); } @@ -89,7 +89,7 @@ namespace Google.ProtocolBuffers.ProtoGen { foreach (MethodDescriptor method in Descriptor.Methods) { writer.WriteLine("case {0}:", method.Index); writer.WriteLine(" return {0}.DefaultInstance;", - DescriptorUtil.GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType)); + GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType)); } writer.WriteLine("default:"); writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");"); @@ -105,7 +105,7 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(" return new Stub(channel);"); writer.WriteLine("}"); writer.WriteLine(); - writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, DescriptorUtil.GetClassName(Descriptor)); + writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, GetClassName(Descriptor)); writer.Indent(); writer.WriteLine("internal Stub(pb::IRpcChannel channel) {"); writer.WriteLine(" this.channel = channel;"); @@ -119,15 +119,15 @@ namespace Google.ProtocolBuffers.ProtoGen { foreach (MethodDescriptor method in Descriptor.Methods) { writer.WriteLine(); - writer.WriteLine("public override void {0}(", Helpers.UnderscoresToPascalCase(method.Name)); + writer.WriteLine("public override void {0}(", NameHelpers.UnderscoresToPascalCase(method.Name)); writer.WriteLine(" pb::IRpcController controller,"); - writer.WriteLine(" {0} request,", DescriptorUtil.GetClassName(method.InputType)); - writer.WriteLine(" global::System.Action<{0}> done) {{", DescriptorUtil.GetClassName(method.OutputType)); + writer.WriteLine(" {0} request,", GetClassName(method.InputType)); + writer.WriteLine(" global::System.Action<{0}> done) {{", GetClassName(method.OutputType)); writer.Indent(); writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index); - writer.WriteLine(" controller, request, {0}.DefaultInstance,", DescriptorUtil.GetClassName(method.OutputType)); + writer.WriteLine(" controller, request, {0}.DefaultInstance,", GetClassName(method.OutputType)); writer.WriteLine(" pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));", - DescriptorUtil.GetClassName(method.OutputType)); + GetClassName(method.OutputType)); writer.Outdent(); writer.WriteLine("}"); } diff --git a/src/ProtoGen/SourceGeneratorBase.cs b/src/ProtoGen/SourceGeneratorBase.cs index 7787d59a..6abe1dde 100644 --- a/src/ProtoGen/SourceGeneratorBase.cs +++ b/src/ProtoGen/SourceGeneratorBase.cs @@ -1,5 +1,5 @@ +using System; using System.Collections.Generic; -using Google.ProtocolBuffers.DescriptorProtos; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers.ProtoGen { @@ -15,19 +15,51 @@ namespace Google.ProtocolBuffers.ProtoGen { get { return descriptor; } } - protected string ClassAccessLevel { - get { - // Default to public - return !descriptor.File.Options.HasExtension(CSharpOptions.CSharpPublicClasses) - || descriptor.File.Options.GetExtension(CSharpOptions.CSharpPublicClasses) ? "public" : "internal"; + internal static string GetClassName(IDescriptor descriptor) { + return ToCSharpName(descriptor.FullName, descriptor.File); + } + + // Groups are hacky: The name of the field is just the lower-cased name + // of the group type. In C#, though, we would like to retain the original + // capitalization of the type name. + internal static string GetFieldName(FieldDescriptor descriptor) { + if (descriptor.FieldType == FieldType.Group) { + return descriptor.MessageType.Name; + } else { + return descriptor.Name; } } - public bool MultipleFiles { - get { return descriptor.File.Options.GetExtension(CSharpOptions.CSharpMultipleFiles); } + private static string ToCSharpName(string name, FileDescriptor file) { + string result = file.CSharpOptions.Namespace; + if (file.CSharpOptions.NestClasses) { + if (result != "") { + result += "."; + } + result += file.CSharpOptions.UmbrellaClassname; + } + if (result != "") { + result += '.'; + } + string classname; + if (file.Package == "") { + classname = name; + } else { + // Strip the proto package from full_name since we've replaced it with + // the C# namespace. + classname = name.Substring(file.Package.Length + 1); + } + result += classname.Replace(".", ".Types."); + return "global::" + result; } - protected static void WriteChildren(TextGenerator writer, string region, IEnumerable children) + protected string ClassAccessLevel { + get { + return descriptor.File.CSharpOptions.PublicClasses ? "public" : "internal"; + } + } + + protected void WriteChildren(TextGenerator writer, string region, IEnumerable children) where TChild : IDescriptor { // Copy the set of children; makes access easier List copy = new List(children); diff --git a/src/ProtoGen/UmbrellaClassGenerator.cs b/src/ProtoGen/UmbrellaClassGenerator.cs index cbb50682..938507b5 100644 --- a/src/ProtoGen/UmbrellaClassGenerator.cs +++ b/src/ProtoGen/UmbrellaClassGenerator.cs @@ -13,6 +13,10 @@ namespace Google.ProtocolBuffers.ProtoGen { : base(descriptor) { } + public string UmbrellaClassName { + get { throw new NotImplementedException(); } + } + public void Generate(TextGenerator writer) { WriteIntroduction(writer); WriteDescriptor(writer); @@ -23,18 +27,18 @@ namespace Google.ProtocolBuffers.ProtoGen { } writer.WriteLine("#endregion"); // The class declaration either gets closed before or after the children are written. - if (!DescriptorUtil.NestClasses(Descriptor)) { + if (!Descriptor.CSharpOptions.NestClasses) { writer.Outdent(); writer.WriteLine("}"); } WriteChildren(writer, "Enums", Descriptor.EnumTypes); WriteChildren(writer, "Messages", Descriptor.MessageTypes); WriteChildren(writer, "Services", Descriptor.Services); - if (DescriptorUtil.NestClasses(Descriptor)) { + if (Descriptor.CSharpOptions.NestClasses) { writer.Outdent(); writer.WriteLine("}"); } - if (DescriptorUtil.GetNamespace(Descriptor) != "") { + if (Descriptor.CSharpOptions.Namespace != "") { writer.Outdent(); writer.WriteLine("}"); } @@ -45,13 +49,13 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine(); Helpers.WriteNamespaces(writer); - if (DescriptorUtil.GetNamespace(Descriptor) != "") { - writer.WriteLine("namespace {0} {{", DescriptorUtil.GetNamespace(Descriptor)); + if (Descriptor.CSharpOptions.Namespace != "") { + writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace); writer.Indent(); writer.WriteLine(); } - writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, DescriptorUtil.GetUmbrellaClassName(Descriptor)); + writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, Descriptor.CSharpOptions.UmbrellaClassname); writer.WriteLine(); writer.Indent(); } @@ -79,11 +83,6 @@ namespace Google.ProtocolBuffers.ProtoGen { writer.WriteLine("new pbd::FileDescriptor[] {"); foreach (FileDescriptor dependency in Descriptor.Dependencies) { - // TODO(jonskeet): The normal code won't work for the bootstrapping descriptor, because we don't get unknown fields :( - if (dependency.Package == "google.protobuf" && dependency.Name.EndsWith("descriptor.proto")) { - writer.WriteLine(" global::" + typeof(DescriptorProtoFile).FullName + ".Descriptor, "); - continue; - } writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency)); } writer.WriteLine("});"); diff --git a/src/ProtocolBuffers.Test/NameHelpersTest.cs b/src/ProtocolBuffers.Test/NameHelpersTest.cs new file mode 100644 index 00000000..0bdab19c --- /dev/null +++ b/src/ProtocolBuffers.Test/NameHelpersTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; + +namespace Google.ProtocolBuffers { + [TestFixture] + public class NameHelpersTest { + + [Test] + public void UnderscoresToPascalCase() { + Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_bar")); + Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("foo_bar")); + Assert.AreEqual("Foo0Bar", NameHelpers.UnderscoresToPascalCase("Foo0bar")); + Assert.AreEqual("FooBar", NameHelpers.UnderscoresToPascalCase("Foo_+_Bar")); + } + + [Test] + public void UnderscoresToCamelCase() { + Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_bar")); + Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("foo_bar")); + Assert.AreEqual("foo0Bar", NameHelpers.UnderscoresToCamelCase("Foo0bar")); + Assert.AreEqual("fooBar", NameHelpers.UnderscoresToCamelCase("Foo_+_Bar")); + } + + [Test] + public void StripSuffix() { + string text = "FooBar"; + Assert.IsFalse(NameHelpers.StripSuffix(ref text, "Foo")); + Assert.AreEqual("FooBar", text); + Assert.IsTrue(NameHelpers.StripSuffix(ref text, "Bar")); + Assert.AreEqual("Foo", text); + } + } +} \ No newline at end of file diff --git a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj index 7f84da07..836ee2d8 100644 --- a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj +++ b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj @@ -42,6 +42,8 @@ ..\..\lib\Rhino.Mocks.dll + + @@ -55,6 +57,7 @@ + diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs index 8a1def53..ff777cbb 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestCustomOptionsProtoFile.cs @@ -109,9 +109,9 @@ namespace Google.ProtocolBuffers.TestProtos { "Zi5NZXNzYWdlT3B0aW9ucxjvi9IDIAEoCzIlLnByb3RvYnVmX3VuaXR0ZXN0" + "LkNvbXBsZXhPcHRpb25UeXBlMzpXCgtjb21wbGV4b3B0NhIfLmdvb2dsZS5w" + "cm90b2J1Zi5NZXNzYWdlT3B0aW9ucxjMy88DIAEoCjIeLnByb3RvYnVmX3Vu" + - "aXR0ZXN0LkNvbXBsZXhPcHQ2QlCC4gkhR29vZ2xlLlByb3RvY29sQnVmZmVy" + - "cy5UZXN0UHJvdG9ziuIJHlVuaXRUZXN0Q3VzdG9tT3B0aW9uc1Byb3RvRmls" + - "ZfDowR3qrcDlJA=="), + "aXR0ZXN0LkNvbXBsZXhPcHQ2Qk/CPkMKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZl" + + "cnMuVGVzdFByb3RvcxIeVW5pdFRlc3RDdXN0b21PcHRpb25zUHJvdG9GaWxl" + + "8OjBHeqtwOUk"), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs index 9dcbf1fe..c31de51b 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestEmbedOptimizeForProtoFile.cs @@ -21,9 +21,9 @@ namespace Google.ProtocolBuffers.TestProtos { "ci5wcm90byKhAQoZVGVzdEVtYmVkT3B0aW1pemVkRm9yU2l6ZRJBChBvcHRp" + "b25hbF9tZXNzYWdlGAEgASgLMicucHJvdG9idWZfdW5pdHRlc3QuVGVzdE9w" + "dGltaXplZEZvclNpemUSQQoQcmVwZWF0ZWRfbWVzc2FnZRgCIAMoCzInLnBy" + - "b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQkxIAYLiCSFH" + - "b29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkhVW5pdFRlc3RF" + - "bWJlZE9wdGltaXplRm9yUHJvdG9GaWxl"), + "b3RvYnVmX3VuaXR0ZXN0LlRlc3RPcHRpbWl6ZWRGb3JTaXplQktIAcI+Rgoh" + + "R29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEiFVbml0VGVzdEVt" + + "YmVkT3B0aW1pemVGb3JQcm90b0ZpbGU="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs index c8f5bef2..c774c644 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestImportProtoFile.cs @@ -19,9 +19,9 @@ namespace Google.ProtocolBuffers.TestProtos { "b3B0aW9ucy5wcm90bxogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJv" + "dG8iGgoNSW1wb3J0TWVzc2FnZRIJCgFkGAEgASgFKjwKCkltcG9ydEVudW0S" + "DgoKSU1QT1JUX0ZPTxAHEg4KCklNUE9SVF9CQVIQCBIOCgpJTVBPUlRfQkFa" + - "EAlCXAoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAGC4gkhR29vZ2xlLlBy" + - "b3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJF1VuaXRUZXN0SW1wb3J0UHJv" + - "dG9GaWxl"), + "EAlCWwoYY29tLmdvb2dsZS5wcm90b2J1Zi50ZXN0SAHCPjwKIUdvb2dsZS5Q" + + "cm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIXVW5pdFRlc3RJbXBvcnRQcm90" + + "b0ZpbGU="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs index 72b06d33..e83794e0 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestMessageSetProtoFile.cs @@ -28,9 +28,9 @@ namespace Google.ProtocolBuffers.TestProtos { "U2V0GPm7XiABKAsyKy5wcm90b2J1Zl91bml0dGVzdC5UZXN0TWVzc2FnZVNl" + "dEV4dGVuc2lvbjIibgoNUmF3TWVzc2FnZVNldBIzCgRpdGVtGAEgAygKMiUu" + "cHJvdG9idWZfdW5pdHRlc3QuUmF3TWVzc2FnZVNldC5JdGVtGigKBEl0ZW0S" + - "DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkZIAYLiCSFHb29n" + - "bGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQcm90b3OK4gkbVW5pdFRlc3RNZXNz" + - "YWdlU2V0UHJvdG9GaWxl"), + "DwoHdHlwZV9pZBgCIAIoBRIPCgdtZXNzYWdlGAMgAigMQkVIAcI+QAohR29v" + + "Z2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9zEhtVbml0VGVzdE1lc3Nh" + + "Z2VTZXRQcm90b0ZpbGU="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs index cc555777..3129ec47 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs @@ -26,9 +26,9 @@ namespace Google.ProtocolBuffers.TestProtos { "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZSIpChxU" + "ZXN0UmVxdWlyZWRPcHRpbWl6ZWRGb3JTaXplEgkKAXgYASACKAUiWgocVGVz" + "dE9wdGlvbmFsT3B0aW1pemVkRm9yU2l6ZRI6CgFvGAEgASgLMi8ucHJvdG9i" + - "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJHSAKC" + - "4gkhR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0UHJvdG9ziuIJHFVuaXRU" + - "ZXN0T3B0aW1pemVGb3JQcm90b0ZpbGU="), + "dWZfdW5pdHRlc3QuVGVzdFJlcXVpcmVkT3B0aW1pemVkRm9yU2l6ZUJGSALC" + + "PkEKIUdvb2dsZS5Qcm90b2NvbEJ1ZmZlcnMuVGVzdFByb3RvcxIcVW5pdFRl" + + "c3RPcHRpbWl6ZUZvclByb3RvRmlsZQ=="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs b/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs index 9e706b02..03195c9d 100644 --- a/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs +++ b/src/ProtocolBuffers.Test/TestProtos/UnitTestProtoFile.cs @@ -284,9 +284,9 @@ namespace Google.ProtocolBuffers.TestProtos { "dW5pdHRlc3QuVGVzdEFsbEV4dGVuc2lvbnMYVSABKAk6AzEyM0ICCAE6QgoT" + "bXlfZXh0ZW5zaW9uX3N0cmluZxIlLnByb3RvYnVmX3VuaXR0ZXN0LlRlc3RG" + "aWVsZE9yZGVyaW5ncxgyIAEoCTo/ChBteV9leHRlbnNpb25faW50EiUucHJv" + - "dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQktCDVVu" + - "aXR0ZXN0UHJvdG9IAYLiCSFHb29nbGUuUHJvdG9jb2xCdWZmZXJzLlRlc3RQ" + - "cm90b3OK4gkRVW5pdFRlc3RQcm90b0ZpbGU="), + "dG9idWZfdW5pdHRlc3QuVGVzdEZpZWxkT3JkZXJpbmdzGAUgASgFQkpCDVVu" + + "aXR0ZXN0UHJvdG9IAcI+NgohR29vZ2xlLlByb3RvY29sQnVmZmVycy5UZXN0" + + "UHJvdG9zEhFVbml0VGVzdFByb3RvRmlsZQ=="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.Descriptor, global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, diff --git a/src/ProtocolBuffers.Test/TestProtos/___7469.tmp b/src/ProtocolBuffers.Test/TestProtos/___7469.tmp new file mode 100644 index 00000000..e69de29b diff --git a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs index 14d6bb64..55a30030 100644 --- a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs +++ b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs @@ -15,35 +15,381 @@ namespace Google.ProtocolBuffers.DescriptorProtos { private static readonly pbd::FileDescriptor descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom( global::System.Convert.FromBase64String( "CiRnb29nbGUvcHJvdG9idWYvY3NoYXJwX29wdGlvbnMucHJvdG8SD2dvb2ds" + - "ZS5wcm90b2J1ZhogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG86" + - "NwoPQ1NoYXJwTmFtZXNwYWNlEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRp" + - "b25zGKCcASABKAk6PwoXQ1NoYXJwVW1icmVsbGFDbGFzc25hbWUSHC5nb29n" + - "bGUucHJvdG9idWYuRmlsZU9wdGlvbnMYoZwBIAEoCTo7ChNDU2hhcnBNdWx0" + - "aXBsZUZpbGVzEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKKcASAB" + - "KAg6OQoRQ1NoYXJwTmVzdENsYXNzZXMSHC5nb29nbGUucHJvdG9idWYuRmls" + - "ZU9wdGlvbnMYo5wBIAEoCDo7ChNDU2hhcnBQdWJsaWNDbGFzc2VzEhwuZ29v" + - "Z2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKScASABKAhCPILiCSdHb29nbGUu" + - "UHJvdG9jb2xCdWZmZXJzLkRlc2NyaXB0b3JQcm90b3OK4gkNQ1NoYXJwT3B0" + - "aW9ucw=="), + "ZS5wcm90b2J1ZhogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8i" + + "4wEKEUNTaGFycEZpbGVPcHRpb25zEhEKCW5hbWVzcGFjZRgBIAEoCRIaChJ1" + + "bWJyZWxsYV9jbGFzc25hbWUYAiABKAkSFgoOcHVibGljX2NsYXNzZXMYAyAB" + + "KAgSFgoObXVsdGlwbGVfZmlsZXMYBCABKAgSFAoMbmVzdF9jbGFzc2VzGAUg" + + "ASgIMlkKDmNzaGFycF9vcHRpb25zEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVP" + + "cHRpb25zGOgHIAEoCzIiLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWxlT3B0" + + "aW9ucyKIAQoSQ1NoYXJwRmllbGRPcHRpb25zEhUKDXByb3BlcnR5X25hbWUY" + + "ASABKAkyWwoOY3NoYXJwX29wdGlvbnMSHS5nb29nbGUucHJvdG9idWYuRmll" + + "bGRPcHRpb25zGOgHIAEoCzIjLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWVs" + + "ZE9wdGlvbnM="), new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, }); #endregion - #region Extensions - public static readonly pb::GeneratedExtensionBase CSharpNamespace = - pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[0]); - public static readonly pb::GeneratedExtensionBase CSharpUmbrellaClassname = - pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[1]); - public static readonly pb::GeneratedExtensionBase CSharpMultipleFiles = - pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[2]); - public static readonly pb::GeneratedExtensionBase CSharpNestClasses = - pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[3]); - public static readonly pb::GeneratedExtensionBase CSharpPublicClasses = - pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[4]); - #endregion - #region Static variables + internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_CSharpFileOptions__Descriptor + = Descriptor.MessageTypes[0]; + internal static pb::FieldAccess.FieldAccessorTable internal__static_google_protobuf_CSharpFileOptions__FieldAccessorTable + = new pb::FieldAccess.FieldAccessorTable(internal__static_google_protobuf_CSharpFileOptions__Descriptor, + new string[] { "Namespace", "UmbrellaClassname", "PublicClasses", "MultipleFiles", "NestClasses", }); + internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_CSharpFieldOptions__Descriptor + = Descriptor.MessageTypes[1]; + internal static pb::FieldAccess.FieldAccessorTable internal__static_google_protobuf_CSharpFieldOptions__FieldAccessorTable + = new pb::FieldAccess.FieldAccessorTable(internal__static_google_protobuf_CSharpFieldOptions__Descriptor, + new string[] { "PropertyName", }); #endregion } + #region Messages + public sealed partial class CSharpFileOptions : pb::GeneratedMessage { + private static readonly CSharpFileOptions defaultInstance = new Builder().BuildPartial(); + public static CSharpFileOptions DefaultInstance { + get { return defaultInstance; } + } + + public override CSharpFileOptions DefaultInstanceForType { + get { return defaultInstance; } + } + + protected override CSharpFileOptions ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFileOptions__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFileOptions__FieldAccessorTable; } + } + + public static readonly pb::GeneratedExtensionBase CSharpOptions = + pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[0]); + private bool hasNamespace; + private string namespace_ = ""; + public bool HasNamespace { + get { return hasNamespace; } + } + public string Namespace { + get { return namespace_; } + } + + private bool hasUmbrellaClassname; + private string umbrellaClassname_ = ""; + public bool HasUmbrellaClassname { + get { return hasUmbrellaClassname; } + } + public string UmbrellaClassname { + get { return umbrellaClassname_; } + } + + private bool hasPublicClasses; + private bool publicClasses_ = false; + public bool HasPublicClasses { + get { return hasPublicClasses; } + } + public bool PublicClasses { + get { return publicClasses_; } + } + + private bool hasMultipleFiles; + private bool multipleFiles_ = false; + public bool HasMultipleFiles { + get { return hasMultipleFiles; } + } + public bool MultipleFiles { + get { return multipleFiles_; } + } + + private bool hasNestClasses; + private bool nestClasses_ = false; + public bool HasNestClasses { + get { return hasNestClasses; } + } + public bool NestClasses { + get { return nestClasses_; } + } + + public static CSharpFileOptions ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(pb::CodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static CSharpFileOptions ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static Builder CreateBuilder() { return new Builder(); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(CSharpFileOptions prototype) { + return (Builder) new Builder().MergeFrom(prototype); + } + + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() {} + + CSharpFileOptions result = new CSharpFileOptions(); + + protected override CSharpFileOptions MessageBeingBuilt { + get { return result; } + } + + public override Builder Clear() { + result = new CSharpFileOptions(); + return this; + } + + public override Builder Clone() { + return new Builder().MergeFrom(result); + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return CSharpFileOptions.Descriptor; } + } + + public override CSharpFileOptions DefaultInstanceForType { + get { return CSharpFileOptions.DefaultInstance; } + } + + public override CSharpFileOptions BuildPartial() { + CSharpFileOptions returnMe = result; + result = null; + return returnMe; + } + + + public bool HasNamespace { + get { return result.HasNamespace; } + } + public string Namespace { + get { return result.Namespace; } + set { SetNamespace(value); } + } + public Builder SetNamespace(string value) { + result.hasNamespace = true; + result.namespace_ = value; + return this; + } + public Builder ClearNamespace() { + result.hasNamespace = false; + result.namespace_ = ""; + return this; + } + + public bool HasUmbrellaClassname { + get { return result.HasUmbrellaClassname; } + } + public string UmbrellaClassname { + get { return result.UmbrellaClassname; } + set { SetUmbrellaClassname(value); } + } + public Builder SetUmbrellaClassname(string value) { + result.hasUmbrellaClassname = true; + result.umbrellaClassname_ = value; + return this; + } + public Builder ClearUmbrellaClassname() { + result.hasUmbrellaClassname = false; + result.umbrellaClassname_ = ""; + return this; + } + + public bool HasPublicClasses { + get { return result.HasPublicClasses; } + } + public bool PublicClasses { + get { return result.PublicClasses; } + set { SetPublicClasses(value); } + } + public Builder SetPublicClasses(bool value) { + result.hasPublicClasses = true; + result.publicClasses_ = value; + return this; + } + public Builder ClearPublicClasses() { + result.hasPublicClasses = false; + result.publicClasses_ = false; + return this; + } + + public bool HasMultipleFiles { + get { return result.HasMultipleFiles; } + } + public bool MultipleFiles { + get { return result.MultipleFiles; } + set { SetMultipleFiles(value); } + } + public Builder SetMultipleFiles(bool value) { + result.hasMultipleFiles = true; + result.multipleFiles_ = value; + return this; + } + public Builder ClearMultipleFiles() { + result.hasMultipleFiles = false; + result.multipleFiles_ = false; + return this; + } + + public bool HasNestClasses { + get { return result.HasNestClasses; } + } + public bool NestClasses { + get { return result.NestClasses; } + set { SetNestClasses(value); } + } + public Builder SetNestClasses(bool value) { + result.hasNestClasses = true; + result.nestClasses_ = value; + return this; + } + public Builder ClearNestClasses() { + result.hasNestClasses = false; + result.nestClasses_ = false; + return this; + } + } + } + + public sealed partial class CSharpFieldOptions : pb::GeneratedMessage { + private static readonly CSharpFieldOptions defaultInstance = new Builder().BuildPartial(); + public static CSharpFieldOptions DefaultInstance { + get { return defaultInstance; } + } + + public override CSharpFieldOptions DefaultInstanceForType { + get { return defaultInstance; } + } + + protected override CSharpFieldOptions ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFieldOptions__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFieldOptions__FieldAccessorTable; } + } + + public static readonly pb::GeneratedExtensionBase CSharpOptions = + pb::GeneratedSingleExtension.CreateInstance(Descriptor.Extensions[0]); + private bool hasPropertyName; + private string propertyName_ = ""; + public bool HasPropertyName { + get { return hasPropertyName; } + } + public string PropertyName { + get { return propertyName_; } + } + + public static CSharpFieldOptions ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(pb::CodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static CSharpFieldOptions ParseFrom(pb::CodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static Builder CreateBuilder() { return new Builder(); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(CSharpFieldOptions prototype) { + return (Builder) new Builder().MergeFrom(prototype); + } + + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() {} + + CSharpFieldOptions result = new CSharpFieldOptions(); + + protected override CSharpFieldOptions MessageBeingBuilt { + get { return result; } + } + + public override Builder Clear() { + result = new CSharpFieldOptions(); + return this; + } + + public override Builder Clone() { + return new Builder().MergeFrom(result); + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return CSharpFieldOptions.Descriptor; } + } + + public override CSharpFieldOptions DefaultInstanceForType { + get { return CSharpFieldOptions.DefaultInstance; } + } + + public override CSharpFieldOptions BuildPartial() { + CSharpFieldOptions returnMe = result; + result = null; + return returnMe; + } + + + public bool HasPropertyName { + get { return result.HasPropertyName; } + } + public string PropertyName { + get { return result.PropertyName; } + set { SetPropertyName(value); } + } + public Builder SetPropertyName(string value) { + result.hasPropertyName = true; + result.propertyName_ = value; + return this; + } + public Builder ClearPropertyName() { + result.hasPropertyName = false; + result.propertyName_ = ""; + return this; + } + } + } + + #endregion + } diff --git a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs index ebb6b159..79e034a1 100644 --- a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs +++ b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs @@ -50,6 +50,8 @@ namespace Google.ProtocolBuffers.Descriptors { private readonly IList extensions; private readonly IList dependencies; private readonly DescriptorPool pool; + private CSharpFileOptions csharpFileOptions; + private readonly object optionsLock = new object(); private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool) { this.pool = pool; @@ -71,6 +73,44 @@ namespace Google.ProtocolBuffers.Descriptors { (field, index) => new FieldDescriptor(field, this, null, index, true)); } + private CSharpFileOptions BuildOrFakeCSharpOptions() { + // TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues + if (proto.Name == "google/protobuf/descriptor.proto") { + return new CSharpFileOptions.Builder { + Namespace = "Google.ProtocolBuffers.DescriptorProtos", + UmbrellaClassname = "DescriptorProtoFile", NestClasses = false, MultipleFiles = false, PublicClasses = true + }.Build(); + } + if (proto.Name == "google/protobuf/csharp_options.proto") { + return new CSharpFileOptions.Builder { + Namespace = "Google.ProtocolBuffers.DescriptorProtos", + UmbrellaClassname = "CSharpOptions", NestClasses = false, MultipleFiles = false, PublicClasses = true + }.Build(); + } + CSharpFileOptions.Builder builder = CSharpFileOptions.CreateBuilder(); + if (proto.Options.HasExtension(CSharpFileOptions.CSharpOptions)) { + builder.MergeFrom(proto.Options.GetExtension(CSharpFileOptions.CSharpOptions)); + } + if (!builder.HasNamespace) { + builder.Namespace = Package; + } + if (!builder.HasMultipleFiles) { + builder.MultipleFiles = false; + } + if (!builder.HasNestClasses) { + builder.NestClasses = false; + } + if (!builder.HasPublicClasses) { + builder.PublicClasses = true; + } + if (!builder.HasUmbrellaClassname) { + int lastSlash = Name.LastIndexOf('/'); + string baseName = Name.Substring(lastSlash + 1); + builder.UmbrellaClassname = NameHelpers.UnderscoresToPascalCase(NameHelpers.StripProto(baseName)); + } + return builder.Build(); + } + /// /// The descriptor in its protocol message representation. /// @@ -85,6 +125,22 @@ namespace Google.ProtocolBuffers.Descriptors { get { return proto.Options; } } + /// + /// Returns the C#-specific options for this file descriptor. This will always be + /// completely filled in. + /// FIXME: This isn't thread-safe. Can't do it at construction time due to bootstrapping issues. + /// + public CSharpFileOptions CSharpOptions { + get { + lock (optionsLock) { + if (csharpFileOptions == null) { + csharpFileOptions = BuildOrFakeCSharpOptions(); + } + } + return csharpFileOptions; + } + } + /// /// The file name. /// @@ -250,7 +306,7 @@ namespace Google.ProtocolBuffers.Descriptors { /// /// This method is to be called by generated code only. It is equivalent - /// to BuilderFrom except that the FileDescriptorProto is encoded in + /// to BuildFrom except that the FileDescriptorProto is encoded in /// protocol buffer wire format. /// public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData, diff --git a/src/ProtocolBuffers/NameHelpers.cs b/src/ProtocolBuffers/NameHelpers.cs new file mode 100644 index 00000000..8b297f95 --- /dev/null +++ b/src/ProtocolBuffers/NameHelpers.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Google.ProtocolBuffers { + /// + /// Helpers for converting names to pascal case etc. + /// + internal class NameHelpers { + + internal static string UnderscoresToPascalCase(string input) { + return UnderscoresToPascalOrCamelCase(input, true); + } + + internal static string UnderscoresToCamelCase(string input) { + return UnderscoresToPascalOrCamelCase(input, false); + } + + /// + /// Converts a string to Pascal or Camel case. The first letter is capitalized or + /// lower-cased depending on is true. + /// After the first letter, any punctuation is removed but triggers capitalization + /// of the next letter. Digits are preserved but trigger capitalization of the next + /// letter. + /// All capitalisation is done in the invariant culture. + /// + private static string UnderscoresToPascalOrCamelCase(string input, bool pascal) { + StringBuilder result = new StringBuilder(); + bool capitaliseNext = pascal; + for (int i = 0; i < input.Length; i++) { + char c = input[i]; + if ('a' <= c && c <= 'z') { + if (capitaliseNext) { + result.Append(char.ToUpperInvariant(c)); + } else { + result.Append(c); + } + capitaliseNext = false; + } else if ('A' <= c && c <= 'Z') { + if (i == 0 && !pascal) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result.Append(char.ToLowerInvariant(c)); + } else { + // Capital letters after the first are left as-is. + result.Append(c); + } + capitaliseNext = false; + } else if ('0' <= c && c <= '9') { + result.Append(c); + capitaliseNext = true; + } else { + capitaliseNext = true; + } + } + return result.ToString(); + } + + internal static string StripProto(string text) { + if (!StripSuffix(ref text, ".protodevel")) { + StripSuffix(ref text, ".proto"); + } + return text; + } + + /// + /// Attempts to strip a suffix from a string, returning whether + /// or not the suffix was actually present. + /// + internal static bool StripSuffix(ref string text, string suffix) { + if (text.EndsWith(suffix)) { + text = text.Substring(0, text.Length - suffix.Length); + return true; + } + return false; + } + } +} diff --git a/src/ProtocolBuffers/ProtocolBuffers.csproj b/src/ProtocolBuffers/ProtocolBuffers.csproj index 3f76aa7f..6a746cc9 100644 --- a/src/ProtocolBuffers/ProtocolBuffers.csproj +++ b/src/ProtocolBuffers/ProtocolBuffers.csproj @@ -97,6 +97,7 @@ + diff --git a/todo.txt b/todo.txt index 71961558..41b33eec 100644 --- a/todo.txt +++ b/todo.txt @@ -1,12 +1,11 @@ Current task list (not in order) -- Extra unit tests for pending Java optimisation +Diff stuff + - Refactor IsInitialized - Performance framework - Optionally remove dependencies to core and csharp options - Remove multifile support -- Remove bootstrapping hack -- Improve "regenerating descriptor.proto" hack - Mono support - Docs - Clean up protogen code