aboutsummaryrefslogtreecommitdiffhomepage
path: root/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
diff options
context:
space:
mode:
authorGravatar Jon Skeet <jonskeet@google.com>2015-07-20 19:24:31 +0100
committerGravatar Jon Skeet <jonskeet@google.com>2015-07-21 12:59:40 +0100
commit53c399a1d65df65e9f83a70b55041a01cf8d7489 (patch)
treebf3f738dd30295dc8ceb65478b9071d6d654e144 /csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
parent2ee4b5665520fe3245eb5e15df8bd35e0c539a07 (diff)
Revamp to reflection.
Changes in brief: 1. Descriptor is now the entry point for all reflection. 2. IReflectedMessage has gone; there's now a Descriptor property in IMessage, which is explicitly implemented (due to the static property). 3. FieldAccessorTable has gone away 4. IFieldAccessor and OneofFieldAccessor still exist; we *could* put the functionality straight into FieldDescriptor and OneofDescriptor... I'm unsure about that. 5. There's a temporary property MessageDescriptor.FieldAccessorsByFieldNumber to make the test changes small - we probably want this to go away 6. Discovery for delegates is now via attributes applied to properties and the Clear method of a oneof I'm happy with 1-3. 4 I'm unsure about - feedback welcome. 5 will go away 6 I'm unsure about, both in design and implementation. Should we have a ProtobufMessageAttribute too? Should we find all the relevant attributes in MessageDescriptor and pass them down, to avoid an O(N^2) scenario? Generated code changes coming in the next commit.
Diffstat (limited to 'csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs')
-rw-r--r--csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs36
1 files changed, 29 insertions, 7 deletions
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index db393480..a10e617b 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -62,11 +62,12 @@ namespace Google.Protobuf.Reflection
get { return proto.Syntax == "proto3" ? ProtoSyntax.Proto3 : ProtoSyntax.Proto2; }
}
- private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies)
+ private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, Type[] generatedTypes)
{
this.pool = pool;
this.proto = proto;
this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
+ IEnumerator<Type> generatedTypeIterator = generatedTypes == null ? null : ((IEnumerable<Type>)generatedTypes).GetEnumerator();
publicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
@@ -74,15 +75,21 @@ namespace Google.Protobuf.Reflection
messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
(message, index) =>
- new MessageDescriptor(message, this, null, index));
+ new MessageDescriptor(message, this, null, index, generatedTypeIterator));
enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
(enumType, index) =>
- new EnumDescriptor(enumType, this, null, index));
+ new EnumDescriptor(enumType, this, null, index, ReflectionUtil.GetNextType(generatedTypeIterator)));
services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
(service, 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>
@@ -265,7 +272,7 @@ namespace Google.Protobuf.Reflection
/// <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>
- private static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies)
+ private static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, Type[] generatedTypes)
{
// Building descriptors involves two steps: translating and linking.
// In the translation step (implemented by FileDescriptor's
@@ -282,7 +289,7 @@ namespace Google.Protobuf.Reflection
}
DescriptorPool pool = new DescriptorPool(dependencies);
- FileDescriptor result = new FileDescriptor(proto, dependencies, pool, allowUnknownDependencies);
+ FileDescriptor result = new FileDescriptor(proto, dependencies, pool, allowUnknownDependencies, generatedTypes);
// 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".)
@@ -319,8 +326,23 @@ namespace Google.Protobuf.Reflection
}
}
+ /// <summary>
+ /// Creates an instance for generated code.
+ /// </summary>
+ /// <remarks>
+ /// The <paramref name="generatedTypes"/> parameter should be null for descriptors which don't correspond to
+ /// generated types. Otherwise, the array should be 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.
+ /// </remarks>
public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
- FileDescriptor[] dependencies)
+ FileDescriptor[] dependencies,
+ Type[] generatedTypes)
{
FileDescriptorProto proto;
try
@@ -336,7 +358,7 @@ namespace Google.Protobuf.Reflection
{
// When building descriptors for generated code, we allow unknown
// dependencies by default.
- return BuildFrom(proto, dependencies, true);
+ return BuildFrom(proto, dependencies, true, generatedTypes);
}
catch (DescriptorValidationException e)
{