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/java_field.h>
36
37#include <memory>
38#ifndef _SHARED_PTR_H
39#include <google/protobuf/stubs/shared_ptr.h>
40#endif
41
42#include <google/protobuf/stubs/logging.h>
43#include <google/protobuf/stubs/common.h>
44#include <google/protobuf/compiler/java/java_context.h>
45#include <google/protobuf/compiler/java/java_enum_field.h>
46#include <google/protobuf/compiler/java/java_enum_field_lite.h>
47#include <google/protobuf/compiler/java/java_helpers.h>
48#include <google/protobuf/compiler/java/java_lazy_message_field.h>
49#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
50#include <google/protobuf/compiler/java/java_map_field.h>
51#include <google/protobuf/compiler/java/java_map_field_lite.h>
52#include <google/protobuf/compiler/java/java_message_field.h>
53#include <google/protobuf/compiler/java/java_message_field_lite.h>
54#include <google/protobuf/compiler/java/java_primitive_field.h>
55#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
56#include <google/protobuf/compiler/java/java_string_field.h>
57#include <google/protobuf/compiler/java/java_string_field_lite.h>
58#include <google/protobuf/io/printer.h>
59#include <google/protobuf/stubs/strutil.h>
60#include <google/protobuf/stubs/substitute.h>
61
62
63namespace google {
64namespace protobuf {
65namespace compiler {
66namespace java {
67
68namespace {
69
70ImmutableFieldGenerator* MakeImmutableGenerator(
71    const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
72    Context* context) {
73  if (field->is_repeated()) {
74    switch (GetJavaType(field)) {
75      case JAVATYPE_MESSAGE:
76        if (IsMapEntry(field->message_type())) {
77          return new ImmutableMapFieldGenerator(
78              field, messageBitIndex, builderBitIndex, context);
79        } else {
80          if (IsLazy(field, context->EnforceLite())) {
81            return new RepeatedImmutableLazyMessageFieldGenerator(
82                field, messageBitIndex, builderBitIndex, context);
83          } else {
84            return new RepeatedImmutableMessageFieldGenerator(
85                field, messageBitIndex, builderBitIndex, context);
86          }
87        }
88      case JAVATYPE_ENUM:
89        return new RepeatedImmutableEnumFieldGenerator(
90            field, messageBitIndex, builderBitIndex, context);
91      case JAVATYPE_STRING:
92        return new RepeatedImmutableStringFieldGenerator(
93            field, messageBitIndex, builderBitIndex, context);
94      default:
95        return new RepeatedImmutablePrimitiveFieldGenerator(
96            field, messageBitIndex, builderBitIndex, context);
97    }
98  } else {
99    if (field->containing_oneof()) {
100      switch (GetJavaType(field)) {
101        case JAVATYPE_MESSAGE:
102          if (IsLazy(field, context->EnforceLite())) {
103            return new ImmutableLazyMessageOneofFieldGenerator(
104                field, messageBitIndex, builderBitIndex, context);
105          } else {
106            return new ImmutableMessageOneofFieldGenerator(
107                field, messageBitIndex, builderBitIndex, context);
108          }
109        case JAVATYPE_ENUM:
110          return new ImmutableEnumOneofFieldGenerator(
111              field, messageBitIndex, builderBitIndex, context);
112        case JAVATYPE_STRING:
113          return new ImmutableStringOneofFieldGenerator(
114              field, messageBitIndex, builderBitIndex, context);
115        default:
116          return new ImmutablePrimitiveOneofFieldGenerator(
117              field, messageBitIndex, builderBitIndex, context);
118      }
119    } else {
120      switch (GetJavaType(field)) {
121        case JAVATYPE_MESSAGE:
122          if (IsLazy(field, context->EnforceLite())) {
123            return new ImmutableLazyMessageFieldGenerator(
124                field, messageBitIndex, builderBitIndex, context);
125          } else {
126            return new ImmutableMessageFieldGenerator(
127                field, messageBitIndex, builderBitIndex, context);
128          }
129        case JAVATYPE_ENUM:
130          return new ImmutableEnumFieldGenerator(
131              field, messageBitIndex, builderBitIndex, context);
132        case JAVATYPE_STRING:
133          return new ImmutableStringFieldGenerator(
134              field, messageBitIndex, builderBitIndex, context);
135        default:
136          return new ImmutablePrimitiveFieldGenerator(
137              field, messageBitIndex, builderBitIndex, context);
138      }
139    }
140  }
141}
142
143ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
144    const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
145    Context* context) {
146  if (field->is_repeated()) {
147    switch (GetJavaType(field)) {
148      case JAVATYPE_MESSAGE:
149        if (IsMapEntry(field->message_type())) {
150          return new ImmutableMapFieldLiteGenerator(
151              field, messageBitIndex, builderBitIndex, context);
152        } else {
153          if (IsLazy(field, context->EnforceLite())) {
154            return new RepeatedImmutableLazyMessageFieldLiteGenerator(
155                field, messageBitIndex, builderBitIndex, context);
156          } else {
157            return new RepeatedImmutableMessageFieldLiteGenerator(
158                field, messageBitIndex, builderBitIndex, context);
159          }
160        }
161      case JAVATYPE_ENUM:
162        return new RepeatedImmutableEnumFieldLiteGenerator(
163            field, messageBitIndex, builderBitIndex, context);
164      case JAVATYPE_STRING:
165        return new RepeatedImmutableStringFieldLiteGenerator(
166            field, messageBitIndex, builderBitIndex, context);
167      default:
168        return new RepeatedImmutablePrimitiveFieldLiteGenerator(
169            field, messageBitIndex, builderBitIndex, context);
170    }
171  } else {
172    if (field->containing_oneof()) {
173      switch (GetJavaType(field)) {
174        case JAVATYPE_MESSAGE:
175          if (IsLazy(field, context->EnforceLite())) {
176            return new ImmutableLazyMessageOneofFieldLiteGenerator(
177                field, messageBitIndex, builderBitIndex, context);
178          } else {
179            return new ImmutableMessageOneofFieldLiteGenerator(
180                field, messageBitIndex, builderBitIndex, context);
181          }
182        case JAVATYPE_ENUM:
183          return new ImmutableEnumOneofFieldLiteGenerator(
184              field, messageBitIndex, builderBitIndex, context);
185        case JAVATYPE_STRING:
186          return new ImmutableStringOneofFieldLiteGenerator(
187              field, messageBitIndex, builderBitIndex, context);
188        default:
189          return new ImmutablePrimitiveOneofFieldLiteGenerator(
190              field, messageBitIndex, builderBitIndex, context);
191      }
192    } else {
193      switch (GetJavaType(field)) {
194        case JAVATYPE_MESSAGE:
195          if (IsLazy(field, context->EnforceLite())) {
196            return new ImmutableLazyMessageFieldLiteGenerator(
197                field, messageBitIndex, builderBitIndex, context);
198          } else {
199            return new ImmutableMessageFieldLiteGenerator(
200                field, messageBitIndex, builderBitIndex, context);
201          }
202        case JAVATYPE_ENUM:
203          return new ImmutableEnumFieldLiteGenerator(
204              field, messageBitIndex, builderBitIndex, context);
205        case JAVATYPE_STRING:
206          return new ImmutableStringFieldLiteGenerator(
207              field, messageBitIndex, builderBitIndex, context);
208        default:
209          return new ImmutablePrimitiveFieldLiteGenerator(
210              field, messageBitIndex, builderBitIndex, context);
211      }
212    }
213  }
214}
215
216
217static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
218  // Reaching here indicates a bug. Cases are:
219  //   - This FieldGenerator should support packing,
220  //     but this method should be overridden.
221  //   - This FieldGenerator doesn't support packing, and this method
222  //     should never have been called.
223  GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
224             << "called on field generator that does not support packing.";
225}
226
227}  // namespace
228
229ImmutableFieldGenerator::~ImmutableFieldGenerator() {}
230
231void ImmutableFieldGenerator::
232GenerateParsingCodeFromPacked(io::Printer* printer) const {
233  ReportUnexpectedPackedFieldsCall(printer);
234}
235
236ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
237
238void ImmutableFieldLiteGenerator::
239GenerateParsingCodeFromPacked(io::Printer* printer) const {
240  ReportUnexpectedPackedFieldsCall(printer);
241}
242
243// ===================================================================
244
245template <>
246FieldGeneratorMap<ImmutableFieldGenerator>::FieldGeneratorMap(
247    const Descriptor* descriptor, Context* context)
248    : descriptor_(descriptor),
249      field_generators_(new google::protobuf::scoped_ptr<
250          ImmutableFieldGenerator>[descriptor->field_count()]) {
251
252  // Construct all the FieldGenerators and assign them bit indices for their
253  // bit fields.
254  int messageBitIndex = 0;
255  int builderBitIndex = 0;
256  for (int i = 0; i < descriptor->field_count(); i++) {
257    ImmutableFieldGenerator* generator = MakeImmutableGenerator(
258        descriptor->field(i), messageBitIndex, builderBitIndex, context);
259    field_generators_[i].reset(generator);
260    messageBitIndex += generator->GetNumBitsForMessage();
261    builderBitIndex += generator->GetNumBitsForBuilder();
262  }
263}
264
265template<>
266FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
267
268template <>
269FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
270    const Descriptor* descriptor, Context* context)
271    : descriptor_(descriptor),
272      field_generators_(new google::protobuf::scoped_ptr<
273          ImmutableFieldLiteGenerator>[descriptor->field_count()]) {
274  // Construct all the FieldGenerators and assign them bit indices for their
275  // bit fields.
276  int messageBitIndex = 0;
277  int builderBitIndex = 0;
278  for (int i = 0; i < descriptor->field_count(); i++) {
279    ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator(
280        descriptor->field(i), messageBitIndex, builderBitIndex, context);
281    field_generators_[i].reset(generator);
282    messageBitIndex += generator->GetNumBitsForMessage();
283    builderBitIndex += generator->GetNumBitsForBuilder();
284  }
285}
286
287template<>
288FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {}
289
290
291void SetCommonFieldVariables(const FieldDescriptor* descriptor,
292                             const FieldGeneratorInfo* info,
293                             map<string, string>* variables) {
294  (*variables)["field_name"] = descriptor->name();
295  (*variables)["name"] = info->name;
296  (*variables)["capitalized_name"] = info->capitalized_name;
297  (*variables)["disambiguated_reason"] = info->disambiguated_reason;
298  (*variables)["constant_name"] = FieldConstantName(descriptor);
299  (*variables)["number"] = SimpleItoa(descriptor->number());
300}
301
302void SetCommonOneofVariables(const FieldDescriptor* descriptor,
303                             const OneofGeneratorInfo* info,
304                             map<string, string>* variables) {
305  (*variables)["oneof_name"] = info->name;
306  (*variables)["oneof_capitalized_name"] = info->capitalized_name;
307  (*variables)["oneof_index"] =
308      SimpleItoa(descriptor->containing_oneof()->index());
309  (*variables)["set_oneof_case_message"] = info->name +
310      "Case_ = " + SimpleItoa(descriptor->number());
311  (*variables)["clear_oneof_case_message"] = info->name +
312      "Case_ = 0";
313  (*variables)["has_oneof_case_message"] = info->name +
314      "Case_ == " + SimpleItoa(descriptor->number());
315}
316
317void PrintExtraFieldInfo(const map<string, string>& variables,
318                         io::Printer* printer) {
319  const map<string, string>::const_iterator it =
320      variables.find("disambiguated_reason");
321  if (it != variables.end() && !it->second.empty()) {
322    printer->Print(
323        variables,
324        "// An alternative name is used for field \"$field_name$\" because:\n"
325        "//     $disambiguated_reason$\n");
326  }
327}
328
329}  // namespace java
330}  // namespace compiler
331}  // namespace protobuf
332}  // namespace google
333