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

Remove the usage of attributes for field/method discovery.

Instead, introduce GeneratedCodeInfo which passes in what we need, and adjust the codegen to take account of this.
Jon Skeet 10 жил өмнө
parent
commit
4668c3dc39
22 өөрчлөгдсөн 243 нэмэгдсэн , 398 устгасан
  1. 1 2
      csharp/src/Google.Protobuf/Google.Protobuf.csproj
  2. 22 142
      csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs
  3. 13 13
      csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
  4. 12 24
      csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
  5. 66 0
      csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs
  6. 23 19
      csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
  7. 9 18
      csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
  8. 0 58
      csharp/src/Google.Protobuf/Reflection/ProtobufFieldAttribute.cs
  9. 0 52
      csharp/src/Google.Protobuf/Reflection/ProtobufOneofAttribute.cs
  10. 1 20
      csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
  11. 0 5
      src/google/protobuf/compiler/csharp/csharp_field_base.cc
  12. 0 1
      src/google/protobuf/compiler/csharp/csharp_field_base.h
  13. 0 1
      src/google/protobuf/compiler/csharp/csharp_map_field.cc
  14. 0 13
      src/google/protobuf/compiler/csharp/csharp_message.cc
  15. 0 2
      src/google/protobuf/compiler/csharp/csharp_message_field.cc
  16. 0 2
      src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
  17. 0 1
      src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc
  18. 0 1
      src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc
  19. 0 1
      src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
  20. 95 20
      src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
  21. 1 1
      src/google/protobuf/compiler/csharp/csharp_umbrella_class.h
  22. 0 2
      src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc

+ 1 - 2
csharp/src/Google.Protobuf/Google.Protobuf.csproj

@@ -81,6 +81,7 @@
     <Compile Include="Reflection\FieldDescriptor.cs" />
     <Compile Include="Reflection\FieldDescriptor.cs" />
     <Compile Include="Reflection\FieldType.cs" />
     <Compile Include="Reflection\FieldType.cs" />
     <Compile Include="Reflection\FileDescriptor.cs" />
     <Compile Include="Reflection\FileDescriptor.cs" />
+    <Compile Include="Reflection\GeneratedCodeInfo.cs" />
     <Compile Include="Reflection\IDescriptor.cs" />
     <Compile Include="Reflection\IDescriptor.cs" />
     <Compile Include="Reflection\IFieldAccessor.cs" />
     <Compile Include="Reflection\IFieldAccessor.cs" />
     <Compile Include="Reflection\MapFieldAccessor.cs" />
     <Compile Include="Reflection\MapFieldAccessor.cs" />
@@ -90,8 +91,6 @@
     <Compile Include="Reflection\OneofDescriptor.cs" />
     <Compile Include="Reflection\OneofDescriptor.cs" />
     <Compile Include="Reflection\PackageDescriptor.cs" />
     <Compile Include="Reflection\PackageDescriptor.cs" />
     <Compile Include="Reflection\PartialClasses.cs" />
     <Compile Include="Reflection\PartialClasses.cs" />
-    <Compile Include="Reflection\ProtobufOneofAttribute.cs" />
-    <Compile Include="Reflection\ProtobufFieldAttribute.cs" />
     <Compile Include="Reflection\ReflectionUtil.cs" />
     <Compile Include="Reflection\ReflectionUtil.cs" />
     <Compile Include="Reflection\RepeatedFieldAccessor.cs" />
     <Compile Include="Reflection\RepeatedFieldAccessor.cs" />
     <Compile Include="Reflection\ServiceDescriptor.cs" />
     <Compile Include="Reflection\ServiceDescriptor.cs" />

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 22 - 142
csharp/src/Google.Protobuf/Reflection/DescriptorProtoFile.cs


+ 13 - 13
csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs

@@ -46,10 +46,11 @@ namespace Google.Protobuf.Reflection
         private readonly MessageDescriptor containingType;
         private readonly MessageDescriptor containingType;
         private readonly OneofDescriptor containingOneof;
         private readonly OneofDescriptor containingOneof;
         private FieldType fieldType;
         private FieldType fieldType;
+        private readonly string propertyName; // Annoyingly, needed in Crosslink.
         private IFieldAccessor accessor;
         private IFieldAccessor accessor;
 
 
         internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
         internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
-                                 MessageDescriptor parent, int index)
+                                 MessageDescriptor parent, int index, string propertyName)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
         {
             this.proto = proto;
             this.proto = proto;
@@ -76,6 +77,12 @@ namespace Google.Protobuf.Reflection
             }
             }
 
 
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
+            // We can't create the accessor until we've cross-linked, unfortunately, as we
+            // may not know whether the type of the field is a map or not. Remember the property name
+            // for later.
+            // We could trust the generated code and check whether the type of the property is
+            // a MapField, but that feels a tad nasty.
+            this.propertyName = propertyName;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -291,26 +298,19 @@ namespace Google.Protobuf.Reflection
             {
             {
                 throw new DescriptorValidationException(this, "MessageSet format is not supported.");
                 throw new DescriptorValidationException(this, "MessageSet format is not supported.");
             }
             }
-
-            accessor = CreateAccessor();
+            accessor = CreateAccessor(propertyName);
         }
         }
 
 
-        private IFieldAccessor CreateAccessor()
+        private IFieldAccessor CreateAccessor(string propertyName)
         {
         {
-            // TODO: Check the performance of this with some large protos. Each message is O(N^2) in the number of fields,
-            // which isn't great...
-            if (containingType.GeneratedType == null)
+            if (containingType.GeneratedType == null || propertyName == null)
             {
             {
                 return null;
                 return null;
             }
             }
-            var property = containingType
-                .GeneratedType
-                .GetProperties()
-                .FirstOrDefault(p => p.IsDefined(typeof(ProtobufFieldAttribute), false) &&
-                                     p.GetCustomAttributes(typeof(ProtobufFieldAttribute), false).Cast<ProtobufFieldAttribute>().Single().Number == FieldNumber);
+            var property = containingType.GeneratedType.GetProperty(propertyName);
             if (property == null)
             if (property == null)
             {
             {
-                return null;
+                throw new DescriptorValidationException(this, "Property " + propertyName + " not found in " + containingType.GeneratedType);
             }
             }
             return IsMap ? new MapFieldAccessor(property, this)
             return IsMap ? new MapFieldAccessor(property, this)
                 : IsRepeated ? new RepeatedFieldAccessor(property, this)
                 : IsRepeated ? new RepeatedFieldAccessor(property, this)

+ 12 - 24
csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs

@@ -62,12 +62,11 @@ namespace Google.Protobuf.Reflection
             get { return proto.Syntax == "proto3" ? ProtoSyntax.Proto3 : ProtoSyntax.Proto2; }
             get { return proto.Syntax == "proto3" ? ProtoSyntax.Proto3 : ProtoSyntax.Proto2; }
         }
         }
 
 
-        private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, Type[] generatedTypes)
+        private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedCodeInfo generatedCodeInfo)
         {
         {
             this.pool = pool;
             this.pool = pool;
             this.proto = proto;
             this.proto = proto;
             this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
             this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
-            IEnumerator<Type> generatedTypeIterator = generatedTypes == null ? null : ((IEnumerable<Type>)generatedTypes).GetEnumerator();
 
 
             publicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
             publicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
 
 
@@ -75,21 +74,15 @@ namespace Google.Protobuf.Reflection
 
 
             messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
             messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
                                                                  (message, index) =>
                                                                  (message, index) =>
-                                                                 new MessageDescriptor(message, this, null, index, generatedTypeIterator));
+                                                                 new MessageDescriptor(message, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
 
 
             enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
             enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
                                                               (enumType, index) =>
                                                               (enumType, index) =>
-                                                              new EnumDescriptor(enumType, this, null, index, ReflectionUtil.GetNextType(generatedTypeIterator)));
+                                                              new EnumDescriptor(enumType, this, null, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
 
 
             services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
             services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
                                                              (service, index) =>
                                                              (service, index) =>
                                                              new ServiceDescriptor(service, this, index));
                                                              new ServiceDescriptor(service, this, index));
-
-            // We should now have consumed all the generated types.
-            if (generatedTypeIterator != null && generatedTypeIterator.MoveNext())
-            {
-                throw new ArgumentException("More generated types left over after consuming all expected ones", "generatedTypes");
-            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -260,7 +253,7 @@ namespace Google.Protobuf.Reflection
             }
             }
             return null;
             return null;
         }
         }
-        
+
         /// <summary>
         /// <summary>
         /// Builds a FileDescriptor from its protocol buffer representation.
         /// Builds a FileDescriptor from its protocol buffer representation.
         /// </summary>
         /// </summary>
@@ -269,10 +262,11 @@ namespace Google.Protobuf.Reflection
         /// file's dependencies, in the exact order listed in the .proto file. May be null,
         /// 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>
         /// in which case it is treated as an empty array.</param>
         /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
         /// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
+        /// <param name="generatedCodeInfo">Reflection information, if any. May be null, specifically for non-generated code.</param>
         /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
         /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
         /// a valid descriptor. This can occur for a number of reasons, such as a field
         /// 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>
         /// having an undefined type or because two messages were defined with the same name.</exception>
-        private static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, Type[] generatedTypes)
+        private static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedCodeInfo generatedCodeInfo)
         {
         {
             // Building descriptors involves two steps: translating and linking.
             // Building descriptors involves two steps: translating and linking.
             // In the translation step (implemented by FileDescriptor's
             // In the translation step (implemented by FileDescriptor's
@@ -289,7 +283,7 @@ namespace Google.Protobuf.Reflection
             }
             }
 
 
             DescriptorPool pool = new DescriptorPool(dependencies);
             DescriptorPool pool = new DescriptorPool(dependencies);
-            FileDescriptor result = new FileDescriptor(proto, dependencies, pool, allowUnknownDependencies, generatedTypes);
+            FileDescriptor result = new FileDescriptor(proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo);
 
 
             // TODO(jonskeet): Reinstate these checks, or get rid of them entirely. They aren't in the Java code,
             // TODO(jonskeet): Reinstate these checks, or get rid of them entirely. They aren't in the Java code,
             // and fail for the CustomOptions test right now. (We get "descriptor.proto" vs "google/protobuf/descriptor.proto".)
             // and fail for the CustomOptions test right now. (We get "descriptor.proto" vs "google/protobuf/descriptor.proto".)
@@ -330,19 +324,13 @@ namespace Google.Protobuf.Reflection
         /// Creates an instance for generated code.
         /// Creates an instance for generated code.
         /// </summary>
         /// </summary>
         /// <remarks>
         /// <remarks>
-        /// The <paramref name="generatedTypes"/> parameter should be null for descriptors which don't correspond to
-        /// generated types. Otherwise, the array should represent all the generated types in the file: messages then
-        /// enums. Within each message, there can be nested messages and enums, which must be specified "inline" in the array:
-        /// containing message, nested messages, nested enums - and of course each nested message may contain *more* nested messages,
-        /// etc. All messages within the descriptor should be represented, even if they do not have a generated type - any
-        /// type without a corresponding generated type (such as map entries) should respond to a null element.
-        /// For example, a file with a messages OuterMessage and InnerMessage, and enums OuterEnum and InnerEnum (where
-        /// InnerMessage and InnerEnum are nested within InnerMessage) would result in an array of
-        /// OuterMessage, InnerMessage, InnerEnum, OuterEnum.
+        /// The <paramref name="generatedCodeInfo"/> parameter should be null for descriptors which don't correspond to
+        /// generated types. Otherwise, it should be a <see cref="GeneratedCodeInfo"/> with nested types and nested
+        /// enums corresponding to the types and enums contained within the file descriptor.
         /// </remarks>
         /// </remarks>
         public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
         public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
                                                                     FileDescriptor[] dependencies,
                                                                     FileDescriptor[] dependencies,
-                                                                    Type[] generatedTypes)
+                                                                    GeneratedCodeInfo generatedCodeInfo)
         {
         {
             FileDescriptorProto proto;
             FileDescriptorProto proto;
             try
             try
@@ -358,7 +346,7 @@ namespace Google.Protobuf.Reflection
             {
             {
                 // When building descriptors for generated code, we allow unknown
                 // When building descriptors for generated code, we allow unknown
                 // dependencies by default.
                 // dependencies by default.
-                return BuildFrom(proto, dependencies, true, generatedTypes);
+                return BuildFrom(proto, dependencies, true, generatedCodeInfo);
             }
             }
             catch (DescriptorValidationException e)
             catch (DescriptorValidationException e)
             {
             {

+ 66 - 0
csharp/src/Google.Protobuf/Reflection/GeneratedCodeInfo.cs

@@ -0,0 +1,66 @@
+using System;
+
+namespace Google.Protobuf.Reflection
+{
+    /// <summary>
+    /// Extra information provided by generated code when initializing a message or file descriptor.
+    /// These are constructed as required, and are not long-lived. Hand-written code should
+    /// never need to use this type.
+    /// </summary>
+    public sealed class GeneratedCodeInfo
+    {
+        private static readonly string[] EmptyNames = new string[0];
+        private static readonly GeneratedCodeInfo[] EmptyCodeInfo = new GeneratedCodeInfo[0];
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
+        /// </summary>
+        public Type ClrType { get; private set; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
+        /// for fields in the message for message descriptors.
+        /// </summary>
+        public string[] PropertyNames { get; private set; }
+
+        /// <summary>
+        /// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
+        /// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
+        /// there will be a "FooCase" property and a "ClearFoo" method.
+        /// </summary>
+        public string[] OneofNames { get; private set; }
+
+        /// <summary>
+        /// The reflection information for types within this file/message descriptor. Elements may be null
+        /// if there is no corresponding generated type, e.g. for map entry types.
+        /// </summary>
+        public GeneratedCodeInfo[] NestedTypes { get; private set; }
+
+        /// <summary>
+        /// The CLR types for enums within this file/message descriptor.
+        /// </summary>
+        public Type[] NestedEnums { get; private set; }
+
+        /// <summary>
+        /// Creates a GeneratedCodeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
+        /// Each array parameter may be null, to indicate a lack of values.
+        /// The parameter order is designed to make it feasible to format the generated code readably.
+        /// </summary>
+        public GeneratedCodeInfo(Type clrType, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedCodeInfo[] nestedTypes)
+        {
+            NestedTypes = nestedTypes ?? EmptyCodeInfo;
+            NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
+            ClrType = clrType;
+            PropertyNames = propertyNames ?? EmptyNames;
+            OneofNames = oneofNames ?? EmptyNames;
+        }
+
+        /// <summary>
+        /// Creates a GeneratedCodeInfo for a file descriptor, with only types and enums.
+        /// </summary>
+        public GeneratedCodeInfo(Type[] nestedEnums, GeneratedCodeInfo[] nestedTypes)
+            : this(null, null, null, nestedEnums, nestedTypes)
+        {
+        }
+    }
+}

+ 23 - 19
csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs

@@ -66,29 +66,33 @@ namespace Google.Protobuf.Reflection
         private readonly Type generatedType;
         private readonly Type generatedType;
         private IDictionary<int, IFieldAccessor> fieldAccessorsByFieldNumber;
         private IDictionary<int, IFieldAccessor> fieldAccessorsByFieldNumber;
         
         
-        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, IEnumerator<Type> generatedTypeIterator)
+        internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedCodeInfo generatedCodeInfo)
             : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
             : base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
         {
         {
             this.proto = proto;
             this.proto = proto;
-            generatedType = ReflectionUtil.GetNextType(generatedTypeIterator);
-            containingType = parent;
-
-            oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDecl,
-                                                               (oneof, index) =>
-                                                               new OneofDescriptor(oneof, file, this, index));
-
-            nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.NestedType,
-                                                                (type, index) =>
-                                                                new MessageDescriptor(type, file, this, index, generatedTypeIterator));
+            generatedType = generatedCodeInfo == null ? null : generatedCodeInfo.ClrType;
 
 
-            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
-                                                              (type, index) =>
-                                                              new EnumDescriptor(type, file, this, index, ReflectionUtil.GetNextType(generatedTypeIterator)));
+            containingType = parent;
 
 
-            // TODO(jonskeet): Sort fields first?
-            fields = DescriptorUtil.ConvertAndMakeReadOnly(proto.Field,
-                                                           (field, index) =>
-                                                           new FieldDescriptor(field, file, this, index));
+            oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.OneofDecl,
+                (oneof, index) =>
+                new OneofDescriptor(oneof, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.OneofNames[index]));
+
+            nestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.NestedType,
+                (type, index) =>
+                new MessageDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedTypes[index]));
+
+            enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.EnumType,
+                (type, index) =>
+                new EnumDescriptor(type, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.NestedEnums[index]));
+
+            fields = DescriptorUtil.ConvertAndMakeReadOnly(
+                proto.Field,
+                (field, index) =>
+                new FieldDescriptor(field, file, this, index, generatedCodeInfo == null ? null : generatedCodeInfo.PropertyNames[index]));
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
         }
         }
                 
                 
@@ -220,6 +224,6 @@ namespace Google.Protobuf.Reflection
             }
             }
 
 
             fieldAccessorsByFieldNumber = new ReadOnlyDictionary<int, IFieldAccessor>(fields.ToDictionary(field => field.FieldNumber, field => field.Accessor));
             fieldAccessorsByFieldNumber = new ReadOnlyDictionary<int, IFieldAccessor>(fields.ToDictionary(field => field.FieldNumber, field => field.Accessor));
-        }        
+        }
     }
     }
 }
 }

+ 9 - 18
csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs

@@ -41,15 +41,16 @@ namespace Google.Protobuf.Reflection
         private readonly OneofDescriptorProto proto;
         private readonly OneofDescriptorProto proto;
         private MessageDescriptor containingType;
         private MessageDescriptor containingType;
         private IList<FieldDescriptor> fields;
         private IList<FieldDescriptor> fields;
-        private OneofAccessor accessor;
+        private readonly OneofAccessor accessor;
 
 
-        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index)
+        internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string clrName)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
         {
             this.proto = proto;
             this.proto = proto;
             containingType = parent;
             containingType = parent;
 
 
             file.DescriptorPool.AddSymbol(this);
             file.DescriptorPool.AddSymbol(this);
+            accessor = CreateAccessor(clrName);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -77,33 +78,23 @@ namespace Google.Protobuf.Reflection
                 }
                 }
             }
             }
             fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
             fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
-            accessor = CreateAccessor();
         }
         }
 
 
-        private OneofAccessor CreateAccessor()
+        private OneofAccessor CreateAccessor(string clrName)
         {
         {
-            if (containingType.GeneratedType == null)
+            if (containingType.GeneratedType == null || clrName == null)
             {
             {
                 return null;
                 return null;
             }
             }
-            var caseProperty = containingType
-                .GeneratedType
-                .GetProperties()
-                .FirstOrDefault(p => p.IsDefined(typeof(ProtobufOneofAttribute), false) &&
-                                     p.GetCustomAttributes(typeof(ProtobufOneofAttribute), false).Cast<ProtobufOneofAttribute>().Single().Name == Name);
+            var caseProperty = containingType.GeneratedType.GetProperty(clrName + "Case");
             if (caseProperty == null)
             if (caseProperty == null)
             {
             {
-                return null;
+                throw new DescriptorValidationException(this, "Property " + clrName + "Case not found in " + containingType.GeneratedType);
             }
             }
-
-            var clearMethod = containingType
-                 .GeneratedType
-                 .GetMethods()
-                 .FirstOrDefault(p => p.IsDefined(typeof(ProtobufOneofAttribute), false) &&
-                                      p.GetCustomAttributes(typeof(ProtobufOneofAttribute), false).Cast<ProtobufOneofAttribute>().Single().Name == Name);
+            var clearMethod = containingType.GeneratedType.GetMethod("Clear" + clrName, ReflectionUtil.EmptyTypes);
             if (clearMethod == null)
             if (clearMethod == null)
             {
             {
-                return null;
+                throw new DescriptorValidationException(this, "Method Clear" + clrName + " not found in " + containingType.GeneratedType);
             }
             }
 
 
             return new OneofAccessor(caseProperty, clearMethod, this);
             return new OneofAccessor(caseProperty, clearMethod, this);

+ 0 - 58
csharp/src/Google.Protobuf/Reflection/ProtobufFieldAttribute.cs

@@ -1,58 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2015 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;
-
-namespace Google.Protobuf.Reflection
-{
-    /// <summary>
-    /// Attribute applied to a generated property corresponding to a field in a .proto file.
-    /// </summary>
-    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
-    public sealed class ProtobufFieldAttribute : Attribute
-    {
-        /// <summary>
-        /// The field number in the original .proto file.
-        /// </summary>
-        public int Number { get; set; }
-        
-        /// <summary>
-        /// The field name in the original .proto file.
-        /// </summary>
-        public string Name { get; set; }
-
-        public ProtobufFieldAttribute(int number, string name)
-        {
-            this.Number = number;
-            this.Name = name;
-        }
-    }
-}

+ 0 - 52
csharp/src/Google.Protobuf/Reflection/ProtobufOneofAttribute.cs

@@ -1,52 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2015 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;
-
-namespace Google.Protobuf.Reflection
-{
-    /// <summary>
-    /// Attribute applied to the "case" property or "clear" method corresponding to a oneof in a .proto file.
-    /// </summary>
-    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)]
-    public sealed class ProtobufOneofAttribute : Attribute
-    {
-        /// <summary>
-        /// The oneof name in the original .proto file.
-        /// </summary>
-        public string Name { get; set; }
-
-        public ProtobufOneofAttribute(string name)
-        {
-            this.Name = name;
-        }
-    }
-}

+ 1 - 20
csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs

@@ -102,25 +102,6 @@ namespace Google.Protobuf.Reflection
             Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
             Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
             Expression call = Expression.Call(castTarget, method);
             Expression call = Expression.Call(castTarget, method);
             return Expression.Lambda<Action<object>>(call, targetParameter).Compile();
             return Expression.Lambda<Action<object>>(call, targetParameter).Compile();
-        }
-
-        /// <summary>
-        /// Returns the next type from an iterator of types, unless the iterator is a null reference,
-        /// in which case null is returned.
-        /// </summary>
-        internal static Type GetNextType(IEnumerator<Type> generatedTypeIterator)
-        {
-            if (generatedTypeIterator == null)
-            {
-                return null;
-            }
-            if (!generatedTypeIterator.MoveNext())
-            {
-                // This parameter name corresponds to any public method supplying the generated types to start with.
-                throw new ArgumentException("More generated types left over after consuming all expected ones", "generatedTypes");
-            }
-            return generatedTypeIterator.Current;
-        }
-
+        }        
     }
     }
 }
 }

+ 0 - 5
src/google/protobuf/compiler/csharp/csharp_field_base.cc

@@ -74,7 +74,6 @@ void FieldGeneratorBase::SetCommonFieldVariables(
 
 
   (*variables)["property_name"] = property_name();
   (*variables)["property_name"] = property_name();
   (*variables)["type_name"] = type_name();
   (*variables)["type_name"] = type_name();
-  (*variables)["original_name"] = descriptor_->name();
   (*variables)["name"] = name();
   (*variables)["name"] = name();
   (*variables)["descriptor_name"] = descriptor_->name();
   (*variables)["descriptor_name"] = descriptor_->name();
   (*variables)["default_value"] = default_value();
   (*variables)["default_value"] = default_value();
@@ -431,10 +430,6 @@ std::string FieldGeneratorBase::capitalized_type_name() {
   }
   }
 }
 }
 
 
-std::string FieldGeneratorBase::field_ordinal() {
-  return SimpleItoa(fieldOrdinal_);
-}
-
 }  // namespace csharp
 }  // namespace csharp
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf

+ 0 - 1
src/google/protobuf/compiler/csharp/csharp_field_base.h

@@ -85,7 +85,6 @@ class FieldGeneratorBase : public SourceGeneratorBase {
   std::string default_value(const FieldDescriptor* descriptor);
   std::string default_value(const FieldDescriptor* descriptor);
   std::string number();
   std::string number();
   std::string capitalized_type_name();
   std::string capitalized_type_name();
-  std::string field_ordinal();
 
 
  private:
  private:
   void SetCommonFieldVariables(map<string, string>* variables);
   void SetCommonFieldVariables(map<string, string>* variables);

+ 0 - 1
src/google/protobuf/compiler/csharp/csharp_map_field.cc

@@ -79,7 +79,6 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
     "$access_level$ pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "}\n");
     "}\n");

+ 0 - 13
src/google/protobuf/compiler/csharp/csharp_message.cc

@@ -115,19 +115,6 @@ void MessageGenerator::Generate(io::Printer* printer) {
       vars,
       vars,
       "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n"
       "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n"
       "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
       "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
-  printer->Print(
-    "private static readonly string[] _fieldNames = "
-    "new string[] { $slash$$field_names$$slash$ };\n",
-    "field_names", JoinStrings(field_names(), "\", \""),
-      "slash", field_names().size() > 0 ? "\"" : "");
-  std::vector<std::string> tags;
-  for (int i = 0; i < field_names().size(); i++) {
-    uint32 tag = FixedMakeTag(descriptor_->FindFieldByName(field_names()[i]));
-    tags.push_back(SimpleItoa(tag));
-  }
-  printer->Print(
-    "private static readonly uint[] _fieldTags = new uint[] { $tags$ };\n",
-    "tags", JoinStrings(tags, ", "));
 
 
   // Access the message descriptor via the relevant file descriptor or containing message descriptor.
   // Access the message descriptor via the relevant file descriptor or containing message descriptor.
   if (!descriptor_->containing_type()) {
   if (!descriptor_->containing_type()) {

+ 0 - 2
src/google/protobuf/compiler/csharp/csharp_message_field.cc

@@ -64,7 +64,6 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "  set {\n"
     "  set {\n"
@@ -159,7 +158,6 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n"
     "  set {\n"
     "  set {\n"

+ 0 - 2
src/google/protobuf/compiler/csharp/csharp_primitive_field.cc

@@ -71,7 +71,6 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "  set {\n"
     "  set {\n"
@@ -175,7 +174,6 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n"
     "  set {\n"
     "  set {\n"

+ 0 - 1
src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc

@@ -65,7 +65,6 @@ void RepeatedEnumFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "}\n");
     "}\n");

+ 0 - 1
src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc

@@ -78,7 +78,6 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "}\n");
     "}\n");

+ 0 - 1
src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc

@@ -65,7 +65,6 @@ void RepeatedPrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "$access_level$ pbc::RepeatedField<$type_name$> $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "}\n");
     "}\n");

+ 95 - 20
src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc

@@ -36,6 +36,7 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/stubs/strutil.h>
 
 
 
 
 #include <google/protobuf/compiler/csharp/csharp_enum.h>
 #include <google/protobuf/compiler/csharp/csharp_enum.h>
@@ -168,10 +169,10 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
     printer->Print("\"$base64$\", \n", "base64", base64.substr(0, 60));
     printer->Print("\"$base64$\", \n", "base64", base64.substr(0, 60));
     base64 = base64.substr(60);
     base64 = base64.substr(60);
   }
   }
-  printer->Outdent();
   printer->Print("\"$base64$\"));\n", "base64", base64);
   printer->Print("\"$base64$\"));\n", "base64", base64);
   printer->Outdent();
   printer->Outdent();
   printer->Outdent();
   printer->Outdent();
+  printer->Outdent();
 
 
   // -----------------------------------------------------------------
   // -----------------------------------------------------------------
   // Invoke InternalBuildGeneratedFileFrom() to build the file.
   // Invoke InternalBuildGeneratedFileFrom() to build the file.
@@ -184,34 +185,108 @@ void UmbrellaClassGenerator::WriteDescriptor(io::Printer* printer) {
       "full_umbrella_class_name",
       "full_umbrella_class_name",
       GetFullUmbrellaClassName(file_->dependency(i)));
       GetFullUmbrellaClassName(file_->dependency(i)));
   }
   }
-  // Specify all the generated types (messages and enums), recursively, as an array. 
   printer->Print("},\n"
   printer->Print("},\n"
-    "    new global::System.Type[] { ");
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    WriteTypeLiterals(file_->message_type(i), printer);
+      "    new pbr::GeneratedCodeInfo(");
+  // Specify all the generated code information, recursively.
+  if (file_->enum_type_count() > 0) {
+      printer->Print("new[] {");
+      for (int i = 0; i < file_->enum_type_count(); i++) {
+          printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i)));
+      }
+      printer->Print("}, ");
+  }
+  else {
+      printer->Print("null, ");
+  }
+  if (file_->message_type_count() > 0) {
+      printer->Print("new pbr::GeneratedCodeInfo[] {\n");
+      printer->Indent();
+      printer->Indent();
+      printer->Indent();
+      for (int i = 0; i < file_->message_type_count(); i++) {
+          WriteGeneratedCodeInfo(file_->message_type(i), printer, i == file_->message_type_count() - 1);
+      }
+      printer->Outdent();
+      printer->Print("\n}));\n");
+      printer->Outdent();
+      printer->Outdent();
   }
   }
-  for (int i = 0; i < file_->enum_type_count(); i++) {
-    printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i)));
+  else {
+      printer->Print("null));\n");
   }
   }
-  printer->Print("});\n");
 
 
   printer->Outdent();
   printer->Outdent();
   printer->Print("}\n");
   printer->Print("}\n");
   printer->Print("#endregion\n\n");
   printer->Print("#endregion\n\n");
 }
 }
 
 
-void UmbrellaClassGenerator::WriteTypeLiterals(const Descriptor* descriptor, io::Printer* printer) {
-    if (IsMapEntryMessage(descriptor)) {
-        printer->Print("null, ");
-        return;
-    }
-    printer->Print("typeof($type_name$), ", "type_name", GetClassName(descriptor));
-    for (int i = 0; i < descriptor->nested_type_count(); i++) {
-        WriteTypeLiterals(descriptor->nested_type(i), printer);
-    }
-    for (int i = 0; i < descriptor->enum_type_count(); i++) {
-        printer->Print("typeof($type_name$), ", "type_name", GetClassName(descriptor->enum_type(i)));
-    }
+// Write out the generated code for a particular message. This consists of the CLR type, property names
+// corresponding to fields, names corresponding to oneofs, nested enums, and nested types. Each array part
+// can be specified as null if it would be empty, to make the generated code somewhat simpler to read.
+// We write a line break at the end of each generated code info, so that in the final file we'll see all
+// the types, pre-ordered depth first, one per line. The indentation will be slightly unusual,
+// in that it will look like a single array when it's actually constructing a tree, but it'll be easy to
+// read even with multiple levels of nesting.
+// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
+// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
+// just controlling the formatting in the generated code.
+void UmbrellaClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
+  if (IsMapEntryMessage(descriptor)) {
+    printer->Print("null, ");
+    return;
+  }
+  // Generated message type
+  printer->Print("new pbr::GeneratedCodeInfo(typeof($type_name$), ", "type_name", GetClassName(descriptor));
+  
+  // Fields
+  if (descriptor->field_count() > 0) {
+      std::vector<std::string> fields;
+      for (int i = 0; i < descriptor->field_count(); i++) {
+          fields.push_back(GetPropertyName(descriptor->field(i)));
+      }
+      printer->Print("new[]{ \"$fields$\" }, ", "fields", JoinStrings(fields, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Oneofs
+  if (descriptor->oneof_decl_count() > 0) {
+      std::vector<std::string> oneofs;
+      for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
+          oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
+      }
+      printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", JoinStrings(oneofs, "\", \""));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Nested enums
+  if (descriptor->enum_type_count() > 0) {
+      std::vector<std::string> enums;
+      for (int i = 0; i < descriptor->enum_type_count(); i++) {
+          enums.push_back(GetClassName(descriptor->enum_type(i)));
+      }
+      printer->Print("new[]{ typeof($enums$) }, ", "enums", JoinStrings(enums, "), typeof("));
+  }
+  else {
+      printer->Print("null, ");
+  }
+
+  // Nested types
+  if (descriptor->nested_type_count() > 0) {
+      // Need to specify array type explicitly here, as all elements may be null. 
+      printer->Print("new pbr::GeneratedCodeInfo[] { ");
+      for (int i = 0; i < descriptor->nested_type_count(); i++) {
+          WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1);
+      }
+      printer->Print("}");
+  }
+  else {
+      printer->Print("null");
+  }
+  printer->Print(last ? ")" : "),\n");
 }
 }
 
 
 }  // namespace csharp
 }  // namespace csharp

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_umbrella_class.h

@@ -57,7 +57,7 @@ class UmbrellaClassGenerator : public SourceGeneratorBase {
 
 
   void WriteIntroduction(io::Printer* printer);
   void WriteIntroduction(io::Printer* printer);
   void WriteDescriptor(io::Printer* printer);
   void WriteDescriptor(io::Printer* printer);
-  void WriteTypeLiterals(const Descriptor* descriptor, io::Printer* printer);
+  void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last);
 
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator);
 };
 };

+ 0 - 2
src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc

@@ -73,7 +73,6 @@ void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $name$_; }\n"
     "  get { return $name$_; }\n"
     "  set {\n"
     "  set {\n"
@@ -170,7 +169,6 @@ void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
   AddDeprecatedFlag(printer);
   AddDeprecatedFlag(printer);
   printer->Print(
   printer->Print(
     variables_,
     variables_,
-    "[pbr::ProtobufField($number$, \"$original_name$\")]\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "$access_level$ $type_name$ $property_name$ {\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
     "  get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
     "  set {\n"
     "  set {\n"

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно