1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <sstream>
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/code_generator.h>
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/plugin.h>
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/descriptor.h>
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/descriptor.pb.h>
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/io/printer.h>
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/io/zero_copy_stream.h>
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/strutil.h>
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_enum.h>
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_helpers.h>
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_message.h>
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_names.h>
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_options.h>
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/compiler/csharp/csharp_reflection_class.h>
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace google {
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace protobuf {
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace compiler {
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace csharp {
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file,
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                   const Options* options)
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : SourceGeneratorBase(file, options),
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      file_(file) {
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  namespace_ = GetFileNamespace(file);
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  reflectionClassname_ = GetReflectionClassUnqualifiedName(file);
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerReflectionClassGenerator::~ReflectionClassGenerator() {
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ReflectionClassGenerator::Generate(io::Printer* printer) {
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  WriteIntroduction(printer);
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  WriteDescriptor(printer);
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Close the class declaration.
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Outdent();
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("}\n");
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // write children: Enums
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (file_->enum_type_count() > 0) {
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#region Enums\n");
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (int i = 0; i < file_->enum_type_count(); i++) {
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      EnumGenerator enumGenerator(file_->enum_type(i), this->options());
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      enumGenerator.Generate(printer);
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#endregion\n");
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("\n");
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // write children: Messages
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (file_->message_type_count() > 0) {
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#region Messages\n");
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    for (int i = 0; i < file_->message_type_count(); i++) {
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      MessageGenerator messageGenerator(file_->message_type(i), this->options());
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      messageGenerator.Generate(printer);
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("#endregion\n");
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("\n");
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(jtattermusch): add insertion point for services.
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!namespace_.empty()) {
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Outdent();
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("}\n");
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("\n");
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("#endregion Designer generated code\n");
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "// source: $file_name$\n"
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "#pragma warning disable 1591, 0612, 3021\n"
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "#region Designer generated code\n"
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "\n"
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "using pb = global::Google.Protobuf;\n"
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "using pbc = global::Google.Protobuf.Collections;\n"
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "using pbr = global::Google.Protobuf.Reflection;\n"
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "using scg = global::System.Collections.Generic;\n",
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "file_name", file_->name());
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!namespace_.empty()) {
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("namespace $namespace$ {\n", "namespace", namespace_);
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Indent();
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("\n");
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "/// <summary>Holder for reflection information generated from $file_name$</summary>\n"
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n",
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "file_name", file_->name());
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  WriteGeneratedCodeAttributes(printer);
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "$access_level$ static partial class $reflection_class_name$ {\n"
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "\n",
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "access_level", class_access_level(),
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "reflection_class_name", reflectionClassname_);
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Indent();
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ReflectionClassGenerator::WriteDescriptor(io::Printer* printer) {
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "#region Descriptor\n"
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "/// <summary>File descriptor for $file_name$</summary>\n"
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "public static pbr::FileDescriptor Descriptor {\n"
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "  get { return descriptor; }\n"
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "}\n"
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "private static pbr::FileDescriptor descriptor;\n"
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "\n"
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "static $reflection_class_name$() {\n",
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "file_name", file_->name(),
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "reflection_class_name", reflectionClassname_);
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Indent();
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    "byte[] descriptorData = global::System.Convert.FromBase64String(\n");
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Indent();
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Indent();
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("string.Concat(\n");
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Indent();
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64.
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  std::string base64 = FileDescriptorToBase64(file_);
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (base64.size() > 60) {
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("\"$base64$\",\n", "base64", base64.substr(0, 60));
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    base64 = base64.substr(60);
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("\"$base64$\"));\n", "base64", base64);
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Outdent();
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Outdent();
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Outdent();
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // -----------------------------------------------------------------
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Invoke InternalBuildGeneratedFileFrom() to build the file.
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,\n");
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("    new pbr::FileDescriptor[] { ");
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  for (int i = 0; i < file_->dependency_count(); i++) {
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // descriptor.proto is special: we don't allow access to the generated code, but there's
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // a separately-exposed property to get at the file descriptor, specifically to allow this
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // kind of dependency.
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (IsDescriptorProto(file_->dependency(i))) {
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("pbr::FileDescriptor.DescriptorProtoFileDescriptor, ");
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print(
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "$full_reflection_class_name$.Descriptor, ",
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "full_reflection_class_name",
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      GetReflectionClassName(file_->dependency(i)));
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("},\n"
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "    new pbr::GeneratedClrTypeInfo(");
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Specify all the generated code information, recursively.
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (file_->enum_type_count() > 0) {
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new[] {");
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < file_->enum_type_count(); i++) {
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          printer->Print("typeof($type_name$), ", "type_name", GetClassName(file_->enum_type(i)));
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("}, ");
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null, ");
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (file_->message_type_count() > 0) {
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new pbr::GeneratedClrTypeInfo[] {\n");
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Indent();
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Indent();
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Indent();
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < file_->message_type_count(); i++) {
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          WriteGeneratedCodeInfo(file_->message_type(i), printer, i == file_->message_type_count() - 1);
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Outdent();
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("\n}));\n");
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Outdent();
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Outdent();
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null));\n");
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Outdent();
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("}\n");
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("#endregion\n\n");
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Write out the generated code for a particular message. This consists of the CLR type, property names
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// corresponding to fields, names corresponding to oneofs, nested enums, and nested types. Each array part
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// can be specified as null if it would be empty, to make the generated code somewhat simpler to read.
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// We write a line break at the end of each generated code info, so that in the final file we'll see all
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// the types, pre-ordered depth first, one per line. The indentation will be slightly unusual,
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in that it will look like a single array when it's actually constructing a tree, but it'll be easy to
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// read even with multiple levels of nesting.
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// The "last" parameter indicates whether this message descriptor is the last one being printed in this immediate
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// context. It governs whether or not a trailing comma and newline is written after the constructor, effectively
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// just controlling the formatting in the generated code.
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last) {
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsMapEntryMessage(descriptor)) {
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    printer->Print("null, ");
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Generated message type
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print("new pbr::GeneratedClrTypeInfo(typeof($type_name$), $type_name$.Parser, ", "type_name", GetClassName(descriptor));
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Fields
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (descriptor->field_count() > 0) {
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      std::vector<std::string> fields;
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < descriptor->field_count(); i++) {
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          fields.push_back(GetPropertyName(descriptor->field(i)));
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new[]{ \"$fields$\" }, ", "fields", JoinStrings(fields, "\", \""));
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null, ");
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Oneofs
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (descriptor->oneof_decl_count() > 0) {
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      std::vector<std::string> oneofs;
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new[]{ \"$oneofs$\" }, ", "oneofs", JoinStrings(oneofs, "\", \""));
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null, ");
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Nested enums
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (descriptor->enum_type_count() > 0) {
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      std::vector<std::string> enums;
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < descriptor->enum_type_count(); i++) {
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          enums.push_back(GetClassName(descriptor->enum_type(i)));
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new[]{ typeof($enums$) }, ", "enums", JoinStrings(enums, "), typeof("));
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null, ");
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Nested types
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (descriptor->nested_type_count() > 0) {
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Need to specify array type explicitly here, as all elements may be null.
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("new pbr::GeneratedClrTypeInfo[] { ");
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      for (int i = 0; i < descriptor->nested_type_count(); i++) {
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          WriteGeneratedCodeInfo(descriptor->nested_type(i), printer, i == descriptor->nested_type_count() - 1);
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("}");
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  else {
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      printer->Print("null");
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  printer->Print(last ? ")" : "),\n");
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace csharp
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace compiler
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace protobuf
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace google
294