1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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 <map>
36#include <string>
37
38#include <google/protobuf/compiler/java/java_enum_field.h>
39#include <google/protobuf/compiler/java/java_doc_comment.h>
40#include <google/protobuf/stubs/common.h>
41#include <google/protobuf/compiler/java/java_helpers.h>
42#include <google/protobuf/io/printer.h>
43#include <google/protobuf/wire_format.h>
44#include <google/protobuf/stubs/strutil.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace java {
50
51namespace {
52
53// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
54//   repeat code between this and the other field types.
55void SetEnumVariables(const FieldDescriptor* descriptor,
56                      int messageBitIndex,
57                      int builderBitIndex,
58                      map<string, string>* variables) {
59  (*variables)["name"] =
60    UnderscoresToCamelCase(descriptor);
61  (*variables)["capitalized_name"] =
62    UnderscoresToCapitalizedCamelCase(descriptor);
63  (*variables)["constant_name"] = FieldConstantName(descriptor);
64  (*variables)["number"] = SimpleItoa(descriptor->number());
65  (*variables)["type"] = ClassName(descriptor->enum_type());
66  (*variables)["default"] = DefaultValue(descriptor);
67  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
68  (*variables)["tag_size"] = SimpleItoa(
69      internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
70  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
71  // by the proto compiler
72  (*variables)["deprecation"] = descriptor->options().deprecated()
73      ? "@java.lang.Deprecated " : "";
74  (*variables)["on_changed"] =
75      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
76
77  // For singular messages and builders, one bit is used for the hasField bit.
78  (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
79  (*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex);
80
81  (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
82  (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
83  (*variables)["clear_has_field_bit_builder"] =
84      GenerateClearBit(builderBitIndex);
85
86  // For repated builders, one bit is used for whether the array is immutable.
87  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
88  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
89  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
90
91  // For repeated fields, one bit is used for whether the array is immutable
92  // in the parsing constructor.
93  (*variables)["get_mutable_bit_parser"] =
94      GenerateGetBitMutableLocal(builderBitIndex);
95  (*variables)["set_mutable_bit_parser"] =
96      GenerateSetBitMutableLocal(builderBitIndex);
97
98  (*variables)["get_has_field_bit_from_local"] =
99      GenerateGetBitFromLocal(builderBitIndex);
100  (*variables)["set_has_field_bit_to_local"] =
101      GenerateSetBitToLocal(messageBitIndex);
102}
103
104}  // namespace
105
106// ===================================================================
107
108EnumFieldGenerator::
109EnumFieldGenerator(const FieldDescriptor* descriptor,
110                      int messageBitIndex,
111                      int builderBitIndex)
112  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
113    builderBitIndex_(builderBitIndex) {
114  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
115}
116
117EnumFieldGenerator::~EnumFieldGenerator() {}
118
119int EnumFieldGenerator::GetNumBitsForMessage() const {
120  return 1;
121}
122
123int EnumFieldGenerator::GetNumBitsForBuilder() const {
124  return 1;
125}
126
127void EnumFieldGenerator::
128GenerateInterfaceMembers(io::Printer* printer) const {
129  WriteFieldDocComment(printer, descriptor_);
130  printer->Print(variables_,
131    "$deprecation$boolean has$capitalized_name$();\n");
132  WriteFieldDocComment(printer, descriptor_);
133  printer->Print(variables_,
134    "$deprecation$$type$ get$capitalized_name$();\n");
135}
136
137void EnumFieldGenerator::
138GenerateMembers(io::Printer* printer) const {
139  printer->Print(variables_,
140    "private $type$ $name$_;\n");
141  WriteFieldDocComment(printer, descriptor_);
142  printer->Print(variables_,
143    "$deprecation$public boolean has$capitalized_name$() {\n"
144    "  return $get_has_field_bit_message$;\n"
145    "}\n");
146  WriteFieldDocComment(printer, descriptor_);
147  printer->Print(variables_,
148    "$deprecation$public $type$ get$capitalized_name$() {\n"
149    "  return $name$_;\n"
150    "}\n");
151}
152
153void EnumFieldGenerator::
154GenerateBuilderMembers(io::Printer* printer) const {
155  printer->Print(variables_,
156    "private $type$ $name$_ = $default$;\n");
157  WriteFieldDocComment(printer, descriptor_);
158  printer->Print(variables_,
159    "$deprecation$public boolean has$capitalized_name$() {\n"
160    "  return $get_has_field_bit_builder$;\n"
161    "}\n");
162  WriteFieldDocComment(printer, descriptor_);
163  printer->Print(variables_,
164    "$deprecation$public $type$ get$capitalized_name$() {\n"
165    "  return $name$_;\n"
166    "}\n");
167  WriteFieldDocComment(printer, descriptor_);
168  printer->Print(variables_,
169    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
170    "  if (value == null) {\n"
171    "    throw new NullPointerException();\n"
172    "  }\n"
173    "  $set_has_field_bit_builder$;\n"
174    "  $name$_ = value;\n"
175    "  $on_changed$\n"
176    "  return this;\n"
177    "}\n");
178  WriteFieldDocComment(printer, descriptor_);
179  printer->Print(variables_,
180    "$deprecation$public Builder clear$capitalized_name$() {\n"
181    "  $clear_has_field_bit_builder$;\n"
182    "  $name$_ = $default$;\n"
183    "  $on_changed$\n"
184    "  return this;\n"
185    "}\n");
186}
187
188void EnumFieldGenerator::
189GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
190  // noop for enums
191}
192
193void EnumFieldGenerator::
194GenerateInitializationCode(io::Printer* printer) const {
195  printer->Print(variables_, "$name$_ = $default$;\n");
196}
197
198void EnumFieldGenerator::
199GenerateBuilderClearCode(io::Printer* printer) const {
200  printer->Print(variables_,
201      "$name$_ = $default$;\n"
202      "$clear_has_field_bit_builder$;\n");
203}
204
205void EnumFieldGenerator::
206GenerateMergingCode(io::Printer* printer) const {
207  printer->Print(variables_,
208    "if (other.has$capitalized_name$()) {\n"
209    "  set$capitalized_name$(other.get$capitalized_name$());\n"
210    "}\n");
211}
212
213void EnumFieldGenerator::
214GenerateBuildingCode(io::Printer* printer) const {
215  printer->Print(variables_,
216    "if ($get_has_field_bit_from_local$) {\n"
217    "  $set_has_field_bit_to_local$;\n"
218    "}\n"
219    "result.$name$_ = $name$_;\n");
220}
221
222void EnumFieldGenerator::
223GenerateParsingCode(io::Printer* printer) const {
224  printer->Print(variables_,
225    "int rawValue = input.readEnum();\n"
226    "$type$ value = $type$.valueOf(rawValue);\n");
227  if (HasUnknownFields(descriptor_->containing_type())) {
228    printer->Print(variables_,
229      "if (value == null) {\n"
230      "  unknownFields.mergeVarintField($number$, rawValue);\n"
231      "} else {\n");
232  } else {
233    printer->Print(variables_,
234      "if (value != null) {\n");
235  }
236  printer->Print(variables_,
237    "  $set_has_field_bit_message$;\n"
238    "  $name$_ = value;\n"
239    "}\n");
240}
241
242void EnumFieldGenerator::
243GenerateParsingDoneCode(io::Printer* printer) const {
244  // noop for enums
245}
246
247void EnumFieldGenerator::
248GenerateSerializationCode(io::Printer* printer) const {
249  printer->Print(variables_,
250    "if ($get_has_field_bit_message$) {\n"
251    "  output.writeEnum($number$, $name$_.getNumber());\n"
252    "}\n");
253}
254
255void EnumFieldGenerator::
256GenerateSerializedSizeCode(io::Printer* printer) const {
257  printer->Print(variables_,
258    "if ($get_has_field_bit_message$) {\n"
259    "  size += com.google.protobuf.CodedOutputStream\n"
260    "    .computeEnumSize($number$, $name$_.getNumber());\n"
261    "}\n");
262}
263
264void EnumFieldGenerator::
265GenerateEqualsCode(io::Printer* printer) const {
266  printer->Print(variables_,
267    "result = result &&\n"
268    "    (get$capitalized_name$() == other.get$capitalized_name$());\n");
269}
270
271void EnumFieldGenerator::
272GenerateHashCode(io::Printer* printer) const {
273  printer->Print(variables_,
274    "hash = (37 * hash) + $constant_name$;\n"
275    "hash = (53 * hash) + hashEnum(get$capitalized_name$());\n");
276}
277
278string EnumFieldGenerator::GetBoxedType() const {
279  return ClassName(descriptor_->enum_type());
280}
281
282// ===================================================================
283
284RepeatedEnumFieldGenerator::
285RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
286                           int messageBitIndex,
287                           int builderBitIndex)
288  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
289    builderBitIndex_(builderBitIndex) {
290  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
291}
292
293RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
294
295int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const {
296  return 0;
297}
298
299int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const {
300  return 1;
301}
302
303void RepeatedEnumFieldGenerator::
304GenerateInterfaceMembers(io::Printer* printer) const {
305  WriteFieldDocComment(printer, descriptor_);
306  printer->Print(variables_,
307    "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
308  WriteFieldDocComment(printer, descriptor_);
309  printer->Print(variables_,
310    "$deprecation$int get$capitalized_name$Count();\n");
311  WriteFieldDocComment(printer, descriptor_);
312  printer->Print(variables_,
313    "$deprecation$$type$ get$capitalized_name$(int index);\n");
314}
315
316void RepeatedEnumFieldGenerator::
317GenerateMembers(io::Printer* printer) const {
318  printer->Print(variables_,
319    "private java.util.List<$type$> $name$_;\n");
320  WriteFieldDocComment(printer, descriptor_);
321  printer->Print(variables_,
322    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
323    "  return $name$_;\n"   // note:  unmodifiable list
324    "}\n");
325  WriteFieldDocComment(printer, descriptor_);
326  printer->Print(variables_,
327    "$deprecation$public int get$capitalized_name$Count() {\n"
328    "  return $name$_.size();\n"
329    "}\n");
330  WriteFieldDocComment(printer, descriptor_);
331  printer->Print(variables_,
332    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
333    "  return $name$_.get(index);\n"
334    "}\n");
335
336  if (descriptor_->options().packed() &&
337      HasGeneratedMethods(descriptor_->containing_type())) {
338    printer->Print(variables_,
339      "private int $name$MemoizedSerializedSize;\n");
340  }
341}
342
343void RepeatedEnumFieldGenerator::
344GenerateBuilderMembers(io::Printer* printer) const {
345  printer->Print(variables_,
346    // One field is the list and the other field keeps track of whether the
347    // list is immutable. If it's immutable, the invariant is that it must
348    // either an instance of Collections.emptyList() or it's an ArrayList
349    // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
350    // a refererence to the underlying ArrayList. This invariant allows us to
351    // share instances of lists between protocol buffers avoiding expensive
352    // memory allocations. Note, immutable is a strong guarantee here -- not
353    // just that the list cannot be modified via the reference but that the
354    // list can never be modified.
355    "private java.util.List<$type$> $name$_ =\n"
356    "  java.util.Collections.emptyList();\n"
357
358    "private void ensure$capitalized_name$IsMutable() {\n"
359    "  if (!$get_mutable_bit_builder$) {\n"
360    "    $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
361    "    $set_mutable_bit_builder$;\n"
362    "  }\n"
363    "}\n");
364
365  WriteFieldDocComment(printer, descriptor_);
366  printer->Print(variables_,
367    // Note:  We return an unmodifiable list because otherwise the caller
368    //   could hold on to the returned list and modify it after the message
369    //   has been built, thus mutating the message which is supposed to be
370    //   immutable.
371    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
372    "  return java.util.Collections.unmodifiableList($name$_);\n"
373    "}\n");
374  WriteFieldDocComment(printer, descriptor_);
375  printer->Print(variables_,
376    "$deprecation$public int get$capitalized_name$Count() {\n"
377    "  return $name$_.size();\n"
378    "}\n");
379  WriteFieldDocComment(printer, descriptor_);
380  printer->Print(variables_,
381    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
382    "  return $name$_.get(index);\n"
383    "}\n");
384  WriteFieldDocComment(printer, descriptor_);
385  printer->Print(variables_,
386    "$deprecation$public Builder set$capitalized_name$(\n"
387    "    int index, $type$ value) {\n"
388    "  if (value == null) {\n"
389    "    throw new NullPointerException();\n"
390    "  }\n"
391    "  ensure$capitalized_name$IsMutable();\n"
392    "  $name$_.set(index, value);\n"
393    "  $on_changed$\n"
394    "  return this;\n"
395    "}\n");
396  WriteFieldDocComment(printer, descriptor_);
397  printer->Print(variables_,
398    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
399    "  if (value == null) {\n"
400    "    throw new NullPointerException();\n"
401    "  }\n"
402    "  ensure$capitalized_name$IsMutable();\n"
403    "  $name$_.add(value);\n"
404    "  $on_changed$\n"
405    "  return this;\n"
406    "}\n");
407  WriteFieldDocComment(printer, descriptor_);
408  printer->Print(variables_,
409    "$deprecation$public Builder addAll$capitalized_name$(\n"
410    "    java.lang.Iterable<? extends $type$> values) {\n"
411    "  ensure$capitalized_name$IsMutable();\n"
412    "  super.addAll(values, $name$_);\n"
413    "  $on_changed$\n"
414    "  return this;\n"
415    "}\n");
416  WriteFieldDocComment(printer, descriptor_);
417  printer->Print(variables_,
418    "$deprecation$public Builder clear$capitalized_name$() {\n"
419    "  $name$_ = java.util.Collections.emptyList();\n"
420    "  $clear_mutable_bit_builder$;\n"
421    "  $on_changed$\n"
422    "  return this;\n"
423    "}\n");
424}
425
426void RepeatedEnumFieldGenerator::
427GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
428  // noop for enums
429}
430
431void RepeatedEnumFieldGenerator::
432GenerateInitializationCode(io::Printer* printer) const {
433  printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
434}
435
436void RepeatedEnumFieldGenerator::
437GenerateBuilderClearCode(io::Printer* printer) const {
438  printer->Print(variables_,
439    "$name$_ = java.util.Collections.emptyList();\n"
440    "$clear_mutable_bit_builder$;\n");
441}
442
443void RepeatedEnumFieldGenerator::
444GenerateMergingCode(io::Printer* printer) const {
445  // The code below does two optimizations:
446  //   1. If the other list is empty, there's nothing to do. This ensures we
447  //      don't allocate a new array if we already have an immutable one.
448  //   2. If the other list is non-empty and our current list is empty, we can
449  //      reuse the other list which is guaranteed to be immutable.
450  printer->Print(variables_,
451    "if (!other.$name$_.isEmpty()) {\n"
452    "  if ($name$_.isEmpty()) {\n"
453    "    $name$_ = other.$name$_;\n"
454    "    $clear_mutable_bit_builder$;\n"
455    "  } else {\n"
456    "    ensure$capitalized_name$IsMutable();\n"
457    "    $name$_.addAll(other.$name$_);\n"
458    "  }\n"
459    "  $on_changed$\n"
460    "}\n");
461}
462
463void RepeatedEnumFieldGenerator::
464GenerateBuildingCode(io::Printer* printer) const {
465  // The code below ensures that the result has an immutable list. If our
466  // list is immutable, we can just reuse it. If not, we make it immutable.
467  printer->Print(variables_,
468    "if ($get_mutable_bit_builder$) {\n"
469    "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
470    "  $clear_mutable_bit_builder$;\n"
471    "}\n"
472    "result.$name$_ = $name$_;\n");
473}
474
475void RepeatedEnumFieldGenerator::
476GenerateParsingCode(io::Printer* printer) const {
477  // Read and store the enum
478  printer->Print(variables_,
479    "int rawValue = input.readEnum();\n"
480    "$type$ value = $type$.valueOf(rawValue);\n");
481  if (HasUnknownFields(descriptor_->containing_type())) {
482    printer->Print(variables_,
483      "if (value == null) {\n"
484      "  unknownFields.mergeVarintField($number$, rawValue);\n"
485      "} else {\n");
486  } else {
487    printer->Print(variables_,
488      "if (value != null) {\n");
489  }
490  printer->Print(variables_,
491    "  if (!$get_mutable_bit_parser$) {\n"
492    "    $name$_ = new java.util.ArrayList<$type$>();\n"
493    "    $set_mutable_bit_parser$;\n"
494    "  }\n"
495    "  $name$_.add(value);\n"
496    "}\n");
497}
498
499void RepeatedEnumFieldGenerator::
500GenerateParsingCodeFromPacked(io::Printer* printer) const {
501  // Wrap GenerateParsingCode's contents with a while loop.
502
503  printer->Print(variables_,
504    "int length = input.readRawVarint32();\n"
505    "int oldLimit = input.pushLimit(length);\n"
506    "while(input.getBytesUntilLimit() > 0) {\n");
507  printer->Indent();
508
509  GenerateParsingCode(printer);
510
511  printer->Outdent();
512  printer->Print(variables_,
513    "}\n"
514    "input.popLimit(oldLimit);\n");
515}
516
517void RepeatedEnumFieldGenerator::
518GenerateParsingDoneCode(io::Printer* printer) const {
519  printer->Print(variables_,
520    "if ($get_mutable_bit_parser$) {\n"
521    "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
522    "}\n");
523}
524
525void RepeatedEnumFieldGenerator::
526GenerateSerializationCode(io::Printer* printer) const {
527  if (descriptor_->options().packed()) {
528    printer->Print(variables_,
529      "if (get$capitalized_name$List().size() > 0) {\n"
530      "  output.writeRawVarint32($tag$);\n"
531      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
532      "}\n"
533      "for (int i = 0; i < $name$_.size(); i++) {\n"
534      "  output.writeEnumNoTag($name$_.get(i).getNumber());\n"
535      "}\n");
536  } else {
537    printer->Print(variables_,
538      "for (int i = 0; i < $name$_.size(); i++) {\n"
539      "  output.writeEnum($number$, $name$_.get(i).getNumber());\n"
540      "}\n");
541  }
542}
543
544void RepeatedEnumFieldGenerator::
545GenerateSerializedSizeCode(io::Printer* printer) const {
546  printer->Print(variables_,
547    "{\n"
548    "  int dataSize = 0;\n");
549  printer->Indent();
550
551  printer->Print(variables_,
552    "for (int i = 0; i < $name$_.size(); i++) {\n"
553    "  dataSize += com.google.protobuf.CodedOutputStream\n"
554    "    .computeEnumSizeNoTag($name$_.get(i).getNumber());\n"
555    "}\n");
556  printer->Print(
557    "size += dataSize;\n");
558  if (descriptor_->options().packed()) {
559    printer->Print(variables_,
560      "if (!get$capitalized_name$List().isEmpty()) {"
561      "  size += $tag_size$;\n"
562      "  size += com.google.protobuf.CodedOutputStream\n"
563      "    .computeRawVarint32Size(dataSize);\n"
564      "}");
565  } else {
566    printer->Print(variables_,
567      "size += $tag_size$ * $name$_.size();\n");
568  }
569
570  // cache the data size for packed fields.
571  if (descriptor_->options().packed()) {
572    printer->Print(variables_,
573      "$name$MemoizedSerializedSize = dataSize;\n");
574  }
575
576  printer->Outdent();
577  printer->Print("}\n");
578}
579
580void RepeatedEnumFieldGenerator::
581GenerateEqualsCode(io::Printer* printer) const {
582  printer->Print(variables_,
583    "result = result && get$capitalized_name$List()\n"
584    "    .equals(other.get$capitalized_name$List());\n");
585}
586
587void RepeatedEnumFieldGenerator::
588GenerateHashCode(io::Printer* printer) const {
589  printer->Print(variables_,
590    "if (get$capitalized_name$Count() > 0) {\n"
591    "  hash = (37 * hash) + $constant_name$;\n"
592    "  hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n"
593    "}\n");
594}
595
596string RepeatedEnumFieldGenerator::GetBoxedType() const {
597  return ClassName(descriptor_->enum_type());
598}
599
600}  // namespace java
601}  // namespace compiler
602}  // namespace protobuf
603}  // namespace google
604