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/enum_lite.h> |
36 | |
37 | #include <map> |
38 | #include <string> |
39 | |
40 | #include <google/protobuf/io/printer.h> |
41 | #include <google/protobuf/stubs/strutil.h> |
42 | #include <google/protobuf/compiler/java/context.h> |
43 | #include <google/protobuf/compiler/java/doc_comment.h> |
44 | #include <google/protobuf/compiler/java/helpers.h> |
45 | #include <google/protobuf/compiler/java/name_resolver.h> |
46 | #include <google/protobuf/descriptor.pb.h> |
47 | #include <google/protobuf/stubs/map_util.h> |
48 | |
49 | namespace google { |
50 | namespace protobuf { |
51 | namespace compiler { |
52 | namespace java { |
53 | |
54 | EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor, |
55 | bool immutable_api, Context* context) |
56 | : descriptor_(descriptor), |
57 | immutable_api_(immutable_api), |
58 | context_(context), |
59 | name_resolver_(context->GetNameResolver()) { |
60 | for (int i = 0; i < descriptor_->value_count(); i++) { |
61 | const EnumValueDescriptor* value = descriptor_->value(index: i); |
62 | const EnumValueDescriptor* canonical_value = |
63 | descriptor_->FindValueByNumber(number: value->number()); |
64 | |
65 | if (value == canonical_value) { |
66 | canonical_values_.push_back(x: value); |
67 | } else { |
68 | Alias alias; |
69 | alias.value = value; |
70 | alias.canonical_value = canonical_value; |
71 | aliases_.push_back(x: alias); |
72 | } |
73 | } |
74 | } |
75 | |
76 | EnumLiteGenerator::~EnumLiteGenerator() {} |
77 | |
78 | void EnumLiteGenerator::Generate(io::Printer* printer) { |
79 | WriteEnumDocComment(printer, enum_: descriptor_); |
80 | MaybePrintGeneratedAnnotation(context: context_, printer, descriptor: descriptor_, immutable: immutable_api_); |
81 | printer->Print( |
82 | text: "$deprecation$public enum $classname$\n" |
83 | " implements com.google.protobuf.Internal.EnumLite {\n" , |
84 | args: "classname" , args: descriptor_->name(), args: "deprecation" , |
85 | args: descriptor_->options().deprecated() ? "@java.lang.Deprecated " : "" ); |
86 | printer->Annotate(varname: "classname" , descriptor: descriptor_); |
87 | printer->Indent(); |
88 | |
89 | for (int i = 0; i < canonical_values_.size(); i++) { |
90 | std::map<std::string, std::string> vars; |
91 | vars["name" ] = canonical_values_[i]->name(); |
92 | vars["number" ] = StrCat(a: canonical_values_[i]->number()); |
93 | WriteEnumValueDocComment(printer, value: canonical_values_[i]); |
94 | if (canonical_values_[i]->options().deprecated()) { |
95 | printer->Print(text: "@java.lang.Deprecated\n" ); |
96 | } |
97 | printer->Print(variables: vars, text: "$name$($number$),\n" ); |
98 | printer->Annotate(varname: "name" , descriptor: canonical_values_[i]); |
99 | } |
100 | |
101 | if (SupportUnknownEnumValue(descriptor: descriptor_->file())) { |
102 | printer->Print(text: "${$UNRECOGNIZED$}$(-1),\n" , args: "{" , args: "" , args: "}" , args: "" ); |
103 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
104 | } |
105 | |
106 | printer->Print( |
107 | text: ";\n" |
108 | "\n" ); |
109 | |
110 | // ----------------------------------------------------------------- |
111 | |
112 | for (int i = 0; i < aliases_.size(); i++) { |
113 | std::map<std::string, std::string> vars; |
114 | vars["classname" ] = descriptor_->name(); |
115 | vars["name" ] = aliases_[i].value->name(); |
116 | vars["canonical_name" ] = aliases_[i].canonical_value->name(); |
117 | WriteEnumValueDocComment(printer, value: aliases_[i].value); |
118 | printer->Print( |
119 | variables: vars, text: "public static final $classname$ $name$ = $canonical_name$;\n" ); |
120 | printer->Annotate(varname: "name" , descriptor: aliases_[i].value); |
121 | } |
122 | |
123 | for (int i = 0; i < descriptor_->value_count(); i++) { |
124 | std::map<std::string, std::string> vars; |
125 | vars["name" ] = descriptor_->value(index: i)->name(); |
126 | vars["number" ] = StrCat(a: descriptor_->value(index: i)->number()); |
127 | vars["{" ] = "" ; |
128 | vars["}" ] = "" ; |
129 | vars["deprecation" ] = descriptor_->value(index: i)->options().deprecated() |
130 | ? "@java.lang.Deprecated " |
131 | : "" ; |
132 | WriteEnumValueDocComment(printer, value: descriptor_->value(index: i)); |
133 | printer->Print(variables: vars, |
134 | text: "$deprecation$public static final int ${$$name$_VALUE$}$ = " |
135 | "$number$;\n" ); |
136 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_->value(index: i)); |
137 | } |
138 | printer->Print(text: "\n" ); |
139 | |
140 | // ----------------------------------------------------------------- |
141 | |
142 | printer->Print( |
143 | text: "\n" |
144 | "@java.lang.Override\n" |
145 | "public final int getNumber() {\n" ); |
146 | if (SupportUnknownEnumValue(descriptor: descriptor_->file())) { |
147 | printer->Print( |
148 | text: " if (this == UNRECOGNIZED) {\n" |
149 | " throw new java.lang.IllegalArgumentException(\n" |
150 | " \"Can't get the number of an unknown enum value.\");\n" |
151 | " }\n" ); |
152 | } |
153 | printer->Print( |
154 | text: " return value;\n" |
155 | "}\n" |
156 | "\n" |
157 | "/**\n" |
158 | " * @param value The number of the enum to look for.\n" |
159 | " * @return The enum associated with the given number.\n" |
160 | " * @deprecated Use {@link #forNumber(int)} instead.\n" |
161 | " */\n" |
162 | "@java.lang.Deprecated\n" |
163 | "public static $classname$ valueOf(int value) {\n" |
164 | " return forNumber(value);\n" |
165 | "}\n" |
166 | "\n" |
167 | "public static $classname$ forNumber(int value) {\n" |
168 | " switch (value) {\n" , |
169 | args: "classname" , args: descriptor_->name()); |
170 | printer->Indent(); |
171 | printer->Indent(); |
172 | |
173 | for (int i = 0; i < canonical_values_.size(); i++) { |
174 | printer->Print(text: "case $number$: return $name$;\n" , args: "name" , |
175 | args: canonical_values_[i]->name(), args: "number" , |
176 | args: StrCat(a: canonical_values_[i]->number())); |
177 | } |
178 | |
179 | printer->Outdent(); |
180 | printer->Outdent(); |
181 | printer->Print( |
182 | text: " default: return null;\n" |
183 | " }\n" |
184 | "}\n" |
185 | "\n" |
186 | "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" |
187 | " internalGetValueMap() {\n" |
188 | " return internalValueMap;\n" |
189 | "}\n" |
190 | "private static final com.google.protobuf.Internal.EnumLiteMap<\n" |
191 | " $classname$> internalValueMap =\n" |
192 | " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" |
193 | " @java.lang.Override\n" |
194 | " public $classname$ findValueByNumber(int number) {\n" |
195 | " return $classname$.forNumber(number);\n" |
196 | " }\n" |
197 | " };\n" |
198 | "\n" |
199 | "public static com.google.protobuf.Internal.EnumVerifier \n" |
200 | " internalGetVerifier() {\n" |
201 | " return $classname$Verifier.INSTANCE;\n" |
202 | "}\n" |
203 | "\n" |
204 | "private static final class $classname$Verifier implements \n" |
205 | " com.google.protobuf.Internal.EnumVerifier { \n" |
206 | " static final com.google.protobuf.Internal.EnumVerifier " |
207 | " INSTANCE = new $classname$Verifier();\n" |
208 | " @java.lang.Override\n" |
209 | " public boolean isInRange(int number) {\n" |
210 | " return $classname$.forNumber(number) != null;\n" |
211 | " }\n" |
212 | " };\n" |
213 | "\n" , |
214 | args: "classname" , args: descriptor_->name()); |
215 | |
216 | printer->Print( |
217 | text: "private final int value;\n\n" |
218 | "private $classname$(int value) {\n" , |
219 | args: "classname" , args: descriptor_->name()); |
220 | printer->Print( |
221 | text: " this.value = value;\n" |
222 | "}\n" ); |
223 | |
224 | printer->Print( |
225 | text: "\n" |
226 | "// @@protoc_insertion_point(enum_scope:$full_name$)\n" , |
227 | args: "full_name" , args: descriptor_->full_name()); |
228 | |
229 | printer->Outdent(); |
230 | printer->Print(text: "}\n\n" ); |
231 | } |
232 | |
233 | } // namespace java |
234 | } // namespace compiler |
235 | } // namespace protobuf |
236 | } // namespace google |
237 | |