From 1711999078ca1d435de3958bf963e95a742e972f Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 30 Aug 2018 14:53:06 +0100 Subject: [PATCH] Provide simple access to descriptor declarations in C# This is primarily for access to comments, which would be expected to be available in a protoc plugin. The implementation has two fiddly aspects: - We use a Lazy to avoid building the map before cross-linking. An alternative would be to crosslink at the end of the constructor, and remove the calls to CrossLink elsewhere. This would be generally better IMO, but deviate from the Java code. - The casts to IReadOnlyList are unfortunate. They'll always work, because these lists are always ReadOnlyCollection for a descriptor type... but we can't use IList as that's not covariant, and it's annoyingly fiddly to change the field to be of type ReadOnlyCollection. --- csharp/generate_protos.sh | 3 + csharp/protos/unittest_proto3.proto | 30 ++ .../Google.Protobuf.Test.csproj | 4 + .../Reflection/DescriptorDeclarationTest.cs | 151 ++++++++ .../TestProtos/UnittestProto3.cs | 333 +++++++++++++++++- csharp/src/Google.Protobuf.Test/testprotos.pb | Bin 0 -> 204268 bytes .../Reflection/DescriptorBase.cs | 45 ++- .../Reflection/DescriptorDeclaration.cs | 106 ++++++ .../Reflection/EnumDescriptor.cs | 11 + .../Reflection/FileDescriptor.cs | 80 +++++ .../Reflection/MessageDescriptor.cs | 15 + .../Reflection/ServiceDescriptor.cs | 12 + 12 files changed, 755 insertions(+), 35 deletions(-) create mode 100644 csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs create mode 100644 csharp/src/Google.Protobuf.Test/testprotos.pb create mode 100644 csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh index 5c748e35cf..31a4b90cc4 100755 --- a/csharp/generate_protos.sh +++ b/csharp/generate_protos.sh @@ -43,6 +43,9 @@ $PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf \ # Test protos $PROTOC -Isrc -Icsharp/protos \ --csharp_out=csharp/src/Google.Protobuf.Test/TestProtos \ + --descriptor_set_out=csharp/src/Google.Protobuf.Test/testprotos.pb \ + --include_source_info \ + --include_imports \ csharp/protos/map_unittest_proto3.proto \ csharp/protos/unittest_issues.proto \ csharp/protos/unittest_custom_options_proto3.proto \ diff --git a/csharp/protos/unittest_proto3.proto b/csharp/protos/unittest_proto3.proto index ef4933a509..bf88f6bcb4 100644 --- a/csharp/protos/unittest_proto3.proto +++ b/csharp/protos/unittest_proto3.proto @@ -368,7 +368,9 @@ message FooResponse {} message FooClientMessage {} message FooServerMessage{} +// This is a test service service TestService { + // This is a test method rpc Foo(FooRequest) returns (FooResponse); rpc Bar(BarRequest) returns (BarResponse); } @@ -378,3 +380,31 @@ message BarRequest {} message BarResponse {} message TestEmptyMessage {} + +// This is leading detached comment 1 + +// This is leading detached comment 2 + +// This is a leading comment +message CommentMessage { + // Leading nested message comment + message NestedCommentMessage { + // Leading nested message field comment + string nested_text = 1; + } + + // Leading nested enum comment + enum NestedCommentEnum { + // Zero value comment + ZERO_VALUE = 0; + } + + // Leading field comment + string text = 1; // Trailing field comment +} + +// Leading enum comment +enum CommentEnum { + // Zero value comment + ZERO_VALUE = 0; +} diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj index 6a430116be..f286e0aaa9 100644 --- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj +++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj @@ -27,4 +27,8 @@ netcoreapp1.0 + + + + diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs new file mode 100644 index 0000000000..b3237455d7 --- /dev/null +++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs @@ -0,0 +1,151 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2018 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using Google.Protobuf.Reflection; +using NUnit.Framework; +using System.Linq; +using System.Reflection; + +namespace Google.Protobuf.Test.Reflection +{ + // In reality this isn't a test for DescriptorDeclaration so much as the way they're loaded. + public class DescriptorDeclarationTest + { + static readonly FileDescriptor unitTestProto3Descriptor = LoadProtos(); + + [Test] + public void ServiceComments() + { + var service = unitTestProto3Descriptor.FindTypeByName("TestService"); + Assert.NotNull(service.Declaration); + Assert.AreEqual(" This is a test service\n", service.Declaration.LeadingComments); + } + + [Test] + public void MethodComments() + { + var service = unitTestProto3Descriptor.FindTypeByName("TestService"); + var method = service.FindMethodByName("Foo"); + Assert.NotNull(method.Declaration); + Assert.AreEqual(" This is a test method\n", method.Declaration.LeadingComments); + } + + [Test] + public void MessageComments() + { + var message = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + Assert.NotNull(message.Declaration); + Assert.AreEqual(" This is a leading comment\n", message.Declaration.LeadingComments); + Assert.AreEqual(new[] { " This is leading detached comment 1\n", " This is leading detached comment 2\n" }, + message.Declaration.LeadingDetachedComments); + } + + [Test] + public void EnumComments() + { + var descriptor = unitTestProto3Descriptor.FindTypeByName("CommentEnum"); + Assert.NotNull(descriptor.Declaration); + Assert.AreEqual(" Leading enum comment\n", descriptor.Declaration.LeadingComments); + } + + [Test] + public void NestedMessageComments() + { + var outer = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + var nested = outer.FindDescriptor("NestedCommentMessage"); + Assert.NotNull(nested.Declaration); + Assert.AreEqual(" Leading nested message comment\n", nested.Declaration.LeadingComments); + } + + [Test] + public void NestedEnumComments() + { + var outer = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + var nested = outer.FindDescriptor("NestedCommentEnum"); + Assert.NotNull(nested.Declaration); + Assert.AreEqual(" Leading nested enum comment\n", nested.Declaration.LeadingComments); + } + + [Test] + public void FieldComments() + { + var message = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + var field = message.FindFieldByName("text"); + Assert.NotNull(field.Declaration); + Assert.AreEqual(" Leading field comment\n", field.Declaration.LeadingComments); + Assert.AreEqual(" Trailing field comment\n", field.Declaration.TrailingComments); + } + + [Test] + public void NestedMessageFieldComments() + { + var outer = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + var nested = outer.FindDescriptor("NestedCommentMessage"); + var field = nested.FindFieldByName("nested_text"); + Assert.NotNull(field.Declaration); + Assert.AreEqual(" Leading nested message field comment\n", field.Declaration.LeadingComments); + } + + [Test] + public void EnumValueComments() + { + var enumDescriptor = unitTestProto3Descriptor.FindTypeByName("CommentEnum"); + var value = enumDescriptor.FindValueByName("ZERO_VALUE"); + Assert.NotNull(value.Declaration); + Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments); + } + + [Test] + public void NestedEnumValueComments() + { + var outer = unitTestProto3Descriptor.FindTypeByName("CommentMessage"); + var nested = outer.FindDescriptor("NestedCommentEnum"); + var value = nested.FindValueByName("ZERO_VALUE"); + Assert.NotNull(value.Declaration); + Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments); + } + + private static FileDescriptor LoadProtos() + { + var type = typeof(DescriptorDeclarationTest); + // TODO: Make this simpler :) + FileDescriptorSet descriptorSet; + using (var stream = type.GetTypeInfo().Assembly.GetManifestResourceStream($"Google.Protobuf.Test.testprotos.pb")) + { + descriptorSet = FileDescriptorSet.Parser.ParseFrom(stream); + } + var byteStrings = descriptorSet.File.Select(f => f.ToByteString()).ToList(); + var descriptors = FileDescriptor.BuildFromByteStrings(byteStrings); + return descriptors.Single(d => d.Name == "unittest_proto3.proto"); + } + } +} diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs index d5dbe866df..0422153660 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs @@ -139,23 +139,26 @@ namespace Google.Protobuf.TestProtos { "NBj//w8gAygEIigKG1Rlc3RDb21tZW50SW5qZWN0aW9uTWVzc2FnZRIJCgFh", "GAEgASgJIgwKCkZvb1JlcXVlc3QiDQoLRm9vUmVzcG9uc2UiEgoQRm9vQ2xp", "ZW50TWVzc2FnZSISChBGb29TZXJ2ZXJNZXNzYWdlIgwKCkJhclJlcXVlc3Qi", - "DQoLQmFyUmVzcG9uc2UiEgoQVGVzdEVtcHR5TWVzc2FnZSpZCgtGb3JlaWdu", - "RW51bRIXChNGT1JFSUdOX1VOU1BFQ0lGSUVEEAASDwoLRk9SRUlHTl9GT08Q", - "BBIPCgtGT1JFSUdOX0JBUhAFEg8KC0ZPUkVJR05fQkFaEAYqdQoUVGVzdEVu", - "dW1XaXRoRHVwVmFsdWUSKAokVEVTVF9FTlVNX1dJVEhfRFVQX1ZBTFVFX1VO", - "U1BFQ0lGSUVEEAASCAoERk9PMRABEggKBEJBUjEQAhIHCgNCQVoQAxIICgRG", - "T08yEAESCAoEQkFSMhACGgIQASqdAQoOVGVzdFNwYXJzZUVudW0SIAocVEVT", - "VF9TUEFSU0VfRU5VTV9VTlNQRUNJRklFRBAAEgwKCFNQQVJTRV9BEHsSDgoI", - "U1BBUlNFX0IQpucDEg8KCFNQQVJTRV9DELKxgAYSFQoIU1BBUlNFX0QQ8f//", - "////////ARIVCghTUEFSU0VfRRC03vz///////8BEgwKCFNQQVJTRV9HEAIy", - "nQEKC1Rlc3RTZXJ2aWNlEkYKA0ZvbxIeLnByb3RvYnVmX3VuaXR0ZXN0My5G", - "b29SZXF1ZXN0Gh8ucHJvdG9idWZfdW5pdHRlc3QzLkZvb1Jlc3BvbnNlEkYK", - "A0JhchIeLnByb3RvYnVmX3VuaXR0ZXN0My5CYXJSZXF1ZXN0Gh8ucHJvdG9i", - "dWZfdW5pdHRlc3QzLkJhclJlc3BvbnNlQixCDVVuaXR0ZXN0UHJvdG+qAhpH", - "b29nbGUuUHJvdG9idWYuVGVzdFByb3Rvc2IGcHJvdG8z")); + "DQoLQmFyUmVzcG9uc2UiEgoQVGVzdEVtcHR5TWVzc2FnZSJwCg5Db21tZW50", + "TWVzc2FnZRIMCgR0ZXh0GAEgASgJGisKFE5lc3RlZENvbW1lbnRNZXNzYWdl", + "EhMKC25lc3RlZF90ZXh0GAEgASgJIiMKEU5lc3RlZENvbW1lbnRFbnVtEg4K", + "ClpFUk9fVkFMVUUQACpZCgtGb3JlaWduRW51bRIXChNGT1JFSUdOX1VOU1BF", + "Q0lGSUVEEAASDwoLRk9SRUlHTl9GT08QBBIPCgtGT1JFSUdOX0JBUhAFEg8K", + "C0ZPUkVJR05fQkFaEAYqdQoUVGVzdEVudW1XaXRoRHVwVmFsdWUSKAokVEVT", + "VF9FTlVNX1dJVEhfRFVQX1ZBTFVFX1VOU1BFQ0lGSUVEEAASCAoERk9PMRAB", + "EggKBEJBUjEQAhIHCgNCQVoQAxIICgRGT08yEAESCAoEQkFSMhACGgIQASqd", + "AQoOVGVzdFNwYXJzZUVudW0SIAocVEVTVF9TUEFSU0VfRU5VTV9VTlNQRUNJ", + "RklFRBAAEgwKCFNQQVJTRV9BEHsSDgoIU1BBUlNFX0IQpucDEg8KCFNQQVJT", + "RV9DELKxgAYSFQoIU1BBUlNFX0QQ8f//////////ARIVCghTUEFSU0VfRRC0", + "3vz///////8BEgwKCFNQQVJTRV9HEAIqHQoLQ29tbWVudEVudW0SDgoKWkVS", + "T19WQUxVRRAAMp0BCgtUZXN0U2VydmljZRJGCgNGb28SHi5wcm90b2J1Zl91", + "bml0dGVzdDMuRm9vUmVxdWVzdBofLnByb3RvYnVmX3VuaXR0ZXN0My5Gb29S", + "ZXNwb25zZRJGCgNCYXISHi5wcm90b2J1Zl91bml0dGVzdDMuQmFyUmVxdWVz", + "dBofLnByb3RvYnVmX3VuaXR0ZXN0My5CYXJSZXNwb25zZUIsQg1Vbml0dGVz", + "dFByb3RvqgIaR29vZ2xlLlByb3RvYnVmLlRlc3RQcm90b3NiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Google.Protobuf.TestProtos.UnittestImportProto3Reflection.Descriptor, }, - new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), }, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.TestProtos.ForeignEnum), typeof(global::Google.Protobuf.TestProtos.TestEnumWithDupValue), typeof(global::Google.Protobuf.TestProtos.TestSparseEnum), typeof(global::Google.Protobuf.TestProtos.CommentEnum), }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes), global::Google.Protobuf.TestProtos.TestAllTypes.Parser, new[]{ "SingleInt32", "SingleInt64", "SingleUint32", "SingleUint64", "SingleSint32", "SingleSint64", "SingleFixed32", "SingleFixed64", "SingleSfixed32", "SingleSfixed64", "SingleFloat", "SingleDouble", "SingleBool", "SingleString", "SingleBytes", "SingleNestedMessage", "SingleForeignMessage", "SingleImportMessage", "SingleNestedEnum", "SingleForeignEnum", "SingleImportEnum", "SinglePublicImportMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedImportMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedImportEnum", "RepeatedPublicImportMessage", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes" }, new[]{ "OneofField" }, new[]{ typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage), global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedMessage.Parser, new[]{ "Bb" }, null, null, null)}), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.NestedTestAllTypes), global::Google.Protobuf.TestProtos.NestedTestAllTypes.Parser, new[]{ "Child", "Payload", "RepeatedChild" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestDeprecatedFields), global::Google.Protobuf.TestProtos.TestDeprecatedFields.Parser, new[]{ "DeprecatedInt32" }, null, null, null), @@ -190,7 +193,8 @@ namespace Google.Protobuf.TestProtos { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.FooServerMessage), global::Google.Protobuf.TestProtos.FooServerMessage.Parser, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarRequest), global::Google.Protobuf.TestProtos.BarRequest.Parser, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.BarResponse), global::Google.Protobuf.TestProtos.BarResponse.Parser, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestEmptyMessage), global::Google.Protobuf.TestProtos.TestEmptyMessage.Parser, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.TestEmptyMessage), global::Google.Protobuf.TestProtos.TestEmptyMessage.Parser, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.CommentMessage), global::Google.Protobuf.TestProtos.CommentMessage.Parser, new[]{ "Text" }, null, new[]{ typeof(global::Google.Protobuf.TestProtos.CommentMessage.Types.NestedCommentEnum) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.TestProtos.CommentMessage.Types.NestedCommentMessage), global::Google.Protobuf.TestProtos.CommentMessage.Types.NestedCommentMessage.Parser, new[]{ "NestedText" }, null, null, null)}) })); } #endregion @@ -233,6 +237,16 @@ namespace Google.Protobuf.TestProtos { [pbr::OriginalName("SPARSE_G")] SparseG = 2, } + /// + /// Leading enum comment + /// + public enum CommentEnum { + /// + /// Zero value comment + /// + [pbr::OriginalName("ZERO_VALUE")] ZeroValue = 0, + } + #endregion #region Messages @@ -7301,6 +7315,293 @@ namespace Google.Protobuf.TestProtos { } + /// + /// This is a leading comment + /// + public sealed partial class CommentMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CommentMessage()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Protobuf.TestProtos.UnittestProto3Reflection.Descriptor.MessageTypes[35]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CommentMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CommentMessage(CommentMessage other) : this() { + text_ = other.text_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CommentMessage Clone() { + return new CommentMessage(this); + } + + /// Field number for the "text" field. + public const int TextFieldNumber = 1; + private string text_ = ""; + /// + /// Leading field comment + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Text { + get { return text_; } + set { + text_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CommentMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CommentMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Text != other.Text) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Text.Length != 0) hash ^= Text.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Text.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Text); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Text.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Text); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CommentMessage other) { + if (other == null) { + return; + } + if (other.Text.Length != 0) { + Text = other.Text; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Text = input.ReadString(); + break; + } + } + } + } + + #region Nested types + /// Container for nested types declared in the CommentMessage message type. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static partial class Types { + /// + /// Leading nested enum comment + /// + public enum NestedCommentEnum { + /// + /// Zero value comment + /// + [pbr::OriginalName("ZERO_VALUE")] ZeroValue = 0, + } + + /// + /// Leading nested message comment + /// + public sealed partial class NestedCommentMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NestedCommentMessage()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Google.Protobuf.TestProtos.CommentMessage.Descriptor.NestedTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NestedCommentMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NestedCommentMessage(NestedCommentMessage other) : this() { + nestedText_ = other.nestedText_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NestedCommentMessage Clone() { + return new NestedCommentMessage(this); + } + + /// Field number for the "nested_text" field. + public const int NestedTextFieldNumber = 1; + private string nestedText_ = ""; + /// + /// Leading nested message field comment + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NestedText { + get { return nestedText_; } + set { + nestedText_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NestedCommentMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NestedCommentMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NestedText != other.NestedText) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NestedText.Length != 0) hash ^= NestedText.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (NestedText.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NestedText); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NestedText.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NestedText); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NestedCommentMessage other) { + if (other == null) { + return; + } + if (other.NestedText.Length != 0) { + NestedText = other.NestedText; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + NestedText = input.ReadString(); + break; + } + } + } + } + + } + + } + #endregion + + } + #endregion } diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb new file mode 100644 index 0000000000000000000000000000000000000000..94ff381705adf502343e9f07e16d4719499e81dd GIT binary patch literal 204268 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 literal 0 HcmV?d00001 diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs index 194041a889..bfbebf176c 100644 --- a/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs +++ b/csharp/src/Google.Protobuf/Reflection/DescriptorBase.cs @@ -30,6 +30,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion +using System.Collections.Generic; + namespace Google.Protobuf.Reflection { /// @@ -37,15 +39,11 @@ namespace Google.Protobuf.Reflection /// public abstract class DescriptorBase : IDescriptor { - private readonly FileDescriptor file; - private readonly string fullName; - private readonly int index; - internal DescriptorBase(FileDescriptor file, string fullName, int index) { - this.file = file; - this.fullName = fullName; - this.index = index; + File = file; + FullName = fullName; + Index = index; } /// @@ -56,10 +54,7 @@ namespace Google.Protobuf.Reflection /// this descriptor's type. (There can be duplicate values for different /// types, e.g. one enum type with index 0 and one message type with index 0.) /// - public int Index - { - get { return index; } - } + public int Index { get; } /// /// Returns the name of the entity (field, message etc) being described. @@ -69,17 +64,29 @@ namespace Google.Protobuf.Reflection /// /// The fully qualified name of the descriptor's target. /// - public string FullName - { - get { return fullName; } - } + public string FullName { get; } /// /// The file this descriptor was declared in. /// - public FileDescriptor File - { - get { return file; } - } + public FileDescriptor File { get; } + + /// + /// The declaration information about the descriptor, or null if no declaration information + /// is available for this descriptor. + /// + /// + /// This information is typically only available for dynamically loaded descriptors, + /// for example within a protoc plugin where the full descriptors, including source info, + /// are passed to the code by protoc. + /// + public DescriptorDeclaration Declaration => File.GetDeclaration(this); + + /// + /// Retrieves the list of nested descriptors corresponding to the given field number, if any. + /// If the field is unknown or not a nested descriptor list, return null to terminate the search. + /// The default implementation returns null. + /// + internal virtual IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) => null; } } \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs new file mode 100644 index 0000000000..613d654524 --- /dev/null +++ b/csharp/src/Google.Protobuf/Reflection/DescriptorDeclaration.cs @@ -0,0 +1,106 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2018 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#endregion + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using static Google.Protobuf.Reflection.SourceCodeInfo.Types; + +namespace Google.Protobuf.Reflection +{ + /// + /// Provides additional information about the declaration of a descriptor, + /// such as source location and comments. + /// + public sealed class DescriptorDeclaration + { + /// + /// The descriptor this declaration relates to. + /// + public IDescriptor Descriptor { get; } + + /// + /// The start line of the declaration within the source file. This value is 1-based. + /// + public int StartLine { get; } + /// + /// The start column of the declaration within the source file. This value is 1-based. + /// + public int StartColumn { get; } + + /// + /// // The end line of the declaration within the source file. This value is 1-based. + /// + public int EndLine { get; } + /// + /// The end column of the declaration within the source file. This value is 1-based. + /// + public int EndColumn { get; } + + /// + /// Comments appearing before the declaration. Never null, but may be empty. + /// + public string LeadingComments { get; } + + /// + /// Comments appearing after the declaration. Never null, but may be empty. + /// + public string TrailingComments { get; } + + /// + /// Comments appearing before the declaration, but separated from it by blank + /// lines. Each string represents a paragraph of comments. The list is never null, + /// but may be empty. Likewise each element is never null, but may be empty. + /// + public IReadOnlyList LeadingDetachedComments { get; } + + private DescriptorDeclaration(IDescriptor descriptor, Location location) + { + // TODO: Validation + Descriptor = descriptor; + bool hasEndLine = location.Span.Count == 4; + // Lines and columns are 0-based in the proto. + StartLine = location.Span[0] + 1; + StartColumn = location.Span[1] + 1; + EndLine = hasEndLine ? location.Span[2] + 1 : StartLine; + EndColumn = location.Span[hasEndLine ? 3 : 2] + 1; + LeadingComments = location.LeadingComments; + TrailingComments = location.TrailingComments; + LeadingDetachedComments = new ReadOnlyCollection(location.LeadingDetachedComments.ToList()); + } + + internal static DescriptorDeclaration FromProto(IDescriptor descriptor, Location location) => + new DescriptorDeclaration(descriptor, location); + } +} diff --git a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs index 89c73a61b2..4c5457a70c 100644 --- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs @@ -72,6 +72,17 @@ namespace Google.Protobuf.Reflection /// public override string Name { get { return proto.Name; } } + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + { + switch (fieldNumber) + { + case EnumDescriptorProto.ValueFieldNumber: + return (IReadOnlyList) Values; + default: + return null; + } + } + /// /// The CLR type for this enum. For generated code, this will be a CLR enum type. /// diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs index 216e03cc2d..6d4520c0bc 100644 --- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs @@ -34,7 +34,10 @@ using Google.Protobuf.WellKnownTypes; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; +using System.Threading; +using static Google.Protobuf.Reflection.SourceCodeInfo.Types; namespace Google.Protobuf.Reflection { @@ -55,6 +58,8 @@ namespace Google.Protobuf.Reflection ForceReflectionInitialization(); } + private readonly Lazy> declarations; + private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, IEnumerable dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo) { SerializedData = descriptorData; @@ -77,6 +82,81 @@ namespace Google.Protobuf.Reflection Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service, (service, index) => new ServiceDescriptor(service, this, index)); + + declarations = new Lazy>(CreateDeclarationMap, LazyThreadSafetyMode.ExecutionAndPublication); + } + + private Dictionary CreateDeclarationMap() + { + var dictionary = new Dictionary(); + foreach (var location in Proto.SourceCodeInfo?.Location ?? Enumerable.Empty()) + { + var descriptor = FindDescriptorForPath(location.Path); + if (descriptor != null) + { + dictionary[descriptor] = DescriptorDeclaration.FromProto(descriptor, location); + } + } + return dictionary; + + IDescriptor FindDescriptorForPath(IList path) + { + // All complete declarations have an even, non-empty path length + // (There can be an empty path for a descriptor declaration, but that can't have any comments, + // so we currently ignore it.) + if (path.Count == 0 || (path.Count & 1) != 0) + { + return null; + } + IReadOnlyList topLevelList = GetNestedDescriptorListForField(path[0]); + DescriptorBase current = GetDescriptorFromList(topLevelList, path[1]); + + for (int i = 2; current != null && i < path.Count; i += 2) + { + var list = current.GetNestedDescriptorListForField(path[i]); + current = GetDescriptorFromList(list, path[i + 1]); + } + return current; + } + + DescriptorBase GetDescriptorFromList(IReadOnlyList list, int index) + { + // This is fine: it may be a newer version of protobuf than we understand, with a new descriptor + // field. + if (list == null) + { + return null; + } + // We *could* return null to silently continue, but this is basically data corruption. + if (index < 0 || index >= list.Count) + { + // We don't have much extra information to give at this point unfortunately. If this becomes a problem, + // we can pass in the complete path and report that and the file name. + throw new InvalidProtocolBufferException($"Invalid descriptor location path: index out of range"); + } + return list[index]; + } + + IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + { + switch (fieldNumber) + { + case FileDescriptorProto.ServiceFieldNumber: + return (IReadOnlyList) Services; + case FileDescriptorProto.MessageTypeFieldNumber: + return (IReadOnlyList) MessageTypes; + case FileDescriptorProto.EnumTypeFieldNumber: + return (IReadOnlyList) EnumTypes; + default: + return null; + } + } + } + + internal DescriptorDeclaration GetDeclaration(IDescriptor descriptor) + { + declarations.Value.TryGetValue(descriptor, out var declaration); + return declaration; } /// diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs index dbb6768b6a..03fd63ce29 100644 --- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs @@ -115,6 +115,21 @@ namespace Google.Protobuf.Reflection /// public override string Name => Proto.Name; + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + { + switch (fieldNumber) + { + case DescriptorProto.FieldFieldNumber: + return (IReadOnlyList) fieldsInDeclarationOrder; + case DescriptorProto.NestedTypeFieldNumber: + return (IReadOnlyList) NestedTypes; + case DescriptorProto.EnumTypeFieldNumber: + return (IReadOnlyList) EnumTypes; + default: + return null; + } + } + internal DescriptorProto Proto { get; } /// diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs index fe5c072c8e..da57055118 100644 --- a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; namespace Google.Protobuf.Reflection { @@ -58,6 +59,17 @@ namespace Google.Protobuf.Reflection /// public override string Name { get { return proto.Name; } } + internal override IReadOnlyList GetNestedDescriptorListForField(int fieldNumber) + { + switch (fieldNumber) + { + case ServiceDescriptorProto.MethodFieldNumber: + return (IReadOnlyList) methods; + default: + return null; + } + } + internal ServiceDescriptorProto Proto { get { return proto; } } ///