Эх сурвалжийг харах

Fix descriptor reflection in various ways

- The protos are no longer publicly exposed at all
- Oneof detection now works (as we default to -1, not 0)
- OneofDescriptor exposes the fields in the oneof
- Removed unnecessary code for replacing protos - remnant of extensions
- There's now just the non-generic form of IDescriptor
Jon Skeet 10 жил өмнө
parent
commit
af259b77bf

+ 28 - 4
csharp/src/ProtocolBuffers.Test/DescriptorsTest.cs

@@ -30,6 +30,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 #endregion
 
 
+using System.Linq;
+using Google.Protobuf.DescriptorProtos;
 using Google.Protobuf.Descriptors;
 using Google.Protobuf.Descriptors;
 using Google.Protobuf.TestProtos;
 using Google.Protobuf.TestProtos;
 using NUnit.Framework;
 using NUnit.Framework;
@@ -50,7 +52,7 @@ namespace Google.Protobuf
             Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Name);
             Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Name);
             Assert.AreEqual("protobuf_unittest", file.Package);
             Assert.AreEqual("protobuf_unittest", file.Package);
 
 
-            Assert.AreEqual("UnittestProto", file.Options.JavaOuterClassname);
+            Assert.AreEqual("UnittestProto", file.Proto.Options.JavaOuterClassname);
             Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Proto.Name);
             Assert.AreEqual("google/protobuf/unittest_proto3.proto", file.Proto.Name);
 
 
             // unittest.proto doesn't have any public imports, but unittest_import.proto does.
             // unittest.proto doesn't have any public imports, but unittest_import.proto does.
@@ -92,7 +94,7 @@ namespace Google.Protobuf
             Assert.AreEqual("protobuf_unittest.TestAllTypes", messageType.FullName);
             Assert.AreEqual("protobuf_unittest.TestAllTypes", messageType.FullName);
             Assert.AreEqual(UnittestProto3.Descriptor, messageType.File);
             Assert.AreEqual(UnittestProto3.Descriptor, messageType.File);
             Assert.IsNull(messageType.ContainingType);
             Assert.IsNull(messageType.ContainingType);
-            Assert.IsNull(messageType.Options);
+            Assert.IsNull(messageType.Proto.Options);
 
 
             Assert.AreEqual("TestAllTypes", messageType.Name);
             Assert.AreEqual("TestAllTypes", messageType.Name);
 
 
@@ -143,7 +145,7 @@ namespace Google.Protobuf
             Assert.AreEqual(messageType, primitiveField.ContainingType);
             Assert.AreEqual(messageType, primitiveField.ContainingType);
             Assert.AreEqual(UnittestProto3.Descriptor, primitiveField.File);
             Assert.AreEqual(UnittestProto3.Descriptor, primitiveField.File);
             Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
             Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
-            Assert.IsNull(primitiveField.Options);
+            Assert.IsNull(primitiveField.Proto.Options);
             
             
             Assert.AreEqual("single_nested_enum", enumField.Name);
             Assert.AreEqual("single_nested_enum", enumField.Name);
             Assert.AreEqual(FieldType.Enum, enumField.FieldType);
             Assert.AreEqual(FieldType.Enum, enumField.FieldType);
@@ -177,7 +179,7 @@ namespace Google.Protobuf
             Assert.AreEqual("protobuf_unittest.ForeignEnum", enumType.FullName);
             Assert.AreEqual("protobuf_unittest.ForeignEnum", enumType.FullName);
             Assert.AreEqual(UnittestProto3.Descriptor, enumType.File);
             Assert.AreEqual(UnittestProto3.Descriptor, enumType.File);
             Assert.Null(enumType.ContainingType);
             Assert.Null(enumType.ContainingType);
-            Assert.Null(enumType.Options);
+            Assert.Null(enumType.Proto.Options);
 
 
             Assert.AreEqual("NestedEnum", nestedType.Name);
             Assert.AreEqual("NestedEnum", nestedType.Name);
             Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedEnum",
             Assert.AreEqual("protobuf_unittest.TestAllTypes.NestedEnum",
@@ -197,5 +199,27 @@ namespace Google.Protobuf
                 Assert.AreEqual(i, enumType.Values[i].Index);
                 Assert.AreEqual(i, enumType.Values[i].Index);
             }
             }
         }
         }
+
+        [Test]
+        public void OneofDescriptor()
+        {
+            OneofDescriptor descriptor = TestAllTypes.Descriptor.FindDescriptor<OneofDescriptor>("oneof_field");
+            Assert.AreEqual("oneof_field", descriptor.Name);
+            Assert.AreEqual("protobuf_unittest.TestAllTypes.oneof_field", descriptor.FullName);
+
+            var expectedFields = new[] {
+                TestAllTypes.OneofBytesFieldNumber,
+                TestAllTypes.OneofNestedMessageFieldNumber,
+                TestAllTypes.OneofStringFieldNumber,
+                TestAllTypes.OneofUint32FieldNumber }
+                .Select(fieldNumber => TestAllTypes.Descriptor.FindFieldByNumber(fieldNumber))
+                .ToList();
+            foreach (var field in expectedFields)
+            {
+                Assert.AreSame(descriptor, field.ContainingOneof);
+            }
+
+            CollectionAssert.AreEquivalent(expectedFields, descriptor.Fields);
+        }
     }
     }
 }
 }

+ 0 - 53
csharp/src/ProtocolBuffers/DescriptorProtos/IDescriptorProto.cs

@@ -1,53 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 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
-
-namespace Google.Protobuf.DescriptorProtos
-{
-    /// <summary>
-    /// Interface implemented by all DescriptorProtos. The generator doesn't
-    /// emit the interface implementation claim, so PartialClasses.cs contains
-    /// partial class declarations for each of them.
-    /// </summary>
-    /// <typeparam name="TOptions">The associated options protocol buffer type</typeparam>
-    public interface IDescriptorProto<TOptions>
-    {
-        /// <summary>
-        /// The brief name of the descriptor's target.
-        /// </summary>
-        string Name { get; }
-
-        /// <summary>
-        /// The options for this descriptor.
-        /// </summary>
-        TOptions Options { get; }
-    }
-}

+ 10 - 28
csharp/src/ProtocolBuffers/DescriptorProtos/PartialClasses.cs

@@ -30,36 +30,18 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 #endregion
 
 
-// This file just contains partial classes for each of the
-// autogenerated classes, so that they implement
-// IDescriptorProto
+// This file just contains partial classes for any autogenerated classes that need additional support.
 namespace Google.Protobuf.DescriptorProtos
 namespace Google.Protobuf.DescriptorProtos
 {
 {
-    public partial class DescriptorProto : IDescriptorProto<MessageOptions>
-    {
-    }
-
-    public partial class EnumDescriptorProto : IDescriptorProto<EnumOptions>
-    {
-    }
-
-    public partial class EnumValueDescriptorProto : IDescriptorProto<EnumValueOptions>
-    {
-    }
-
-    public partial class FieldDescriptorProto : IDescriptorProto<FieldOptions>
-    {
-    }
-
-    public partial class FileDescriptorProto : IDescriptorProto<FileOptions>
-    {
-    }
-
-    public partial class MethodDescriptorProto : IDescriptorProto<MethodOptions>
-    {
-    }
-
-    public partial class ServiceDescriptorProto : IDescriptorProto<ServiceOptions>
+    internal partial class FieldDescriptorProto
     {
     {
+        // We can't tell the difference between "explicitly set to 0" and "not set"
+        // in proto3, but we need to tell the difference for OneofIndex. descriptor.proto
+        // is really a proto2 file, but the runtime doesn't know about proto2 semantics...
+        // We fake it by defaulting to -1.
+        partial void OnConstruction()
+        {
+            OneofIndex = -1;
+        }
     }
     }
 }
 }

+ 15 - 48
csharp/src/ProtocolBuffers/Descriptors/DescriptorBase.cs

@@ -34,61 +34,36 @@ using Google.Protobuf.DescriptorProtos;
 
 
 namespace Google.Protobuf.Descriptors
 namespace Google.Protobuf.Descriptors
 {
 {
-    // TODO(jonskeet): The descriptor type hierarchy needs changing so that we can hide the descriptor protos.
     /// <summary>
     /// <summary>
     /// Base class for nearly all descriptors, providing common functionality.
     /// Base class for nearly all descriptors, providing common functionality.
     /// </summary>
     /// </summary>
-    /// <typeparam name="TProto">Type of the protocol buffer form of this descriptor</typeparam>
-    /// <typeparam name="TOptions">Type of the options protocol buffer for this descriptor</typeparam>
-    public abstract class DescriptorBase<TProto, TOptions> : IDescriptor<TProto>
-        where TProto : IMessage, IDescriptorProto<TOptions>
+    public abstract class DescriptorBase : IDescriptor
     {
     {
-        private TProto proto;
         private readonly FileDescriptor file;
         private readonly FileDescriptor file;
         private readonly string fullName;
         private readonly string fullName;
+        private readonly int index;
 
 
-        protected DescriptorBase(TProto proto, FileDescriptor file, string fullName)
+        internal DescriptorBase(FileDescriptor file, string fullName, int index)
         {
         {
-            this.proto = proto;
             this.file = file;
             this.file = file;
             this.fullName = fullName;
             this.fullName = fullName;
+            this.index = index;
         }
         }
 
 
-        internal virtual void ReplaceProto(TProto newProto)
-        {
-            this.proto = newProto;
-        }
-
-        protected static string ComputeFullName(FileDescriptor file, MessageDescriptor parent, string name)
-        {
-            if (parent != null)
-            {
-                return parent.FullName + "." + name;
-            }
-            if (file.Package.Length > 0)
-            {
-                return file.Package + "." + name;
-            }
-            return name;
-        }
-
-        IMessage IDescriptor.Proto
-        {
-            get { return proto; }
-        }
-
-        /// <summary>
-        /// Returns the protocol buffer form of this descriptor.
-        /// </summary>
-        public TProto Proto
+        /// <value>
+        /// The index of this descriptor within its parent descriptor. 
+        /// </value>
+        /// <remarks>
+        /// This returns the index of this descriptor within its parent, for
+        /// 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.)
+        /// </remarks>
+        public int Index
         {
         {
-            get { return proto; }
+            get { return index; }
         }
         }
 
 
-        public TOptions Options
-        {
-            get { return proto.Options; }
-        }
+        public abstract string Name { get; }
 
 
         /// <summary>
         /// <summary>
         /// The fully qualified name of the descriptor's target.
         /// The fully qualified name of the descriptor's target.
@@ -98,14 +73,6 @@ namespace Google.Protobuf.Descriptors
             get { return fullName; }
             get { return fullName; }
         }
         }
 
 
-        /// <summary>
-        /// The brief name of the descriptor's target.
-        /// </summary>
-        public string Name
-        {
-            get { return proto.Name; }
-        }
-
         /// <value>
         /// <value>
         /// The file this descriptor was declared in.
         /// The file this descriptor was declared in.
         /// </value>
         /// </value>

+ 1 - 1
csharp/src/ProtocolBuffers/Descriptors/DescriptorPool.cs

@@ -257,7 +257,7 @@ namespace Google.Protobuf.Descriptors
         /// or unqualified. C++-like name lookup semantics are used to search for the
         /// or unqualified. C++-like name lookup semantics are used to search for the
         /// matching descriptor.
         /// matching descriptor.
         /// </summary>
         /// </summary>
-        public IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
+        internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
         {
         {
             // TODO(jonskeet):  This could be optimized in a number of ways.
             // TODO(jonskeet):  This could be optimized in a number of ways.
 
 

+ 11 - 11
csharp/src/ProtocolBuffers/Descriptors/EnumDescriptor.cs

@@ -38,14 +38,16 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Descriptor for an enum type in a .proto file.
     /// Descriptor for an enum type in a .proto file.
     /// </summary>
     /// </summary>
-    public sealed class EnumDescriptor : IndexedDescriptorBase<EnumDescriptorProto, EnumOptions>
+    public sealed class EnumDescriptor : DescriptorBase
     {
     {
+        private readonly EnumDescriptorProto proto;
         private readonly MessageDescriptor containingType;
         private readonly MessageDescriptor containingType;
         private readonly IList<EnumValueDescriptor> values;
         private readonly IList<EnumValueDescriptor> values;
 
 
         internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
         internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
-            : base(proto, file, ComputeFullName(file, parent, proto.Name), index)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
         {
+            this.proto = proto;
             containingType = parent;
             containingType = parent;
 
 
             if (proto.Value.Count == 0)
             if (proto.Value.Count == 0)
@@ -61,6 +63,13 @@ namespace Google.Protobuf.Descriptors
             File.DescriptorPool.AddSymbol(this);
             File.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        internal EnumDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
         /// <value>
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// </value>
         /// </value>
@@ -95,14 +104,5 @@ namespace Google.Protobuf.Descriptors
         {
         {
             return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
             return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
         }
         }
-
-        internal override void ReplaceProto(EnumDescriptorProto newProto)
-        {
-            base.ReplaceProto(newProto);
-            for (int i = 0; i < values.Count; i++)
-            {
-                values[i].ReplaceProto(newProto.Value[i]);
-            }
-        }
     }
     }
 }
 }

+ 10 - 10
csharp/src/ProtocolBuffers/Descriptors/EnumValueDescriptor.cs

@@ -37,27 +37,27 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Descriptor for a single enum value within an enum in a .proto file.
     /// Descriptor for a single enum value within an enum in a .proto file.
     /// </summary>
     /// </summary>
-    public sealed class EnumValueDescriptor : IndexedDescriptorBase<EnumValueDescriptorProto, EnumValueOptions>                                              
+    public sealed class EnumValueDescriptor : DescriptorBase                                            
     {
     {
         private readonly EnumDescriptor enumDescriptor;
         private readonly EnumDescriptor enumDescriptor;
+        private readonly EnumValueDescriptorProto proto;
 
 
         internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
         internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
                                      EnumDescriptor parent, int index)
                                      EnumDescriptor parent, int index)
-            : base(proto, file, parent.FullName + "." + proto.Name, index)
+            : base(file, parent.FullName + "." + proto.Name, index)
         {
         {
+            this.proto = proto;
             enumDescriptor = parent;
             enumDescriptor = parent;
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddEnumValueByNumber(this);
             file.DescriptorPool.AddEnumValueByNumber(this);
         }
         }
 
 
-        public int Number
-        {
-            get { return Proto.Number; }
-        }
+        internal EnumValueDescriptorProto Proto { get { return proto; } }
+        
+        public override string Name { get { return proto.Name; } }
 
 
-        public EnumDescriptor EnumDescriptor
-        {
-            get { return enumDescriptor; }
-        }
+        public int Number { get { return Proto.Number; } }
+
+        public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } }
     }
     }
 }
 }

+ 18 - 12
csharp/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs

@@ -38,21 +38,20 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Descriptor for a field or extension within a message in a .proto file.
     /// Descriptor for a field or extension within a message in a .proto file.
     /// </summary>
     /// </summary>
-    public sealed class FieldDescriptor : IndexedDescriptorBase<FieldDescriptorProto, FieldOptions>,
-                                          IComparable<FieldDescriptor>
+    public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
     {
     {
+        private readonly FieldDescriptorProto proto;
         private EnumDescriptor enumType;
         private EnumDescriptor enumType;
         private MessageDescriptor messageType;
         private MessageDescriptor messageType;
-        private MessageDescriptor containingType;
-        private OneofDescriptor containingOneof;
+        private readonly MessageDescriptor containingType;
+        private readonly OneofDescriptor containingOneof;
         private FieldType fieldType;
         private FieldType fieldType;
 
 
-        private readonly object optionsLock = new object();
-
         internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
         internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
                                  MessageDescriptor parent, int index)
                                  MessageDescriptor parent, int index)
-            : base(proto, file, ComputeFullName(file, parent, proto.Name), index)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
         {
+            this.proto = proto;
             if (proto.Type != 0)
             if (proto.Type != 0)
             {
             {
                 fieldType = GetFieldTypeFromProtoType(proto.Type);
                 fieldType = GetFieldTypeFromProtoType(proto.Type);
@@ -64,7 +63,8 @@ namespace Google.Protobuf.Descriptors
                                                         "Field numbers must be positive integers.");
                                                         "Field numbers must be positive integers.");
             }
             }
             containingType = parent;
             containingType = parent;
-            if (proto.OneofIndex != 0)
+            // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
+            if (proto.OneofIndex != -1)
             {
             {
                 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
                 if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
                 {
                 {
@@ -72,12 +72,18 @@ namespace Google.Protobuf.Descriptors
                         "FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
                         "FieldDescriptorProto.oneof_index is out of range for type " + parent.Name);
                 }
                 }
                 containingOneof = parent.Oneofs[proto.OneofIndex];
                 containingOneof = parent.Oneofs[proto.OneofIndex];
-                containingOneof.fieldCount ++;
             }
             }
 
 
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal FieldDescriptorProto Proto { get { return proto; } }
+        
         /// <summary>
         /// <summary>
         /// Maps a field type as included in the .proto file to a FieldType.
         /// Maps a field type as included in the .proto file to a FieldType.
         /// </summary>
         /// </summary>
@@ -133,12 +139,12 @@ namespace Google.Protobuf.Descriptors
 
 
         public bool IsMap
         public bool IsMap
         {
         {
-            get { return fieldType == FieldType.Message && messageType.Options != null && messageType.Options.MapEntry; }
+            get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; }
         }
         }
 
 
         public bool IsPacked
         public bool IsPacked
         {
         {
-            get { return Proto.Options.Packed; }
+            get { return Proto.Options != null && Proto.Options.Packed; }
         }        
         }        
 
 
         /// <summary>
         /// <summary>
@@ -278,7 +284,7 @@ namespace Google.Protobuf.Descriptors
 
 
             File.DescriptorPool.AddFieldByNumber(this);
             File.DescriptorPool.AddFieldByNumber(this);
 
 
-            if (containingType != null && containingType.Options != null && containingType.Options.MessageSetWireFormat)
+            if (containingType != null && containingType.Proto.Options != null && containingType.Proto.Options.MessageSetWireFormat)
             {
             {
                 throw new DescriptorValidationException(this, "MessageSet format is not supported.");
                 throw new DescriptorValidationException(this, "MessageSet format is not supported.");
             }
             }

+ 19 - 34
csharp/src/ProtocolBuffers/Descriptors/FileDescriptor.cs

@@ -43,7 +43,7 @@ namespace Google.Protobuf.Descriptors
     /// IDescriptor is implemented such that the File property returns this descriptor,
     /// IDescriptor is implemented such that the File property returns this descriptor,
     /// and the FullName is the same as the Name.
     /// and the FullName is the same as the Name.
     /// </summary>
     /// </summary>
-    public sealed class FileDescriptor : IDescriptor<FileDescriptorProto>
+    public sealed class FileDescriptor : IDescriptor
     {
     {
         private readonly FileDescriptorProto proto;
         private readonly FileDescriptorProto proto;
         private readonly IList<MessageDescriptor> messageTypes;
         private readonly IList<MessageDescriptor> messageTypes;
@@ -87,6 +87,22 @@ namespace Google.Protobuf.Descriptors
                                                              new ServiceDescriptor(service, this, index));
                                                              new ServiceDescriptor(service, this, index));
         }
         }
 
 
+        /// <summary>
+        /// Computes the full name of a descriptor within this file, with an optional parent message.
+        /// </summary>
+        internal string ComputeFullName(MessageDescriptor parent, string name)
+        {
+            if (parent != null)
+            {
+                return parent.FullName + "." + name;
+            }
+            if (Package.Length > 0)
+            {
+                return Package + "." + name;
+            }
+            return name;
+        }
+
         /// <summary>
         /// <summary>
         /// Extracts public dependencies from direct dependencies. This is a static method despite its
         /// Extracts public dependencies from direct dependencies. This is a static method despite its
         /// first parameter, as the value we're in the middle of constructing is only used for exceptions.
         /// first parameter, as the value we're in the middle of constructing is only used for exceptions.
@@ -127,19 +143,11 @@ namespace Google.Protobuf.Descriptors
         /// <value>
         /// <value>
         /// The descriptor in its protocol message representation.
         /// The descriptor in its protocol message representation.
         /// </value>
         /// </value>
-        public FileDescriptorProto Proto
+        internal FileDescriptorProto Proto
         {
         {
             get { return proto; }
             get { return proto; }
         }
         }
 
 
-        /// <value>
-        /// The <see cref="DescriptorProtos.FileOptions" /> defined in <c>descriptor.proto</c>.
-        /// </value>
-        public FileOptions Options
-        {
-            get { return proto.Options; }
-        }
-
         /// <value>
         /// <value>
         /// The file name.
         /// The file name.
         /// </value>
         /// </value>
@@ -213,14 +221,6 @@ namespace Google.Protobuf.Descriptors
             get { return this; }
             get { return this; }
         }
         }
 
 
-        /// <value>
-        /// Protocol buffer describing this descriptor.
-        /// </value>
-        IMessage IDescriptor.Proto
-        {
-            get { return Proto; }
-        }
-
         /// <value>
         /// <value>
         /// Pool containing symbol descriptors.
         /// Pool containing symbol descriptors.
         /// </value>
         /// </value>
@@ -255,22 +255,7 @@ namespace Google.Protobuf.Descriptors
             }
             }
             return null;
             return null;
         }
         }
-
-        /// <summary>
-        /// Builds a FileDescriptor from its protocol buffer representation.
-        /// </summary>
-        /// <param name="proto">The protocol message form of the FileDescriptor.</param>
-        /// <param name="dependencies">FileDescriptors corresponding to all of the
-        /// file's dependencies, in the exact order listed in the .proto file. May be null,
-        /// in which case it is treated as an empty array.</param>
-        /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
-        /// a valid descriptor. This can occur for a number of reasons, such as a field
-        /// having an undefined type or because two messages were defined with the same name.</exception>
-        public static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies)
-        {
-            return BuildFrom(proto, dependencies, false);
-        }
-
+        
         /// <summary>
         /// <summary>
         /// Builds a FileDescriptor from its protocol buffer representation.
         /// Builds a FileDescriptor from its protocol buffer representation.
         /// </summary>
         /// </summary>

+ 2 - 13
csharp/src/ProtocolBuffers/Descriptors/IDescriptor.cs

@@ -33,23 +33,12 @@
 namespace Google.Protobuf.Descriptors
 namespace Google.Protobuf.Descriptors
 {
 {
     /// <summary>
     /// <summary>
-    /// The non-generic form of the IDescriptor interface. Useful for describing a general
-    /// descriptor.
+    /// Interface implemented by all descriptor types.
     /// </summary>
     /// </summary>
     public interface IDescriptor
     public interface IDescriptor
     {
     {
         string Name { get; }
         string Name { get; }
         string FullName { get; }
         string FullName { get; }
         FileDescriptor File { get; }
         FileDescriptor File { get; }
-        IMessage Proto { get; }
-    }
-
-    /// <summary>
-    /// Strongly-typed form of the IDescriptor interface.
-    /// </summary>
-    /// <typeparam name="TProto">Protocol buffer type underlying this descriptor type</typeparam>
-    internal interface IDescriptor<TProto> : IDescriptor where TProto : IMessage
-    {
-        new TProto Proto { get; }
-    }
+    }    
 }
 }

+ 0 - 65
csharp/src/ProtocolBuffers/Descriptors/IndexedDescriptorBase.cs

@@ -1,65 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 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.DescriptorProtos;
-
-namespace Google.Protobuf.Descriptors
-{
-    /// <summary>
-    /// Base class for descriptors which are also indexed. This is all of them other than
-    /// <see cref="FileDescriptor" />.
-    /// </summary>
-    public abstract class IndexedDescriptorBase<TProto, TOptions> : DescriptorBase<TProto, TOptions>
-        where TProto : IMessage<TProto>, IDescriptorProto<TOptions>
-    {
-        private readonly int index;
-
-        protected IndexedDescriptorBase(TProto proto, FileDescriptor file, string fullName, int index)
-            : base(proto, file, fullName)
-        {
-            this.index = index;
-        }
-
-        /// <value>
-        /// The index of this descriptor within its parent descriptor. 
-        /// </value>
-        /// <remarks>
-        /// This returns the index of this descriptor within its parent, for
-        /// 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.)
-        /// </remarks>
-        public int Index
-        {
-            get { return index; }
-        }
-    }
-}

+ 14 - 43
csharp/src/ProtocolBuffers/Descriptors/MessageDescriptor.cs

@@ -39,8 +39,9 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Describes a message type.
     /// Describes a message type.
     /// </summary>
     /// </summary>
-    public sealed class MessageDescriptor : IndexedDescriptorBase<DescriptorProto, MessageOptions>
+    public sealed class MessageDescriptor : DescriptorBase
     {
     {
+        private readonly DescriptorProto proto;
         private readonly MessageDescriptor containingType;
         private readonly MessageDescriptor containingType;
         private readonly IList<MessageDescriptor> nestedTypes;
         private readonly IList<MessageDescriptor> nestedTypes;
         private readonly IList<EnumDescriptor> enumTypes;
         private readonly IList<EnumDescriptor> enumTypes;
@@ -48,8 +49,9 @@ namespace Google.Protobuf.Descriptors
         private readonly IList<OneofDescriptor> oneofs;
         private readonly IList<OneofDescriptor> oneofs;
         
         
         internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
         internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex)
-            : base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex)
+            : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
         {
         {
+            this.proto = proto;
             containingType = parent;
             containingType = parent;
 
 
             oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDecl,
             oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDecl,
@@ -68,23 +70,16 @@ namespace Google.Protobuf.Descriptors
             fields = DescriptorUtil.ConvertAndMakeReadOnly(proto.Field,
             fields = DescriptorUtil.ConvertAndMakeReadOnly(proto.Field,
                                                            (field, index) =>
                                                            (field, index) =>
                                                            new FieldDescriptor(field, file, this, index));
                                                            new FieldDescriptor(field, file, this, index));
-
-            for (int i = 0; i < proto.OneofDecl.Count; i++)
-            {
-                oneofs[i].fields = new FieldDescriptor[oneofs[i].FieldCount];
-                oneofs[i].fieldCount = 0;
-            }
-            for (int i = 0; i< proto.Field.Count; i++)
-            {
-                OneofDescriptor oneofDescriptor = fields[i].ContainingOneof;
-                if (oneofDescriptor != null)
-                {
-                    oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
-                }
-            }
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal DescriptorProto Proto { get { return proto; } }
+
         /// <value>
         /// <value>
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// If this is a nested type, get the outer descriptor, otherwise null.
         /// </value>
         /// </value>
@@ -144,7 +139,7 @@ namespace Google.Protobuf.Descriptors
 
 
         /// <summary>
         /// <summary>
         /// Finds a nested descriptor by name. The is valid for fields, nested
         /// Finds a nested descriptor by name. The is valid for fields, nested
-        /// message types and enums.
+        /// message types, oneofs and enums.
         /// </summary>
         /// </summary>
         /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
         /// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
         /// <returns>The descriptor, or null if not found.</returns>
         /// <returns>The descriptor, or null if not found.</returns>
@@ -171,32 +166,8 @@ namespace Google.Protobuf.Descriptors
 
 
             foreach (OneofDescriptor oneof in oneofs)
             foreach (OneofDescriptor oneof in oneofs)
             {
             {
-                // TODO(jonskeet): Do we need to do this?
-                // oneof.C
-            }
-        }
-
-        /// <summary>
-        /// See FileDescriptor.ReplaceProto
-        /// </summary>
-        internal override void ReplaceProto(DescriptorProto newProto)
-        {
-            base.ReplaceProto(newProto);
-
-            for (int i = 0; i < nestedTypes.Count; i++)
-            {
-                nestedTypes[i].ReplaceProto(newProto.NestedType[i]);
-            }
-
-            for (int i = 0; i < enumTypes.Count; i++)
-            {
-                enumTypes[i].ReplaceProto(newProto.EnumType[i]);
-            }
-
-            for (int i = 0; i < fields.Count; i++)
-            {
-                fields[i].ReplaceProto(newProto.Field[i]);
+                oneof.CrossLink();
             }
             }
-        }
+        }        
     }
     }
 }
 }

+ 14 - 14
csharp/src/ProtocolBuffers/Descriptors/MethodDescriptor.cs

@@ -37,8 +37,9 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Describes a single method in a service.
     /// Describes a single method in a service.
     /// </summary>
     /// </summary>
-    public sealed class MethodDescriptor : IndexedDescriptorBase<MethodDescriptorProto, MethodOptions>
+    public sealed class MethodDescriptor : DescriptorBase
     {
     {
+        private readonly MethodDescriptorProto proto;
         private readonly ServiceDescriptor service;
         private readonly ServiceDescriptor service;
         private MessageDescriptor inputType;
         private MessageDescriptor inputType;
         private MessageDescriptor outputType;
         private MessageDescriptor outputType;
@@ -46,35 +47,34 @@ namespace Google.Protobuf.Descriptors
         /// <value>
         /// <value>
         /// The service this method belongs to.
         /// The service this method belongs to.
         /// </value>
         /// </value>
-        public ServiceDescriptor Service
-        {
-            get { return service; }
-        }
+        public ServiceDescriptor Service { get { return service; } }
 
 
         /// <value>
         /// <value>
         /// The method's input type.
         /// The method's input type.
         /// </value>
         /// </value>
-        public MessageDescriptor InputType
-        {
-            get { return inputType; }
-        }
+        public MessageDescriptor InputType { get { return inputType; } }
 
 
         /// <value>
         /// <value>
         /// The method's input type.
         /// The method's input type.
         /// </value>
         /// </value>
-        public MessageDescriptor OutputType
-        {
-            get { return outputType; }
-        }
+        public MessageDescriptor OutputType { get { return outputType; } }
 
 
         internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
         internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
                                   ServiceDescriptor parent, int index)
                                   ServiceDescriptor parent, int index)
-            : base(proto, file, parent.FullName + "." + proto.Name, index)
+            : base(file, parent.FullName + "." + proto.Name, index)
         {
         {
+            this.proto = proto;
             service = parent;
             service = parent;
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        internal MethodDescriptorProto Proto { get { return proto; } }
+
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
         internal void CrossLink()
         internal void CrossLink()
         {
         {
             IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);
             IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);

+ 23 - 22
csharp/src/ProtocolBuffers/Descriptors/OneofDescriptor.cs

@@ -31,48 +31,49 @@
 #endregion
 #endregion
 
 
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using Google.Protobuf.DescriptorProtos;
 using Google.Protobuf.DescriptorProtos;
 
 
 namespace Google.Protobuf.Descriptors
 namespace Google.Protobuf.Descriptors
 {
 {
-    public sealed class OneofDescriptor
+    public sealed class OneofDescriptor : DescriptorBase
     {
     {
-        private int index;
-        private OneofDescriptorProto proto;
-        private FileDescriptor file;
+        private readonly OneofDescriptorProto proto;
         private MessageDescriptor containingType;
         private MessageDescriptor containingType;
-        internal int fieldCount;
-        internal IList<FieldDescriptor> fields;
+        private IList<FieldDescriptor> fields;
 
 
-        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file,
-                                 MessageDescriptor parent, int index)
+        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
+            : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
         {
             this.proto = proto;
             this.proto = proto;
-            this.file = file;
-            this.index = index;
-
             containingType = parent;
             containingType = parent;
-            fieldCount = 0;
-        }
 
 
-        public int Index
-        {
-            get { return index; }
+            file.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
         public MessageDescriptor ContainingType
         public MessageDescriptor ContainingType
         {
         {
             get { return containingType; }
             get { return containingType; }
         }
         }
 
 
-        public int FieldCount
-        {
-            get { return fieldCount; }
-        }
+        public IList<FieldDescriptor> Fields { get { return fields; } }
 
 
-        public FieldDescriptor Field(int index)
+        internal void CrossLink()
         {
         {
-            return fields[index];
+            List<FieldDescriptor> fieldCollection = new List<FieldDescriptor>();
+            foreach (var field in ContainingType.Fields)
+            {
+                if (field.ContainingOneof == this)
+                {
+                    fieldCollection.Add(field);
+                }
+            }
+            fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
         }
         }
     }
     }
 }
 }

+ 1 - 6
csharp/src/ProtocolBuffers/Descriptors/PackageDescriptor.cs

@@ -37,7 +37,7 @@ namespace Google.Protobuf.Descriptors
     /// just as placeholders so that someone cannot define, say, a message type
     /// just as placeholders so that someone cannot define, say, a message type
     /// that has the same name as an existing package.
     /// that has the same name as an existing package.
     /// </summary>
     /// </summary>
-    internal sealed class PackageDescriptor : IDescriptor<IMessage>
+    internal sealed class PackageDescriptor : IDescriptor
     {
     {
         private readonly string name;
         private readonly string name;
         private readonly string fullName;
         private readonly string fullName;
@@ -50,11 +50,6 @@ namespace Google.Protobuf.Descriptors
             this.name = name;
             this.name = name;
         }
         }
 
 
-        public IMessage Proto
-        {
-            get { return file.Proto; }
-        }
-
         public string Name
         public string Name
         {
         {
             get { return name; }
             get { return name; }

+ 12 - 12
csharp/src/ProtocolBuffers/Descriptors/ServiceDescriptor.cs

@@ -39,19 +39,28 @@ namespace Google.Protobuf.Descriptors
     /// <summary>
     /// <summary>
     /// Describes a service type.
     /// Describes a service type.
     /// </summary>
     /// </summary>
-    public sealed class ServiceDescriptor : IndexedDescriptorBase<ServiceDescriptorProto, ServiceOptions>
+    public sealed class ServiceDescriptor : DescriptorBase
     {
     {
+        private readonly ServiceDescriptorProto proto;
         private readonly IList<MethodDescriptor> methods;
         private readonly IList<MethodDescriptor> methods;
 
 
-        public ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
-            : base(proto, file, ComputeFullName(file, null, proto.Name), index)
+        internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
+            : base(file, file.ComputeFullName(null, proto.Name), index)
         {
         {
+            this.proto = proto;
             methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
             methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
                                                             (method, i) => new MethodDescriptor(method, file, this, i));
                                                             (method, i) => new MethodDescriptor(method, file, this, i));
 
 
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
         }
         }
 
 
+        /// <summary>
+        /// The brief name of the descriptor's target.
+        /// </summary>
+        public override string Name { get { return proto.Name; } }
+
+        internal ServiceDescriptorProto Proto { get { return proto; } }
+
         /// <value>
         /// <value>
         /// An unmodifiable list of methods in this service.
         /// An unmodifiable list of methods in this service.
         /// </value>
         /// </value>
@@ -77,14 +86,5 @@ namespace Google.Protobuf.Descriptors
                 method.CrossLink();
                 method.CrossLink();
             }
             }
         }
         }
-
-        internal override void ReplaceProto(ServiceDescriptorProto newProto)
-        {
-            base.ReplaceProto(newProto);
-            for (int i = 0; i < methods.Count; i++)
-            {
-                methods[i].ReplaceProto(newProto.Method[i]);
-            }
-        }
     }
     }
 }
 }

+ 0 - 2
csharp/src/ProtocolBuffers/ProtocolBuffers.csproj

@@ -61,7 +61,6 @@
     <Compile Include="Collections\ReadOnlyDictionary.cs" />
     <Compile Include="Collections\ReadOnlyDictionary.cs" />
     <Compile Include="Collections\RepeatedField.cs" />
     <Compile Include="Collections\RepeatedField.cs" />
     <Compile Include="DescriptorProtos\DescriptorProtoFile.cs" />
     <Compile Include="DescriptorProtos\DescriptorProtoFile.cs" />
-    <Compile Include="DescriptorProtos\IDescriptorProto.cs" />
     <Compile Include="DescriptorProtos\PartialClasses.cs" />
     <Compile Include="DescriptorProtos\PartialClasses.cs" />
     <Compile Include="Descriptors\DescriptorBase.cs" />
     <Compile Include="Descriptors\DescriptorBase.cs" />
     <Compile Include="Descriptors\DescriptorPool.cs" />
     <Compile Include="Descriptors\DescriptorPool.cs" />
@@ -74,7 +73,6 @@
     <Compile Include="Descriptors\FileDescriptor.cs" />
     <Compile Include="Descriptors\FileDescriptor.cs" />
     <Compile Include="Descriptors\OneofDescriptor.cs" />
     <Compile Include="Descriptors\OneofDescriptor.cs" />
     <Compile Include="Descriptors\IDescriptor.cs" />
     <Compile Include="Descriptors\IDescriptor.cs" />
-    <Compile Include="Descriptors\IndexedDescriptorBase.cs" />
     <Compile Include="Descriptors\MessageDescriptor.cs" />
     <Compile Include="Descriptors\MessageDescriptor.cs" />
     <Compile Include="Descriptors\MethodDescriptor.cs" />
     <Compile Include="Descriptors\MethodDescriptor.cs" />
     <Compile Include="Descriptors\PackageDescriptor.cs" />
     <Compile Include="Descriptors\PackageDescriptor.cs" />