| 1 | // Protocol Buffers - Google's data interchange format | 
| 2 | // Copyright 2008 Google Inc.  All rights reserved. | 
| 3 | // https://developers.google.com/protocol-buffers/ | 
| 4 | // | 
| 5 | // Redistribution and use in source and binary forms, with or without | 
| 6 | // modification, are permitted provided that the following conditions are | 
| 7 | // met: | 
| 8 | // | 
| 9 | //     * Redistributions of source code must retain the above copyright | 
| 10 | // notice, this list of conditions and the following disclaimer. | 
| 11 | //     * Redistributions in binary form must reproduce the above | 
| 12 | // copyright notice, this list of conditions and the following disclaimer | 
| 13 | // in the documentation and/or other materials provided with the | 
| 14 | // distribution. | 
| 15 | //     * Neither the name of Google Inc. nor the names of its | 
| 16 | // contributors may be used to endorse or promote products derived from | 
| 17 | // this software without specific prior written permission. | 
| 18 | // | 
| 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 30 |  | 
| 31 | // Author: kenton@google.com (Kenton Varda) | 
| 32 | //  Based on original Protocol Buffers design by | 
| 33 | //  Sanjay Ghemawat, Jeff Dean, and others. | 
| 34 |  | 
| 35 | #include <google/protobuf/compiler/java/file.h> | 
| 36 |  | 
| 37 | #include <memory> | 
| 38 | #include <set> | 
| 39 |  | 
| 40 | #include <google/protobuf/compiler/code_generator.h> | 
| 41 | #include <google/protobuf/io/printer.h> | 
| 42 | #include <google/protobuf/io/zero_copy_stream.h> | 
| 43 | #include <google/protobuf/dynamic_message.h> | 
| 44 | #include <google/protobuf/stubs/strutil.h> | 
| 45 | #include <google/protobuf/compiler/java/context.h> | 
| 46 | #include <google/protobuf/compiler/java/enum.h> | 
| 47 | #include <google/protobuf/compiler/java/enum_lite.h> | 
| 48 | #include <google/protobuf/compiler/java/extension.h> | 
| 49 | #include <google/protobuf/compiler/java/generator_factory.h> | 
| 50 | #include <google/protobuf/compiler/java/helpers.h> | 
| 51 | #include <google/protobuf/compiler/java/message.h> | 
| 52 | #include <google/protobuf/compiler/java/name_resolver.h> | 
| 53 | #include <google/protobuf/compiler/java/service.h> | 
| 54 | #include <google/protobuf/compiler/java/shared_code_generator.h> | 
| 55 | #include <google/protobuf/descriptor.pb.h> | 
| 56 |  | 
| 57 | // Must be last. | 
| 58 | #include <google/protobuf/port_def.inc> | 
| 59 |  | 
| 60 | namespace google { | 
| 61 | namespace protobuf { | 
| 62 | namespace compiler { | 
| 63 | namespace java { | 
| 64 |  | 
| 65 | namespace { | 
| 66 |  | 
| 67 | struct FieldDescriptorCompare { | 
| 68 |   bool operator()(const FieldDescriptor* f1, const FieldDescriptor* f2) const { | 
| 69 |     if (f1 == NULL) { | 
| 70 |       return false; | 
| 71 |     } | 
| 72 |     if (f2 == NULL) { | 
| 73 |       return true; | 
| 74 |     } | 
| 75 |     return f1->full_name() < f2->full_name(); | 
| 76 |   } | 
| 77 | }; | 
| 78 |  | 
| 79 | typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> | 
| 80 |     FieldDescriptorSet; | 
| 81 |  | 
| 82 | // Recursively searches the given message to collect extensions. | 
| 83 | // Returns true if all the extensions can be recognized. The extensions will be | 
| 84 | // appended in to the extensions parameter. | 
| 85 | // Returns false when there are unknown fields, in which case the data in the | 
| 86 | // extensions output parameter is not reliable and should be discarded. | 
| 87 | bool CollectExtensions(const Message& message, FieldDescriptorSet* extensions) { | 
| 88 |   const Reflection* reflection = message.GetReflection(); | 
| 89 |  | 
| 90 |   // There are unknown fields that could be extensions, thus this call fails. | 
| 91 |   if (reflection->GetUnknownFields(message).field_count() > 0) return false; | 
| 92 |  | 
| 93 |   std::vector<const FieldDescriptor*> fields; | 
| 94 |   reflection->ListFields(message, output: &fields); | 
| 95 |  | 
| 96 |   for (int i = 0; i < fields.size(); i++) { | 
| 97 |     if (fields[i]->is_extension()) { | 
| 98 |       extensions->insert(x: fields[i]); | 
| 99 |     } | 
| 100 |  | 
| 101 |     if (GetJavaType(field: fields[i]) == JAVATYPE_MESSAGE) { | 
| 102 |       if (fields[i]->is_repeated()) { | 
| 103 |         int size = reflection->FieldSize(message, field: fields[i]); | 
| 104 |         for (int j = 0; j < size; j++) { | 
| 105 |           const Message& sub_message = | 
| 106 |               reflection->GetRepeatedMessage(message, field: fields[i], index: j); | 
| 107 |           if (!CollectExtensions(message: sub_message, extensions)) return false; | 
| 108 |         } | 
| 109 |       } else { | 
| 110 |         const Message& sub_message = reflection->GetMessage(message, field: fields[i]); | 
| 111 |         if (!CollectExtensions(message: sub_message, extensions)) return false; | 
| 112 |       } | 
| 113 |     } | 
| 114 |   } | 
| 115 |  | 
| 116 |   return true; | 
| 117 | } | 
| 118 |  | 
| 119 | // Finds all extensions in the given message and its sub-messages.  If the | 
| 120 | // message contains unknown fields (which could be extensions), then those | 
| 121 | // extensions are defined in alternate_pool. | 
| 122 | // The message will be converted to a DynamicMessage backed by alternate_pool | 
| 123 | // in order to handle this case. | 
| 124 | void CollectExtensions(const FileDescriptorProto& file_proto, | 
| 125 |                        const DescriptorPool& alternate_pool, | 
| 126 |                        FieldDescriptorSet* extensions, | 
| 127 |                        const std::string& file_data) { | 
| 128 |   if (!CollectExtensions(message: file_proto, extensions)) { | 
| 129 |     // There are unknown fields in the file_proto, which are probably | 
| 130 |     // extensions. We need to parse the data into a dynamic message based on the | 
| 131 |     // builder-pool to find out all extensions. | 
| 132 |     const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName( | 
| 133 |         name: file_proto.GetDescriptor()->full_name()); | 
| 134 |     GOOGLE_CHECK(file_proto_desc) | 
| 135 |         << "Find unknown fields in FileDescriptorProto when building "  | 
| 136 |         << file_proto.name() | 
| 137 |         << ". It's likely that those fields are custom options, however, "  | 
| 138 |            "descriptor.proto is not in the transitive dependencies. "  | 
| 139 |            "This normally should not happen. Please report a bug." ; | 
| 140 |     DynamicMessageFactory factory; | 
| 141 |     std::unique_ptr<Message> dynamic_file_proto( | 
| 142 |         factory.GetPrototype(type: file_proto_desc)->New()); | 
| 143 |     GOOGLE_CHECK(dynamic_file_proto.get() != NULL); | 
| 144 |     GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data)); | 
| 145 |  | 
| 146 |     // Collect the extensions again from the dynamic message. There should be no | 
| 147 |     // more unknown fields this time, i.e. all the custom options should be | 
| 148 |     // parsed as extensions now. | 
| 149 |     extensions->clear(); | 
| 150 |     GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions)) | 
| 151 |         << "Find unknown fields in FileDescriptorProto when building "  | 
| 152 |         << file_proto.name() | 
| 153 |         << ". It's likely that those fields are custom options, however, "  | 
| 154 |            "those options cannot be recognized in the builder pool. "  | 
| 155 |            "This normally should not happen. Please report a bug." ; | 
| 156 |   } | 
| 157 | } | 
| 158 |  | 
| 159 | // Our static initialization methods can become very, very large. | 
| 160 | // So large that if we aren't careful we end up blowing the JVM's | 
| 161 | // 64K bytes of bytecode/method. Fortunately, since these static | 
| 162 | // methods are executed only once near the beginning of a program, | 
| 163 | // there's usually plenty of stack space available and we can | 
| 164 | // extend our methods by simply chaining them to another method | 
| 165 | // with a tail call. This inserts the sequence call-next-method, | 
| 166 | // end this one, begin-next-method as needed. | 
| 167 | void MaybeRestartJavaMethod(io::Printer* printer, int* bytecode_estimate, | 
| 168 |                             int* method_num, const char* chain_statement, | 
| 169 |                             const char* method_decl) { | 
| 170 |   // The goal here is to stay under 64K bytes of jvm bytecode/method, | 
| 171 |   // since otherwise we hit a hardcoded limit in the jvm and javac will | 
| 172 |   // then fail with the error "code too large". This limit lets our | 
| 173 |   // estimates be off by a factor of two and still we're okay. | 
| 174 |   static const int bytesPerMethod = kMaxStaticSize; | 
| 175 |  | 
| 176 |   if ((*bytecode_estimate) > bytesPerMethod) { | 
| 177 |     ++(*method_num); | 
| 178 |     printer->Print(text: chain_statement, args: "method_num" , args: StrCat(a: *method_num)); | 
| 179 |     printer->Outdent(); | 
| 180 |     printer->Print(text: "}\n" ); | 
| 181 |     printer->Print(text: method_decl, args: "method_num" , args: StrCat(a: *method_num)); | 
| 182 |     printer->Indent(); | 
| 183 |     *bytecode_estimate = 0; | 
| 184 |   } | 
| 185 | } | 
| 186 | }  // namespace | 
| 187 |  | 
| 188 | FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options, | 
| 189 |                              bool immutable_api) | 
| 190 |     : file_(file), | 
| 191 |       java_package_(FileJavaPackage(file, immutable: immutable_api)), | 
| 192 |       message_generators_(file->message_type_count()), | 
| 193 |       extension_generators_(file->extension_count()), | 
| 194 |       context_(new Context(file, options)), | 
| 195 |       name_resolver_(context_->GetNameResolver()), | 
| 196 |       options_(options), | 
| 197 |       immutable_api_(immutable_api) { | 
| 198 |   classname_ = name_resolver_->GetFileClassName(file, immutable: immutable_api); | 
| 199 |   generator_factory_.reset(p: new ImmutableGeneratorFactory(context_.get())); | 
| 200 |   for (int i = 0; i < file_->message_type_count(); ++i) { | 
| 201 |     message_generators_[i].reset( | 
| 202 |         p: generator_factory_->NewMessageGenerator(descriptor: file_->message_type(index: i))); | 
| 203 |   } | 
| 204 |   for (int i = 0; i < file_->extension_count(); ++i) { | 
| 205 |     extension_generators_[i].reset( | 
| 206 |         p: generator_factory_->NewExtensionGenerator(descriptor: file_->extension(index: i))); | 
| 207 |   } | 
| 208 | } | 
| 209 |  | 
| 210 | FileGenerator::~FileGenerator() {} | 
| 211 |  | 
| 212 | bool FileGenerator::Validate(std::string* error) { | 
| 213 |   // Check that no class name matches the file's class name.  This is a common | 
| 214 |   // problem that leads to Java compile errors that can be hard to understand. | 
| 215 |   // It's especially bad when using the java_multiple_files, since we would | 
| 216 |   // end up overwriting the outer class with one of the inner ones. | 
| 217 |   if (name_resolver_->HasConflictingClassName(file: file_, classname: classname_, | 
| 218 |                                               equality_mode: NameEquality::EXACT_EQUAL)) { | 
| 219 |     error->assign(str: file_->name()); | 
| 220 |     error->append( | 
| 221 |         s: ": Cannot generate Java output because the file's outer class name, "  | 
| 222 |         "\"" ); | 
| 223 |     error->append(str: classname_); | 
| 224 |     error->append( | 
| 225 |         s: "\", matches the name of one of the types declared inside it.  "  | 
| 226 |         "Please either rename the type or use the java_outer_classname "  | 
| 227 |         "option to specify a different outer class name for the .proto file." ); | 
| 228 |     return false; | 
| 229 |   } | 
| 230 |   // Similar to the check above, but ignore the case this time. This is not a | 
| 231 |   // problem on Linux, but will lead to Java compile errors on Windows / Mac | 
| 232 |   // because filenames are case-insensitive on those platforms. | 
| 233 |   if (name_resolver_->HasConflictingClassName( | 
| 234 |           file: file_, classname: classname_, equality_mode: NameEquality::EQUAL_IGNORE_CASE)) { | 
| 235 |     GOOGLE_LOG(WARNING) | 
| 236 |         << file_->name() << ": The file's outer class name, \""  << classname_ | 
| 237 |         << "\", matches the name of one of the types declared inside it when "  | 
| 238 |         << "case is ignored. This can cause compilation issues on Windows / "  | 
| 239 |         << "MacOS. Please either rename the type or use the "  | 
| 240 |         << "java_outer_classname option to specify a different outer class "  | 
| 241 |         << "name for the .proto file to be safe." ; | 
| 242 |   } | 
| 243 |  | 
| 244 |   // Print a warning if optimize_for = LITE_RUNTIME is used. | 
| 245 |   if (file_->options().optimize_for() == FileOptions::LITE_RUNTIME && | 
| 246 |       !options_.enforce_lite) { | 
| 247 |     GOOGLE_LOG(WARNING) | 
| 248 |         << "The optimize_for = LITE_RUNTIME option is no longer supported by "  | 
| 249 |         << "protobuf Java code generator and is ignored--protoc will always "  | 
| 250 |         << "generate full runtime code for Java. To use Java Lite runtime, "  | 
| 251 |         << "users should use the Java Lite plugin instead. See:\n"  | 
| 252 |         << "  "  | 
| 253 |            "https://github.com/protocolbuffers/protobuf/blob/main/java/"  | 
| 254 |            "lite.md" ; | 
| 255 |   } | 
| 256 |   return true; | 
| 257 | } | 
| 258 |  | 
| 259 | void FileGenerator::Generate(io::Printer* printer) { | 
| 260 |   // We don't import anything because we refer to all classes by their | 
| 261 |   // fully-qualified names in the generated source. | 
| 262 |   printer->Print( | 
| 263 |       text: "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"  | 
| 264 |       "// source: $filename$\n"  | 
| 265 |       "\n" , | 
| 266 |       args: "filename" , args: file_->name()); | 
| 267 |   if (!java_package_.empty()) { | 
| 268 |     printer->Print( | 
| 269 |         text: "package $package$;\n"  | 
| 270 |         "\n" , | 
| 271 |         args: "package" , args: java_package_); | 
| 272 |   } | 
| 273 |   PrintGeneratedAnnotation( | 
| 274 |       printer, delimiter: '$', annotation_file: options_.annotate_code ? classname_ + ".java.pb.meta"  : "" ); | 
| 275 |  | 
| 276 |   printer->Print( | 
| 277 |       text: "$deprecation$public final class $classname$ {\n"  | 
| 278 |       "  private $ctor$() {}\n" , | 
| 279 |       args: "deprecation" , | 
| 280 |       args: file_->options().deprecated() ? "@java.lang.Deprecated "  : "" , | 
| 281 |       args: "classname" , args: classname_, args: "ctor" , args: classname_); | 
| 282 |   printer->Annotate(varname: "classname" , file_name: file_->name()); | 
| 283 |   printer->Indent(); | 
| 284 |  | 
| 285 |   // ----------------------------------------------------------------- | 
| 286 |  | 
| 287 |   printer->Print( | 
| 288 |       text: "public static void registerAllExtensions(\n"  | 
| 289 |       "    com.google.protobuf.ExtensionRegistryLite registry) {\n" ); | 
| 290 |  | 
| 291 |   printer->Indent(); | 
| 292 |  | 
| 293 |   for (int i = 0; i < file_->extension_count(); i++) { | 
| 294 |     extension_generators_[i]->GenerateRegistrationCode(printer); | 
| 295 |   } | 
| 296 |  | 
| 297 |   for (int i = 0; i < file_->message_type_count(); i++) { | 
| 298 |     message_generators_[i]->GenerateExtensionRegistrationCode(printer); | 
| 299 |   } | 
| 300 |  | 
| 301 |   printer->Outdent(); | 
| 302 |   printer->Print(text: "}\n" ); | 
| 303 |   if (HasDescriptorMethods(file_, enforce_lite: context_->EnforceLite())) { | 
| 304 |     // Overload registerAllExtensions for the non-lite usage to | 
| 305 |     // redundantly maintain the original signature (this is | 
| 306 |     // redundant because ExtensionRegistryLite now invokes | 
| 307 |     // ExtensionRegistry in the non-lite usage). Intent is | 
| 308 |     // to remove this in the future. | 
| 309 |     printer->Print( | 
| 310 |         text: "\n"  | 
| 311 |         "public static void registerAllExtensions(\n"  | 
| 312 |         "    com.google.protobuf.ExtensionRegistry registry) {\n"  | 
| 313 |         "  registerAllExtensions(\n"  | 
| 314 |         "      (com.google.protobuf.ExtensionRegistryLite) registry);\n"  | 
| 315 |         "}\n" ); | 
| 316 |   } | 
| 317 |  | 
| 318 |   // ----------------------------------------------------------------- | 
| 319 |  | 
| 320 |   if (!MultipleJavaFiles(descriptor: file_, immutable: immutable_api_)) { | 
| 321 |     for (int i = 0; i < file_->enum_type_count(); i++) { | 
| 322 |       if (HasDescriptorMethods(file_, enforce_lite: context_->EnforceLite())) { | 
| 323 |         EnumGenerator(file_->enum_type(index: i), immutable_api_, context_.get()) | 
| 324 |             .Generate(printer); | 
| 325 |       } else { | 
| 326 |         EnumLiteGenerator(file_->enum_type(index: i), immutable_api_, context_.get()) | 
| 327 |             .Generate(printer); | 
| 328 |       } | 
| 329 |     } | 
| 330 |     for (int i = 0; i < file_->message_type_count(); i++) { | 
| 331 |       message_generators_[i]->GenerateInterface(printer); | 
| 332 |       message_generators_[i]->Generate(printer); | 
| 333 |     } | 
| 334 |     if (HasGenericServices(file: file_, enforce_lite: context_->EnforceLite())) { | 
| 335 |       for (int i = 0; i < file_->service_count(); i++) { | 
| 336 |         std::unique_ptr<ServiceGenerator> generator( | 
| 337 |             generator_factory_->NewServiceGenerator(descriptor: file_->service(index: i))); | 
| 338 |         generator->Generate(printer); | 
| 339 |       } | 
| 340 |     } | 
| 341 |   } | 
| 342 |  | 
| 343 |   // Extensions must be generated in the outer class since they are values, | 
| 344 |   // not classes. | 
| 345 |   for (int i = 0; i < file_->extension_count(); i++) { | 
| 346 |     extension_generators_[i]->Generate(printer); | 
| 347 |   } | 
| 348 |  | 
| 349 |   // Static variables. We'd like them to be final if possible, but due to | 
| 350 |   // the JVM's 64k size limit on static blocks, we have to initialize some | 
| 351 |   // of them in methods; thus they cannot be final. | 
| 352 |   int static_block_bytecode_estimate = 0; | 
| 353 |   for (int i = 0; i < file_->message_type_count(); i++) { | 
| 354 |     message_generators_[i]->GenerateStaticVariables( | 
| 355 |         printer, bytecode_estimate: &static_block_bytecode_estimate); | 
| 356 |   } | 
| 357 |  | 
| 358 |   printer->Print(text: "\n" ); | 
| 359 |  | 
| 360 |   if (HasDescriptorMethods(file_, enforce_lite: context_->EnforceLite())) { | 
| 361 |     if (immutable_api_) { | 
| 362 |       GenerateDescriptorInitializationCodeForImmutable(printer); | 
| 363 |     } else { | 
| 364 |       GenerateDescriptorInitializationCodeForMutable(printer); | 
| 365 |     } | 
| 366 |   } else { | 
| 367 |     printer->Print(text: "static {\n" ); | 
| 368 |     printer->Indent(); | 
| 369 |     int bytecode_estimate = 0; | 
| 370 |     int method_num = 0; | 
| 371 |  | 
| 372 |     for (int i = 0; i < file_->message_type_count(); i++) { | 
| 373 |       bytecode_estimate += | 
| 374 |           message_generators_[i]->GenerateStaticVariableInitializers(printer); | 
| 375 |       MaybeRestartJavaMethod( | 
| 376 |           printer, bytecode_estimate: &bytecode_estimate, method_num: &method_num, | 
| 377 |           chain_statement: "_clinit_autosplit_$method_num$();\n" , | 
| 378 |           method_decl: "private static void _clinit_autosplit_$method_num$() {\n" ); | 
| 379 |     } | 
| 380 |  | 
| 381 |     printer->Outdent(); | 
| 382 |     printer->Print(text: "}\n" ); | 
| 383 |   } | 
| 384 |  | 
| 385 |   printer->Print( | 
| 386 |       text: "\n"  | 
| 387 |       "// @@protoc_insertion_point(outer_class_scope)\n" ); | 
| 388 |  | 
| 389 |   printer->Outdent(); | 
| 390 |   printer->Print(text: "}\n" ); | 
| 391 | } | 
| 392 |  | 
| 393 | void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( | 
| 394 |     io::Printer* printer) { | 
| 395 |   printer->Print( | 
| 396 |       text: "public static com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 397 |       "    getDescriptor() {\n"  | 
| 398 |       "  return descriptor;\n"  | 
| 399 |       "}\n"  | 
| 400 |       "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 401 |       "    descriptor;\n"  | 
| 402 |       "static {\n" , | 
| 403 |       // TODO(dweis): Mark this as final. | 
| 404 |       args: "final" , args: "" ); | 
| 405 |   printer->Indent(); | 
| 406 |  | 
| 407 |   SharedCodeGenerator shared_code_generator(file_, options_); | 
| 408 |   shared_code_generator.GenerateDescriptors(printer); | 
| 409 |  | 
| 410 |   int bytecode_estimate = 0; | 
| 411 |   int method_num = 0; | 
| 412 |  | 
| 413 |   for (int i = 0; i < file_->message_type_count(); i++) { | 
| 414 |     bytecode_estimate += | 
| 415 |         message_generators_[i]->GenerateStaticVariableInitializers(printer); | 
| 416 |     MaybeRestartJavaMethod( | 
| 417 |         printer, bytecode_estimate: &bytecode_estimate, method_num: &method_num, | 
| 418 |         chain_statement: "_clinit_autosplit_dinit_$method_num$();\n" , | 
| 419 |         method_decl: "private static void _clinit_autosplit_dinit_$method_num$() {\n" ); | 
| 420 |   } | 
| 421 |   for (int i = 0; i < file_->extension_count(); i++) { | 
| 422 |     bytecode_estimate += | 
| 423 |         extension_generators_[i]->GenerateNonNestedInitializationCode(printer); | 
| 424 |     MaybeRestartJavaMethod( | 
| 425 |         printer, bytecode_estimate: &bytecode_estimate, method_num: &method_num, | 
| 426 |         chain_statement: "_clinit_autosplit_dinit_$method_num$();\n" , | 
| 427 |         method_decl: "private static void _clinit_autosplit_dinit_$method_num$() {\n" ); | 
| 428 |   } | 
| 429 |  | 
| 430 |   // Proto compiler builds a DescriptorPool, which holds all the descriptors to | 
| 431 |   // generate, when processing the ".proto" files. We call this DescriptorPool | 
| 432 |   // the parsed pool (a.k.a. file_->pool()). | 
| 433 |   // | 
| 434 |   // Note that when users try to extend the (.*)DescriptorProto in their | 
| 435 |   // ".proto" files, it does not affect the pre-built FileDescriptorProto class | 
| 436 |   // in proto compiler. When we put the descriptor data in the file_proto, those | 
| 437 |   // extensions become unknown fields. | 
| 438 |   // | 
| 439 |   // Now we need to find out all the extension value to the (.*)DescriptorProto | 
| 440 |   // in the file_proto message, and prepare an ExtensionRegistry to return. | 
| 441 |   // | 
| 442 |   // To find those extensions, we need to parse the data into a dynamic message | 
| 443 |   // of the FileDescriptor based on the builder-pool, then we can use | 
| 444 |   // reflections to find all extension fields | 
| 445 |   FileDescriptorProto file_proto; | 
| 446 |   file_->CopyTo(proto: &file_proto); | 
| 447 |   std::string file_data; | 
| 448 |   file_proto.SerializeToString(output: &file_data); | 
| 449 |   FieldDescriptorSet extensions; | 
| 450 |   CollectExtensions(file_proto, alternate_pool: *file_->pool(), extensions: &extensions, file_data); | 
| 451 |  | 
| 452 |   if (extensions.size() > 0) { | 
| 453 |     // Must construct an ExtensionRegistry containing all existing extensions | 
| 454 |     // and use it to parse the descriptor data again to recognize extensions. | 
| 455 |     printer->Print( | 
| 456 |         text: "com.google.protobuf.ExtensionRegistry registry =\n"  | 
| 457 |         "    com.google.protobuf.ExtensionRegistry.newInstance();\n" ); | 
| 458 |     FieldDescriptorSet::iterator it; | 
| 459 |     for (it = extensions.begin(); it != extensions.end(); it++) { | 
| 460 |       std::unique_ptr<ExtensionGenerator> generator( | 
| 461 |           generator_factory_->NewExtensionGenerator(descriptor: *it)); | 
| 462 |       bytecode_estimate += generator->GenerateRegistrationCode(printer); | 
| 463 |       MaybeRestartJavaMethod( | 
| 464 |           printer, bytecode_estimate: &bytecode_estimate, method_num: &method_num, | 
| 465 |           chain_statement: "_clinit_autosplit_dinit_$method_num$(registry);\n" , | 
| 466 |           method_decl: "private static void _clinit_autosplit_dinit_$method_num$(\n"  | 
| 467 |           "    com.google.protobuf.ExtensionRegistry registry) {\n" ); | 
| 468 |     } | 
| 469 |     printer->Print( | 
| 470 |         text: "com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 471 |         "    .internalUpdateFileDescriptor(descriptor, registry);\n" ); | 
| 472 |   } | 
| 473 |  | 
| 474 |   // Force descriptor initialization of all dependencies. | 
| 475 |   for (int i = 0; i < file_->dependency_count(); i++) { | 
| 476 |     if (ShouldIncludeDependency(descriptor: file_->dependency(index: i), immutable_api_: true)) { | 
| 477 |       std::string dependency = | 
| 478 |           name_resolver_->GetImmutableClassName(descriptor: file_->dependency(index: i)); | 
| 479 |       printer->Print(text: "$dependency$.getDescriptor();\n" , args: "dependency" , | 
| 480 |                      args: dependency); | 
| 481 |     } | 
| 482 |   } | 
| 483 |  | 
| 484 |   printer->Outdent(); | 
| 485 |   printer->Print(text: "}\n" ); | 
| 486 | } | 
| 487 |  | 
| 488 | void FileGenerator::GenerateDescriptorInitializationCodeForMutable( | 
| 489 |     io::Printer* printer) { | 
| 490 |   printer->Print( | 
| 491 |       text: "public static com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 492 |       "    getDescriptor() {\n"  | 
| 493 |       "  return descriptor;\n"  | 
| 494 |       "}\n"  | 
| 495 |       "private static final com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 496 |       "    descriptor;\n"  | 
| 497 |       "static {\n" ); | 
| 498 |   printer->Indent(); | 
| 499 |  | 
| 500 |   printer->Print( | 
| 501 |       text: "descriptor = $immutable_package$.$descriptor_classname$.descriptor;\n" , | 
| 502 |       args: "immutable_package" , args: FileJavaPackage(file: file_, immutable: true), args: "descriptor_classname" , | 
| 503 |       args: name_resolver_->GetDescriptorClassName(file: file_)); | 
| 504 |  | 
| 505 |   for (int i = 0; i < file_->message_type_count(); i++) { | 
| 506 |     message_generators_[i]->GenerateStaticVariableInitializers(printer); | 
| 507 |   } | 
| 508 |   for (int i = 0; i < file_->extension_count(); i++) { | 
| 509 |     extension_generators_[i]->GenerateNonNestedInitializationCode(printer); | 
| 510 |   } | 
| 511 |  | 
| 512 |   // Check if custom options exist. If any, try to load immutable classes since | 
| 513 |   // custom options are only represented with immutable messages. | 
| 514 |   FileDescriptorProto file_proto; | 
| 515 |   file_->CopyTo(proto: &file_proto); | 
| 516 |   std::string file_data; | 
| 517 |   file_proto.SerializeToString(output: &file_data); | 
| 518 |   FieldDescriptorSet extensions; | 
| 519 |   CollectExtensions(file_proto, alternate_pool: *file_->pool(), extensions: &extensions, file_data); | 
| 520 |  | 
| 521 |   if (extensions.size() > 0) { | 
| 522 |     // Try to load immutable messages' outer class. Its initialization code | 
| 523 |     // will take care of interpreting custom options. | 
| 524 |     printer->Print( | 
| 525 |         text: "try {\n"  | 
| 526 |         // Note that we have to load the immutable class dynamically here as | 
| 527 |         // we want the mutable code to be independent from the immutable code | 
| 528 |         // at compile time. It is required to implement dual-compile for | 
| 529 |         // mutable and immutable API in blaze. | 
| 530 |         "  java.lang.Class<?> immutableClass = java.lang.Class.forName(\n"  | 
| 531 |         "      \"$immutable_classname$\");\n"  | 
| 532 |         "} catch (java.lang.ClassNotFoundException e) {\n" , | 
| 533 |         args: "immutable_classname" , args: name_resolver_->GetImmutableClassName(descriptor: file_)); | 
| 534 |     printer->Indent(); | 
| 535 |  | 
| 536 |     // The immutable class can not be found. We try our best to collect all | 
| 537 |     // custom option extensions to interpret the custom options. | 
| 538 |     printer->Print( | 
| 539 |         text: "com.google.protobuf.ExtensionRegistry registry =\n"  | 
| 540 |         "    com.google.protobuf.ExtensionRegistry.newInstance();\n"  | 
| 541 |         "com.google.protobuf.MessageLite defaultExtensionInstance = null;\n" ); | 
| 542 |     FieldDescriptorSet::iterator it; | 
| 543 |     for (it = extensions.begin(); it != extensions.end(); it++) { | 
| 544 |       const FieldDescriptor* field = *it; | 
| 545 |       std::string scope; | 
| 546 |       if (field->extension_scope() != NULL) { | 
| 547 |         scope = name_resolver_->GetMutableClassName(descriptor: field->extension_scope()) + | 
| 548 |                 ".getDescriptor()" ; | 
| 549 |       } else { | 
| 550 |         scope = FileJavaPackage(file: field->file(), immutable: true) + "."  + | 
| 551 |                 name_resolver_->GetDescriptorClassName(file: field->file()) + | 
| 552 |                 ".descriptor" ; | 
| 553 |       } | 
| 554 |       if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 
| 555 |         printer->Print( | 
| 556 |             text: "defaultExtensionInstance = com.google.protobuf.Internal\n"  | 
| 557 |             "    .getDefaultInstance(\"$class$\");\n"  | 
| 558 |             "if (defaultExtensionInstance != null) {\n"  | 
| 559 |             "  registry.add(\n"  | 
| 560 |             "      $scope$.getExtensions().get($index$),\n"  | 
| 561 |             "      (com.google.protobuf.Message) defaultExtensionInstance);\n"  | 
| 562 |             "}\n" , | 
| 563 |             args: "scope" , args: scope, args: "index" , args: StrCat(a: field->index()), args: "class" , | 
| 564 |             args: name_resolver_->GetImmutableClassName(descriptor: field->message_type())); | 
| 565 |       } else { | 
| 566 |         printer->Print(text: "registry.add($scope$.getExtensions().get($index$));\n" , | 
| 567 |                        args: "scope" , args: scope, args: "index" , args: StrCat(a: field->index())); | 
| 568 |       } | 
| 569 |     } | 
| 570 |     printer->Print( | 
| 571 |         text: "com.google.protobuf.Descriptors.FileDescriptor\n"  | 
| 572 |         "    .internalUpdateFileDescriptor(descriptor, registry);\n" ); | 
| 573 |  | 
| 574 |     printer->Outdent(); | 
| 575 |     printer->Print(text: "}\n" ); | 
| 576 |   } | 
| 577 |  | 
| 578 |   // Force descriptor initialization of all dependencies. | 
| 579 |   for (int i = 0; i < file_->dependency_count(); i++) { | 
| 580 |     if (ShouldIncludeDependency(descriptor: file_->dependency(index: i), immutable_api_: false)) { | 
| 581 |       std::string dependency = | 
| 582 |           name_resolver_->GetMutableClassName(descriptor: file_->dependency(index: i)); | 
| 583 |       printer->Print(text: "$dependency$.getDescriptor();\n" , args: "dependency" , | 
| 584 |                      args: dependency); | 
| 585 |     } | 
| 586 |   } | 
| 587 |  | 
| 588 |   printer->Outdent(); | 
| 589 |   printer->Print(text: "}\n" ); | 
| 590 | } | 
| 591 |  | 
| 592 | template <typename GeneratorClass, typename DescriptorClass> | 
| 593 | static void GenerateSibling( | 
| 594 |     const std::string& package_dir, const std::string& java_package, | 
| 595 |     const DescriptorClass* descriptor, GeneratorContext* context, | 
| 596 |     std::vector<std::string>* file_list, bool annotate_code, | 
| 597 |     std::vector<std::string>* annotation_list, const std::string& name_suffix, | 
| 598 |     GeneratorClass* generator, | 
| 599 |     void (GeneratorClass::*pfn)(io::Printer* printer)) { | 
| 600 |   std::string filename = | 
| 601 |       package_dir + descriptor->name() + name_suffix + ".java" ; | 
| 602 |   file_list->push_back(x: filename); | 
| 603 |   std::string info_full_path = filename + ".pb.meta" ; | 
| 604 |   GeneratedCodeInfo annotations; | 
| 605 |   io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( | 
| 606 |       &annotations); | 
| 607 |  | 
| 608 |   std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); | 
| 609 |   io::Printer printer(output.get(), '$', | 
| 610 |                       annotate_code ? &annotation_collector : NULL); | 
| 611 |  | 
| 612 |   printer.Print( | 
| 613 |       "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"  | 
| 614 |       "// source: $filename$\n"  | 
| 615 |       "\n" , | 
| 616 |       "filename" , descriptor->file()->name()); | 
| 617 |   if (!java_package.empty()) { | 
| 618 |     printer.Print( | 
| 619 |         text: "package $package$;\n"  | 
| 620 |         "\n" , | 
| 621 |         args: "package" , args: java_package); | 
| 622 |   } | 
| 623 |  | 
| 624 |   (generator->*pfn)(&printer); | 
| 625 |  | 
| 626 |   if (annotate_code) { | 
| 627 |     std::unique_ptr<io::ZeroCopyOutputStream> info_output( | 
| 628 |         context->Open(filename: info_full_path)); | 
| 629 |     annotations.SerializeToZeroCopyStream(output: info_output.get()); | 
| 630 |     annotation_list->push_back(x: info_full_path); | 
| 631 |   } | 
| 632 | } | 
| 633 |  | 
| 634 | void FileGenerator::GenerateSiblings( | 
| 635 |     const std::string& package_dir, GeneratorContext* context, | 
| 636 |     std::vector<std::string>* file_list, | 
| 637 |     std::vector<std::string>* annotation_list) { | 
| 638 |   if (MultipleJavaFiles(descriptor: file_, immutable: immutable_api_)) { | 
| 639 |     for (int i = 0; i < file_->enum_type_count(); i++) { | 
| 640 |       if (HasDescriptorMethods(file_, enforce_lite: context_->EnforceLite())) { | 
| 641 |         EnumGenerator generator(file_->enum_type(index: i), immutable_api_, | 
| 642 |                                 context_.get()); | 
| 643 |         GenerateSibling<EnumGenerator>( | 
| 644 |             package_dir, java_package: java_package_, descriptor: file_->enum_type(index: i), context, file_list, | 
| 645 |             annotate_code: options_.annotate_code, annotation_list, name_suffix: "" , generator: &generator, | 
| 646 |             pfn: &EnumGenerator::Generate); | 
| 647 |       } else { | 
| 648 |         EnumLiteGenerator generator(file_->enum_type(index: i), immutable_api_, | 
| 649 |                                     context_.get()); | 
| 650 |         GenerateSibling<EnumLiteGenerator>( | 
| 651 |             package_dir, java_package: java_package_, descriptor: file_->enum_type(index: i), context, file_list, | 
| 652 |             annotate_code: options_.annotate_code, annotation_list, name_suffix: "" , generator: &generator, | 
| 653 |             pfn: &EnumLiteGenerator::Generate); | 
| 654 |       } | 
| 655 |     } | 
| 656 |     for (int i = 0; i < file_->message_type_count(); i++) { | 
| 657 |       if (immutable_api_) { | 
| 658 |         GenerateSibling<MessageGenerator>( | 
| 659 |             package_dir, java_package: java_package_, descriptor: file_->message_type(index: i), context, | 
| 660 |             file_list, annotate_code: options_.annotate_code, annotation_list, name_suffix: "OrBuilder" , | 
| 661 |             generator: message_generators_[i].get(), pfn: &MessageGenerator::GenerateInterface); | 
| 662 |       } | 
| 663 |       GenerateSibling<MessageGenerator>( | 
| 664 |           package_dir, java_package: java_package_, descriptor: file_->message_type(index: i), context, | 
| 665 |           file_list, annotate_code: options_.annotate_code, annotation_list, name_suffix: "" , | 
| 666 |           generator: message_generators_[i].get(), pfn: &MessageGenerator::Generate); | 
| 667 |     } | 
| 668 |     if (HasGenericServices(file: file_, enforce_lite: context_->EnforceLite())) { | 
| 669 |       for (int i = 0; i < file_->service_count(); i++) { | 
| 670 |         std::unique_ptr<ServiceGenerator> generator( | 
| 671 |             generator_factory_->NewServiceGenerator(descriptor: file_->service(index: i))); | 
| 672 |         GenerateSibling<ServiceGenerator>( | 
| 673 |             package_dir, java_package: java_package_, descriptor: file_->service(index: i), context, file_list, | 
| 674 |             annotate_code: options_.annotate_code, annotation_list, name_suffix: "" , generator: generator.get(), | 
| 675 |             pfn: &ServiceGenerator::Generate); | 
| 676 |       } | 
| 677 |     } | 
| 678 |   } | 
| 679 | } | 
| 680 |  | 
| 681 | std::string FileGenerator::GetKotlinClassname() { | 
| 682 |   return name_resolver_->GetFileClassName(file: file_, immutable: immutable_api_, kotlin: true); | 
| 683 | } | 
| 684 |  | 
| 685 | void FileGenerator::GenerateKotlinSiblings( | 
| 686 |     const std::string& package_dir, GeneratorContext* context, | 
| 687 |     std::vector<std::string>* file_list, | 
| 688 |     std::vector<std::string>* annotation_list) { | 
| 689 |   for (int i = 0; i < file_->message_type_count(); i++) { | 
| 690 |     const Descriptor* descriptor = file_->message_type(index: i); | 
| 691 |     MessageGenerator* generator = message_generators_[i].get(); | 
| 692 |     auto open_file = [context](const std::string& filename) { | 
| 693 |       return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename)); | 
| 694 |     }; | 
| 695 |     std::string filename = package_dir + descriptor->name() + "Kt.kt" ; | 
| 696 |     file_list->push_back(x: filename); | 
| 697 |     std::string info_full_path = filename + ".pb.meta" ; | 
| 698 |     GeneratedCodeInfo annotations; | 
| 699 |     io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( | 
| 700 |         &annotations); | 
| 701 |     auto output = open_file(filename); | 
| 702 |     io::Printer printer( | 
| 703 |         output.get(), '$', | 
| 704 |         options_.annotate_code ? &annotation_collector : nullptr); | 
| 705 |  | 
| 706 |     printer.Print( | 
| 707 |         text: "//Generated by the protocol buffer compiler. DO NOT EDIT!\n"  | 
| 708 |         "// source: $filename$\n"  | 
| 709 |         "\n" , | 
| 710 |         args: "filename" , args: descriptor->file()->name()); | 
| 711 |     if (!java_package_.empty()) { | 
| 712 |       printer.Print( | 
| 713 |           text: "package $package$;\n"  | 
| 714 |           "\n" , | 
| 715 |           args: "package" , args: java_package_); | 
| 716 |     } | 
| 717 |  | 
| 718 |     generator->GenerateKotlinMembers(printer: &printer); | 
| 719 |     generator->GenerateTopLevelKotlinMembers(printer: &printer); | 
| 720 |  | 
| 721 |     if (options_.annotate_code) { | 
| 722 |       auto info_output = open_file(info_full_path); | 
| 723 |       annotations.SerializeToZeroCopyStream(output: info_output.get()); | 
| 724 |       annotation_list->push_back(x: info_full_path); | 
| 725 |     } | 
| 726 |   } | 
| 727 | } | 
| 728 |  | 
| 729 | bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor, | 
| 730 |                                             bool immutable_api) { | 
| 731 |   return true; | 
| 732 | } | 
| 733 |  | 
| 734 | }  // namespace java | 
| 735 | }  // namespace compiler | 
| 736 | }  // namespace protobuf | 
| 737 | }  // namespace google | 
| 738 |  | 
| 739 | #include <google/protobuf/port_undef.inc> | 
| 740 |  |